Глава 9. Прерывания.

Граждане, этот больной пой­дет вне очереди,

М.А. Булгаков Мастер и Маргарита.

I.

Прерывание по своему смыслу есть временное прекращение какого-то процесса. Команды INTh САІХреализуют программные прерывания. Они выполняются, когда приходит время выполнить соответствующую команду. После их выполнения програм­ма продолжает работать с команды, стоящей за командой вызова прерывания. Суще­ствуют и аппаратные прерывания, которые происходят, когда наступает некоторое со­бытие, внешнее по отношению к программе. Это может быть сигнал по прошествию определенного промежутка времени, нажатие клавиши, переход принтера в состояние готовности, наступление некоторого события в микропроцессоре (деление на нуль, переполнение и т.п.) и т.д. Соответственно, аппаратные прерывания, происходящие от внешних будем называть внешними, а аппаратные прерывания, происходя-

щие от события в микропроцессоре - внутренними. Естьеще немаскируемое прерыва­ние - NMT. Это прерывание невозможно запретить командой CLI. Мы не будем больше рассматривать        за исключением материала главы 26.

Выполнять команды CALL-и INT мы научились. А как использовать прерывания в своих целях? Здесь многому еще придется научиться.

Как было указано в главе 1, в начале памяти (младшие адреса) располагаются векто­ры прерываний. Некоторые векторы устанавливаются до загрузки операционной систе­мы, некоторые устанавливает сама MS DOS. Например, вектор 8Н (т.е. в памяти он рас­положен по адресу 0:8П*4, см. главу 2) является вектором прерывания таймера. При нормальной установке каждую секунду происходит 18.2 обращений к процедуре обра­ботки, на которую указывает это вектор. Пет принципиального различия между векто­рами программных прерываний (векторы 21Н, 16Н, ЮНидр.) и векторами прерываний аппаратных (это векторы Ш, 9Н, 8Н идр.). Иге, и другие могут стать объектом перехва­та, т.е. переустановки на другую процедуру. Зачем это может понадобиться? А затем, что в некоторых ситуациях Вы можете быть недовольны тем, как обрабатывает преры­вания системная процедура, и захотите, чтобы обработку вела собственная процедура.

Пичто не мешает установить вектор прерывания на Вашу процедуру. Возникает вопрос: как поступить стой процедурой, на которую он был направлен до перехвата? Здесь может быть три варианта решения. Все остальные будут являться комбинация­ми этих трех. Па Рис. 9.1 эти ситуации показаны схематично.

Из схем, приведенных на Рис. 9.1, схема (С) реже всего встречается в чистом виде. Как правило, на практике встречается некоторая смесь - ВС. Теперь том, почему желательно, а во многих случаях необходимо выполнять процедуру, на которую указы­вал старый вектор Представьте, что Вы перехватили прерывание номер 21Н. Если теперь не выполнять старую процедуру, то функции MS DOS будут заблоки­рованы. В большинстве случаев такое блокирование нежелательно. И в конце концов надо иметь уважение К тем, кто перехватил данное прерывание раньше и желает полу­чить свое. При таком подходе образуется целая цепочка процедур, которые будут выпол­няться друг за другом, пока не будет выполнена последняя, после чего произойдет воз­врат туда, откуда это прерывание было выполнено. Есть, однако, прерывания, которые иначе, чем по схеме (С), нет смысла перехватывать. О них речь пойдет впереди.

Выполняем старую процедуру

Вектор

Выполняем команды

Возвращаемся (ИЗЕТ)

(А)

 

Вектор

(В)

 

Вектор

(С)

Рис. 9.1. Возможные схемы " перехвата прерываний.

Вызвать старую процедуру прерывания можно двумя способами22. Пусть старый вектор прерывания хранится в двух смежных словах: ОJTNTи S_INT: 0_INT - смещение, находится в младшем слове,

S_INT- сегмент, старшее слово; предполагается, что слова расположены в сегмен­те данных.

Первый способ:

JMP DWORD PTR DS:[0_INT]

передаст управление старой процедуре прерьвзания, причем возврата в Вашу про­цедуру не произойдет.

Второй способ:

PUSHF

CALL DWORD PTR DS:[0_INT]

передаст управление старой процедуре прерывания, после выполнения процеду­ры (или целой цепочки процедур) произойдет возврат в Вашу программу21. Дополни­тельная PUSHF необходима для того, чтобы правильно был осуществлен возврат по IRET. Второй способ часто бывает необходим, но пользоваться им следует с большой осторожностью. Дело втом, что процедуры прерывания, к которым Вы обратились посредством команды CALL, могут возвращать в регистрах некоторую информацию, например, в регистре флагов, в регистре АХ. Вы не должны портить эту информацию (см. главу 12).

Для вызова прерывания можно также использовать свободные векторы. Для этого ншбходимонаправитьнеиспользуемыйвектор(см.ниже)нанужнуюпроцедуруиза-тем вызвать его командой INT. Например, Вы работаете с вектором 16Н. Он направлен на Вашу процедуру. Старое значение вектора 16Нприсвойте, например, вектору FEH. В конце Вашей процедуры обработки поставьте команду INT FEH. Такой вызов будет аналогичен вызову через CALL (см. выше).

Перенаправить вектор можно также двумя способами:

1) используя функции DOS 25Н и 35Н;

2) непосредственно обратившись к таблице векторов и изменив содержимое соответствующих ячеек.

Рассмотрим первый способ, иллюстрируемый следующим фрагментом.

22 Во всяком случае, использования этих целей скажем ЯЕТЕбыло бы слишком экзотично.

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

MOV AL,5 INT 21Н

MOV

MOV OLD_0,BX

MOVAH,25H

MOV DX, OFFSET P_5

MOV AX, SEG P_5

MOV DS,AX

INT 21H

;получить вектор прерывания

;вектор 5    (печать экрана) : ;после выполнения содержимое в

; сохранить старый вектор

/установить ;смещение

/сегмент

вектор на свою процедуру

Следующий фрагмент делает же самое, не использует функции DOS.

CLI

MOV АХ, О MOV ES,AX MOVDX,ES: [5Н*4] MOVBX,ES:[5H*4+2]

MOV OLD_S,BX

MOV0LD__0,DX MOV DX,OFFSET P 5 MOV AX, SEG P 5 MOVES: [5H*4], DX MOV ES: [5H*4+2] ,AX

STI

/запретить прерывания

/смещение в БХ /сегмент в ВХ /сохраняем старый /вектор

