From 143f34d941f32e0808fc9344d4c4126ff530d64a Mon Sep 17 00:00:00 2001 From: Andrew Date: Thu, 22 Oct 2020 21:03:24 +0400 Subject: =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D1=80?= =?UTF-8?q?=D0=B5=D1=88=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B2=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D1=81=D0=B5=D0=BC=D0=B5=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sem2/lab5/DumpTSR.asm | 291 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 sem2/lab5/DumpTSR.asm (limited to 'sem2/lab5/DumpTSR.asm') diff --git a/sem2/lab5/DumpTSR.asm b/sem2/lab5/DumpTSR.asm new file mode 100644 index 0000000..fd3fad9 --- /dev/null +++ b/sem2/lab5/DumpTSR.asm @@ -0,0 +1,291 @@ +.MODEL Tiny +.286 +.CODE +ORG 100h + +LOCALS ; считать метки, начинающиеся с @@ локальными в пределах процедур + +TSRKeyCode = 2000h ; код комбинации клавиш Alt+D + +Start: + + jmp SetIntVec ; прыжок на установщик вектора + +; Обработчик прерывания 9 (прерывание от клавиатуры) +Handler9: + pushf ; записываем в стек флаги (для вызова старого обработчика прерывания) + call dword ptr cs:OldInt9 ; вызываем старый обработчик прерывания 9 + ; Проверка комбинации клавиш и флага занятости + pusha ; сохраняем все регистры общего назначения + cmp byte ptr cs:BusyFlag,0 ; проверяем флаг занятости (признак того, что этот код уже работает - это нужно для того, чтобы повторное нажатие Alt+D не вызвало наш код ещё раз) + jne @@Exit9 ; если не ноль, прыгаем + mov ah,11h ; функция получения информации о нажатии клавиши (без ожидания) + int 16h ; проверяем - нажата ли какая-либо клавиша (и какая) + jz @@Exit9 ; прыгаем, если нет + cmp ax,TSRKeyCode ; проверяем код нужной нам комбинации клавиш + jne @@Exit9 ; прыгаем, если не наша + sti ; разрешаем прерывания (чтобы во время отображения не происходило зависания... хотя этого обычно и не происходит, лучше всё же это сделать) + mov ah,10h + int 16h ; удаляем нажатую комбинацию клавиш из буфера клавиатуры + mov byte ptr cs:BusyFlag,1 ; устанавливаем флаг занятости + ; Вывод даты/времени + push ds + push es ; сохраняем DS, ES + call MainTSRProc ; вызываем процедуру вывода дампа с сохранением и восстановлением старого текста + pop es + pop ds ; восстанавливаем ES, DS + mov byte ptr cs:BusyFlag,0 ; сбрасываем флаг занятости в 0 (признак того, что этот код отработал - это нужно для того, чтобы Alt+D снова срабатывало) + @@Exit9: + popa ; восстанавливаем все регистры общего назначения + iret ; выходим из прерывания + +; Процедура вывода дампа с сохранением и восстановлением старого текста +MainTSRProc proc + ; Получение информации о видеорежиме + mov ah,0Fh + int 10h ; получаем в AL текущий видеорежим, в BH номер видеостраницы + cmp al,3 ; сравниваем с 3 (стандартный текстовый режим 80х25) + je @@OkVideoMode ; прыгаем, если равно + ; Действие в случае неверного видеорежима + mov al,7 + int 29h ; издаём звуковой сигнал (в случае неверного видеорежима) + ret ; выходим из процедуры + ; Сохранение информации о курсоре, видеостранице, адреса дампа + @@OkVideoMode: + mov cs:[VideoPage],bh ; сохраняем номер активной видеостраницы + mov ah,3 + int 10h ; получаем размер курсора в CX + mov cs:[OldCurSize],cx ; сохраняем размер + mov bp,sp + mov ax,[bp+2+4+16] ; смещение адреса дампа (2 - адрес возврата, 4 - сохранённые ds,es, 16 - pusha) + mov cs:[DumpAddr],ax + mov ax,[bp+2+4+16+2] ; сегмент адреса дампа + mov cs:[DumpAddr+2],ax + ; Чтение старого изображения + xor ax,ax + mov ds,ax ; DS = сегмент 0 + mov si,ds:[44Eh] ; SI = смещение начала активной видеостраницы, он же адрес для чтения данных (содержимого экрана) + mov cs:[VideoOffset],si ; сохраняем его + mov ax,0B800h + mov ds,ax ; DS = сегмент видеопамяти + push cs + pop es ; ES = сегмент кода и данных нашей программы + lea di,ScreenBuffer ; DI = адрес для записи данных (наш буфер) + mov cx,80*25 + cld ; прямой порядок копирования данных + rep movsw ; копируем содержимое экрана в наш буфер (CX слов из DS:SI в ES:DI) + ; Прячем курсор + mov ah,1 + mov ch,20h ; спрятать курсор + int 10h ; прячем курсор + ; Рисование рамки + push ds + pop es ; сегмент видеопамяти + push cs + pop ds ; DS = сегмент кода и данных нашей программы + mov di,[VideoOffset] ; DI = смещение начала активной видеостраницы + mov ax,1BC9h ; белый цвет на синем фоне (AH) и код символа левого верхнего угла + stosw ; записываем его (AX) в видеопамять (ES:DI, DI=DI+2) + mov al,205 ; символ горизонтальной линии + mov cx,78 + rep stosw ; записываем его 78 раз + mov al,187 ; символ правого верхнего угла + stosw + mov cx,23 + @@Vert: mov al,186 ; символ ветикальной линии + cmp cl,3 + jne @@1 + mov al,199 ; вертикальная линия с ответвлением для 3-й строки с конца + @@1: stosw + mov al,' ' ; пробел + cmp cl,3 + jne @@2 + mov al,196 ; горизонтальная линия для 3-й строки с конца + @@2: push cx + mov cx,78 + rep stosw + pop cx + mov al,186 ; символ ветикальной линии + cmp cl,3 + jne @@3 + mov al,182 ; вертикальная линия с ответвлением для 3-й строки с конца + @@3: stosw + loop @@Vert + mov al,200 ; символ левого нижнего угла + stosw + mov al,205 ; символ горизонтальной линии + mov cx,78 + rep stosw ; записываем его 78 раз + mov al,188 ; символ правого нижнего угла + stosw + ; Вывод текста помощи + mov ah,1Eh ; жёлтый текст на синем фоне + lea si,HelpText1 + mov di,(22*80 + 6)*2 + call ShowText ; выводим текст помощи + mov di,(23*80 + 3)*2 + call ShowText ; выводим текст помощи (SI уже на HelpText2, т.к. он идёт сразу за HelpText1) + ; Вывод дампа и обработка клавиш + @@MainLoop: + call ShowDump ; вывод дампа + mov ah,10h + int 16h ; ожидание нажатия на клавишу + cmp ax,4BE0h ; проверка клавиши влево + jne @@R + dec [DumpAddr] ; уменьшение смещения на 1 + @@R: cmp ax,4DE0h ; проверка клавиши вправо + jne @@CL + inc [DumpAddr] ; увеличение смещения на 1 + @@CL: cmp ax,73E0h ; проверка клавиши Ctrl+влево + jne @@CR + sub [DumpAddr],100h ; уменьшение смещения на 100h + @@CR: cmp ax,74E0h ; проверка клавиши Ctrl+вправо + jne @@U + add [DumpAddr],100h ; увеличение смещения на 100h + @@U: cmp ax,48E0h ; проверка клавиши вверх + jne @@D + dec [DumpAddr+2] ; уменьшение сегмента на 1 + @@D: cmp ax,50E0h ; проверка клавиши вниз + jne @@PU + inc [DumpAddr+2] ; увеличение сегмента на 1 + @@PU: cmp ax,49E0h ; проверка клавиши Page Up + jne @@PD + sub [DumpAddr+2],100h ; уменьшение сегмента на 100h + @@PD: cmp ax,51E0h ; проверка клавиши Page Down + jne @@E + add [DumpAddr+2],100h ; увеличение сегмента на 100h + @@E: cmp ax,11Bh ; проверка нажатия на Esc + jne @@MainLoop + ; Восстановление старого изображения + lea si,ScreenBuffer ; SI = смещение сохранённой области памяти + mov di,[VideoOffset] ; DI = смещение начала активной видеостраницы + mov cx,80*25 + rep movsw ; восстанавливаем изображение: копируем из буфера в область видеопамяти (CX слов из DS:SI в ES:DI) + ; Восстановление курсора + mov ah,1 + mov bh,[VideoPage] ; видеостраница + mov cx,[OldCurSize] ; размер курсора + int 10h ; восстанавливаем размер курсора + ret +MainTSRProc endp + +; Вывод текста по адресу DS:SI для нулевого символа цветом AH в позицию ES:DI +ShowText proc + @@Char: lodsb ; читаем символ + test al,al ; тестируем на ноль + jz @@Ret ; выходим, если ноль + stosw ; выводим его вместе с цветом + jmp @@Char ; повторяем + @@Ret: ret +ShowText endp + +; Вывод значения AL цветом AH в 16-ричном виде по адресу ES:DI +ShowByte proc + push ax + shr al,4 ; выделяем старшую часть + cmp al,9 + jbe @@1 + add al,'A'-('9'+1) + @@1: add al,'0' ; преобразуем в 16-ричную цифру + stosw ; выводим + pop ax + and al,0Fh ; выделяем младшую часть + cmp al,9 + jbe @@2 + add al,'A'-('9'+1) + @@2: add al,'0' ; преобразуем в 16-ричную цифру + stosw ; выводим + ret +ShowByte endp + +; Вывод значения DX цветом AH в 16-ричном виде по адресу ES:DI +ShowWord proc + mov al,dh + call ShowByte + mov al,dl + call ShowByte + ret +ShowWord endp + +ShowDump proc + push ds + lds si,dword ptr [DumpAddr] ; DS:SI = адрес дампа + mov di, (1*80 + 2)*2 ; стартовая позиция + + mov cx,20 ; 20 строк дампа + @@1: push cx + mov ah,1Bh ; светло-голубой цвет на синем фоне + mov dx,ds + call ShowWord ; вывести сегмент + mov al,':' + stosw ; вывести двоеточие + mov dx,si + call ShowWord ; вывести смещение + + mov cx,16 ; 16 элементов + mov ax,1320h ; тёмно-голубой цвет на синем фоне и пробел + stosw ; выводим пробел + @@2: mov al,' ' + stosw ; вывести пробел + lodsb ; прочитать символ из памяти DS:SI (SI=SI+1) + call ShowByte ; вывести 16-ричное значение байта из памяти + loop @@2 + + mov al,' ' + stosw + stosw ; вывести 2 пробела + mov cx,16 ; 16 символов + sub si,cx ; назад на 16 символов + mov ah,12h ; тёмно-зелёный цвет на синем фоне + @@3: lodsb ; прочитать символ из памяти DS:SI (SI=SI+1) + stosw ; вывести символ из памяти + loop @@3 + + pop cx + add di,160-(9+1+3*16+2+16)*2 ; переходим на новую строку + loop @@1 + pop ds + ret +ShowDump endp + +BusyFlag db 0 ; флаг занятости процедуры отображения дампа (0 - не занята, 1 - занята) +HelpText1 db 27,'/',26,' - one byte offset scroll, Ctrl',27,'/Ctrl',26,' - 100h bytes offset scroll',0 +HelpText2 db 24,'/',25,' - one segment scroll, PageUp/PageDn - 100h segments scroll, Esc - exit',0 + +TSRCodeEnd = $ ; конец кода резидентной части (дальше идут буферы) + +OldInt9 dw ?,? ; адрес старого обработчика прерывания 9 +DumpAddr dw ?,? ; адрес дампа +OldCurSize dw ? ; старый размер курсора +VideoOffset dw ? ; смещение начала области текущей видеопамяти (для активной видеостраницы) +VideoPage db ? ; номер активной видеостраницы +ScreenBuffer dw 80*25 dup (?) ; буфер для хранения старого изображения с экрана + +TSREnd = $ ; конец резидентной части программы +ORG TSRCodeEnd ; для экономии места на диске следующий код будет начинаться здесь (на месте начала буфера, всё равно этот буфер не инициализирован) + +; Установка векторов прерывания +SetIntVec: + mov ax,3509h ; функция получения вектора прерывания 9 (прерывание от клавиатуры) + int 21h ; получаем вектор + mov OldInt9[0],bx ; сохраняем смещение + mov OldInt9[2],es ; сохраняем сегмент + mov ah,25h ; функция установки обработчика прерывания - записи вектора прерывания (AL=9 не менялся после вызова предыдущей функции 35h) + lea dx,Handler9 ; DS:DX = адрес нашего обработчика + int 21h ; устанавливаем наш обработчик + + mov ah,49h ; функция освобождения памяти + mov es,ds:[2Ch] ; сегмент переменных окружения + int 21h ; освобождаем сегмент с переменными окружения (чтобы программа занимала меньше памяти) + + mov ah,9 ; функция вывода сообщения (до '$') + lea dx,MsgInstalled ; адрес сообщения + int 21h ; выводим сообщение + + lea dx,TSREnd ; конец обработчика прерывания + int 27h ; выходим, оставив программу резидентной + +MsgInstalled db 'DumpTSR is successfully installed!',13,10 + db 'Press + to activate.',13,10,'$' + +END Start -- cgit v1.2.3