Правила написания ROM-версий программ.
Программа для ROM-Drive представляет собой файл или несколько файлов, которые будут записываться в ПЗУ пользователя.
В принципе, программу писать не надо, а надо написать простейший загрузчик в кодах, стартующий с адреса 0000Н и расположит в ПЗУ блок (блоки) кодов с какого-то адреса (адресов) "Обязанности" загрузчика заключаются в том, что обычно делает BASIC: устанавливает цвет бордюра, системные переменные, делает POKES и т.п.; а также в том, чтобы перебросить командами LDIR блоки кодов на свои места (с адресов в ПЗУ - по адресам, которые известны из BASICa.) Причём не нужно заботиться о неперекрытии областей блока-источника и блока-назначения: всё равно данные считываются только из ПЗУ, а записываются в "другое адресное пространство" - ОЗУ, даже если их адреса одинаковы.
При написании загрузчика необходимо учитывать следующие правила:
а). Во время работы загрузчика системное ПЗУ недоступно. Например, если Вам очень нужно вывести сообщение, Вы должны либо иметь в ПЗУ-П подпрограмму вывода символов и символьный набор, либо "не мудрить" и нарисовать сообщение в ART-STUDIO. Вывод картинки с сообщением на экран сведётся к одной команде LDIR.
б). Во время работы загрузчика нельзя ничего прочитать из ОЗУ (туда можно только записать): в частности, нельзя пользоваться стеком и командами CALL, RST. Поэтому подпрограммы загрузчика не должны хранить что-либо в ОЗУ: сохранить-то сохранишь, но не прочитаешь, пока не передашь управление в ОЗУ.
в). Во время работы загрузчика прерывания должны быть запрещены, в противном случае Вы должны будете разместить с адреса 0038Н программу обработки прерываний (простейшая программа состоит из одного оператора RET).
Приведу для примера целый загрузчик игровой программы, очень простой для понимания основной идеи.
Пусть мы имеем "игрушку", состоящую из бейсиковского загрузчика, заставки длиной 6912 байт и блока кодов длиной 38000 байт, причём в бейсике сказано:
Подсчитав сумму длин 2-х блоков кодов (6912+38000= 44912), приходим к выводу, что нам нужно ПЗУ типа D27512 объёмом 64К. В свободном месте ПЗУ (около 20К) можно разместить ещё одну небольшую программу, но об этом пока говорить не будем. Недолго думая, пишем ROM-загрузчик, основываясь на тексте бейсика:Код:10 BORDER 0: PAPER 0: INK 0: CLEAR 25999 20 LOAD "SCREEN"CODE 16384 30 LOAD "codeHCODE 26000 40 POKE 32550,201 50 RANDOMIZE USR 60000
г) Обратите внимание на то, чтобы передача управления в ОЗУ была сделана ОДНИМ оператором JP. Например, если загрузчик исходной кассетной версии заканчивался словами:Код:00000 DI ; прерывания лучше запретить XOR А ; А=0 LD (23624),А ; установка чёрного цвета бордюра OUT (#FE),A LD SP,25999 ; примерно то же, что и CLEAR (цвета чернил и бумаги менять не будем) LD HL,00256 ; с этого адреса в ПЗУ будет блок SCREEN LD DE,16384 ; на этот адрес он будет переброшен LD ВС,06912 ; это его длина LDIR ; заставка уже на экране! LD ВС,#7FFE ; ждём нажатия "пробела", иначе картинка сразу пропадет IN А,(С) LOOP BIT 0,А JR NZ,LOOP LD HL,(256+6912) ; сразу за заставкой в ПЗУ расположим блок code, поэтому его адрес-такой. LD DE,26000 ; адрес назначения блока code LD ВС,38000 ; длина блока code LDIR ; кодовый блок загружен! LD А,201 ; число для РОКЕ LD (32550),А ; РОКЕ готово! JP 60000 ; 3апуск!!! ………………………………………………………………………………………………………………………………………………………………………………………… 00056 RET ; это "программа обработки прерываний". ………………………………………………………………………………………………………………………………………………………………………………………… 00256 <здесь находится блок SCREEN>. ………………………………………………………………………………………………………………………………………………………………………………………… 07168 <а здесь - блок code (07168=256+6912)> …………………………………………………………………………………………………………………………………………………………………………………………
LOAD "ABC" CODE 25000: RANDOMIZE USR 25000: RANDOMIZE USR 43560
т.е. два вызова подпрограмм, то в ROM-загрузчике Вы должны разместить, эти вызовы (запускающий модуль) в ОЗУ и передать управление на первый из них. У Вас должно получиться что-то вроде:
Можно сделать и по другому - иметь готовый запускающий модуль в ПЗУ, перебросить его в ОЗУ и передать на него управление.Код:LD HL,<адрес начала блока ABC в ПЗУ> LD DE,25000 LD ВС,<длина блока АВС> LDIR ; загрузили блок в ОЗУ LD HL,16384 ; здесь в ОЗУ будет запускающий модуль LD A,#CD ; код инструкции CALL LD (HL),A ; в ОЗУ его ! INC H ; следующий адрес LD ВС,25000 ; операнд для CALL LD (HL),С ; младший байт - в ОЗУ! INC HL LD (HL),В ; старший байт - в ОЗУ! INC HL LD А,#С3 ; код инструкции JP LD (HL),А ; в ОЗУ! INC HL LD ВС,43560 ; операнд для JP LD (HL),С ; младший байт - в ОЗУ! INC HL LD (HL),В ; Теперь с адреса 16384 у нас есть модуль: ; CALL 25000 ; JP 43560 JP 16384 ; Выход из ПЗУ пользователя и запуск программы
В общем, адаптация программ под ROM-Drive не сложнее, чем адаптация кассетных версий под TR-DOS. Однако, к каждой программе нужен индивидуальный подход.Код:LD HL,<адрес начала блока ABC в ПЗУ> LD DE,25000 LD ВС,<длина блока АВС> LDIR ; загрузили блок в ОЗУ LD HL,ROMADR ; адрес запускающего модуля в ПЗУ LD DE,16384 ; сюда будет переброшен запускающий модуль, LD ВС,00006 ; длина которого 6 байт LDIR ; загрузили запускающий модуль JP 16384 ; и - вперёд! ………………………………………………………………………………………………………………………………………………………………………………………… ROMADR CALL 25000 ; Это и есть JP 43560 ; наш запускающий модуль. *****
Если кто-то знает способ запуска Magic-файлов в TR-DOSe, может попытаться написать ROM-загрузчик таких файлов из ПЗУ. Преимущества очевидны: этот загрузчик может быть универсальным (или почти универсальным) для всех ПП и производство ROM-версий можно "поставить на поток".
В конечном результате у Вас должен получиться файл длиной 8, 16, 32 или 64Кб. В последнем случае проще сделать 2 файла по 32Кб. Неиспользованную часть ПЗУ лучше заполнить кодами #FF - это облегчит внесение изменений.
Полученный файл должен быть записан в ПЗУ соответствующей ёмкости:
8Кб - D2764 или К573РФ4(РФ6)
16Кб - D27128
32Кб - D27256 или К573РФ8
64K6 - D27512
Если в Вашей местности нет программаторов к "Спектруму", перенесите файл на IBM-овский диск (например, через iS-DOS). Возможно, у кого-то найдется IBM с программатором.
Наиболее оправданным (по соотношению цена/ёмкость) я считаю D27512. (Её цена на рынках разных городов составляет 2-3$). В случае записи нескольких ПП в одно ЦЗУ, нужно ввести в ROM-загрузчик программу, позволяющую пользователю выбрать необходимую ПП (например, из меню).
Что ещё не сделано?
Недостатки системы очевидны:
а). малая ёмкость ПЗУ-картриджа - 64К при использовании D27512;
б). невозможность поочередной "подгрузки" уровней в блочных играх и других программах (без применения кнопки "сброс").
Возможные пути их устранения:
а). Можно применить страничную организацию ПЗУ-П и устанавливать либо несколько микросхем D27512, либо микросхему D271000 (128Кб при цене 5-6$) или D274000 (512Кб при цене 12-15$). Для управления страницами вполне возможно использовать порт FEH.
б). Посмотрите на схему контроллера дисководов Beta Disk Interface. Схема селектора адресов, применённая для входа в ПЗУ TR-DOS'a (обычно делается на микросхеме К555ЛА2), вполне подойдёт для входа в ПЗУ-П, только диапазон адресов для входа должен быть иным. Не исключена возможность использования общего селектора TR-DOSом и ROM-Drive, однако тогда будет нужен коммутатор "диск"-"ПЗУ".
Мной сделана ROM-версия игры TETRIS-2 фирмы Golden Triangle, записанная в ПЗУ D27256. Работа игры проверена на компьютере "Ленинград-1", оборудованом ROM-Drive. При замкнутом переключателе S1 (см. рис. 1) игра начинается сразу после включения компьютера, однако хочу предупредить, что лучше в общем случае сначала произвести обычный сброс, а потом включать ROM-Drive.




Ответить с цитированием