PDA

Просмотр полной версии : Эмулятор Союз-Неон ПК-11/16 - EmuStudio



Страницы : 1 [2]

Titus
16.06.2021, 14:30
Причём, под XP версия 0.16a рисует только тулбар, а самого окна с экраном Союз-Неона под ним нет.
Во всех остальных комбинациях просто чёрный экран.
Лучше прикладывать скриншоты.

А также подробно то, что пишет консольное окно.

Manwe
16.06.2021, 20:19
Лучше прикладывать скриншоты. А также подробно то, что пишет консольное окно.Снял скриншоты, включая консольное окно. Windows XP и Windows 7 ведут себя одинаково с версиями 0.15n и 0.16a, а вот на Windows 10 появляется отличие в версии 0.15n.

https://pic.maxiol.com/thumbs2/1623863889.3105916926.winxpv15.png (https://pic.maxiol.com/?v=1623863889.3105916926.winxpv15.png&dp=2)

https://pic.maxiol.com/thumbs2/1623863920.3105916926.winxpv16.png (https://pic.maxiol.com/?v=1623863920.3105916926.winxpv16.png&dp=2)

https://pic.maxiol.com/thumbs2/1623863939.3105916926.win10v15.png (https://pic.maxiol.com/?v=1623863939.3105916926.win10v15.png&dp=2)

Titus
16.06.2021, 23:09
а вот на Windows 10 появляется отличие в версии 0.15n.
Ну что же, могу предположить, что в эмуляторе винды что-то где-то недоэмулировано.
Попробуй другой эмулятор, если он есть.

Manwe
16.06.2021, 23:12
Ну что же, могу предположить, что в эмуляторе винды что-то где-то недоэмулировано.
Попробуй другой эмулятор, если он есть.Другого за разумную цену и под процессор M1, к сожалению, нет.
Однако, эмулятор БК ведь работает в CrossOver. А там всё сложней с графикой (разные окна выводятся разными средствами).

Titus
16.06.2021, 23:41
Однако, эмулятор БК ведь работает в CrossOver. А там всё сложней с графикой (разные окна выводятся разными средствами).
У меня все выводится просто через DirectX. Причем, старой версии, которая еще под WinXP работает.

Manwe
17.06.2021, 10:53
У меня все выводится просто через DirectX. Причем, старой версии, которая еще под WinXP работает.microxa посмотрел исходники, говорит, что ты используешь Clipper, а это чревато. Ещё не очень понятно почему DirectX 7, если в XP уже поддерживается DX9.

Titus
17.06.2021, 12:40
microxa посмотрел исходники, говорит, что ты используешь Clipper, а это чревато. Ещё не очень понятно почему DirectX 7, если в XP уже поддерживается DX9.

Клиппер я использовал вроде бы для того, чтобы выводить с помощью DirectX в окно.

Почему DX7 тоже не помню. Вроде бы тогда в 2005 году или не было DX9, или же его надо было устанавливать отдельно.
Кроме того, никакого функционала от DX9, которого не было в предыдущих DX мне не было нужно.

Manwe
17.06.2021, 13:30
Клиппер я использовал вроде бы для того, чтобы выводить с помощью DirectX в окно.
Почему DX7 тоже не помню. Вроде бы тогда в 2005 году или не было DX9, или же его надо было устанавливать отдельно.
Кроме того, никакого функционала от DX9, которого не было в предыдущих DX мне не было нужно.Хм, microxa вообще через древний DirectDraw делал:

var
{$ifdef delphi6}
lpDD: IDIRECTDRAW;
lpDDSPrimary: IDIRECTDRAWSURFACE;
lpDDSBack: IDIRECTDRAWSURFACE;
lpClipper: iDirectDrawClipper;

Titus
17.06.2021, 13:34
Хм, microxa вообще через древний DirectDraw делал:
и...?

Manwe
17.06.2021, 14:08
и...?И отображается в CrossOver :)


lpDD.WaitForVerticalBlank(1,0);
if lpDDSPrimary.Blt(@WndRect,lpDDSBack,nil, 0{ DDBLT_WAIT DDBLT_ASYNC },nil)
= DDERR_SURFACELOST then lpDDSPrimary.Restore;

Titus
17.06.2021, 18:29
И отображается в CrossOver
У меня примерно тоже самое используется)
И тот же самый клиппер.
Значит дело в чем-то еще)

svinka
17.06.2021, 19:43
microxa посмотрел исходники, говорит, что ты используешь Clipper, а это чревато.

А где посмотреть исходники?

Manwe
18.06.2021, 00:56
А где посмотреть исходники?в IDA Pro, конечно ;)

svinka
18.06.2021, 10:34
Ой
а где сообщение Igor76 про бессмертие автора?

а то я собрался ответить
верните чтоли

Manwe
18.06.2021, 12:11
Значит дело в чем-то еще)И никто так и не узнает в чём же дело... Ладно, тогда пока без нового софта под Союз-Неон. Возвращаюсь на БК 0010 - его эмулятор работает под CrossOver.

На самом деле, выбирая на что потратить 5000 руб - на Parallels Desktop (в котором работает эмулятор Союз-Неона) или на развитие эмулятора, я бы выбрал второе. В идеале было бы скомпилировать эмулятор Союз-Неона под MacOS (M1+Intel). Насколько я понимаю, это возможно, поскольку EmuStudio кроссплатформенный. Titus, примешь посильное пожертвование?

Titus
18.06.2021, 13:08
Насколько я понимаю, это возможно, поскольку EmuStudio кроссплатформенный. Titus, примешь посильное пожертвование?

Это нереально. Он заточен под винду. Пришлось бы новую оболочку писать.
Кроме того, я и так взялся в некотором роде переделывать GUI, просто на лето затормозил, т.к. дача, огород и не до этого.

Manwe
18.06.2021, 13:43
Это нереально. Он заточен под винду. Пришлось бы новую оболочку писать.
Кроме того, я и так взялся в некотором роде переделывать GUIЕсли будет возможность, проверяй, пожалуйста, на CrossOver - вдруг заработает :)



просто на лето затормозил, т.к. дача, огород и не до этого.А я наоборот на даче по вечерам пишу демки :)

Titus
18.06.2021, 23:12
Если будет возможность, проверяй, пожалуйста, на CrossOver - вдруг заработает
У меня нет мака, чтобы проверять)

- - - Добавлено - - -


А я наоборот на даче по вечерам пишу демки
Видимо, ты днем не вкалываешь на огороде)

Manwe
19.06.2021, 11:26
У меня нет мака, чтобы проверять)Могу дать для тестирования.


Видимо, ты днем не вкалываешь на огороде)Я как-то потратил 3 дня и сделал высокие тёплые грядки и засыпал мульчой, они всё лето сами себя рыхлили и поливали, а я отдыхал.
Лайфхак :)

Titus
19.06.2021, 13:33
Я как-то потратил 3 дня и сделал высокие тёплые грядки и засыпал мульчой, они всё лето сами себя рыхлили и поливали, а я отдыхал.
Лайфхак
Видимо, ты в параллельной реальности живешь)

Есть еще парники, которые сами себя не польют и не откроют как надо)

- - - Добавлено - - -


Могу дать для тестирования.
Летом-то точно в эти дела влезать не буду эмуляторные.

Manwe
03.07.2021, 15:19
S_V_B скомпилировал проигрыватель MOD/STM авторства RDC. Я запустил на эмуляторе, посмотрел что он пишет в LPT-порт 161032. Нужна поддержка Covox в эмуляторе! А то как же так? Софт под Covox есть, а послушать не на чем.

xolod
03.07.2021, 15:33
А на своем реале не пробовал?

Titus
03.07.2021, 15:38
Нужна поддержка Covox в эмуляторе! А то как же так? Софт под Covox есть, а послушать не на чем.
Для поддержки ковокса нужна в принципе поддержка звука в эмуляторе, а ее пока нет.

nzeemin
25.12.2022, 16:39
Titus, пытаюсь дописать свой эмулятор Союз-Неона до хоть какого-то рабочего состояния. Сравниваю с твоим.

Вот такой вопрос - это бага эмулятора или так и задумано? Проверял на EmuStudio 0.15n.
Запускаем эмулятор, на проверке памяти выходим в отладчик - F8.

Доходим до 001000 (0x0200) в режиме USER:


r200
HALT MMU: 000, 000, 000, 000, 002, 004, 000, 000
USER MMU: 006, 008, 00A, 00C, 002, 004, 000, 000
SNDC2R = 36458
PPIC = IH-0
PPIB = HI10
PIC_IRQM = --5-----
PICMR = 76543210

