"Си — инструмент, острый, как бритва: с его помощью можно создать и элегантную программу, и кровавое месиво"
(С) я думаю всё знают чей =)
Вид для печати
Насколько я понимаю - в первом случае к объекту i применяется копирование типа long, а во втором случае сначала создаётся новый объект типа long - т.е. вызывается его конструктор, получающий значение объекта i в качестве начального значения, а потом копируется уже вновь созданный объект. Если включена оптимизация - код может получиться одинаковым, а если нет - первый вариант будет короче.
Про ООП (но не про Си!)
Скрытый текст
Я не проф. и Си вообще всегда бежал, но вот Паскаль от УК-НЦ потом турбо-паскаль в ДОС - для удовольствия и наконец Delphi под Win. ООП - конструкторы\диструкторы я понял только из объяснений Patrona - слишком заумные мне попадались видимо толкователи до этого.
Но я вот что хотел сказать то - читал учебник (автора не помню), по Delphi, где автор полностью отказался от термина ООП и вообще не использовал его ни разу ни на одной странице (единственный учебник в котором автор на одном со мной языке говорил про ООП паскаль и Delphi), он вводит там такой термин Событийно Ориентированное Программирование.
Мне например "методы" ? Ну то есть переменные объекта, которые через
точку пишутся очень обрадовали! Но потребовалось время что-бы привыкнуть воспринимать и код и результат по новому, если раньше программа была строго линейная (или я такой как рельсы прямой!), то есть автоматом вылетала в монитор
когда доходила до END., то под Win созданное окно так и будет висеть и получать сообщения. В целом это я так - впечатлениями делюсь, но мне например
нелегко было отказаться от циклов и некоторых других вещей которые "не рекомендуются" при СОП, просто потому-что не нужны или не желательны или требуют дополнительного обслуживания (я имею в виду ProcessMessages).
И странное дело, вот объяснения Patrona я понимаю, а код из примеров (сам синтаксис Си для меня всегда был страшен - может потому что я
начинал с Бейсика на БК0010? Но все эти фигурные скобочки - у меня
ассоциация с комментами из паскаля ))) Паскаль - просто больше похож
(Delphi сюда же). на язык человека и наглядней (для меня) для простых
вычислений. Но я не профи.
[свернуть]
Вот кстати говоря вопрос такой - если Си родился из макро-11 (а судя
по данным многие профессионалы сразу начинали с той самой версии,
минуя ассемблер, где Паскаль впервые в виде транслятора появился,
так же на PDP? (наверное это легко нагуглить, но всё же).
---------- Post added at 20:35 ---------- Previous post was at 20:34 ----------
Главное - какой будет быстрее работать?
Сейчас оптимизаторы достигли такой крутизны, что при включённой глобальной оптимизации - вызов целого вороха вложенных функций может скомпилироваться в одну-две ассемблерных команды вообще без всяких вызовов подпрограмм.
Когда я впервые в жизни включил глобальную оптимизацию и посмотрел ассемблерный листинг компиляции - то очень удивился. Из функций исчезли прологи и эпилоги, а аргументы стали передаваться в регистрах вместо стека. Если функция не числится глобальной (а значит не должна быть доступна в OBJ-файле в виде глобального имени) - оптимизатор может иногда вообще не компилировать её, а подставлять в точках вызовов как макрос.
Patron, Vamos -- спасибо за критику и вклад в проект.
Сейчас станции уже начинают пытаться переговариваться, но сбиваются.
http://img-fotki.yandex.ru/get/4119/..._3d220139_orig
При этом на принимающей станции выпадает в СТОП.
Загрузчик из сети в ПЗУ (спасибо Alex_K):
Код:; Загрузчик из сети
164160$:MTPS #340 ; Запретить прерывания
MOVB @#176561,R5 ; Выделение в R5 номера сетевой станции
MOV R5,R0
BIC #177760,R5
ASR R0
BIC #177717,R0
BIS R0,R5
MOVB R5,164556$ ; Сохранение номера сетевой станции
MOVB 164572$,R0 ; R0 = 173(8)
XOR R5,R0 ; R0 = 173(8) XOR номер_сетевой_станции
MOVB R0,164572$
MOV #30,R0 ; R0 = 30 (адрес вектора команды EMT)
MOV #164500$-164160$+1000,(R0)+ ; Установка вектора прерывания EMT
CLR (R0)+ ; Установка ССП при вызове EMT
MOV #164512$-164160$+1000,(R0)+ ; Установка вектора прерывания TRAP
CLR (R0)+ ; Установка ССП при вызове TRAP
164244$:MOV #10000,SP ; Установка указателя стека
MOV #164526$-164160$+1000,@#100 ; Устан. вект. прер. сет. таймера
CLR @#102
MTPS #0 ; Разрешить прерывания
CLR 164534$ ; Очистка счетчика ожидания
164272$:TRAP 0 ; Чтение пришедшего байта
CMP 164534$,#5 ; Счетчик ожидания больше пяти
BLO 164272$ ; Нет
164304$:EMT 0 ; Посылка и чтение очередного байта
CMPB #376,R0 ; Пришедший байт равен 376(8)
BNE 164304$ ; Нет
MOV #164554$-164160$+1000,R1 ; R1 = адрес блока передачи
164320$:MOVB (R1)+,R0 ; R0 = очередной байт из блока передачи
CMPB #376,R0 ; Он равен 376(8) ?
BEQ 164334$ ; Да
EMT 0 ; Посылка и чтение очередного байта
BR 164320$
164334$:EMT 0 ; Посылка и чтение очередного байта
CMPB #377,R0 ; Прочитанный байт равен 377(8) ?
BNE 164334$ ; Нет
EMT 0 ; Посылка и чтение очередного байта
CMPB R5,R0 ; Полученный байт равен номеру станции ?
BNE 164334$ ; Нет
MOV #377,R4 ; R4 = 377(8) (контрольная сумма)
XOR R0,R4 ; R4 = 377(8) XOR номер_сетевой_станции
MOV #50000,R1 ; R1 = адрес расположения загрузчика
EMT 0 ; Посылка и чтение очередного байта
MOV R0,R3 ; R3 = считанный байт
XOR R0,R4 ; Подсчет контрольной суммы
164372$:EMT 0 ; Посылка и чтение очередного байта
CMPB #373,R0 ; Считанный байт равен 373(8) ?
BLOS 164410$ ; Выше или равен 373(8)
XOR R0,R4 ; Подсчет контрольной суммы
MOVB R0,(R1)+ ; Передача принятого байта в память
BR 164372$
164410$:BNE 164426$ ; Принятый байт равен не равен 373(8)
EMT 0 ; Посылка и чтение очередного байта
COM R0 ; Инверсия принятого байта
XOR R0,R4 ; Подсчет контрольной суммы
MOVB R0,(R1)+ ; Передача принятого байта в память
COM R0 ; Инверсия для передачи
BR 164372$
164426$:CMPB #374,R0 ; Принятый байт равен 374(8)
BNE 164244$ ; Нет
EMT 0 ; Посылка и передача байта
CMPB R0,R4 ; Он равен контрольной сумме ?
BNE 164244$ ; Нет
EMT 0 ; Посылка и передача байта
BISB #10,R0 ; R0 = R0 OR 10(8)
EMT 0 ; Посылка и передача байта
CMPB #377,R0 ; Принятый байт равен 377(8)
BNE 164244$ ; Нет
EMT 0 ; Посылка и передача байта
MOV #4,@#176560 ; Включение кольцевой сети
MTPS #340 ; Запретить прерывания
JMP @#50000 ; Переход на исполнение загрузчика
; Подпрограмма передачи байта в локальную сеть (исполнение команды EMT)
164500$:TSTB @#176564 ; Передатчик СА готов ?
BPL 164500$ ; Нет
MOVB R0,@#176566 ; Передача байта в сеть
; Подпрограмма чтения байта, пришедшего по сети (исполнение команды TRAP)
164512$:TSTB @#176560 ; Приемник СА готов ?
BPL 164512$ ; Нет
MOVB @#176562,R0 ; Прием байта из сети
RTI
; Подпрограмма исполнения прерываний таймера
164526$:CLR @#176560 ; Включение режима загрузки
INC (PC)+ ; Инкремент счетчика ожидания
164534$:.WORD 0
CMP 164534$,#1000 ; Счетчик ожидания превысил лимит времени ?
BHI 164550$ ; Да
RTI
164550$:JMP 164244$
; Блок передачи в сеть
164554$:.BYTE 377,0,0,204,0,0,0,0,0,0,0,0,0,374,173,60,377,376,0,0
Так вот он какой 1801ВП-065, там оказывается есть бит 0 и бит 2 в регистре состояния приемника.
Бит 2 это вывод ST, программное управление вкл./выкл. станции из кольцевой сети.
Бит 0 ??? , разрыв линии
Получается это те самые DTR/DSR которые и должны были быть 107, 108 на стыке С2
Уже писалось, что линии квитирования ни на какие биты не выводятся, квитирование делается полностью аппаратно самим 1801ВП1-065.
Бит 0 - разрыв линии - это посылка BREAK.
А вывод ST - это не бит 2, а сигнал "свой адрес". Благодаря этому можно на неиспользуемые биты 1801ВП1-065 вешать свою обвязку без необходимости дешифрации адреса. В этом случае достаточно запомнить только младшие биты (различать приемник, передатчик, регистры данных) и реагировать на сигналы DIN, DOUT. Сигнал RPLY выставит сама 1801ВП1-065. Вот в этой обвязке есть номер станции и управление электронным коммутатором сети.
Так и там тоже были переполнения
http://zx-pk.ru/attachment.php?attac...1&d=1358979832
поэтому, проверить на счёт переполнений всегда есть смысл первым делом.
Как я понял, запись в буфер происходит слишком быстро и код эмулятора не успевает.
Ну вот чего ему не хватает :mad:
http://zx-pk.ru/attachment.php?attac...1&d=1359589855
если кому попадался этот тест с пунктом 6 (стык С2) поделитесь пожалуйста.
Patron, на этот вопрос у меня ответа нет, но вот код, может там чего
Код:if (m_SerialInCallback != NULL && frameticks % 416 == 0)
{
CFirstMemoryController* pMemCtl = (CFirstMemoryController*) m_pFirstMemCtl;
if ((pMemCtl->m_Port176574 & 004) == 0) // Not loopback?
{
BYTE b;
if (m_SerialInCallback(&b))
{
if ((pMemCtl->m_Port176570 & 0200) == 0) // Ready?
{
pMemCtl->m_Port176572 = b;
}
else
{
pMemCtl->m_Port176570 |= 010000; // Set Overflow flag
}
pMemCtl->m_Port176570 |= 0200; // Set Ready flag
}
}
}
if (m_SerialOutCallback != NULL && frameticks % serialOutTicks == 0)
{
CFirstMemoryController* pMemCtl = (CFirstMemoryController*) m_pFirstMemCtl;
if (serialTxCount > 0)
{
serialTxCount--;
if (serialTxCount == 0) // Translation countdown finished - the byte translated
{
if ((pMemCtl->m_Port176574 & 004) == 0) // Not loopback?
{
(*m_SerialOutCallback)((BYTE)(pMemCtl->m_Port176576 & 0xff));
}
else // Loopback
{
pMemCtl->m_Port176572 = pMemCtl->m_Port176576 & 0xff;
pMemCtl->m_Port176570 |= 0200; // Set Ready flag
}
pMemCtl->m_Port176574 |= 0200; // Set Ready flag
}
}
else if ((pMemCtl->m_Port176574 & 0200) == 0) // Ready is 0?
{
serialTxCount = 8; // Start translation countdown
}
}
У меня пока основная гипотеза -- что передача байт из эмулятора происходит без проверки того готов ли к этому COM-порт. Поэтому вероятно мы и видим overrun. Вообще общение с COM-портом у меня построено не на overlapped и не на событиях, а по более простой схеме -- чисто байтовое чтение и запись. При чтении если очередной байт не готов -- он не отдаётся. Но при записи пишется всё не взирая на возможные переполнения.
Эта версия TUK.SAV от СЭМЗА, я сейчас потыкался - другой версии не нашёл,
попробуй TS.SAV - просто ради эксперимента?
http://savepic.org/2745756.png
http://savepic.org/2736540.png
и вот ещё отдельный для СА "TSA.SAV"
http://savepic.org/2697628.png
Кажется где-то под С2 было что-то отдельно написано, если откопаю-вспомню выложу сразу.
А мы таки видим именно overrun ?
Мы видим именно бит 010000 в регистре статуса приёмника ?
Если да - это неправильная эмуляция.
Вот такой код в принципе ошибочен:
Код:if (m_SerialInCallback(&b))
{
if ((pMemCtl->m_Port176570 & 0200) == 0) // Ready?
{
pMemCtl->m_Port176572 = b;
}
else
{
pMemCtl->m_Port176570 |= 010000; // Set Overflow flag
}
pMemCtl->m_Port176570 |= 0200; // Set Ready flag
}
Так и надо.Цитата:
Вообще общение с COM-портом у меня построено не на overlapped и не на событиях, а по более простой схеме -- чисто байтовое чтение и запись. При чтении если очередной байт не готов -- он не отдаётся. Но при записи пишется всё не взирая на возможные переполнения.
Но ещё надо учитывать, что драйвер com0com - пакетный. Он не следит за промежутком времени между байтами ( в Windows вообще ни одна программа этого не делает ), поэтому, если эмулятор допускает формирование признака overrun - при работе в Windows этот признак обязательно будет формироваться.
---------- Post added at 11:38 ---------- Previous post was at 11:35 ----------
Здесь даже промежутки времени не столь важны.
Ведь в реальном порту действует квитирование, т.е. байт не может быть принят, если порт не готов. А в эмуляторе может! И даже признак overrun формируется!
---------- Post added at 11:41 ---------- Previous post was at 11:38 ----------
Поэтому - в нынешнем состоянии эмулятор эмулирует работу 1801ВП1-065 по кабелю без линий квитирования. А по такому кабелю ни TU58, ни сеть УКНЦ работать не могут.
А в чем ошибочность кода? Если стоит признак готовности, то данные с приемника не считаны, и при приходе других данных ставится бит переполнения, а принятая посылка теряется.
А как это так, что байт не может быть принят, если порт не готов? Может, еще как может. Ведь для приема другая сторона его передает, а если она не следит за состояниями линии квитирования, то она может его передать и возможно переполнение. Единственное 1801ВП1-065 не сможет передать байт, если на линии BSYD нет готовности от приемника той стороны.
И кстати в сетевом адаптере линии квитирования не используются, там только прием, передача и земля.
Ошибочность в том, что Windows не исключает приход в программу любого количества байтов без задержки вообще. Это же мы не с аппаратным портом по прерываниям работаем, а опрашиваем входной буфер Windows ёмкостью 3К. Пока Windows занимается своими делами - в этом буфере копятся байты, а когда процесс исполняющейся программы эмулятора получает свой квант - ему вываливаются из буфера все накопившиеся там байты разом.
И это на скорости 57600.. Круто! Быстро же должны работать программы сетевого обмена, чтобы не потерять ни одного байта.Цитата:
кстати в сетевом адаптере линии квитирования не используются, там только прием, передача и земля.
Это же с какой скоростью по COM-порту идти данные? Да и как же редко программ должна получать кванты времени?
Проблема может быть в другом. UKNCBTL работает по фреймам, 25 фреймов в секунду. Т.е. быстренько эмулируется 1/25 секунды, обновляется экран, а потом спит в ожидании завершения 1/25 секунды на реальном PC. Вот во время этой спячки и могут придти реальные данные. Но однако же в эмуляторе данные с очереди снимаются со скоростью порта внутри фрейма, поэтому между снятиями данных эмулируемая программа должна успеть прочесть приемник. Если успевает, то и переполнения не будет.
Быстро. Загрузчик из ПЗУ без прерываний. А в RT-11 драйвер MC.SYS работает в режиме прерываний. Но драйвер MC.SYS не является самим драйвером, а скорее резидентной программой, сидящей на обработке и отправке пакетов по сети.
Именно так. И проведённые испытания показывают, что как раз и не успевает.
В настройках COM-порта можно сделать дополнительную опцию: Эмулировать OVERRUN - при включении которой чтение из буфера Windows будет работать как сейчас, а при выключении - как надо.
---------- Post added at 14:11 ---------- Previous post was at 14:08 ----------
Даже за 1/50 секунды com0com на скорости 9600 насыпет во входной буфер 20 байтов.
---------- Post added at 14:19 ---------- Previous post was at 14:11 ----------
Хочется же иметь возможность эмулировать как работу по кабелю без квитирования, так и работу по кабелю с квитированием.
Вот выбор этих режимов и надо добавить в окно настроек COM-порта.
Если с выключенной эмуляцией оверрана всё заработает - значит оверран эмулируется плохо. Если же и тогда ничего не заработает - значит качество эмуляции оверрана не при чём.
Если загрузчик TU58 использует сигнал BREAK, то он не начнёт нормально работать до тех пор, пока в нужные места эмулятора не будут вставлены вызовы SetCommBreak и ClearCommBreak.
Эксперимент по запуску эмулятора TU58 с "Эмулятором ДВК" показал, что эмуляция сигнала BREAK для работы с эмулятором TU58 через com0com не обязательна.
После запуска - TU58.exe предлагает нажать клавишу [Esc] и пропустить ожидание сигнала BREAK. После чего начинает обрабатывать пакеты в заданном порту, позволяя результативно выполнить в эмуляторе ДВК команды DIR DD: и BOOT DD:
---------- Post added at 16:05 ---------- Previous post was at 14:48 ----------
Выяснилось, что эксперимент по работе с эмулятором TU58 без сигнала BREAK был не вполне корректным - оказывается, и эмулятор последовательного порта в "Эмуляторе ДВК", и адаптер COM-порта в модульном API поддерживают передачу сигнала BREAK. В описании com0com тоже указано, что передача сигнала BREAK не просто поддерживается, а многократно улучшалась.
Однако, эмулятор TU58 начал нормально работать только после отключения ожидания сигнала BREAK нажатием клавиши [Esc].
Так что пока вся эта история с сигналом BREAK выглядит довольно непонятно.
как бы вот, после нажатия ESC
http://zx-pk.ru/attachment.php?attac...1&d=1359728766
Когда я отключил в эмуляторе ДВК посылку сигнала BREAK - стало так же, поэтому без посылки BREAK TU58.exe работать не будет.
Посылку BREAK добавить нетрудно - когда программа устанавливает бит 00 в статусе передатчика - нужно вызвать SetCommBreak( hComPort ) ( и ещё можно сделать Sleep(15) - тогда Windows успевает отреагировать до сброса этого бита эмулятором ), а когда программа обнуляет установленный бит 00 - нужно вызвать ClearCommBreak( hComPort ) ( здесь Sleep уже не нужен ).
---------- Post added at 20:45 ---------- Previous post was at 19:45 ----------
Хотя, если внимательнее присмотреться к сообщениям TU58.exe:
получается, что эмулятор опознал и выполнил команду чтения вторичного загрузчика.Код:command 2 count 800 block 2
Поэтому, ситуация с сигналом BREAK в данном конкретном случае не вполне ясна - если TU58.exe и без сигнала BREAK передал загрузчик, то на чём всё потом остановилось..
Однако, когда я отключил BREAK в эмуляторе ДВК и дал DIR DD: - эффект был нулевой, а с посылкой BREAK - всё работало как надо.
---------- Post added at 20:49 ---------- Previous post was at 20:45 ----------
Возможно, в последнем случае дело было не в самом сигнале BREAK, а в том, что при подаче BREAK эмулятор делал Sleep(15) - вот TU58.exe и успевал ответить до отвала драйвера DD.SYS по таймауту.
Сейчас проверю эту гипотезу..
---------- Post added at 20:59 ---------- Previous post was at 20:49 ----------
ДА! TU58.exe нормально работает без BREAK !!!
Если вместо сигнала BREAK просто делать Sleep(15) - TU58.exe без проблем обслуживает любые запросы драйвера DD.SYS
Только что загрузил RT-11 c DD: с отключенной посылкой BREAK.
У меня нет.
видимо нет. видимо BREAK
http://zx-pk.ru/attachment.php?attac...1&d=1359744341
Подскажите куда втыкать SetCommBreak, там где порт инициализируется или там где бит 00 обрабатывается.
Вот сюда:
Код:void CFirstMemoryController::SetPortByte(WORD address, BYTE byte)
{
WORD word = (address&1)?((WORD)byte) << 8:(WORD)byte;
switch (address) {
case 0176574: // Стык С2: Регистр состояния передатчика
case 0176575:
if (((m_Port176574 & 0300) == 0200) && (word & 0100))
m_pProcessor->InterruptVIRQ(8, 0374);
if (word & 01)
{
if (!(m_Port176574 & 01))
{ // BREAK
SetCommBreak( m_hEmulatorComPort );
Sleep(15);
}
}
else
if (m_Port176574 & 01)
ClearCommBreak( m_hEmulatorComPort );
m_Port176574 = (m_Port176574 & ~0105) | (word & 0105);
break;
}
}
void CFirstMemoryController::SetPortWord(WORD address, WORD word)
{
switch (address) {
case 0176574: // Стык С2: Регистр состояния передатчика
case 0176575:
if (((m_Port176574 & 0300) == 0200) && (word & 0100))
m_pProcessor->InterruptVIRQ(8, 0374);
if (word & 01)
{
if (!(m_Port176574 & 01))
{ // BREAK
SetCommBreak( m_hEmulatorComPort );
Sleep(15);
}
}
else
if( m_Port176574 & 01 )
ClearCommBreak( m_hEmulatorComPort );
m_Port176574 = (m_Port176574 & ~0105) | (word & 0105);
break;
}
}
Я вот думаю -- не проще ли сразу после SystemFrame() вызвать SetCommBreak(), а непосредственно перед SystemFrame() сделать ClearCommBreak().
Если проблема действительно в паузе между фреймами, это может помочь.
---------- Post added at 17:10 ---------- Previous post was at 17:00 ----------
Попробовал -- не помогает.
Кроме того, я пробовал запускать загрузку по сети когда оба эмулятора работают на полной скорости (без звука) -- загрузка тоже падает с ошибкой.