В конец страницы

Прерывания

  1. Прерывания пользователя.
  2. Обработчик прерываний от таймера

Прерывания пользователя.

Программы обработки прерываний (или попросту обработчики прерываний) относятся к важнейшим программным средствам персональных компьютеров. Запросы на обработку прерываний могут иметь различную природу. Прежде всего, различают аппаратные прерывания от периферийных устройств или других компонентов системы и программные прерывания, вызываемые командой int, которая используется, в частности, для программного обращения к функциям DOS и BIOS. Сигналы, возбуждающие аппаратные прерывания, могут инициироваться цепями самого процессора, например, при попытке выполнения операции деления на ноль (такие прерывания называются внутренними, или отказами), а могут приходить из периферийного оборудования (внешние прерывания). Внешние аппаратные прерывания вызываются, например, сигналами микросхемы таймера, сигналами от принтера или контроллера диска, нажатием или отпусканием клавиши. Таким образом, можно говорить о прерываниях трех типов: внутренних, внешних и программных. Независимо от источника, действия процессора по обслуживанию поступившего прерывания всегда выполняются одинаково, как для аппаратных, так и для программных прерываний. Эти действия обычно называют процедурой прерывания. Подчеркнем, что здесь идет речь лишь о реакции самого процессора на сигнал прерывания, а не об алгоритмах обработки прерывания, предусматриваемых пользователем в обработчике прерываний.
Объекты вычислительной системы, принимающие участие в процедуре прерывания, и их взаимодействие показаны на рис. 25.1.
Самое начало оперативной памяти от адреса 0000h до 03FFh отводится под векторы прерываний - четырехбайтовые области, в которых хранятся адреса программ обработки прерываний (ПОП). В два старших байта каждого вектора записывается сегментный адрес ПОП, в два младших - относительный адрес точки входа в ПОП в сегменте. Векторы, как и соответствующие им прерывания, имеют номера, причем вектор с номером 0 располагается, начиная с адреса 0, вектор 1 - с адреса 4, вектор 2 - с адреса 8 и т.д. Вектор с номером N занимает, таким образом, байты памяти от N*4 до N*4+3. Всего в выделенной под векторы области памяти помещается 256 векторов.

                          Адреса памяти

рис. 4.1. Процедура прерывания

Получив сигнал на выполнение процедуры прерывания с определенным номером, процессор сохраняет в стеке выполняемой программы текущее содержимое трех регистров процессора: регистра флагов, CS и IP. Два последних числа образуют полный адрес возврата в прерванную программу. Далее процессор загружает CS и IP из соответствующего вектора прерываний, осуществляя тем самым переход на ПОП.
Программа обработки прерывания обычно заканчивается командой возврата из прерывания iret (interrupt return, возврат из прерывания), выполняющей обратные действия - загрузку IP, CS и регистра флагов из стека, что приводит к возврату в основную программу в ту самую точку, где она была прервана.
Большая часть векторов прерываний предназначена для выполнения определенных действий и автоматически заполняется адресами системных программ при загрузке системы;
часть векторов зарезервирована для будущих применений, а часть (конкретно с номерами 60h...66h) свободна и может использоваться в прикладных программах.
Для того чтобы прикладной обработчик получал управление в результате прерывания, его адрес следует поместить в соответствующий вектор прерывания. Хотя содержимое вектора прерываний можно изменить простой командой mov, однако предпочтительнее использовать специально предусмотренную функцию DOS 25h. При вызове функции 25h в регистр AL помещается номер модифицируемого вектора, а в регистры DS:DX - полный двухсловный адрес нового обработчика.
Рассмотрим методику использования в прикладной программе прерывания пользователя.

Пример 4.1. Обработка прерываний пользователя

new_65h proc
                        ;Процедура наложения на экран цветного окна для динамической
                        ;очистки экрана по ходу выполнения программы
