ZX-Ревю 1993 №1-2 1992 г.

Применение ассемблера для создания быстроработающих программ - в основу этой книги положена весьма плодотворная идея - опереться на знание пользователем БЕЙСИКа и постепенно развивать эти знания в направлении машинного кода.


>ПРИМЕНЕНИЕ АССЕМБЛЕРА ДЛЯ СОЗДАНИЯ БЫСТРОРАБОТАЮЩИХ ПРОГРАММ

предисловие

Известные книги, справочники и руководства по машинному языку процессора Z-80 используемого в компьютере "ZX-Spectrum" в основном ограничиваются описанием действий всех команд процессора и порядком применения этих команд на простейших примерах программ в машинных кодах. В лучшем случае приводятся программы для сложения чисел или им подобные.

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

Как нам кажется, в основу этой книги положена весьма плодотворная идея -опереться на знание пользователем БЕЙСИКа и постепенно развивать эти знания в направлении машинного кода, шаг за шагом показывая как алгоритмы БЕЙСИКа переносятся на язык АССЕМБЛЕРа. Эта концепция очень хорошо укладывается в тот стиль работы, который "ИНФОРКОМ" ведет уже третий год на страницах "ZX-РЕВЮ" и в прочих своих книгах.

Нам также показалась очень привлекательной идея книги дать широкое представление конкретному программисту о возможности использования процедур, "зашитых" в ПЗУ для своей повседневной работы. Это может заинтересовать и тех, кто достаточно хорошо знает "АССЕМБЛЕР, но не имеет доступной информации об использовании процедур ПЗУ в своих программах.

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

К сожалению, мы не могли бы сказать, что оригинал написан простым доступным языком, понятным каждому неспециалисту. Но мы очень хорошо потрудились над ее адаптацией. Оставив по сути без изменения структуру книги и ее фактическое содержание, мы полностью переработали всю методику подачи материала и надеемся, что сделали ее доступной для неподготовленного читателя, впрочем о том, как это удалось, судить будете Вы сами.

Поскольку сама книга фактически не является учебником по машинному кодированию, а служит практическим пособием для тех, кто пошел по этому пути, мы должны напомнить Вам о целесообразности приобретения нашего издания "Программирование в машинных кодах. Первые шаги, практикум. Справочник". По этой книге уже обучились тысячи пользователей и она пока продолжает оставаться лучшим из всего, что было написано на данную тему.

Для тех наших читателей, которые сейчас решают вполне естественный вопрос о целесообразности приобретения всего комплекта "ZX-РEВЮ-93", мы даем содержание книги, которая войдет в "РЕВЮ-93" полностью:

1. Вывод на экран.

2. Команды PLOT, DRAW, CIRCLE.

3. Счет очков в программах.

4. Случайные числа.

5. Опрос клавиатуры.

6. Перемещение объектов.

7. Музыкальные и звуковые эффекты.

8. Команды ATTR, SCREEN$, POINT.

Стюарт Николс

9. Работа с принтером.

10. Разбор конкретного примера перевода игровой программы из БЕЙСИКа в машинный код.

1. ВЫВОД НА ЭКРАН

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

На компьютере "ZX_SPECTRUM" можно создать 21 графический элемент, форма которых полностью определяется пользователем. Это так называемые символы графики пользователя (User Definable Graphics - UDG). Необходимо как можно полнее использовать эти символы в своих программах при выводе информации на экран. Например, при создании игровой программы типа "космических завоевателей" для получения отдельных фрагментов изображения экрана можно использовать те же символы, что используются для создания самих "завоевателей" или других объектов.

Для вывода информации на экран целесообразно использовать контрастные цвета. Не рекомендуется использовать вместе красный и розовый, желтый и белый и т.п. Благоразумно в программах использовать только черный и белый цвета, так как не все пользователи имеют цветные мониторы или цветные телевизоры.

Так как выводить информацию на экран необходимо при работе практически любой программы, то мы начнем нашу книгу с того, что рассмотрим в этой главе способы перевода команды БЕЙСИКа PRINT в машинный код.

