1. Задание
Разработать резидент-замедлитель исполнения программ. Замедление реализуется процедурой задержки, вставленной в обработчик прерывания пользователя по таймеру (int 1Ch). Инициализация резидента осуществляется через посредство комбинации клавиш . Значение символа цифровой клавиши влияет на скорость замедления.
 2. Структура и описание разработки
 Вся разработка состоит из двух файлов: *.com – непосредственно резидента и *.exe – демонстрационной программы. Рассмотрим сначала структуру и принцип действия резидента. В состав *.com файла входят следующие обработчики: пользовательский обработчик new_1Ch, заменяющий прерывание 1Сh, пользовательский обработчик клавиатуры new_09h, заменяющий системный обработчик 09h, а также обработчик new_2Fh, заменяющее соответствующее прерывание. Также в файле находятся дополнительные поля и методы, необходимые для корректного функционирования резидента.
 Рассмотрим работу пользовательского прикладного обработчика прерываний new_1Ch, заменяющего на время работы резидента прикладной аппаратный обработчик прерываний DOS Int 1Ch, входящего в состав системного обработчика BIOS 08h Прерывание DOS Int 1Ch служит для перехвата тактов системного таймера (18,206 Гц), не нарушая его работу, и изначально содержит лишь одну команду Iret. Новый обработчик содержит алгоритм замедления исполнения программ, основывающийся на том факте, что прерывание 1Ch вызывается примерно 18 раз в секунду. Получается, каждый вызов происходит примерно через каждые 55 мс. Таким образом можно для замедления исполнения программ пропускать каждые n-е вызовы, а остальные задерживать специальным алгоритмом. Получаем замедлитель в n раз исполнения программ, где n- это коэффициент замедления, который регулируется переменной cnt, которая находится в кодовом сегменте. Эта переменная может принимать значения от 0 до 8. Следует добавить, что обработчик new_1Ch несёт ещё одну функцию – демонстрационную. Он выводит на экран не замедленное системное время. Это означает, что в каком ни было режиме замедления обработчик не находился бы, на экране будет отображаться системное время. Рассмотрим теперь работу алгоритма задержки. При очередном вызове обработчика new_1Ch происходит проверка режима работы замедлителя. Режим работы характеризуется состоянием переменной fn, находящейся в кодовом сегменте. Эта переменная может принимать значения от 0 до 8. Значение переменной “0” соответствует “скрытому” режиму работы, при котором на экран не выводится системное время, а так же не происходит никакого замедления. Значения переменной от 1 до 8 характеризуют соответствующий коэффициент задержки при выводимом на экран системном времени. Итак, при установлении режима работы резидента ( по умолчанию идёт 0 ), происходит выставление в переменную cnt, хранящуюся там же коэффициента замедления, а так же по режиму работы определяется выводить или нет на экран системного времени. Коэффициент замедления – это количество вызовов процедуры задержки исполнения программы, время исполнения которой примерно равно 55 мс. Далее происходит анализ переменной f1 на тот факт, что производит на этот раз: проход на Iret, или же производить задержку исполнения. Если fn==0, то идём на выход и выставляем fn=1, если же fn==1, то запускаем алгоритм задержки с возможностью вывода системного или без оного. По завершению работы алгоритма fn выставляется в 0, т.е. при следующем вызове обработчика задержки происходить не будет.
 Стоит заметить, что переменная fn, характеризующая режим работы резидента находится хоть и сегменте кода, но не в пределах функции new_1Ch, а вне её. Это необходимо для общедоступности этой переменной, т.к. её использует пользовательский обработчик new_09h для выставления режима работы, а так же обработчик new_2Fh для считывания его.
 Теперь рассмотри работу пользовательского обработчика прерываний от клавиатуры new_09h. Проанализируем введённый символ с клавиатуры, если он принадлежит заданному диапазону значений, то продолжим, иначе передадим управление системному обработчику, адрес которого изначально был сохранён. Если всё нормально, то проверяем, включён ли режим Scroll Lock, если нет , то на выход, иначе выставляем в переменной соответствующий номер режима, восстанавливаем все регистры и выходим из обработчика.
 Мультиплексное прерывание new_2Fh работает по следующему принципу: сначала проверяется содержимое регистра ax на запрос режима работы резидента, если такой запрос имеет место, то возвращается содержимое переменной fn в том же регистре и происходит выход из процедуры. Если такого запроса не поступило, то происходи анализ того же регистра на наличие нашей функции в памяти. Стоит отметить, что функцией присвоен идентификатор 0C88h. При наличие резидента в памяти произойдёт возвращение в младшем байте регистра ax значения 0ffh. Если и этого запроса не поступило, то проверяется наличие запроса на деинсталляцию. При положительном результате происходит восстановление всех ранее перехваченных векторов и выгрузка из памяти резидента вместе с PSP. При отсутствии всех выше перечисленных запросов произойдёт переход в следующий по цепочке обработчик.
 В секции инициализации Init Выполняется проверка на наличие в памяти первого экземпляра резидента. Если первый экземпляр не обнаружен, то независимо от вида запускающей программу команды ;(с опцией или без неё) происходит переход на метку ОК с установкой программы в памяти. При обнаружении первого экземпляра программы начинается сравнение опции команды с ожидаемой. Если результат сравнения оказался отрицательным (опция есть, но другая), программа завершается выводом сообщения о невозможности повторной установки. При идентичности опции ожидаемой резидент выгружается из памяти с выводом соответствующего сообщения.