г I

/изменяем вектор /разрешить прерывание

Обратите внимание, что во втором фрагменте передтем, какизменять вектор, мы запрещаем прерывания. Это делается для того, чтобы обезопасить себя от прерывания именно по этому вектору, когдаонещенедо конца изменен. Функции MS DOS делают это сами.

П.

При работе с прерываниями нужно быть аккуратным. Перед выходом из програм­мы следует присвоить векторам их прежние значения. При выходе в MS DOS область памяти, занимаемая программой, освобождается. Если Вы не присвоите векторам их старые значения, то они будут направлены на освобожденную область памяти, что в конечном итоге приведет к "зависанию" всей системы. Исключение составляют толь­ко векторы 23Н и 24Н (а также 22Н) - операционная система еаманаправитих, куда надо, по выходу из программы.

В главе У уже говорилось о том, какую функцию реализует вектор 23Н. Если Вы хотите избавиться от Ctrl Break (Ctrl С), направьте его на процедуру, где будет стоять лишь одна команда - IRET. Можно вставитьтудаидругие команды. Личноя, однако, не использую этот способ (см. главу У).

Поговорим теперь о векторе 24Н24. Процедура, на которую указывает данный век­тор, выполняется при критических ошибках (отсутствие дискеты, неготовность прин­тера и т.п.). Вы можете направить свою процедуру. Использование вектора 24Н открывает довольно широкие возможности обработки критических ситуаций. Зесь будет рассказано только о наиболее частом способе обработки. Перед тем как возвра­титься из процедуры, пошлите в регистр код обработки: - игнорировать ошибку (опасно); 1 - повторить операцию (можно сделать несколько повторений); 2 - выйти через вектор 23Н; 3 - вернуться с индикацией ошибки.

Наиболее приемлемым является третий вариант, который, кстати, чаще всего и используют. Покане вернетесь из прерывания, не вздумайте обращаться ккаким-либо функциям MS DOS. Помните и еще об одном нюансе: при возвращении с AL=3 следу­ет выполнить какую-нибудь функцию MS DOSc номером выше ОСН. Это вернет опе­рационную систему в нормальное состояние. Не пугайтесь, что при этом будет взве­ден флаг ошибки. Следующие функции MS DOS будут уже выполняться нормально. В последнем разделе главы мы снова возвращаемся к прерыванию 24Н.

Рассмотрим конкретный пример перехвата прерываний. На Рис.9.1 представлена программа, выход из которой можно осуществить только по нажатию клавиши ESC. Ни на Ctrl Break, ни на Ctrl С программа не реагирует, несмотря на то, что ввод и вывод осуществляется посредством функций MS DOS (выводится на экран и прове­ряется буфер клавиатуры). Подход является общим, хотя и непростым. Блокирование нажатия Ctrl С можно проводить и по-другому, сбрасывая флаг клавиши и, выполняя стандартную процедуру обработки прерывания клавиатуры. Я же хотел обратить Ваше внимание на возможность ситуации, когда Вашей программе придется брать на себя всю обработку прерывания, не вызывая стандартную процедуру. Строки, отмеченные звездочками, можно было бы с тем же успехом заменить всего одной строкой (!):

AND     BYTE PTR ES: [417Н], 11111011В .

В этом случае нажатие Ctrl С было бы равносильно просто нажатию С.

Отключены в этой программе также клавиши PrtScn Pause. Первая клавиша от­ключается путем направления вектора печати экрана (номер 5) на процедуру, содер­жащую только команду IRET. Отключение клавиши Pause осуществляется путем сбра­сывания соответствующего       по адресу (см. главу У, флаги клавиатуры).

Обратите также внимание на использование в программе портов с адресами 60Н и 61Н. Это порты микросхемы управления периферией. Мы встречались с портом 61Н, когда говорили о генерации звука. Это портидля чтения, и для записи. Засылкавпорт

:* Я не ставил своей задачей рассказать обо всех векторах. О них с исчерпывающей полнотой Вы прочтете в справочнике программиста. Я хочу лишь изложить основные идея, а как Вы их будете применять, Ваше дело. байта с установленным 7-м битом дает подтверждение, что скан-код нажатой клавиши принят. Порт 60Н используется только для чтения и после нажатия клавиши содержит скан-код этой клав........

хранятся старые векторы клавиатуры

по Ctrl Break

DS:DATA,   SS:SSEG

DATA SEGMENT ; в сегменте данных ;вектор прерывания OLD_09_0 DW ? OLD_09_S DW ? ;вектор прерывания 0LD_1B_0 D W ? OLD_1B_S  DW ?

;вектор прерывания печати экрана OLD_05_0  DW ? OLD_05_S DW ?

DATA ENDS

SSEG SEGMENT STACK DB  200 DUP(?)

SSEG ENDS CODE SEGMENT

ASSUME CS:CODE, BEGIN:

MOV AX,DATA

MOV DS,AX /определяем значение векторов

MOV AX,351BH

INT 21H

MOV 0LD_1B_S,ES MOV 0LD_1B__0,BX MOV AX,3509H

INT 21H

MOV OLD_09_S,ES MOV OLD_09_O,BX MOV AX,3505H

INT 21H

MOV OLD_05_S,ES MOV OLD_05_O,BX

новое

1BH, 05 сохраняем

значение векторов

PUSH DS

PUSH CS '

POP DS

MOV DX,OFFSET CS:INT09

MOV AX,2509H

■ INT. . 2,1 H

MOV. DX, OFFSET CS: ,INT1B

MOV AX,251BH

их

21H

DX,OFFSET CS:INT05 AX,2505H

21H .

DS

которого можно  выйти только  нажатием клавиши ESC

INT

MOV

MOV

INT

POP ;цикл, из L001:

MOV DL,48

MOV АН, 2

INT 21Н

MOV АН,ОбН

MOV DL,OFFH

INT 21H

JZ LO01

CMP AL,27

JNZ LO01 /восстанавливаем старое

значение векторов

PUSH

DS

POP

ES

MOV

DX,ES:OLD 1

MOV

DS,ES:OLD 1

MOV

AX,2509H

INT

21H

MOV

DX,ES:OLD_

MOV

DS,ES:OLD_:

MOV

AX,251BH

INT

21H

MOV

DX,ES:OLDJ

MOV

DS,ES:OLD 1

MOV

AX,2505H

INT

21H

;выходим в DOS MOV АН,4CH

INT 21H

