
- •1. Рп с вызовом через вектор прерывания Int 60h.................4
- •Резидентные программы
- •1. Установка резидентной программы
- •2. Резидентный обработчик прерываний от клавиатуры с подключением до системного обработчика.
- •3. Резидентный обработчик прерываний от клавиатуры
- •4. Резидентная программа
- •5. Выгрузка рп с помощью ее вызова
- •6. Общая программа загрузки и выгрузки рп
- •7. Обработка опций
- •8. Создание диалоговой среды
- •9. Загрузка рп в верхнюю память
- •10. Действия,выполняемые рп
- •Задание на курсовую работу
8. Создание диалоговой среды
Еще больше удобств дает возможность прямо отвечать на вопросы,
которые нам задает программа при загрузке. При этом сначала проверяется
загружена или нет данная резидентная программа. Если программа еще не
загружена, то производится ее загрузка. Если программа уже загружена,
то выдается запрос:
Вы хотите выгрузить РП из памяти? (Y,N)
В ответ требуется ввести один из указанных в скобках символов. В
зависимости от этого, либо выполнится выгрузка, либо просто закончится
программа.
Пример 8
Напишем фрагмент программы, который производит указанные выше
действия. Будем считать, что резидентная часть программы уже содержит
раздел проверки на повторную установку (как в примере 4), и раздел
выгрузки программы из памяти (как в примере 5). После проработки
предыдущих примеров у Вас появился достаточный опыт в составлении
резидентных программ. Поэтому приведем здесь лишь фрагмент инициирующей
части программы без конкретного значения меток переходов:
M1: ;---------------------- ;Инициирующая часть
mov AH,0C8h ;Вызов INT 2Fh с функцией C8h
mov AL,00 ;и подфункцией 00h
INT 2Fh ; -------
cmp AL,0FFh ;Вернулась подфункция = FFh?
jnz M16 ;Eсли 'нет', то на загрузку
mov AH,09h ;Вывод строки x1 с текстом:
lea DX,x1 ;'Вы хотите выгрузить РП ? (Y,N)'
INT 21h ; -------
mov AH,01h ;Прием символа с клав. в рег. AL
INT 21h ;Ожидает нажатия клавиши
cmp AL,'Y' ;Введен код клавиши 'Y'?
jz M18 ;Eсли 'да', переход к выгрузке РП,
;иначе - окончание программы.
9. Загрузка рп в верхнюю память
Любую резидентную программу можно загрузить в верхнюю память, чтобы
освободить место в обчной памяти для работы других программ. Это легко
сделать с помощью команды Loadhigh или LH:
LH rez.com Здесь 'rez.com'- имя резидентной программы
Выгрузку можно делать как с LH, так и без нее. Ведь при этом программа
никуда не устанавливается, а только выполняется:
rez.com off
Разумеется, резидентная программа загрузится в верхнюю память при
условии, что в файле CONFIG.SYS были загружены программы HIMEM и EMM386
и в блоке UPPER достаточно свободного места для размещения Вашей
программы.
10. Действия,выполняемые рп
Резидентная программа загружается в память с целью выполнения
определенного действия. Поскольку РП обычно вызывается прерыванием, то
и выполняемая ею функция носит название - обработчик прерывания.
Обработчик прерывания это главный фрагмент резидентной части программы,
выполняющий заданное действие, ради которого и была создана данная РП.
В приведенных выше примерах со 2 по 6 для вывода цветного символа на
зкран был использован обработчик прерывания вида:
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
Если обработчик прерывания вызывается аппаратным прерыванием,
в частности прерыванием от клавиатуры, как в вышеприведенных примерах,
то он не должен содержать внутри себя никаких прерываний DOS (int 21h).
Крайне нежелательны и прерывания BIOS, хотя некоторые из них иногда
работают нормально. Все зависит от среды из которой вызывается наш
обработчик.
Рассмотрим еще один обработчик прерывания от клавиатуры, который
может быть использован Вами при выполнении курсовой работы.
Пример 9
Вывод текущей даты в последние позиции экрана.
mov AL,87h ; Занесение адреса числа
out 70h,AL ; в порт 70h
in AL,71h ; Чтение числа из порта 71h
mov BX,00 ; Номер позиции на экране для вывода
call P1 ; Вывод 2-х цифр из AL на экран
mov AL,88h ; Занесение адреса месяца
out 70h,AL ; в порт 70h
in AL,71h ; Чтение месяца из порта 71h
mov BX,06 ; Номер позиции на экране для вывода
call P1 ; Вывод 2-х цифр из AL на экран
mov AL,89h ; Занесение адреса года
out 70h,AL ; в порт 70h
in AL,71h ; Чтение года из порта 71h
mov BX,12 ; Номер позиции на экране для вывода
call P1 ; Вывод 2-х цифр из AL на экран
mov AX,0EA3h ;
mov ES:[BX+3984],AX ;Вывод символа 'г'
jmp M3
P1 proc ;Процедура вывода 2-х цифр из AL на экран
push CX ;Сохраним те регистры, содержимое
push AX ;которых меняется в программе
mov CL,4 ;Число сдвигов
SHR AL,CL ;Сдвиг AL вправо 4 р
call P2 ;Перевод цифры из AL в символ
mov ES:[BX+3980],AX ;Вывод старшей цифры
pop AX ;Восстановим AX
call P2 ;Перевод цифры из AL в символ
mov ES:[BX+3982],AX ;Вывод младшей цифры
mov AX,0E2Eh ;
mov ES:[BX+3984],AX ;Вывод символа '.'
pop CX ;Восстановим CX
ret
P1 endp
P2 proc ;Процедура перевода цифры из AL в символ
and AL,0Fh ;Выделение мл. полубайта
add AL,'0' ;Добавление кода 30h
mov AH,0Eh ;Байт атрибутов
ret
P2 endp
Здесь все составляющие даты читаются из CMOS через порт 71h.
Предварительно в порт 70h должен быть записан требуемый Вам адрес
CMOS с единицей в старшем разряде (см.лекцию 'Часы реального времени'),
то есть, например, вместо адреса 04h, следует записать 84h.
Карта адресов CMOS
00 Секунды 01 Секунды будильника
02 Минуты 03 Минуты будильника
04 Часы 05 Часы будильника
06 День недели (1 - воскресенье)
07 Число месяца
08 Месяц
09 Год
Процедуры P1 и P2 нужны для перевода чисел прочитанных из CMOS
в символьную форму. Например, чтобы вывести на экран число 0101b (5h),
его надо преобразовать в код 35h.
Следует также помнить, что там, где Вы в программе сохраняете
в стеке реистры: push AX, push ES и т.д., надо добавить и сохранение
регистров используемых обработчиком!
Если обработчик прерывания вызывается прерыванием пользователя,
например int 60h, то написание его программы упрощается. Такой
обработчик может содержать внутри себя любые прерывания DOS и BIOS.
Рассмотрим такой обработчик прерывания, вызываемый пользовательским
прерыванием int 60h. Он также может быть использован Вами при выполнении
курсовой работы. Для вызова РП, команда int 60h вписывается в нужные
места отлаживаемой программы.
Пример 10
Вывод содержимого регистров отлаживаемой программы.
Для удобства здесь приведена полностью резидентная часть РП.
;--------------------- Резидентная часть
str1 db 10,13,' Регистры:',10,13
str2 db ' SS=**** ES=****',10,13
str3 db ' DS=**** SP=****',10,13
str4 db ' IP=**** CS=****',10,13
str5 db 'Флаг=**** ',10,13,'$'
P1 ;Процедура перевода 4-х цифр регистра AX в символьную форму
proc
push AX ;Сохраним AX
mov CL,12 ;Сдвиг 1-й цифры в самый младший
shr AX,CL ;полубайт рег.AX
call P2 ;Перевод в симв. форму 1-й цифры
;и занесение его в строку вывода
pop AX ;Восстановим AX
push AX ;Сохраним AX
mov CL,8 ;Сдвиг 2-й цифры в самый младший
shr AX,CL ;полубайт рег.AX
inc SI ;Для занесения в след. байт
call P2 ;Перевод в симв. форму 2-й цифры
;и занесение его в строку вывода
pop AX ;Восстановим AX
push AX ;Сохраним AX
mov CL,4 ;Сдвиг 3-й цифры в самый младший
shr AX,CL ;полубайт рег.AX
inc SI ;Для занесения в след. байт
call P2 ;Перевод в симв. форму 3-й цифры
;и занесение его в строку вывода
pop AX ;Восстановим AX
inc SI ;Для занесения в след. байт
call P2 ;Перевод в симв. форму 4-й цифры
ret ;и занесение его в строку вывода
P1 endp
;------------------------------------------
P2 proc
and AX,0Fh ;Выделим мл. цифру из AX
cmp AL,0Ah ;если цифра >=10
jnb V1 ;то переход к V1
add AL,'0' ;иначе добавл.30h
jmp V2 ;вывод цифры <10
V1: add AL,37h ;доб. 37h (коды цифр A,B,C,D...)
V2: mov [SI],AL ;Занесение в строку вывода
ret
P2 endp
;----------------------- Обработчик прерывания РП
M2:
push SP ;Сохраним в стеке используемые
push DS ;регистры. Заодно, будет удобно
push ES ;читать и содержимое этих
push SS ;регистров командами MOV AX,[BP]
mov BP,SP ;Указатель стека в BP
push CS ;Пересылка из CS в DS
pop DS
mov AX,[BP] ;Выводимый рег. SS
lea SI,str2+5 ;Адрес, куда помещать результат
call P1 ;Перевод 4-х цифр из AX в символы
mov AX,[BP]+2 ;Выводимый рег. ES
lea SI,str2+15 ;Адрес, куда помещать результат
call P1 ;Перевод 4-х цифр из AX в символы
mov AX,[BP]+4 ;Выводимый рег. DS
lea SI,str3+5 ;Адрес, куда помещать результат
call P1 ;Перевод 4-х цифр из AX в символы
mov AX,[BP]+6 ;Выводимый рег. SP
lea SI,str3+15 ;Адрес, куда помещать результат
call P1 ;Перевод 4-х цифр из AX в символы
mov AX,[BP]+8 ;Выводимый рег. IP
lea SI,str4+5 ;Адрес, куда помещать результат
call P1 ;Перевод 4-х цифр из AX в символы
mov AX,[BP]+10 ;Выводимый рег. CS
lea SI,str4+15 ;Адрес, куда помещать результат
call P1 ;Перевод 4-х цифр из AX в символы
mov AX,[BP]+12 ;Выводимый рег. Флагов
lea SI,str5+5 ;Адрес, куда помещать результат
call P1 ;Перевод 4-х цифр из AX в символы
mov AH,09h ;Вывод строки результатов
lea DX,str1 ;Адрес начала строки вывода
int 21h
pop SS ;Восстановим содержимое
pop ES ;регистров
pop DS ;
pop SP ;
IRET ;Выход в DOS
M1: ;---------------------- ;Инициирующая часть
Здесь обработчик прерывания читает содержимое регистров прямо из стека
с помощью команд:
mov AX,[BP] ;Содержимое рег. SS
mov AX,[BP]+2 ;Содержимое рег. ES
mov AX,[BP]+4 ;Содержимое рег. DS
и т.д.
Регистры IP, CS и рег. флагов помещаются в стек еще при вызове int 60h,
поэтому их содержимое мы также можем извлечь.
Командами типа:
lea SI,str2+15
мы заносим в рег. SI адрес байта в строке, куда будем помещать
результат командой:
mov [SI],AL ;Занесение в строку вывода
при выполнении процедуры P2.
После того,как строки str2, str3, str4, str5 будут заполнены, их
вывод на экран (всех сразу) производится прерыванием int 21,09h:
mov AH,09h ;Функция вывода
lea DX,str1 ;Адрес начала строки вывода
int 21h ;Вывод строки результатов