Обычно БЕЙСИК-программа начинается с того, что определяются основные цветовые атрибуты, например:

10 PAPER 3: INK 1: BORDER 5

Затем эти атрибуты устанавливаются в системных переменных компьютера и становятся действующими. Делают это командой CLS. 20 CLS

Давайте попробуем сделать то же самое в машинном коде. Самой простой будет операция установления цвета бордюра. Она займет всего лишь 6 байтов в оперативной памяти.

Сначала в регистр A процессора заносится число 5 (оно означает зеленый цвет бордюра), а затем вызывается процедура ПЗУ, которая выполнит изменение этого цвета. Данная процедура называется BORDER и находится она в ПЗУ по адресу 229ВН (8859 DEC).

Процедура не только установит необходимый цвет окантовки экрана, но и передаст значение номера цвета в системную переменную BORDER (23624 DEC - 5С48Н). Для хранения номера цвета бордюра в этой системной переменной отведены 3 бита (с третьего по пятый) и, таким образом, всего могут быть установлены до 8 различных цветов. Оставшиеся биты в этой системной переменной используются для хранения цветовых атрибутов нижней части экрана (системного окна). Системное окно занимает как правило (не всегда) две нижние строки экрана, в которых Вы выполняете INPUT или редактирование программы. Биты 0...3 определяют номер цвета INK в системном окне, бит 6 отвечает за параметр BRIGHT, а бит 7 - за параметр FLASH.

Итак, программа в машинных кодах, эквивалентная команде БЕЙСИКа BORDER 5, будет выглядеть так, как показано на листинге 1.1 (Предполагается, что машинной код начинается с адреса, заданного директивой АССЕМБЛЕРа ORG).

Листинг 1.1

АДРЕС МАШ.КОД АССЕМБЛЕР КОММЕНТАРИЙ ORG 23760

23760 3Е 05 LD А,5 ;Установили в аккумуляторе число

; "5" - код зеленого цвета.

23762 CD 9В 22 CALL 8859 ;Вызов процедуры ПЗУ "BORDER".

23765 С9 RET ;Выход.

Выполнить установку цветов INK и PAPER немного сложнее и соответствующая программа в машинных кодах у нас займет уже не 6, а 13 байтов (она приведена на листинге 1.2).

За установку цветов PAPER и INK в основной части экрана отвечает системная переменная ATTR-P (23693 DEC = 5C8D Н). Поэтому установка этих цветов из машинного кода сводится к переключению битов в данной системной переменной, а раскладка этих битов такова:

7 6 5 4 3 2 1 0

x

x

x

x

x

x

x

x

Цвет PAPER Цвет INK

- Параметр BRIGHT

- Параметр FLASH

Если мы хотим из машинного кода дать команду, аналогичную PAPER 3; INK 1, то нам надо включить биты в системной переменной ATTR_P следующим образом:

7 6 5 4 3 2 1 0

0

0

0

1

1

0

0

1

0 + 0 + 0 + 16 + 8 + 0 + 0 + 1 = 25

Т.е. фактически нам надо было бы в ячейку памяти с адресом 23693 заслать число 25, например так:

LD (23693),25

Но такой команды, которая позволила бы заслать произвольное число в произвольную ячейку памяти компьютера у процессора Z-80 нет. Приходится немного комбинировать.

Сейчас у нас есть возможность познакомиться с интересным способом адресации в процессоре Z-80, который называется индексной адресацией. Дело в том, что в процессоре есть шестнадцатиразрядная регистровая пара IY, в которой может храниться какое-либо целое число от 0 до 65535. Работа компьютера "ZX-Spectrum" организована таким образом, что после включения его в сеть в этой регистровой паре устанавливается число 23610 (Это адрес системной переменной ERR_NR). И этим активно пользуются на практике. Есть неофициальная договоренность, что для работы с системными переменными используется эта регистровая пара. При этом не надо указывать адрес нужной Вам системной переменной, а достаточно указать "смещение", т.е. величину, на которую отстоит нужный Вам адрес от заранее установленного в регистре IY. Тогда вместо LD (23693),25 можно записать команду: LD (IY+83),25