; процедура прерывания клавиатуры INTO 9  PROC FAR

PUSH AX

PUSH ES

PUSH DS

значение DS нужно,    потому что вызов клавиатуры может   произойти   в момент, /когда DS не указывает на сегмент данных ;   (например,   во  время выполнения функции DOS) MOV    АХ,DATA MOV    DS, AX MOV AX,0

MOV ES,AX■ IN AL,60Н

CMP AL,46 ;скан-код клавиши С

JNZ LOO

TEST BYTE PTR ES:[417H],4 /проверяем, не нажата ли Ctrl JZ      LOO ■ ■

/следующие команды необходимы,    чтобы дать контроллеру

/клавиатуры сигнал,   что символ принят

IN

AL,61H

 

MOV

АН, AL

 

OR

AL,80Н

 

OUT

61H,AL

. *

MOV

AL, АН

 

OUT

61H,AL

. *

/две следующие команды дают сигнал контроллеру прерываний, / что процедура   прерывания завершена

MOV

AL,20H

і

OUT

20H,AL

,• *

POP

DS

r *

POP

ES

'. *

r

POP

AX

. *

r

IRET

 

 

LOO:

PUSHF

CALL DWORD PTR

AND BYTE PTR клавиши /Pause POP DS POP ES '

POP AX IRET INT09 ENDP

/процедура прерывания по Ctrl Break

INT1B   PROC FAR

IRET INT1B ENDP

прерывания PrtScr

INT05 PROC IRET

INT05 ENDP

CODE ENDS

END BEGIN

Рис. 9.l. Пример программы с перехватом прерываний.

IV.

Внешние аппаратные прерывания обслуживает специальное устройство, назы­ваемое контроллером прерываний (Intel 8259) (см. Приложение 9). Речь идет о пре­рываниях, связанных с событиями на внешних устройствах, т.е. внешними преры­ваниями, но не с событиями, происходящими внутри микропроцессора (деление на нуль и т.п.). Контроллер распознает прерывание и посылает сигнал микропро­цессору. Если прерывания разрешены, то микропроцессор на следующем шаге получает байт-номер прерывания и, закончив выполнение текущей команды, вы­полняет соответствующую команду INT. В задачу контроллера прерываний входит также обслуживание прерываний по приоритетам. Может статься, что, пока обслу­живается одно прерывание, произойдет другое. Контроллер определяет приори­тет, так что прервать уже выполняющееся прерывание может лишь прерывание с более высоким приоритетом. Если два прерывания произойдут одновременно, то первым будет выполняться прерывание с более высоким приоритетом. Надо, одна­ко, учесть, что, когда выполняется аппаратное прерывание, запрещаются все пре­рывания на уровне микропроцессора - выполняется команда CLI. Если у Вас нет возражений на то, чтобы прерывания все-таки происходили, поставьте в начале процедуры команду STI. В этом случае будут происходить лишь прерывания более высокого приоритета (этим будет управлять контроллер прерываний). В конце про­цедуры следует указать контроллеру, что прерывание закончено (см. программу на Рис. 9.1).

Наиболее высоким приоритетом обладает прерывание таймера - вектор 08Н. Сле­дует избегать ситуаций, когда это прерывание оказывается надолго запрещенным. Это может повлиять наход системныхчасов. Ниже все прерывания расположены в поряд­ке их приоритетов.

Прерывание

Вектор

Источник

IRQ0

8

Таймер

IRQ1

9

Клавиатура

IRQ2

OAH

Канал ввода-вывода

*IRQ8

70H

Часы реального времени (АТ)

*IRQ9

71H

Программно переводится в 2

*IRQ10

72H

Резерв

*IRQ11

73H

Резерв

*IRQ12

74H

Резерв

*IRQ13

75H

Мат. Сопроцессор (АТ)

*IRQ14

76H

Контроллер жесткого диска (АТ)

*IRQ15

77H

Резерв

IRQ3

QBE

СОМ2 (для ХТ было СОМ 1)

IRQ4

OCR

СОМ 1 (для ХТ было СОМ2)

IRQ5

ODH

ЬРТ2 (для ХТ был жесткий диск)

IRQ6

QEE

Гибкий диск

IRQ7

OFH

ЬРТ1

Рис. 9.2. Приоритеты прерываний.

Первая показывает номера приоритетов прерываний, вторая -

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

обслуживаются вторым контроллером.

Из рисунка видно, чтоуАТ имеется больше прерываний, чемуХТ. Объясняется это тем, что у AT прерывания обслуживают две микросхемы 8259. Основной контрол­лер называется ведущим, дополнительный контроллер - ведомым. Вектор прерывания получается путем сложения базового вектора и номера прерывания. У ведущего кон­троллера базовый вектор равен 8, у ведомого - 70E. Таким образом, номер вектора прерывания от клавиатуры равен 1+8,т.е. 9. Базовое значение вектора прерываний может быть изменено (см. главу 20). Программирование ведущего контроллера осу­ществляется через порты

На уровне контроллера возможно маскирование отдельных прерываний. Для это­го необходимо послать цепочку соответствующих битов в порт 21E - регистр маски (порт для второй микросхемы AT имеет адрес 1АН). Чтобы, например, замаскировать прерывание клавиатуры,достаточно выполнить следующиекоманды:

MOVAL, ООООООЮВ OUT 21H,AL

В конце программы следует порт очистить. Если Ваша процедура перехватывает аппаратное (sic!) прерывание (см. Рис. 9.2) по схеме (С), т.е. полностью заменяется стандартный обработчик, то в конце процедуры следует поставить следующие маги­ческие строки:

MOV AL,20H

OUT 20Н,AL (OUT OAOH.AL - для второго контроллера) .

Этим Вы очищаете регистр обслуживания прерывания и разрешаете обработку прерываний с более низким приоритетом (см. программу на Рис. 9.1). При перехвате не аппаратных прерываний (не от внешних устройств) в таких действиях нет необхо­димости. Так, прерывание IRQ8 (оттаймера)требуетсигналаокончания. Прерывание же с вектором ЮНвызывается уже после отработки первого прерывания и сигнала

окончания не требует.

На Рис. 9.3 приведена схема работы контроллера прерываний.

5 - 4072

-X)

->t ->2 ->3 ->4

->s

->6 ->7

 

Регжявр Регистр Запросов маски Порт 2ОН   Itopr 2Ш

Схема Региотр

аказяйа обслужи-

пряоря- ваешх

«тегов Запросов

Порт гон порт гон

