ZX-Ревю 1993 №3-4 1992 г.

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


Темы статьи: Программирование  

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

Продолжение. (Начало см. в "ZX-РЕВЮ-ЭЗ" N 1,2)

Заканчивая рассмотрение вопросов выдачи информации на экран, мы должны еще обсудить возможность печати в нижней части экрана, т.е. в строках с номерами 22 и 23.

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

Здесь для вывода в нижнюю часть экрана сначала открывается канал с номером "минус 3" (253). Чтобы информационное сообщение "0:0.K.", появляющееся после исполнения программы не переместило выведенную нами на экран строку, необходимо иметь эквивалент команды PAUSE 0 в машинных кодах.

Останов программы можно реализовать, если использовать команду ассемблера HALT, которая приостанавливает работу процессора до очередного прерывания (до очередного сканирования клавиатуры, выполняемого процедурой ПЗУ KEYSCAN). Для реализации команды, аналогичной PAUSE 0, необходимо после команды HALT выполнить проверку состояния 5-го бита системной переменной FLAGS, который включается при нажатии произвольной клавиши. Если этот бит сброшен, то выполняется возврат к команде HALT, в противном случае программа выполняется дальше. Обратите внимание на то, что здесь 22-я строка считается нулевой, а 23-я - первой.

При выводе данных на экран весьма полезной для Вас может оказаться одна процедура из ПЗУ, находящаяся там по адресу 3652. Она позволяет уладить заданное число строк с экрана, причем отсчет строк начинается с 23-й строки, т.е. с ее помощью Вы можете как стирать информацию в системном окне, так и на основном экране. Пользоваться этой процедурой придется, по-видимому очень часто.

Перед вызовом процедуры необходимо записать в регистр B число удаляемых строк. Атрибуты экрана остаются такими, какие записаны в системной переменной ATTR-P. Так, например, нижние две строки экрана могут быть очищены с помощью следующей короткой программы: LD B,2 CALL 3652 RET

Листинг 1.8

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

АДРЕС

МАШ

. КОД

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

ORG 23760

23760

3E

FD

LD A,253

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

23762

CD

01

16

CALL 5633

Открываем канал "системного окна компьютера"

23765

11

EA

LD DE,DATA

Адрес начала выводимых данных.

23768

01

1E

00

LD BC,30

Длина данных с учетом управляющих кодов.

23771

CD

3C

20

CALL 8252

Вызов процедуры ПЗУ для печати сообщения.

WAIT

Начало процедуры "задержки", аналогичной PAUSE 0.

23774

76

HALT

Прекращение работы процессора до прихода системного прерывания

23775

FD

CB

01 6E

BIT 5,(IY+1)

Проверка пятого бита системной переменной FLAGS.

23779

28

F9

JR Z,WAIT

Если он выключен - клавиша не нажималась, то возврат на метку WAIT.

23781

FD

CB

01

AE

RES 5,(IY+1)

Если он включен, то выключаем его и продолжаем работу

23785

C9

RET

Выход из процедуры.

DATA

22

00

10

Аналог "AT 0, 10"

73

78

80

85

84

текстовое сообщение

32

76

73

78

69

"INPUT LINE 0", записан

32

48

ное в кодах ASCII.

22

01

10

Аналог "AT 1, 10"

73

78

80

85

84

Текстовое сообщение

32

76

73

78

69

"INPUT LINE 1", записан-

32

49

ное в кодах ASCII.

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

Команда PLOT x,y позволяет поставить на экране точку (включить пиксел), координата которой определяются значениями x и у, а цвет зависит от установленного значения INK. Координата x определяет номер столбца, а координата у - номер строки той точки экрана, где будет включен пиксел.

Пиксел, координаты которого равны 0,0, находится в нижнем левом углу экрана, а пиксел с координатами 175,255 - в верхнем правом углу экрана.

Для этой цели в ПЗУ компьютера имеется процедура PLOT, у которой есть две возможные точки входа.

Первая точка входа имеет адрес 8933 DEC (22E5 HEX). Перед вызовом этой процедуры по команде CALL 8933, необходимо в регистр B записать значение координаты у (0...175), а в регистр C - значение координаты x (0...255). Пример записи показан в программе 2.1.

Листинг 2.1

АДРЕС

МАШ

и. КОД

АССЕМБЛЕР ORG 23760

КОММЕНТАРИЙ

23760

08

7D

LD B,125

;Координата y=

=125.

23762

0E

4B

LD C,75

;Координата x=

=75.

23764

CD

E5 22

CALL 8933

;Печать точки

(125,75)

23767

C9

RET

;Возврат.

Использование десятиричных чисел вместо шестнадцатиричных мы применяем только для того, чтобы начинающие читатели быстрее адаптировались к сути работы в машинном коде. Они более наглядны, если применяется раздельная загрузка регистров B и C. Однако, если записывать координаты сразу же в регистровую пару BC, то лучше все же использовать шестнадцатиричные числа - при такой записи проще представить положение пиксела на экране.

Вторая точка входа имеет адрес 8924 DEC (22DC HEX). При этом значения координат x и у должны быть предварительно записаны не в регистровую пару BC, а на стек так называемого встроенного калькулятора, причем значение у должно находиться на вершине стека, а значение x - под ним.

Начинающий программистам надо сказать и несколько слов о стеке калькулятора.

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

приходится программировать его вручную.

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

Остается, правда, пока открытым вопрос, а как же записать координаты своей точки на стек калькулятора? Очень просто, для этой цели тоже используется процедура ПЗУ компьютера? Она находится по адресу 11560 DEC (2D28 HEX). Вам нужно поместить желаемое число в регистр A процессора и вызвать эту процедуру. Число будет передано на стек, чтобы отправить туда два числа, операцию надо сделать дважды. Естественно, что то число, которое будет передано последним и будет размещено на вершине стека.

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

Листинг 2.2

КОММЕНТАРИЙ

Координата x=75. Поместили x на стек калькулятора. Координата y=125 Поместили ее на стек. Печать точки (125,75) Возврат.

АДРЕС

23760 23762

23765 23767 23770 23773

МАШ. КОД

3E 4B CD 28 2D

3E 7D CD 28 2D CD DC 22 C9

АССЕМБЛЕР ORG 23760 LD A,75 CALL 11560

LD A,125 CALL 11560 CALL 8924 RET

Листинг 2.3

АДРЕС

МАШ

. КОД

АССЕМБЛЕР

КОММЕНТАРИЙ

ORG 23760

23760

3E

03

LD A,3

23762

FD

77 57

LD (IY+87)

A

Включение двух младших битов сист. перем. P_FLAG

23765

06

28

LD B,40

Координата у=40.

23767

0E

19

LD C,25

Координата х=25

23769

CD

E5 22

CALL 8933

Печать точки (40,25) в ре жиме OVER 1.

23772

AF

XOR A

Очистка регистра A.

23773

FD

77 57

LD (IY+87)

A

Восстановление P_FLAG.

23776

C9

RET

Возврат.

АССЕМБЛЕР ORG 23760 LD L,64 LD H,00 ADD HL,HL ADD HL,HL ADD HL,HL LD DE,(23606)

АДРЕС

23760 23762

23764

23765

23766

23767

МАШ. КОД

2E 7F 26 00 29 29 29

ED 5B 36 5C

23771

19

23772

06 08

ADD HL,DE

LD B,8

Листинг 2.4

КОММЕНТАРИЙ