Эта запись выглядит понятнее уже хотя бы потому, что все, кто программируют на "Спектруме" в машинных кодах, сразу мгновенно понимают: раз используется IY, значит здесь загружают какую-то системную переменную. А какую именно, они быстро определят, ОТКРЫВ таблицу системных переменных.

Вернемся к нашему примеру, см. листинг 1.2. Итак, в первой строчке мы установили необходимые цвета PAPER и INK.

Листинг 1.2

АДРЕС

МАШ

.КОД

АССЕМБЛЕР

ORG 23760

23760

FD

36 53 19

LD (IY+83),25

23764

3E

02

LD A,02

23766

CD

01 16

CALL 5633

23769

CD

6В 0D

CALL 3435

23772

C9

RET

АДРЕС МАШ.КОД

АССЕМБЛЕР ORG 23760 LD A,2 CALL 5633 LD A,65 RST 16 RET

КОММЕНТАРИЙ

Установили в системной переменной BORDER значения INK и PAPER. Подготовка к открытию канала 2. Открываем канал 2. Вызов процедуры CLS. Выход.

Листинг 1.3

КОММЕНТАРИЙ

Подготовка к открыванию канала.

Открываем канал экрана.

Код символа "А".

Вызов процедуры печати символа.

Выход.

Листинг 1.4

КОММЕНТАРИЙ

Подготовка к открыванию канала.

Открываем канал экрана.

Код символа "H".

Вызов процедуры печати символа.

Код символа "E".

Вызов процедура печати символа.

Выход.

АДРЕС МАШ.КОД

23760 3E 02

23762 CD 01 16

23765 3E 48

23767 D7

23768 3E 45 23770 D7 23768 C9

АССЕМБЛЕР ORG 23760 LD A, 2 CALL 5633 LD A,72 RST 16 LD A,69 RST 16 RET

Теперь мы должны дать команду CLS. Это тоже сделает за нас процедура, записанная в машинном коде ПЗУ. Данная процедура так и называется - CLS и находится по адресу 0D6BH = 3435 DEC.

Вместе с тем, Вы по-видимому обратили внимание на то, что перед вызовом этой процедуры вызывается еще одна процедура ПЗУ по адресу 5633 (1601Н). Это весьма важная процедура, она называется CHAN_OPEN, и мы будем еще не раз использовать ее при изучении материалов данной главы. Вызовом этой процедуры открывается канал вывода данных на экран - это канал под номером 2 и потому перед вызовом процедуры в регистр A загружается число 2. Когда Вы работали в БЕЙСИКе, то могли не думать о назначении каналов. Если же Вы выдаете информацию из машинного кода, то никто за Вас этого не сделает, а сделать это необходимо, иначе компьютер не поймет, куда надо подавать информацию.

Теперь Вы, уважаемые читатели, должны уметь устанавливать в машинном коде атрибуты экрана и выполнять очистку экрана. Давайте посмотрим как же нам напечатать на экране что-нибудь содержательное. Проще всего напечатать на экране какой-либо символ. В листинге 1.3 показан пример программы, которая напечатает символ "А" (символ имеет номер 65 DEC) в левом верхнем углу экрана с координатами позиции печати (0,0). Именно такие координаты текущей позиции устанавливаются после того, как отработает процедура CLS.

Если Вы хотите распечатать на экране какой-либо символ, то его код предварительно должен быть заслан в регистр A процессора, после чего должна быть выдана команда RST 16, что Вы и видите на листинге 1.3. По команде RST 16 процессор запустит процедуру ПЗУ PRINT_A_2, находящуюся по адресу 15F2H = 5618 DEC. Символ, код которого находится в аккумуляторе будет напечатан и осуществится переход к следующей позиции печати.