Рис. 9.3. Работа контроллера прерываний.

Рассмотрим работу контроллера прерываний по схеме Рис.9.3. Сигнал запроса прерываний от некоторого устройства (у нас оно имеет номер 2) поступает на вход регистра запросов и устанавливает в единицу значение соответствующего бита. Пока этотбитне сброшен, прерывание данного номера игнорируется. Далее сигнал посту­пает в регистр маски. Пройти через регистр маски сигнал может лишь при условии, что соответствующий бит равен нулю. Заметим, что уже пояснялось, как замаскиро­вать отдельные прерывания. Из сказанного следует, что маскирование прерывания сохраняет последний запрос. После регистра маски сигнал поступает на схему анали­за приоритетов. Данная схема начинает играть важную роль лишь тогда, когда два или более прерываний накладываются друг на друга. После схемы анализа приоритетов сигнал поступает в микропроцессор и одновременно в регистр обслуживания запро­сов, где дается разрешение на установку соответствующего бита.

Микропроцессор воспринимает поступивший сигнал лишь в том случае, если раз­решены прерывания (не было команды СЫ). Если же была команда С1Л, то запрос блокируется, однако, как ясно из схемы, не пропадает. Соответственно после разреше­ния прерываний повторяется. Если прерывания разрешены, то:

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

2. Посылается сигнал в регистр запросов и сбрасывается соответствующий бит.

После этого контроллер уже может восприниматьсигналтогожепрерывания.

3. Запрещаются Прерывания на уровне микропроцессора - не явно выполняется команда СЕ1. л

4. Выполняется процедура прерывания.

Из изложенной схемы становится ясно, как реагирует контроллер на одновремен­ный приход несколькихпрерываний. Если одно прерывание уже работает, то начинает играть схема приоритетов прерываний. Пропускаются лишь прерывания более высо­кого приоритета, которые, однако, задерживаются на уровне контроллера, т.к. выпол­нена команда СЕІ. Если Вы хотите, чтобы Ваша процедура прерывания не блокирова­ла выполнение более высоких прерываний, выполните в начале процедуры команду БИ Более же низкие по приоритету прерывания разрешаются только после посылки в порт 20Н числа 20Н (см. выше).

Как уже было сказано, базовый вектор для ведущего контроллера равен 8Н, а для контроллера ведомого - 70Н. Значение этих векторов можно изменить. Тем самым мы можем менять значения векторов прерываний. В главе 26 Вы увидите, что действи­тельно иногда это необходимо сделать. Для того чтобы сменить значение базовых век­торов, необходимо провести инициализацию контроллера. Не вдаваясь в подробнос­ти, рассмотрим алгоритм такой инициализации.

1. Послать в порт 20Н (АОН для второго контроллера) число ПН (для АТ).

2. Послать значение базового вектора в порт2Ш (АШдля второго контроллера).

3. Послать слово, определяющее, к какому входу ведущего контроллера подсое­динен контроллер ведомый. Обычно это вход 2. Биту 2 соответствует число 4, которое посылается в порт2Ш (и в А1Н).

4. Послать в порт21Н (в А1Н) число I.

Этот алгоритм будет использован в дальнейшем в главе 26. Подведем некоторый итог:

1. Сигнал прерывания от внешнего устройства попадает вначале в контроллер пре­рываний, который, как хороший секретарь, пропускает сигналы к микропро­цессору по очереди и по приоритетам.

2. Номер пришедшего прерывания посредством базового вектора определяет век­тор прерывания, а следовательно, и вызываемую процедуру. Базовый вектор может быть изменен.

3. Существует три уровня запрета прерываний:

а) на уровне микропроцессора (СЫ),

б) на уровне контроллера прерываний (см. выше),

в) на уровне конкретного устройства - запретить вырабатывать сигналы пре-рьгваний.

V.

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

Номер Назначение_

~~0        Происходит при возникновении ошибки «переполнение при

делении»25. Чтобы это не происходило, можно перехватить его и направить на IRET. Более правильно будет включить его в алгоритм деления (см. [3]), а также программу ниже (Рис. 9.5).

1 После установки бита трассировки микропроцессор выполняетего

после каждой команды. Перехватывается различными отладчиками. Если Вы захотите выяснить первоначальное значение какого-либо вектора, без перехвата прерывания 1 не обойтись.

5 Вектор процедуры печати экрана. Вызывается из

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

8 В нормальном состоянии вызывается 18.2раз в секунду. Одна из задач этого прерывания - поддерживать правильный ход системных часов. Часто перехватывается различными программами для выполнения фоновых задач. Вызывает пользовательское прерывание 1СН. Выключает мотор дисководов, если в течение двух секунд к дисководу не было обращения.

9 Прерывание клавиатуры. Резидентными программами используется

для взведения флага вызова. Можно перехватить для распознавания нажатия таких клавиш, как Shift, Alt, Ctrl, CapsLock и т.д.

OCH     Прерывание, вызываемое при совершении события в порте СОМ 1. Перехватывается в различных коммуникационных программах.

ОВН     Прерывание, вызываемое при совершении события в порте COM2. Аналогично предыдущему.

Прерывание принтера. Вызывается, когда принтер готов к выполнению очередной операции. Используется редко, так какие все адаптеры его поддерживают.

ЮН      Данный вектор обычно перехватываютдрайверы экрана для

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

ПН      Определение набора подключенного оборудования (ненадежно).

13Н    Дисковые операции. Перехватываются некоторыми резидентными программами для контроля над операциями ввода-вывода.

14Н     Функция обслуживания порта асинхронной связи.

35   Для микропроцессоров 8086/8088 программа не прерывалась, а после сообщения продолжа­ла выполняться следующая инструкция.

15Н

Расширенный АТ-сервис (см. главу 5)

16Н

Процедуры обслуживания клавиатуры. Иногда вместо вектора 9

 

удобнее и безопаснее работать с этим.

17Н

Процедура вывода на печатающее устройство. Перехватывается

 

различными резидентными драйверами печати. Особенно часто это

 

приходится делать в случае несовпадения кодировки принтера и

 

компьютера.

18Н

В некоторых компьютерах при вызове этого прерывания запускается

 

кассетный Бейсик.

19Н

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

1 АН

Функции таймера и часов реального времени.

1ВН

Прерывание вызывается при нажатии Control_Break.

1СН

Пользовательское прерывание таймера. Вызывается из 8-го. Не

 

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

 

фоновых задач: фоновая музыка, часы, активизация резидентных

 

