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

Материал из Emuverse
Данный материал защищён авторскими правами!

Использование материала заявлено как добросовестное, исключительно для образовательных некоммерческих целей.

Автор: А. Евдокимов, А. Капульцевич, И. Капульцевич, ИД «Питер»

НЕКОТОРЫЕ НЕДОКУМЕНТИРОВАННЫЕ КОМАНДЫ

К недокументированным относятся те команды, которые не были описаны фирмой-разработчиком микропроцессора Z80A CPU. Вполне возможно, они даже не были запланированы, а получились, если так можно выразиться, как издержки производства. В связи с этим каждый программист «открывает» их для себя, пользуясь методом «научного тыка». Вы также можете поэкспериментировать, используя некоторые правила построения системы команд, о которой мы и хотим здесь рассказать.

Внимательно изучив коды, приведенные в предыдущем приложении, вы сможете заметить определенную закономерность. Сравните, например, команды LD HL,NN, LD IX,NN и LD IY,NN. Не правда ли, кодировки очень похожи друг на друга? Команды, использующие индексные регистры, состоят из тех же кодов, что и LD HL,NN, но предваряются специальным префиксом #DD для IX или #FD для IY. Среди «стандартных» мнемоник отсутствуют команды обработки половинок индексных регистров, но воспользовавшись правилами кодировки, не трудно получить такие команды. Они будут соответствовать кодам обработки регистров H и L, перед которыми стоит один из указанных выше префиксов. Например, для загрузки младшей половинки регистра IX числом 32 можно написать следующую последовательность:

       DEFB  #DD
       LD    L,32

В мнемоническом обозначении такая команда обычно записывается как LD IXL,32. С префиксами #DD и #FD аналогичным образом могут быть получены следующие команды:

       ADD   A,s
       ADC   A,s
       AND   s
       CP    s
       DEC   s
       INC   s
       LD    r,s
       LD    s,n
       LD    s,r
       OR    s
       SBC   A,s
       SUB   s
       XOR   s

где s - IXH, IXL, IYH или IYL; r - A, B, C, D или E; n - однобайтовое числовое значение.

Существует еще целый ряд интересных команд, получаемых с префиксами #DD и #FD, которые могут выполнять сразу два действия - устанавливать или сбрасывать биты одновременно в регистре и в памяти, адресуемой индексными регистрами. Например, команда

       SET   1,A(IX+3)

сначала установит бит 1 в ячейке, адресуемой IX со смещением в 3 байта, а затем поместит полученное значение в регистр A. То есть выполняются как бы две команды:

       SET   1,(IX+3)
       LD    A,(IX+3)

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

       SET   1,A

Эта команда кодируется двумя байтами #CB и #CF (см. <a href="append01.htm#n00" target="view">Приложение I</a>). Для получения новой команды необходимо вначале поставить код префикса, а между байтами исходной команды вставить байт величины смещения. Таким образом, приведенная выше мнемоника должна кодироваться последовательностью #DD, #CB, #03, #CF.

Команда

       RES   5,H(IY-5)

получается, исходя из кодировки команды

       RES   5,H

В результате у вас должна получиться последовательность кодов #FD, #CB, #FB, #AC. Конечно, все предложенные мнемоники не поддерживаются ассемблером GENS, поэтому использовать их можно одним лишь способом - записывая коды непосредственно в директиве DEFB. То есть последняя команда в ассемблерном тексте будет выглядеть так:

       DEFB  #FD,#CB,#FB,#AC

Несколько сложнее дела обстоят с другими префиксами: #CB и #ED. С ними также можно получить ряд новых команд, хотя часто они лишь повторяют «стандартные» инструкции (особенно это относится к префиксу #ED) и практической пользы поэтому от них мало. Такие команды чаще используются для защиты коммерческих программ, чтобы текст невозможно было прочитать (ни один из известных дизассемблеров недокументированные команды не распознает).

Для поисков лучше всего использовать отладчик MONS, так как он в режиме трассировки тупо выполняет машинные инструкции, совершенно не вникая в их смысл. Но в данном случае вам это как раз и нужно. Любой код, который вы ему подсунете, будет выполнен абсолютно так же, как и в программе (заметим, что другой трассировщик - Mon2 - перед выполнением очередной команды справляется о ней в таблице, поэтому, если вы решите использовать для экспериментов именно этот дизассемблер, стоит оформлять искомые коды в виде подпрограммы и трассировать их, нажимая клавишу S).

Поскольку «пропущенных» команд, получаемых с использованием префикса #CB немного, приведем их полный список (кстати, дизассемблер Mon2, в отличие от MONS, прекрасно «справляется» с этой группой команд).

       SLL   (HL)        ; CB36
       SLL   (IX+Д)      ; DDCBXX36
       SLL   (IY+Д)      ; FDCBXX36
       SLL   A           ; CB37
       SLL   B           ; CB30
       SLL   C           ; CB31
       SLL   D           ; CB32
       SLL   E           ; CB33
       SLL   H           ; CB34
       SLL   L           ; CB35

Эти команды дополняют перечень команд сдвига. При их выполнении содержимое регистра или ячейки памяти сдвигается влево на один разряд. Старший бит переходит во флаг CY, а младший в любом случае заполняется единицей. Например, после сдвига числа 00101110 командой SLL (в такой мнемонике данные команды показываются дизассемблером Mon2, однако в литературе часто предлагается другое обозначение - SLI; тем не менее, это те же самые команды) получится значение 01011101. Команда воздействует на флаги CY, Z, P/V и S. Флаги H и N сбрасываются в 0.

Если вы решите использовать в своей программе приведенные выше инструкции, то помните, что ассемблер GENS понятия не имеет о существовании мнемоники SLL. Поэтому все команды придется кодировать исключительно с помощью директивы DEFB.