R0=8202 R4=0000 PSW =0000 0200 15DF 0003 F86A MOV #$0003,(#$F86A)
R1=0000 R5=0000 PSW'=0000 0206 00A0 NOP
R2=0000 SP=0000 PC' =0200 0208 15C2 040E MOV #$040E,R2
R3=0000 PC=0200 Ctr=047188 020C 11C6 MOV PC,SP
Flags = U-------- CPU (Main) 020E 09DF 0402 JSR (#$0402)

Дальше как видим обращение к эмулируемому регистру -- как мы знаем, на NOP будет прерывание.

Делаем шаг:


m0
HALT MMU: 000, 000, 000, 000, 002, 004, 000, 000
USER MMU: 006, 008, 00A, 00C, 002, 004, 000, 000
SNDC2R = 36467
PPIC = IH-0
PPIB = HI10
PIC_IRQM = --5-----
PICMR = 76543210

R0=8202 R4=0000 PSW =0180 0368 11BF 7CA2 MOV SP,@($800E)
R1=0000 R5=0000 PSW'=0000 036C 17C6 800E MOV (#$800E),SP
R2=0000 SP=0000 PC' =0200 0370 1166 PUSH R5
R3=0000 PC=0368 Ctr=047152 0372 1126 PUSH R4
Flags = HP------- CPU (Main) 0374 10E6 PUSH R3

Странно, что мы сразу провалились в прерывание, не дойдя до NOP.

Теперь пропустим всё прерывание:


r200
HALT MMU: 000, 000, 000, 000, 002, 004, 000, 000
USER MMU: 006, 008, 00A, 00C, 002, 004, 000, 000
SNDC2R = 320
PPIC = IH-0
PPIB = H-10
PIC_IRQM = --------
PICMR = 76543210

R0=8202 R4=0000 PSW =0000 0200 15DF 0003 F86A MOV #$0003,(#$F86A)
R1=0000 R5=0000 PSW'=0000 0206 00A0 NOP
R2=0000 SP=0000 PC' =0200 0208 15C2 040E MOV #$040E,R2
R3=0000 PC=0200 Ctr=045404 020C 11C6 MOV PC,SP
Flags = U-------- CPU (Main) 020E 09DF 0402 JSR (#$0402)

Мы опять на адресе 0200.
Делаем два шага:


m0
HALT MMU: F86, 000, 000, 000, 002, 004, 000, 000
USER MMU: 006, 008, 00A, 00C, 002, 004, 000, 000
SNDC2R = 334
PPIC = IH-0
PPIB = H--0
PIC_IRQM = --------
PICMR = 76543210

R0=8202 R4=0000 PSW =0000 0206 00A0 NOP
R1=0000 R5=0000 PSW'=0000 0208 15C2 040E MOV #$040E,R2
R2=0000 SP=0000 PC' =0200 020C 11C6 MOV PC,SP
R3=0000 PC=0206 Ctr=045350 020E 09DF 0402 JSR (#$0402)
Flags = U-------- CPU (Main) 0212 0A00 CLR R0


m0
HALT MMU: F86, 000, 000, 000, 002, 004, 000, 000
USER MMU: 006, 008, 00A, 00C, 002, 004, 000, 000
SNDC2R = 343
PPIC = IH-0
PPIB = H--0
PIC_IRQM = --------
PICMR = 76543210

R0=8202 R4=0000 PSW =0180 0368 11BF 7CA2 MOV SP,@($800E)
R1=0000 R5=0000 PSW'=0000 036C 17C6 800E MOV (#$800E),SP
R2=0000 SP=0000 PC' =0206 0370 1166 PUSH R5
R3=0000 PC=0368 Ctr=045314 0372 1126 PUSH R4
Flags = HP------- CPU (Main) 0374 10E6 PUSH R3

Теперь мы упали в прерывание на NOP, причём в PPIB по-другому выставлены EF0/EF1.

Это точно правильное поведение, что на одну запись в эмулируемый регистр мы отрабатываем прерывание дважды?

Возможно, первое прерывание здесь связано с выставленным INT5 в PIC, но там же маска его запрещает, нет?

Alex_K, если радиальный сигнал HALT установлен до перехода в режим USER, то при переходе в USER сразу отрабатывает прерывание HALT, или сначала успевает отработать одна команда и только затем отрабатывает прерывание HALT?

Тут же ещё всё сложнее. Переход в режим USER тут выполняется командой STEP, после которой не происходит обработки прерываний до выполнения следующей команды. Тогда выглядит так, что Titus это не учитывает.

Alex_K
25.12.2022, 18:51
@Alex_K, если радиальный сигнал HALT установлен до перехода в режим USER, то при переходе в USER сразу отрабатывает прерывание HALT, или сначала успевает отработать одна команда и только затем отрабатывает прерывание HALT?

Тут же ещё всё сложнее. Переход в режим USER тут выполняется командой STEP, после которой не происходит обработки прерываний до выполнения следующей команды. Тогда выглядит так, что Titus это не учитывает.

nzeemin, собственно на этот вопрос вы сами и ответили. После STEP обязательно выполнится команда нового процесса. А вот после START ничего не выполнится и сразу же перейдём в режим HALT. Тут ещё надо учитывать, что у радиального прерывания HALT приоритет равен пяти и если есть более приоритетные прерывания, то выполнятся они. Ну при START прерываний TRAP4 и TRAP10 не будет, а вот T-разряд и ACLO могут быть.

Titus
26.12.2022, 01:10
Это точно правильное поведение, что на одну запись в эмулируемый регистр мы отрабатываем прерывание дважды?
Я думаю, что Alex_K уже все прояснил)

- - - Добавлено - - -

Только почему ты делаешь шаг командой 'm0'? Шаг - это просто Enter. А m0 - это запись памяти в файл.

Alex_K
26.12.2022, 20:35
Я думаю, что @Alex_K уже все прояснил)
Alex_K прояснил про то, как работает команда STEP, а не почему прерывание возникает дважды.

Titus
26.12.2022, 23:58
Alex_K прояснил про то, как работает команда STEP, а не почему прерывание возникает дважды.
Не могу так сказать. Возможно, это связано с особенностями отладчика, и без него все работает как надо. Давно не занимался ПК11, не помню.

nzeemin
31.12.2022, 18:02
Titus, ещё вопрос про загрузку с дискеты.
У себя я вижу что загружается 512 байт первого сектора, но загрузчик выглядит довольно странно. Так и задумано? Или этот код вообще не предназначен для исполнения?


001000 NOP
001002 BR 001036
001004 HALT
001006 HALT
001010 HALT
001012 HALT
001014 HALT
001016 HALT
001020 HALT
001022 HALT
001024 HALT
001026 HALT
001030 HALT
001032 BIC (R4), (R0)+
001034 MOVB 000400(R0), (R0)+
001040 JMP @#000574
001044 HALT
001046 HALT
001050 HALT
001052 HALT

Titus
31.12.2022, 18:08
Titus, ещё вопрос про загрузку с дискеты.
У себя я вижу что загружается 512 байт первого сектора, но загрузчик выглядит довольно странно. Так и задумано? Или этот код вообще не предназначен для исполнения?
Тоже не могу пояснить, потому что основательно подзабыл.
Думаю, Alex_K и тут лучше меня подскажет.

dk_spb
31.12.2022, 18:31
Я, конечно, в этом ничего не понимаю, но разве после

001000 NOP
001002 BR 001036

мы попадаем на 1034, а не на 1036
001034 MOVB 000400(R0),

Hunta
31.12.2022, 19:27
1036 - BR 1040
1040 - JMP @#000574

И вообще это этот код должен грузиться с нуля, а не с 1000

- - - Добавлено - - -

И вдогонку - вообще сильно похоже на обычный код в начале первичного загрузчика

nzeemin
31.12.2022, 20:48
1036 - BR 1040
1040 - JMP @#000574

И вообще это этот код должен грузиться с нуля, а не с 1000

- - - Добавлено - - -

И вдогонку - вообще сильно похоже на обычный код в начале первичного загрузчика

Ха, действительно, в эмуляторе Титуса он грузится с нуля, и у меня тоже.
Спасибо! Буду копать дальше.

Alex_K
31.12.2022, 21:03
У себя я вижу что загружается 512 байт первого сектора, но загрузчик выглядит довольно странно. Так и задумано?
В первичном загрузчике в трёх словах перед точкой входа записаны слова конфигурации - на какой шине используется (QBUS, UNIBUS и т.д. и т.п.), сколько сторон. При этом третье слово может быть командой 400(BR ENTRY) - одна сторона, либо 100400(BMI ENTRY) - две стороны. Вот на это третье слово и осуществляется переход.

- - - Добавлено - - -

Вдогонку, а как у СОЮЗ-НЕОН буфер считывается? Он маппируется в память или последовательно считывается через какой-то регистр? Если считывается через регистр, то как сбрасывается счетчик буфера?

nzeemin
31.12.2022, 21:11
Вдогонку, а как у СОЮЗ-НЕОН буфер считывается? Он маппируется в память или последовательно считывается через какой-то регистр? Если считывается через регистр, то как сбрасывается счетчик буфера?

Как я понял, загрузка из сектора диска в один из четырёх буферов идёт автоматически, нужно только выбрать текущий буфер.
А дальше буфер процессором вычитывается последовательным байтовым чтением регистра HD.BUFF:


013504 MOVB (R0), (R1)+
013506 MOVB (R0), (R1)+
013510 SOB R3, 013504

Alex_K
31.12.2022, 21:22
Как я понял, загрузка из сектора диска в один из четырёх буферов идёт автоматически, нужно только выбрать текущий буфер.
Вроде в ТО написано, что буфер общий для дисковода и MFM-винчестера. И какой адрес этого буфера?

nzeemin
31.12.2022, 21:33
Вроде в ТО написано, что буфер общий для дисковода и MFM-винчестера. И какой адрес этого буфера?

Насколько я понимаю, буфер действительно общий для дисковода и винчестера.
И это совершенно отдельные 2К на отдельной 537РУ10, на память не смаплена, доступ только через регистр HD.BUFF.


4.3.8. Контроллер НГМД/НЖМД

Контроллер совмещает в себе функции управления НГМД (1─2
накопителя) и НЖМД (1 устройство). Управление и обмен данными с
НГМД осуществляется БИС КР1818ВГ72А (D59). Аналогичные функции для
НЖМД выполняет БИС КМ1809ВГ7 (D62). Контроллер имеет совмещенную
шину для всех подключаемых накопителей. Контроллер также включает
в себя буферную память 2К байт на основе БИС 537РУ10 (D61),
счетчик адреса буферной памяти К561ИЕ10 (D60), а также БИС ПЛМ
(D63:D67). Контроллер подключен к системной шине адресаеданных
через буфер КР1533АП6 (D58).


Переключение с дисковода на винчестер происходит установкой бита 3 регистра hd.sdh = 161054.

Мы сейчас по эмулятору двигаемся вместе с xolod, он аппаратные вещи раскапывает. Может ещё что подскажет по части буферов.

Alex_K
31.12.2022, 21:55
Переключение с дисковода на винчестер происходит установкой бита 3 регистра hd.sdh = 161054.
Хотя вроде исходники ПЗУ были, если что, то наверное там можно посмотреть.

А так интересно, когда сбрасывается счётчик буфера, автоматически после операции чтения или его как-то через регистр сбрасывают. Также перед записью его надо заполнить.

nzeemin
01.01.2023, 21:05
В первичном загрузчике в трёх словах перед точкой входа записаны слова конфигурации - на какой шине используется (QBUS, UNIBUS и т.д. и т.п.), сколько сторон. При этом третье слово может быть командой 400(BR ENTRY) - одна сторона, либо 100400(BMI ENTRY) - две стороны. Вот на это третье слово и осуществляется переход.

А есть спецификации на это - слова/биты которые имеют особое значение в первичном загрузчике?

Продвинулся чуть дальше.
Сначала считался 1-й сектор 0-й дорожки - первичный загрузчик.
Затем 3-й сектор 0-й дорожки.

Alex_K
01.01.2023, 21:27
А есть спецификации на это - слова/биты которые имеют особое значение в первичном загрузчике?
Да вроде нет, они там так чисто информационные.

Продвинулся чуть дальше.
Сначала считался 1-й сектор 0-й дорожки - первичный загрузчик.
Затем 3-й сектор 0-й дорожки.
Вторичный загрузчик занимает на нулевой дорожке 3-й, 4-й, 5-й и 6-й сектора.

Вот тут и вопрос. Насколько я понимаю, контроллер считывает сектор в буфер и устанавливает в своем регистре статуса готовность. Далее этот буфер должна считать программа. А вот как далее - даётся команда на чтение следующего сектора или контроллеру можно дать задание на чтение нескольких секторов? Доку на контроллер дисковода пока не читал.

nzeemin
01.01.2023, 21:35
Если вдруг кому-то интересно -- первичный загрузчик, режим USER:


000000 NOP
000002 BR 000036
000036 BR 000040
000040 JMP @#000574
000574 MOV #010000, SP
000600 MOV @#177130, -(SP)
000604 BIC #177774, (SP)
000604 BIC #177774, (SP)
000610 MOV (SP), 000332
000614 SWAB 000332
000620 MOV #000002, R0
000624 MOV #002000, R1
000630 MOV #001000, R2
000634 CALL 000210
000210 NOP
000212 MOV #000010, 000316
000220 MOV R0, 000330
000224 MOVB @#177130, 000333
000232 BIC #176377, 000332
000240 BISB #000010, 000333
000246 MOV R2, 000334
000252 MOV R1, 000336
000256 MOV PC, R0
000260 ADD #000050, R0
000264 MOV R0, @#177130
000270 NOP
000272 TSTB @#177130
000276 BPL 000272
000300 NOP
000302 MTPS #000000
000306 TSTB @#177131
000312 BEQ 000326
000326 RETURN
000640 MOV #000210, @#004730
000646 MOV #023040, @#004716
000654 MOV (SP)+, @#004722
000660 JMP @#001000

Дальше исполняется код из 3-го сектора:


001000 MOV #003336, @#000100
001006 CLR @#000102
001012 CLR R3
001014 MOV (R3), 004734
001020 CLR (R3)+
001024 MOV SP, #000000
001030 MOV #001104, (R3)
001034 MOV (R3), @#000010
001040 unknown 000007 -- MFPT -- TRAP 10
001104 TST 003636
001110 BMI 001152
...


- - - Updated - - -


Да вроде нет, они там так чисто информационные.

Вторичный загрузчик занимает на нулевой дорожке 3-й, 4-й, 5-й и 6-й сектора.

Вот тут и вопрос. Насколько я понимаю, контроллер считывает сектор в буфер и устанавливает в своем регистре статуса готовность. Далее этот буфер должна считать программа. А вот как далее - даётся команда на чтение следующего сектора или контроллеру можно дать задание на чтение нескольких секторов? Доку на контроллер дисковода пока не читал.

Спасибо за инфу. Пока у меня читается только 3-й сектор, буду смотреть почему.
Про то как управляется/работает контроллер - инфы пока мало. Есть конечно отдельные спеки на 8272A и WD1010, но то как работает именно Неон-овский совмещённый контроллер - это только из исходников, плюс часть по железу определили, но всё ещё многое непонятно.

- - - Updated - - -

По документации на 8272A - да, там есть режим "Multi-Sector Read Operation" - когда за одним сектором сразу автоматически читается следующий, надо разбираться в деталях. Завершение чтения секторов обозначается передачей сигнала Terminal Count (TC).

Alex_K
01.01.2023, 21:58
По документации на 8272A - да, там есть режим "Multi-Sector Read Operation" - когда за одним сектором сразу автоматически читается следующий, надо разбираться в деталях.
Так там всё-таки стоит 1810ВГ72А, а не 1818ВГ72А из ТО? А то про 1818ВГ72А ничего не нашёл.

nzeemin
01.01.2023, 22:12
Так там всё-таки стоит 1810ВГ72А, а не 1818ВГ72А из ТО? А то про 1818ВГ72А ничего не нашёл.

В ТО тоже в двух местах по-разному:


КР1810ВГ72А (161070─161076)
FD.CSR ═ 161070
FD.BUF ═ 161072
FD.CNT ═ 161076
─ контроллер накопителя на гибком магнитном диске.

Titus
01.01.2023, 22:42
Вот, как у меня FDD сделан в эмуляторе.

Понятно, что я его не эмулировал целиком, а только то, что было не обходимо для работоспособности FDD.
И как это работает, я уже не помню)