;Номер символа "@"=64 DEC. ;Теперь в паре HL число 64 ;Умножили его на 2. ;Умножили его на 4. ;умножили его на 8. ;Загрузили в DE адрес, на ;который указывает системная переменная CHARS. ;Прибавили к нему "смещение" нашего символа от ;начала символьного набо-;ра, ранее вычисленное в ;регистровой паре HL. ;Счетчик строк в шаблоне символа, равный 8.

Запомнили адрес начала шаблона на машинном стеке Счетчик столбцов в шаблоне символа, равный 8. Принимаем в аккумулятор байт шаблона символа. Запомнили содержимое BC, чтобы освободить BC для других дел.

Ввод в BC координат позиции печати.

Ротация регистра A влево. Содержимое старшего бита при этом переходит во флаг CARRY регистра F. Запомнили регистры A и F на машинном стеке. Если флаг CARRY выключен, то точку печатать не надо. Делаем обход печати. Перед печатью точки запоминаем координаты. Вызов процедуры PLOT. Восстановили координаты. Переход к очередному столбцу символа. Запомнили новую позицию печати.

Восстановление пары AF. Восстановление счетчиков в BC Уменьшение счетчика столбцов. Если он еще не обнулился возвращаемся для печати соседней точки в ряду. Если же он равен 0, то с этим рядом закончили и надо переходить к новому. Сперва временно запомним счетчики. Возьмем координаты. Уменьшим номер ряда. Число 248 - это то же самое, что и "минус 8". В результате сложения из содержимого C (коорд. x) будет вычтено 8. Результат оставлен в A. Перенесем его в C и запомним в переменной COORD. Восстановили счетчики рядов и столбцов. Восстановление указателя. Приняли из символьного набора конструкцию очередного ряда. Уменьшаем на единицу счетчик рядов в B и если он еще не обнулялся, то возвращаемся назад. Выход

PUSH HL LD C,B LD A,(HL) PUSH BC

E5

0E 08

7E

C5

ED 4B 0E 5D 17

LD BC,(COORD) RLA

PUSH AF JR NC,23792

F5

30 05

C5

CD E5 22 C1

0C

ED 43 0E 5D

F1 C1 0D

20 E8

PUSH BC

CALL 8933 POP BC INC C

LD (COORD),BC

POP AF POP BC DEC C

JR NZ,23778

C5

PUSH BC

ED 4B 0E 5D 05

3E F8 81

LD BC,(COORD) DEC B LD A,248

ADD A,C

LD C,A

LD (COORD),BC POP BC POP HL INC HL

DJNZ 23774

4F

ED 43 0E 5D

C1

E1

23

10 D1

C9 RET

DEFB 100 DEFB 20

;Координата y=100 ;Координата x=20

тма 2.2 показывает использование процедуры PLOT со второй точкой входа C HEX). Процедура PLOT снимет два верхних числа со стека калькулятора и как координаты для включения пиксела на экране. Числа на стеке при этом не

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

PLOT OVER 1; x,y.

В этой программе перед вызовом процедуры PLOT необходимо включить нулевой и первый биты системной переменной P-FLAG (IY+87). А затем, после вызова процедуры PLOT, восстановить прежнее значение этих битов. Если этого не сделать, то и все последующие точки и символы будут выводиться на экран в режиме OVER 1.

Включение режима INVERSE аналогично включению режима OVER. Отличие состоит лишь в том, что теперь необходимо включить 2-ой и 3-ий биты системной переменной P-FLAG, т.е. надо записать в эту переменную число 12.

Используя точку входа 8933, мы можем написать программу для построения символа в любом месте экрана по точкам. При этом код ASCII символа должен быть в диапазоне 32... 127, а шаблон символа (его конструкция) должен быть задан в участке символьного набора (см. программу 2.4).

Чтобы определить, где хранятся конструкции (шаблоны) символов, служит системная переменная CHARS (23606 DEC = 5C36 HEX). Тот адрес, который в ней хранится, указывает на 256 байтов ниже, чем начало символьного набора.

В программе 2.4 код выводимого на экран символа записывается в регистр L. Затем это значение умножается на 8 (т.к. в символьном наборе на конструкцию каждого символа использовано по 8 байтов) и результат суммируется с числом, которое хранится в системной переменной CHARS. Таким образом определяется начальный адрес восьми байтов, описывающих форму нужного вам символа.

Вы знаете, что первые 32 символа (с 0 по 31) являются непечатными, поэтому очень удобно, что CHARS указывает на 256 байтов ниже, чем начало набора, т.к. благодаря этому они-то как раз и оказываются пропущенными (32*8=256).

Теперь регистровая пара HL используется как указатель адреса очередного байта, а регистровая пара BC - как счетчик элементов матрицы 8x8 битов, описывающей форму символа. Здесь в B хранится номер текущего ряда, а в C - номер столбца. Регистр A используется для манипуляций с текущим байтом.

Листинг 2.5

АДРЕС

МАШ

. КОД

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

ORG 23760

23760

2E

7F

LD L,87

Номер символа "W"=87 DEC

23762

Строки 23762... 23791

этой программы соответ-

23791

ствуют программе 2/4.

23792

04

INC B

Переход к очередной стро-

ке экрана.

23793

ED

43

0E

5D

LD(COORD),0BC

Запомнили позицию печати

23797

F1

POP AF

Восстановление пары AF.

23798

C1

POP BC

Восстановление счетчиков.

23799

0D

DEC C

Уменьшение счетчика

столбцов.

23800

20

E8

JR NZ,23778

Если он еще не обнулялся,

возвращаемся для печати

соседней точки в ряду.

23802

C5

PUSH BC

Переходя к очередному ря

ду, запомнили счетчики.

33803

ED

4B

0E

5D

LD BC,(COORD)

Возьмем координаты.

23807

05

DEC B

Уменьшим номер ряда.

23808

3E

F8

LD A,248

Уменьшение координаты

23810

80

ADD A,B

y на 8.

23811

47

LD B,A

23812

ED

43

0E

5D

LD (COORD),BC

Запомнили координату.

23816

C1

POP BC

Восстановили счетчики ря

дов и столбцов.

23817

E1

POP HL

Восстановление указателя.

Очередной ряд.

23818

23819

23

10 D1

INC HL DJNZ 23774

Уменьшаем на единицу сче тчик рядов в B и если он еще не обнулился, то воз вращаемся назад.

Выход

23821

C9

RET

:Координата y=100 ;Координата х=20

COORD 23822 23323

DEFB 100 DEFB 20

Так, например, одной из манипуляций является ротация байта влево командой RLA, которая производит циклическое смещение всех битов байта влево и перенос седьмого бита во флаг CARRY. Если этот бит равен единице, то флаг CARRY включается, следовательно будет включен и соответствующий пиксел на экране, если же бит равен 0, то не включатся ни флаг, ни пиксел. Команда RLA выполняется по 8 раз для каждого из 8 байтов, описывающих шаблон символа.

После каждой команды RLA координаты очередного пиксела изменяются. Начальное значение этих координат соответствует верхнему левому углу матрицы 8*8 битов, хранящей форму символа. Понятно, что при этом начальное значение координаты у должно быть в диапазоне 7...175, а значение координаты x может быть в диапазоне 0...255. Если же это значение окажется больше, чем 255, то это равносильно тому, что значение равно 0, так как если C=255 и выполняется команда INC C, то результат будет C = 0.