mov   АН, 06h           ;Функция задания окна
mov   AL,0              ;Режим создания окна
  mov   BH,1Bh          ;Атрибут всех символов в окне: светло-бирюзовые символы, синий фон
mov   СХ,0              ;Координаты верхнего левого угла 0,0
mov   DH,24             ;Нижняя Х-координата
mov   DL,79             ;Правая Х-координата
int   10h               ;Прерывание BIOS
iret
new_65h   endp
main         proc
mov   AX,data
mov   DS,AX 
                        ;Заполним вектор прерывания пользователя адресом нашего обработчика
mov   АН,25h            ;Функция заполнения вектора прерывания
mov   AL,65h            ;Номер вектора
mov   DX,offset new_65h ;Смещение прикладного обработчика
push DS                 ;Сохранны DS
push CS                 ;Настроим DS на сегмент команд (в
pop DS                  ;котором находится наш обработчик)
int   21h               ;Вызовем DOS
 pop   DS               ;Восстановим DS
                  ;Будем в цикле выводить ил экран строки с предварительной очисткой экрана
gogo:       int   65h   ;Вызов прикладного обработчика (очистка
                        ;экрана перед выводом текста) 
                        ;Позиционируем курсор
mov   АН,02h            ;Функция позиционирования
mov   BH,0              ;Видеостраница
mov   DH,line           ;Строка
mov   DL,coloumn        ;Столбец
int   10h               ;Прерывание BIOS 
                        ;Выведем на экран строку символов
mov  АН,0Ah             ;функция вывода символа без атрибута
mov  AL,sym             ;Символ
mov  BH,0               ;Видеостраница
mov  СХ,60              ;Коэффициент повторения
int   10h               ;Прерывание BIOS 
                        ;Изменим символ и позицию и зациклим программу с возможностью
                        ;завершения по нажатию клавиш /C
inc   sym               ;Следующий символ по таблице ASCII
inc  line               ;Следующая строка экрана
mov   АН,08h            ;Функция ввода баз эха, чувствует /C
int   21h
jmp  gogo               ;Бесконечный цикл 
main endp               ;Поля данных
line db 2               ;Строка 
coloumn db 10	        ;Столбец 
sym db 0lh              ;Выводимый символ

Процедура new_65h, вызываемая с помощью программного прерывания (для которого выбран вектор 65h), выполняет простую операцию - очищает экран, накладывая на него окно с заданным атрибутом.
В основной программе, прежде всего заполняется вектор прерывания 65h. Поскольку функция заполнения вектора 25h требует, чтобы адрес прикладного обработчика содержался в парс регистров DS:DX, a DS у нас указывает на сегмент данных, перед вызовом DOS в DS следует занести сегментный адрес того сегмента, в котором находится обработчик, т.е., в нашем случае, общего сегмента команд. Этот адрес извлекается из CS.
Далее в бесконечном цикле выполняется вызов нашего обработчика, позиционирование курсора с помощью функции 02h BIOS и вывод на чистый экран строки символов (функцией 0Ah BIOS). Эта функция не позволяет задавать атрибуты выводимых символов. Символы приобретают атрибут тех позиций, куда они выводятся, т.е., в нашем случае, атрибут окна. После вывода на экран строки выполняется изменение кода символов и номера строки экрана, куда эти символы выводятся.
Функция DOS 08h (ввод символа без эха), включенная в цикл, выполняет две задачи. Bo-первых, она останавливает выполнение программы и позволяет изучить содержимое экрана в каждом шаге цикла. Для того, чтобы продолжить выполнение программы, достаточно нажать на любую клавишу. Во-вторых, эта функция, будучи чувствительна к вводу с клавиатуры сочетания /C, позволяет завершить программу, которая в противном случае выполнялась бы вечно.

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