Если с этим Вам все понятно, то Вы без труда поймете работу программы 1.4, которая напечатает целое слово - "НЕ", поочередно засылая символы в аккумулятор и выдавая их командой RST 16.

Хорошо, что слово "НЕ" имеет только два символа, а как быть, если нужно напечатать длинное предложение? Понятно ведь, что кодировать печать длинной фразы по символам дело очень утомительное, к тому же необходим большой расход оперативной памяти - он в два раза больше, чем длина Вашего сообщения, поскольку на каждый символ еще нужна команда RST 16, занимающая байт.

Для решения этой проблемы существуют как минимум три пути.

Главная идея состоит в том, чтобы записать все символы выводимого сообщения в некоторый банк данных и считывать их оттуда по одному до тех пор, пока весь банк не будет исчерпан. Этот прием показан в Листинге 1.5 (версия 1).

В этом листинге Вы знакомитесь с двумя новыми регистровыми парами - ВС и DE. Как правило, пара ВС используется программистами для организации в ней разного рода счетчиков, а пара DE - для указания на какой-либо адрес в памяти компьютера. Регистры B,C,D и Е не обязательно должны использоваться парами, как это было с регистром IY. Они могут использоваться и как одиночные восьмибитные регистры для хранения целых чисел от 0 до 255.

Обратите внимание на пару операций

LD A,B OR C

Это очень быстрый, экономичный и к тому же общепринятый способ проверки ВС на ноль. Поскольку в регистре A у нас загружено содержимое регистра B, то результат операции OR C будет нулевым в том и только в той случае, если и B и C равны нулю.

Листинг 1.5 (Версия 1).

АДРЕС

МАШ

].КОД

АССЕМБЛЕР КОММЕНТАРИЙ

ORG 23760

23760

3E

02

LD A,2

Подготовка к открыванию канала.

23762

CD

01

16

CALL 5633

открываем канал экрана.

23765

11

E4

LD DE,DATA

В регистровую пару DE загрузили адрес, в котором хранится наше текстовое сообщение.

23768

01

07

00

LD ВС,7

В регистровой паре ВС организовали счетчик на 7 символов.

LOOP

23771

78

LD A^

Проверка не обнулился ли счет

23772

В1

OR C

чик символов в ВС?

23773

C8

RET Z

Выход, если он обнулялся.

23774

LD A,(DE)

Взяли в аккумулятор текущий символ из списка DATA.

23775

D7

RST 16

Напечатали его на экране.

23776

13

INC DE

Перешли к очередному символу.

23777

08

DEC ВС

Уменьшили счетчик символов на 1.

23778

18

F7

JR LOOP

Перешли на метку LOOP для очередной проверки не закончился ли список печатаемых символов.

DATA

23779

72

69

76

80 32 77 69

Начиная с адреса 23779 мы храним

сообщение "HELP ME".

Листинг 1.5 (Версия 2).

АДРЕС

МАШ

.КОД

АССЕМБЛЕР КОММЕНТАРИЙ

ORG 23760

23760

3E

02

LD A,2

Подготовка к открыванию канала

23762

CD

01 16

CALL 5633

Открываем канал экрана.

23765

11

DF 5С

LD DE,DATA

Адрес сообщения.

23768

01

07 00

LD ВС,7

Длина сообщения - 7 символов.

23771

CD

3C 20

CALL 8252

Вызов процедуры ПЗУ PR_STRING.

23774

C9

RET

Выход.

DATA

23775

72

69 76

80 32 77 69

Сообщение "HELP ME".

Обратите также внимание на то, что мы записали наше сообщение, начиная с адреса 23779. Но это совсем не обязательно. Можете хранить свои тексты где хотите, в любых адресах, удобных Вам. Важно только, чтобы в строке LD DE,DATA в регистровую пару DE был заслан истинный адрес начала Вашего сообщения ОТ 0 ДО 65535.

