| [Назад] [Далее] | ![]() |
Все, что изображено на мониторе — и графика, и текст, одновременно присутствует в памяти, встроенной в видеоадаптер. Для того чтобы изображение появилось на мониторе, оно должно быть записано в память видеоадаптера. Для этого отводится специальная область памяти, начинающаяся с абсолютного адреса B800h:0000h (для текстовых режимов) и заканчивающаяся на B800h:FFFFh. Все, что программы пишут в эту область памяти, немедленно пересылается в память видеоадаптера. В текстовых режимах для хранения каждого изображенного символа используются два байта: байт с ASCII-кодом символа и байт с его атрибутом, так что по адресу B800h:0000h лежит байт с кодом символа, находящимся в верхнем левом углу экрана; по адресу B800h:0001h лежит атрибут этого символа; по адресу B800h:0002h лежит код второго символа в верхней строке экрана и т.д.
Таким образом, любая программа может вывести текст на экран простой командой пересылки данных, не прибегая ни к каким специальным функциям DOS или BIOS.
; dirout.asm
; Выводит на экран все ASCII-символы без исключения,
; используя прямой вывод на экран
.model tiny
.code
.386 ; будет использоваться регистр ЕАХ
; и команда STOSD
org 100h ; начало СОМ-файла
start:
mov ax,0003h
int 10h ; видеорежим 3 (очистка экрана)
cld ; обработка строк в прямом направлении
; подготовка данных для вывода на экран
mov еах,1F201F00h ; первый символ 00 с атрибутом 1Fh,
; затем пробел (20h) с атрибутом 1Fh
mov bx,0F20h ; пробел с атрибутом 0Fh
mov cx,255 ; число символов минус 1
mov di,offset ctable ; ES:DI - начало таблицы
cloop:
stosd ; записать символ и пробел в таблицу ctable
inc al ; AL содержит следующий символ
test cx,0Fh ; если СХ не кратен 16,
jnz continue_loop ; продолжить цикл,
push cx ; иначе: сохранить значение счетчика
mov cx,80-32 ; число оставшихся до конца строки символов
xchg ax,bx
rep stosw ; заполнить остаток строки пробелами
; с атрибутом 0F
xchg bx.ax ; восстановить значение ЕАХ
pop cx ; восстановить значение счетчика
continue_loop:
loop cloop
stosd ; записать последний (256-й) символ и пробел
; собственно вывод на экран
mov ax,0B800h ; сегментный адрес видеопамяти
mov es,ax
xor di,di ; DI = 0, адрес начала видеопамяти в ES:DI
mov si,offset ctable ; адрес таблицы в DS:SI
mov cx,15*80+32 ; 15 строк по 80 символов, последняя строка - 32
rep movsw ; скопировать таблицу ctable в видеопамять
ret ; завершение СОМ-файла
ctable: ; Данные для вывода на экран начинаются сразу
; за концом файла. В ЕХЕ-файле такие данные
; определяют в сегменте .data?
end start
При подготовке данных для копирования в видеопамять в этой программе использовался тот факт, что в архитектуре Intel при записи слова (или двойного слова) в память старший байт располагается по старшему адресу. Так что при записи в память двойного слова 1F201F00h сначала записывается самый младший байт 00h (ASCII-код текущего символа), потом 1Fh, используемый в этом примере атрибут, потом 20h (код пробела) и потом, по самому старшему адресу, — самый старший байт, 1Fh, атрибут для этого пробела. Кроме того, в этом примере использовались некоторые 32-битные команды (MOV и STOSD). Этими командами можно пользоваться из 16-битной программы (разумеется, если процессор 80386 и выше), но не стоит этим злоупотреблять, так как каждая такая команда оказывается длиннее на 1 байт и выполняется дольше на 1 такт.