Эта программа может быть легко модифицирована для вывода на экран символа, развернутого на 90 градусов против часовой стрелки (см. программу 2. 5).

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

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

Обычно каждый спрашивает "а почему компьютер печатает только символами 8X8?" Почему нельзя печатать символами 5X8, 6X8 и даже 3X6, как например в программе "THE LAST WORD 2". Почему нельзя печатать символами 17X18? Может быть для тех, кто пишет программу на японском языке это было бы очень удобно.

Оказывается, если Вы печатаете из БЕЙСИКа или из машинного кода командой RST 16 или процедурой ПЗУ, которая опирается на RST 16, Вы действительно ограничены системным требованием размера 8x8. Так уж заложено в системных процедурах ПЗУ. Но если Вы выполняете графическую печать, то есть как бы не печатаете свои символы, а рисуете их по точкам, то можете обойти эти процедуры и создать свои, которые позволят вам делать все, что захотите.

Листинг 2.6

5 OVER 0: INK 0: PAPER 6: BORDER 3: CLS

10 LET x=24: LET y=79: LET h=5: LET w =2: LET a$="STOP THE TAPE" 15 INK 2: RANDOMIZE USR 32393: PAUSE 100 20 LET w=8: LET y=150: LET x=0: LET a$="PLOT" 30 INK 1: RANDOMIZE USR 32393

35 LET a$ =" ": LET y=140: INK 1: RANDOMIZE USR 32393

250 PRINT AT 8,0:"Высота 1-22? ", "Ширина 1-32? ", "х-коорд. 0-255? ", "Y-коорд. 0195? ", "СООБЩЕНИЕ?", " INK 0-9?", 255 LET z$=" " 257 LET v$=" "

260 PRINT OVER 1; AT 8,0; z$

262 INPUT h: PRINT AT 8,14; h;" ":OVER 1; AT 8,0; v$

265 PRINT OVER 1; AT 9,0; z$: INPUT w; PRINT AT 9,14; w: " "; OVER 1; AT 9,0; v$ 270 PRINT OVER 1; AT 10,0;z$: INPUT x: PRINT AT 10,17;x;" "; OVER 1; AT 10,0;v$ 272 PRINT OVER 1; AT 11,0:z$: INPUT y: PRINT AT 11,17; y:" "; OVER 1: AT 11,0;v$

273 PRINT OVER 1; AT 12,0;z$; AT 13,0; z$: INPUT a$: PRINT AT 13,0: a$; : FOR k=LEN a$ TO

31: PRINT " ";: NEXT k: PRINT OVER 1; AT 12,0; v$; OVER 1: AT 13,0; v$ 275 PRINT OVER 1; AT 14,0; z$: INPUT 1: PRINT AT 14,0; INK 1; OVER 1; v$ 280 PAUSE 50: CLS: INK 1: RANDOMIZE USR 32393: INK 0

300 PRINT #0; AT 0,0 "Q - конец работы"; AT 1,0; "Прочие клавиши - повтор" 310 PAUSE 0: IF INKEY$="Q" OR INKEY$ = "q" ^N STOP 320 CLS: GO TO 250

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

Эта программа состоит из двух блоков. Первый блок - настроечный, он выполнен на БЕЙСИКе, т.к. от него не требуется выстродействие. второй блок - основной, он выполнен в машинных кодах. Связь между блоками нужна для передачи основных параметров: высота и ширина символов (h,w), начальные координаты сообщения (x,y) и само сообщение (a$). И эта связь осуществляется благодаря тому, что эти параметры в БЕЙСИК-программе являются заданы программными переменными, а в подпрограмму в машинных кодах передается с помощью команд POKE.

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

БЕЙСИК-программа приведена в листинге 2.6.

Блок в машинных кодах приведен в листингах 2.7.1 - 2.7.5 и представляет собой расширенную версию программы 2.4.

Машиннокодовый блок включает в себя следующие процедуры: FIND, SET, START, PLOT и SKIP. для простоты рассмотрим их по отдельности.

Процедура FIND (32335 - 32380) приведена в листинге 2.7.1. Она выполняет поиск значения БЕЙСИК-переменной по ее имени, которое должно быть предварительно задано. У нас имя искомой переменной задано в ячейке памяти 23728.

Это нужно сделать для того, чтобы передать из БЕЙСИКа в машинный код параметры x^,h,w и само текстовое сообщение.

Сама по себе задача передачи параметров из БЕЙСИКа в машинный код - весьма интересная и важная. Для этого существуют много разных способов. Наиболее распространенный прием - через параметры функции пользователя FN () мы рассмотрели и нашей книге "Элементарная графика" ("ИНФОРКОМ", М:, 1992, с. 111).

Здесь С. Николс предлагает прием передачи параметров через БЕЙСИК-переменные. Вот их поиском и занимается процедура FIND. Если Вам покажется сложным то, как она это делает, значит Вы не вполне знакомы с форматом БЕЙСИК-переменных, в котором они хранятся в памяти компьютера. Тогда посмотрите "7Х-РЕВЮ-92" на с. 166.

Процедура SET (32381-32392) приведена в листинге 2.7.2. Она служит для того, чтобы передать параметры x,y,b,w, разысканные процедурой FIND в области БЕЙСИК-переменных в область буфера принтера (весьма удобное место для хранения данных, обычно ничем не занятое в компьютере. Эта область расположена всегда в адресах 23396-23551). Сюда же передается и количество символов в выводимой на экран сообщении, а также коды символов сообщения. Наша основная программа будет работать с параметрами, беря их из области буфера принтера.

Выполнение машинного кода в программе 2.7 начинается с адреса 32393. Это стартовый адрес процедуры START. Она приведена в листинге 2.7.3. Сначала (32393...32418) регистровая пара BC определается в качестве указателя буфера принтера, после чего вызывается процедура SET для записи кода переменной в ячейку 23728. Затем (32419... 32442) определяется количество символов в переменной a$ и переписываются

коды всех символов в буфер принтера. Процедура (32443... 32456) проверяет текущее значение координаты у. Если это значение будет больше 175, то выполняется операция у-176 и новые значения координат x и у записываются в ячейки 23728/9 и 23296/7.

Процедура PLOT (Листинг 2.7.4) представляет собой расширенную версию процедуры вывода символа на экран по точкам с добавлением циклов вывода на зкран точки шириной w пикселов в h строках подряд.

Обратим внимание на то, что здесь неиспользуемые "Спектрумом" ячейки памяти 23728/9 служат для хранения текущих экранных координат позиции печати, а не для того, для чего они использовались в процедуре FIND.

Листинг 2.7.1

АДРЕС

FIND

32335

2A

4B

L2

32338

3A

B0

32341

BE

32342

C8

32343

CB

6E

32345

20

08

32347

23

32340

5E

32349

23

32350

56

32351

19

32352

23

32353

18

EF

L1

32355

CB

76

32357

20

0C

32359

23

32360

7E

32361

CB

7F

32363

28

FA

32365

11

06

32368

19

38369

18

DF

L3

32371

CB

7E

32373

28

F6

32375

11

13

32378

19

52379

18

D5

КОММЕНТАРИЙ

23627 - адрес системной перем. VARS, в которой хранится адрес, с которого начинается размещение переменных БЕЙСИКа.

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

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

Если седьмой бит равен нулю, это односимвольная переменная (хоть и не наша.) Вернемся на 32365, пропустим 6 байтов и повторим поиск с L2. Седьмой бит равен единице

