Задание №1
Разработать резидентный обработчик прерывания, который после нажатия некоторой комбинации клавиш должен при нажатии любой клавиши выводить на экран буквы латинского алфавита (последовательно).
В данном задании приходится полностью заменять прерывание от клавиатуры.
Суть алгоритма следующая: при нажатии клавиши в нашем обработчике подменяется скен-код и Ascii-код, и в кольцевой буфер помещается уже наш символ, не взирая, на что вы там нажали.
Просто выводить латинский алфавит выводит было скучно, поэтому вместо алфавита будем выводить слова известной песни.
Сам текст песни будет храниться в таблицах Ascii-кодов mytable и скен-кодов myscan.
Исходный код модуля RezVar28.asm
.386
cseg segment use16
assume cs:cseg,ds:cseg
org 100h
main proc
jmp init ;переход на секцию инициализации резидента
old_vector dd 0 ;сохраним адрес старого обработчика от клавиатуры
old_2fh dd 0 ;для обработчика мультиплексного прерывания
status db 0
count dw 0
mytable db 97h,0e2h,0aeh,20h,0e2h,0a0h,0aah,0aeh,0a5h,20h,0aeh,0e1h,0a5h,0adh,0ech,20h,0edh,0e2h,0aeh,20h,0adh,0a5h,0a1h,0aeh,2ch,0dh
db 8fh,0abh,0a0h,0e7h,0e3h,0e9h,0a5h,0a5h,20h,0adh,0a5h,0a1h,0aeh,20h,0afh,0aeh,0a4h,20h,0adh,0aeh,0a3h,0a0h,0ach,0a8h,2ch,0dh
db 82h,20h,0abh,0e3h,0a6h,0a0h,0e5h,20h,90h,0a0h,0a7h,0abh,0a5h,0e2h,0a0h,0eeh,0e2h,0e1h,0efh,20h,0afh,0e2h,0a8h,0e6h,0ebh,20h,0e1h,20h,0aeh,0a1h,0abh,0a0h,0aah,0a0h,0ach,0a8h,2ch,0dh
db 0aeh,0e1h,0a5h,0adh,0ech,20h,0efh,20h,0a4h,0a0h,0a2h,0adh,0aeh,20h,0e1h,20h,0e2h,0aeh,0a1h,0aeh,0eeh,20h,0adh,0a5h,20h,0a1h,0ebh,0abh,21h,0dh
myscan db 2dh,31h,24h,39h,31h,21h,13h,24h,14h,39h,24h,2eh,14h,15h,32h,39h,28h,31h,24h,39h,15h,14h,33h,24h,35h,1ch
db 22h,25h,21h,2dh,12h,18h,14h,14h,39h,15h,14h,33h,24h,39h,22h,24h,26h,39h,15h,24h,16h,21h,2Fh,30h,35h,1ch
db 20h,39h, 25h,12h,27h,21h,01ah,39h,23h,21h,19h,25h,14h,31h,21h,34h,31h,2eh,2ch,39h,22h,31h,30h,11h,1fh,39h,2eh,39h,24h,33h,25h,21h,13h,21h,2fh,30h,35h,1ch
db 24h,2eh,14h,15h,32h,39h,2ch,39h,26h,21h,20h,15h,24h,39h,2eh,39h,31h,24h,33h,24h,10h,39h,15h,14h,39h,33h,1fh,25h,02h,1ch
newint proc
pusha
cmp cs:status,0
jne m1
in al,60h ;обращение к порту для считывания скенкода
cmp al,58h ;проверяем нажата ли клавиша F12
jnz callold ;не нажата
mov ah,2 ;функция получения флагов нажатых клавиш
int 16h ;прерывание BIOS
test al,000000100b ;нажата CTRL
jz callold
inc cs:status
jmp callold
m1:
;получаем скан-код и посылаем сигнал подтверждения
in al,60h
mov ah,al ;помещаем копию в ah
push ax ;сохраняем в стеке
in al,61h ;читаем состояние порта 61h
or al,10000000b ;устанавливаем бит 7
out 61h,al ;посылаем измененный байт в порт
and al,01111111b ;сбрасываем бит 7
out 61h,al
;ES должен указывать на область данных BIOS
mov ax,40h ;утанавливаем сегмент
mov es,ax
pop ax ;возвращаем скан-код из стека
test al,10000000b ;код освобождения клавиши
jnz myquit
cmp cs:count,120 ;проверяем не конец ли таблицы
je mm ;если да обнулим счетчик
mm2: mov bx,cs:count
mov si,cs:count
mov al,cs:mytable[bx]
mov ah,cs:myscan[si]
inc cs:count
;код клавиши готов (в ah-скан код,в al-заменяемый код ASCII)
;проверим не полон ли буфер клавиатуры
mov bx,1Ah ;смещение указателя на голову буфера
mov cx,ES:[bx] ;получаем его значение
mov di,es:[bx]+2 ;получаем укзатель хвоста буфера (смещение 1Ch)
cmp cx,60 ;голова на вершине буфера?
je high_end ;да - переходим к специальному случаю
inc cx ;увеличиваем указатель головы
inc cx ;на 2
cmp cx,di ;сравниваем с указателем хвоста
je myquit ;если равны, то буфер полон
jmp go_head ;иначе вставляем символ
high_end: cmp di,30 ;проверка специального случая
je myquit ; если буфер полон, то выход
go_head: mov es:[di],al ;помещаем символ в позицию хвоста
cmp di,60 ;хвост в конце буфера
jne no_wrap ;если нет, то добавляем 2
mov di,28 ;иначе указатель хвоста =28+2
no_wrap: add di,2 ;получаем новое значение хвоста
mov es:[bx]+2,di ;посылаем его в область данных
myquit: popa
mov al,20h
out 20h,al
iret
mm: mov cs:count,0
jmp mm2
callold:
popa
jmp Dword ptr cs:[old_vector] ;переход на старое прерывание
newint endp
new_int2fh proc
cmp ah,0f1h ;наша функция?
jne out_2fh ;не наша, уходим на старый обработчик мультиплексного прерывания
cmp al,00h ;проверим подфункция 00
je inst
cmp al,1h ;проверим подфункция выгрузки?
je off ;переход на блок выгрузки
jmp short out_2fh ;если нет наших подфункций, то на старый обработчик
inst: mov al,0ffh ; говорим, что мы уже в памяти
iret ; возврат из прерывания
out_2fh:
jmp cs:old_2fh
off: push ds ;сохраним используемые регистры в стеке
push es
push dx
mov ax,2509h ; функция установки вектора 09h
lds dx,cs:old_vector ;в ds:dx адрес старого обработчика
int 21h
mov ax,252fh
lds dx,cs:old_2fh
int 21h
mov es,cs:2ch ;сегмент окружения из PSP
mov ah,49h ;функция освобождения блока памяти
int 21h
push cs ;скопируем cs в es
pop es ;es указывет на начало программы
mov ah,49h
int 21h
pop dx
pop es
pop ds
iret
new_int2fh endp
end_res=$
main endp
tail db 'off' ; ожиданмый параметр для выгрузки программы
flag db 0 ; проверочный флаг для выгрузки программы
init proc
mov cl,es:80h ;проверим длину хвоста команды из PSP
cmp cl,0 ; без хвоста?
je live ; значит программа запущена без параметров
xor ch,ch ;программа запущена с параметрами и в СХ-длина хвоста
mov di,81h ;ES:DI - хвост в PSP
lea si,tail ; DS:SI - поле tail
mov al,' ' ; Уберем пробелы из начала хвоста
repe scasb ; сканируем хвост пока пробелы
dec di ; DI- первый символ после пробелов
mov cx,3 ; ожидаемая длина параметра (off)
repe cmpsb ;сравниваем параметр из командной строки с ожидаемым
jne live ; идем проверять на наличие в памяти
inc flag ; устанавливаем флаг выгрузки
live: mov ah,0f1h ; наша функция
mov al,0 ; наша подфункция
int 2fh ; вызов мультиплексного прерывания
cmp al,0ffh ; смотрим вернулось ли 0ffh
je installed ; да мы уже в памяти
cli ; иначе запрет на чужие прерывания
mov ax,352fh ; функция чтения вектора 2fh
int 21h
mov word ptr cs:old_2fh,bx ;сохраняем старый вектор
mov word ptr cs:old_2fh+2,es ;мультиплексного прерывания
mov ax,252fh ; функция установки нового обработчика 2fh
mov dx,offset new_int2fh ;dx -смещение нового обработчика
int 21h
mov ax,3509h ;функция чтения вектора 09h (keyboard)
int 21h
mov word ptr cs:old_vector,bx ;сохраняем
mov word ptr cs:old_vector+2,es
mov ax,2509h ; устанавливаем новый обработчик
mov dx,offset newint
int 21h
sti ; разрешаем прерывания
mov ah,09h ; выведим сообщение об установке резидента
mov dx, offset mes
int 21h
mov ax,3100h ;функция завершить и оставить в памяти
mov dx,(end_res-main+10fh)/16 ; размер резидента в параграфах без секции инициализации
int 21h
installed:
cmp flag,1 ; проверяем флаг выгрузки
je unins ; если выставлен то дадим команду выгрузки
mov ah,09h ; иначе ругнемся, что уже в памяти
lea dx,mes1
int 21h
mov ax,4c01h ; заверщим нормально программу
int 21h
unins:
mov ax,0f101h ; наша функция 0f1h и наша подфункция выгрузки
int 2fh ; вызываем мультиплексное прерывание
mov ah,09h ; сообщаем, что выгрузились
lea dx,mes2
int 21h
mov ax,4c00h ; завершаем программу
int 21h
mes db 'Program installed$'
mes1 db 'Program already installed$'
mes2 db 'Program is unload$'
init endp
cseg ends
end main
|