Примеры реализаций типовых заданий
П.3.1. Листинг 3.4. Программа получения скан-кодов
Программа выводит на экран в виде четырёх 16-теричных чисел скан-код и ASCII- кода произвольной клавиши клавиатуры на основе использования функции BIOS 10h, Int 16h (101/102- key). Вызов: AH = 10h, Int 21h. Возврат: AL = ASCII -код символа, изображённый на клавише/Код признака расширения (00h/0Ah/0Dh или E0h); AH = скан-код/расширенный ASCII- код клавиши. При выводе на экран старшая пара цифр отделяется от младшей пробелом и сопровождается сообщением " Скан-код (расширенный ASCII- код)/ ASCII- код (00h/0Ah/0Dh или E0h) ". Ideal Model small Stack 256 macro out_str mes mov ah, 09h lea dx, [mes] int 21h Endm out_str Dataseg table_hex db '0123456789ABCDEF' buf_hex db 5 DUP(?) mes1 db 10, 13, 'Скан-код (расш. ASCII-код)/ASCII-код (00h/0Ah/0Dh или E0h): $' Codeseg Start: mov ax, @data; Установка в ds адреса mov ds, ax; сегмента данных again: mov ah, 10h int 16h; АХ< - информ-код клавиши после её нажатия cmp al, 1Bh; Нажата клавиша < Exc>? je Exit; Да, выходим из программы mov dx, ax; Нет, продолжаем работу. Сохраним АХ mov al, dh; Возьмём старший байт информ-кода для преобразования. call conv_hex; Процедура преобразования двоичного кода из AL ; в пару 16-теричных ASCII- цифр в регистре АХ mov [word buf_hex], ax; Запомним старшую пару ASCII- чисел в младших ; байтах буфера. При этом в AH должна располагаться младшая цифра. Это связано с особен- ; ностью записи информации из регистра в буфер памяти – старшая часть регистра записыва- ; ется по старшему адресу. mov [byte buf_hex+2], ' '; Запись пробела mov al, dl; Возьмём младший байт информ-кода для преобразования. call conv_hex mov [word buf_hex+3], ax; Запомним младшую пару ASCII- чисел в старших ; байтах буфера out_str mes1; Вывод сообщения mes1 ; Вывод информационного кода mov ah, 40h mov bx, 1 mov cx, 5 lea dx, [buf_hex] int 21h jmp again; Обработка следующей клавиши Exit: mov ax, 4C00h; Функция DOS 4Сh: выход из программы int 21h; Вызов DOS. Останов Proc conv_hex ; Процедура преобразования двоичного кода из регистра AL в пару 16-теричных ASCII-цифр ; в регистре АХ на основе использования команды XLAT push dx; Сохраним DX mov bx, offset table_hex mov ah, 0 mov cl, 4 shl ax, cl; AH < - старшая двоичная тетрада shr al, cl; AL < - младшая двоичная тетрада xlatb; AL < - младшая 16-теричная ASCII- цифра mov dh, al; Сохраним в старшей части DX mov al, ah xlatb; AL < - старшая 16-теричная ASCII- цифра mov dl, al; Сохраним mov ax, dx pop dx; Восстановим DX ret Endp conv_hex END Start; Конец программы/точка входа П.3.2. Листинг 3.5. Демонстрационная программа использования Программа демонстрирует применение функций BIOS при работе с экраном и клавиатурой. Внимательный анализ программы окажет Вам значительную помощь при выполнении собственных программ. Другой особенностью программы является широкое использование макросов. Макросы – эффективное языковое средство ассемблера, облегчающее разработку, модификацию и чтение программ. Приведённые ниже примеры макросов на основе функций BIOS, следует рассматривать лишь как один из возможных вариантов, так как структура макросов и реализуемые ими функции зависят как от целевого назначения программы, так и от стиля программирования. Comment /* Программа инициализирует экран и вводит 2 локальных окна. Командой < F1> устанавливается режим перетаскивания данных, контролируемых курсором, с одного окна в другое. Меню управления курсором, считыванием и записью символов в позиции курсора, содержится в служебном сообщении на экране. В качестве исходных данных предлагаются символы таблицы ASCII, которые выводятся в левое окно опцией < F2>. Командой < F4> для окна_2 вводится режим блокнота для набора произвольного текста с клавиатуры с возможностью редактирования клавишей < Backspace>. Из режима блокнота можно снова перейти в режим перетаскивания данных, нажав клавишу < F1>. */ Ideal P386N MODEL small Stack 256 ; Макросы ; Макрос инициализации окна с цветом (N=0) или его скроллинг вверх на N-строк ; Входные значения: N- параметр, определяющий назначение макроса, ; attrib- атрибут цвета, ; y1, x1- текстовые координаты левого верхнего угла окна, ; y2, x2- текстовые координаты правого нижнего угла окна. ; Выход отсутствует. MACRO window N, attrib, y1, x1, y2, x2 mov ah, 06h; Функция инициализация окна или его скроллинг вверх mov al, N mov bh, attrib; Атрибут цвета mov ch, y1; Координаты левого верхнего угла (у1, х1) mov cl, x1 mov dh, y2; Координаты правого нижнего угла (у2, х2) mov dl, x2 int 10h ENDM window ; Макроопределение locate позиционирования курсора в произвольную точку экрана (y, x) с ; запоминанием координат переменными row_k, col_k (k- номер локального окна на экране). ; Входные значения: определены в описании макроса. ; Выход: row_k= dh= y, col_k= dl= x. MACRO locate y, x, k mov ah, 02h; Функция позиционирования курсора mov bh, 0; Номер страницы mov dh, y mov dl, x mov [row_& k], dh mov [col_& k], dl int 10h ENDM locate ; Макрос вывода сообщения mes, длиной leng, атрибутом цвета attrib и с позиции (row_k, ; col_k), здесь k -номер окна. После вывода сообщения курсор перемещается в его конец. ; Если сообщение не укладывается в одну строку можно применить управляющие коды 10h ; (перевод строки) и 13h (возврат каретки). ; Входные значения: определены в описании макроса. Выход: отсутствует. MACRO out_str mes, leng, attrib, k mov ah, 13h mov al, 1; Признак смещения курсора в конец строки mov bh, 0; Номер видеостраницы mov bl, attrib mov cx, leng mov dh, [row_& k] mov dl, [col_& k] mov bp, offset mes; Адрес строки ES: BP int 10h ENDM out_str ; Запись символа с текущим атрибутом на экран в позицию курсора ; Входные значения: AL= ASCII- код символа, BH, CX= номер видеостраницы и число пов- ; торений символа. Выход отсутствует. Macro write mov ah, 0Ah; Функция записи символа с текущим атрибутом mov al, [ASCIIchar]; ASCII- код символа mov bh, 0 mov cx, 1; Число повторений символа int 10h Endm write ; Чтение символа и атрибута в позиции курсора и запись их в память для хранения. ; Входные значения: BH= номер страницы. ; Выход: AX= AH: AL= " атрибут: ASCII-код символа" этих параметров (дополнительно, эти ; параметры сохраняются переменными attrib и ASCIIchar). Macro read push bx mov ah, 08h; Функция чтение символа и атрибута mov bh, 0 int 10h mov [attrib], ah; Сохраним атрибут и mov [ASCIIchar], al; символ pop bx Endm read ; Копирование символа в позиции курсора с его удалением. Удаление осуществляется ; записью пробела с сохранением в данной позиции текущего атрибута. ; Входные значения: отсутствуют. ; Выход: AX= AH: AL= " атрибут: ASCII-код символа" (дополнительно, эти параметры ; сохраняются переменными attrib и ASCIIchar). Macro read_del Read; Сохраним атрибут и символ mov ah, 09h; Функция записи символа с заданными атрибутами на экран mov al, 20h; Поместим ASCII- код пробела и текущий атрибут mov bl, [attrib] mov cx, 1 int 10h Endm read_del crlf equ 13, 10, 5 DUP(20h) crlf2 equ 13, 10, 42 DUP(20h) Dataseg ExCode DB 0 mes0 DB '< F1> - режим переноса данных, контролируемых курсором, с одного' DB crlf, 'места экрана в другое. Опции режима: < F2> - вывод таблицы символов' DB crlf, 'ASCII в окно_1, < F3> - Очистка локального окна_2, < Ctrl-ins> -' DB crlf, 'копирование символа, < Ctrl-del> -копирование с удалением, < Ins> -' DB crlf, 'запись, ", , ¯, ® " – навигация курсора по экрану. ' DB crlf, '< F4> - режим набора текста в окне_2. < F10> -выход из программы.'
DB crlf2, ' При наборе текста используем ' DB crlf2, ' клавиши < Backspace> и < Enter> '
leng_mes0 = $-mes0 mes1 DB '0 1 2 3 4 5 6 7 8 9 A B C D E F' leng_mes1 = $-mes1 Label mes2 byte Line = 30h Rept 10 DB 4 DUP(20h), line, 13, 10 Line = line+1 endm line = 41h rept 6 DB 4 DUP(20h), line, 13, 10 Line = line+1 endm leng_mes2 = $-mes2 ASCIIchar DB? Attrib DB? Backspace DB 08h, 20h, 08h row_0 DB? col_0 DB? row_1 DB? col_1 DB? row_2 DB? col_2 DB? CODESEG Start: mov ax, @data; Установка в ds адреса mov ds, ax; сегмента данных mov es, ax; es=ds mov ax, 1003h; Вызов функции повышенной яркости экрана mov bl, 0; Повышенная яркость int 10h ; Инициализация экрана с атрибутом 0B0h (чёрные символы по бирюзовому фону) ; с координатами: (0, 0)- левый верхний угол, (24, 79)- правый нижний window 0, 0B0h, 0, 0, 24, 79 locate 1, 5, 0; row_0=1, col_0=5 out_str mes0, leng_mes0, 0B0h, 0; Вывод сообщения mes0 ; Инициализация локального окна_1 с атрибутом 0C1h (синий по розовому) ; с координатами: (8, 6)- левый верхний угол, (23, 38)- правый нижний window 0, 0C1h, 8, 6, 23, 38 locate 7, 7, 0; row_0=7, col_0=7 out_str mes1, leng_mes1, 0B0h, 0; Вывод сообщения mes1 locate 8, 0, 0 out_str mes2, leng_mes2, 0B0h, 0; Вывод сообщения mes2 ; Инициализация локального окна_2 с атрибутом 0E4h (красный по жёлтому) ; с координатами: (10, 42)- левый верхний угол, (23, 76)- правый нижний window 0, 0E4h, 11, 42, 23, 76 mov ax, 0C00h; Очистка буфера клавиатуры int 21h ; Выбор режима работы mode: mov ah, 10h; Чтение символа с клавиатуры с ожиданием int 16h cmp al, 00h; Управляющая клавиша c мл. байтом 00h jne mode cmp ah, 3Bh; Нажата < F1>? je F1; Да cmp ah, 3Eh; нажата < F4>? je F4; Да jmp mode; Цикл ввода режима F3: window 0, 0E4h, 11, 42, 23, 76; Очистка окна_2 ; Блок управления программой в режиме < F1> F1: mov ah, 10h; Функция чтения символа с клавиатуры ; (101/105 key). При нажатии клавиши, соответствующей расширенному ASCII-коду ; в АН засылается расширенный ASCII- код, в AL-значение 00h или 0E0h int 16h cmp al, 00h; Управляющая клавиша c мл. байтом 00h je @@1; Да cmp al, 0E0h; Управляющая клавиша c мл. байтом E0h je @@1; Да jmp F1; Нет, повторить ввод @@1: cmp ah, 3Ch; Нажата < F2>? je F2; Да cmp ah, 3Dh; нажата < F3>? je F3; Да cmp ah, 3Eh; нажата < F4>? je F4; Да cmp ah, 44h; Нажата < F10>? je F10; Да cmp ah, 92h; Нажата < ctrl-ins>? je ctrl_ins; Да cmp ah, 93h; Нажата < ctrl-del>? je ctrl_del; Да cmp ah, 52h; Нажата < ins>? je insert; Да ; Считывание текущих координат курсора push ax mov ah, 03h mov bh, 0 int 10h; D= номер строки, DL= номер столбца pop ax ; Продолжение опроса cmp ah, 48h; Нажата je up; Да cmp ah, 50h; Нажата ¯ je down; Да cmp ah, 4Bh; Нажата je left; Да cmp ah, 4Dh; Нажата ® je right; Да jmp F1; Нажата не запланированная ; Навигация курсора, копирование, запись, считывание ctrl_ins: mov di, 1; Разрешить запись read jmp F1 ctrl_del: mov di, 1; Разрешить запись read_del jmp F1 insert: cmp di, 1; Чтение выполнялось? jne @@1; Нет, запись выполнять нельзя write; Да, выполним запись @@1: jmp F1 up: cmp dh, 0; На строку вверх je L3 sub dh, 1 jmp L3 down: cmp dh, 25; На строку вниз je L3 add dh, 1 jmp L3 left: cmp dl, 0; На столбец влево je L3 sub dl, 1 jmp L3 right: cmp dl, 80; На столбец вправо je L3 add dl, 1 L3: mov ah, 02h; Установить новую позицию курсора mov bh, 0 int 10h jmp F1 ; Вывод изображения всех символов таблицы ASCII, включая управляющие, в окно_1 в фор- ; мате " 16 x16". Символы в строке разделяются пробелами. F2: locate 8, 7, 1; row_1=8, col_1=7 mov al, 0; Первый символ ASCII с кодом 00h mov cx, 256; Счётчик циклов вывода ; Вывод символа любого кода ASCII, (включая управляющие) из AL в позицию курсора с ; координатами row_1, col_1 в окно_1 c последующим увеличением координаты курсора в ; строке на 2 позиции вправо cycle: push cx mov ah, 0Ah; Функция вывода символа с текущим атрибутом из al mov bh, 0; Номер страницы mov cx, 1; Число повторений символа int 10h; Вывести символ в текущую позицию inc al; Следующий символ test al, 0Fh; Если al не кратен 16 jnz L1; продолжить вывод в строке, add [row_1], 1; иначе увеличить номер строки на 2 mov [col_1], 7; Столбец = 7 jmp L2 L1: add [col_1], 2; Увеличить номер столбца на 2 L2: mov dh, [row_1] mov dl, [col_1] mov ah, 2; Функция установки курсора int 10h; Переместить курсор в позицию row_1, col_1 pop cx loop cycle jmp F1 ; Режим < F4> - вывод текста в окно_2 (блокнот). Переход на новую строку осуществляется ; кл. < Enter> с ASCII- кодом 0Dh, допускается редактирование текста клавишей < Backspace> F4: locate 11, 44, 2 repet: mov ah, 08h; Функция ввода ASCII- символа в AL без эха int 21h; ASCII- код в AL cmp al, 00h; Расширенный ASCII? je ex_ascii; Да cmp al, 08h; Управляющий код " назад" je erase; Да, сотрём предыдущий символ cmp al, 0Dh; ASCII- код равен 0Dh? jne out_symb; Нет, выводим символ на экран mov ah, 03h; Да, переходим на новую строку. Для этого ; вызовем функцию считывания текущей позиции курсора mov bh, 0; Номер страницы int 10h; Номер строки в DH, столбца в DL add dh, 1; Формирование координаты новой строки mov dl, 44; в окне_2 cmp dh, 23; Номер следующей строки равен 23? je scroll; Да, надо произвести прокрутку окна position: mov ah, 02h; Функция установки позиции курсора int 10h; Курсор установлен jmp repet; Продолжим вывод текста scroll: push dx Window 4, 0E4h, 11, 42, 23, 76; Прокрутка на 4 строки вверх pop dx sub dh, 4; Декремент строки на параметр прокрутки mov bh, 0; Номер страницы jmp position out_symb: mov ah, 0Eh; Функция вывода символа с текущим атрибутом mov bh, 0; в режиме телетайпа int 10h; Символ выведен jmp repet ; Стирание предыдущего символа путём вывода последовательности 08h, 20h, 08h erase: mov cx, 3 mov si, 0 @@1: mov al, [backspace+si] inc si mov ah, 0Eh; Функция вывода символа с текущим атрибутом в mov bh, 0; в режиме телетайпа int 10h; Символ выведен loop @@1 jmp repet ; Проверка запроса о выходе из режима набора текста в режим перетаскивания символов< F1> ex_ascii: mov ah, 08h; Введём старший байт ASCII- кода int 21h cmp al, 3Bh; Скан-код клавиши < F1>? je F1; Да, переходим в режим < F1> cmp al, 44h; Скан-код клавиши < F10>? je F10; Да, выходим из программы jmp repet; Нет, остаёмся в данном режиме ; Выход из программы с восстановлением режима обычной яркости F10: mov ax, 1003h; Вызов функции mov bl, 1; Мерцание символа int 10h Exit: mov ax, 4C00h; Функция DOS 4Сh: выход из программы int 21h; Вызов DOS. Останов END Start; Конец программы/точка входа
|