Второй вариант этой программы выглядит немного более простым. Если Вы заранее установили в регистровой паре DE адрес, с которого начинается Ваше сообщение, а в ВС -длину этого сообщения, то больше можно вообще ничего не делать, а вызвать процедуру ПЗУ под названием PR_STRING, которая сама напечатает за Вас это длинное сообщение. Процедура PR_STRING находится по адресу 8252 DEC = 203СН. Пример см. в Листинге 1.5 (версия 2).

Третий способ - самый мощный. Его применяют в тех случаях, когда у Вас заготовлено не одно сообщение, а много, т.е. Вы имеете целую таблицу сообщений, но заранее не знаете, какое когда придется печатать. В этом случае Вам хотелось бы выдавать на экран нужное сообщение указав только его номер. Именно так и поступают в абсолютном большинстве программ, написанных в машинных кодах. Именно так организовано и само ПЗУ, которое, как Вы знаете, хранит в себе много разных сообщений типа "Start tape and press key..." и выдает вам всякий раз именно то, которое надо.

Чтобы программа знала, где кончается одно сообщение и начинается другое, применяют специальный прием - к коду последнего символа сообщения прибавляют число 127, т.е. фактически в последнем символе каждого сообщения принудительно включают старший (7-ой) бит. Таким образом, символ, код которого > 127 является маркером конца сообщения. Теперь нетрудно создать программу для печати 1-го сообщения. Она просмотрит тексты, начиная с адреса, установленного в DE, отсчитает N-1 маркер и начнет печатать то, что найдет после него. Символы будут печататься по одному до тех пор, пока не будет найден N-ый маркер. Для печати последнего придется предварительно отнять от его значения число 127.

В листинге 1.5 приведен пример такой работы, но для простоты там принято, что у Вас есть не таблица, а только одно сообщение, заканчивающееся инвертированным символом (к коду символа прибавлено число 127).

Кстати, обратите внимание на то, что если числа, большие чем 27, являются маркерами конца сообщения, то очевидно нельзя допускать, чтобы в Ваших текстах были символы, код которых больше 27, т.е. символы блочной графики коды от 128 до 143) и символы графики пользователя (коды от 144 до 164) воспроизводить таким методом нельзя.

Похожая на эту, но более сложная процедура вывода на экран значений клавишных слов и сообщений об ошибках используется в ПЗУ компьютера. Стартовый адрес этой процедуры - 3082 -DEC = 0C0AH.

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

Так, они могут быть легко выведены на экран с помощью команды RST 8. Байт, следующий за этой командой, определяет какой вид сообщения необходимо вывести, например, если необходимо вывести на экран сообщение "K invalid colour", которое в перечне сообщений об ошибках является двадцать первым по счету, то необходимо записать:

RST 8

DEFB 19 (номер сообщения минус 2)

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

Теперь мы можем приступить к рассмотрению способов вывода на экран символов или даже целых строк в заданную позицию на экране. В BASIC-программах это выполняется с помощью оператора PRINT AT, после которого записывается номер строки, номер столбца и, наконец, само сообщение, которое необходимо вывести на экран.