static struct { // Определить структуру, описывающую дисководы
UINT8 Track, // Номер трека (00..79, при over-позицировании > 79)
Side, // Сторона (0 - нижняя головка, 1 - верхняя головка)
Motor, // Мотор (00 - включен, иначе выключен)
PrevMotor, // Предыдущее состояние мотора (для иконок дискет)
Mode, // Режим (00 - нет чтения/записи, 01 - чтение, 02 - запись)
Sector; // Текущий сектор (0..9)
UINT8 *ImagePTR; // Указатель на образ диска (образ 819200 байт)
} Floppy[2];

static UINT8 FDD_DataBuf[2048]; // Буфер для сектора HDD/FDD
static UINT32 FDD_DataBufAdr; // Указатель адреса в буферном ОЗУ контроллера HDD/FDD
static UINT8 FDD_ComDim[256]; // Буфер для команд ввода-вывода
static UINT8 FDD_ComAdr; // Указатель на текущий адрес в массиве данных ввода-вывода
static UINT8 FDD_ComLen; // Оставшееся число байт до конца пакета
static UINT8 *FDD_DataAdr; // Указатель на массив сектора в памяти
static UINT32 FDD_DataPTR = 0; // Позиция внутри сектора 0..511

static const MaxTrack = 79; // Максимальный разрешенный номер трека

static UINT8 FD_CSR = 0x80; // Регистр статуса FDD
// Бит 7: 0 - контроллер не готов, 1 - контроллер готов
// Бит 6: 0 - обмен по чтению, 1 - обмен по записи

static char FDDImageNames[4][1024]; // Имена файлов для 4-х образов дисков




static UINT16 FASTC CPU_RdW_HD_BUF(void) // hd.buf
{
UINT8 Byte;

//printf("Read word from CPU register HD.BUF from location PC=0x%X\n",
// (UINT16)CPU->l.PC);

Byte = FDD_DataBuf[FDD_DataBufAdr & 0x07FF]; // Чтение байта из буферного ОЗУ контроллера HDD/FDD

FDD_DataBufAdr++;

return(Byte);
}



static UINT16 FASTC CPU_RdW_HD_CSR(void) // hd.csr
{
//printf("Read word from CPU register HD.CSR from location PC=0x%X\n",
// (UINT16)CPU->l.PC);

FDD_DataBufAdr = 0; // [T] Сброс адресного указателя буферного ОЗУ
// (пока что считаем, что он сбрасывается при чтении hd.csr

return(0x41); // Первичная готовность да, вторичная - нет
}





static UINT16 FASTC CPU_RdW_FD_BUF(void) // fd.buf
{
UINT8 Byte = 0;

Byte = FDD_ComDim[FDD_ComAdr++]; // Взять байт из буфера

if (FDD_ComAdr == FDD_ComLen) // Если конец пакета, то
{
switch (FDD_ComDim[0])
{
case 0x08: // Sence Interrupt Status (Опрос состояния)
// FDDNum = FDD_ComDim[1] & 0x3; // FDDNum - номер дисковода

// Floppy[FDDNum].Track = 0; // Установиться на трек 00

FD_CSR = 0x80; // Установить готовность записи данных в контроллер
FDD_ComAdr = 0; // Обнулить указатель адреса в буфере обмена

break;

case 0x45: // Write Data MFM

FD_CSR = 0x80; // Установить готовность записи данных в контроллер
FDD_ComAdr = 0; // Обнулить указатель адреса в буфере обмена
break;

case 0x46: // Read Data MFM

FD_CSR = 0x80; // Установить готовность записи данных в контроллер
FDD_ComAdr = 0; // Обнулить указатель адреса в буфере обмена
break;

default:
printf ("WARNING FDD 002!!!\n");
}
}

//printf("Read word 0x%02X from CPU register FD.BUF from location PC=0x%X\n",
// Byte, (UINT16)CPU->l.PC);

return(Byte);
}