Структура обработчика прерываний и его взаимодействие с остальными компонентами программного комплекса определяются рядом факторов, из которых важнейшими являются следующие:
• прерывания, инициализирующие обработчик, могут быть аппаратными (от периферийных устройств) или программными (команда int).
• обработчик может входить в состав прикладной программы или представлять собой самостоятельную единицу. В последнем случае он относится к специальному классу резидентных программ;
• вектор обрабатываемого прерывания может быть свободным и использоваться системой или какой-либо резидентной прикладной программой;
• если вектор уже используется системой, т.е. в составе DOS имеется системный или прикладной разработчик прерываний с данным номером, то новый обработчик может полностью заменять уже загруженный (превращая его тем самым фактически в бесполезную программу) или “сцепляться” с ним;
• в случае сцепления с загруженным ранее обработчиком новый обработчик может выполнять свои функции до уже имеющегося в системе или после него.
В настоящем разделе будут рассмотрены общие вопросы обработки прерываний на примере простого обработчика прерывания 1Ch.
Для того чтобы прикладные программы могли использовать сигналы таймера, не нарушая при этом работу системных часов, в программу BIOS, обслуживающую аппаратные прерывания от таймера, поступающие через вектор 08, включен вызов int 1Ch, передающий управление на программу-заглушку BIOS, которая содержит единственную команду iret (рис. 46.1.). пользователь может записать в вектор 1Ch адрес прикладного обработчика сигналов таймера и использовать в своей программе средства реального времени. Естественно, перед завершением программы следует восстановить старое значение вектора 1Ch.

 Векторы прерываний                              Программа BIOS
                                                 отсчета времени 

Рис. 4.2 Прикладная обработка прерываний от таймера

При рассмотрении методики включения в программу процедур-подпрограмм мы отмечали, что порядок расположения процедур в программе не влияет на ход ее выполнения. Важно лишь так скомпоновать текст программы, чтобы подпрограммы никогда не активизировались “сами по себе”, иначе, чем в результате выполнения команды call в вызывающей программе. Это правило относится и к обработчикам прерываний, включаемым в состав программы. Текст обработчика можно расположить в любом месте программы, обеспечив лишь невозможность случайного перехода на его строки не в результате прерывания, а по ходу выполнения основной программы. Обычно обработчики располагаются либо в начале, либо в конце текста программы. В примере 46.1 текст обработчика идет вслед за текстом основной программы.
Другое замечание относится к оформлению программы обработчика. Так же, как и в случае подпрограмм, обработчик прерывания может образовывать процедуру (что наглядно), но может начинаться просто с метки. Важно лишь, чтобы последней выполняемой командой обработчика была команда iret.

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

text segment 'code'       ;(1)
include mac.mac                ;(2)
assume CS:text;DS:data         ;(3)
main proc                      ;(4)Главная процедура
mov AX,data                    ;(5)Сделаем наши данные
mov DS,AX                      ;(6)адресуемыми 
;Сохраним вектор 1Ch
mov AX,351ch                   ;(7)Функция 35h, вектор 1Ch
int 21h                        ;(8)Вызов DOS
mov word ptr old_lch,BX        ;(9)Сохраним смещение сегментного обработчика
mov word ptr old_lch+2,ES      ;(10)Сохраним сегмент системного обработчика
 ;Заполним вектор 1Ch
mov AX,251Ch                   ;(11)Функция 25h, вектор 1Ch
mov DX,offset new_lch          ;(12)Смещение нашего обработчика
push DS                        ;(13)Сохраним наш DS
push CS                        ;(14)Настроим DS на сегмент обработчика
pop DS                         ;(15)(т.е. на сегмент команд)
int 21h                        ;(16)Вызов DOS
pop DS                         ;(17)Восстановим адресуемость данных 
                    ;Организуем контрольный вывод на экран строк текста в цикле с задержкой
mov СХ,20                      ;(18)Число повторений вывода строк
 wri: write string             ;(19)Макрокоманда вывода на экран