- это параметр цикла. В этом случае пропускаем 19 байтов и повторяем поиск с L2.

МАШ. КОД

АССЕМБЛЕР ORG 32335

LD HL,(23627)

LD A,(23728) CP (HL) RET Z

BIT 5,(HL) JR NZ,L1 INC HL LD E,(HL) INC HL LD D,HL ADD HL,DE INC HL JR L2

BIT 6,(HL) JR NZ,L3

INC HL LD A,(HL) BIT 7,(HL) JR Z,-6 LD DE,6 ADD HL,DE JR L2

BIT 7,(HL) JR Z,-10

LD DE,19 ADD HL,DE

JR L2

Листинг 2.7.2

КОММЕНТАРИЙ

АДРЕС

. КОД

АССЕМБЛЕР

в стандартном "Спектруме" ячейки 23728/9 не используются

SET 32381

32 B0 5C

LD (23728),A

Мы храним в них имя переменной (х, у, h... ) Поиск значения переменной по ее имени. За именем переменной в БЕЙСИКе хранится ее значение в пятибайтной форме. Для целых чисел меньших 255 это форма:

32384

CD 4F 7E

CALL FIND

INC HL INC HL INC HL

32387

32388

32389

23 23 23

|имя|00|Знак^|00|00|

| |

(HL) (HL)+3

Вот для чего нужны три команды INC HL подряд. Переброска параметра в буфер принтера. Выход из процедуры.

32390

32391

32392

LD A,(HL) LD (BC),A RET

7E 02

C9

Процедура SKIP (Листинг 2.7.5) завершает подпрограмму. Она ведет учет изменения экранной координаты позиции печати. В частности, она осуществляет переход к следующей строке, а когда достигнут низ экрана (y>175), она выполняет переход на первую строку за счет операции "y-175".

Выше мы отметили, что в процедуре ПЗУ PLOT имеется еще одна точка входа по адресу 8924, с помощью которой можно напечатать на экране точку, координаты которой заданы на вершине стека калькулятора. Мы говорили о том, что это может быть удобным при печати результатов расчета калькулятора.

Не углубляясь в подробности работы процедуры CALCULATOR, рассмотрим работу программы, которая использует адрес 8924 для входа в процедуру PLOT.

Листинг 2.7.3

АДРЕС

МАШ

и. КОД

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

START

Точка входа в программу.

32393

01

00

5B

LD BC,23296

Начало буфера принтера.

32396

3E

7B

LD A,120

120 - код буквы "x".

32598

CD

7D

7E

CALL SET

в 23296 - коорд. "x".

32401

03

INC BC

Очередной байт буфера.

32402

3E

79

LD A,121

121 - код буквы y.

32405

CD

7D

7E

CALL SET

в 23297 - коорд. "y".

32407

03

INC BC

Очередной байт буфера.

32408

3E

68

LD A,104

104 - код буквы h.

32410

CD

7D

7E

CALL SET

В 23298 - высота "h".

32413

03

INC BC

Очередной байт буфера.

32414

3E

77

LD A,119

119 - код буквы w.

32416

CD

7D

7E

CALL SET

в 23299 - ширина "w".

32419

3E

41

LD A,65

65 - код буквы A.

52421

32

B0

5C

LD (23728),A

Подготовка и проведение

32424

CD

4F

7E

CALL FIND

поиска переменной a$.

32427

23

INC HL

32428

5E

LD E,(HL)

В DE помещается длина

32429

23

INC HL

нашего сообщения и пере-

32430

56

LD D,(HL)

дается в буфер принтера

32431

ED

53

04 5B

LD(23300),DE

По адресу 23300.

32435

D5

PUSH DE

Переброска длины сообще-

32436

C1

POP BC

ния из DE в BC.

32437

23

INC HL

Переброска самого текста

32438

11

05

5B

LD DE,23301

сообщения в буфер принте

32441

ED

B0

LDIR

ра начиная с 23301.

32443

2A

00

5B

LD HL,(23296)

В HL - координаты x,y.

Причем y находится в H.

AF

7C

DE B0 38 04

32452

32453 32456

LD H,A

LD (23296),HL LD (23728),HL

LD HL,23301

PUSH HL LD A,(HL) LD H,0 LD L,A ADD HL,HL ADD HL,HL ADD HL,HL LD DE,15360 ADD HL,DE

LD B,8

PUSH BC LD BC,(23297)

LD A,(HL) PUSH HL PUSH BC LD B,8

PUSH BC RLA

PUSH AF JP C,PLOT

LD HL,(23299)

LD A,(23728) ADD A,L LD (23728),A JP SKIP

67

22 00 5B 22 B0 5C

32446

XOR A

32447 32443 32450

LD A,H SBC A,176 JR C,+4

32459

21 05 5B

LP5

32462

E5

32463

7E

32464

26

00

32466

6F

3246т

29

32468

29

32469

39

32470

11

00

3C

32473

19

32474

06

08

LP4

32476

C5

52477

ED

4B

01

LP3

32481

7E

32482

E5

32483

С5

32484

06

08

LP2

32486

С5

32487

17

32488

F5

32489

DA

F9

7E

32492

2A

03

5B

32495

3A

B0

5C

32498

85

32499

32

B0

5C

32502

C3

0F

7F

Сброс флага переноса (это необходимо перед операцией SBC). Координата y. Проверка на >= 176. Если нет, то переход на адрес 32456 (все O.K.) В противном случае оставляем "y минус 176" и запоминаем копию в 23728/9. Итак, в 23728 - "x"; в 23729 - "y-176". Указание на начало текста

Запомнили начало текста. Взяли символ. Код символа передаем в HL и

умножаем его код на 8.

Нашли адрес, начиная с которого в ПЗУ хранится шаблон этого символа. Счетчик байтов в шаблоне

Запомнили его. в "B" - высота символа; в "C" - его коорд. "y".

Байт шаблона символа. Запомнили его. Запомнили "h" и "у". Счетчик битов в байте шаблона.

Запомнили текущий байт. Ротация байта. Запомнили результат ротации вместе с флагами. Если флаг переноса включился, переходим на 32505 для печати точки. В регистр "L" помещается ширина "w". Координата "x". Нашли "x+w" Запомнили в 23728. Обход.

Программа 2.8 демонстрирует построение по точкам синусоиды, описываемой формулой

88 + 8 0*SIN(A/128*PI)

с применением процедуры CALCULATOR.

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

Например, если на вершине стека записаны два числа: 1234 и 2, а после включения процедуры CALCULATOR (RST 40) записан код 4 (DEFB 4), то эти два числа будут извлечены из калькуляторного стека, перемножены между собой, а их произведение будет записано обратно на вершину калькуляторного стека. Теперь на стеке будет записано только одно

число, равное 2468, если до этого там кроме сомножителей ничего не было записано.

Целые положительные числа могут быть занесены на стек следующими способами: STACK VAL A - CALL 11560 STACK VAL BC - CALL 11563,

т.е. число предварительно записывается в регистр а или регистровую пару BC, а затем вызывается соответствующая процедура.

В программе 2.8 используется вызов STACK VAL A для размещения на стеке чисел в следующем порядке:

переменная A 88 80

переменная A 128

