Иллюстрированный самоучитель по Assembler

Обработчики аппаратных прерываний. Обработчики программных прерываний.

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

Будем считать, что наш программный комплекс представляет собой программу типа .ЕХЕ и что обработчик прерываний входит в общий с основной программой программный сегмент. Для определенности будем использовать вектор 08h, хотя, разумеется, для любого другого аппаратного вектора структура программы останется той же. Поначалу приведем текст программы с некоторыми купюрами.

Пример 3.3. Обработчик прерываний от таймера.

code segment
assume CS:code,DS:data
;Главная процедура
main proc
mov AX,data; Инициализация сегментного
mov DS,AX; регистра DS
;Сохраним исходный вектор
mov AH,35h; Функция получения вектора
mov AL,08h; Номер вектора
int 21h
mov word ptr old_08,BX; Смещение исходного обработчика
mov word ptr old_08+2,ES; Сегмент исходного обработчика
;Установим наш обработчик
mov AH,25h; Функция заполнения вектора
mov AL,08h; Номер вектора
mov DX,offset new_08; Смещение нашего обработчика
push DS; Сохраним DS=data
push CS; Перепишем CS в DS
pop DS; через стек. DS:DX › new_08
int 21h
pop DS; Восстановим DS=data
…; Продолжение основной программы
; Перед завершением программы восстановим исходный вектор
Ids DX,old_08; Заполним DS:DX из old_08
mov AH,25h; Функция заполнения вектора
move AL,08h; Номер вектора
int 21h
mov AX,4C00h; Функция завершения программы
int 21h
main endp
;Процедура обработчика прерываний от таймера
new_08 proc
…; Действия. выполняемые 18 раз в секунду
mov AL,20h; Разблокировка прерываний
out 20h,AL; в контроллере прерываний
iret; Возврат в прерванную программу
new_08 endp
code ends
data segment
old_08 db 0; Ячейка для хранения исходного вектора
data ends
stk segment stack
db 256 dup(U)
stk ends
end main

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

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

Хотя и чтение, и заполнение вектора прерываний можно выполнить с помощью простых команд mov, однако предпочтительнее использовать специально предусмотренные для этого функции DOS. Для чтения вектора используется функция с номером 35h. В регистр AL помещается номер вектора. Функция возвращает исходное содержимое вектора в парс регистров ES:BX (легко догадаться, что в ES сегментный адрес, а в ВХ смещение). Для хранения исходного содержимого вектора в сегменте данных предусмотрена двухсловная ячейка old_08. В младшем слове этой ячейки (с фактическим адресом old_08) будет хранится смещение, в старшем (с фактическим адресом old_08+2) – сегментный адрес.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.