delay 50                       ;(20)Макрокоманда задержки
loop wri                       ;(21) 
                           ;Перед завершением программы восстановим содержимое вектора 1Ch
Ids DX,old_1ch                 ;(22)Отправим в DS:DX сохраненный вектор 1Ch
mov AX,251Ch                   ;(23)Функция 25h, вектор 1Ch
int 21h                        ;(24)Вызов DOS ;Завершим программу обычным образом
outprog                        ;(25)Завершение программы 
main endp                      ;(26)Конец главной процедуры 
new_1ch proc                   ;(27)Процедура нашего обработчика 
                ;Наш обработчик от таймера. Его функция - вывод на экран мигающего символа,
                               ;свидетельствующего об активности программы!
push AX                        ;(28)Сохраним используемые в
push ES                        ;(29)нем регистры
mov AX,OB800h                  ;(30)Настроим ES
mov ES,AX                      ;(31)на видеобуфер
mov AX,CS:syml                 ;(32)Получим символ с атрибутом из ячейки syml
mov ES:3998,AX                 ;(33)Выведем в последнюю позицию экрана
xchg AX,CS:sym2                ;(34)Обменяем содержимое
mov CS:syml,AX                 ;(35)ячеек syml и sym2
pop ES                         ;(36)Восстановим
pop AX                         ;(37)сохраненные регистры
iret                           ;(38)Вывод из прерывания 
                               ;Поля данных обработчика в сегменте команд 
syml dw 421 Eh                 ;(39)Символы с атрибутами 
sym2 dw 241Eh                  ;(40)для вывода на экран
new_lch	endp	               ;(41)Конец процедуры обработчика
text	ends	               ;(42)
data	segment	               ;(43)
old_lch	dd 0	               ;(44)Двухсловная ячейка для хранения
                               ; исходного вектора
string	db '************0123456789**********',10,13,’$’  ;(45) 
data	ends	               ;(46) 
	end main	       ;(47)

В рассмотренном примере используются макрокоманды из файла mac.mac. Для того, чтобы сделать доступными эти макрокомнда в нашей программе, используем директиву include. Файл mac.mac имеет следующее содержание:

outprog  macro       ;(1)Завершение программы
         mov AX,4C00h     ;(2)		
         int 21h          ;(3)
         endm             ;(4) 
delay_50 macro            ;(5)Задержка
         push CX          ;(6)
         mov CX,100       ;(7)Счетчик внешнего цикла
outer:	 push CX          ;(8)Сохраним его в стеке
	 mov CX,65535     ;(9)Счетчик внутреннего цикла
inner:	 loop inner       ;(10)Повторим команду loop 65535 раз
	 pop CX	          ;(11)Восстановим внешний счетчик
	 loop outer       ;(12)Повторим все это 100 раз
	 pop CX	          ;(13)Восстановим счетчик демо-цикла 
         endm             ;(14)
write_string macro        ;(15)
         mov  AH,09h      ;(16) AH=09h номер функции вывода на экран
         mov  DX,offset string      ;  (17) В DX заносится адрес выводимого сообщения 
         int  21h                   ;  (18) Вызов прерывания MS-DOS
         endm             ;(19)

