Как написать игру для ZX Spectrum на ассемблере

         

Прямые линии


Продвинемся еще на один шаг вперед и научимся проводить прямые линии. Для этого потребуется сперва указать начальные координаты, поставив точку, от которой протянется линия, а затем задать величины смещения по горизонтали и вертикали до конечной точки линии. В Бейсике это должно выглядеть примерно так:

PLOT 120,80: DRAW 35,-60

Оператор DRAW реализует подпрограмма ПЗУ, находящаяся по адресу 9402. Перед обращением к ней в регистры C и B необходимо последовательно занести значения параметров, взятые по абсолютной величине, то есть в C в нашем примере помещается число 35, а в B нужно загрузить не -60, а 60. Но чтобы не потерять знаки, их следует разместить на регистрах E и D. Это значит, что в регистр E заносится единица, а в D - минус единица (или, что то же самое, 255). Таким образом, приведенная выше строка Бейсика на ассемблере запишется так:

LD BC,#5078 ;C = 120 (#78), B = 80 (#50) CALL 8933 LD BC,#3C23 ;C = 35 (#23), B = 60 (#3C) LD DE,#FF01 ;E = 1 (#01), D = -1 = 255 (#FF) CALL 9402 RET

Вроде бы все просто, однако здесь вы можете столкнуться с одной серьезной проблемой. Если запустить эту программку не из ассемблера (использовав директиву ENT и команду редактора R), а из Бейсика с помощью функции USR, то вы заметите, что компьютер ведет себя довольно странно. В лучшем случае появится какое-нибудь сообщение об ошибке, а в худшем - компьютер «зависнет» или «сбросится». А происходит это оттого, что при выполнении подпрограммы 9402 теряется некоторая информация, необходимая для нормального завершения функции USR. Значит, нам нужно выяснить, что это за информация и где она находится, чтобы можно было сохранить ее на входе и восстановить на выходе из нашей программы.

До сих пор мы говорили только о семи регистрах общего назначения, но на самом деле микропроцессор Z80 имеет их гораздо больше. Постепенно мы изучим их все, а сейчас скажем еще несколько слов об уже известных вам регистрах. Дело в том, что имеется не один, а два набора регистров данных, но активным в каждый момент времени может быть только какой-то один из них, то есть одновременно вы все равно можете работать только с семью регистрами общего назначения.


Регистры второго, или, как говорят, альтернативного набора абсолютно ничем не отличаются от регистров первого набора. Они имеют те же имена (для отличия альтернативных регистров от активных в данный момент времени после имени пары, включающей в себя этот регистр, ставят символ апострофа, например, DE') и выполняют те же функции, поэтому нет никакой возможности определить, какой из двух наборов активен в данный момент - об этом должен позаботиться программист.

В любой момент вы можете переключиться на альтернативные регистры, использовав команду EXX. Выполнив эту же команду повторно, вы вернете прежние значения регистров, ничего не потеряв. Потому данная команда, как правило, в программах встречается парами, подобно PUSH и POP.

Применяя команду EXX, нужно также помнить, что она переключает на альтернативный набор не все семь регистров, а только 6: BC, DE и HL. Для переключения аккумулятора существует другая команда. Не вдаваясь пока в смысл символики, скажем, что записывается она так:

EX AF,AF'

Добавим еще к сказанному, что мнемоника EX и EXX происходит от английского слова exchange - обменивать.

Вернемся снова к функции USR. В простых и небольших по объему программах семи регистров общего назначения, как правило, вполне хватает (во всяком случае, мы вам советуем не слишком злоупотреблять командой EXX, лучше при необходимости для временного хранения информации пользоваться стеком). Но в таких больших и сложных программах, как операционная система ZX Spectrum, иногда возникает необходимость привлекать и альтернативный набор регистров. Так функция USR перед вызовом программы в машинных кодах заносит важную информацию в регистровую пару HL', поэтому для нормального выхода в Бейсик ее необходимо сохранять всегда, когда она может измениться. В частности, при использовании подпрограммы рисования линий 9402.

Перепишем предыдущий пример таким образом, чтобы его можно было вызвать из Бейсика:

ORG 60000 EXX ;в начале программы меняем ; на альтернативный набор PUSH HL ;сохраняем регистровую пару HL LD BC,#5078 CALL 8933 LD BC,#3C23 LD DE,#FF01 CALL 9402 POP HL ;восстанавливаем значение HL EXX ;делаем его альтернативным RET

Поскольку перед вызовом подпрограммы в машинных кодах функция USR загружает регистр HL' всегда одним и тем же значением, а именно, числом 10072, то можно не сохранять его в стеке, а просто записать перед выходом в Бейсик:

LD HL,10072 EXX RET

При желании вы можете проверить содержимое пары HL', оттранслировав такую программку:

ORG 60000 EXX ;меняем на альтернативный набор PUSH HL ;запоминаем в стеке значение HL' EXX ;возвращаем «стандартные» регистры POP BC ;забираем число из стека в пару BC ; для передачи в Бейсик RET ;возврат в Бейсик

и затем выполнив ее строкой

PRINT USR 60000

в результате чего на экране должно появиться число 10072.


Содержание раздела