ПРИМЕНЕНИЕ АССЕМБЛЕРА ДЛЯ СОЗДАНИЯ БЫСТРОРАБОТАЮЩИХ ПРОГРАММ
Перевод с английского Пашорина В. И.
Продолжение. Начало см. с. 9-12, 48-61.
4. СЛУЧАЙНЫЕ ЧИСЛА
Случайные числа являются неотъемлемой частью большинства игровых программ. Получить случайные числа с помощью программы в машинных кодах довольно легко и, в зависимости от диапазона выборки, определяющего границы интервала, в котором необходимо получить случайные числа, различают два способа.
Первый способ, вполне удовлетворительный для большинства игровых программ, основан на использовании системных переменных SEED и FRAMES. Применяться этот способ может при следующих диапазонах выборки:
0. |
.1, |
0. |
.3, |
0. |
.7, |
0. |
.15, |
0. |
.31, |
0. |
.63, |
0. |
.127 |
6. |
.255 |
Для этого в регистровую пару HL записывается значение системной переменной SEED (5C76HEX = 23670 DEC), а в регистровую пару DE - значение младшего байта системной переменной FRAMES (5C78HEX = 23672 DEC). Затем эти два числа суммируется и результат заносится в системную переменную SEED (это нужно для выборки очередного случайного числа). В регистр A поочередно записываются значения H и L и путем логической операции AND маскируются незначимые биты для задания диапазона выборки случайного числа.
В программе 4.1, к примеру, для задания диапазона выборки 0...31 т.е. для получения таких же случайных чисел, как к по BASIC-команде INT(RND*32), в регистре A маскируются биты с пятого по седьмой.
Как уже отмечалось, такой способ может быть использован для получения случайных чисел в строго определенных диапазонах. Однако, представленную программу можно усовершенствовать и расширить диапазон фиксированных интервалов для случайных чисел. Например, для реализации INT(RND*23) необходимо добавить:
LD A,H AND 15 LD H,A LD A,L AND 7 ADD A,H
Обратите внимание на то, что в программе 4.1 регистр B используется как счетчик шагов цикла (10 шагов) и значение этого же регистра используется в PRINT-процедуре: PRINT AT B,10 для вывода случайных чисел на экран.
Листинг 4.1
АДРЕС |
МАШ |
и. КОД |
АССЕМБЛЕР КОММЕНТАРИЙ |
|
|
|
|
ORG 23760 |
|
23760 |
06 |
0A |
|
LD B, 10 |
Счетчик на 10 шагов. |
23762 |
C5 |
|
L1 |
PUSH BC |
Запомнили состояние счетчика. |
23763 |
2A |
76 |
5С |
LD HL,(23670) |
Приняли в HL состояние системной переменной SEED. |
23766 |
ED |
5В |
78 5С |
LD DE,(23672) |
Приняли в DE состояние системной перем. FRAMES. |
23770 |
19 |
|
|
ADD HL,DE |
Нашли их сумму |
23771 |
22 |
76 |
5С |
LD (23670),HL |
и установили результат в SEED. |
23774 |
7D |
|
|
LD A,L |
|
23775 |
E6 |
1F |
|
AND 31 |
Гашение ненужных битов. |
23777 |
F5 |
|
|
PUSH AF |
Запомнили результат. |
23776 |
3E |
02 |
|
LD A,2 |
I |
23780 |
CD |
01 |
16 |
CALL 5633 |
|Открытие канала печати на |
23783 |
3E |
16 |
|
LD A,22 |
|экран и выдача управля |
23785 |
D7 |
|
|
RST 16 |
ющих кодов для установки |
23786 |
78 |
|
|
LD A,B |
|позиции печати |
23787 |
D7 |
|
|
RST 16 |
| |
23788 |
3E |
0A |
|
LD A,10 |
| AT B, 10 |
23790 |
D7 |
|
|
RST 16 |
| |
23791 |
F1 |
|
|
POP AF |
Восстановление числа со стека. |
23792 |
CD |
28 |
2D |
CALL 11560 |
Процедура STACK-A (помещает на стек калькулятора число, записанное в аккумуляторе процессора. |
23795 |
CD |
E3 |
2D |
CALL 11747 |
Процедура PRINT_FP. Печата ет действительное число, находящееся на вершине стека калькулятора. |
23798 |
C1 |
|
|
POP BC |
Восстановление счетчика. |
23799 |
10 |
D9 |
|
DJNZ L1 |
Уменьшение счетчика и возврат на новый шаг. |
23801 |
C9 |
|
|
RET |
Выход из процедуры. |
Для получения случайных чисел из произвольного интервала применяется второй способ. Этот способ основан на использовании RND-процедуры из системного ПЗУ компьютера. К сожалению, эту процедуру нельзя вызвать простой командой CALL RND, т.к. она не завершается командой RET. Процедура эта занимает участок памяти с адреса 9725 по адрес 9765 (25FDHEX...2625HEX) и в своей работе использует встроенный калькулятор, а по завершении работы меняет значение переменной SEED. Для этого в начале работы это значение извлекается из SEED, преобразуется, а затем дважды записывается на вершину калькуляторного стека. Первое значение на вершине стека передается в системную переменную SEED для генерации очередного случайного числа, а оставшееся на вершине стека значение преобразуется для получения соответствующего ему числа в диапазоне 0...1 (но не = 1). Чтобы использовать эту процедуру, необходимо ее скопировать из ПЗУ и затем вызывать, как подпрограмму.
Подпрограмма 4.2 показывает применение этого способа для получения случайных
чисел
INT (RND*12345)
и вывода 44 из них в два столбца на экране путем использования CHR$6.
RND-процедура использует несколько новых для нас кодов калькулятора, которые могут быть полезны и для других процедур:
Код 161 (A1H) - stack_one - помещает на вершину стека калькулятора единицу.
Код 52 (34H) - stack_data - интерпретирует следующие за ним пять байтов как действительное число с плавающей точкой, записанное в интегральной форме и помещает
его на вершину стека калькулятора.
Код 50 (32H) - n_mod_m - вместо делимого (n) и делителя (m) эта команда помещает на стек остаток от деления и целое частное.
Код 02 - delete - команда служит для удаления числа с вершины стека калькулятора.
Последние два кода редко используются в игровых программах. Вызов процедуры FP_TO_BC, находящейся по адресу 11682 DEC (2DA2HEX) - CALL 11682, позволяет извлечь число с вершины стека, округлить его до ближайшего целого числа и затем записать в регистровую пару BC. В отличие от этой процедуры, процедура FF_TO_A, находящаяся по адресу 11733DEC (2BD5HEX), передает число с вершины стека в регистр A.
В данной программе скопированная RND-процедура заканчивается по адресу 23810, а начиная с адреса 23811 и по адрес 23820 находится процедура, осуществляющая дальнейшее преобразование случайного числа, записанного на стеке. Для этого на стек записывается число 12345, определяющее диапазон выборки, а затем производится перемножение случайного числа из диапазона 0...1, находящегося на стеке, с этим числом. Затем кодом калькулятора 02 (delete) удаляем со стека дробную часть произведения и на вершине стека остается целое число INT(RND*12345). Процедура PRINT VALUE выводит на экран 44 случайных числа в 2 столбца.
Листинг 4. 2
АДРЕС |
МАШ |
. КОД |
23760 |
3E |
02 |
|
23762 |
CD |
01 |
16 |
23765 |
CD |
6В |
0D |
23768 |
06 |
2C |
|
23770 |
С5 |
|
|
23771 |
ED |
4B |
76 |
23775 |
CD |
2B |
2D |
23778 |
EF |
|
|
23779 |
A1 |
|
|
23780 |
0F |
|
|
23781 |
34 |
37 |
16 |
23784 |
04 |
|
|
23785 |
34 |
80 |
41 |
23791 |
32 |
|
|
23792 |
02 |
|
|
23793 |
A1 |
|
|
23794 |
03 |
|
|
23795 |
31 |
|
|
23796 |
36 |
|
|
23797 |
СО |
A2 |
2D |
23800 |
ED |
43 |
76 |
23804 |
7E |
|
|
A7
28 03 D6 10
77
АССЕМБЛЕР ORG 23760 LD A,2 CALL 5633 CALL 3435 LD B,44 L1 PUSH BC
LD BC,(23670)
CALL 11563
RST 40
stack_one
add
stack_number multiply stack_number n_mod_m
delete
stack_one subtract duplicate endcalc CALL 11682
LD (23670),ВС
LD A,(HL)
AND А JR Z,L2 SUB 16
LD (HL),A
КОММЕНТАРИЙ
Открываем канал для печати на экран. Очистка экрана. Инициализация счетчика. Запомнили показания счетчика.
Приняли в ВС текущее значение системной переменной SEED.
Переброска содержимого BC на стек калькулятора. Включение калькулятора. На стеке (SEED), 1 (SEED)+1
На стек помещаем число 75.
((SEED)+1)*75
Число 65537
Деление на 65537 с остатком.
Частное удалили, оставили только остаток. "остаток",1 "остаток"-1
Ha стеке сделали копию. Выключение калькулятора. Перенос результата со стека калькулятора в регистровую пару BC. Установка нового значения системной переменной SEED. Экспонента числа, находя-шегося на вершине стека. Выставление флагов. Обход, если экспонента = 0 Вычитание числа 16 из экспоненты эквивалентно делению на 65536.
Изменили экспоненту числа, на вершине стека. Теперь на вершине стека
;случайное число в диапазоне от 0 до 1.
L2 |
|
|
|
|
|
23811 |
01 |
39 |
30 |
LD ВС,12345 |
|
23814 |
CD |
2B |
2D |
CALL 11563 |
Число 12345 DEC переносим на стек. |
23817 |
EF |
|
|
RST 40 |
Включение калькулятора. |
23818 |
04 |
|
|
multiply |
Умножение. На стеке случайное число от 0 до 12345 |
23819 |
27 |
|
|
int |
Выделение целой части. |
23820 |
38 |
|
|
endcalc |
Выключение калькулятора. |
23821 |
ЗЕ |
02 |
|
LD A,02 |
|
23823 |
CD |
01 |
16 |
CALL 5633 |
Открыли канал печати на экран. |
23826 |
CD |
E3 |
2D |
CALL 11747 |
Процедура PRINT_FP. Печата ет действительное число, находящееся на вершине стека калькулятора. |
25829 |
3E |
06 |
|
LD A,06 |
|
23831 |
D7 |
|
|
RST 16 |
Печать кода CHR$ 6. |
23832 |
C1 |
|
|
POP BC |
Восстановление счетчика. |
23833 |
10 |
BF |
|
DJNZ L1 |
Возврат на повторный шаг. |
23835 |
C9 |
|
|
RET |
Выход из процедуры. |
Демонстрационная программа 4.3 показывает, как применяется процедура RND. Здесь эта процедура используется для задания случайным образом цвета и высоты домов в городе и может быть использована в программах типа "Бомбардировщик". Все необходимые символы UDG здесь уже определены и Вы можете легко усовершенствовать эту программу для своих целей.
Начальное изображение на экране формируется с помощью БЕЙСИКа, а последующее, через несколько секунд, с помощью программы в машинных кодах, что позволяет сравнить скорость выполнения функции RND. Чтобы не менять начальное значение для генератора случайных чисел, используйте для вызова программы в машинных кодах не RANDOMIZE USR "адрес", а LET "переменная" = USR "адрес". Можно использовать команду PRINT USR "адрес", если Вы хотите получить число, записанное в регистровой паре BC после выхода из процедуры в машинных кодах. Для установки цветов PAPER и INK в процедуре используется LD (IY+83),47 вместо
LD A,47 и LD (IY+83),A.
как это было в предыдущих примерах, что позволяет уменьшить требуемый для процедуры объем памяти.
Перед вызовом генератора случайных чисел в регистр A записывается значение коэффициента n в формуле RND*n, которое затем передается в ячейку по адресу 23681 (в стандартной версии это неиспользуемая ячейка в области системных переменных). Это число округляется до ближайшего целого числа и записывается опять в регистр A, а оттуда, с помощью процедуры CALL 11733 переписывается на вершину стека.
Необходимая для организации вывода на экран информация находится в буфере принтера в следующей последовательности: AT(22), x,y, INK(16),a$, b$.
5. ОБСЛУЖИВАНИЕ КЛАВИАТУРЫ
Существуют два способа создания программ в машинных кодах для опроса состояния клавиатуры. Оба способа вполне приемлемы, но конкретный выбор одного из них зависит от типа программы.
5.1. Использование системной переменной LAST_KEY.
В области памяти ОЗУ компьютера "ZX-Spectrum" имеется процедура KEYSCAN которая вызывается каждую 1/50 секунды для опроса состояния клавиатуры и изменения соответствующих системных переменных. В случае, если будет нажата произвольная клавиша, то установится 5-й бит системной переменной FLAGS(23611 DEC = 5С3B HEX), сигнализирующий о факте нажатия клавиши, а код нажатой клавиши запишется в системную переменную LAST_KEY. Если же не будет нажата ни одна клавиша, то при каждом вызове процедуры KEYSCAN будет увеличиваться на 1 только значение системной переменной FRAMES.
Поскольку команда процессора HALT приостанавливает выполнение программы до очередного вызова процедуры KEYSCAN, то можно реализовать в машинных кодах программу, аналогичную по действию BASIC-команде PAUSE 0 (см. листинг 5.1). Эта программа зациклена на непрерывной проверке 5-го бита системной переменной FLAGS и, как только будет обнаружено, что этот бит включен (т.е. после очередного нажатия клавиши), выполнение программы будет продолжено дальше. Необходимо при этом сразу же сбросить 5-й бит переменной FLAGS для того, чтобы при очередном вызове процедуры опять сработала задержка до нажатия произвольной клавиши.
АДРЕС |
МАШ |
.КОД |
|
АССЕМБЛЕР |
|
|
|
|
|
ORG 23760 |
23760 |
3E |
00 |
|
|
LD A,0 |
23762 |
CD |
9В |
22 |
|
CALL 8859 |
23765 |
FD |
36 |
53 |
2F |
LD (IY+83),47 |
23769 |
3E |
02 |
|
|
LD A,2 |
23771 |
CD |
01 |
16 |
|
CALL 5633 |
23774 |
CD |
6В |
0D |
|
CALL 3435 |
23777 |
FD |
21 |
00 |
5В |
LD IY,23296 |
23781 |
FD |
36 |
00 |
16 |
LD (IY+0),22 |
23785 |
FD |
36 |
03 |
10 |
LD (IY+03),16 |
23789 |
FD |
21 |
3А |
5С |
LD IY,23610 |
23793 |
3E |
1F |
|
|
LD A,31 |
L1 |
|
|
|
|
|
23795 |
32 |
02 |
5В |
|
LD (23298),А |
23798 |
3E |
0A |
|
|
LD A,10 |
23800 |
32 |
81 |
5С |
|
LD (23681),A |
23803 |
CD |
61 |
5D |
|
CALL RND |
23806 |
6F |
|
|
|
LD L,A |
23807 |
3E |
13 |
|
|
LD A,19 |
23809 |
95 |
|
|
|
SUB L |
23810 |
32 |
01 |
5В |
|
LD (23297),А |
23813 |
3E |
02 |
|
|
LD A,2 |
23815 |
32 |
81 |
5С |
|
LD (23681),А |
23818 |
CD |
61 |
5В |
|
CALL RND |
23821 |
C6 |
94 |
|
|
ADD A,148 |
23823 |
32 |
05 |
5В |
|
LD (23301),А |
23826 |
3E |
04 |
|
|
LD A,4 |
23826 |
32 |
81 |
5С |
|
LD (23681),А |
23831 |
CD |
61 |
5D |
|
CALL RND |
23834 |
32 |
04 |
5B |
|
LD (23300),A |
Листинг 4.3
КОММЕНТАРИЙ
;Черный цвет бордюра. ;Окраска бордюра. ;Установка цвета: ;PAPER = 5; INK = 7 ;Канал экрана. ;Открыли канал. ;Очистка экрана CLS. ;Регистровая пара IY становится ;указателем на буфер принтера. ;B буфер принтера помещаем ;код 22 - код AT. ;Туда же (со смещением +3) ;помещаем код 16 - код INK. ;Восстановление IY в исходное состояние. ;Счетчик столбцов экрана.
;Текущую координату X поместили на ее место в буфере принтера. ;Множитель 10 для RND. ;Сохраняем его в 23681. ;Вызов копии процедуры RED. ;Копия организована в 23905 ;Случайное число.
;19-RND*10 - это Y-координата ;позиции печати. ;Заложили ее на свое место ;в буфере принтера.
;Множитель при RND равен 2. ;INT (RND*2)
;INT (RND*2) + 148 - выбор ;символа UDG - 148 или 149. ;Код печатаемого символа ;переносим в буфер принтера
;Множитель при RND равен 4. ;INT (RND*4) ;Код цвета INK 0...3
23837 |
3E |
02 |
|
|
LD A,02 |
Канал 2. |
23839 |
CD |
01 |
16 |
|
CALL 5633 |
Открыли канал экрана. |
23842 |
3E |
16 |
|
|
LD A,22 |
|
23644 |
D7 |
|
|
|
RST 16 |
Печать кода 22 - AT. |
23845 |
3A |
01 |
5В |
|
LD A,(23297) |
Координата Y. |
23848 |
3D |
|
|
|
DEC A |
Y-1 |
23849 |
D7 |
|
|
|
RST 16 |
...AT (Y-1).... |
23850 |
3A |
02 |
5B |
|
LD A,(23298) |
Координата X. |
23853 |
D7 |
|
|
|
RST 16 |
...AT (Y-1),X |
23854 |
3E |
93 |
|
|
LD A,147 |
Символ UDG (CHR$ 147). |
23856 |
D7 |
|
|
|
RST 16 |
PRINT AT (Y-1),X ;CHR$ 147 |
23857 |
11 |
00 |
5B |
|
LD DE,23296 |
Начало буфера принтера. |
23860 |
01 |
06 |
00 |
|
LD ВС,06 |
Шесть кодов из буфера. |
23863 |
CD |
3C |
20 |
|
CALL 8252 |
Печать серии символов. |
23866 |
3A |
01 |
5В |
|
LD A,(23297) |
Координата Y. |
23869 |
3C |
|
|
|
INC A |
|
23870 |
32 |
01 |
5В |
|
LD (23297),A |
Y=Y+1 |
23873 |
FE |
15 |
|
|
CP 21 |
Проверка на конец игрово |
|
|
|
|
|
|
го поля по вертикали. |
23875 |
20 |
ЕС |
|
|
JR NZ,L2 |
Возврат на L2, если конец |
|
|
|
|
|
|
не достигнут. |
23877 |
3E |
99 |
|
|
LD A,153 |
Код символa UDG. |
23879 |
32 |
05 |
5В |
|
LD (23301),А |
|
23882 |
3E |
07 |
|
|
LD A,7 |
Белый цвет INK. |
23884 |
32 |
04 |
5В |
|
LD (23300),А |
|
23887 |
11 |
00 |
5В |
|
LD DE,23296 |
Начало буфера принтера. |
23890 |
01 |
06 |
00 |
|
LD ВС,06 |
Шесть кодов из буфера. |
23893 |
CD |
3C |
20 |
|
CALL 8252 |
Печать управляющих кодов. |
23896 |
3A |
02 |
5В |
|
LD A,(23298) |
Координата X. |
23899 |
3D |
|
|
|
DEC A |
X=X-1 |
23900 |
FE |
FF |
|
|
CP FF |
X сравнили с -1. |
23902 |
20 |
93 |
|
|
JR NZ,L1 |
Если еще не все столбцы |
|
|
|
|
|
|
обработаны, то возврат на |
|
|
|
|
|
|
метку L1. |
23904 |
C9 |
|
|
|
RET |
Возврат. |
|
|
|
|
|
ORG 23905 |
|
RND |
|
|
|
|
|
|
23905 |
ED |
4В |
76 |
5С |
LD ВС,(23670) |
Значение SEED, |
23909 |
CD |
2В |
2D |
|
CALL 11563 |
Переносим его на стек. |
23912 |
EF |
|
|
|
RST 40 |
Включение калькулятора. |
23913 |
A1 |
|
|
|
stack one |
|
23914 |
0F |
|
|
|
add |
|
23915 |
34 |
37 |
16 |
|
stack_number |
Копия системной процедуры |
23918 |
04 |
|
|
|
multiply |
RND. Комментарий см. в 4.1 |
23919 |
34 |
80 |
41 |
00 00 80 |
stack_number |
|
23925 |
32 |
|
|
|
n_mod_m |
|
23926 |
02 |
|
|
|
delete |
|
23927 |
A1 |
|
|
|
stack_one |
|
23928 |
03 |
|
|
|
subtract |
|
23929 |
31 |
|
|
|
duplicate |
|
23930 |
38 |
|
|
|
endcalc |
|
23931 |
CD |
A2 |
2D |
|
CALL 11682 |
|
23934 |
ED |
43 |
76 |
5C |
LD (23670),ВС |
|
23938 |
7E |
|
|
|
LD A,(HL) |
|
23939 |
A7 |
|
|
|
AND A |
|
23940 |
28 |
03 |
|
|
JR Z,L3 |
|
23942 |
D6 |
10 |
|
|
SUB 16 |
|
23944 |
77 |
|
|
|
LD (HL),A |
|
L3 |
|
|
|
|
|
|
23945 |
3A |
81 |
5C |
|
LD A,(23681) |
Множитель при RND. |
23948 |
CD |
28 |
2D |
|
CALL 11560 |
Поместили его на стек. |
23951 |
EF |
|
|
|
RST 40 |
Включение калькулятора. |
23952 |
04 |
|
|
|
multiply |
Умножение. |
23953 |
27 |
|
|
|
int |
Выделение целой части. |
Выключение калькулятора. Перенос результата в акк-р Выход из процедуры RND.
Листинг 5.1
КОММЕНТАРИЙ
Проверка 5-го бита системной
переменной FLAGS.
Зацикливание на метку L1,
если никакая клавиша не нажата.
Принудительное выключение
5-го бита, если клавиша была нажата.
Выход из процедуры.
АДРЕС ORG 23760 L1
23760 23764 23766 23770
МАШ.КОД
FD CB 01 6Е 28 FA
FD CB 01 АЕ C9
АССЕМБЛЕР
BIT 5,(IY+1) JR Z,L1 RES 5,(IY+1) RET
5.2 Опрос клавиатуры, как внешнего порта: IN A,(C)
Аналогично команде БЕЙСИКа IN, при этом способе проверяется состояние одной из половин ряда клавиатуры. Спецификация проверяемого ряда находится в регистровой паре ВС, а код нажатой клавиши передается в регистр A. Так как каждая половина ряда клавиатуры включает по 5 клавиш, то для идентификации нажатой клавиши используют с 0 по 4 биты аккумулятора. Нулевой бит соответствует внешней клавише ряда, а четвертый бит соответствует внутренней клавише полуряда клавиатуры.
Все биты регистра A изначально установлены и, если не нажата ни одна из клавиш, то значение регистра A должно быть равно 255. Если же одна из клавиш будет нажата, то сбрасывается бит, соответствующий этой клавише. Например, если будет нажата клавиша "0", то сбрасывается нулевой бит регистра A и значение этого регистра теперь будет равно 254. При этом способе можно определить одновременное нажатие более чем одной клавиши путем анализа битов аккумулятора.
Этот способ оказывается весьма полезным для создания игр, в которых участвуют два и более игроков, либо для организации перемещения объектов по экрану одновременно в двух направлениях. Одним словом, этим приемом пользуются в тех случаях, когда надо обрабатывать нажатие пользователем второй клавиши при неотпущенной первой. В программе 5.2 показано, как осуществить задержку в выполнении программ до тех пор, пока не будет нажата клавиша "0".
Есть еще один случай, когда опрос клавиатуры как внешнего порта оказывается единственным рабочим приемом - случай, когда прерывания работы процессора отключены командой DI.
Даже во время выполнения Вашей собственной программы, написанной в машинных кодах, 50 раз в секунду будет вызываться процедура KEYSCAN и, в результате, увеличивается время выполнения Вашей программы. Можно отменить эти прерывания, чтобы сократить время выполнения программы, используя команду DI. Однако, это будет означать, что все прерывания запрещены и, следовательно, нельзя будет использовать процедуру LAST_KEY для считывания состояния клавиатуры, т.е. команда IN остается единственный доступным способом.
В программе 5.3 показан порядок работы при запрете прерываний.
Всегда помните, что перед выходом из процедуры, где Вы используете команду DI, необходимо записать команду EI, разрешающую прерывания. Попробуйте выполнить программу 5.3 без этой команды и увидите, что из этого получится. Сброса программы не произошло, но компьютер "завис" и для того, чтобы клавиатура вновь заработала, необходимо выключить и опять включить компьютер.
Программа 5.4 является аналогом БЕЙСИК-команды PAUSE n, т.е. позволяет остановить выполнение программы на заданный промежуток времени, либо продолжить выполнение сразу же после нажатия произвольной клавиши. Эта программа основана на том, что сканирование клавиатуры происходит строго через каждые 0.02 секунды, а команда HALT приостанавливает выполнение программы до очередного сканирования клавиатуры.
Листинг 5.2
КОММЕНТАРИЙ
МАШ.КОД 01 FE EF
ED 78 CB 47
C8
18 F6
АССЕМБЛЕР ORG 23760
LD BC,61438
IN A,(C) BIT 0,A
SET Z
JR L1
Установка в BC адреса внешнего порта, соответствующего верхнему правому полуряду клавиатуры. Ввод данных из порта в аккумулятор. Проверка нулевого бита, который соответствует внешней клавише полуряда. Если бит выключен, то клавиша нажата, следует возврат из процедуры. В противном случае состояние ожидания следует продолжить и вернуться на L1.
Листинг 5.3
АССЕМБЛЕР
ORG 23760 DI
LD BC,61438
IN A,(C)
BIT 0,A JR NZ,L1
EI RET
АССЕМБЛЕР
ORG 23760 LD BC,500
HALT
МАШ.КОД F3
01 FE EF
ED 78
CB 47 20 F7
FB
C9
МАШ.КОД
01 F4 01 76
FD CB 01 6E 20 05
23760 L1
23761
23764
23766 23760
23770
23771
АДРЕС
23760 L1
23763
23761 23768
BIT 5,(IY+1) JR NZ,L2
23770
23771
23772
23773
L2
23775 23779
0B 78 B1
20 F7
FD CB 01 AE C9
DEC BC LD A,B OR C
JR NZ,L1
RES 5,(IY+1) RET
КОММЕНТАРИЙ
Запрет прерываний.
Установка в BC адреса внешнего порта, соответствующего верхнему правому полуряду клавиатуры. Ввод данных из порта в аккумулятор. Проверка нулевого бита. Если бит включен, то клавиша не нажата. Следует -повторять проверку. Разрешение прерываний перед выходом. Выход из процедуры.
КОММЕНТАРИЙ
Размер паузы
Остановка процессора до прохождения прерывания. Проверка 9-го бита системной переменной FLAGS. Если 5-ый бит FLAGS включился, значит была нажата какая-то клавиша и пауза прерывается, следует переход на L2.
Уменьшение счетчика.
Проверка счетчика на 0. Если счетчик не обнулен, то пауза продолжается.
Принудительное выключение пятого бита FLAGS. Выход из процедуры.