summaryrefslogtreecommitdiff
path: root/sem2/lab5/DumpTSR.asm
diff options
context:
space:
mode:
Diffstat (limited to 'sem2/lab5/DumpTSR.asm')
-rw-r--r--sem2/lab5/DumpTSR.asm291
1 files changed, 291 insertions, 0 deletions
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 <Alt>+<D> to activate.',13,10,'$'
+
+END Start