программ и т.д.

21Н

Функции DOS. Перехватывается резидентными программами для

 

реализации их безопасного вызова. Перехватывается различными

 

антивирусными мониторами.

23Н

Выход по Ctrl Break. О перехвате его мы говорили в главе 7.

24Н

Критическая ошибка. Перехватывается для собственной обработки

 

критических ошибок.

25Н-26Н

Процедуры DOS прямой записи-чтения диска. Перехватываются для

 

контроля над обращением к диску.

27Н

Процедура "Остатьсярезидентным". Перехватывается различными

 

антивирусными мониторами.

28Н

Недокументированное прерывание. Используется для безопасного

 

вызова резидентных программ.

2FH

прерывание. Специально используется резидентными

 

программами для "общения" друг с другом. Первоначально

 

предполагалось для использования утилитой MS DOS

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

Наиболее часто такой подход используется при работе Є последовательным пор­том. Это и работа с мышью, и модемная связь, и связь между компьютерами непосред­ственно через порт (нуль-модем) и т.д. Посылка данных на принтер по прерыванию также возможна. К сожалению, не все адаптеры параллельного порта способны рабо­тать по прерыванию, поэтому такой подход используется довольно редко. Для органи­зации фоновой печати применяется другой метод. Опрос параллельного порта осуще­ствляет процедура, вызываемая прерыванием по времени (вектора (Шили 1СН). Кста­ти, именно таким образом работает известная DOS'c-вская утилита PRINT.EXE.

Ниже схематично показана процедура передачи данных на печатающее устрой­ство по прерыванию.

INT_PRINT PROC

{сохранить все используемые регистры}

MOV  DS,SEG BUF ; DS на сегмент,   где находится буфер

CMP LEN_BUF, 0 ;не пуст ли буфер

JZ QUIT

CALL OUTPUT ; вывод символа,   если ошибка,   то флаг С

;взведен

JC QUIT

CALL MOV POLNT    ,-переместить указатель  в буфере на

символ

QUIT:

{восстановить регистры} IRET

INT_PRINT ENDP

Данную схему следует дополнить некоторыми пояснениями. В частности, это ка­сается устройства буфера. Часто для этой цели используют кольцевой буфер, наподо­бие клавиатурного (см. главу 7). Возможен и другой вариант. Его можно назвать буфе­ром с фиксированным началом. Состояние буфера определяет его длина. При этом символы поступают туда по принципу стека. Длина буфера показывает смещение пос­леднего положенного туда символа. Символы берутся с начала (смещение 0). После каждого считывания все символы сдвигаются к началу, и длина буфера уменьшается на единицу. Добавлю также, что, для того чтобы готовность принтера генерировала прерывание, следует установить        в регистре управления принтера (см. главу 7).

VI.

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

DATA SEGMENT

; старый вектор прерываний от адаптера асинхронной связи OLD_VEC_OFF DW ? OLD_VEC_SEG DW ?

STR DB 0,0,0,13,10/ '$' ;строка для вывода содержимого порта DATA ENDS

ST1   SEGMENT STACK DB  200 DUP(?)

ST1 ENDS CODE SEGMENT

ASSUME CSrCODE,   DS:DATA, SS:ST1

beg:

начальный блок MOV AX,DATA MOV DS,AX

MOV

MOV SS,AX

;установка вектора прерываний MOV AX, 0 MOV ES,AX

MOV BX,WORD  PTR ES: [0CH*4]

MOV  DS:OLD_VEC_OFF,BX

MOV BX,WORD PTR ES:[0CH*4+2]

MOV CLI

LEA BX,CS:INT_AD MOV ES:[0CH*4J ,BX

PUSH CS POP BX

MOV  ES:[0CH*4+2],BX /разрешить все прерывания,   в том числе и от СОМ-порта MOV AL, 0

OUT 21H,AL

/инициализация адаптера  асинхронной связи MOV   DX,ES:[400H]     ;ПОрт СОМ1. ADD DX,3

IN AL.DX

AND AL,01111111B

OUT  DX,AL       ;на всякий  случай  сбросить   7-й бит SUB DX,2 MOV AL,1

OUT DX,AL /разрешить прерывания по получению данных STI

;ждем нажатия клавиши MOV АН,О

INT 16H

; восстановим вектор и запретим прерывание  от СОМ1 CLI

MOV  BX,DS:OLD_VEC_OFF

MOV WORD  PTR ES: [0CH*4],BX

MOV  BX,DS:OLD_VEC_SEG

MOV WORD  PTR ES:   [0CH*4+2j,BX MOV AL,0 OUT  DX,AL

STI

;выход в DOS

MOV АН,4CH

INT 21H

прерывания INT_ AD     PROC FAR PUSH DS PUSH AX PUSH DX PUSH ES

MOV    AX, SEG STR

MOV    DS, AX

MOV    AX, 0

MOV    ES, AX

MOV    DX,ES: [40OH]

IN      AL,DX     ; содержимое регистра данных CALL WRI_BYTE ;магическая последовательность MOV AL,2 0H OUT 20H,AL

/восстанавливаем регистры микропроцессора

POP ES

POP DX

POP AX

POP DS

I RET INT ' AD ENDPвывода байта в десятичном виде WRI_BYTE PROC

PUSH AX

PUSH DX

; вначале преобразование   числа   в   строку ASCII XOR АН,АН MOV  DL, 10 ' DIV DL

что  DS указывает на   сегмент данных ;если не  так,   то  следует  об  этом позаботиться ADD АН,48 MOV DS:STR+2,AH XOR АН,АН

DIV DL

ADD AL,48 ADD АН,48

MOV DS:STR,AL

MOV

печать

LEA

MOV AH, 9

INT 21H

строки   для   следующего вывода MOV BYTE  PTR DS:STR,0 MOV  BYTE   PTR DS:STR+1,0 MOV BYTE   PTR DS:STR+2,0

POP DX POP AX RET

WRI_BYTE ENDP

CODE ENDS END BEG

Рис. 9.4. Простая иллюстрация взаимодействия с СОМ-портомпо прерыванию.

Рассмотрим программу на Рис. 9.3 относительно работы с СОМ-портом. Обращаю Ваше внимание, что вектор прерывания ОСН взят потому, что программа работает с портом СОМ 1. Если бы надо было работать с портом COM2, то потребовался бы вектор ОВН. Аналогично следует сказать об адресе портов. Базовый адрес порта СОМ 1 нахо­дится в памяти по адресу 0:400Н, COM2 - 0:402Н. По базовому адресу находится ре­гистр приема и передачи данных. Увеличив базовый адрес на единицу, мы получим ад­рес для регистра прерываний. Биты в этом регистре определяют, какие прерывания от адаптера будут разрешены. Мы разрешаем прерывание по получению данных (битО). Наконец, если мы увеличим базовый адресна 3,то получим адрес для регистра управле­ния. Наличие в этом регистре седьмого бита говорит о том, что два первых регистрабудут использоваться для задания скорости передачи данных. Поэтому мы сбрасываем этотбит, т.к. первые два регистра используются для других целей (см. выше).

VII.

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

вводятся в шестнадцатеричном виде. Данной программой следует заинтересоваться

по следующим причинам:

а) Приводиться пример преобразования чисел из ASCII-формата вдвоичный фор­мат и обратно посредством специальных таблиц и команды XLAT

б) Перехватывается прерывание 0: если ввести нулевой делитель, то появится со­общение о недопустимости деления на 0 и произойдет выход из программы

DATA SEGMENT

; таблицы перевода ;ASCII :> байт ТАВ1     DB  48 DUP(O) DB 0,1,2,3,4,5,6,7,8,9 DB 7 DUP(O) DB 10,11,12,13,14,15 DB  26 DUP(O) DB 10,11,12,13,14,15

DB 153 DUP(O)

;байт -> ASCII

TAB2     DB   '0123456789ABCDEF'

для  ввода  строки в   4 байта MAX        DB  5   ; 4   байта строки + байт возврат каретки (0DH) DB ?

STROKA DB   4 DUP(?) DB ?

MES       DB   'Деление на нуль недопустимо!', 13,10,'$ '

хранится  старое   значение   вектора О OLD_INT_OF    DW ?

OLD_INT_SEG DW ?

DATA ENDS

ST1 SEGMENT STACK

DW 50 DUP(?)

ST1 ENDS

CODE SEGMENT

ASSUME CSrCODE,   DS:DATA, SS:ST1

/новая  процедура  прерывания,    вызываемая   при делении  на О

INT_0 PROC

о   недопустимости   нулевого делителя LEA DX,MES

MOV   АН, 9 INT 21Н

вектор О

POP ES

mov AX,OLD_INT_SEG mov    ES:[2],AX mov AX,OLD_INT_OF mov    ES:[0],AX

из  программы с  кодом ошибки mov AX,4C01H

INT 21H INT_0 ENDP

BEGIN:

MOV

mov DS,AX

векторов xor AX,AX mov ES,AX

PUSH ES

сохраним старое  значение вектора mov AX,ES:[0] mov OLD_INT_OF,AX mov AX,ES:[2] mov  OLD_INT_SEG, AX

PUSH CS

pop    AX ■

;теперь установим новый вектор,   направив его на нашу процедуру mov    ES : [2] , АХ lea AX,CS:INT_0 mov   ES:[0],AX

числа  с клавиатуры lea SI,STROKA

строку нулями call CLEARjSTR lea DX,MAX mov AH,OAH ввод

INT 21H

mov BL,MAX+1

строки  в число

call SHIF

CALL STR_NUM

строку нулями

CALL CLEAR STR

PUSH AX

CALL ENT ;ввести делитель

LEA DX,MAX

MOV AH,OAH

INT 21H

MOV BL,MAX+1 ;преобразование строки в число

CALL SHIF

CALL STR_NUM

LEA SI,STROKA

MOV BX,AX

POP AX

XOR    DX, DX ;разделить

DIV BX

PUSH DX CALL ENT

CALL NUM_STR

/вывод результата деления

CALL PRINT_STR

POP AX

CALL NUM_STR остатка

CALL PRINT_STR /восстановить вектор О

POP ES

MOV    AX,OLD_INT_SEG MOV    ES:[2],AX MOV    AX,OLD_INT_OF MOV    ES: [0] , AX

_END:

MOV AX,4C00H

INT 21H /область процедур /преобразует 2  байта <1б-ричные)

