Обработчики аппаратных прерываний. Обработчики программных прерываний.
Рассмотрим структуру программы с обработкой аппаратных прерываний. Наиболее удобным аппаратным прерыванием, которое можно использовать в исследовательских целях, является прерывание от системного таймера, которое генерируется 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) – сегментный адрес.