Главная процедура начинается, как обычно, с инициализации сегментного регистра DS. Перед тем, устанавливать собственный обработчик какого-либо прерывания, следует сохранить его исходный (системный) вектор, чтобы перед завершением программы вернуть систему в исходное состояние. Для получения содержимого вектора 1Ch используется функция DOS 35h, которая возвращает содержимое указанного вектора в регистрах ES:BX. Для сокращения объема исходного текста программы и номер функции, и номер требуемого вектора заносятся в регистры АН и AL одной командой (предложение 7). Исходный вектор сохраняется в двухсловной ячейке old_1ch, объявленной директивой dd (define double, определить двойное слово) в сегменте данных программы. Однако команды пересылки не могут работать с двойными словами, поэтому сохраняемый вектор засылается из регистров ES:BX в память пословно, сначала в младшую половину ячейки old_1ch (предложение 9), затем в старшую, естественно, равен old_lch+2 (предложение 10). Поскольку ячейка old_1ch объявлена с помощью директивы dd, для обращения к ее составляющим (словам) необходимо включать в команду описатели word ptr (word pointer, указатель на слово), которые как бы отменяют на время трансляции команды первоначальное описание ячейки.
Сохранив вектор, мы можем приступить к заполнению его адресом нашего обработчика. Для этого используется функция DOS 25h, которая, как уже отмечалось, требует указания в регистре AL номера заполняемого вектора, а в регистрах DS:DX полного адреса обработчика, который и будет записан в указанный нами вектор. Однако регистр DS настроен на сегмент данных программы. Кстати, если бы это было не так, мы не могли бы выполнить предложения 9 и 10, так как поля данных программы адресуются через регистр DS. Поэтому на время выполнения функции 25h нам придется изменить содержимое DS, настроив его на тот сегмент, в котором находится процедура обработчика, т.е. на сегмент команд. Это и выполняется в предложениях 13... 15. Содержимое DS сохраняется в стеке, а затем в него через стек заносится содержимое регистра CS, который, очевидно, указывает на сегмент команд. После возврата из DOS в программу исходное содержимое DS восстанавливается (предложение 17).
Начиная с этого момента, прерывания от таймера, приводящие к выполнению в системной программе BIOS команды int 1Ch, будут активизировать 18,2 раз в секунду программу нашего обработчика. При этом вся наша программа должна находиться в памяти и что-то делать, так как если она завершена, то она и обработчик уйдут из памяти. Для задержки программы в ней предусмотрен многократный, в цикле вывод на экран строки текста (предложения 18...21).
Перед завершением программы необходимо с помощью той же функции 25h восстановить исходное содержимое вектора 1Ch. Для загрузки регистров DS:DX требуемым адресом в примере 46.1 используется удобная команда Ids (load pointer using DS, загрузка указателя с использованием DS). В качестве операндов для этой команды указывается один из регистров общего назначения и двухсловное поле памяти с искомым адресом. Следует иметь в виду, что после выполнения этой команды старое содержимое регистра DS теряется. В нашем примере оно больше не нужно, так как, выполнив восстановление вектора, программа завершается (предложение 25). Вообще же перед выполнением команды Ids исходное содержимое регистра DS следует сохранить в стеке.
Рассмотрим теперь программу обработчика прерывания от таймера. Программа начинается с сохранения в стеке регистров, которые будут использоваться в обработчике. Это чрезвычайно важное действие, так как переход на программу обработчика осуществляется по команде int1ch из системной программы обработки прерываний от таймера. При выполнении процедуры прерывания процессор настраивает должным образом только регистры CS и IP. Содержимое всех остальных регистров (в том числе сегментных) отражает состояние системной программы, и если оно будет изменено, то после возврата из нашего обработчика в вызвавшую его системную программу она перестанет функционировать. В нашем обработчике используются лишь регистры АХ и ES, которые и сохраняются в стеке (предложения 28-29).
Далее регистр ES настраивается на адрес видеобуфера (предложения 30-31), а в регистр АХ помещается код ASCII выводимого на экран символа вместе с его атрибутом (предложение 32). В последнем предложении используется важная возможность замены сегмента. Как уже отмечалось, при обращении к памяти по умолчанию используется сегментный регистр DS, т.е. предполагается, что адресуемая ячейка находится в том сегменте, на который в настоящий момент указывает DS, в нашем же случае в момент выполнения этой команды DS почти, наверное указывает на какой-то сегмент программы BIOS. Для адресации к нашим данным можно сохранить содержимое DS и настроить его на наши данные. Однако можно поступить проще, именно, ввести в команду префикс замены сегмента CS: и тем самым указать транслятору, чтобы он в данной команде использовал адресацию через регистр CS. Но и данные в этом случае следует разместить не в сегменте данных, к которому нет доступа, а в сегменте команд. У нас так и сделано. Ячейки sym1 и sym2, к которым обращается обработчик, расположены в конце процедуры new_1ch в пределах сегмента команд (предложения 39-40).
Вывод одного и того же символа в одно и то же место экрана приведет к тому, что мы не будем знать, работает ли наш обработчик. В нашем примере предусмотрена периодическая смена атрибута символа, что делает символ мерцающим. Для этого при каждом проходе программы обработчика ячейки sym1 и sym2 взаимно обмениваются своим содержимым. В результате на экран выводится то один, то другой код. Для обмена содержимого регистров или ячеек предусмотрена специальная команда xchg (exchange, обмен). Поскольку в микропроцессорах 80х86 запрещены команды с адресацией к памяти в обоих операндах, обмен приходится осуществлять через регистр АХ.
После восстановления сохраненных в стеке регистров работа обработчика завершается командой iret, которая передает управление назад в вызвавшую наш обработчик программу BIOS. Когда эта программа дойдет до своего завершения, она выполнит команду iret и управление вернется в нашу программу в ту (неопределенную) точку, в которой она была прервана сигналом таймера.
Кроме того при необходимости работать с реальным временем можно использовать различные функции – одна из них AH=00h. Формат её использования имеет следующий вид:
INT 1Ah АН = 00h — Считать значение счетчика времени.
Ввод: АН = 00h
Вывод: CX:DX=значение счетчика, AL=байт переполнения счетчика.
Приведём пример программы, использующей эту функцию. Программа выводит на экран прямоугольник, который меняет цвет с периодичностью 3 секунды, выход по F10. Задержка реализована в макрокоманде. Пример 4.3