/вход -  DS:SI   - строка /выход   АХ - число STR_NUM PROC

PUSH SI

ADD SI,3 MOV CX,2

LOO:

XOR

в

число

MOV

AL, [SI]

LEA

BX,TAB1

XLATB

MOV

DI, AX

MOV

AL, [SI]-1

LEA

BX,TAB1

XLATB

MOV

DL, 16

MUL

DL

ADD

AX, DI

PUSH AX

SUB

SI, 2

LOOP LOO

POP

AX

MOV

CL, 8

SHL

AX,CL

POP

BX

ADD

AX,BX

POP

SI

RETN

STR_NUM

ENDP

/преобразует число  в строку ;число находится в АХ ;на строку указывает DS:SI NUM_STR PROC

PUSH AX

MOV CL,8

SHR AX,CL

MOV BL,16

DIV BL

LEA BX,TAB2

XLATB

MOV [SI],AL MOV AL,AH LEA BX,TAB2

XLATB

MOV

POP AX

AND AX,00FFH MOV BL,16

DIV BL LEA BX,TAB2

XLATB

MOV [SI]+2,AL

LEA BX,TAB2

XLATB

MOV [SI+3] ,AL

RETN

NUM_STR ENDP

строки

ENT PROC

PUSH AX PUSH DX

MOV DL,13 MOV AH,2

INT 21H

MOV DL,10 MOV AH,2

INT 21H POP DX POP AX RETN ENT ENDP

строки символом ;DS:SI - на строку

CLEAR_STR PROC PUSH SI PUSH AX

MOV   CX, 4

L002 :

MOV BYTE PTR INC SI LOOP L002 POP AX POP SI RETN CLEAR_STR ENDP

строки BL длина строки

-  адрес строки /преобразование типа  78   -> 0078 SHIF PROC

CMP BL,0

JNZ NO_ZER RETN NO_ZER:

PUSH SI

XOR

MOV DI,SI

ADD   DI, 3 LOOl:

MOV

MOV BYTE   PTR    [SI][BX]-1,10'

MOV [DI],AL

DEC DI

DEC BX

JNZ L001

POP SI RETN

SHIF ENDP

строки - на строку

PRINT_STR PROC

MOV CX, 4

MOV AH,2 L004:

MOV    DL, [SI]

INT 21H INC SI

LOOP  LOO4

CALL ENT

RETN PRINT_STR ENDP CODE ENDS

END BEGIN

