7.3. Составление процедуры обработки прерывания

Обработка прерываний в реальном режиме производится в три этапа:

1) прекращается выполнение текущей программы;

2) запоминаются в стек FL, затем CS и IP, очищается флаг IF и осуществляется передача управления по адресу из таблицы векторов прерываний;

3) выполняется процедура обработки прерываний, и с помощью команды IRET возвращается управление прерванной программе. Команда IRET восстанавливает содержимое регистров IP, CS и FL.

Команда int n производит следующие действия:

push FL;

push CS;

push IP;

очищает бит IF;

передает в IP содержимое слова, имеющего адрес 4n;

передает в CS содержимое слова, имеющего адрес 4n+2.

Команда into генерирует прерывание 4, если флаг OF=1, в противном случае никаких действий не выполняет.

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

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

Пример 1. Напишем программу, вызывающую собственную процедуру обработки прерывания, состоящую из единственной команды nop:

< 1 > title     uintr

< 2 > code     segment

< 3 > assume    cs:code, ds:code

< 4 > vect     equ   3fch

< 5 >

< 6 > main     proc

< 7 > mov       ax,0

< 8 > mov       es,ax      ;очистить es

< 9 > mov       es:[vect+0], offset user

< 10 > mov       es:[vect+2], cs

< 11 > int       vect/4     ;вызов прерывания

< 12 > mov       ah,0       ;ожидание

< 13 > int       16h

mov   ax,4c00h

< 1 >

< 2 > int       21h

< 3 > main     endp

< 4 >

< 5 > user     proc  far   ;адрес из 4 байт

< 6 > nop

< 7 > iret

< 8 > user     endp

< 9 > code     ends

< 10 > end       main

Более естественным является оставить собственную подпрограмму обработки прерывания резидентной. Такая подпрограмма называется драйвером. Это делается с помощью прерывания 27h.

Пример 2. Напишем подпрограмму обработки прерывания 1Ch, генерируемого при каждом тиканьи часов. Наша процедура будет выводить на экран после каждых 100 тиканий двоичное значение счетчика, заданного в регистре bx.

< 1 > title     udriv.com

< 2 > code     segment

< 3 > org       100h

< 4 > assume    cs:code, ds:code, ss:code

< 5 > begin:

< 6 > jmp       setdrv

< 7 > drv      proc  far

< 8 > push      ax

< 9 > push      bx

< 10 > push      cx

< 11 > push      dx

< 12 > push      si

< 13 > push      di

< 14 > push      es

< 15 > push      ds

< 16 > push      cs

< 17 > pop       ds

< 18 > mov    ax,count

< 19 > inc       ax

< 20 > mov       count,ax

< 21 > cmp       ax,10      ;если нет

< 22 > jb enddrv ;10 тиков

< 23 > mov       ax,0

< 24 > mov       count,ax

< 25 > mov       bx,number

< 26 > inc       bx

< 27 > mov       number,bx

< 28 > mov       ax,0b800h

< 29 > mov       es,ax

< 30 > mov       di,0       ;cs:[di] — начало экрана

< 31 > mov       cx,16

< 32 > lp1:

< 33 > mov       al,’0′

< 34 > shl       bx,1

< 35 > jnc       lp2

< 36 > inc       al

< 37 > lp2:

< 38 > stosb                ;al->es:[di]

< 39 > mov       al,7       ;атрибут

< 40 > stosb

< 41 > loop      lp1

< 42 > enddrv:

< 43 > pop       ds

< 44 > pop       es

< 45 > pop       di

< 46 > pop       si

< 47 > pop       dx

< 48 > pop       cx

< 49 > pop       bx

< 50 > pop       ax

iret

< 1 >

< 2 > count    dw    0

< 3 > number   dw 0

< 4 > finish   equ $ ;отметка конца процедуры

< 5 > drv      endp

< 6 > setdrv:

< 7 > mov       dx,offset drv

< 8 > mov       al,1Ch     ;номер прерывания

< 9 > mov       ah,25h     ;функция установки вектора

< 10 > int       21h

< 11 > lea       dx,finish  ;оставить процедуру

< 12 > int       27h        ;в памяти

< 13 > ret                  ;выход

< 14 > code     ends

< 15 > end       begin