Демонстрация работы резидента основывается на показательном сравнении “заторможенного” и “не заторможенного” системного времени. “Заторможенное” системное время получается в результате работы резидента. При этом происходит задержка вывода времени на экран. “Не заторможенное” время выводится непосредственно прикладным обработчиком 1Ch. Дело в том, что какой бы то ни было коэффициент замедления не был установлен, время в любом случае будет выводится на экран, так как функция вывода системного времени установлена в алгоритме замедления, суть которого заключается в многократном вызове циклов (порядка не скольких сотен тысяч раз в секунду). Таким образом можно сравнить реально идущее время с заторможенным, а так же можно не вооруженным глазом определить коэффициент замедления.
 Весь интерфейс демонстрационной программы оформлен в псевдографике, имеет несколько информационных окон – статус резидента, «заторможенное время», «незаторможенное время», коэффициент замедления.
 3. Результаты демонстрации программы.
При запуске .com программы из командной строки было выведено соответствующее сообщение об удачной загрузке резидента в память. При повторном запуске .com приложения было выведено сообщение, что резидент уже загружен. Для дальнейшего продолжения демонстрации работы запустили демонстрационную программу со специальным экранным интерфейсом, в котором отображалось состояние резидента. В окне Статус высвечивается статус резидента, в После предварительного включения режима Scroll Lock последовательно жмём на цифровые клавиши, при этом начинает изменяться информация о состоянии резидента. Заметим, что по умолчанию резидент находился в “скрытом” состоянии, что характеризовалось отсутствием выводимого системного времени на экране, а так же коэффициентом замедления 1. Стоит отметить, что изменение коэффициента замедление не происходит мгновенно, а только в зависимости от предыдущего значения коэффициента замедления
Выгрузка резидента происходит следующим образом: в командной строке прописывается имя файла «пробел» off, после этого будет выведено сообщение об выгрузке резидента из памяти.
 4. Листинг программ
Файл RES.asm
;Студент: Шевченко Н.С. преподаватель: Афанасьев В.А.
;Вариант 11
;Задание: Реализовать Резидент-замедлитель исполнения программ.
;Замедление реализуется поцедурой задержки, вставленной
; в обработчик прерывания пользователя по таймеру (int 1Ch).
;Инициализация резидента осуществляется через
;посредство комбинации клавиш .
;Значение символа цифровой клавиши влияет на скорость замедления
;Res.com – основнной модуль, содержащий резидент с пользовательскими
;обработчиками new_1Ch, new_09h и new_2Fh заменяющими соостветствующие
;обработчики 1Ch, 09h и 2Fh
;test.exe – демонстрационная программа, показывающая на примере
;вывода системного времени работу резидента
 IDEAL
 MODEL TINY
 p486n
 CODESEG
 org 100h ;Установим IP на адрес после PSP
MACRO cprintf mes,len,attrib,x,y,n
 mov ah,13h
 mov al,1 ;Признак смещения курсора в конец строки
 mov bh,n ;Номер видеостраницы
 mov bl,attrib
 mov cx,len
 mov dh,y
 mov dl,x
 mov bp,offset mes ;Адрес строки ES:BP
 int 10h
ENDM cprintf
;———————————————————————-
Proc resident
 jmp init ; Переход на секцию инициализации
 old_1Ch dd 0 ; Адреса заменяемых обработчиков
 old_2Fh dd 0 ;
 old_09h dd 0 ;
 ten db 10 ; Основание сисемы исчисления
 fn db 0 ; Режим работы резидента
