|
Обработка прерываний - драйвер джойстика
|
Прерывание - это сигнал, с помощью которого процессор оповещается о внешнем событии. При его поступлении процессор приостанавливает выполнение текущей программы и передает управление специальной подпрограмме обработки прерывания, которую часто называют обработчиком прерывания. Прерывания подразделяются на маскируемые и немаскируемые. Первое может быть разрешено или запрещено (в этом случае процессор игнорирует сигнал прерывания) командами El (Enable Interrupt) или DI (Disable Interrupt). Второе-же безусловно выполняется при поступлении сигнала прерывания.
В компьютере ZX Spectrum установлен микропроцессор Z80, имеющий две входные линии, на которые поступают сигналы прерываний: линия NMI используется для регистрации немаскируемых прерываний, а линия INT - для маскируемых. В компьютере с минимальной конфигурацией линия NMI не задействована (обычно она выводится на разъем для подключения внешних устройств), а линия INT подключена к блоку, вырабатывающему синхронизирующие сигналы для телевизора и активизируется с частотой кадровой развертки (50 раз в секунду) . Стандартный обработчик этого прерывания, код которого находится в постоянном запоминающем устройстве (ПЗУ), выполняет две функции: во-первых увеличивает на 1 значение трехбайтовой переменной, находящейся по адресу 23672 (#5С78), которая может использоваться прикладными программами для измерения промежутков времени с дискретностью 1/50 сек., и во-вторых, опрашивает состояние клавиатуры, преобразует коды нажатых клавиш во внутреннее представление и помещает их в буфер клавиатуры из которого они бу¬дут считываться интерпретатором Бейсика или прикладными программами.
Поскольку в ZX Spectrum стандартный обработчик прерывания записан в ПЗУ, его код не может быть модифицирован программой. Единственный способ изменения процедуры обработки прерывания состоит в "перехвате" прерывания другим обработчиком. Рассмотрим как это можно сделать.
Микропроцессор Z80 имеет три режима прерываний - 0,1 и 2. Вы¬бор нужного режима осуществляется командами IM 0, IM 1 или IM 2 соответственно. В режиме 0 прерывание отрабатывается также, как и на микропроцессоре i8080 (К580ВМ80), т.е. после поступления прерывания с шины данных считывается и исполняется код команды, формируемый обычно специальной микросхемой контроллера прерыва¬ний. В ZX Spectrum микросхема контроллера прерываний отсутствует, а используется схемотехническая особенность, состоящая в том, что при отключении от шины данных всех устройств ее линии переводятся в состояние "1". Поэтому, когда при поступлении сигнала прерывания от шины данных отключаются все устройства, это эквивалентно приходу от контроллера прерываний байта #FF, что соответствует команде RST #38. В режиме 1 при поступлении сигнала прерывания микропроцессор автоматически выполняет команду RST #38 ничего не считывая с шины данных. Т.е. режимы 0 и 1 на ZX Spectrum полностью идентичны. Наконец, режим 2. Это самый "хитрый" режим прерываний в Z80. Специально для этого режима в микропроцессоре имеется регистр вектора прерываний I. Значение регистра I может быть прочитано или записано командами LD А,I или LD I,А. При поступлении сигнала пре¬рывания процессор считывает с шины данных байт и формирует адрес, старший байт которого равен I, а младший равен считанному байту (напомним, что на ZX Spectrum он всегда равен #FF). Двухбайтовая ве¬личина, расположенная по этому адресу, интерпретируется далее про¬цессором как адрес обработчика прерывания.
Таким образом "перехват" прерывания осуществляется следующим образом. По адресу #xxFF записывается адрес точки входа в новый обработчик прерывания. Затем в регистр I заносится значение хх и выполняется команда IM 2.
Проиллюстрируем эту технику на примере драйвера джойстика.
ORG #FEFF
VECTOR DEFW ENTRY
TABL
DEFW #2713 ; значение DE для кнопки ’’вправо"
DEFW #2704 ; значение DE для кнопки "влево"
DEFW #2703 ; значение DE для кнопки "вниз"
DEFW #270В ; значение DE для кнопки "вверх"
DEFW #2723 ; значение DE для кнопки "огонь"
ENTRY
PUSH AF
PUSH HL ; увеличиваем на 1 системный
LD HL,(#5C78) ; счетчик времени
INC HL LD (#5C78),HL
LD A,H
OR L
JR NZ,L0048
INC (IY+64)
L0048
PUSH BC
PUSH DE
CALL GETKEY
POP DE
POP BC
POP HL
POP AF
EI
RET
GETKEY
IN A,(#DF) ; опрос джойстика
LD HL,#FFFF
NOBIT
RRCA
INC HL ; поиск справа-налево единичного
JR NC,NOBIT ; бита
LD A,L
CP 5 ; если не нажата ни одна из кнопок
JP Z,#02BF ; джойстика, то опрос клавиатуры
ADD HL,HL
LD DE,TABL ; в противном случае опрос: клавиатуры
ADD HL,DE ; имитируется занесением в DE
LD Е, (HL) ; значения из таблицы TABL
INC HL
LD D, (HL)
JP #02СЗ
INIT
LD A,#FE
LD I.A
IM 2
RET
Процедура ENTRY идентична соответствующей процедуре обработчика прерываний, "прошитого" в ПЗУ, - значение 3-байтового системного счетчика времени увеличивается на 1 и производится вызов процедуры GETKEY, осуществляющей опрос джойстика и клавиатуры. Различия появляются в процедуре GETKEY. В ПЗУ находится следующий код:
02BF: CALL #028Е
02С2: RET NZ
02СЗ: LD HL,#5C00
Процедура #028Е осуществляет опрос клавиатуры и возвращает в регистровой паре DE коды нажатых клавиш. Если ни одна клавиша не нажата, то DE=#FFFF, если нажата ровно одна клавиша, то D=#FF, а в Е находится код клавиши. Если нажато две клавиши, причем одна из них CapsShift или SymbolShift, то код CapsShift или SymbolShift находится в D, а в Е находится код второй клавиши. Во всех этих случаях флаг Z установлен, свидетельствуя о разрешенной комбинации нажатых клавиш, для остальных комбинаций он сбрасывается. На рисунке схематично показана клавиатура и коды клавиш, возвращаемые в регистровой паре DE.
В процедуре GETKEY опрашивается состояние порта джойстика. Положения кнопок индицируют биты 0-4: бит 0 - кнопка "вправо" (1 - нажата, 0 – не нажата); 1 - "влево", 2 - "вниз", 3 - "вверх", 4 - "огонь". Биты 5-7 всегда равны "1". Если нажатие кнопки джойстика не зафик¬сировано, то управление передается по адресу #02BF (стандартная обработка прерывания). В противном случае в регистровую пару DE помещается нужное значение из таблицы TABL (имитация вызова процедуры опроса клавиатуры #028Е) и управление также передается стандартному обработчику, но уже минуя опрос клавиатуры.
Активизация драйвepa джойстика производится вызовом процедуры INIT.
Ниже приводится текст драйвера джойстика на Бейсике.
1 DATA 65279,3
2 DATA «OBFF1327042703270B272327F5E52A785C2322785C7CB52003FD3440C5D5CD2658»
3 DATA «FFD1C1E1F1FBC9DBDF21FFFF0F2330F C7DFE05CABF02291101FF195E2356C3C319»
4 DATA «023EFEED47ED5EBD»
100 CLEAR 65278: GO SUB 9993
110 RANDOMIZE USR 65344: STOP
9993 READ a,S: FOR f=1 TO S
9994 READ 1$: LET 1=LEN 1$: LET s=0: LET k=2
9995 LET a$=l$(k-l): LET b$=l$(k)
9996 LET c=(CODE а$-48-(7*(а$>"@")))*16+CODE b$-48-(7*(b$>"@”))
9997 IF kc THEN PRINT "error in string";f+l: STOP
(продолжение следует)
|