Портирование Lode Runner с БК на УКНЦ

В марте-мае этого года я потратил несколько недель (по вечерам и выходным) на портирование игрушки Lode Runner с БК-0010 на УКНЦ.
Скриншот меню портированной версии:
1d3d35f4111c4f4c9e4324d8e285ea26.png
Игровой экран портированной версии:
4f0798b1ff524bcab9d1a8039ccd8473.png

БК-0010 это бытовой компьютер конца 1980-х и начала 1990-х, и отчасти школьный компьютер (классы КУВТ-86). УКНЦ это школьный компьютер 1990-х. БК и УКНЦ частично совместимы по архитектуре и системе команд — оба компьютера восходят к семейству PDP-11.

Выбор игры


До этого года я не писал ничего серьёзного под УКНЦ, но приходилось разбираться в машинном коде. Было желание написать что-нибудь, но обычно у меня большие проблемы со свободным временем, так что сделать что-либо с нуля вряд ли получилось бы. И для начала лучше брать задачу попроще. При портировании объём работы обычно намного меньше чем при написании с нуля — сталкиваешься в основном с проблемами несовместимости двух систем.

На форуме zx.pk.ru (одна из площадок где тусуются любители ретрокомпьютинга вообще и PDP-11 совместимых машин в частности) участник hobot расхваливал реализацию Lode Runner на БК — собственно это и стало поводом, для начала я попробовал «посмотреть» на код игрушки, ну и втянулся.

Меню оригинальной версии:
8ba13b271f1c441e9f561d6dd4998e0b.png
Игровой экран оригинальной версии (на цветном мониторе):
e7a798d5016f47129bc81b51ddfa59bb.png

Обратная разработка


Пару недель по вечерам и выходным я потратил время на анализ и дизассемблирование. В эмуляторе BKBTL добавил возможность собирать трассу — то есть, каждая инструкция дизассемблируется и сохраняется в текстовый файл.
Делаю прогон участка который меня интересует с записью трассы, потом сворачиваю трассу (sort & uniq) — получаю фрагменты логики. Добавляю к этому комментарии, получаю постепенно общий файл.

Звучит просто, но на самом деле это довольно сложная работа, основанная на догадках и их подтверждении или опровержении. Например, смотрим что адрес 001756 перед началом игры получает значение 10, потом декрементируется, при достижении 0 игра заканчивается — видимо, это количество жизней. Находим этому подтверждение, расставляем комментарии по тексту где встречается этот адрес. Это довольно простой пример, в более сложных случаях я потратил много времени на то чтобы догадаться что к чему.

Когда полученный объём стал достаточно большим (40+ КБ текста, больше 1500 строк) и я разобрался хотя бы в общих чертах что к чему, как хранится и выводится — стал думать как это перевести на УКНЦ.

Здесь можно посмотреть на итоговый листинг, полученный в результате дизассемблирования:
github.com/nzeemin/uknc-loderunner/blob/master/original/loderunner.lst

Лабиринт


Каждый лабиринт — это 20 строк по 30 блоков, всего 600 блоков.
Тип блока кодируется числом от 0 до 7 — три бита, триплет. На одно 16-разрядное слово получается 5 полных триплетов.
В работе с PDP-11 like машинами повсеместно используется 8-ричная система, поэтому использовать триплеты довольно удобно.
В итоге, каждый лабиринт укладывается в 240 байт.

Типы блоков:

;    0 -- пусто
;       1 -- сплошная стена
;       2 -- кирпичная стена
;       3 -- верёвка
;       4 -- чёрт
;       5 -- человек
;       6 -- сундук
;       7 -- лестница


Спрайты этих объектов расположены в порядке нумерации типов блоков. Когда раскодируется лабиринт, одновременно создаётся «образ лабиринта» в памяти (по байту на блок), и тут же рисуется начальное состояние лабиринта на экране.

Организация экрана


На БК экран адресуется непосредственно обращением к памяти, строки идут одна за другой, по сути это «framebuffer», и я бы сказал что это прекрасно — очень удобно для программирования графики. Строка БК — 256 цветных пикселей, 64 байта на строку. А вот то, сколько пикселей в строке, зависит от того как вы подключили монитор:
если по чёрно-белому выходу, то это 512 ч/б пикселей в строке (1 бит на пиксел, 8 пикселей на байт),
а если по цветному выходу, то это 256 цветных пикселей в строке (2 бита на пиксел, 4 пиксела на байт).

На УКНЦ же организация экрана совсем другая, и намного более сложная. Экран лежит в трёх блоках памяти, трёх «планах». И каждый пиксель это три бита, по биту в каждом плане — получаем 8 цветов. На УКНЦ у нас есть несколько видеорежимов — 640 × 288, 320 × 288, 160 × 288, точнее, у нас всегда ровно 288 строк и к каждой отдельной строке можно применить свой делитель, получая разное разрешение по горизонтали. Для центрального процессора (ЦП) планы экрана не доступны непосредственно, только через обращение к портам. Причём, для ЦП доступны только два плана из трёх.

В данном случае мне хорошо подходил режим 320 × 288 — строка получается в 320 цветных пикселей длиной 80 байт в каждом из трёх планов. Если использовать два плана, то пиксели получаются тоже четырёхцветные — почти как на БК.

Синтез


Начал писать примеры на ассемблере УКНЦ и несколько приуныл — потому что цикл «скомпилил — слинковал — запустил» получается довольно медленный. Проблема в инструментах. Кросс-ассемблер MACRO11 есть, хоть он и несколько глючный. А вот кросс-линкера нет. Но к счастью, не так давно Patron выложил консольную RT-11: zx-pk.ru/showthread.php? t=24755 — по сути это эмулятор PDP11-совместимой машины, взаимодействующий с командной строкой ОС как с терминалом. Тем самым, стала возможной компиляция и линковка родными средствами RT-11. Это я считаю настоящий прорыв, резко ускорило работу.

После этого дело пошло, сделал отрисовку рамки игрового поля, отрисовку спрайтов, разобрался как биты в спрайтах нужно перемешать (для перемешивания написал программу на C#), затем блоками стал переносить код из общего файла с дизасмом в новые исходники. Взял дамп памяти с БК, выделил блок где лежат уровни, RT11-утилитой DUMP сделал текстовик под уровни.

Сначала перенёс блок кода который выводит уровень, на этом отладил вывод спрайтов. Потом игровую логику стал переносить. Т.е. в целом перенос практически один-к-одному, за исключением мест где вывод на экран идёт. Поэтому есть места в логике которые я не понимаю как работают (тот же AI чёртиков), но это и не важно — главное что работают.

В итоге, к началу мая (когда основная работа меня снова поглотила) получился работающий вариант, хотя и без звука.

Фото работающей игры на реальной машине (спасибо hobot):
08ea17867ee7451794d3f5c7d099c698.jpg

Ссылки


© Geektimes