Встретил на гф топик, где заданный вопрос заставил меня вернуться к древнему компьютеру. Вопрос касался ввода текста и печати сообщений, но я ничего про это не знал. Лет 8 назад я публиковал статью о разработке и эмуляции в сообществе было-Hype. Статья была невнятной и неполной, а сейчас многое изменилось.
Я использовал эмулятор simh v1.4b, в котором была включена эмуляция экрана. Сейчас я нашел simh v4 - сборник исполняемых файлов. Уже в старой версии была добавлена возможность исполнения команд при запуске: нужно создать файл simh.ini и ввести команды:
set dpy enable включить дисплей
attach ptr hex.rim подключить образ ленты hex.rim
boot ptr загрузка и запуск программы
Для отладки можно добавить break 100.
Еще один эмулятор классической игры SpaceWar! - это MAME/MESS
Способ запуска игры можно описать как "через задницу", но игра запускалась - были ролики на Ютуб.
Сейчас в версии 0.270 добавлена возможность загрузки .rim, включен отладчик, но мне так и не удалось загрузить файл, эмулятор невнятно ругался и ничего не работало. Если верить скриншотам, эмуляция шла на отлично:
Более того, сборник ROM находился неизвестно где, нашел заблокированный архив на web.archive.org. Камрады с чятика подсказали, что для скачки нужна регистрация - заработало! Приложил архивы ко всем файлам - ни один копираст не докопается.
Теперь разработка. Мое знание опкодов касалось книги PDP1_Handbook_Oct63, но сейчас появился отличный сайт с эмулятором и списком опкодов. В архив добавлен документ, т.к. сайт иногда уходит в кому.
В интернетах можно найти пример печати текста. Всегда интересно разобраться с программой, а не скомпилировать, запустить, и почувствовать себя великим программистом.
/ above: title line - was punched in human readable letters on paper tape
/ below: location specifier - told assembler what address to assemble to
100/
lup, lac i ptr / load ac from address stored in pointer
cli / clear io register
lu2, rcl 6s / rotate combined ac + io reg 6 bits to the left
/ left 6 bits in ac move into right 6 bits of io reg
tyo / type out character in 6 right-most bits of io reg
sza / skip next instr if accumulator is zero
jmp lu2 / otherwise do next character in current word
idx ptr / increment pointer to next word in message
sas end / skip next instr if pointer passes the end of message
jmp lup / otherwise do next word in message
hlt / halt machine
ptr, msg / pointer to current word in message
msg, text "hello, world" / 3 6-bit fiodec chars packed into each 18-bit word
end, . / sentinel for end of message
start 100 / tells assembler where program starts
lac i ptr здесь используется косвенная адресация или AC=peek(peek(ptr))
rcl 6s сдвиг влево регистров AC и IO. 6s в исходнике описана как { DEFFIX, "6s", 0000077 } - это тоже 6 единиц.
tyo печать значения правых 6 бит в IO. Не очень ясно, что печатается, если значение 0.
sza Выполнение опкода jmp lu2 пропущено, если AC=0(опкод группы skip).
jmp lu2
idx ptr Увеличить указатель на 1, переход к следующему символу. AC=peek(ptr)+1
sas end Еще один skip-опкод: следующая инструкция будет пропущена, если AC равен адресу end/
jmp lup
hlt остановка выполнения.
Ввод с клавиатуры я решил написать сам, не ища опубликованные исходники. Почитал упомянутую книгу Handbook и получил результат. Потом я изменил программу, чтобы ввод останавливался при нажатии Enter(или CR).
100/
bg,
cla
clf 1 /clear Program flag 0-7 holds at 0-7
sbf,
szf 1
jmp gk
jmp sbf
gk,
tyi /IO=code, right 6 bits
dio chk /stupid lai for PDP-1D
law 77
sad chk /skip if AC=m(cr)
hlt /stop execution
tyo /output
jmp bg
chk,0
end, .
start 100
Здесь до опроса нажатия клавиши сбрасывается Flag 1, он устанавливается при нажатии клавиши. Выход из цикла - szf 1, в регистре IO хранится код клавиши и выводится на консоль эмулятора(вангую, что в реале печатается на бумаге). После печати код проверяется на значение 77o или CR и в случае совпадения останавливается выполнение.
Интересно, что после кодинга я нашел похожий пример в описании Macro 1, но синтаксис отличается от того, что было под рукой.
Теперь еще одно - печать числа в восьмиричной системе исчисления:
100/
law 1234
jda opt
hlt
opt,0
dap opx
law i 6
dac occ
cli
opc, lac opt
ral 3s
dac opt
and v7
sza i
law 20
rcr 9s
rcr 9s
tyo
isp occ
jmp opc
opx, jmp .
occ, 0
v7, 7
end, .
start 100
law 1234 загрузка значения AC=1234octal
jda opt выполняется как dac opt jsp oct+1
dap opx На момент выполнения AC=адресу для своего рода возврата из "процедуры" AC= адрес ниже, чем jda opt.
law i 6 Загрузка в AC отрицательного числа -6. Увидел похожий прием в примерах - это счетчик цикла
dac occ Сохранить счетчик в occ
opc, lac opt Загрузка числа
ral 3s Циклический сдвиг AC влево
dac opt Сохранить значение
and v7 AC=AC&peek(v7) или AC=AC&7 получить три бита числа
sza i Снова skip - пропустить следующий опкод, если AC=0
law 20 Ели AC=0, то загрузка кода символа "0"
rcr 9s Пара инструкций - это обмен AC и IO
rcr 9s см. исходный текст SpaceWar, где встречается макрос swap.
tyo печать кода в IO, код это правые 6 бит.
isp occ Index and skip if result is positive Счетчик увеличивается от -6 до 0 и при AC=0 будет пропущен переход jmp opc
jmp opc
opx, jmp . это возврат из "процедуры"
Описание кода слегка утомляет, поэтому не буду описывать мои попытки нарисовать на экране. Вместо старого алгоритма получилась просто фигня, названная displayhack.
На этом я закончу свой рассказ, упомянутые файлы тут.
А самая красивая программа snowflake в simh так и не работает.
Дополнение. похоже, что я не совсем понял, как работает код. В исходнике печати восьмиричного числа пара инструкций rcr 9s работают как обмен регистров AC и IO.
Печать текста выглядит еще интереснее. Посмотрел на сгенерированный листинг:
00114 434633
00115 002646
00116 514364
18 00117 000117 end, . / sentinel for end of message
Комментарии
Отправить комментарий