4. РАЗБОР ПРОГРАММ В МАШИННЫХ КОДАХ.
Для закрепления практических навыков мы предлагаем Вашему вниманию подробный разбор некоторых реальных процедур.
Мы рассмотрели в качестве примеров ответы на конкретные вопросы, которые в своих письмах задают нам наши читатели. Как организуется вывод на бордюр экрана цветных полос? Часто это можно видеть при загрузке фирменных игровых программ (например, "BOMB JACK", "INTERNATIONAL KARATE"). Как осуществляется в машинных кодах управление от джойстика и клавиатуры, как можно вывести текст на экран и др.?
4.1. Вывод на бордюр цветных полос.
Из части 1 Вы должны знать, что управление бордюром производится по трем младшим битам порта 2 54 (FE HEX) . Идея организации вывода разноцветных полос состит в том, чтобы выдавать по этому порту команды на изменение бордюра, причем делать это надо с достаточной частотой. Если частота сигналов на изменение цвета много меньше кадровой частоты телевизионного изображения, то Вы увидите только мигание и изменение цвета бордюра (как в режиме ожидания загрузки от магнитофона) . Если эта частота слишком высока, то полосы на экране будут узкими и частыми, так что даже их цвет трудно разобрать .
Мы на примере промоделируем возможность получения цветных полос различной ширины.
Логика работы программы такая. Процессор выбирает какой-либо байт из области ПЗУ, проверяет в нем три младших бита, устанавливает новый цвет бордюра, равный значению этих битов (от 0 до 7) и далее выдерживает паузу, тем большую, чем больше величина поступившего байта. После этого выполняется прием следующего байта на ПЗУ и т. д.
При загрузке программ типа "INTERNATIONAL KARATE" то же самое происходит при приеме очередного байта из магнитофонного порта. Мы, к сожелению, лишены возможности рассмотреть здесь подробно как обрабатывается сигнал, поступивший от магнитофона, поскольку это выполняет пакет процедур, содержащихся в ПЗУ, что выходит за рамки данной книги и рассмотрено подробно в статье "Секреты ПЗУ" в "ZX-РЕВЮ" N 4,5 за 1991 г. и в статье "Защита программ" в "ZX-РЕВЮ" N1,2 за 1993 г. Поэтому рассмотрим управление бордюром на модельном примере. Укажем только, что основная сложность при написании процедур нестандартной загрузки состоит в синхронизации работы процедуры с частотой поступления импульсов от магнитофонного порта, что достигается тщательным расчетом замедляющих циклов.
Процедура ассемблирована, начиная с адреса 2 6000 (6590HEX) и может запускаться RANDOMIZE USR 2 6000.
АДРЕС МАШ.КОД 6590 11FF3F
210000 7E
E607
D3FE 7E
47
10FE
659F 65A0 65A1 65A2 65A3
65A5
23 1B 7A B3
2 0F1 C 9
6593
6596
6597
6599 659B
65 9С 65 9D
МНЕМОНИКА
LD DE,3 FFF
LD HL,0000
LD A, (HL)
AND 07
OUT (FE) ,
LD A, (HL
LD B, A
DJNZ FE
INC HL DEC DE LD OR JR
RET
КОММЕНТАРИИ
В DE помещается длина области ПЗУ В HL - начало ПЗУ
В аккумулятор идет байт из ПЗУ Старшие 5 битов маскируются (гасятся), остаются младшие три Акк-р выдается по 254-му порту Повторно в акк-р загружается тот же байт из ПЗУ и переносится в регистр B Замедляющий цикл, повторяющийся тем дольше, чем больше поступивший байт. Переход на новый байт ПЗУ Уменьшение счетчика байтов Проверка на то, что в счетчике
(DE) достигнут 0 Если нет, то переход назад и повторение для очередного байта Выход из процедуры
Несколько слов о том, как следует практиковаться с нашими процедурами.
Конечно, лучше всего набирать их в программе АССЕМБЛЕР (все равно в каком) . Это позволяет избежать множества мелких ошибок при наборе процедуры. Набрав текст, надо дать команду на компиляцию и после устранения выявленных при компиляции неточ-
Для небольших процедур (до 100. . .200 байтов) в принципе возможен набор процедуры последовательным введением байтов одного за другим из какого-либо АССЕМБЛЕРа, но учебная ценность такого подхода ниже, зато есть возможность в случае появления ошибки использовать отладочные возможности дисассемблера.
Только не забудьте перед пробным запуском отгрузить введенный машинный код на ленту. Вероятность ошибки при вводе достаточно большая и обидно повторять ввод второй раз.
Для совсем маленьких процедур типа той, что мы привели выше, можно выполнить ввод и из БЕЙСИКа. При этом можно перевести шестнадцатиричный код в десятиричный и вводить его через FOR ... READ ... DATA ... POKE ... NEXT, а можно использовать какую-либо БЕЙСИК-программу шестнадцатиричного загрузчика.
Шестнадцатиричным загрузчиком вводят иногда и очень большие блоки кодов (до нескольких килобайт), однако имейте в виду, что набор больших блоков кодов (более 256 байтов) очень сложен и крайне необходимо, чтобы вводимый блок имел контрольные суммы после каждой группы (из 8-ми или 16-ти) байтов и применяемый шестнадцатириный загрузчик должен выполнять проверку этих контрольных сумм.
Для тех, кто не хочет утруждать себя применением АССЕМБЛЕРа или ДИСАССЕМБЛЕРа, в порядке исключения дадим распечатку загрузчика данной процедуры из БЕЙСИКа. 10 DIM a(22) 20 FOR i = 1 TO 2 2 30 READ a(i) 40 POKE (25999+i),a(i) 50 NEXT i
60 DATA 17,255,63,33 7 0 DATA 0,0,126,230 80 DATA 7 , 21 1, 2 54 , 12 6 9 0 DATA 71,16,254,35 100 DATA 2 7, 1 22 , 1 7 9, 32 110 DATA 2 4 1 , 2 0 1 120 RANDOMIZE USR 26000