Proc new_1Ch ; Пользовательский обработчик new_1Ch
 pusha
 push ds es
 mov ax,cs
 mov ds,ax ;ds=cs
 cmp [cs:cnt],0 ; время замедления равно 0
 je end_out ; то идём на выход
 mov cx,[cs:cnt] ;Число внешних циклов
outer: push cx ;собственно задержка
 mov cx,0 ;
 ;
inner: loop inner ;0FFFFh – число внутренних циклов
 pop cx ;
 loop outer ;
 mov ah,02h ; иначе выведем на экран
 int 1Ah ; в определённые координаты (для демонстрации)
 ; строку системного время с атрибутом
; показать замедленное время
 mov al,ch
 call bin_asc ; вызовем функцию перевода в ASCII символы
 mov [cs:clock],ah ; сохраним значения
 mov [cs:clock+2],al ;
 mov al,cl
 call bin_asc
 mov [cs:clock+6],ah
 mov [cs:clock+8],al
 mov al,dh
 call bin_asc
 mov [cs:clock+12],ah
 mov [cs:clock+14],al
 mov cx,clock_len
 mov ax,0B800h
 mov es,ax
 mov di,[cs:locate]
 mov si,offset clock ; выведем строку на экран
 cld
 rep movsb
end_out:
 pop es ds ; восстановим все регистры
 popa
 jmp [dword cs:old_1Ch]
 iret
 ; выйдем из процедуры
Endp new_1Ch
;—————————————————
Proc bin_asc ; Процедура преобразования BCD-кода
 ;mov ah, al
 ;sub ah, al
 ;shr ah, 1
 ;sub al, 10
 ;add ah, ‘0’
 ;add al, ‘0’
 mov ah,al ; из регистра al в ASCII-символы
 and al,0Fh
 shr ah,4
 or ax,3030h
 ret
Endp bin_asc
;————————————
clock DB 2 DUP(20h,1Fh),”:”,1Fh ; строка системного времени с атрибутом
 DB 2 DUP(20h,1Fh),”:”,1Fh,2 DUP(20h,1Fh)
clock_len = $-clock ; длинна строки
locate DW 1352 ; 1352 позиция точки ввода на экране
cnt DW 0 ; коэффициент замедления
f1 DB 0 ; 0- не производить замедление 1- наоборот
;————————————
Proc new_09h ; пользовательский обработчик new_09h
 pusha ; Сохраним регистры
 push es
 push ds
 in al,60h ; Введём скан-код
 cmp al,0Bh
 je h0
 cmp al,02h
 je h1
 cmp al,03h
 je h2
 cmp al,04h
 je h3
 cmp al,05h
 je h4
 cmp al,06h
 je h5
 cmp al,07h
 je h6
 cmp al,08h
 je h7
 cmp al,09h
 je h8
xxx:
 pop ds ; Если ни одна из комбинаций клавиш не
 pop es ; присутствует, то восстановим регистры
 popa ; и в системный обработчик без вовзврата
 jmp [dword cs:old_09h]
h0: mov ax,40h ;Настроим ES на сегмент данных BIOS
 mov es,ax
 mov al,[es:17h] ;Получим первый байт флагов
 and al,00010000b ;выделяем 4-ый бит
 cmp al,0 ;Клавиша Scroll Loсk нажата?
 je xxx
 ;test al,10h ;Клавиша Scroll Loсk нажата?
 ;je xxx ;если нет, то выйдем
 mov [cs:fn],0h ; если гажата, то выставим соответствующий режим
 mov [cs:cnt], 0
 jmp xxxx ; работы резидента, и пойдём на выход
h1: mov ax,40h
 mov es,ax
 mov al,[es:17h]
 test al,10h
 je xxx
 mov [cs:fn],1h
 mov [cs:cnt], 0
 jmp xxxx
h2: mov ax,40h
 mov es,ax
 mov al,[es:17h]
 test al,10h
 je xxx
 mov [cs:fn],2h
 mov [cs:cnt],160
 jmp xxxx
h3: mov ax,40h
 mov es,ax
 mov al,[es:17h]
 test al,10h
 je xxx
 mov [cs:fn],3h
 mov [cs:cnt], 240
 jmp xxxx