Вызов процедуры CALCULATOR осуществляется по команде RST40. Байты, записанные после этой команды, определяют вид выполняемой операции. В программе 2.8 сразу же после команды RST 40 следует байт, равный 5, что означает "Деление". При этом из стека извлекаются два верхних числа, выполняется деление одного числа на другое и результат записывается обратно в калькуляторный стек. Следующий байт - 163 является кодом операции "stack PI/2"- он переписывает на стек значение PI/2, хранимое в ПЗУ. Затем следует код 49 (duplicate top value) - он дублирует верхнее число на стеке, а код 15 "add top two values" производит суммирование двух верхних чисел и записывает результат обратно на стек. Теперь на вершине стека записано число PI. Следующий код 4 (multiply top two values) перемножает два верхних числа, т.е. число PI и A/128, и результат возвращается на стек. Код 31 (SIN of top value) определяет синус числа на вершине калькуляторного стека, а последующие коды 4 и 15 завершает расчет по записанной формуле. Последний код 56 "end calc" выполняет выход из процедуры, т.е. как бы выключает калькулятор и осуществляет возврат в программу в машинных кодах.

Листинг 2. 7.4

КОММЕНТАРИЙ

АДРЕС

МАШ. КОД

АССЕМБЛЕР

LD BC, (23298)

PUSH BC LD BC,(23298) PUSH BC CALL 8933

POP BC INC C

PLOT 32505

LP1

32509

32510

32514

32515

32518

32519

32520

32524

32525

ED 4B B0 5C

C5

ED 4B B0 5C C5

CD E5 22

C1

0C

ED 43 B0 5C C1

10 EE

LD (23728),BC POP BC DJNZ LP1

АДРЕС

. КОД

АССЕМБЛЕР

Процедура печати точки. В "B" - ширина "w" В "C" - высота "h".

Запомнили на стеке. Повторили на стеке еще раз.

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

Переход к соседней точке.

Запомнили текущую координату.

Если не все точки напечатаны, возврат на 32509

КОММЕНТАРИЙ

Листинг 2.7.5

Восстановили текущий байт шаблона.

Восстановили счетчик Уменьшили его и, если он не обнулялся, возврат на LP2 для последующей ротации. Координата "x".

Принимаем "x" в качестве текущей экранной коорди-

SKIP

32527

32528

32529

POP AF

POP BC DJNZ LP2

F1 C1

10 03

32531 32534 32537

3A 00 5B 21 B0 5C 77

LD A,(23296) LD HL,23728 LD (HL),A

наты.

32536

23

INC HL

Указание на "y".

32539

AF

XOR A

Сброс флага переноса,

32540

7E

LD A,(HL)

Координата "y"

32541

DE

B0

SBC A,176

Проверка на "y>175".

32543

38

03

JR C,+3

Если так, переход к 32546

32545

77

LD (HL),A

"y"

32546

18

08

JR +8

Переход на 32556.

32548

7E

LD A,(HL)

"y-176".

32349

FE

00

CP 0

Проверка на "ноль".

32551

20

02

JR NZ,+2

Если не 0, переход на адрес 32555.

32553

36

B0

LD (HL),176

32555

35

DEC (HL)

32556

C1

POP BC

32557

E1

POP HL

32558

10

B1

DJNZ LP3

32560

23

INC HL

Переход к следующему байту шаблона.

32561

C1

POP BC

Восстановили счетчик.

32562

10

A8

DJNZ LP4

Если он еще не обнулился, переход на LP 4.

32564

3A

03

5B

LD A,(E3299)

Ширина символа "w".

33567

87

ADD A,A

Умножаем

32566

67

ADD A,A

ее

32569

67

ADD A,A

на 8.

32570

6F

LD L,A

Запомнили в L.

32571

3A

B0

5C

LD A,(25728)

Новая экранная коорд. "x"

32574

85

ADD A,L

32575

32

00

5B

LD (23296),A

Запомнили ее.

32578

32

B0

5C

LD (23728),A

- "" -- "" -

32581

3A

01

5C

LD A,(23297)

Новая экранная коорд. "7"

32584

3A

B1

5C

LD (23729),A

Запомнили ее.

32587

E1

POP HL

Восстановили указатель на текущий символ.

32588

23

INC HL

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

32569

3A

04

5B

LD A,(23300)

Длина сообщения.

32592

3D

DEC A

Умножаем ее на 1.

32593

C8

RET Z

Проверка на конец. Если так, то выход.

32594

32

04

5B

LD (23300),а

Запомнили новую длину.

32597

C3

CE

7E

JP LP5

Возврат на печать очеред-

;ного символа.

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

И еще одно важное замечание. Перед возвратом в BASIC-систему после применения процедуры CALCULATOR необходимо полностью очистить калькуляторыый стек от всех записей. В программе 2.8 после последнего кода 56 на стеке все же остаются два числа: переменная A и результат вычисления по формуле 88+80*SIN(A/128*PI). Процедура PLOT(CALL 6924) извлекает эти два значения, тем самым полностью очищая стек и использует эти два числа как координаты для пиксела.

Код программы для построения синусоиды приведен в листинге 2.8.

Листинг 2.8

АДРЕС

МАШ

. КОД

АССЕМБЛЕР

КОММЕНТАРИЙ

23760

AF

XOR A

;Обнуление аккумулятора.

LOOP

23761

F5

PUSH AF

;Запомнили его на стеке.

23762

CD

28 2D

CALL 11560

;На кальк. стеке - текущее

;значение аргумента.

23765

3E

5B

LD A,88

;На кальк. стеке -

23767

CD 28 2D

CALL 11560

88, A.

23770

3E 50

LD A,80

На кальк. стеке -

23772

CD 28 2D

CALL 11560

80, 88, A.

23775

F1

POP AF

B акк-ре текущее значение аргумента.

23776

F5

PUSH AF

Запомнили его на стеке.

23777

CD 28 2D

CALL 11560

A, 80, 88, A.

23780

3E 80

LD A,128

23782

CD 28 2D

CALL 11560

128, A, 80, 88, A.

23765

EF

RST 40

Включение калькулятора.

23766

DEFB 05

division

A/128, 80, 88, A.

23787

DEFB 163

stack PI/2

PI/2, A/128, 80, 88, A.

23788

DEFB 49

duplicate

PI/2, PI/2, а/128, 80, 88, A

23789

DEFB 15

add

PI, A/128, 80, 88, A.

23780

DEFB 04

multiply

PI*A/128, 80, 88, A.

23781

DEFB 31

Sin

SIN(A/128*PI), 80, 88,A.

23782

DEFB 04

multiply

80*SIN(A/128*PI), 88, A.

23783

DEFB 15

add

88+80*SIN(A/128*PI), A.

23784

DEFB 56

endcalc

Выключение калькулятора.

23795

CD DC 22

CALL 8924

Вызов процедуры PLOT.

23798

F1

POP AF

Текущее значение аргумента.

23799

3C

INC A

Приращение аргумента.

23800

FE 00

CP 0

Проверка на конец экрана.

23802

20 D5

JR NZ,LOOP

Возврат для расчета и печати следующей точки.

23804

C9

RET

Выход из процедуры.

DRAW x,y.

Две точки входа в ПЗУ существуют и для реализации команды DRAW х,у. Для входа через первую точку (CALL 9402) необходимо, чтобы в регистре B было записано ABS(y), а в регистре C - ABS (х). Регистровая пара DE служит для хранения знака приращения координат х и у. Регистр D хранит знак приращения по х (SGN dx), а регистр C - знак приращения по у (1, если число положительное и 255, если число отрицательное). Программа 2.9 является модифицированной версией программы 2.8, которая демонстрирует реализацию команды DRAW. Обратите внимание, что перед вызовом процедуры DRAW, начальное значение регистровой пары H'L' (альтернативная) должно быть сохранено. Для этого содержимое этой пары записывается в машинный стек.