static void FASTC CPU_WrW_HD_CSR(UINT16 Data) // [T] hd.csr
{
//printf("Write word 0x%04X to unrealized CPU register HD.CSR from location PC = 0x%X\n",
// Data, (UINT16)CPU->l.PC);

if (Data == 0x0010) // [T] Если записали 0x0010 в порт, то
PIC_IRQM |= 0x02; // дать запрос на прерывание от FDD/HDD
// (чтобы контроллер отстал и не тормозил)
return;
}


static void FASTC CPU_WrW_FD_BUF(UINT16 Data) // [T] fd.buf
{
UINT8 Byte = (UINT8)Data,
FDDNum,
BCnt;

//printf("Write word 0x%04X to CPU register FD.BUF from location PC = 0x%X\n",
// Data, (UINT16)CPU->l.PC);

if (FDD_ComAdr == 0) // Если адрес в буфере обмена = 0, то код команды
{

switch (Byte)
{
case 0x03: // Specify (Задание параметров)
// printf("FDD Command: Specify\n");

FDD_ComLen = 3; // Длина команды

FDD_ComDim[0] = Byte; // Записать команду в начало буфера
break;

case 0x07: // Recalibrate (Трек-0)
//printf("FDD Command: Track-0\n");

FDD_ComLen = 2; // Длина команды

FDD_ComDim[0] = Byte; // Записать команду в начало буфера
break;

case 0x08: // Sence Interrupt Status (Опрос состояния)
// printf("FDD Command: Sence Status\n");

FDD_ComLen = 3; // Длина команды

FDD_ComDim[0] = Byte; // Записать команду в начало буфера

FDD_ComDim[1] = 0x20; // Записать байт корректного результата в буфер ($20)
FDD_ComDim[2] = 0; // (Остальные байты не опрашиваются)

FD_CSR = 0xC0; // Установить готовность чтения данных из контроллера
break;

case 0x0F: // Seek (Перемещение)
// printf("FDD Command: Seek\n");

FDD_ComLen = 3; // Длина команды

FDD_ComDim[0] = Byte; // Записать команду в начало буфера
break;

case 0x45: // Write Data MFM
// printf("FDD Command: Write Data MFM\n");

FDD_ComLen = 9; // Длина команды

FDD_ComDim[0] = Byte; // Записать команду в начало буфера
break;

case 0x46: // Read Data MFM
// printf("FDD Command: Read Data MFM\n");

FDD_ComLen = 9; // Длина команды

FDD_ComDim[0] = Byte; // Записать команду в начало буфера
break;

default:
printf("WARNING! FDD Command 0x%02X unrealized!\n", Byte);
}

FDD_ComAdr++; // Перейти к следующей позиции в буфере

}

else // Иначе блок данных команды
{
FDD_ComDim[FDD_ComAdr++] = Byte; // Записать байт в буфер

if (FDD_ComAdr == FDD_ComLen) // Если конец пакета, то
{

switch (FDD_ComDim[0])
{
case 0x03: // Specify (Задание параметров)

// Данные игнорируем // [T]

FDD_ComAdr = 0; // Обнулить указатель адреса в буфере обмена
break;

case 0x07: // Recalibrate (Трек-0)
FDDNum = FDD_ComDim[1] & 0x3; // FDDNum - номер дисковода

Floppy[FDDNum].Track = 0; // Установиться на трек 00

PIC_IRQM |= 0x02; // Запрос на прерывание от FDD/HDD
FDD_ComAdr = 0; // Обнулить указатель адреса в буфере обмена
break;

case 0x0F: // Seek (Перемещение)
FDDNum = FDD_ComDim[1] & 0x3; // FDDNum - номер дисковода

Floppy[FDDNum].Track = FDD_ComDim[2]; // Установиться на трек nn

//printf("FDD - Seek to track %d\n", Floppy[FDDNum].Track);

PIC_IRQM |= 0x02; // Запрос на прерывание от FDD/HDD
FDD_ComAdr = 0; // Обнулить указатель адреса в буфере обмена
break;

case 0x45: // Write Data MFM
FDDNum = FDD_ComDim[1] & 0x3; // FDDNum - номер дисковода

Floppy[FDDNum].Track = FDD_ComDim[2]; // Трек
Floppy[FDDNum].Side = (FDD_ComDim[1] >> 2) & 1; // Сторона
Floppy[FDDNum].Sector = FDD_ComDim[4]; // Сектор

if (Floppy[FDDNum].Track > MaxTrack) // Ограничить максимальный номер трека
Floppy[FDDNum].Track = MaxTrack;

if (Floppy[FDDNum].Sector > 10) // Ограничить максимальный номер сектора (1..10)
Floppy[FDDNum].Sector = 10;

FDD_ComDim[9] = 0x20; // Записать байт корректного результата в буфер ($20)
FDD_ComDim[10] = 0; // (Остальные байты не опрашиваются)
FDD_ComDim[11] = 0; //
FDD_ComDim[12] = 0; //
FDD_ComDim[13] = 0; //
FDD_ComDim[14] = 0; //
FDD_ComDim[15] = 0; //

BCnt = 4 - (FD_CNT & 0x3); // BCnt - счетчик секторов для записи за один раз

//printf("FDD - Write MFM: Drive: %d, Track: %d, Head: %d, Sector: %d, Len: %d\n",
// FDDNum, FDD_ComDim[2], FDD_ComDim[3], FDD_ComDim[4], BCnt);

// Самой записи пока нет

FDD_ComLen += 7; // Увеличить длину команды на 7 байт (ответ контроллера)

PIC_IRQM |= 0x02; // Запрос на прерывание от FDD/HDD
FD_CSR = 0xC0; // Установить готовность чтения данных из контроллера
break;

case 0x46: // Read Data MFM
FDDNum = FDD_ComDim[1] & 0x3; // FDDNum - номер дисковода

Floppy[FDDNum].Track = FDD_ComDim[2]; // Трек
Floppy[FDDNum].Side = (FDD_ComDim[1] >> 2) & 1; // Сторона
Floppy[FDDNum].Sector = FDD_ComDim[4]; // Сектор

if (Floppy[FDDNum].Track > MaxTrack) // Ограничить максимальный номер трека
Floppy[FDDNum].Track = MaxTrack;

if (Floppy[FDDNum].Sector > 10) // Ограничить максимальный номер сектора (1..10)
Floppy[FDDNum].Sector = 10;

FDD_ComDim[9] = 0x20; // Записать байт корректного результата в буфер ($20)
FDD_ComDim[10] = 0; // (Остальные байты не опрашиваются)
FDD_ComDim[11] = 0; //
FDD_ComDim[12] = 0; //
FDD_ComDim[13] = 0; //
FDD_ComDim[14] = 0; //
FDD_ComDim[15] = 0; //

BCnt = 4 - (FD_CNT & 0x3); // BCnt - счетчик секторов для чтения за один раз

// Копируем сектор в буферное ОЗУ контроллера
memcpy(FDD_DataBuf,
(Floppy[FDDNum].ImagePTR +
((Floppy[FDDNum].Track << 1) + (Floppy[FDDNum].Side & 0x1)) * 5120 +
((Floppy[FDDNum].Sector - 1) * 512)),
512 * BCnt);

//printf("FDD - Read MFM: Drive: %d, Track: %d, Head: %d, Sector: %d, Len: %d\n",
// FDDNum, FDD_ComDim[2], FDD_ComDim[3], FDD_ComDim[4], BCnt);

FDD_ComLen += 7; // Увеличить длину команды на 7 байт (ответ контроллера)

PIC_IRQM |= 0x02; // Запрос на прерывание от FDD/HDD
FD_CSR = 0xC0; // Установить готовность чтения данных из контроллера
break;

default:
printf ("WARNING FDD 001!!!\n");
}
}
}



return;
}


static void FASTC CPU_WrW_FD_CNT(UINT16 Data) // [T] fd.cnt
{
//printf("Write word 0x%04X to CPU register FD.CNT from location PC = 0x%X\n",
// Data, (UINT16)CPU->l.PC);

FD_CNT = (UINT8)Data;

if (Data == 0x10) // Инициализация регистров контроллера?
{
FD_CSR = 0x80; // Установить готовность записи данных в контроллер
FDD_ComAdr = 0; // Обнулить указатель адреса в буфере обмена
}

if ((Data >= 0) && (Data < 4)) // Если число в диапазоне от 0..3, то это
{ // число секторов (блоков) для чтения в буферное ОЗУ контроллера
;
}


return;
}

nzeemin
01.01.2023, 23:00
Titus, ты подтвердил мои догадки насчёт нижних двух бит FD.CNT


BCnt = 4 - (FD_CNT & 0x3);

Alex_K
01.01.2023, 23:40
FD.CNT ═ 161076
У самого контроллера адресный вход только один, потому регистры FD.CSR и FD.BUF относятся к нему непосредственно. А FD.CNT выполнен на внешней логике, тут уже схему надо смотреть.