Рис. 9.5. Программа деления нацело четырехзначных чисел, представленных в

шестнадцатеричном виде.

После того, как Вы познакомились с текстом программы и проверили, как она работает, прочтите и пояснения к ней.

1. В программе заменяется стандартный обработчик деления на 0 (вектор 0) на нашу процедуру. При нулевом делителе появляется сообщение о недопустимости де­ления на 0. Прямо из этой процедуры мы выходим в операционную систему. Для такой программы это естественно, но есть и проблема. Дело в том, что если для компьюте­ров на базе микропроцессоров 8088/8086 в стек помещался адрес следующей коман­ды (следующей за ОГУ или ГОГУ), то для следующих поколений микропроцессоров в стек помещается адрес самой команды деления. Ставить в конце процедуры обработ­ки команду ЖЕТбыло бы бессмысленно: возник бы бесконечный цикл вызова проце­дуры. Мы пошли по самому простому пути и сразу передаем управление операцион­ной системе. Более сложные пути должны предполагать переходы из процедуры в те или иные точки программы (с освобождением стека, естественно).

2. Структура, начинающаяся со слова МАХ, служит и для ввода строк и для их вывода (см. функция DOS ОАН). Процедуры CLEAR_STRh SHIF служат для пред­ставления вводимых чисел в удобном для преобразования виде. Первая заполняет стро­ку символами '0', а вторая осуществляет преобразования типа 123 -> 0123,2->0002 и т.п. Процедуры STR_NUM и NUM_STR осуществляют преобразования строки в чис­ло и обратно.

3. Замечу в заключение, что данная программа является прекрасной иллюстраци­ей использование такой команды как, XLAT.

VIII.

В Приложении 9, в разделе, посвященном таймеру, приведена программа с проце­дурой, осуществляющей задержку во времени. Задержки в программах применяются довольно часто. Как правило, для этой цели используют какой-либо циклический ал­горитм. Однакотакаязадержкаявляетсямашинно-зависимой. В Приложении 9 про­грамма работает правильно независимо от производительности процессора. Алгоритм основан на непрерывном опросе таймера. Здесь предлагается другой вариант проце­дуры задержки с использованием прерывания 1СН.

CODE SEGMENT

ASSUME CS:CODE, DS:CODE

ORG 100H BEGIN:

MOV AH,9

LEA DX,TEXT1

INT 21H ;количество секунд задержки

MOV CX,10

CALL TIME

MOV AH, 9 LEA DX,TEXT2

INT 21H RET

TIME PROC

/установить  вектор прерывания

XOR AX,AX

MOV ES,AX /вначале сохранить   старый вектор

MOV AX,ES:[1CH*4]

MOV   INTOFF,AX

MOV AX,ES:[1СН*4+2]

MOV  INTSEG,AX

/теперь установить   новый   вектор '   .   , ;

CLI

LEA АХ,INT1C

MOV ES: [1СН*4] ,АХ

PUSH CS POP AX

MOV ES : [ 1СН*4+2 ], AX ;установить счетчики MOV COUNT,CX MOV AH,2CH

INT 21H MOV SEC,DH STI

;цикл проверки счетчика LOO:

CMP CS:COUNT, 0

JNZ LOO ;продолжить,   если счетчик не нулевой

вектор

CLI

MOV    АХ,INTOFF

MOV    ES:[1СН*4],АХ

MOV    АХ,INTSEG

MOV    ES:[1СН*4+2],АХ

STI

RETN TIME ENDP INT1C PROC

MOV AH,2CH

INT 21H

CMP CS:SEC,DH

JZ CONT

DEC    CS:COUNT

MOV CS:SEC,DH CONT:

IRET

INT1C ENDP

;хранится количество   секунд  текущего времени SEC DB ?

; счетчик интервала

COUNT DW ?

ТЕХТ1 DB   'Ждите ..  10 С.',13,10, '$' TEXT2   DB    'Конец',13,10,'$' ■

INTSEG DW ? INTOFF DW ?

CODE ENDS

END BEGIN

Puc. 9.6. Демонстрация процедуры задержки.

Принцип работы программы, приведенной на Рис. 9.6, следующий: процедура, вызываемая через прерывание 1СН, приблизительно 18 раз в секунду проверяет, не изменилось ли значение секунд системных часов. Если значение изменилось, то счет­чик секунд уменьшается. Параллельно этому ведется непрерывный опрос счетчика секунд. Выход из цикла происходит, когда счетчик становится равным нулю. Особо отметьте, что весь алгоритм построен на том факте, что длительность всех выполняе­мых команд намного меньше секунды. В противном случае нам пришлось бы прове­рять, на сколько секунд изменился показатель системныхчасов.

IX.

Как я и обещал, возвратимся снова к проблеме обработки критической ошибки, т.е. к прерыванию 24Н.

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

DATA SEGMENT

PATH DB "A:\FILE", 0      ;имя открываемого файла HANDLE DW ? ;описатель открытого файла HANDLE DW ?

ТЕХТ1   DB   "Жду  нажатия  клавиши",13,10,"$" ТЕХТ2  DB  "Файл создан",13,10,"$" ТЕХТЗ   DB   "Произошла ошибка",13,10,"$"

DATA ENDS STA   SEGMENT STACK DB   500 DUP(0)

STA ENDS CODE SEGMENT

ASSUME CS:CODE,   DS:DATA, SS:STA

BEGIN:

MOV AX,DATA

MOV DS,AX /переустановить вектор 24Н

MOV AX,0

MOV ES,AX

LEA AX,CS:INT24

MOV  ES: [24H*4] ,AX

MOV ES: [24H*4+2] , CS

INP:

LEA DX,TEXT1

CALL TEXTOUT

CALL   INPUT ;ждем нажатие клавиши

CMP AL,27 ; проверка на нажатие ESC

JZ END ;открыть файл

MOV АХ,ЗС00Н LEA  DX,PATH MOV СХ, О INT 21H JNC DAL2 LEA DX,TEXT3 CALL TEXTOUT

JMP SHORT INP ;повторить операцию открытия

DAL2 :

MOV DS:HANDLE,AX /записать в файл

LEA DX,TEXT2

CALL TEXTOUT INP1:

LEA DX,TEXT1

CALL TEXTOUT

.     CALL INPUT LEA DX,TEXT2 /производим операцию записи MOV  BX,DS:HANDLE MOV CX,11 MOV AX,4000H INT 21H JNC DAL1 LEA  DX,TEXT3