h4: mov ax,40h
 mov es,ax
 mov al,[es:17h]
 test al,10h
 je xxx
 mov [cs:fn],4h
 mov [cs:cnt],320
 jmp xxxx
h5: mov ax,40h
 mov es,ax
 mov al,[es:17h]
 test al,10h
 je xxx
 mov [cs:fn],5h
 mov [cs:cnt],400
 jmp xxxx
h6: mov ax,40h
 mov es,ax
 mov al,[es:17h]
 test al,10h
 je xxx
 mov [cs:fn],6h
 mov [cs:cnt], 480
 jmp xxxx
h7: mov ax,40h
 mov es,ax
 mov al,[es:17h]
 test al,10h
 je xxx
 mov [cs:fn],7h
 mov [cs:cnt],560
 jmp xxxx
h8: mov ax,40h
 mov es,ax
 mov al,[es:17h]
 test al,10h
 je xxx
 mov [cs:fn],8h
 mov [cs:cnt],640
 jmp xxxx
xxxx: in al,61h ;Введём содержимое порта 61h
 or al,80h ;Подтвердим приём кода, записав 1 в старший
 out 61h,al ;бит порта 61h
 and al,7Fh ;Снова разрешим работу контроллера клавиатуры
 out 61h,al ;сбросив старший бит порта 61h
 mov al,20h ;20h – команда EOI
 out 20h,al ;20h – порт контроллера
 pop ds ;Восстановим регистры
 pop es
 popa
 iret ; выйдем из прерывания
Endp new_09h
Proc new_2Fh ; мультиплексное прерывание
 cmp ah,0C7h ; Если поступил запрос на режим работы резидента
 jne dalshe ; то вернём его в младшем байте регистра ax
 mov al,[cs:fn] ; иначе продолжим .
 iret ;
dalshe:
 cmp ah,0C8h ; Наша функция?
 jne out_2Fh ; Не наша, – на выход
 cmp al,00h ; Подфункция проверки на повторную установку
 je i_here ; Да, сообщим о невозможности повторной установки
 cmp al,01h ; Подфункция выгрузки?
 je uninst ; Да, на выгрузку
 jmp short out_2Fh ; Неизвестная подфункция, на выход
i_here: mov al,0ffh
 iret
out_2Fh:jmp [dword cs:old_2Fh] ; Переход в следующий по цепочке обработчик
uninst: push ds
 push es
 push dx
 mov ax,251Ch ; Восстановим вектор 1Ch
 lds dx,[cs:old_1Ch]
 int 21h
 mov ax,252Fh ; Восстановим вектор 2Fh
 lds dx,[cs:old_2Fh]
 int 21h
 mov ax,2509h ; Восстановим вектор 09h
 lds dx,[cs:old_09h]
 int 21h
 ; Получим из PSP адрес собственного окружения и выгрузим его
 mov es,[cs:2Ch] ; es  mov ah,49h ; Функция освобождения блока памяти
 int 21h
 ; Выгрузим теперь программу из памяти вместе с PSP
 push cs
 pop es ; es снова указывает на начало PSP
 mov ah,49h ; Функция освобождения блока памяти
 int 21h
 pop dx
 pop es
 pop ds
 iret
Endp new_2Fh
Endp resident
;Секция инициализации
;- Выполняется проверка на наличие в памяти первого экземпляра резидента.
;- Если первый экземпляр не обнаружен, то независимо от вида запускающей программу команды
;(с опцией или без неё) происходит переход на метку ОК с установкой программы в памяти
;- При обнаружении первого экземпляра программы начинается сравнение опции команды с
;ожидаемой
;- Если результат сравнения оказался отрицательным (опция есть, но другая), программа завершается
;выводом сообщения о невозможности повторной установки
;- При идентичности опции ожидаемой резидент выгружается из памяти с выводом
соответствующего сообщения
Proc init
 mov ax,0C800h ;Запрос на наличие в памяти первого
 int 2Fh ;экземпляра программы
 cmp al,0ffh ;Вернулся код 0ffh?
 jne ok ;Нет, данная программа в памяти отсутствует. Выполним её
 ;установку, перейдя на метку оk
 ;Первый экземпляр обнаружен. Была ли у команды опция ‘off’?
 mov cl,[es:80h] ;Получим длину хвоста из PSP
 cmp cl,0 ;Длина хвоста = 0?
 je fin ;Да, программа запущена без него
 xor ch,ch ;Пусть сх=cl=длина хвоста
 mov di,81h ;Адрес хвоста es:di в PSP
 mov al,’ ‘ ;Уберём пробелы из начала хвоста
 cld ;просмотр вперёд
 repe scasb ;Сканируем хвост (al – dst), пока пробелы
 dec di ;di- первый символ после пробела
 mov cx,3 ;Ожидаемая длина опции
 mov si,offset option ;Адрес ожидаемой опции (option) ds:si
 repe cmpsb ;Сравниваем введённую опцию с ожидаемой
 jne fin ;Опции не совпали. На выход
 mov ax,0C801h ;Опции совпали, пошлём в резидентную
 int 2Fh ;программу команду (al=01) на выгрузку. По окончанию
 mov dx,offset msg3 ;выгрузки выведем сообщение об этом
 jmp fin1