Начальное значение регистровой пары H'L' не должно быть потеряно в ходе выполнения программы, написанной пользователем, иначе при возврате в BASIC-систему произойдет сбой в работе компьютера. Начальное значение регистровой пары H'L' восстанавливается после команды DRAW. Команды OVER и INVERSE включаются таким же образом, как и PLOT OVER/INVERSE.

Для реализации команды DRAW х,у через вторую точку входа (CALL 9335) необходимо, чтобы значения х и у были записаны в калькуляторном стеке, причем значение у должно быть верхним в стеке. Чтобы использовать эту точку входа, необходимо прочитать главу 7, для ознакомления со способом записи 5-ти байтных чисел в калькуляторный стек.

Листинг 2.9

АДРЕС

МАШ

и. КОД

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

23760

06

5F

LD B,95

Координата "y".

23762

0E

00

LD C,00

Координата "x".

23764

CD

E5 22

CALL 8933

Печать исходной точки.

23767

D9

EXX

Включение регистров

альтернативного набора.

23768

E5

PUSH HL

Сохранение пара H'L'.

23769

D9

EXX

Выключение альтернативного набора

23770

06

00

LD B,0

Приращение по "y"=0.

23772

0E

FF

LD C,255

Приращение по "x" = 255.

23774

16

01

LD D,1

Знак приращ. по x=+.

23776

1E

01

LD E,1

Знак приращ. по y=+.

23778

CD BA 24

CALL 9402

Рисуем прямую линию.

23781

D9

EXX

Включение регистров

альтернативного набора.

23782

E1

POP HL

Восстановление пары H'L'.

23783

D9

EXX

Выключение альтернативного набора

23784

AF

XOR A

Обнуление аккумулятора.

LOOP

23765

F5

PUSH AF

Запомнили его на стеке.

23766

CD 28 2D

CALL 11560

На кальк. стеке - текущее

значение аргумента.

23789

3E 78

LD A,120

На кальк. стеке -

23791

CD 28 2D

CALL 11560

120,A.

23794

3E 28

LD A,40

На кальк. стеке -

23796

CD 28 2D

CALL 11560

40, 120, A.

23799

F1

POP AF

в акк-ре текущее значение

аргумента.

23600

F5

PUSH AF

Запомнили его на стеке.

23601

CD 28 2D

CALL 11560

A, 40, 120, A.

23804

3E 10

LD A,16

23806

CD 28 2D

CALL 11560

16, A, 40, 120, A.

23809

EF

RST 40

Включение калькулятора.

23810

DEFB 05

division

A/16, 40, 120, A.

23811

DEFB 163

stack PI/2

PI/2, A/16, 40, 120, A.

23813

DEFB 49

duplicate

PI/2, PI/2, A/16, 40, 120, A.

23813

DEFB 15

add

PI, A/16, 40, 120, A.

23814

DEFB 04

multiply

PI*A/16, 40, 120, A.

23815

DEFB 31

Sin

SIN(A/16*PI), 10, 120, A.

23816

DEFB 04

multiply

40*SIN(A/16*PI), 120, A.

25617

DEFB 15

add

120+40*SIN (A/16*PI), A.

23618

DEFB 56

endcalc

Выключение калькулятора.

23819

CD DC 22

CALL 8924

Вызов процедуры PLOT.

23822

D9

EXX

Включение альтерн. набора

23823

E5

PUSH HL

Сохраняя H'L'.

23824

D9

EXX

Выключение альтерн. наб.

23825

06 32

LD B,50

Приращение по "y".

23827

0E 00

LD C,0

Приращение по "x".

23829

16 FF

LD D,255

Знак приращения по "y"

"минус".

23831

1E 01

LD E,01

Знак приращения по "х" -

"плюс".

23833

CD BA 24

CALL 9402

Рисование линии.

23836

D9

EXX

Включение альтерн. набора

23837

E1

POP HL

Восстановление пары H'L'.

23838

D9

EXX

Выключение альтернатив-

ного набора.

23839

F1

POP AF

Текущее значение аргумента.

23840

3C

INC A

Приращение аргумента.

23841

FE 00

CP 0

Проверка на конец экрана.

23843

20 D5

JR NZ, LOOP

Возврат для расчета и

печати следующей точки.

23845 C9

RET

Выход из процедуры.

DRAW x,y,a

Точкой входа в ПЗУ для реализации этой команды служит адрес 9106. В этом случае необходимо, чтобы значения x, y и а были записаны в калькуляторный стек в таком порядке, чтобы значение "a" было верхним на стеке. Опять же, начальное значение регистровой пары H'L' (альтернативной) должно быть сохранено.

CIRCLE x,y,r

Точкой входа в ПЗУ для реализации этой команды служит адрес 9005. При этом необходимо, чтобы значения x,y, и r были записаны в калькуляторном стеке. Начальное значение регистровой пары H'L' должно сохраниться в отдельном месте в течение работы

процедуры CIRCLE.

Программа 2.10 демонстрирует метод рисования концентрических окружностей. Обратите внимание на тот факт, что эта программа в машинных кодах выполняется также медленно, как и на языке BASIC. Это потому, что процедура CIRCLE в ПЗУ достаточно длинная. Если в Вашей программе возникнет необходимость построить окружность, то будет быстрее, если Вы будете строить ее по точкам, используя для постановки пиксела координаты, записанные как последовательность байтов с именем DATA.

Машинный код процедуры представлен в листинге 2.10. В качестве аналога выступает следующая БЕЙСИК-программа: 10 REM CIRCLE x,y,r 20 FOR b= 1 TO 2 30 FOR a= 1 TO 21 STEP 2 40 CIRCLE OVER 1; 128,88,a 50 NEXT а 60 NEXT b

Листинг 2.10

АДРЕС

МАШ

и. КОД

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

23760

06

02

LD B,2

FOR b=1 TO 2

L2

23762

C5

PUSH BC

23763 1 1

3E

01

LD A,1

FOR a=1 TO ...

L1

23765

F5

PUSH AF

23766

FD

36

57 03

LD (IY+87),3

OVER 1

23770

3E

80

LD A,128

23772

CD

28

2D

CALL 11560

На кальк. стеке - 128.

23775

3E

58

LD A,88

23777

CD

28

2D

CALL 11560

На кальк. стеке - 88,128

23780

F1

POP AF

текущее "а".

23781

F5

PUSH AF

23782

CD

28

2D

CALL 11560

На к. стеке - а, 88, 128

23785

D9

EXX

23786

E5

PUSH HL

Сохранение H'L'.

23787

D9

EXX

23788

CD

2D

23

CALL 9005

CALL CIRCLE

23791

D9

EXX

23792

E1

POP HL

Восстановление H'L'.

23793

D9

EXX

23794

F1

POP AF

Текущее "a".

23795

3C

INC A

23796

3C

INC A

STEP 2

23797

FE

17

CP 23

a = 23?

23794

20

DC

JR NZ, L1

Цикл не завершен.

23801

C1

POP BC

цикл по "A" завершен.

23802

10

D6

DJNZ L2

Конец цикла по "b".

23804

FD

36

57 00

LD (IY+87),D

- OVER 0.

23808

C9

RET

Выход

