Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
31
Добавлен:
20.06.2014
Размер:
262.14 Кб
Скачать

2. Резидентный обработчик прерываний от клавиатуры с подключением до системного обработчика.

Чаще всего резидентная программа запускается по заданной клавише. То есть с помощью прерывания от клавиатуры IRQ1 с вектором 09. Однако, в этом случае надо, чтобы кроме нашей программы, выполнялось и стандартное прерывание обработки кодов клавиатуры. Это наиболее сложный способ. Здесь надо сначала получить адрес старого вектора прерывания с помощью:

Int 21,35 - получить адрес вектора прерывания

AL - номер прерывания

Результат:

ES:BX - адрес прерывающей программы

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

После этого выполнить нашу резидентную программу можнотремя способами:

- выполнить собственный обработчик прерывания до системного;

- выполнить собственный обработчик прерывания после системного;

- выполнить часть обработчика прерывания до и часть после системного.

Рассмотрим сначала первый способ:

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

Пример 2

Создадим резидентную программу с вызовом по клавише со скан-кодом 29h (обр.апостроф).

При вызове программа выводит цветной символ в последнюю

позицию экрана и меняет цвет символа при каждом новом вызове.

Seg1 SEGMENT

ASSUME SS:Seg1,DS:Seg1,CS:Seg1,ES:Seg1

ORG 100h ;Начало программы с 0100h

Pr: JMP M1 ;Пропускаем резидентную часть

;--------------------- Резидентная часть

old_09 dd 0 ;Старый адрес Int 09h

sym1 dw 421Eh ;1-й выводимый символ

sym2 dw 241Eh ;2-й выводимый символ

;---------------------

M2: push AX ;Сохраним те регистры, содержимое

push ES ;которых меняется в программе

in AL,60h ;Ввод кода нажатой кл.из рег.60h

cmp AL,29h ;Анализ кода нажатой кл.

jnz M3 ;Переход, если скан-код не 29h

mov AX,0B800h ;В рег.ES засылаем cегментный

mov ES,AX ;адрес буфера экрана B800

mov AX,CS:sym1 ;¬

xchg AX,CS:sym2 ;¦Oбмен местами sym1 - sym2

mov CS:sym1,AX ;-

mov ES:3998,AX ;Вывод в посл.поз.экрана 3998

M3: pop ES ;Восстановим содержимое

pop AX ;регистров ES и AX

jmp CS:old_09 ;передать управление на системный

; обработчик прерываний

M1: ;---------------------- ;Инициирующая часть

mov AX,3509h ;Получить старый адрес в ES:BX

INT 21h ;обработчика прерывания int 09h

mov word ptr CS:old_09,BX ;и запомнить ES:BX

mov word ptr CS:old_09+2,ES ;в ячейке old_09

mov AX,2509h ;Установка нового адреса <адр.M2>

lea DX,M2 ;обработчика прерывания int 09h

INT 21h ; -------

mov AH,09h ;Вывод строки:

lea DX,x ;'Резидентный обработчик загружен$'

INT 21h ; -------

mov AX,3100h ;Завершить и оставить pезидентной

mov DX,(M1-Pr+10Fh)/16 ;часть размером (M1-Pr+10Fh)/16

INT 21h ; -------

x db 'Резидентный обработчик загружен$'

Seg1 ENDS ;Конец сегмента

END Pr ;Полный конец программы Pr

Здесь полученный старый адрес обработчика прерывания int 09h запоминается двумя командами вида 'mov word ptr CS:old_09,BX'.

Поскольку переменная 'old_09' типа 'dd'(двойное слово), потребовалось переопределять тип переменной.

Резидентная часть здесь всегда заканчивается переходом на системный обработчик прерывания 09h (команда 'jmp CS:old_09'). Это приводит к тому, что по клавише со скан-кодом 29h(обр.апостроф) программа выводит не только цветной символ в последнюю позицию экрана, но и нормальный символ клавиши. Чтобы этого не происходило, следует по выбранному коду клавиши заканчивать прерывание 09h самостоятельно.

Для этого необходимо:

- в 7 р. регистра 'B' контроллера клавиатуры (адр. 61h) заслать сначала 1, затем 0. Этим мы указываем контроллеру, что обработка кода клавиши закончена;

- в 5 р. регистра контроллера прерываний (адр.20h) заслать единицу, указав тем самым, что обработка прерывания закончена;

- самостоятельно закончить резидентную программу командой IRET.

Такая программа от предыдущей будет отличаться только окончанием резидентной части:

;--------------------- Резидентная часть

old_09 dd 0 ;Старый адрес Int 09h

sym1 dw 421Eh ;1-й выводимый символ

sym2 dw 241Eh ;2-й выводимый символ

;---------------------

M2: push AX ;Сохраним те регистры, содержимое

push ES ;которых меняется в программе

in AL,60h ;Ввод кода нажатой кл.из рег.60h

cmp AL,29h ;Анализ кода нажатой кл.

jz M3 ;Переход, если скан-код = 29h

pop ES ;Восстановим содержимое

pop AX ;регистров ES и AX

jmp CS:old_09

M3: mov AX,0B800h ;В рег.ES засылаем сегментный

mov ES,AX ;адрес буфера экрана B800

mov AX,CS:sym1 ;¬

xchg AX,CS:sym2 ;¦Oбмен местами sym1 - sym2

mov CS:sym1,AX ;-

mov ES:3998,AX ;Вывод в посл.поз.экрана 3998

in AL,61h ;

or AL,80h ;В регистр по адр. 61h

out 61h,AL ;засылаем 1 в 7-й разряд

and AL,7Fh ;В регистр по адр. 61h

out 61h,AL ;засылаем 0 в 7-й разряд

mov AL,20h ;В регистр по адр. 20h

out 20h,AL ;засылаем 1 в 5-й разряд

pop ES ;Восстановим содержимое

pop AX ;регистров ES и AX

iret ;Выход в DOS

Для занесения 1 или 0 в один из разрядов рег. 61h, мы должны сохранить информацию в остальных разрядах этого регистра. Для этого содержимое регистра сначала читается командой 'in AL,61h', затем изменяется содержимое рег. AL и записывается в рег.61h. В регистр по адр. 20h просто заносится число 20h без сохранения предыдущего кода.

Почему выход в DOS осуществляется командой IRET, а не RET уже объяснялось ранее.

Соседние файлы в папке Кр и методичка Разработка резидентной программы в MS DOS