fin: mov dx,offset msg2 ;Попытка вторичной установки
fin1: mov ah,09h
 int 21h
 mov ax,04C00h ;Функция DOS 4Сh: выход из программы
 int 21h ;Вызов DOS. Останов
 ;Первой экземпляр (резидент) отсутствует. Установим программу
ok: mov ax,351Ch ;Чтение и сохранение вектора 1Ch
 int 21h
 mov [word cs:old_1Ch],bx
 mov [word cs:old_1Ch+2],es
 mov ax,3509h ;Чтение и сохранение вектора 09h
 int 21h
 mov [word cs:old_09h],bx
 mov [word cs:old_09h+2],es
 mov ax,352Fh ;Чтение и сохранение вектора 2Fh
 int 21h
 mov [word cs:old_2Fh],bx
 mov [word cs:old_2Fh+2],es
 mov ax,251Ch ;Установка обработчика 1Ch
 mov dx,offset new_1Ch
 int 21h
 mov ax,2509h ;Установка обработчика 09h
 mov dx,offset new_09h
 int 21h
 mov ax,252Fh ;Установка обработчика 2Fh
 mov dx,offset new_2Fh
 int 21h
 mov ah,09h
 mov dx,offset msg1 ;Сообщение об успешной установке программы
 int 21h
 mov ax,3100h
 mov dx,(init-resident+10Fh)/16
 int 21h
Endp init
;———————————————-
msg1 db ‘Резидентный обработчик установлен$’
msg2 db ‘Резидент уже установлен. Выгрузка через опцию off$’
msg3 db ‘Резидент выгружен из памяти$’
option db ‘off’
END resident
Файл TEST.asm
;Студент: Шевченко Н.С. преподаватель: Афанасьев В.А.
;Вариант 11
;Задание: Реализовать Резидент-замедлитель исполнения программ.
;Замедление реализуется поцедурой задержки, вставленной
; в обработчик прерывания пользователя по таймеру (int 1Ch).
;Инициализация резидента осуществляется через
;посредство комбинации клавиш .
;Значение символа цифровой клавиши влияет на скорость замедления
;R.com – основнной модуль, содержащий резидент с пользовательскими
;обработчиками new_1Ch, new_09h и new_2Fh заменяющими соостветствующие
;обработчики 1Ch, 09h и 2Fh
;DEMO.exe – демонстрационная программа, показывающая на примере
;вывода системного времени работу резидента
 Ideal
 Model small
 P486N
 Stack 256
MACRO window N,attrib,y1,x1,y2,x2
 mov ah,06h
 mov al,N
 mov bh,attrib
 mov ch,y1
 mov cl,x1
 mov dh,y2
 mov dl,x2
 int 10h
ENDM window
MACRO locate y,x
 mov ah,02h
 mov bh,0
 mov dh,y
 mov dl,x
 int 10h
ENDM locate
MACRO cprintf mes,len,attrib,x,y,n
 mov ah,13h
 mov al,1 ;Признак смещения курсора в конец строки
 mov bh,n ;Номер видеостраницы
 mov bl,attrib
 mov cx,len
 mov dh,y
 mov dl,x
 mov bp,offset mes ;Адрес строки ES:BP
 int 10h
ENDM cprintf
MACRO out_str mes
 mov ah,09h
 lea dx,[mes]
 int 21h
ENDM out_str
 DATASEG
intro db 13,10,” ╔═════════════════════════════════════╗”
 db 13,10,” ║ Курсовая работа по Ассемблеру ║”
 db 13,10,” ║ Студент: Шевченко Н.С. Преподаватель: Афанасьев В.А. ║”
 db 13,10,” ╚═════════════════════════════════════╝”,13,10,’$’