CALL TEXTOUT

JMP  SHORT   INP1 /повторить операцию записи

DAL1:

/закрыть файл INP2:

LEA  DX,TEXT1 .

CALL TEXTOUT

MOV BX,HANDLE MOV АН,3EH

INT 21H JNC _END LEA DX,TEXT3

CALL TEXTOUT

JMP SHORT  INP1 /повторить операцию закрытия

_END:

MOV AX,4C00H

INT

INPUT PROC .   ,, MOV 'AH, 0. INT 16H

RET

INPUT: ENDP

прерывания 24Н

INT24 PROC

MOV AL,1 IRET

INT24 ENDP

;вывод текстовой строки

TEXTOUT PROC

MOV АН,9

INT 21H RET

TEXTOUT ENDP CODE ENDS

END BEGIN

Рис. 9,7. Обработка критических ошибок.

Главное, что Вы должны для себя уяснить, работая с данной программой, это то, как обрабатываются операции открытия файла, записи в файл и закрытия файла в слу­чае возникновения критической ошибки. В нашем случае AL=1 и все операции обра­батываются одинаково, т.е. повторяются до тех пор, пока не перестанет происходить ошибка. При других значениях AL операции обрабатываются по-разному. Вы это про­верите сами, замечу только, что логика разработчиков вполне понятна. Если, к приме­ру, не удалось открыть файл, то ситуация вполне однозначна: данные не сохранены или не прочитаны. Если же не удалось записать данные, то здесь возникает некоторая неопределенность: не ясно, что с файлом. Так что разработчиков понять можно.

С версии 4.0 MS DOS, однако, появилась функция 6СН, позволяющая открывать файлы так, что критическая ошибка не вызывает прерывание. О наличии любой ошибки можно, естественно, судить по флагу переноса. Расширенный код ошибки получается, как и обычно, через функцию 59Н. Остается открытым вопрос: зачем вообще нужно

было выделять таким образом критическую ошибку?

В заключение замечу, что при входе в процедуру обработки критической ошибки

стек содержит всю нужную информацию, чтобы самостоятельно можно было обрабо­тать возникшую ситуацию. Вот структура стека:

1. Адрес возврата в MS DOS (3 слова: IP,CS,Flags). Выполняя IRET, мы как раз используем эти данные.

2. Значения регистров перед вызовом int 21Н: AX,BX,CX,DX,SI,DI,BP,DS,ES.

3. Адрес возврата к команде int 21Н в ' вашей программе (3 ' слова: IP,CS,Flags).

X. Перехват прерываний.

В этом разделе будет представлен модуль, который может быть использован как в программах наязыке ассемблера, таки наязыках высокого уровня. Вызов процедуры INIKB должен производиться в начале программы. Перед выходом из программы должна быть вызвана процедура REKB. После выполнения процедуры INI_KB пере­стают работать клавиши PAUSE, PRTSC, сочетания клавиш Ctrl Break, Ctrl С, Ctrl Alt Del. Все остальное работает по-прежнему. Блокирование клавиш производится неза­висимо оттого, какие функции выполняетпрограмма.

CODE SEGMENT

ASSUME   CS:CODE PUBLIC   INI_KB, RE_KB ; старые векторы INT_05O DW ? INT_05S DW ? INT_1BO   DW ? INT_1BS  DW ? INT_09O DW ? INT_09S DW ?

;новые  процедуры   обработки прерываний

/-обработка Prtsc _05 PROC IRET _05 ENDP

/-обработка Ctrl Break _1B PROC

IRET

_1В ENDP SCAN DB ?

/ -обработка клавиатурного прерывания PROC

PUSH AX

IN    AL,60H

MOV CS:SCAN,AL

PUSH ES XOR

MOV ES,AX /обработка Ctrl Alt Del

TEST BYTE PTR ES: [417H], 00000100B

JZ PROD

TEST BYTE PTR ES :   {417H], 00001000B

JZ PROD

AND BYTE PTR 11110111B POP ES

JMP    ТО  INT 9

PROD:

;обработка Ctrl С

CMP CS:SCAN, 46

JNZ PRODI

TEST BYTE   PTR ES:  [417H], 00000100B

JZ PRODI POP ES

JMP SHORT EMUL

PRODI:

POP ES

TO_INT9:

PUSHF

CALL  DWORD   PTR CS:INT_09O

PUSH ES

XOR AX,AX MOV ES,AX

клавишу PAUSE AND    BYTE  PTR ES :  [ 418H] , 1111011 IB

POP ES

POP AX

IRET

EMUL:

IN

MOV AH,AL

OR AL,80H OUT 61H,AL MOV AL,AH OUT 61H,AL MOV AL,20H OUT 20H,AL

POP AX IRET

09 ENDP

обработку

INI_KB  PROC FAR

PUSH AX PUSH ES

XOR    AX, AX

MOV ES,AX

MOV AX,ES:[05H*4]

MOV CS:INT_05O,AX

MOV AX,ES: [05H*4+2]

MOV CS:INT_05S,AX

LEA AX,CS:_05

MOV ES: [05H*4] ,AX

MOV ES: [05HM+2J , CS

MOV AX,ES:[1BH*4]

MOV CS : INTJLBO, AX

MOV AX,ES:[1ВН*4+2]

MOV CS: INT_1BS, AX

LEA AX,CS:_1B

MOV ES : [1BH*4] , AX

MOV ES:[1ВН*4+2],CS

I

MOV AX,ES:[09H*4]

MOV CS:INT_0 90,AX

MOV AX,ES:[09H*4+2]

MOV CS : INTM)9S, AX

LEA AX,CS:_09

MOV ES:[09H*4],AX MOV

POP ES

POP AX STI

RETF INI_KB ENDP

;восстановить обработку RE_KB  PROC FAR CLI

PUSH AX

PUSH AX

XOR AX,AX

MOV ES,AX /восстанавливаем векторы прерываний MOV

MOV ES : [05H*4 ], AX

MOV AX,CS:INT_05S

MOV ES:[05H*4+2],AX

MOV AX,CS:INT_1B0

MOV ES: [1BH*4] ,AX

mov ax,cs:int_1bs mov   es:[1вн*4+2],ax

MOV    ax,cs:int_0 90 MOV    ES: [09h*4],ax MOV    ax,cs:int_09s MOV    es: [09h*4+2],ax

POP AX POP AX sti

RETF RE_KB ENDP CODE ENDS

END

Puc. 9.8. Пример обработки прерываний.