О том и речь ) Благодарю, Patron !
Поэтому я и предложил пускай пользователь имеет возможность либо определить
путь сохранения в ini файле или допустим в буфер системы ?
Или как-то так наверное даже правильней?
Вид для печати
На текущий момент мыслей по поводу реализации прерываний нет, поэтому пока то что есть: работающий С2 и СА оба пока не работают по прерываниям.
По С2 можно загрузиться с НХ сервера, по СА загрузка останавливается с ошибкой, но тоже результат :) .
Для связи используется программа сом0сом http://sourceforge.net/projects/com0com/
Все остальное в ветках "Сеть УКНЦ" и "УКНЦ загрузка через стык С2"
Для сети запуск копий из разных папок.
Затащил к себе код от Vamos, и озаботился настройкой COM-портов -- уже жаловались что приходится менять код под себя. Не доделал ещё, но будет примерно так: отдельный диалог на редактирование структуры DCB. Если какие-либо ещё параметры DCB нужно вытащить в редактор -- скажите, сделаю.
http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx -- DCB structure
http://img-fotki.yandex.ru/get/5642/..._dc87e392_orig
Наверное это лишнее, в реале УКНЦ кроме скорости стыка С2 все жёстко определено.
nzeemin, если будет возможность - посмотри пожалуйста ещё раз про звук для свежей компиляции UKNCBTL. Штука такая - на обычном DESKTOPE у меня бортовой звук и там все норм работает, а на ноуте UKNCBTL портит настройку так, что приходиться лазить поправлять иначе такое в колонках шипение при запуске других приложений пугающее ))) Впрочем я привык уже после запуска эмулятора лазить автоматом в звук.настройки ноута ))) Проблема в том, что минимальное значение ползунка почему то на звуковухе бука вызывает перегруз в купе с переключением на (только) левый канал. Какие ещё доработки планируются?
Возможно ли ожидать Load State в обозримом будущем и в целом любые новости по этому проекту всегда очень интересно !
Для реализации прерываний портов СА и С2 нужно модифицировать не только функцию void CFirstMemoryController::SetPortWord(WORD address, WORD word), но и void CFirstMemoryController::SetPortByte(WORD address, BYTE byte), которая в данный момент выглядит довольно бледно:
Код:void CFirstMemoryController::SetPortByte(WORD address, BYTE byte)
{
WORD word = (address&1)?((WORD)byte) << 8:(WORD)byte;
switch (address) {
case 0176560: //network
case 0176561: //СА: Регистр состояния приемника
m_Port176560 = (m_Port176560 & ~0100) | (word & 0100); // Bit 6 only
break;
case 0176562: // СА: Регистр данных приемника
case 0176563: // недоступен по записи
return ;
case 0176564: // СА: Регистр состояния источника
case 0176565:
m_Port176564 = (m_Port176564 & ~0105) | (word & 0105); // Bits 0,2,6
break;
case 0176566: // СА: Регистр данных источника
case 0176567: // нижние 8 бит доступны по записи
m_Port176566 = word & 0xff;
m_Port176564 &= ~128; // Reset bit 7 (Ready)
break;
case 0176570: // Стык С2: Регистр состояния приемника
case 0176571:
case 0176572: // Стык С2: Регистр данных приемника
case 0176573:
case 0176574: // Стык С2: Регистр состояния источника
case 0176575:
case 0176576: // Стык С2: Регистр данных источника
case 0176577:
return ;
}
}
---------- Post added at 10:56 ---------- Previous post was at 10:29 ----------
Правильно ли я понимаю, что при использовании такого алгоритма обработки в эмуляторе байтовой записи в порт - команда CLRB @#176561 сбросит разрешение прерываний ?Код:void CFirstMemoryController::SetPortByte(WORD address, BYTE byte)
{
WORD word = (address&1)?((WORD)byte) << 8:(WORD)byte;
switch (address) {
case 0176560: //network
case 0176561: //СА: Регистр состояния приемника // Bit 6 only
m_Port176560 = (m_Port176560 & ~0100) | (word & 0100);
break;
}
}
Настоящая УКНЦ действительно преобразует байт в слово перед записью в порт ?
Patron, видимо nzeemin еще не затащил код, у меня там все прописано.
Но толку пока от этих прерываний мало, DLTST показывает что все хорошо, а загрузка как не шла так и не идет TU58 в том числе.
Вот не знаю, но команда MOVB @#176561,R5 проходит, номер станции работает.
---------- Post added at 12:09 ---------- Previous post was at 12:05 ----------
С этой функции все и началось, после того как я туда скопипастил из void CFirstMemoryController::SetPortWord(WORD address, WORD word) все для С2, стала работать загрузка НХ сервера.
Тут все значительно проще - 1801ВП1-065 сигнал WTBT не обрабатывает, при байтовой записи в 1801ВМ2 неиспользуемый байт устанавливается нулями, потому и есть такая строчка: WORD word = (address&1)?((WORD)byte) << 8:(WORD)byte;, которая делает целое слово, присутствующее на линиях адреса-данных. Достаточно вызвать SetPortWord с этим словом.
Тогда нужно просто добавить туда обработку прерываний.
...
Исправленный исходник требует дальнейших улучшений:
1. При установке разрешения прерывания в готовом регистре приёмника - прерывание возникает так же, как в передатчике, а регистры приёмников почему-то остались неисправленными:
Код:void CFirstMemoryController::SetPortWord(WORD address, WORD word)
{
switch (address) {
case 0176560: //network
case 0176561: // СА: Регистр состояния приемника // Bits 2,6 only
m_Port176560 = (m_Port176560 & ~0104) | (word & 0104);
break;
case 0176570: // Стык С2: Регистр состояния приемника
case 0176571: // Bit 6 only
m_Port176570 = (m_Port176570 & ~0100) | (word & 0100);
break;
}
}
2. Приоритеты IRQ портов СА и С2 в файле Board.cpp остались неправильными:
Код:m_pCPU->InterruptVIRQ(3, 0370);
m_pCPU->InterruptVIRQ(3, 0374);
m_pCPU->InterruptVIRQ(3, 0360);
m_pCPU->InterruptVIRQ(3, 0364);
---------- Post added at 11:31 ---------- Previous post was at 11:22 ----------
Запись байта в регистр данных передатчиков СА и С2 обрабатывается так:
Почему такая разница ?Код:void CFirstMemoryController::SetPortByte(WORD address, BYTE byte)
{
WORD word = (address&1)?((WORD)byte) << 8:(WORD)byte;
switch (address) {
case 0176566: // СА: Регистр данных источника
case 0176567: // нижние 8 бит доступны по записи
m_Port176566 = word & 0xff;
m_Port176564 &= ~128; // Reset bit 7 (Ready)
break;
case 0176576: // Стык С2: Регистр данных источника
case 0176577:
return ;
}
}
Как записываемый в регистр данных С2 байт попадает в переменную m_Port176576 ?
Правильно ли, что при записи байта в регистр данных передатчика С2 - бит готовности в слове состояния не сбрасывается ?
---------- Post added at 11:38 ---------- Previous post was at 11:31 ----------
Ещё ошибка:
Должно быть:Код:m_pProcessor->InterruptVIRQ(8, 0364);
Код:m_pProcessor->InterruptVIRQ(10, 0364);
http://zx-pk.ru/showpost.php?p=571646&postcount=568
Меня смущает вот это m_Port176564 &= ~128; // Reset bit 7 (Ready)
я думаю должно быть так m_Port176564 &= ~0200; // Reset bit 7 (Ready)
У всех прерываний должны быть разные приоритеты IRQ ( для С2 - приемник 7, передатчик 8, для СА - приемник 9, передатчик 10 ), иначе прерывания могут теряться.
---------- Post added at 11:42 ---------- Previous post was at 11:40 ----------
128 == 0200 (проверил при помощи калькулятора).
Но лучше, конечно, везде писать 0200 - тогда легче понять о чём речь.
Я не проснулся, я просто не использую восьмеричную систему, и нигде, кроме PDP-систем ее не встречал) Она для меня чуждая) Близкая - десятичная и шестнадцатиричная. Поэтому все нюансы, связанные с ней мне не известны)
Мало того, видел много исходников на Си, встречаются шестнадцатиричные числа 0x..., но чтобы восьмеричные встретить - никогда такого не было)
Нуу.. после Макро11 он мне показался китайской грамотой, а сейчас там еще всякие объекты классы, мне компилятор чуть мозг не вынес сообщениями об ошибках когда я его три недели назад поставил впервые к себе на комп.
Хотя сейчас посмотрев на некоторые исходники Макро11, это конечно стилем называется, но помоему это очень много букв.
Согласен. Я тоже не люблю ООП. Когда работаешь с ассемблером или простым Си, прекрасно понимаешь, что ты делаешь конкретной функцией, и с каким типом данным работаешь. А это наследование и классы, уходящие к первоисточникам, набирая по пути дополнительных свойств и функций - это бррр... Для чего-то это может и удобно, но мне антагонистично)
---------- Post added at 13:31 ---------- Previous post was at 13:28 ----------
Не, ну не сейчас) У эмулятора же даже нет настроек, чтобы это включить)
На самом деле смысл объектного программирования в своей основе вполне "ассемблерный" - объект это немного улучшенная обычная структура ( srtuct ), с тремя важными и полезными новшествами:
1. Добавлены две специальные функции "конструктор" и "деструктор", которые всегда (ну, или почти всегда) автоматически вызываются при создании и уничтожении такой "классной" структуры.
2. Членами могут быть не только данные, но и функции (их называют "методы"), и даже автоматически разыменуемые указатели на функции ( их называют "виртуальные методы" ).
3. Алгоритмы всех операций, автоматически совершаемых компилятором над такой структурой ( например - копирование ) могут быть явно изменены.
Если никакие из этих возможностей не использовать - объект класса C++ будет ничем не отличим от экземпляра обычной структуры C.
И для того чтобы сделать простую вещь, передать значение переменной, нужно прописать кучу указателей по всем этим классам и объектам т.е. почесать правой рукой за левым ухом легче.
Конструкторы - это просто песня. Т.к. в C++ все типы данных являются классами - конструктор можно задать для чего угодно. У меня почти все "обычные" структуры имеют конструкторы с пустым телом - просто устанавливающие для членов значения по умолчанию.
Например:
В подобной ситуации становится абсолютно невозможно создать экземпляр такой структуры с неинициализированными членами.Код:struct Point {
int X;
int Y;
Point():
X(0),
Y(0)
{}
};
Если хочется дополнительно иметь возможноcть явно задавать начальные значения членов при создании структуры - можно сделать так:
и создавать экземпляры, например, так:Код:struct Point {
int X;
int Y;
Point( int X0 = 0, int Y0 = 0 ):
X(X0),
Y(Y0)
{}
};
Код:Point A;
Point B(1,1);
C++ - это и есть практически "чистый ассемблер" в том виде, в котором он должен быть. Использовать все его возможности в полном объёме или не использовать - зависит от потребностей. По мере роста потребностей - растёт и объём используемых возможностей.
Важно лишь с самого начала понимать, что все без исключения возможности С++ - это практически всё тот же "чистый ассемблер" без каких-либо "наворотов".
То, что повсюду называют ООП - на мой взгляд - просто вывих мозга. Как можно писать в таком стиле я представить себе не могу. Именно безумный стиль "ООП" многие (как я понимаю) путают с сутью объектного подхода.
На самом деле программа, использующая объекты - это лишь упрощённый вариант программы без объектов.
Вот пример класса LockVarType, создающего объекты быстрой межпоточной синхронизации размером в одно слово:
Этот объект имеет после компиляции размер в одно слово.Код:#define DWORD_ALIGN __declspec(align(4))
#define LOCK_VAR_TYPE DWORD_ALIGN LONG volatile
class LockVarType {
public:
LockVarType():dwLockVar(0){}
inline dword IsLocked(){ return dwLockVar; }
inline void Lock( int nSleepMS = 0 )
{
while( InterlockedCompareExchange( &dwLockVar, 1, 0 ) ) { Sleep( nSleepMS ); }
}
inline void UnLock() { dwLockVar = 0; }
inline bool TimedLock( dword uTimeOut_MS, int nSleepMS = 0 )
{
dword uTC = GetTickCount();
while( InterlockedCompareExchange( &dwLockVar, 1, 0 ) )
{
if( GetTickCount() - uTC >= uTimeOut_MS ) { return false; }
Sleep( nSleepMS );
}
return true;
}
inline bool TryLock() { return !InterlockedCompareExchange( &dwLockVar, 1, 0 ); }
protected:
LOCK_VAR_TYPE dwLockVar;
};
Сделать межпоточную синхронизацию легче и проще вряд ли реально.
Это макросы, которые подставляются в код программы в тех местах, где пользователь хочет как-то использовать объект.
Например, чтобы включить, а потом выключить межпоточную блокировку пользователь пишет:
А в код программы вставляется:Код:LockVar.Lock();
................
LockVar.UnLock();
Код:while( InterlockedCompareExchange( &dwLockVar, 1, 0 ) ) { Sleep(0); }
................
dwLockVar = 0;
Обычно нужно ещё передать используемую переменную в качестве параметра (не писать же для каждой новой переменной собственные уникальные макросы), а когда переменная объект - она сама себя передаёт в качестве аргумента своим методам.
---------- Post added at 16:26 ---------- Previous post was at 16:23 ----------
Вот и получается, что разница между LockVar( &dwLockVar ) и LockVar.Lock() только в том, что при переносе кода из одного проекта в другой - не надо думать, что относится к блокировке, а что нет - всё необходимое уже "упаковано" в описание объекта.
---------- Post added at 16:41 ---------- Previous post was at 16:26 ----------
Важное преимущество C++ перед C, которое заставляет писать даже C-программы в формате C++ - это возможность объявлять любую переменную там, где она нужна, а не в начале функции.
Когда пишешь функцию на несколько экранов ( а у меня они почти все такие ) - лазить каждый раз в самое начало, чтобы добавить новую переменную - очень утомляет.
А можно в ANSI C задавать переменную цикла прямо в операторе for ?
Код:for( int i = 0 ; i < 100 ; i++ )
Да, это возможность удобная, и сам ее иногда использую. Хотя, стараюсь не злоупотреблять, чтобы не раскидывать обьявления по коду.
Так же в Си++ удобно, что можно писать преобразование типов, скажем, не k = (long)i, а k = long(i). Для наглядности иногда удобней.
Вот и все, чем я пользуюсь из Си++ )