Для этого используются так называемые управляющие коды. Если Вы посмотрите любую таблицу символов ASCII, то увидите, что печатным символам соответствуют коды, начиная с 32 DEC (это символ "пробел". А коды с 0 до 31 является непечатными (т.е. не имеют закрепленной за ними литеры) и используются в качестве управляющих. Так, например, в "Спектруме" коды с 0 по 5 и с 24 по 31 вообще не используются, а с 6 по 23 -служат в качестве управляющих. (В компьютерах других систем это может быть и не так).

За координаты позиции печати отвечает код 22, он является аналогом БЕЙСИКовского оператора AT. К нашему счастью, команда RST 16 распознает код 22 как PRINT AT и использует следующие 2 байта как "x" и "y" координаты, задающие PRINT-позицию для вывода сообщения на экран. Программа 1.6 демонстрирует использование последовательности байтов DEFB 22 DEFB 3 DEFB 5

как аналог оператора

PRINT AT 3,5.

Совершенно так же можно применять коды 23 и 13 как аналоги операторов TAB и ENTER, соответственно.

Листинг 1.5 (Версия 3).

АДРЕС

МАШ

.КОД

АССЕМБЛЕР КОММЕНТАРИЙ

ORG 23760

23760

3E

02

LD A,2

Подготовка к открыванию канала.

23762

CD

01

16

CALL 5633

Открываем канал экрана.

23765

11

Е5

LD DE,DATA

Адрес начала сообщения.

LOOP

23768

1A

LD A,(DE)

Взяли текущий символ.

23769

CB

7F

BIT 7,А

Проверяем его старший бит.

23771

20

04

JR NZ,END

Если он не нулевой, то это последний символ и мы переходим на метку END.

23773

D7

RST 16

Иначе печатаем его на экране.

23774

13

INC DE

Перешли к очередному символу.

23775

18

F7

JR LOOP

Возврат на метку LOOP.

END

23777

CB

BF

RES 7,А

Выключили старший бит последнего символа.

23779

D7

RST 16

Напечатали последний символ.

23780

C9

RET

Выход DATA

23781

72

69

76

80 32 77 197

Сообщение "HELP ME".

Листинг 1.6

АДРЕС

МАШ

.КОД

АССЕМБЛЕР КОММЕНТАРИЙ

ORG 23760

23760

3E

02

LD A,2

Подготовка к открыванию канала.

23762

CD

01 16

CALL 5633

Открываем канал экрана.

23765

11

DF 5C

LD DE,DATA

Адрес начала сообщения.

23768

01

0С 00

LD ВС,12

Длина сообщения с учетом управляющих

23771

CD

ЗС 20

CALL 8252

Вызов процедуры ПЗУ PR_STRING

23774

C9

RET

Выход DATA

23775

22

DEFB 22

Код управления позицией печати

23776

03

DEFB 3

Координата "Y=3"

23777

05

DEFB 5

Координата "Х=5"

23778

84

72 65

78

Текст сообщения "THANK YOU"

23783

32

89 79

65

Листинг 1.7

АДРЕС

МАШ

.КОД

АССЕМБЛЕР КОММЕНТАРИЙ

ORG 23760

23760

3E

02

LD A,2

Подготовка к открыванию канала.

23762

CD

01

16

CALL 5633

Открываем канал экрана.

23765

11

E2

LD DE,DATA

Адрес начала сообщения.

23768

01

24

00

LD ВС,36

Длина сообщения с учетом управляющих

23771

CD

3C

20

CALL 6252

Вызов процедуры ПЗУ PR_STRING

23774

CD

4D

0D

CALL 3405

Копирование ATTR-P в ATTR-Т.

23777

C9

RET

Выход DATA

23778

22

04

07

17 02

Сообщение CAN YOU READ THIS с

инплантированными в нем кодами управления координатой позиции печати и кодами управления цветовыми атрибутами.

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

INK - код 16

PAPER - код 17 FLASH - код 18 BRIGHT - 19 INVERSE - 20 OVER - код 21

Программа 1.7 показывает как используются управляющие коды, соответствующие PAPER, INK, BRIGHT и т.д.

После использования временных цветов для вывода на экран сообщения необходимо вернуться к постоянным цветам для обеспечения дальнейшего вывода. Для режимов OVER и INVERSE это требование легко выполняется, так как команда RST 16 легко распознает их управляющие коды. Для изменения PAPER, INK, BRIGHT и FLASH, необходимо вызвать из ПЗУ процедуру (адрес 3405), которая копирует содержимое системной переменной ATTR-P (23693) в системную переменную ATTR-^23695).

(Продолжение следует)

Михайленко В.С., Турович А.К.




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Премьера - новый великолепный музыкальный редактор "Pro Sound Maker" и программа "Visual Decompressor" для использования различных эффектов при декомпрессии экранных файлов.
Sega online - описания и порты к сеговским играм.
INCOMING - Описание особенностей игры DAEMON.
Сладкие - осуждение.
Содержание - краткое описание материалов первого номера журнала.

В этот день...   3 декабря