5.10.4. Видеоадаптеры VGA
VGA-совместимые видеоадаптеры управляются при помощи портов ввода-вывода ОЗСОЬ - 03CFh, 03B4h, 03B5h, 03D4h, 03D5h, 03DAh, причем реальное число внутренних регистров видеоадаптера, к которым можно обращаться через это окно, превышает 50. Так как BIOS предоставляет хорошую поддержку для большинства стандартных функций, мы не будем подробно говорить о программировании видеоадаптера на уровне портов, а только рассмотрим основные действия,
для которых принято обращаться к видеоадаптеру напрямую.
Внешние регистры контроллера VGA (03C2h - 03CFh)
Доступ к этим регистрам осуществляется прямым обращением к соответствующим портам ввода-вывода.
Регистр состояния ввода О (ISRO) - доступен для чтения из порта ОЗС2
бит 7: произошло прерывание обратного хода луча IRQ2
бит 6: дополнительное устройство 1 (линия FEAT1)
бит 5: дополнительное устройство 0 (линия FEATO)
бит 4: монитор присутствует Регистр вывода (MOR) - доступен для чтения из порта ЗССЪ и для записи как 3C2h
биты 7-6: полярность сигналов развертки: (01, 10, 11) = (400, 350, 480) линий бит 5: 1/0: нечетная/четная страница видеопамяти биты 3-2: частота: (00, 01) = (25,175 МГц, 28,322 МГц) бит 1: 1/0: доступ CPU к видеопамяти разрешен/запрещен бит 0: 1/0: адрес порта контроллера CRT = Регистр состояния ввода 1 (ISR1) - доступен для чтения из порта 03DAh
бит 3: происходит вертикальный обратный ход луча бит 0: происходит любой обратный ход луча
Лучшим моментом для вывода данных в видеопамять является тот, когда электронный луч двигается от конца экрана к началу и экран не обновляется, то есть вертикальный обратный ход луча. Перед копированием в видеопамять полезно вызывать, например, следующую процедуру:
: Процедура wait_retrace.
; Возвращает управление в начале обратного вертикального хода луча. :
wait_retrace proc near push ax
Программирование на уровне портов .'ШЯН
push |
dx |
|
mov |
dx,03DAh |
; Порт регистра ISR1. |
wait retrace |
end: |
|
in " |
al, dx |
|
test |
al,1000b |
; Проверить бит З. |
|
|
; Если не ноль - |
jnz |
wait_retrace_ |
end ; подождать конца текущего обратного хода, |
wait_retrace_ |
start: |
|
in |
' al,dx |
|
test |
al,1000b |
; а теперь подождать начала следующего. |
jz |
wait_retrace. |
.start |
pop |
dx |
|
pop |
ax |
|
ret |
|
|
wait_retrace |
endp |
|
Регистры контроллера атрибутов (ОЗСОЬ - 03C1h)
Контроллер атрибутов преобразовывает значения байта атрибута символа в цвета символа и фона. Надо записать в порт ОЗСОЬ номер регистра, а затем (второй командой out) - данные для этого регистра. Чтобы убедиться, что ОЗСОЬ находится в состоянии приема номера, а не данных, надо выполнить чтение из ISR1 (порт 03DAh). Порт 03Clh можно использовать для чтения последнего записанного индекса или данных.
OOh - OFh; Регистры палитры EGA
биты 5-0: номер регистра в текущей странице VGA DAC, соответствующего данному EGA-цвету Регистр управления режимом бит 7: разбиение регистров VGA DAC для 16-цветных режимов: 1 = 16 страниц по 16 регистров, 0 = 4 страницы по 64 регистра бит 6: 1 = 8-битный цвет, 0 = 4-битный цвет бит 5: горизонтальное панорамирование разрешено бит 3: 1/0: бит 7 атрибута управляет миганием символа/цветом фона
бит 2: девятый пиксел в каждой строке повторяет восьмой
бит 1: 1/0: генерация атрибутов для монохромных/цветных режимов бит 0: 1/0: генерация атрибутов для текстовых/графических режимов lih: Регистр цвета бордюра экрана (по умолчанию OOh)
биты 7-0: номер регистра VGA DAC
12h: Регистр разрешения использования цветовых плоскостей
бит 3: разрешить плоскость 3
бит 2: разрешить плоскость 2
бит 1: разрешить плоскость 1
бит 0: разрешить плоскость О 13h: Регистр горизонтального панорамирования
биты 3-0: величина сдвига по горизонтали в пикселах (деленная на 2 для режима 13h)
14h: Регистр выбора цвета (по умолчанию OOh)
Функции INT 10h AX = lOOOh - 1009h позволяют использовать большинство из этих регистров, но кое-что, например панорамирование, оказывается возможным только при программировании на уровне портов.
Регистры графического контроллера (ОЗСЕп - 03CFh)
Для обращения к регистрам графического контроллера следует записать индекс нужного регистра в порт ОЗСЕп, после чего можно будет читать и писать данные для выбранного регистра в порт 03CFh. Если требуется только запись в регистры, можно просто поместить индекс в AL, посылаемый байт - в АН и выполнить команду вывода слова в порт ОЗСЕп. Этот контроллер, в первую очередь, предназначен для обеспечения передачи данных между процессором и видеопамятью в режимах, использующих цветовые плоскости, как, например, режим 12h (640x480x16).
00h: Регистр установки/сброса
биты 3-0: записывать FFh в цветовую плоскость 3-0 соответственно Olh: Регистр разрешения установки/сброса
биты 3-0: включить режим установки/сброса для цветовой плоскости 3-0
В этом режиме данные для одних цветовых слоев получают от CPU,
а для других - из регистра установки/сброса. Режим действует
только в нулевом режиме работы (см. регистр 05h).
02h: Регистр сравнения цвета
биты 3-0: искомые биты для цветовых плоскостей 3-0
Используется для поиска пиксела заданного цвета, чтобы не обращаться по очереди во все цветовые слои.
03h: Регистр циклического сдвига данных
биты 4-3: выбор логической операции:
00 - данные от CPU записываются без изменений
01 - операция AND над CPU и регистром-защелкой
10 - операция OR над CPU и регистром-защелкой
11 - операция XOR над CPU и регистром-защелкой
биты 2-0: на сколько битов выполнять вправо циклический сдвиг данных перед записью в видеопамять
04h: Регистр выбора читаемой плоскости биты 1-0: номер плоскости (0-3)
. Запись сюда изменяет номер цветовой плоскости, данные из которой получает CPU при чтении из видеопамяти.
05h: Регистр выбора режима работы
бит 6: 1/0: 256/16 цветов
бит 4: четные адреса соответствуют плоскостям 0, 2; нечетные - 1, 3 бит 3: 1 режим сравнения цветов
биты 1-0: режим:
00: данные из CPU (бит на пиксел) + установка/сброс + циклический сдвиг + логические функции
!
01: данные в/из регистра-защелки (прочитать в него и записать в другую область памяти быстрее, чем через CPU)
10: данные из CPU, байт на пиксел, младшие 4 бита записываются в соответствующие плоскости то же самое + режим битовой маски 06h: Многоцелевой регистр графического контроллера биты видеопамять:
00: OAOOOOh - OBFFFFh (128 Кб)
01: OAOOOOh - OAFFFFh (64 Кб)
10: OBOOOOh - 0B7FFFh (32 Кб)
11: 0B8000h - OBFFFFh (32 Кб)
бит 0: 1/0: графический/текстовый режим
07h: Регистр игнорирования цветовых плоскостей биты 3-0: игнорировать цветовую плоскость
08h: Регистр битовой маски
Если бит этого регистра 0, то соответствующий бит будет браться из регистра-
защелки, а не из CPU. (Чтобы занести данные в регистр-защелку, надо выполнить одну операцию чтения из видеопамяти, при этом в каждый из четырех регистров-защелок будет помещено по одному байту из соответствующей
цветовой плоскости.)
Графический контроллер предоставляет весьма богатые возможности по управлению режимами, использующими цветовые плоскости. В качестве примера напишем процедуру, выводящую точку на экран в режиме 12h (640x480x16) с применением механизма установки/сброса.
; Процедура putpixel12h.
; Выводит на экран точку с заданным цветом в режиме 12h (640x480x16).
; Вход: DX = строка
СХ = столбец
; BP = цвет
; ES = OAOOOh
proc near
pusha
, Вычислить номер байта в видеопамяти.
xor |
bx,bx |
|
mov |
ax, dx |
; АХ = строка. |
lea |
eax, [eax+eax*4] |
; АХ = АХ х 5. |
shl |
ax, 4 |
; АХ = АХ х 16. |
|
|
; АХ = строка х байт в строке |
|
|
; (строка х 80). |
push |
cx |
|
shr |
cx,3 |
; СХ = номер байта в строке. |
add |
ax, |
; АХ = номер байта в видеопамяти. |
mov |
di, ax |
; Сохранить его в БІ. |
|
|
; Вычислить номер бита в байте. |
pop |
cx |
|
Сложные приемы программирования
and |
cx,07h |
; Остаток от деления на 8 - номер ; бита в байте, считая справа налево. |
mov |
bx,0080П |
|
shr |
bx, |
; В ВЬ теперь нужный бит установлен в 1. ; Программирование портов. |
mov |
dx,03CEh |
; Индексный порт -. графического контроллера. |
mov |
ax,0F01h |
; Регистр 01п: разрешение ; установки/сброса. |
out |
dx, ax |
; Разрешить установку/сброс для : всех плоскостей (эту часть лучше |
сделать однажды в программе, например сразу после установки видеорежима, и не повторять каждый раз при вызове процедуры).
mov |
ах, bp |
|
shl |
ах, 8 |
Регистр регистр |
|
|
; установки/сброса. |
out |
dx, ах |
; АН = цвет. |
mov |
al,08 |
; Порт 08п: битовая маска. |
mov |
ah, Ы |
; Записать в битовую маску нули |
|
|
: всюду, кроме |
out |
dx, ах |
; бита, соответствующего выводимому |
mov |
ah, byte |
еБ:№] ; Заполнить |
,
mov
es: fdi J. аґп
,
бит
регистры-защелки.
Вывод на экран: ; выводится единственный ; в соответствии с содержимым регистра битовой маски, осталвные ; биты берутся из защелки, то еств не изменяются. Цвет выводимого ; бита полноствю определяется значением регистра установки/сброса, рора ret
putpixel12h endp
Регистры контроллера CRT (03D4h - 03D5h)
Контроллер CRT управляет разверткой и формированием кадров на дисплее. Как и для графического контроллера, чтобы обратиться к регистрам контроллера CRT, следует записать индекс нужного регистра в порт 03D4h, после чего можно будет читать и писать данные для выбранного регистра в порт 03D5h. Если требуется только запись в регистры, можно просто поместить индекс в AL, посылаемый байт — в АН и выполнить команду вывода слова в порт 03D4h.
OOh: общая длина горизонтальной развертки
Olh: длина отображаемой части горизонтальной развертки минус один 02h: начало гашения луча горизонтальной развертки 03h: конец гашения луча горизонтальной развертки
биты 6—5: горизонтальное смещение в текстовых режимах . .
биты 4-0: конец импульса 04h: начало горизонтального обратного хода луча
05п: конец горизонтального обратного хода луча
биты 7, 4-0: конец импульса
биты 6-5: горизонтальное смещение импульса 06Ь: число вертикальных линий растра без двух старших битов 07Ь: дополнительный регистр .
бит 7: бит 9 регистра 10Ь ■
бит 6: бит 9 регистра 12п
бит 5: бит 9 регистра 061т
бит 4: бит 8 регистра 18Ь
бит 3: бит 8 регистра 15Ь
бит 2: бит 8 регистра 10Ь
бит 1: бит 8 регистра 12п
бит 0: бит 8 регистра 06п 08Ь: предварительная горизонтальная развертка
биты 6-5: биты 5 и 4 регистра горизонтального панорамирования
биты 4-0: номер линии в верхней строке, с которой начинается изображение 09Ь: высота символов
бит 7: двойное сканирование (400 линий вместо 200)
бит 6: бит 9 регистра 18Ь
бит 5: бит 9 регистра 15Ь
биты 4-0: высота символов минус один (от 0 до 31) ОАЬ: начальная линия курсора (бит 5: гашение курсора) ОВЬ: конечная линия курсора (биты 6-5: отклонение курсора вправо) ОСЬ: старший байт начального адреса
СЮЬ: младший байт начального адреса (это адрес в видеопамяти, начиная с которого выводится изображение)
ОЕЬ: старший байт позиции курсора ОРЬ: младший байт позиции курсора
10Ь: начало вертикального обратного хода луча без старшего бита конец вертикального обратного хода луча без старшего бита бит 7: защита от записи в регистры 00-07 (кроме бита 4 в 07Ь) бит 6: 1/0: 5/3 цикла регенерации за время обратного хода луча бит 5: 1/0: выключить/включить прерывание по обратному ходу луча бит 4: запись нуля сюда заканчивает обработку прерывания биты 3-0: конец вертикального обратного хода луча
12Ь: число горизонтальных линий минус один без двух старших битов
13Ь: логическая ширина экрана (в словах/двойных словах на строку)
14Ь: положение символа подчеркивания
бит 6: 1/0: адресация словами/двойными словами бит 5: увеличение счетчика адреса регенерации на 4 биты 4-0: положение подчеркивания
15Ь: начало импульса гашения луча вертикальной развертки без двух старших битов
16Ь: конец импульса гашения вертикальной развертки
17Ь: регистр управления режимом
бит 7: горизонтальный и вертикальный ходы луча отключены бит 6: 1/0 - адресация байтами/словами бит 4: 1 - контроллер выключен
бит 3: 1/0 - счетчик адреса регенерации растет на 2/1 на каждый символ бит 2: увеличение в 2 раза разрешения по вертикали 18h: регистр сравнения линий без двух старших битов
(от начала экрана до линии с номером из этого регистра отображается начало видеопамяти, а от этой линии до конца - видеопамять, начиная с адреса, указанного в регистрах и ODh) 22h: регистр-защелка (только для чтения) 23h: состояние контроллера атрибутов
биты 7-3: текущее значение индекса контроллера атрибутов бит 2: источник адреса палитры
бит 0: состояние порта контроллера атрибутов: 0/1 = индекс/данные
BIOS заполняет регистры этого контроллера соответствующими значениями при переключении видеорежимов. Поскольку одного контроллера CRT мало для полного переключения в новый видеорежим, мы вернемся к этому чуть позже,
а пока посмотрим, как внести небольшие изменения в действующий режим, например: как превратить текстовый режим 80x25 в 80x30:
; 80x30.asm
; Переводит экран в текстовый режим 80x30 (размер символов 8x16)
; (Norton Commander 5.0 в отличие от, .например, FAR восстанавливает режим по .
; окончании программы, но его можно обмануть, если предварительно нажать Alt-F9).
'start:
tiny |
|
|
. code |
|
|
.186 |
|
Для команды outsw. |
org |
lOOh |
СОМ-программа. |
mov |
ax,3 |
Установить режим 03h (80X25), |
int |
10h |
только внести небольшие изменения. |
mov |
dx,3CCh |
Порт регистр вывода на чтение. |
in |
al.dx |
|
mov |
dl,0C2h |
Порт 03C2h: регистр вывода (MOR) на запись. |
or |
al.OCOh |
Установить полярности І; І - для 480 строк. |
out |
dx, al |
|
mov |
dx,03D4h |
DX = порт 03D4h: индекс CRT. |
mov |
si .offset crt480 |
DS:SI = адрес таблицы данных для CRT. |
mov |
cx,crt480_l |
СХ = ее размер. |
rep |
outsw |
Послать все устанавливаемые параметры в порты |
03D4h и 03D5h.
Нельзя забывать сообщать BIOS об изменениях в видеорежиме.
push 0040h
pop es ; ES = 0040h.
mov byte ptr es:[84h],29 ; 0040h:0084h - число строк, ret
; Данные-для контроллера CRT в формате индекс в младшем байте, данные ; в старшем - для записи при помощи команды outsw.
crt480 dw OC11h ; Регистр 11h всегда надо записывать первым,
; так как его бит 7 разрешает запись в другие
dw OB06h,.3E07h,0EA1Oh,0DF12h,0E715h,0416h ; регистры.
crt480_l = ($-crt480)/2
end start
Еще одна интересная возможность, которую предоставляет контроллер CRT, -плавная прокрутка экрана при помощи регистра 08h:
; vscroll.asm
; Плавная прокрутка экрана по вертикали. Выход - клавиша Esc.
.model |
tiny |
|
.code |
|
|
.186 |
|
Для push OB400h. |
orglOOh |
|
СОМ-программа. |
start: |
|
|
push |
OB800h |
|
pop |
es |
|
xor |
si,si |
; ES:SI - начало видеопамяти. |
mov |
di,80*25*2 |
; ES:DI - начало второй страницы видеопамяти. |
mov |
cx, di |
|
rep movs |
es:any_label,es:any_label ; Скопировать первую страницу во вторую. |
|
mov |
dx,G3D4h |
; Порт G3D4h: индекс CRT. |
screen_loop: |
|
Цикл по экранам. |
mov |
cx,80*12*2 |
CX = начальный адрес - адрес середины экрана. |
line_lpop: |
|
Цикл по строкам. |
mov |
al.OCh |
Регистр ОСЬ - старший байт начального адреса. |
mov |
ah, ch |
Байт данных - СН. |
out |
dx, ax |
Вывод в порты G3D4, G3D5. |
inc |
ax |
Регистр ODh - младший байт начального адреса. |
mov |
ah, cl |
Байт данных - CL. |
out |
dx, ax |
Вывод в порты G3D4, G3D5. |
mov |
bx,15 |
Счетчик линий в строке. |
sub |
cx, 8G |
Переместить начальный адрес на начало |
|
|
предыдущей строки (так как это движение вниз). |
pel_loop: |
|
Цикл по линиям в строке. ' |
call |
wait_retrace |
Подождать обратного хода луча. |
mov |
al,8 |
Регистр - выбор номера линии в первой |
|
|
строке, с которой начинается вывод изображения |
mov |
ah.bl |
(номер линии из BL). |
out |
dx,ax |
|
dec jge
wait_retrace
any_label
end
bx
pel_loop
Уменьшить число линий.
Если больше или равно нулю -
прокрутилась до конца и цикл
продолжается.
строка еще по линиям
|
in |
al,60h |
Прочитать скан-код последнего символа. |
|
cmp |
al,8lh |
Если это 81 h (отпускание клавиши Esc), |
|
jz |
done |
выйти из программы. |
|
cmp |
cx,0 |
Если еще не прокрутился целый экран, |
|
jge |
line_loop |
продолжить цикл по строкам. |
|
jmp |
short screen_loop |
Иначе: продолжить цикл по экранам. |
done: |
|
|
Выход из программы. |
|
mov |
ax, 8 |
Записать в регистр CRT 08h |
|
out |
dx, ax |
байт 00 (никакого сдвига по вертикали), |
|
add |
ax, 4 |
а также 00 в регистр |
|
out |
ax |
|
|
inc |
ax |
и ODh (начальный адрес |
|
out |
dx, ax |
с началом |
|
ret |
|
|
wait_retrace |
proc near |
|
|
|
push |
dx |
|
|
mov |
dx,03DAh |
|
VRTL1: |
in |
dx |
Порт 03DAh - регистр ISR1. |
|
test |
al,8 |
|
|
j.nz |
VRTL1 |
Подождать конца текущего обратного хода |
VRTL2: |
in |
al, dx |
|
|
test |
al,8 |
|
|
U |
VRTL2 |
а теперь начала следующего. |
|
pop |
dx |
|
|
ret |
|
|
endp
label byte start
Метка для переопределения сегмента в
Горизонтальная прокрутка осуществляется аналогично, только с использованием регистра горизонтального панорамирования Ш из контроллера атрибутов.
Регистры синхронизатора (03С4п - ОЗСБЬ)
Для обращения к регистрам синхронизатора следует записать индекс нужного регистра в порт 03C4h, после чего можно будет читать и писать данные для выбранного регистра в порт 03C5h. Точно так же, если требуется только запись в регистры, можно просто поместить индекс в AL, посылаемый байт - в АН и выполнить команду вывода слова в порт
ООЬ: регистр сброса синхронизации
бит 1: запись нуля сюда вызывает синхронный сброс бит 0: запись нуля сюда вызывает асинхронный сброс
Olh: регистр режима синхронизации
бит 5: 1; обмен данными между видеопамятью и дисплеем выключен
бит 3: 1: частота обновления для символов уменьшена в два раза
бит 0: 1/0: ширина символа 8/9 точек 02h: регистр маски записи
бит 3: разрешена запись CPU в цветовую плоскость 3
бит 2: разрешена запись CPU в цветовую плоскость 2
бит 1: разрешена запись CPU в цветовую плоскость 1
бит 0: разрешена запись CPU в цветовую плоскость О 03h: регистр выбора шрифта
бит 5: если бит 3 атрибута символа = 1, символ берется из шрифта 2
бит 4: если бит 3 атрибута символа = 0, символ берется из шрифта 2
биты 3-2: номер таблицы для шрифта 2 биты 1-0: номер таблицы для шрифта 1
(00, 01, 10, 11) = (О Кб, 16 Кб, 32 Кб, 48 Кб от начала памяти шрифтов VGA) 04h: регистр организации видеопамяти
бит 3: 1: режим CHAIN-4 (используется только в видеорежиме 13К) бит 2: 0: четные адреса обращаются к плоскостям 0, 2, нечетные - к 1, 3 бит 1: объем видеопамяти больше 64 Кб
Даже несмотря на то, что BIOS позволяет использовать некоторые возможности этих регистров, в частности работу со шрифтами (INT 10h АН = llh) и выключение обмена данными между видеопамятью и дисплеем (INT 10h, АН = 12h, 32h), прямое программирование регистров синхронизатора вместе с регистрами контроллера CRT разрешает изменять характеристики видеорежимов VGA, вплоть до установки нестандартных видеорежимов. Наиболее популярными режимами являются так называемые режимы X с 256 цветами и с разрешением 320 или 360 пикселов по горизонтали и 200, 240, 400 или 480 пикселов по вертикали. Поскольку такие режимы не поддерживаются BIOS, для их реализации нужно написать все необходимые процедуры - установку видеорежима, вывод пиксела, чтение пиксела, переключение страниц, изменение палитры, загрузку шрифтов. При этом для всех режимов из этой серии, кроме 320x240x256, приходится также учитывать измененное соотношение размеров экрана по вертикали и горизонтали, чтобы круг, выведенный на экран, не выглядел как эллипс, а квадрат - как прямоугольник.
Установка нового режима выполняется почти точно так же, как и в предыдущем примере, - путем модификации существующего. Кроме того, нам придется изменять частоту кадров (биты 3-2 регистра а это приведет к сбою синх-
ронизации, если мы не выключим синхронизатор на время изменения частоты (записью в регистр 00h):
; Процедура setjnodex.
; Переводит видеоадаптер VGA в один из режимов X с 256 цветами.
; Вход: 01 = номер режима
; 0: 320x200, соотношение сторон 1,2:1
; 1: 320x400, соотношение сторон 2,4:1
360x200, соотношение сторон 1,35:1
360x400, соотношение сторон 2,7:1
320x240, соотношение сторон 1:1
320x480, соотношение сторон 2:1
360x240, соотношение сторон 1,125:1
360x480, соотношение сторон 2,25:1 = С8
Для вывода информации на экран в этих режимах см. процедуру ри!р1хе!_х
2: 3: 4:
5: 6: 7:
DS
setmode х
mov 4nt mov int
cmp
ja
shl
mov mov
out
mov
out
mov mov
out
mov
mov rep
mov rep
proc near ax,12h 10h
ax,13h 10h
di,7
exitjnodex di,1
ptr
Очистить все четыре цветовые плоскости видеопамяти. Установить режим 13І1, который будем модифицировать.
Если нас вызвали с БІ > 7, выйти из процедуры (оставшись в режиме 131т). Умножить на 2, так как х_тогіез -таблица слов. х_шос^[(И] ; Прочитать
адрес таблицы настроек для выбранного режима.
dx,03C4h ;
ах,OlOOh ;
dx.ax ;
ах,0604h ;
ax
dl,0C2h ;
al.byte ptr [di] ;
dx.al ;
dl,0D4h
si,word ptr offset
cx,a
outsw si,word ptr offset
cx, 7
outsw
Порт 03C4h - индекс синхронизатора.
Регистр OOh, значение 01. Асинхронный сброс. Регистр 04h, значение 06h. Отключить режим CHAIN4.
Порт 03С2П - регистр M0R на запись. Записать в него значение частоты кадров и полярности развертки для выбранного режима.
Порт 03D4h - индекс контроллера CRT. [di+2J
Адрес строки с настройками
для выбранной ширины в DS:SI. Длина строки настроек в СХ. Вывод строки слов в порты 03D4/03D5. [di+4] ; Настройки для выбранной высоты в DS:SI.
строки настроек в СХ/
mov
mov rep
mov mov
mov mov out
exit_modex:
ret ptr offset • Настройки
; для включения/выключения удвоения
; по вертикали (200/400 и 240/480 строк).
сх,3
outsw
ах, word ptr offset [di+8] word ptr x_width,ax
• Число байтов в
Сохранитв в переменной x.width.
dl,OC4h ax,0300h dx, ax
Порт 03С4п - индекс синхронизатора.
Регистр ООП, значение 03. Выйти из состояния сброса.
; Таблица адресов таблиц с настройками режимов, xjrodes dw offset mode_0,offset mode_1
dw offset mode_2,offset mode 3
dw offset mode 4,offset mode_5
dw offset mode_6,offset mode_7
; Таблица настроек режимов: значение регистра MOR, адрес строки ; настроек ширины, адрес строки настроек высоты, адрес строки ; настроек удвоения по вертикали, число байтов в строке.
63h,offset mode_320w,offset mode_200h,offset mode.double,320/4 63h,offset mode_320w,offset mode_400h,offset mode_single,320/4 67h,offset mode_360w,offset mode_200h,offset mode_double,360/4 67h,offset mode„360w,offset mode_400h,offset mode_single,360/4 0E3h,offset mode J320w,offset mode_240h,offset mode_double,320/4 0E3h,offset mode_320w,offset mode_480h,offset mode_single,320/4 0E7h,offset mode_360w,offset mode_240h,offset
mode_0 |
dw |
mode 1 |
dw |
mode_2 |
dw |
mode_3 |
dw |
mode_4 |
dw |
mode_5 |
dw |
mode_6 |
dw |
mode 7 |
dw |
• Настройки
; старший -mode_320w: •
0E7h,offset mode_360w,offset
В каждом слове младший байт
mode_double,360/4 mode_480h,offset mode_single,360/4
- номер регистра, в этот регистр заносится. ; Настройка ширины 320. Первый регистр обязательно 11п, хотя он и не относится к ширине, но разрешает запись в остальные регистры, если она была запрещена
CRT.
значение,
которое
(!)■
dw
mode_360w:
dw
mode_200h:
mode_400h:
dw
mode_240h: mode_480h:
dw
mode_single:
dw
mode_double:
dw
setmode_x 0Е11П, 5Р00п, 4Р01И, 5002г1,8203г1,5404п,8005п,2813г1
; Настройка ширины 360. ОЕНЬ, 6В00Г1, 5901П, 5А02г., ЗЕОЗг., 5Е04И, 8А05И, 2013И
; Настройка высоты 200/400. ОВРОбГ!, 1Р07п, 9010(1, 0Е11п, 8Р12г>, 9615И, 08916)1
; Настройка высоты 240/480. ОРОбП, ЗЕ07И, ОЕАЮИ, 0С11Г1, 00Е12Ь, 0Е715И, 0616п
; Настройка режимов без удвоения. 4009п,0014п,ОЕ317п
; Настройка режимов с удвоением. 410911, 0014П, 0Е317П
епбр
; Число байтов в строке.
; Эту переменную инициализирует зет.тос1е_х, а использует риср1хе1_х.
Процедура
Выводит точку с заданным цветом
в текущем режиме X.
; Вход: DX = |
строка |
|
; СХ = |
столбец |
|
; ВР = |
цвет |
|
; ES = |
OAOOOh |
|
; DS = |
сегмент, в |
котором находится переменная |
putpixel_x |
proc |
near |
pusha |
|
|
mov |
ax, dx |
|
шиї |
word ptr |
x_width ; AX = строка х число байтов в строке. |
mov |
di,cx |
; ' DI = столбец. |
shr |
di,2 |
; DI = столбец/4 (номер байта в строке). |
add |
di, ax |
; 01 = номер байта в видеопамяти/ |
mov |
ax,0102h |
; AL = 02h (номер регистра). |
|
|
; АН = 01 (битовая маска). |
and |
cl,03h |
CL = остаток от деления столбца на 4 = |
|
|
номер цветовой плоскости. |
shl |
ah, cl |
Теперь в АН выставлен в 1 бит, |
|
|
соответствующий нужной цветовой плоскости. |
mov |
dx,03C4h |
Порт - индекс синхронизатора. |
out |
dx, ax |
Разрешить запись только |
|
|
в нужную плоскость. |
mov |
ax, bp |
Цвет в AL. |
stosb |
|
Вывод байта в видеопамять. |
рора |
|
|
ret |
|
|
putpixel_x |
endp |
|
Регистры VGA DAC (3C6h - 3C9h)
Таблица цветов VGA на самом деле представляет собой 256 регистров, в каждом из которых записаны три 6-битных числа, соответствующих уровням красного, зеленого и синего цвета. Подфункции INT lOhAX = 1010b. - 101Bh позволяют
удобно работать с этими регистрами, но, если требуется максимальная скорость,
программировать их на уровне портов ввода-вывода не намного сложнее.
03C6h для чтения/записи: регистр маскирования пикселов (по умолчанию OFFh) При обращении к регистру DAC выполняется операция AND над его номером и содержимым этого регистра.
03C7h для записи: регистр индекса DAC для режима чтения
Запись байта сюда переводит DAC в режим чтения, так что следующее чтение из вернет значение регистра палитры с этим индексом.
03С7п для чтения: регистр состояния DAC
биты 1-0: ООЬ/ИЬ - DAC в режиме записи/чтения
03С8п для чтения/записи: регистр индекса DAC для режима записи
Запись байта сюда переводит DAC в режим записи, поэтому дальнейший вывод в 03C9h будет приводить к записи новых значений в регистры палитры, начиная с этого индекса.
03C9h для чтения/записи: регистр данных DAC
Чтение отсюда считывает значение регистра палитры с индексом, помещенным предварительно в 03C8h, запись - записывает новое значение в регистр палитры с индексом, находящимся в 03C8h. На каждый регистр требуются три операции чтения/записи, передающие три 6-битных значения уровня цвета: красный, зеленый, синий. После третьей операции чтения/записи индекс текущего регистра палитры увеличивается на 1, так что можно считывать/записывать сразу несколько регистров
Команды insb/outsb серьезно облегчают работу с регистрами DAC в тех случаях, когда требуется считывать или загружать значительные участки палитры или всю палитру целиком, - такие процедуры оказываются и быстрее, и меньше аналогичных, написанных с использованием прерывания INT 10h. Посмотрим, как это реализуется на примере программы плавного гашения экрана.
; fadeout.asm
; Выполняет плавное гашение экрана.
.model tiny
start:
. code .186
org
eld mov
call
mov call
mov
main_loop:
push
call
mov mov call
call
mov
call
pop 100h
di, offset palettes read_palette
di, offset palettes+256*3 read_palette
CX, 64
cx
wait_retrace
di,offset palettes+256-
si, di
dec_palette
wait_retrace
si,offset palettes+256*
write_palette
cx
Для команд шзЬ/оибзЬ. СОМ-программа.
Для команд строковой обработки.
Сохранить текущую палитру, чтобы восстановить в самом конце программы,
а также записать еще одну копию текущей палитры, которую будем модифицировать.
Счетчик цикла изменения палитры.
Подождать начала обратного хода луча.
Уменьшить яркость всех цветов. Подождать начала следующего
обратного хода луча.
Записать новую палитру.
loop
ШОУ
саіі
гес
main_loop
palettes
write_palette
Цикл выполняется 64 раза - достаточно для обнуления самого яркого цвета (максимальное значение 6-битной компоненты - 63).
Восстановить первоначальную палитру. Конец программы.
чтения.
; 'Процедура |
read_palette. |
|
; Помещает палитру УОА в строку |
по адресу ЕЭ:01. |
|
read_palette |
proc near |
|
mov |
dx,03C7h |
; Порт 03С7п - индекс БАС/режим |
mov |
al,0 |
; Начинать с нулевого цвета. |
out |
dx, al |
|
mov |
dl,0C9h |
; Порт ОЗСЭИ - данные БАС. |
mov |
cx,256*3 |
; Прочитать 256 х 3 байт |
rep |
insb |
; в строку по адресу ЕБ:01. |
ret |
|
|
read_palette |
endp |
|
; Процедура write_palette. |
|
|
Загружает в |
DAC VGA палитру из |
строки по адресу 08:81. |
write_palette |
proc near |
|
mov |
dx,03C8h |
; Порт 03С8І1 - индекс БАС/режим |
mov |
al,0 |
Начинать с нулевого цвета. |
out |
dx,al |
|
mov |
dl,0C9h |
; Порт ОЗСЭп - данные БАС. |
mov |
cx,256*3 |
; Записать 256 х 3 байт |
rep |
outsb |
; из строки в 05:51. |
записи.
гес
ягіве_раМве
endp
Процедура аес_ра1еббе.
Уменьшает значение каждого байта на 1 с насыщением (то есть, после того как байт становится равен нулю, он больше не уменьшается) из строки в 08:81 и записывает результат в строку в Б8:81.
dec_paiette
. mov
dec_ioop:
• lodsb test
jz
dec
already_zero:
stosb
loop ret
dec_palette
proc near cx,256*3
al.al
already_zero ax
dec^loop
Длина строки 256 х 3 байт.
Прочитать байт. Если он ноль,
пропустить следующую команду. Уменьшить байт на 1.
Записать его обратно. Повторить 256 х 3 раз.
endp
; Процедура w-ait_r.etr.ace. '
; Ожидание начала следующего обратного хода луча.
wait_retrace push
proc
dx near
mov in
dx,03DAh
VRTL1:
al, dx
al,8
VRTL1
al.dx al,8
VRTL2 dx
Порт
регистр ISR1.
test
jnz in
Подождать конца текущего обратного хода луча.
VRTL2:
test
pop ret
А теперь начала следующего.
wait_retrace
endp
palettes:
За концом программы мы храним две копии палитры - всего 1,5 Кб.
end start