Макроопределение задержки;
dely    macro time              ;(1)
        local zd,c1,cikl,ii,ii1 ;(2) описываем все метки, используемые вмакроопределении
        push cx                 ;(3) помещаем в стек используемые в макроопределении 
        push bx                 ;(4) регистры
        push bp                 ;(5)
        push ax                 ;(6)
        push dx                 ;(7)
        mov cx,time             ;(8) задаём количество повторений цикла задержки zd – 
zd:     push cx                 ;(9) задержка в цикле 18.2 секунды
        mov bp,0                ;(10)
        mov bx,1                ;(11)
cikl:   
        inc BP                  ;(12)
        mov ah,00h              ;(13)       
        int 1Ah                 ;(14)
        cmp BP,1                ;(15)
        je ii                   ;(16) переходим на метку ii на первой итерации цикла
        jmp ii1                 ;(17) на следующих итерациях переходим на метку ii1
ii:     add bx,dx               ;(18) формируем значение на единицу больше, чем в 
ii1:                            ;(19) регистре dx
        cmp bx,dx               ;(20) если значение в регистре dx изменилось(сравниваем 
        jne cikl                ;(21) значение в dx с сформированным в строке 18 
        pop cx                  ;(22) значением в регистре bx, которое на единицу больше, 
        loop zd                 ;(23)на единицу больше значение в dx станет через 18.2 сек)
        pop cx                  ;(24) если нет, то новая итерация циклаесли да, конец 
        pop bx                  ;(25) макрокоманды задержки
        pop bp                  ;(26)
        pop ax                  ;(27)
        pop dx                  ;(28)
        endm                    ;(29)
Text	  segment 'code'        ;(30)	        
	  assume CS:text,DS:data;(31)
                                ;процедура рисования прямоугольника
Prymoug   proc                  ;(32)
                mov AL,cvet     ;(33) определяем цвет
                mov BH,0        ;(34) видеостраница
                mov SI,250      ;(35) задаём начальные 
                mov DI,150      ;(36) координаты
                mov CX,y        ;(37) высота прямоугольника