nzeemin
01.01.2023, 23:53
У самого контроллера адресный вход только один, потому регистры FD.CSR и FD.BUF относятся к нему непосредственно. А FD.CNT выполнен на внешней логике, тут уже схему надо смотреть.

xolod говорит, нижние байты FD.CNT выбирают буфер.
Рабочая гипотеза у меня такая: данные читаются с указанного буфера до последнего (3-го). Если перед чтением выбран буфер #3 - читается один буфер (один сектор), если выбран буфер #0 - читаются четыре буфера.

Alex_K
02.01.2023, 00:03
@xolod (https://zx-pk.ru/member.php?u=5750) говорит, нижние байты FD.CNT выбирают буфер.
Рабочая гипотеза у меня такая: данные читаются с указанного буфера до последнего (3-го). Если перед чтением выбран буфер #3 - читается один буфер (один сектор), если выбран буфер #0 - читаются четыре буфера.
Тут лучше глянуть схему. А чтение запускается в каком режиме - DMA или INT?

xolod
02.01.2023, 00:18
А так интересно, когда сбрасывается счётчик буфера, автоматически после операции чтения или его как-то через регистр сбрасывают. Также перед записью его надо заполнить.

Счетчик буфера сбрасывается при записи любого значения в порт 161076.

- - - Добавлено - - -


Тут лучше глянуть схему. А чтение запускается в каком режиме - DMA или INT?

Ну я так понимаю что для ВГ72 это режим с чтением во внешний буфер, а для СPU его просто потом по байтово копирует в DRAM.

Alex_K
02.01.2023, 00:54
Ну я так понимаю что для ВГ72 это режим с чтением во внешний буфер
ВГ72 работает в режиме DMA или INT. При инициализации контроллера командой SPECIFY устанавливается режим работы, вместе со временами шага и загрузки головки.

Alex_K
02.01.2023, 12:36
ВГ72 работает в режиме DMA или INT. При инициализации контроллера командой SPECIFY устанавливается режим работы, вместе со временами шага и загрузки головки.
Осмотрел исходники процесса дисковода и винчестера. Там контроллер программируется в режиме DMA. Сами данные для команды:
f.spec: .byte 3, 12.*20+1, 2
Т.е. время шага равно 12 мс, время разгрузки головки 16 мс (1), время загрузки головки 2 мс (1) и режим DMA (бит 0 в последнем байте равен нулю). В режиме DMA задействуются сигналы DRQ, DACK, RD, WR - это уже надо смотреть схему, как это там реализовано. А так как объём буферного СОЗУ вроде бы только 2 КБайта, то за раз можно прочесть и записать максимум четыре сектора.

nzeemin
03.01.2023, 20:11
Titus, а как вы заполняете HR0/HR1 при обращении к регистрам эмуляции 174000..177677 ?
Код прерывания в BIOS для чтения сначала смотрит в HR0 и потом в HR1, для записи сначала в HR1 потом HR0.
Но отлаживая эмулятор, я понял что всегда надо писать адрес в HR0.

- - - Updated - - -

Alex_K, вы не разбирались с картой процессов в памяти? Если я правильно понимаю, она лежит по адресу 0x00217a и дальше. Хотелось бы понять что к чему, сделать отдельную вкладку со списком процессов в эмуляторе.

Titus
03.01.2023, 20:15
Titus, а как вы заполняете HR0/HR1 при обращении к регистрам эмуляции 174000..177677 ?
Код прерывания в BIOS для чтения сначала смотрит в HR0 и потом в HR1, для записи сначала в HR1 потом HR0.
Но отлаживая эмулятор, я понял что всегда надо писать адрес в HR0.

Не совсем понял вопрос, но вот то, что относится к этим регистрам:




static UINT16 HR0 = 0, // Регистры MMU HALT-режима
HR1 = 0,
HR2 = 0,
HR3 = 0,
HR4 = 0,
HR5 = 0,
HR6 = 0,
HR7 = 0;





CPU_RgRdWProc[0x0280] = CPU_RdW_HR0; // Регистр HR0 (чтение)
CPU_RgWrWProc[0x0280] = CPU_WrW_HR0; // Регистр HR0
CPU_RgRdWProc[0x0282] = CPU_RdW_HR1; // Регистр HR1 (чтение)
CPU_RgWrWProc[0x0282] = CPU_WrW_HR1; // Регистр HR1
CPU_RgRdWProc[0x0284] = CPU_RdW_HR2; // Регистр HR2 (чтение)
CPU_RgWrWProc[0x0284] = CPU_WrW_HR2; // Регистр HR2
CPU_RgRdWProc[0x0286] = CPU_RdW_HR3; // Регистр HR3 (чтение)
CPU_RgWrWProc[0x0286] = CPU_WrW_HR3; // Регистр HR3
CPU_RgRdWProc[0x0288] = CPU_RdW_HR4; // Регистр HR4 (чтение)
CPU_RgWrWProc[0x0288] = CPU_WrW_HR4; // Регистр HR4
CPU_RgRdWProc[0x028A] = CPU_RdW_HR5; // Регистр HR5 (чтение)
CPU_RgWrWProc[0x028A] = CPU_WrW_HR5; // Регистр HR5
CPU_RgRdWProc[0x028C] = CPU_RdW_HR6; // Регистр HR6 (чтение)
CPU_RgWrWProc[0x028C] = CPU_WrW_HR6; // Регистр HR6
CPU_RgRdWProc[0x028E] = CPU_RdW_HR7; // Регистр HR7 (чтение)
CPU_RgWrWProc[0x028E] = CPU_WrW_HR7; // Регистр HR7




printf("HALT MMU: %03X, %03X, %03X, %03X, %03X, %03X, %03X, %03X\nUSER MMU: %03X, %03X, %03X, %03X, %03X, %03X, %03X, %03X\n",
HR0 >> 4, HR1 >> 4, HR2 >> 4, HR3 >> 4, HR4 >> 4, HR5 >> 4, HR6 >> 4, HR7 >> 4,
UR0 >> 4, UR1 >> 4, UR2 >> 4, UR3 >> 4, UR4 >> 4, UR5 >> 4, UR6 >> 4, UR7 >> 4);




static UINT16 FASTC CPU_RdW_HR0(void) // HR0
{
//printf("Read word from CPU register HR0 from location PC=0x%X\n",
// (UINT16)CPU->l.PC);

PPI_B |= 0x0002; // EF1 = 1

PPI_B |= 0x0001; // EF0 = 1

return(HR0);
}

static UINT16 FASTC CPU_RdW_HR1(void) // HR1
{
//printf("Read word from CPU register HR1 from location PC=0x%X\n",
// (UINT16)CPU->l.PC);

return(HR1);
}

static UINT16 FASTC CPU_RdW_HR2(void) // HR2
{
//printf("Read word from CPU register HR2 from location PC=0x%X\n",
// (UINT16)CPU->l.PC);

return(HR2);
}

static UINT16 FASTC CPU_RdW_HR3(void) // HR3
{

//printf("Read word from CPU register HR3 from location PC=0x%X\n",
// (UINT16)CPU->l.PC);

return(HR3);
}

static UINT16 FASTC CPU_RdW_HR4(void) // HR4
{
//printf("Read word from CPU register HR4 from location PC=0x%X\n",
// (UINT16)CPU->l.PC);

return(HR4);
}

static UINT16 FASTC CPU_RdW_HR5(void) // HR5
{
//printf("Read word from CPU register HR5 from location PC=0x%X\n",
// (UINT16)CPU->l.PC);

return(HR5);
}

static UINT16 FASTC CPU_RdW_HR6(void) // HR6
{
//printf("Read word from CPU register HR6 from location PC=0x%X\n",
// (UINT16)CPU->l.PC);

return(HR6);
}

static UINT16 FASTC CPU_RdW_HR7(void) // HR7
{
//printf("Read word from CPU register HR7 from location PC=0x%X\n",
// (UINT16)CPU->l.PC);

return(HR7);
}







static void FASTC CPU_WrW_HR0(UINT16 Data) // [T] HR0
{
//printf("Write word 0x%04X to CPU register HR0 from location PC = 0x%X\n",
// Data, (UINT16)CPU->l.PC);

HR0 = Data;

return;
}

static void FASTC CPU_WrW_HR1(UINT16 Data) // [T] HR1
{
//printf("Write word 0x%04X to CPU register HR1 from location PC = 0x%X\n",
// Data, (UINT16)CPU->l.PC);

HR1 = Data;

return;
}

static void FASTC CPU_WrW_HR2(UINT16 Data) // [T] HR2
{
//printf("Write word 0x%04X to CPU register HR2 from location PC = 0x%X\n",
// Data, (UINT16)CPU->l.PC);

HR2 = Data;
SetMMU_Halt(2, Data);

return;
}

static void FASTC CPU_WrW_HR3(UINT16 Data) // [T] HR3
{
//printf("Write word 0x%04X to CPU register HR3 from location PC = 0x%X\n",
// Data, (UINT16)CPU->l.PC);

HR3 = Data;
SetMMU_Halt(3, Data);

return;
}

static void FASTC CPU_WrW_HR4(UINT16 Data) // [T] HR4
{
//printf("Write word 0x%04X to CPU register HR4 from location PC = 0x%X\n",
// Data, (UINT16)CPU->l.PC);

HR4 = Data;
SetMMU_Halt(4, Data);

return;
}

static void FASTC CPU_WrW_HR5(UINT16 Data) // [T] HR5
{
//printf("Write word 0x%04X to CPU register HR5 from location PC = 0x%X\n",
// Data, (UINT16)CPU->l.PC);

HR5 = Data;
SetMMU_Halt(5, Data);

return;
}

static void FASTC CPU_WrW_HR6(UINT16 Data) // [T] HR6
{
//printf("Write word 0x%04X to CPU register HR6 from location PC = 0x%X\n",
// Data, (UINT16)CPU->l.PC);

HR6 = Data;
SetMMU_Halt(6, Data);

return;
}

static void FASTC CPU_WrW_HR7(UINT16 Data) // [T] HR7
{
//printf("Write word 0x%04X to unrealized CPU register HR7 from location PC = 0x%X\n",
// Data, (UINT16)CPU->l.PC);

HR7 = Data;

return;
}

Alex_K
03.01.2023, 22:25
Alex_K, вы не разбирались с картой процессов в памяти? Если я правильно понимаю, она лежит по адресу 0x00217a и дальше. Хотелось бы понять что к чему, сделать отдельную вкладку со списком процессов в эмуляторе.
С этим не разбирался. Но на диске SOUZ-NEON_HD4_CLIB11_P16VPO_IMG.DSK есть виртуальный диск P16VP0.DSK, в нём программа, выводящая список процессов - PS.MAC.
Она небольшая:
.title processes listing

.include "sy:p16mac"


sbuf = 177566
start:
mov pc, sp
mov #str0, @#sbuf
nop
mov #str1, @#sbuf
nop
mfhlt #running
sub #p.sp, r0
mov r0, runn
mfhlt #pdptr
mov r0, next
10$:
inc num
mov #freepr,r0
11$:
mfhlt r0
cmp next, r0
beq 14$
tst r0
bne 11$


mov next, r0
call ttt
mov #s.num, @#sbuf ;.print #s.num
14$:
add #p.dsucc,next
mfhlt next
mov r0, next
bne 10$
clr pc


ttt:
;------------------------------------------------------------
mov r0, r3 ;desc. address
mov #s.da+6,r4
mov #6, r5
call oct
;------------------------------------------------------------
mov num, r3 ;process number
mov #s.num+2,r4
mov #2, r5
call dec0
;------------------------------------------------------------
mov next, r0 ;CPU time
add #p.tim1,r0
mfhlt r0
mov r0, r1
cmp runn, next
bne 10$
mfhlt #c.tim1
add r0, r1
10$:
clr r0
div #60., r0
mov r1, r3
mov #s.time+9.,r4
mov #2, r5
call dec
movb #':, -(r4)
mov r0, r1
beq 16$
clr r0
div #60., r0
mov r1, r3


mov #2, r5
call dec
mov r0, r3
beq 20$
movb #'., -(r4)
mov #2, r5
call dec
br 24$
16$:
movb #'0, -(r4)
movb #40, -(r4)
20$:
movb #40, -(r4)
movb #40, -(r4)
movb #40, -(r4)
24$:
;------------------------------------------------------------
mov #16., r5 ; process name
mov #s.name,r4
mov next, r1
add #p.name,r1
26$:
mfhlt r1
cmpb r0, #40
blo 30$ ;
; cmpb #176, r0
; bcs 30$
movb r0, (r4)+
dec r5
swab r0
cmpb r0, #40
blo 30$ ;
; cmpb #176, r0
; bcs 30$
movb r0, (r4)+
tst (r1)+
sob r5, 26$
br 40$
30$:
movb #40, (r4)+
sob r5, 30$
;------------------------------------------------------------
40$:
mov next, r0 ;priority
add #p.pri, r0
mfhlt r0
mov #40, r1
mov r0, r3
bpl 45$
neg r3
mov #'-, r1
45$:
mov #s.pri+6,r4
mov #5, r5
call oct0
movb r1, -(r4)
;------------------------------------------------------------
mov next, r0 ;process state
cmp r0, runn
bne 50$
mov #st.run,r0
br 60$
50$:
add #p.mask,r0
mfhlt r0
bit #m.run, r0
beq 51$
mov #st.wai,r0
br 60$
51$:
bit #m.tio, r0
beq 52$
mov #st.tim,r0
br 60$
52$:
tstb r0
beq 53$
mov #st.int,r0
br 60$
53$:
mov #st.io, r0
60$:
mov #s.stat,r1
movb (r0)+, (r1)+
movb (r0)+, (r1)+
movb (r0)+, (r1)+
movb (r0)+, (r1)+
;---------------------------------------------------------------------
mov next, r0 ;process memory size
add #p.mem, r0
mfhlt r0 ; map addr
clr low
clr high
mov r0, r1
beq 70$ ;no ram-map
mov #4, r5 ;low mem
62$:
mfhlt r1
com r0
63$:
rol r0
beq 64$
adc low
clc
br 63$
64$:
tst (r1)+
sob r5, 62$
MFHLT #MAPLEN ;
sub #4*2, r0 ;
asr r0 ;
mov r0, r5 ;low mem
65$:
mfhlt r1
com r0
66$:
rol r0
beq 67$
adc high
clc
br 66$
67$:
tst (r1)+
sob r5, 65$
asl low
asl low
asl high
asl high


mov #s.time-1,r4
movb #'k, -(r4)
mov high, r3
mov #3, r5
call dec0
movb #40, -(r4)
movb #40, -(r4)
movb #'k, -(r4)
mov low, r3
mov #3, r5
call dec0
movb #40, -(r4)
movb #40, -(r4)
movb #'k, -(r4)
mov low, r3
add high, r3
mov #3, r5
call dec0
br 80$
70$:
mov #s.nomem,r0
mov #s.mem, r1
72$: tstb (r0)
beq 80$
movb (r0)+, (r1)+
br 72$
;------------------------------------------------------------
80$:


return


.enabl lsb
oct: mov #8., exp
br 10$
dec: mov #10., exp
10$:
clr r2
div (pc)+, r2
exp: .blkw 1
bis #'0, r3
movb r3, -(r4)
mov r2, r3
sob r5, 10$
return
.dsabl lsb


.enabl lsb
oct0: mov #8., exp0
br 10$
dec0: mov #10., exp0
10$:
clr r2
div (pc)+, r2
exp0: .blkw 1
bis #'0, r3
movb r3, -(r4)
mov r2, r3
beq 20$
sob r5, 10$
15$:
return
20$:
dec r5
beq 15$
movb #40, -(r4)
br 20$


.dsabl lsb
runn: .word 0
num: .word 0
low: .word 0
high: .word 0
next: .word pdptr
st.run: .ascii /Run /
st.wai: .ascii /Wait/
st.io: .ascii "I/O "
st.int: .ascii /Int /
st.tim: .ascii /Tim /
str0:
.ascii <33>/[2J/<33>/[H/
.asciz /Num Name Descriptor Priority State Mem: Low High CPU Time/
.asciz /Num Name Desc.addr Priority State Mem Low High CPU Time/
str1:
.asciz /--- ---------------- ------ ------ ---- ---- ---- ---- --------/
s.num: .ascii / 1 /
s.name: .ascii /Operating system /
s.da: .ascii /102062 /
s.pri: .ascii /-00001 /
s.stat: .ascii /Run /
s.mem: .ascii /768k 12k 160k /
s.time: .asciz / 2.58.03 /
s.nomem:.asciz / No memory map /
.even
.end start

- - - Добавлено - - -


Код прерывания в BIOS для чтения сначала смотрит в HR0 и потом в HR1, для записи сначала в HR1 потом HR0.
Но отлаживая эмулятор, я понял что всегда надо писать адрес в HR0.
Вроде бы при обработке прерывания HALT всегда сначала смотрится HR1, потом HR0:

;--------------------------------5$: ;
mov ppib, r0 ;
bis #340, r0 ;
mtps r0 ;
bvc write ;
bcc read ;
beq ioint ;
br hlt ;
;------------------------------------------------
read: ;
mov hr1, r1 ;
beq 100$ ;
mov -20000(r1),r0 ; l.rda
beq trap4. ;
bpl 100$ ;
add #4, r0 ;
movb #rd, (r0) ;
call $$put1 ;
;................................
100$: mov hr0, r1 ;
mov -20000(r1),r0 ; l.rda
beq trap4. ;
bpl h.int ;
add #4, r0 ;
movb #rd, (r0) ;
br $$put0 ;
;----------------------------------------
write: mov hr1, r1 ;
beq 10$ ;
bic #30000, r1 ; l.reg
mov 10000(r1),r0 ; l.rda
bpl jrq ;
bic (r0)+, (r1) ; l.reg
bis (r0)+, (r1) ;
movb #wr+rd, (r0) ;
call $$put1 ;
;................................
10$: mov hr0, r1 ;
bic #30000, r1 ; l.reg
mov 10000(r1),r0 ; l.rda
bpl jrq ;
bic (r0)+, (r1) ;
bis (r0)+, (r1) ;
movb #wr+rd, (r0) ;
А так интересно, если не установлен EF1, то запись, если не установлен EF0, то чтение. Хотя логика может быть и инверсной.

nzeemin
04.01.2023, 00:48
А так интересно, если не установлен EF1, то запись, если не установлен EF0, то чтение. Хотя логика может быть и инверсной.

Из схемы нам известно, что биты EF0 и EF1 - инверсные, бит IOINT - прямой.
По записи снимаются биты EF0 и EF1, по чтению снимается бит EF0.

Alex_K
04.01.2023, 11:30
Из схемы нам известно, что биты EF0 и EF1 - инверсные, бит IOINT - прямой.
По записи снимаются биты EF0 и EF1, по чтению снимается бит EF0.
А уже есть расшифровка всех ПЛМ? Просто схема построена на множестве ПЛМ, а расшифровку я видел только P1.

nzeemin
05.01.2023, 17:29
Очень странно.
По словам xolod, по схеме, перехват (эмуляция) регистров работает только в диапазоне от 174000 до 177677 (в отличие от того что написано в ТО).
Здесь на форуме уже обсуждалось что если самые верхние регистры ловить, то эмулятор не будет работать.
Но я вижу, что эмулятор Titus реагирует на обращение к адресу $FFF0:


032C 00A0 NOP
032E 5448 OR (R1)+,(R0)
0330 0BDF FFF0 TST (#$FFF0)
0368 11BF 7CA2 MOV SP,@($800E) <-- это заход в прерывание HALT
036C 17C6 800E MOV (#$800E),SP

Alex_K
05.01.2023, 17:40
Titus, а как вы заполняете HR0/HR1 при обращении к регистрам эмуляции 174000..177677 ?
Код прерывания в BIOS для чтения сначала смотрит в HR0 и потом в HR1, для записи сначала в HR1 потом HR0.
Но отлаживая эмулятор, я понял что всегда надо писать адрес в HR0.
По ПЛМ получается, что EF0 устанавливается при любом обращении к регистру эмуляции, а EF1 только при операции записи. Там ещё довольно приличная схема удержания этих сигналов, очень много условий.

- - - Добавлено - - -


Очень странно.
По словам @xolod, по схеме, перехват (эмуляция) регистров работает только в диапазоне от 174000 до 177677 (в отличие от того что написано в ТО).
Здесь на форуме уже обсуждалось что если самые верхние регистры ловить, то эмулятор не будет работать.
Но я вижу, что эмулятор @Titus реагирует на обращение к адресу $FFF0:
nzeemin, а чтобы решить этот вопрос, то надо посмотреть таблицу эмулируемых регистров в памяти, а также на реальной машине запустить IOSCAN. Да, я тоже видел в EmuStudio много разных регистров в конце памяти. Кстати IOSCAN лучше запустить на голой системе, чтобы лишние процессы не подгрузились, прервать исполнение STARTS.COM при загрузке двойным нажатием УПР+C.

nzeemin
05.01.2023, 18:15
Попробовал посмотреть регистры через пульт, но там какое-то ограничение в области эмуляции - видимо, показывает только те регистры, на которые выставлена эмуляция процессами. Причём это не зависит от режима пульта User/Halt:

https://pic.maxiol.com/thumbs2/1672931498.1565642383.photo2023010518030.jpg (https://pic.maxiol.com/?v=1672931498.1565642383.photo2023010518030.jpg&dp=2)

- - - Updated - - -

Alex_K, не подскажете где взять подходящий IOSCAN?
И да, если нужен какой-то эксперимент на реальной машине - я могу провести.

Alex_K
05.01.2023, 18:28
Здесь на форуме уже обсуждалось что если самые верхние регистры ловить, то эмулятор не будет работать.
Не будет работать, если эмулировать регистр 0177776, который PSW на многих PDP-11. Тогда RT-11 не будет применять команд MTPS/MFPS, а будет работать через этот регистр.

- - - Добавлено - - -


Alex_K, не подскажете где взять подходящий IOSCAN?
Загрузочный диск для Неона с IOSCAN - https://disk.yandex.ru/d/P62_WYLabU012w. В EmuStudio работает.

nzeemin
05.01.2023, 18:42
Результат IOSCAN на реале:

https://pic.maxiol.com/thumbs2/1672933295.1565642383.photo2023010518401.jpg (https://pic.maxiol.com/?v=1672933295.1565642383.photo2023010518401.jpg&dp=2)

Alex_K
05.01.2023, 19:00
Результат IOSCAN на реале:
Понятно, IOSCAN надо дорабатывать, вставлять команду NOP после команды теста регистра. Попробую поискать исходники и сделать новую версию.

- - - Добавлено - - -


Результат IOSCAN на реале:

Понятно, IOSCAN надо дорабатывать, вставлять команду NOP после команды теста регистра. Попробую поискать исходники и сделать новую версию.
Файл заменил, по той же ссылке - https://disk.yandex.ru/d/P62_WYLabU012w. На образе диска и исходники, утилита от form.

nzeemin
05.01.2023, 19:22
Понятно, IOSCAN надо дорабатывать, вставлять команду NOP после команды теста регистра. Попробую поискать исходники и сделать новую версию.

Файл заменил, по той же ссылке - https://disk.yandex.ru/d/P62_WYLabU012w. На образе диска и исходники, утилита от form.

https://pic.maxiol.com/thumbs2/1672935710.1565642383.photo2023010519192.jpg (https://pic.maxiol.com/?v=1672935710.1565642383.photo2023010519192.jpg&dp=2)

Alex_K
05.01.2023, 19:29
https://pic.maxiol.com/thumbs2/1672935710.1565642383.photo2023010519192.jpg (https://pic.maxiol.com/?v=1672935710.1565642383.photo2023010519192.jpg&dp=2)
Интересно, зачем тогда Titus эмулирует целую кучу несуществующих регистров?

- - - Добавлено - - -

Кстати, когда Titus писал EmuStudio, то он спрашивал меня про адрес 0160000. Ведь RT-11 проверяет объём памяти по адрес 0170000, потому он эту ячейку исключил, а то RT-11 не загружалось.

nzeemin
05.01.2023, 19:34
Интересно, зачем тогда Titus эмулирует целую кучу несуществующих регистров?

Меня сейчас больше волнует вопрос - почему тогда его эмулятор грузит RT-11, а мой - нет. :clownface:

Alex_K
05.01.2023, 19:41
Меня сейчас больше волнует вопрос - почему тогда его эмулятор грузит RT-11, а мой - нет.
Надо знать, на каком месте спотыкается. Сперва идёт первичный загрузчик, потом четыре блока вторичного. Далее вторичный загрузчик просматривает каталог диска, ищет драйвер системного устройства, загружает его, загружает RMON, настраивает его, настраивает вектора. Ну и потом запуск системы.

nzeemin
05.01.2023, 19:58
Надо знать, на каком месте спотыкается. Сперва идёт первичный загрузчик, потом четыре блока вторичного. Далее вторичный загрузчик просматривает каталог диска, ищет драйвер системного устройства, загружает его, загружает RMON, настраивает его, настраивает вектора. Ну и потом запуск системы.

Мой эмулятор читает уже гораздо больше.
Но в терминал выводит только приветствие системы с номером версии. И в конце сваливается в отладчик на последовательном порту.
В аттаче - лог чтения + список файлов диска с номерами блоков.

В отладчик он выводит:


010172 000000 000000 000062 014202 161056 011324 000002 000000
PK11/12 _>

- - - Updated - - -

Alex_K, а может как-то сказываться скорость работы процессора? сейчас мой медленнее того что у Титуса раза в полтора.

Alex_K
05.01.2023, 20:14
В аттаче - лог чтения + список файлов диска с номерами блоков.
По логу могу сказать, что в конце вторичный загрузчик стал читать нулевые блоки всех драйверов и после проверки записывать данные драйверов в таблицу RMON. Последним прочёлся SL.SYS. Далее никакой информации. После этого вроде бы должен быть выход в систему с запуском STARTS.COM. Но это надо шагать отладчиком.

- - - Добавлено - - -


Alex_K, а может как-то сказываться скорость работы процессора? сейчас мой медленнее того что у Титуса раза в полтора.
Вряд ли, RT-11 должно быть по барабану, она и на более медленных машинах работает.

- - - Добавлено - - -

У SL.SYS в качестве подпрограммы проверки выступает вывод названия драйвера. Но для НЕОНа надпись немного пропатчили, она выводит только возврат каретки и перевод строки. А после вывода версии RT-11 курсор ещё проскакивает на следующую строку?

Titus
05.01.2023, 20:58
Интересно, зачем тогда Titus эмулирует целую кучу несуществующих регистров?
Я их не эмулирую. Вернее, на их месте стоят заглушки, из них читается 0.

Alex_K
05.01.2023, 21:00
Я их не эмулирую. Вернее, на их месте стоят заглушки, из них читается 0.
Но зачем они тогда есть?

Titus
05.01.2023, 21:06
Кстати, когда Titus писал EmuStudio, то он спрашивал меня про адрес 0160000. Ведь RT-11 проверяет объём памяти по адрес 0170000, потому он эту ячейку исключил, а то RT-11 не загружалось.

У меня все регистры, которых нет - это заглушки, из которых читается 0.
А так как при чтении из 0160000 это приводило к глюку, я по этому адресу сделал несуществующий регистр, который трапается. Мог бы и по всем другим адресам тоже сделать, но надобности в этом не возникло, т.к. все программы работают прекрасно. Особенно игры)

- - - Добавлено - - -


Но зачем они тогда есть?
Они не то, чтобы есть. Они по умолчанию у меня. Потому что при написании эмулятора мне было удобнее, чтобы из регистра, который должен быть, но который я еще не реализовал, прочитался бы 0, а при записи не было трапа.

- - - Добавлено - - -


Меня сейчас больше волнует вопрос - почему тогда его эмулятор грузит RT-11, а мой - нет. :clownface:
Потому что еще какие-то вещи работают не так, как нужно для запуска системы. Исправятся, и все заработает)

- - - Добавлено - - -


Alex_K, а может как-то сказываться скорость работы процессора? сейчас мой медленнее того что у Титуса раза в полтора.
Это сомнительно. Это же не в разы.

nzeemin
05.01.2023, 21:34
Нашёл почему выходит в отладчик, но это пока мало что даёт:
V.SUPR - прерывание по необслуживаемому вектору;

До кучи ещё, обнаружил что если остановиться на точке останова где-то в начале загрузки и затем продолжить - то приветствие RT11 выводится. А если не прерывать процесс эмуляции - то нет :clownface:

Чувствую, что уже не так много осталось доделать - поймать какие-то мелкие косяки и/или мои собственные непонимания.

Alex_K
05.01.2023, 21:44
Нашёл почему выходит в отладчик, но это пока мало что даёт:
V.SUPR - прерывание по необслуживаемому вектору;

До кучи ещё, обнаружил что если остановиться на точке останова где-то в начале загрузки и затем продолжить - то приветствие RT11 выводится. А если не прерывать процесс эмуляции - то нет :clownface:

Чувствую, что уже не так много осталось доделать - поймать какие-то мелкие косяки и/или мои собственные непонимания.
Собственно если нет какого-то вектора, то вот список:
;async interrupt vectors
dw v.init ,2 ;reset-instruction
dw v.flop ,2 ;floppy disk int
dw v.rcrd ,2 ;dl-receiver ready
dw v.trrd ,2 ;dl-transmitter ready
dw v.kbd ,2 ;keyboard request
dw v.scrn ,2 ;screen interrupt
dw v.prrd ,2 ;printer ready
dw v.slot ,2 ;request from slot

А вот и место, откуда вызывается, переход на метку supr:
;------------------------------------------------
h.int: ;
bit #4, ppib ;
beq schedule ;
ioint: mov #piccsr,r1 ;
mov #14, (r1) ;
clr r0 ;
bisb (r1), r0 ;
aslb r0 ;
bcc schedule ;
;
mov #40, (r1)+ ;eoi
aslb r0 ;
add #v.init,r0 ;
int4: mov (r0)+, r3 ;+2
beq supr ;
int5: bmi int10 ;
call (r3) ; call hlt-process
br schedule ;



Поставить точку останова, посмотреть, что в регистре R0 перед прибавлением v.init.

nzeemin
07.01.2023, 00:02
Подозреваю, что у меня что-то не то с реализацией VIRQ, хотя казалось бы всё сделал по инструкции.
Вот такая трасса выполнения, которая заканчивается инструкцией HALT:


U002100 NOP
U002102 MOV #000000, @#177546
002100 CPU HALT INT vector=000274 PC=001446 PSW=000600
H001446 MOV R5, @#100052
H001452 MOV R0, @#100040
H001456 MOV @#100146, R5
H001462 MOV (R5)+, R0
H001464 CMP (R5), R0
H001466 BNE 001512
H001470 BIC #000010, @#100036
H001476 BIS #000010, @#161034
H001476 GETPORT 161034 PPIC -> 000015
H001476 SETPORT 000015 -> (161034) PPIC 1101
H001504 CMP #100150, R5
H001510 BEQ 001536
H001512 MOV R0, @(R5)+
H001514 MOV -(R5), 000002(R0)
H001520 CLR -(R5)
H001522 SUB #100072, R5
H001526 MFUS
H001530 WCPC
H001532 MFUS
H001534 WCPS
H001536 MOV @#100040, R0
H001542 MOV @#100052, R5
H001546 STEP
U000000 HALT
000000 CPU HALT INT vector=000170 PC=001550 PSW=000600


Собственно как выполняю прерывание VIRQ -- сначала заносим в стек CPSW и CPC, затем (мы же не дождались ответа) - выполняем HALT mode interrupt по вектору 274.

Alex_K
07.01.2023, 01:41
Собственно как выполняю прерывание VIRQ -- сначала заносим в стек CPSW и CPC, затем (мы же не дождались ответа) - выполняем HALT mode interrupt по вектору 274.
Перед заносом в стек процессор принудительно переключается в режим USER, потому что VIRQ можно вызвать из HALT-режима с разрешёнными прерываниями. Хотя обратно на Неоне в него не вернуться.
Да и зря сбрасываете m_VIRQrq при обработке VIRQ, требование будет всегда, пока в порте PPIC не сбросят это требование. И неправильно реализована запись в PPIC, при сбросе бита 3 устанавливается требование VIRQ, а при установке не сбрасывается.

nzeemin
07.01.2023, 03:34
Перед заносом в стек процессор принудительно переключается в режим USER

Спасибо! Теперь проходит немного дальше - после первых блоков .SYS-файлов читает ещё два блока больше из RT11SJ.SYS и висит на опросе клавиатуры.

nzeemin
07.01.2023, 16:50
Спасибо! Теперь проходит немного дальше - после первых блоков .SYS-файлов читает ещё два блока больше из RT11SJ.SYS и висит на опросе клавиатуры.

Удалось раскопать вот что: застреваем на ожидании что значение по адресу 146070 станет нулевым, но там всегда 001.
Отследил все изменения этой ячейки памяти (UR6=032), после теста памяти изменение только одно, по адресу PC=155130:


U155120 CMPB #000377, 000010(R3)
U155126 BEQ 155120
U155130 INCB 000010(R3) ; тут меняется 000 -> 001
155130 Value at 146070 changed 000000 -> 000001
...
155262=DAB2 TSTB 000010(R3) ; R3=146060, (146070)=001 -- застряли тут
155266 BNE 155262

Вот фрагмент кода, может удастся опознать что это?


155100 DEC (R4)+
155102 MOV (R4), R4
155104 MOV (R4), 155034
155110 CLRB @#177776
155114 CLR (R4)+
155116 MOV R3, (R4)+
155120 CMPB #000377, 000010(R3)
155126 BEQ 155120
155130 INCB 000010(R3) ; тут изменение 000 -> 001
155134 PUSH R3
155136 PUSH R0
155140 MOV R4, R3
155142 POP (R4)+
155144 CLRB R1
155146 MOV R1, (R4)+
155150 MOV (R5)+, (R4)+
155152 MOV 000002(SP), (R4)+
155156 TST (R5)+
155160 MOV (R5)+, (R4)
155162 CMPB (R4), #000377
155166 BNE 155200
155170 SWAB (R4)
...
155240 MOV R3, 177774(R1)
155244 MOV R3, (R2)
155246 CLRB @#177776
155252 POP R5
155254 POP R3
155256 TST -(R5)
155260 BNE 155270
155262 TSTB 000010(R3) ; тут зацикливаемся
155266 BNE 155262
155270 POP R4
155272 RETURN

Alex_K
07.01.2023, 17:14
155110 CLRB @#177776
Ох как плохо. Никита, а у вас эмулятор точно делает TRAP4 в диапазоне адресов 0177700-0177777? Всё дело в том, что RT-11 собрана с использованием регистра PSW 0177776. А вот вторичный загрузчик проверяет этот регистр, и если его нет, то патчит только что загруженный RMON на использование команд MFPS/MTPS.

nzeemin
07.01.2023, 17:25
Ох как плохо. Никита, а у вас эмулятор точно делает TRAP4 в диапазоне адресов 0177700-0177777? Всё дело в том, что RT-11 собрана с использованием регистра PSW 0177776. А вот вторичный загрузчик проверяет этот регистр, и если его нет, то патчит только что загруженный RMON на использование команд MFPS/MTPS.

Отлично! То что нужно. Загрузился до командной строки.

https://pic.maxiol.com/thumbs2/1673101485.1565642383.20230107142419106.png (https://pic.maxiol.com/?v=1673101485.1565642383.20230107142419106.png&dp=2)

Alex_K
07.01.2023, 17:31
Отлично! То что нужно. Загрузился до командной строки.
УРРРРРРРРРРРААААААААААААА ААААА !!!!!
А клавиатура работает? В командной строке можно что-нибудь понабирать?

nzeemin
07.01.2023, 19:31
УРРРРРРРРРРРААААААААААААА ААААА !!!!!
А клавиатура работает? В командной строке можно что-нибудь понабирать?

Клавиши почти не размаплены - как раз займусь сегодня.

Спасибо вам всем огромное, Alex_K, xolod, Titus - благодаря вам появился второй эмулятор Союз-Неона!

Alex_K
07.01.2023, 19:54
появился второй эмулятор Союз-Неона!
А пощупать можно будет?
P.S. Про гитхаб не надо, а то качать, ставить VisualC++, лучше сразу собранный релиз.

nzeemin
07.01.2023, 20:09
А пощупать можно будет?
P.S. Про гитхаб не надо, а то качать, ставить VisualC++, лучше сразу собранный релиз.

Всё понимаю.
https://github.com/nzeemin/neonbtl/releases/download/preview-94/NEONBTL-preview-94.zip

Titus, извиняюсь что захватил и замусорил тему - исправляюсь:
https://zx-pk.ru/threads/34880-emulyator-soyuz-neon-pk-11-16-neonbtl.html
Предлагаю всё обсуждение по моему эмулятору продолжать там.

Titus
15.02.2024, 02:56
Внимание, вопрос: Кто-нибудь еще использует эмулятор на WinXP?

Спрашиваю потому, что не хочу тащить за собой устаревший DirectDraw и DirectSound, на смену которым в Vista пришли более качественные Direct2D и WASAPI.

yur
01.04.2024, 05:06
да

Titus
01.04.2024, 11:33
да

Уже поздно, придется переходить на Win7 и выше, если выйдет новая версия)