3. Счет

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

Первый настолько непригляден и занимает так иного памяти, что мы рассмотрим его кратко, лишь в общих чертах. Способ этот позволяет организовать счет в программе от 0 до очень большого числа. Максимально возможное число определяется только количеством байтов, зарезервированных для представления этого числа. Например, для того, чтобы получить счетчик от 0 до 999 999, необходимо зарезервировать 6 байтов, т. е. для каждого разряда числа нужен 1 байт. Поскольку показание счетчика выводится на экран как значение символьной переменной, то на экране в начальный момент времени будет 6 нулей: 000 000. Затем, с увеличениен значения на 1, изменения произойдут только в разряде единиц. Если же последнее записанное в этом разряде число равно 9, то с добавлением 1 этот разряд обнулится, а единица добавится к числу в следующем разряде. Продедура проверки значения числа выполняется для каждого разряда и, если во всех шести разрядах записано число 9, то дальнейший счет прекращается. Для того, чтобы шаг счетчика был больше, чем 1, необходимо включить в процедуру счета специальные циклы.

Второй способ используется для создания счетчиков, показания которых не выходят за пределы диапазона 0...65535. Реализация этого способа показана в программе 3.1. В этой программе используется одна из процедур ПЗУ, позволяющая выводить на экран значение числа, записанного на вершине калькуляторного стека. Вызов этой процедуры осуществляется командой CALL 11747. При этом текущее значение счетчика может, например, храниться в неиспользуемой системной переменной 23726. Значение счетчика извлекается из этой системной переменной, увеличивается на 1, а затем вновь записывается в эту переменную и на вершину калькуляторного стека. После этого определяются параметры PRINT AT и вызывается процедура 11563, печатающая содержимое стека калькулятора.

LD BC,0

BEGIN

LD (23728),BC CALL 11563

LD A,2 CALL 5633 LD A,22 RST 16 LD A,16 RST 16 CALL 11747 LD BC,(23728) INC BC LD A,B OR C RET Z

BIT 5,(IY+1) JR Z, BEGIN RET

Листинг 3. 1

Инициализация счетчика по адресу 23728. Переброска на стек калькулятора Открыли канал печати на экран.

Аналог ... AT 22

Аналог AT 22,16 Печать счетчика. Вызов счетчика. Приращение. Проверка на обнуление. Выход, если 0. Проверка не была ли нажата клавиша Повтор, если не было нажатия. Выход, если клавиша была нажата.

Если в регистровой паре значение числа становится равным 65535, то осуществляется возврат в BASIC систему. В эту программу включена также процедура EXIT (строки 23795...23800), благодаря которой имеется возможность прервать счет и вернуться в BASIC систему, если нажата какая-нибудь клавиша. Это удобно, так как счет от 0 до 65535 выполняется несколько минут.

Третий способ также основан на использовании калькулятора. Выше, когда мы говорили о калькуляторном стеке, мы не останавливались на детальном рассмотрении способа записи и хранения чисел в стеке. Числа в стеке хранятся в 5-байтной форме, что позволяет калькулятору легко выполнять действия с ними. Более подробно об этом будет сказано в седьмой главе. Здесь же приводим программу, которая выполняет счет от 0 до бесконечно большого числа с шагом 250. При достижении показания счетчика 99 999 999, форма вывода на экран меняется на E-форму (1E+9). Однако счетчик, у которого диапазон представляемых чисел достигает 100 млн. вполне пригоден для большинства программ и на этот факт можно не обращать внимание.

В программе 3.2 есть много важных процедур, которые необходимо объяснить. Начальное значение счетчика, равное нулю, записывается в стек с помощью кода калькулятора 160 (stack_zero). Это число занимает 5 верхних байтов стека, содержимое которых затем копируется в буфер принтера, используемого как "хранилище" для счетчика. Копирование выполняется командой LDIR. Значение, записанное в регистровой паре HL при этом считается равным STACKEND-5.

Значение счетчика выводится на экран с помощью процедуры 11747. Затем в стек записывается число 250 (шаг изменения показания счетчика) и число из "хранилища" в 5-байтной форме. Следующая команда вызова калькулятора RST 40 и код калькулятора 15(add) обеспечивают суммирование двух чисел, записанных на вершине стека, и осуществляется переход на начало цикла для передачи нового значения в "хранилище" и вывода этого значения на экран. В этой программе предусмотрена также процедура преждевременного выхода из цикла счета, если будет нажата любая клавиша. Перед возвратом в BASIC-систему после окончания счета стек обнуляется путем перемещения последнего записанного там значения.

Для создания счетчика, значение которого с каждым шагом уменьшается, необходимо в стек первоначально записать максимальное значение счетчика (запись в стек чисел больше, чем 65535, показана в главе 7), а вместо кода калькулятора для сложения - 15 (add) следует использовать код для вычитания 3 (subtract). Необходимо помнить, что при вычитании верхнее в стеке число вычитается из числа, записанного вторым. После каждой операции вычитания проверяется достигнут ли 0 (либо включен ли 7 бит результата) и если это так, то счет прекращается. Перед выводом очередного значения счетчика необходимо очищать экран, чтобы избежать ошибок, связанных с устареванием экранной информации. Например, если экран не очищать, то при изменении значения счетчика с 1000 на 999 на экране будет изображено не 999, а 9990.

Листинг 3.2

ORG 23760 RST 40 DEFB 160 DEFB 56

LD DE,23296

LD BC,5

LDIR LD A,2 CALL 5633 LD A,22 RST 16 LD A,11 RST 16 CALL 11747

LD A,250 CALL 11560

LD HL,23296

LD DE,(23653)

LD BC,5 LDIR

LD (23653),DE

RST 40 DEFB 15

включили кальк-р. На стек - 0. Выключили кальк-р.

начало буфера принтера. Число перебрасываемых байтов. Переброска. Канал экрана. Открыли канал. ... AT 22 ...

...AT 22,11

Печать показаний счетчика. Шаг счетчика. Поместили его на стек кальк-ра. Начало буфера принтера.

23553 - системная переменная STKEND. Число перебрасываемых байтов. Переброска. Новое значение STKEND.

Включили кальк-р. Код сложения (add)

L1

DEFB 56 BIT 5(IY+1)

Выключение к-ра. Проверка не была ли нажата какая -либо клавиша. Если нет, то повтор. (STKEND)

JR Z,L1

LD HL,(23653) DEC HL DEC HL DEC HL DEC HL DEC HL

LD (23553),HL RET

(STKEND)-5 Выход

И завершим мы материал этого номера небольшой игрой, в которой объединим то, о чем Вы сегодня прочитали. Программа 3.3 показывает возможность использования счетчика для измерения скорости Вашей реакции.

Программа состоит из двух частей: первая часть написана на БЕЙСИКе и служит в качестве интерфейса между пользователем и компьютером. Она не требует скорости в работе. Машинный код служит для выдачи сообщений и запросов нестандартным шрифтом и для измерения скорости реакции. Печать нестандартным шрифтом выполняется с помощью блока машинного кода, приведенного в листинге 2.7, рассмотренного ранее. Он должен быть подгружен, начиная с адреса 32335. измерение скорости реакции выполнит процедура 3.3.2, приведенная ниже.

Измерение скорости вашей реакции производится следующим образом. Сначала процедура 2.7 нарисует на экране большую букву от A до Z, после чего будет включен режим CAPS LOCK и Вам надо нажать соответствующую клавишу. Время Вашей реакции замерит процедура 3.3.2.