Prym1:       push CX            ;(38) 
                mov CX,x        ;(39) ширина прямоугольника
Prym:         push CX	      
              mov AH,0ch        ;(40)  функция ввода пиксела
                mov CX,SI       ;(41) задаем начальные
                mov DX,DI       ;(42) координаты
                int 10h         ;(43) перрывание BIOS
                inc SI          ;(44) смещение по оси ox
                pop CX          ;(45)
                loop Prym      
                inc DI          ;(46) смещение по oy
                mov SI,250      ;(47) возвращаем прежнюю x-координату
                pop CX          ;(48)
                loop Prym1      ;(49)               
          ret                   ;(50)
Prymoug   endp                  ;(51)
                                ;процедура задержки
Zadergka   proc                 ;(52)
                mov bp,1        ;(53)
                mov cvet1,1     ;(54)
mig:                            ;(55)
                mov bl,cvet1    ;(56)задаём значение
                mov cvet,bl     ;(57)цвета
                call prymoug    ;(58)
                dely 18         ;(59) задержка в одну секунду       
                inc bp          ;(60)
                cmp bp,3        ;(61)на третьей итерации цикла(когда задержка будет 3 сек.)
                je  changCvet   ;(62) переходим на метку changCvet
                mov ah,06h      ;(63) функция ввода с клавиатуры без эха
                mov dl,0ffh     ;(64) задаём режим функции
                int 21h         ;(65) 
                cmp al,44h      ;(66) если нажата F10( 44h –ASCI код F10), то переходим на
                jne mig         ;(67) ex – выход из программы
                jmp ex          ;(68)       
changCvet:      inc cvet1       ;(69) меняем константу цвета
                mov bp,1        ;(70) приводим счётчик в исходное положение
                jmp mig         ;(71)
ex:                             ;(72)
          ret                   ;(73)
Zadergka   endp                 ;(74)   
                                ;главная процедура
Main            proc            ;(75)	        
                mov AX,data     ;(76)			
	        mov DS,AX       ;(77)
                int 21h         ;(78)
                mov x,30        ;(79) задаём ширину прямоугольника
                mov y,30        ;(80)
                mov AH,00h      ;(81) функция задания режима	
                mov AL,10h      ;(82) графический режим EGA
                int 10h         ;(83) прерывание BIOS
                call Zadergka   ;(84) вызываем процедуру задержки
                mov AH,00h      ;(85) возвращаемся в
                mov AL,03h      ;(86) текстовый режим
                int 10h         ;(87)
                mov ax,4c00h    ;(88)
	        int 21h         ;(89)  
main            endp            ;(90)
text            ends            ;(91)
data            segment         ;(92)
                x dw 0          ;(93)
                y dw 0          ;(94)
                cvet db 0       ;(95)
                cvet1 db 0      ;(96)
data            ends            ;(97)
stk             segment stack 'stack';(98)
                dw 128 dup (0)  ;(99)
stk             ends            ;(100)
		end main        ;(101)	

Общий алгоритм работы макроопределения задержки следующий: результат работы функции 00h возвращается в регистрах СX:DX. В данной программе работаем по регистру DX – младшие значения времени. Значение в регистре DX изменяется 18.2 раза в секунду, поскольку именно с такой периодичностью таймер вызывает аппаратное переывание. Сохраняем в регистре bx значение на единицу больше, чем в dx, затем сравниваем эти значения(строка 20). Всё это происходит в цикле. Как только значение dx измениться(прошло 18.2 сек) происходит выход из цикла. Данный цикл заключён во внешний цикл zd(строка 9). И поскольку внешний цикл cikl(строка 11) выполняется 18.2 раза в сек., то если внешний выполнить 18 раз, то общая задержка примерно равна 1 сек. Параметром, задающим количество повторений внешнего цикла, является параметр макрокоманды time. Т.е. команда Dely 18 – задержка примерно в 1 сек. для данного макроопределения.

В начало страницы