┌──────────────────────────────┐
│ ───────── СИСТЕМА ────────── │
└──────────────────────────────┘
Станислав В. Ефимов
Новое о Z-80,
или как используются недокумен-
тированные возможности процессо-
ра, а также кое-что про архитек-
туру компьютера.
Тот, кто программирует на ас-
семблере, прекрасно знает все
инструкции, флаги, которые меня-
ются под воздействием этих
инструкций и, в зависимости от
опыта и прочих условий, полага-
ет, что ему известно все о Z80.
Однако я уверен, что информация,
изложенная мною ниже, если и не
будет для кого-то неожиданной,
то будет интересной и, возможно,
полезной.
Каждый из вас изучал ас-
семблер по своему: кто-то читал
различные книги "русского" изда-
ния (Из великого множества книг
безусловно можно выделить широко
известный трехтомник "Инфорко-
ма"), а кто-то со временем, и не
читая никаких книг набирался
опыта у "западных" программис-
тов, бесконечно просматривая в
MONSе бесконечные тексты беско-
нечного множества программ, а
также листая различные "западны-
е" энциклопедии по Z80 (этим пу-
тем шло огромное количество лю-
дей, которые начали заниматься
программированием Z80 в не столь
отдаленные "перестроечные" го-
да). Со временем появляется все
больше книг, так или иначе каса-
ющихся Спектрума, однако там нет
ни слова о том, о чем пойдет
речь ниже...
Существует множество нигде не
документированных возможностей
Z80, которые не описаны ZILOG ни
в каких документах. Однако прог-
раммы, которые используют эти
возможности, существуют (и, ра-
зумеется, работают).
Подавляющее количество ин-
струкций ассемблера однобайто-
вые, т.е. состоят из одного бай-
та, собственно, кода операции и
операнда: байта или слова. Четы-
ре байта CB, DD, ED и FD - это
байты, которые меняют смысл ко-
дов, следующих за ними. Су-
ществуют 248 CB-инструкций. Од-
нако комбинации с CB30 до CB37
опущены из официального списка.
Эти инструкции обычно дизас-
семблируются как мнемоники SLL-
Shift Left Logical, которые
сдвигают операнд влево и уста-
навливают 0-й бит операнда.
Например эту инструкцию ис-
пользуют программы Bouder и
Enduro Racer. И таких программ
довольно много...
Инструкции, начинающиеся с
байтов DD и FD предполагают ис-
пользование регистров IX и IY,
Посмотрите внимательно, как они
работают:
2A nn LD HL,(nn)
DD 2A nn LD IX,(nn)
7E LD A,(HL)
DD 7E d LD A,(IX+d)
Но это вещи хорошо известные.
Когда Вы видите инструкцию
DD2Ann, то она воспринимается
Вами, как очевидная.
Однако, если инструкция ис-
пользует регистр H или L, то
байт-префикс позволяет работать
Вам со старшей или младшей поло-
виной регистра IX или IY.
Например:
44 LD B,H
FD 44 LD B,IYh
Эти типы неофициальных инструк-
ций используются огромным коли-
чеством программ. Другие типы
DD и FD инструкций, не приведен-
ные выше можно лишь использовать
с полезностью, не большей NOP.
Несколько подряд DD или FD може-
те попробовать распечатать
MONSом (посмотрите результат са-
ми)...
Я не встречал программ, кото-
рые использовали бы неофици-
альные ED инструкции, такие как
ED6Bnn - "длинная" версия 2Ann,
LD HL,(nn).
Ну а теперь о регистре R,
точнее о том, по какому закону
происходит его изменение... Поп-
росту говоря, регистр R - это
счетчик, который обновляется
после каждой инструкции, причем
DD, FD, ED и CB процессор
"воспринимает" как отдельные
инструкции! Т.е. инструкции с
такими префиксами увеличивают R
на 2. Но существует интересная
особенность: "двойные" префиксы,
такие как DDCB и FDCB увеличива-
ют R также на 2! LDI увеличивает
R на два, LDIR на 2*BC (также
как и LDDR).
Последовательность LD R,A/LD A,R
увеличивает А на 2, кроме стар-
шего бита (7-го): Этот бит ре-
гистра R не изменяется. Происхо-
дит это потому, что ранее ис-
пользовались 16KBitные микросхе-
мы, где биты группируются в мат-
рицу 128x128, т.е. для доступа к
ним необходимо лишь 7 бит... Во
многих программах регистр R ис-
пользуется как база для реализа-
ции генератора случайных чисел.
Следующие несколько страниц
будут верны лишь для машин с
"раздельным полем памяти", т.е.
на плате это выглядит как 8 штук
K565РУ6 & 8 штук K565РУ5 (напри-
мер, версия схемы МОСКВА-48). Ну
и, конечно, нижеследующее будет
верно для "фирменного" Спекрума
с 48k RAM.
Если у Вас одна из таких машин,
Вы можете посмотреть, как рабо-
тает регистр R при регенерации
памяти. (Нижеследующая программа
также будет полезна тем, кто хо-
чет определить, с каким "полем
памяти" у него машина.)
Введите программу:
ORG #7530
DI
XOR A
LD B,A
L1 XOR A
LD R,A
DEC HL
LD A,L
OR H
JR NZ,L1
DJNZ L1
EI
RET
Запустите эту программу. Ког-
да она отработает (это произой-
дет через несколько минут), пос-
мотрите содержимое "верхних"
32k. Лишь несколько первых байт
из каждых 256-и будут содержать
ту информацию, которая в них на-
ходилась. Содержимое этих байт
не изменится, потому что они ус-
пеют регенерировать за время
"тела цикла"...
ULA оперирует с памятью в ди-
апазоне #4000-#7FFF, процессор
"верхним" диапазоном памяти и
ПЗУ составляет диапазон
#0000-#3FFF, каждая из этих сос-
тавляющих всю память работает с
различной скоростью и независимо
друг от друга. Шины данных и ад-
реса Z80 и ULA соединяются с по-
мощью сопротивлений малой емкос-
ти; это дает очень эффективный
доступ к памяти.
Если Z80 нужно прочитать или за-
писать данные в "нижние" 16k в
то время, когда ULA занята чте-
нием, процессор приостанавлива-
ется, а когда этот процесс за-
кончится, ULA позволяет получить
доступ к "нижним" 16K непос-
редственно через сопротивления.
Это необычайно эффективно. Когда
Вы запускаете программу в "ниж-
них" 16k RAM или пишите-читаете
эту память, процессор слегка
"подвисает". Поэтому эта часть
памяти медленнее, чем верхние
32k. Именно поэтому никогда не
пишите программы типа ввод/вывод
в этих "нижних" 16k RAM (также
это относится к написанию
подпрограмм, связанных с воспро-
изведением звуков через встроен-
ный динамик).
Из всего вышесказанного сле-
дует, что если Вы напишете такие
подпрограммы на машине с "общим
полем памяти", то когда Вашу
программу запустят на "фирмен-
ном" Спектруме, в случае
синхро-ввода/вывода программа
просто не будет работать, а в
случае со звуками Ваша музыка
будет "непрезентабельной". К
этому же относится чтение порта
FE, поскольку ULA "поставляет"
его значение. Каждый раз, когда
Вы будете читать этот порт, ULA
временно останавливает процес-
сор, потому чтение значения из
этого порта несколько медленнее,
чем из других портов. Приведу
факты: обычно IN A,(nn) выполня-
ется процессором за 11T (так-
тов), однако это время возраста-
ет до 12.15T, если nn=FE (приве-
дено, разумеется, среднее значе-
ние).
На тему чтения несуществующих
портов, порта FF, о вопросах
синхронизации экрана, прерывани-
ях, степени "совместимости"
программ на различных компьюте-
рах (т.е. отчего одна программа
работает на одном Спектруме и не
работает на другом ...), специ-
альных эффектах, совместимости
различных версий TR-DOS и о
многом другом планируется еще
один разговор. Поскольку я нем-
ного отошел в сторону от темы
данной статьи, я продолжаю...
Есть еще один, но далеко не
единственный "темный угол", им
пользуются программы Sabrewulf,
Ghosts'n Goblins, а также защита
Speedlock. Это загадка недоку-
ментированных флагов. Биты 3 и 5
регистра флагов F не используют-
ся.
Казалось бы, Вы можете их уста-
новить или сбросить, используя
лишь POP AF и PUSH AF. Однако
эмпирическим путем (т.е. методом
научного тыка) было определено,
что значение этих битов зависит
от 8-и бит результата последней
инструкции, которая воздействует
на обычные биты регистра флагов
F. (Уфф, ну и сказал).
Пример 1:
После ADD A,B биты 7,5 и 3
будут идентичны битам регистра А
(бит 7 регистра F - бит знака,
понятно, что он также берется из
7-го бита A).
Пример 2:
После инструкции CP x (где
x, разумеется, регистр, (HL) или
константа), в недокументирован-
ных битах будут находится биты
аргумента.
Рассмотрим инструкции, кото-
рые оперируют с 16-битовым сло-
вом. В этом случае значение не-
документированных битов следует
брать из старших 8-ми бит ре-
зультата. Так, S-флаг берем из
15-го бита результата.
За примером программы, кото-
рая использовала бы недокументи-
рованные биты регистра F, далеко
ходить не надо. Возьмем очень
старую программу Sabre Wulf '84.
Носорог в этой программе бежит в
одну, затем в другую сторону,
благодаря следующей последова-
тельности инструкций:
#AD86 DDCB067E BIT 7,(IX+6)
#AD8A F28FAD JP P,#AD8F
Не правда ли, оригинально!
Те, кто сталкивался на прак-
тике с системой защиты программ,
называемой Speedlock, обратили
внимание, что для того чтобы
"пройти шагом" по программе да-
лее, необходимо точнейшим обра-
зом обойти все ловушки, такие,
как показано выше. К слову ска-
зать, наши "отечественные" сис-
темы такого рода на базе вышес-
казанного смотрятся более чем
скромно...
В заключение следует также
сказать, что ROM для 128-го
Спектрума использует AF для вре-
менного хранения адреса подпрог-
раммы.
Как принято во всем цивилизо-
ванном мире, я передам огромное
спасибо автору отменного эмуля-
тора ZX-SPECTUM 48/128 + Sammy +
Interface I & more...more... для
IBM PC, Z80 v2.01:
Hello & thanx, Gerton A. Lunter!
Отдельные моменты его советов
изложены выше.
Как уже было сказано, еще есть
темы, о которых можно погово-
рить.
P.S.
Эту статью не следует воспри-
нимать как Истину в последней
инстанции (Истина находится в
оригинальной "фирменной" доку-
ментации, которой не существу-
ет). Любая неверно данная инфор-
мация связана с моим возможным
заблуждением относительно трак-
товки данного вопроса. Любая не-
полно(!) данная информация сяза-
на ислючительно с моей неуверен-
ностью в правильной трактовке
данного вопроса, а не с нежела-
нием давать подобную информацию
в силу других причин (если это
не указано особо), за исключени-
ем "очевидных" вещей, где сте-
пень "очевидности" остается на
моей совести. Поэтому Вы можете
присылать любые дополнения и пр.
Любые претензии касательно СО-
ДЕРЖАНИЯ по сути, высказанные в
некорректной форме, не принима-
ются и не обсуждаются.
Автор не вступает в переписку с
читателями ни под каким видом,
однако присланная Вами информа-
ция будет полезна при подготовке
материала следующих статей.
С уважением, Fanatic Stas.
* * *