В ней применен один хитрый прием. Дело в том, что рисование с помощью PLOT буквы на экране происходит не очень быстро, и за то время, пока идет этот процесс, Вы можете в принципе догадаться, что это за буква и подготовиться к нажатию соответствующей клавиши. Чтобы этого не было, буква рисуется желтым цветом INK=6 по желтому фону PAPER=6 и ее на экране не будет видно. Когда же дело дойдет до измерения Вашей реакции, процедура 3.3.2 включит на экране цвет пикселов INK=1 (черный). Произойдет это с огромной скоростью и буква появится мгновенно.

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

SAVE "counter" LINE 9800

Листинг 3.3.1

12 PAPER 6: CLS 15 DATA 87,143,1,2, "COUNT" 20 DATA 95,63,1,2, "SLOW" 30 DATA 71,63,1,2, "AVERAGE" 40 DATA 95,63,1,2, "GOOD" 50 DATA 63,63,1,2, "VERY GOOD" 6O DATA 63,63,1,2, "EXCELLENT" 80 DATA 47,63,1,2, "NOT TRYING" 9O DATA 0,31,1,2, "ANOTHER GO? y/n"

95 DATA 55,125,5,2, "THANK YOU"

96 DATA 103,79,3,2, "for"

97 DATA 71,50,5,2, "PLAYING"

100 DATA 24,79,5,2, "STOP THE TAPE" 105 DATA 15,167,1,2, "REACTION TIMER"

110 DATA 13,164,2,2, "________________________________"

120 DATA 24,15,1,2, "PRESS ANY KEY"

125 RESTORE 100: FOR a=1 TO 4:PAUSE 25: INK 2: GO SUB 9000:NEXT a 180 PAUSE 0: BORDER 5: PAPER 6: INK 0: CLS

190 RESTORE 105: INK 0: GO SUB 9000 290 PRINT AT 20,5; "PRESS ANY KEY TO PLAY" 300 IF INKEY$<>"" THEN GO TO 300 302 IF INKEY$="" THEN GO TO 302

310 CLS: RESTORE 105: INK 1: GO SUB 9000: INK 5: GO SUB 9000 330 RESTORE 15: INK 2: GO SUB 9000

350 INK 0: PLOT 102,114: DRAW 50,0: DRAW 0,-38: DRAW 50,0: DRAW 0,38 380 LET z=INT (RND*26+65)

390 LET x-111: LET y=111: LET h=4: LET w=4: LET a$=CHR$ z

400 INK 6: LET c=USR 33393: FOR a=1 TO RND*200+50: NEXT a

420 INK 0: LET c=USR 30000: LET a=PEEK 23728+256*PEEK 237729

450 IF a>=140 OR a=0 THEN RESTORE 20

460 IF a<140 THEN RESTORE 20

470 IF a<120 THEN RESTORE 30

480 IF a<100 THEN RESTORE 40

490 IF а<85 THEN RESTORE 50

500 IF a<70 THEN RESTORE 60

510 GO SUB 9000

7000 RESTORE 90:INK 1:GO SUB 9000 7010 IF INKEY$<>"" THEN GO TO 7010 7020 IF INKEY$="" THEN GO TO 7020 7030 LET d$=INKEY$ 7040 IF d$ <> "y" THEN GO TO 8000 7050 LET c=USR 30082: GO TO 350

8000 RESTORE 95: POKE 30083,20: LET c=USR 30082: POKE 30083,18 8030 FOR a=1 TO 3: GO SUB 9000: NEXT a: STOP 9000 READ x, y, h, w, a$: LET c=USR 32393: RETURN 9800 CLEAR 29999: LOAD ""CODE: GO TO 12

МАШ. КОД

АДРЕС

АССЕМБЛЕР

30000 30002

LD A,122 LD BC,23681

30005

CALL 32381

30008

SET 3,(IY+48)

3E 7A 01 81 5C

CD 7D 7E

FD CB 30 DE

30012

21

00

58

LD HL,22528

L1

30015

7E

LD A,(HL)

30016

FE

36

CP 54

30018

20

02

JR NZ,L2

30020

36

30

LD (HL),48

L2

30022

23

INC HL

30023

7C

LD A,H

30024

FE

5B

CP 91

30026

20

F3

JR NZ,L1

30028

01

00

00

LD BC,0

L3

30031

C5

PUSH BC

30032

CD

2B

2D

CALL 11563

30035

3E

02

LD A,2

30037

CD

01

16

CALL 5633

30040

3E

16

LD A,22

30042

D7

RST 16

Листинг 3.3.2

КОММЕНТАРИЙ

;Код буквы "z" ;Для хранения параметра "z" ;выбирается неиспользуемая ;в стандартном "Спектруме" ;ячейка 23681. ;Параметр "z" перебрасыва-;ется в 23681 (см. процедуры 2.7.1, 2.7.2.) ;Включение 3-го бита сис-;темной переменной FLAGS2 ;(23656) эквивалентно включению режима CAPS LOCK. ;Первый байт области цветовых атрибутов экрана.

;Проверка этого байта. Переключение атрибутов ;экранной области с ре-;жима PAPER = 6, INK = 6 ;на режим PAPER =6. ;INK = 0.

;Ранее нарисованная бук-;ва мгновенно "проявля-;ется" на экране. ;Инициализация счетчика,

Помещение его на стек калькулятора. Открываем канал печати на экран. Аналог ... AT ...

30043

3E

06

LD A,6

Аналог ... AT 6...

30045

D7

RST 16

30046

3E

0E

LD A,14

30046

D7

RST 16

Аналог ... AT 6,14

30049

CD

E3

2D

CALL 11747

Печать показаний счетчика.

30052

C1

POP BC

30053

03

INC BC

Увеличение счетчика.

30054

78

LD A,B

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

30055

B1

OR C

нуление.

30056

28

0F

JR Z,END

Выход, если он успел обну-литься (достиг 256).

30058

FD

CB

01

6E

BIT 5,(IY+1)

Проверка не была ли нажата какая-либо клавиша.

30062

28

DF

JR Z,L3

Если нет, то возврат на повтор.

30064

3A

08

5C

LD A,(23560)

Код нажатой клавиши.

30067

21

81

5C

LD HL,23681

Код буквы, которая была показана на экране.

30070

BE

CP (HL)

Сравнили их между собой.

30071

20

06

JR NZ,L3

Если они не совпадают, значит нажата не та клавиша. Следует повторить попытку.

END

30073

ED

43

B0

5C

LD(23728),BC

Результат испытания передается из BC в адрес 23728

30077

FD

CB

30

9E

RES 3,(IY+48)

Выключается ранее включенный режим CAPS LOCK.

30081

C9

RET

Выход из программы.

13082

06

12

LD B,18

Эта вспомогательная проце-

30084

CD

44

0E

CALL 3652

дура служит для очистки

30087

C9

RET

k нижних строк экрана, где k-число, установленное в адресе 30083 (исходно 18).




СОДЕРЖАНИЕ:


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

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



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

Похожие статьи:
Fantasy - начало цикла статей о ФЕНТЕЗИ.
Форум - С.Астров. Генератор псевдослучайных чисел.
Разберемся - Подробный отчет о прохождении игры WILD WEST SEYMOUR.
От авторов - О создании новой газеты.
Информация - новости о движении против повременной оплаты телефона.

В этот день...   26 апреля