mes_t11
 db 13,10,” ╔═════════════════════════════════╗”
 db 13,10,” ║ Текущее время: ║”
 db 13,10,” ║ Реальное время: ║”
 db 13,10,” ╚═════════════════════════════════╝$”
status db 13,10,” ╔════════════════════════════════╗”
 db 13,10,” ║ Статус: ║”
 db 13,10,” ╚════════════════════════════════╝$”
mode db 13,10,” ╔════════════════════════════════╗”
 db 13,10,” ║ Коэффициент замедления: ║”
 db 13,10,” ╚════════════════════════════════╝$”
info1 db 13,10,” ╔═════════════════════════════════════════════╗”
 db 13,10,” ║ Нажмите комбинацию клавиш вида  ║”
 db 13,10,” ║ где цифра = 1 . 8 (коэффициент замедления) ║”
 db 13,10,” ║ цифра ‘1’ означает, что замедление отсутствует ║”
 db 13,10,” ║ Примечание : по умолчанию замедление отсутствует! ║”
 db 13,10,” ╚═════════════════════════════════════════════╝$”
str1 db “1/1$”
str2 db “1/2$”
str3 db “1/3$”
str4 db “1/4$”
str5 db “1/5$”
str6 db “1/6$”
str7 db “1/7$”
str8 db “1/8$”
len7 = $-str8
error db 13,10,13,10, “Неверная комбинация клавиш. Попробуйте еще раз. $”
temp db ?
temp1 db ?
clocks db “00:00:00”
sclock_len = $-clocks
yes db “Резидент обнаружен”
yes_len = $-yes
no db “Резидент не обнаружен”
no_len = $-no
;————————————————————–
 Codeseg
Start:
 mov ax,@data
 mov ds,ax
 mov es,ax
;вывод пользовательского меню
 window 0,8Fh,0,0,25,80
 locate 0,0
 out_str intro
 out_str mes_t11
 out_str status
 out_str mode
 out_str info1
 mov ax,0C800h
 int 2Fh
 cmp al,0ffh
 jne ok
 cprintf yes,yes_len,2Fh,12,11,0
 mov [temp1],1
 jmp work
; резидента в памяти нет – выход
ok:
 cprintf no,no_len,4Fh,12,11,0
 jmp quit
; вывод на экран незамедленного (системного) времени
work:
 mov ah, 2Ch
 int 21h
 jc end_out
 mov al,ch
 call bcd_asc
 mov [clocks],ah
 mov [clocks+1],al
 mov al,cl
 call bcd_asc
 mov [clocks+3],ah
 mov [clocks+4],al
 mov al,dh
 call bcd_asc
 mov [clocks+6],ah
 mov [clocks+7],al
 cprintf clocks,sclock_len,1Fh,36,7,0
end_out:
;——————————————————————–
 push ax
 mov ax,0C700h
 int 2Fh
 mov [temp],al
 locate 14,30
 cmp [temp],0h
 jne del1
 cmp [temp1],1h
 jne del1
 out_str str1,len7,1Eh,63,15,0
del1: cmp [temp],01h
 jne del2
 out_str str1,len7,1Eh,63,15,0
del2: cmp [temp],02h
 jne del3
 out_str str2,len7,1Eh,63,15,0
del3: cmp [temp],03h
 jne del4
 out_str str3,len7,1Eh,63,15,0
del4: cmp [temp],04h
 jne del5
 out_str str4,len7,1Eh,63,15,0
del5: cmp [temp],05h
 jne del6
 out_str str5,len7,1Eh,63,15,0
del6: cmp [temp],06h
 jne del7
 out_str str6,len7,1Eh,63,15,0
del7: cmp [temp],07h
 jne del8
 out_str str7,len7,1Eh,63,15,0
del8: cmp [temp],08h
 jne del9
 out_str str8,len7,1Eh,63,15,0
del9:
 pop ax
;—————————————————————
; проверка на нажатие клавиши
quit: mov ah, 01h
 int 16h
 je work
exit:
 mov ax,4C00h
 int 21h
;—————————————————————
; процедура преобразования числа в ASCII-форму
Proc bcd_asc
 xor bx,bx
 mov bl, al
 mov bh, 00h
 mov ax,bx
 mov cl, 10 ; 10 == 1010b
 div cl
 add ah, ‘0’
 add al, ‘0’
 xchg ah,al
 ret
Endp bcd_asc
;—————————————————————
End start ; конец программы/точка выхода
