В этой главе мы опишем все основные регистры видеоадаптеров EGA, VGA и SVGA, которые могут быть полезны при написании программ. Программирование видеоадаптеров на уровне регистров позволяет увеличить скорость работы программ и решить некоторые задачи, которые нельзя решить только при помощи функций BIOS.
Непосредственное использование регистров может вызвать ряд проблем при переносе ваших программ на другие машины. Дело в том, что не все адаптеры совместимы на уровне регистров. Например, оригинальный видеоадаптер CGA создан на основе микросхемы Motorola 6845, а видеоадаптеры EGA и VGA используют более совершенный аналог этой микросхемы. Некоторые регистры CGA располагаются по другим адресам и могут выполнять какие-либо дополнительные функции, чем регистры EGA и VGA. Кроме того, в каждом новом видеоадаптере SVGA расширяется набор используемых регистров.
Существуют модели видеоадаптеров EGA, VGA и SVGA, поддерживающие режим совместимости, когда они эмулируют адаптеры более низкого уровня (например MDA, Hercules, CGA). Эмуляция обычно происходит на уровне регистров, что гарантирует полную их совместимость. Режимы совместимости, если они поддерживаются, описаны в руководстве данного видеоадаптера.
На практике, для управления видеоадаптерами, рекомендуется преимущественно использовать функции BIOS. Это избавит вас от неприятных минут, когда ваша работающая программа, при переносе на другую машину перестанет правильно выполняться.
Видеоадаптеры EGA, VGA и SVGA имеют большое количество регистров. Адаптер EGA имеет около шестидесяти регистров, а VGA и SVGA еще больше. Большая часть регистров EGA доступна только для записи, что создает определенные проблемы, особенно для мультизадачных систем.
Некоторые фирмы-изготовители видеоадаптеров выпускают платы видеоадаптеров совместимые с EGA, для регистров которых разрешена также и операция чтения. В адаптерах VGA и SVGA практически все регистры доступны как для записи, так и для чтения.
Доступ к большинству регистров видеоадаптеров осуществляется в два этапа: через один порт ввода/вывода выбирается номер интересующего вас регистра, а затем через другой порт ввода/вывода осуществляется обмен данными. Такая организация регистров позволяет сэкономить большое количество портов центрального процессора. Остальные регистры адресуются непосредственно через соответствующие порты ввода/вывода - каждому регистру соответствует один порт ввода/вывода.
Заметим, что в различных режимах работы видеоадаптера, его регистры могут иметь различные адреса.
Приведем список адресов регистров в монохромных режимах:
Адрес |
Регистр |
3C2h |
Регистр определения различных режимов работы (Miscellaneous Output Register - MOR), |
3BAh |
Регистр управления дополнительным устройством (Feature Control Register), |
3BBh |
Регистр очистки защелки светового пера (Clear Light Pen Latch Register- CLPLR) |
3BCh |
Установка защелки светового пера (Set Light Pen Latch Register - SLPLR) |
3C4h, 3C5h |
Регистры синхронизатора (Sequencer Register's - SR) |
3B4h, 3B5h |
Регистры контроллера ЭЛТ (CRT Controller Register's - CRT_CR) |
3CAh, 3CCh, 3CEh, 3CFh |
Регистры графического контроллера (Graphics Controller Register's - GCR) |
3C0h |
Регистр контроллера атрибутов (Attribute Controller Register - ACR) |
3C3h |
Регистр разрешения работы системы VGA (VGA Enable Register - VGA_ER) |
3C6h, 3C7h, 3C8h, 3C9h |
Регистры цифро-аналогового преобразователя (ЦАП) VGA (VGA Video DAC Register - VGA_DAC_R) |
А теперь перечислим адреса тех же регистров, но уже для цветных режимов видеоадаптера:
Адрес |
Регистр |
3C2h |
Регистр определения различных режимов работы (Miscellaneous Output Register - MOR), |
3DAh |
Регистр управления дополнительным устройством Feature Control Register), |
3DBh |
Регистр очистки защелки светового пера (Clear Light Pen Latch Register- CLPLR) |
3DCh |
Установка защелки светового пера (Set Light Pen Latch Register - SLPLR) |
3C4h, 3C5h |
Регистры синхронизатора (Sequencer Register's - SR) |
3D4h, 3D5h |
Регистры контроллера ЭЛТ (CRT Controller Register's - CRT_CR) |
3CAh, 3CCh, 3CEh, 3CFh |
Регистры графического контроллера (Graphics Controller Register's - GCR) |
3C0h |
Регистр контроллера атрибутов (Attribute Controller Register - ACR) |
3C3h |
Регистр разрешения работы системы VGA (VGA Enable Register - VGA_ER) |
3C6h, 3C7h, 3C8h, 3C9h |
Регистры ЦАП VGA (VGA Video DAC Register - VGA_DAC_R) |
В зависимости от режима работы видеопамять адаптера занимает различное адресное пространство:
Номер режима работы |
Адрес памяти |
0,1,2,3,4,5,6 |
B000:8000h-B000:FFFFh |
7 |
B000:0000h-B000:7FFFh |
0Dh,0Eh,0Fh,10h,11h,12h,13h |
A000:0000h-A000:FFFFh |
Ниже мы привели исходный текст функции Get_Seg_Vmem. Данная функция определяет текущий режим работы видеоадаптера и возвращает сегментный адрес начала видеопамяти. Если видеоадаптер работает в нестандартном режиме, функция возвращает нулевое значение.
Чтобы узнать номер текущего режима видеоадаптера, используется функция 0Fh прерывания INT 10h. Пример вызова данной функции представлен в листинге 4.1.
Листинг 4.1. Файл SEGVMEM.C
// Файл SYSP.H представлен в листинге 3.2 #include "sysp.h" unsigned GetSegVmem(void) { unsigned char mode; unsigned seg_address; // Определяем текущий режим видеоадаптера _asm { mov ah,0Fh int 10h mov mode,al } // Если видеоадаптер находится в режимах 0, 1, 2, 3, // 4, 5, 6 то видеопамять начинается с сегмента B800h if((mode >= 0) && (mode <= 6)) seg_address = 0xB800; // Если видеоадаптер находится в режиме 7, // то видеопамять начинается с сегмента B000h else if(mode == 7) seg_address = 0xB000; // Если видеоадаптер находится в режимах 0Dh - 13h, // то видеопамять начинается с сегмента A000h else if((mode >= 0x0D) && (mode <= 0x13)) seg_address = 0xA000; // Если видеоадаптер не находится в стандартном режиме // возвращаем ноль else seg_address = 0x0; return(seg_address); }
Ниже подробно рассмотрены регистры видеоадаптеров EGA и VGA. Мы выделили следующие группы регистров:
Видеоадаптер EGA содержит большинство регистров внутри одной центральной микросхемы. В ней расположены контроллер атрибутов, контроллер ЭЛТ, графический контроллер и преобразователь последовательности. Только несколько регистров размешены в отдельной микросхеме. Они стали называться внешними.
При разработке видеоадаптеров VGA и SVGA внешние регистры были объединены с остальными регистрами в одной микросхеме, но название внешние сохранилось.
Каждому внешнему регистру соответствует порт ввода/вывода.
У видеоадаптера EGA данный регистр доступен только для записи. Вы можете записать в него новое значение через порт ввода/вывода с адресом 3C2h. Видеоадаптер VGA позволяет прочитать содержимое регистра MOR, но уже по адресу 3CCh. Ниже представлено описание отдельных битов регистра MOR:
Биты |
Описание |
D0 |
Выбор адресов портов ввода/вывода |
D1 |
Разрешение доступа к видеопамяти |
D2, D3 |
Выбор частоты |
D4 |
Запрещение управления видеоадаптером |
D5 |
Бит четной/нечетной страницы |
D6 |
Полярность сигнала горизонтальной синхронизации |
D7 |
Полярность сигнала вертикальной синхронизации |
D7 Полярность сигнала вертикальной синхронизации. Нулевая величина для данного бита устанавливает положительную полярность сигнала, единичная - отрицательную. Монохромный, цветной и улучшенный цветной мониторы используют положительную полярность сигнала синхронизации.
D6 Полярность сигнала горизонтальной синхронизации. Нулевая величина для данного бита устанавливает положительную полярность, единичная - отрицательную. Монохромный монитор использует отрицательную полярность сигнала синхронизации, а цветной - положительную.
Улучшенный цветной монитор и аналоговый монитор используют биты D7 и D6 для определения частоты развертки. Следующая таблица содержит допустимые значения для этих битов:
D7 D6 |
EGA |
VGA |
00 |
200 линий |
Не используется |
01 |
350 линий |
350 линий |
10 |
Не используется |
400 линий |
11 |
Не используется |
480 линий |
D5 Бит четной/нечетной страницы используется для режимов, которые передают данные по четным адресам в нулевой цветовой слой, а по нечетным - в первый. Все текстовые режимы устанавливают этот бит. Бит D5 выбирает одну из двух страниц видеопамяти.
D4 Управление видеоадаптером. Бит доступен только для видеоадаптера EGA. Видеоадаптеры VGA и SVGA этот бит не используют. Обычно бит D4 имеет значение 0. В этом случае управление монитором осуществляет видеоадаптер. Если бит D4 принимает значение 1, то монитор управляется сигналами, поступающими от разъема дополнительного устройства.
D2, D3 Биты выбора частоты управляют тактовой частотой видеоадаптера. Таблица, расположенная ниже, представляет правильные варианты установки битов D3 и D2:
D3 |
D2 |
Режим |
0 |
0 |
640 пикселов в строке |
0 |
1 |
720 пикселов в строке |
1 |
0 |
Используется внешний генератор. Внешний генератор подключается через разъем дополнительного устройства) |
1 |
1 |
Зарезервировано |
D1 Доступ к видеопамяти. Данный бит может запретить доступ процессора к видеопамяти. Если бит равен нулю, то доступ центрального процессора к видеопамяти запрещен.
D0 Выбор адресов портов ввода/вывода. Бит D0 определяет адрес регистра управления дополнительным устройством (Feature Control Register), регистра состояния 1 (Input Status Register 1) и регистров контроллера ЭЛТ (CRT Controller). Когда бит D0 равен нулю, происходит выбор адресного пространства монохромного режима (адреса 3Bхh). Если бит равен единице, то используется адресное пространство цветного режима работы видеоадаптера (адреса 3Dхh).
Данные, первоначально записываемые BIOS в этот регистр зависят от режима работы видеоадаптера:
Режим |
0-6,0Dh,0Eh |
7 |
Fh |
10h |
Содержимое регистра |
23h |
0A6h |
0A2h |
0A7h |
Для видеоадаптера EGA биты D1 и D0 данного регистра передают сигналы на разъем дополнительного устройства. Бит D0 соответствует линии FC0 (вывод 21 разъема дополнительного устройства), а бит D1 линии FC1 (вывод 20 разъема дополнительного устройства).
Регистр не используется для видеоадаптеров VGA и SVGA, однако бит D3 в этом случае должен содержать ноль.
Адрес порта ввода/вывода регистра FCR зависит от режима работы видеоадаптера. В монохромных режимах адрес порта 3BAh, а в цветных - 3DAh. У видеоадаптера EGA регистр FCR доступен только для записи. Видеоадаптеры VGA и SVGA позволяют прочитать его содержимое через порт 3CAh.
Регистр ISR0 доступен через порт 3C2h только для чтения. Формат регистра приведен ниже:
Биты |
Описание |
D3-D0 |
Не используются |
D4 |
Состояние переключателей |
D5 |
Бит 0 дополнительного устройства (FEAT0) |
D6 |
Бит 1 дополнительного устройства (FEAT1) |
D7 |
Бит прерывания от ЭЛТ |
D7 Бит установлен в 1, во время обратного вертикального хода луча (погашенный луч перемещается из правого нижнего угла экрана в левый верхний). Бит D7 устанавливается в начале обратного вертикального хода луча и сбрасывается при записи в регистр конца вертикального хода луча.
D6 Бит 1 дополнительного устройства. Используется только видеоадаптерами EGA. Бит D6 регистра управляет уровнем сигнала FEAT0 (вывод 17 разъема дополнительного устройства).
D5 Бит 0 дополнительного устройства. Используется только видеоадаптерами EGA. Бит регистра управляет уровнем сигнала FEAT1 (вывод 19 разъема дополнительного устройства).
D4 Состояние переключателей. Проанализировав бит D4, функции BIOS EGA могут определить состояние четырех переключателей, находящихся на плате видеоадаптера. Номер считываемого переключателя задается двумя битами выбора частоты (D2 и D3) регистра определения различных режимов работы (MOR), согласно следующей таблице:
Бит D3 |
Бит D2 |
Номер переключателя |
0 |
0 |
1 |
0 |
1 |
2 |
1 |
0 |
3 |
1 |
1 |
4 |
Если бит D4 установлен в единицу, то переключатель, заданный битами D2 и D3 регистра определения различных режимов работы, находится в положении ON. Если бит сброшен в ноль, то переключатель находится в положении OFF.
К компьютеру могут быть подключены две различные видеосистемы - два видеоадаптера и два монитора. На плате адаптеров EGA расположены четыре переключателя. Их положение определяет, какие видеоадаптеры и мониторы могут быть подключены одновременно.
Если к компьютеру подключены два видеоадаптера, то один из них является первичным, а другой дополнительным. Первичный видеоадаптер используется по умолчанию сразу после включения компьютера.
Ниже представлены правильные варианты установки переключателей для различных конфигураций видеосистемы компьютера.
|
4 |
3 |
2 |
1 |
|
ON |
. |
|
|
. |
Первичный: EGA с цветным монитором (40х25) |
OFF |
|
. |
. |
|
Дополнительный: MDA |
|
4 |
3 |
2 |
1 |
|
ON |
. |
|
|
|
Первичный: EGA с цветным монитором (80х25) |
OFF |
|
. |
. |
. |
Дополнительный: MDA |
|
4 |
3 |
2 |
1 |
|
ON |
|
. |
. |
. |
Первичный: EGA с улучшенным цветным монитором |
OFF |
. |
|
|
|
Дополнительный: MDA |
|
4 |
3 |
2 |
1 |
|
ON |
|
. |
. |
|
Первичный: EGA с улучшенным цветным монитором |
OFF |
. |
|
|
. |
Дополнительный: MDA |
|
4 |
3 |
2 |
1 |
|
ON |
|
. |
|
. |
Первичный: EGA с монохромным монитором |
OFF |
. |
|
. |
|
Дополнительный: CGA с цветным монитором (40х25) |
|
4 |
3 |
2 |
1 |
|
ON |
|
. |
|
|
Первичный: EGA с монохромным монитором |
OFF |
. |
|
. |
. |
Дополнительный: CGA с цветным монитором (80х25) |
|
4 |
3 |
2 |
1 |
|
ON |
. |
. |
. |
. |
Первичный: MDA |
OFF |
|
|
|
|
Дополнительный: EGA с цветным монитором (40х25) |
|
4 |
3 |
2 |
1 |
|
ON |
. |
. |
. |
|
Первичный: MDA |
OFF |
|
|
|
. |
Дополнительный: EGA с цветным монитором (80х25) |
|
4 |
3 |
2 |
1 |
|
ON |
. |
. |
|
. |
Первичный: MDA |
OFF |
|
|
. |
|
Дополнительный: EGA с цветным монитором (80х25) |
|
4 |
3 |
2 |
1 |
|
ON |
. |
. |
|
|
Первичный: MDA |
OFF |
|
|
. |
. |
Дополнительный: EGA с цветным монитором |
|
4 |
3 |
2 |
1 |
|
ON |
. |
|
. |
. |
Первичный: CGA с цветным монитором 40х25 |
OFF |
|
. |
|
|
Дополнительный: EGA с монохромным монитором |
|
4 |
3 |
2 |
1 |
|
ON |
. |
|
. |
|
Первичный: CGA с цветным монитором 80х25 |
OFF |
|
. |
|
. |
Дополнительный: EGA с монохромным монитором |
Видеоадаптеры VGA и SVGA используют бит D4 для определения типа монитора (цветной или монохромный). Положение этих переключателей может быть считано из оперативной памяти по адресу 0000:0488h:
Биты |
Описание |
D3-D0 |
Биты, соответствующие переключателям. Если бит установлен в единицу, то соответствующий переключатель находится в положении ON. Если бит сброшен в ноль, то переключатель находится в положении OFF |
D7-D4 |
Не используются |
Регистр позволяет получить различную информацию о состоянии видеоадаптера. Для видеоадаптера CGA содержимое регистра можно считать через порт, имеющий адрес 3DAh. Для адаптеров EGA, VGA и SVGA данный регистр, имеет адрес 3BAh в монохромных режимах и адрес 3DAh - в цветных. Регистр состояния 1 доступен только для чтения.
Приведем формат регистра состояния 1:
Биты |
Описание |
D0 |
Бит разрешения отображения |
D1 |
Бит триггера светового пера |
D2 |
Бит переключателя светового пера |
D3 |
Бит обратного вертикального хода |
D5-D4 |
Диагностические биты |
D7-D6 |
Биты не используются |
D7, D6 Биты не используются
D5, D4 Диагностические биты позволяют проверить два из шести цветовых выходных сигналов передаваемых монитору (для видеоадаптера EGA). Для выбора проверяемых сигналов используют регистр разрешения цветового слоя контроллера атрибутов:
Регистр разрешения цветового слоя |
Регистр состояния 1 |
||
D5 |
D4 |
D5 |
D4 |
0 |
0 |
Красный |
Синий |
0 |
1 |
Второй красный |
Второй зеленый |
1 |
0 |
Второй синий |
Зеленый |
1 |
1 |
Не используется |
Не используется |
Следующая таблица показывает, как можно считать два из восьми цветовых сигналов, вырабатываемых контроллером атрибутов видеоадаптера VGA:
Регистр разрешения цветового слоя |
Регистр состояния 1 |
||
D5 |
D4 |
D5 |
D4 |
0 |
0 |
P2 |
P0 |
0 |
1 |
P5 |
P4 |
1 |
0 |
P3 |
P1 |
1 |
1 |
P7 |
P6 |
Биты D5 и D4 позволяют прочитать содержимое регистров таблицы цветовой палитры видеоадаптера EGA. Следует отметить, что некоторые адаптеры, совместимые с EGA, не поддерживают эти биты. Поэтому их использование может наложить ограничения на работу программы.
D3 Бит обратного вертикального хода луча. Бит принимает значение 1 в течение обратного вертикального хода луча по кадру. Данный бит также установлен в случае, если разрешено прерывание IRQ2, и любое устройство компьютера выдает запрос на это прерывание.
Биты D2 и D1 управляют световым пером. Видеоадаптеры VGA и SVGA не поддерживают световое перо, поэтому биты D2 и D1 не используются.
D2 Бит переключателя светового пера. Если переключатель светового пера находится в положении ON (включено), то бит D2 равен единице. Если переключатель находится в положении OFF (выключено), то бит D2 равен нулю.
D1 Бит триггера светового пера. Бит равен единице, если триггер светового пера установлен. Сброс бита происходит при записи нуля через порт с адресом 3BBh для монохромного режима, или через порт 3DBh - для цветного режима.
D0 Бит разрешения отображения. Бит принимает значение единицы во время интервала активности монитора (когда адаптер читает данные из видеопамяти), и равен нулю во время горизонтального и вертикального обратного хода луча.
Во многих случаях возникает необходимость синхронизовать программирование регистров видеоадаптера с периодом вертикального или горизонтального обратного хода луча. Этого можно достичь периодической проверкой регистра состояния 1.
Листинг 4.2 содержит программу, использующую функцию WaitVert для определения частоты кадров. Функция WaitVert задерживает выполнение программы до начала обратного вертикального хода луча.
Листинг 4.2. Файл RASTR.C
// Программа определения частоты кадров #include <time.h> #include <stdio.h> #include <bios.h> #define NUM 200 // Описания функций. Смотри файл DISPLAY.ASM void __pascal __far WaitVert(void); unsigned __pascal __far HorByVer(void); //=========================================================== // Главная функция //=========================================================== void main() { time_t t_start, t_end; int i; float fr; unsigned vert_fr; // Определяем начальное время t_start = clock(); // Ожидаем исполнения NUM вертикальных разверток for(i = 0; i < NUM; i++) WaitVert(); // Определяем конечное время t_end = clock(); // Вычисляем частоту кадров fr = NUM/(((float)t_end - t_start) / CLK_TCK); printf( "\nЧастота кадров = %4.1f \n", (float)fr ); }
Исходный текст функции WaitVert представлен в листинге 4.3. Функция WaitVert периодически проверяет регистр состояния 1 (ISR1), ожидая начало обратного вертикального хода луча по экрану монитора.
Листинг 4.3. Файл DISPLAY.ASM
TITLE DISPLAY.ASM NAME DISPLAY PAGE 55,132 P286 IDEAL NOWARN BRK SEGMENT WAIT_TEXT WORD PUBLIC 'CODE' ASSUME cs:WAIT_TEXT ;=========================================================== ; Функция void WaitVert(void) ;=========================================================== PUBLIC WAITVERT PROC WAITVERT FAR enter 0, 0 mov ax,0h mov es,ax ; Определяем адрес порта индексного регистра контроллера ; ЭЛТ (3B4h/3D4h) mov dx,es:[463h] ; Вычисляем адрес порта регистра состояния 1 (ISR1) add dl,6 ; Читаем содержимое порта регистра состояния 1 in al,dx ; Тестируем бит D3 регистра состояния 1 ; бит D3 = 1 при обратном вертикальном ходе луча test al,8 jz wait_on wait_off: in al,dx ; Тестируем бит D3 test al,8 ; Ожидаем конец обратного вертикального хода луча jnz wait_off wait_on: in al,dx test al,8 ; Ожидаем начало обратного вертикального хода луча jz wait_on ; +------------------------------------------------------+ ; Здесь могут распологаться операции, которые необходимо ; выполнить во время обратного вертикального хода луча ; +------------------------------------------------------+ leave ret ENDP WAITVERT ENDS WAIT_TEXT END
Данный регистр имеет адрес 3С3h. Регистр используется только видеоадаптерами VGA и SVGA. Биты D1-D7 зарезервированы, а бит D0 управляет работой адаптера. Если бит D0 равен нулю, тогда запрещен доступ к видеопамяти и портам ввода/вывода видеоадаптера (кроме регистра VGA_ER).
В цветных режимах регистр LPLRR доступен через порт 3DBh, а в монохромных режимах через порт 3BBh. Регистр используется только видеоадаптерами CGA и EGA. Любая операция записи в регистр LPLRR сбрасывает триггер-защелку светового пера.
В цветных режимах регистр LPLSR доступен через порт 3DCh, а в монохромных режимах через порт 3BCh. Регистр используется только видеоадаптерами CGA и EGA. Любая операция записи в этот регистр вызывает установку триггера-защелки светового пера.
Регистры контроллера ЭЛТ управляют сигналами синхронизации, необходимыми для формирования растра, определяют формат данных на экране и форму курсора. Для видеоадаптеров CGA и EGA регистры контроллера ЭЛТ также управляют световым пером.
Большинство из регистров ЭЛТ не представляют интереса. Более того, их неправильное использование может послужить причиной физического разрушения монитора. Поэтому мы подробно рассмотрим лишь наиболее полезные и безопасные регистры контроллера. Назначение и формат ряда регистров контроллера ЭЛТ различаются для видеоадаптеров EGA, VGA, SVGA и для видеоадаптеров MDA, Hercules, CGA.
При программировании регистров контроллера ЭЛТ используется понятие одного знакоместа (characters) и времени необходимого для отображения одного символа (character clock). При вычислении значений регистров следует учесть, что ширина одного символа составляет 8 пикселов.
Растр состоит из совокупности строк развертки, следующих одна за другой. Электронный луч включается в начале каждой строки и выключается в конце. Включение и выключение электронного луча выполняется сигналом разрешения отображения (Display Enable), вырабатываемым контроллером ЭЛТ.
Когда электронный луч включен (разрешено отображение) видеоадаптер читает данные из видеопамяти и соответствующим образом модулирует интенсивность и цвет электронного луча.
После того как луч прочертит весь экран монитора справа налево, он перемещается в начало следующей строки. Контроллер ЭЛТ снова включает электронный луч, в ответ на сигнал разрешения отображения и выводит на экран следующую строку видеоинформации.
Промежуток времени между окончанием отображения видеоинформации на одной строке и началом отображения следующей строки называется горизонтальным неотображаемым интервалом. Промежуток времени отводимый для обратного хода луча меньше горизонтального неотображаемого интервала. Поэтому на правой и левой границе экрана образуются неотображаемые области.
Контроллер ЭЛТ позволяет оставить электронный луч включенным во время перемещения по не отражаемой области. При этом вокруг изображения образуется цветная рамка. Размер и цвет рамки вы можете задавать сами.
После того как электронный луч прочертит все горизонтальные линии растра, контроллер ЭЛТ отключает сигнал разрешения отображения (электронный луч гаснет) и вырабатывает сигнал вертикального обратного хода луча. Электронный луч перемещается с нижней части экрана в верхний левый угол. Продолжительность вертикального обратного хода луча меньше, чем период вертикального неотображаемого интервала. В результате в нижней и верхней части экрана возникают неотображаемые области.
Одной из основополагающих величин, определяющих разрешающую способность режимов видеоадаптера, является частота вывода пикселов на экран монитора. Эта частота определяется генератором синхросигналов видеоадаптера. Чем выше частота вывода, тем больше пикселов может уместиться на экране при известной частоте кадров и частоте строчной развертки.
Генераторы синхросигналов видеоадаптеров MDA, CGA и Hercules работают только на одной частоте. Для видеоадаптеров EGA, VGA и SVGA доступно несколько различных частот.
Старые модели мониторов могут работать только с фиксированными значениями частоты горизонтальной и вертикальной развертки. Практически все современные мониторы могут работать в некотором диапазоне частот. Поэтому они называются мультичастотными.
Видеоадаптер |
Режим |
Частота вывода пикселов, Мгц |
Частота горизонтальной развертки, Кгц |
Частота вертикальной развертки, Гц |
MDA |
720х350 |
16257 |
18430 |
50 |
CGA |
640х200 |
14318 |
15750 |
60 |
EGA |
640х200 |
14318 |
15750 |
60 |
640х350 |
16257 |
21850 |
60 |
|
720х350 |
16257 |
18430 |
50 |
|
VGA |
640х400 |
25175 |
31500 |
70 |
720х400 |
28322 |
31500 |
70 |
|
640х480 |
25175 |
31500 |
60 |
|
640х350 |
25175 |
31500 |
70 |
|
SVGA |
640х480 |
31500 |
37861 |
72,809 |
800х600 |
40000 |
37879 |
60,317 |
|
800х600 |
50000 |
48077 |
72,187 |
|
1024х768 |
65000 |
48363 |
60,000 |
|
1024х768 |
75000 |
56476 |
70,069 |
Чтобы вычислить, сколько пикселов помещается на каждой строке развертки разделите частоту вывода точек на частоту горизонтальной развертки. Затем разделите полученное значение на 8 и вы узнаете, сколько символов помещается в строке развертки.
Если вы самостоятельно программируете регистры ЭЛТ видеоадаптеров VGA или SVGA вы должны отнять от полученной величины число 5 (для адаптера EGA следует отнять 2) и записать результат в регистр общей длинны линии горизонтальной развертки (Horizontal Total Register - HTR).
Во время выполнения горизонтальной развертки отображаются только пикселы в рабочей области экрана. Например, для режима VGA 640х480 пикселов, на одной линии горизонтальной развертки отображается только 640 пикселов. Разделите количество пикселов отображаемых в одной строке на 8 и вы узнаете, сколько символов выводится в каждой строке. Полученное значение записывается при выборе режима работы адаптера в регистр длины отображаемой части горизонтальной развертки (Horizontal Display Enable End Register - HDER).
Вы видите, что общая длина горизонтальной развертки больше длины отображаемой части горизонтальной развертки. Разница между этими двумя значениями определяет, сколько времени отводится на обратный ход луча и на нерабочую область развертки.
Регистры начала импульса гашения луча горизонтальной развертки (Start Horizontal Blank Register - SHBR) и конца импульса гашения луча горизонтальной развертки (End Horizontal Blank Register - EHBR) определяют размер нерабочей области горизонтальной развертки.
Регистры начала горизонтального обратного хода луча (Start Horizontal Retrace Register - SHRR) и конца импульса горизонтального обратного хода луча (End Horizontal Retrace Register - EHRR) определяют момент начала и окончания горизонтального обратного хода луча.
При вычислении значений регистров SHRR и EHRR следует учитывать, что для большинства мониторов, совместимых с видеоадаптерами VGA требуется отвести на горизонтальный обратный ход луча 2-4 микросекунды. Значения регистров SHRR и EHRR, как и других регистров контроллера ЭЛТ, необходимо записать в символах. Вычислим промежуток времени, в течение которого отображается один символ. Для этого следует разделить 1 на частоту вывода точек и умножить полученное число на 8 (горизонтальный размер символа в пикселах). Если частота вывода точек составляет 25,175 Мгц, тогда на отображение одного символа затрачивается 8/25175 = 0,318 микросекунд. Отсюда вычисляем, что для горизонтального обратного хода луча достаточно времени затрачиваемого на отображение 7 (2/0,318) символов.
Выберите значение для регистра начала горизонтального обратного хода луча (SHRR) таким образом, чтобы растр был отцентрован на экране. Участки нерабочей области до и после горизонтального обратного хода луча должны иметь одинаковый размер.
Всего в строке развертки 100 символов. Из них 80 символов отводится для видимой области строки растра и 12 символов для горизонтального обратного хода луча. Остаток - 8 символов (100-80-12) относится к нерабочей области строки развертки. Значит горизонтальный обратный ход луча должен начинаться по прошествии времени, необходимого для отображения 80+8/2=84 символов.
Регистры контроллера ЭЛТ составляют самую многочисленную группу регистров видеоадаптеров. Для видеоадаптеров EGA и VGA группа содержит 24 регистра. В следующей таблице приведен список всех регистров контроллера ЭЛТ и их индексы, используемые для доступа к ним.
Индекс |
Регистр контроллера ЭЛТ |
0 |
Общая длина линии горизонтальной развертки (Horizontal Total Register - HTR) |
1 |
Длина отображаемой части горизонтальной развертки (Horizontal Display Enable End Register - HDER) |
2 |
Начало импульса гашения луча горизонтальной развертки (Start Horizontal Blank Register - SHBR) |
3 |
Конец импульса гашения луча горизонтальной развертки (End Horizontal Blank Register - EHBR) |
4 |
Начало импульса горизонтального обратного хода луча (Start Horizontal Retrace Register - SHRR) |
5 |
Конец импульса горизонтального обратного хода луча (End Horizontal Retrace Register - EHRR) |
6 |
Количество горизонтальных линий растра (Vertical Total Register - VTR) |
7 |
Дополнительный регистр (Overflow Register - OVR) |
8 |
Предварительная установка горизонтальной развертки (Preset Row Scan Register - PRSR) |
9 |
Высота символов текста (Max Scan Line Register - MSLR) |
0Ah |
Начальная линия курсора (Cursor Start Register - CSR) |
0Bh |
Конечная линия курсора (Cursor End Register - CER) |
0Ch |
Старший байт начального адреса (Start Address Register - SAR, high byte) |
0Dh |
Младший байт начального адреса (Start address Register - SAR, low byte) |
0Eh |
Старший байт позиции курсора (Cursor Location Register - CLR, high byte) |
0Fh |
Младший байт позиции курсора (Cursor Location Register - CLR, low byte) |
10h |
Начало обратного вертикального хода луча (Vertical Retrace Start Register - VRSR) |
11h |
Конец обратного вертикального хода луча (Vertical Retrace End Register - VRER) |
10h |
Старший байт адреса светового пера (Light Pen Address Register - LPAR, high byte) |
11h |
Младший байт адреса светового пера (Light Pen Address Register - LPAR, low byte) |
12h |
Начало гашения вертикальной развертки (Vertical Display End Register - VDER) |
13h |
Логическая ширина экрана (Offset Register - OFR) |
14h |
Положение подчеркивания символа (Underline Location Register - ULR) |
15h |
Начало импульса гашения вертикальной развертки (Start Vertical Blank Register - SVBR) |
16h |
Конец импульса гашения вертикальной развертки (End Vertical Blank Register - EVBR) |
17h |
Управление режимом (Mode Control Register - MCR) |
18h |
Регистр сравнения линий (Line Compare Register - LCR) |
В отличие от внешних регистров, адресация к регистрам контроллера ЭЛТ происходит через два порта. В первый порт (индексный) записывается индекс регистра, к которому осуществляется доступ, а через второй порт (порт данных) можно выполнять обмен данными (запись или чтение).
У видеоадаптеров MDA и Hercules индексный порт имеет адрес 3B4h, а порт данных - адрес 3B5h. Для CGA адреса портов другие. Индексный порт имеет адрес 3D4h, а порт данных - адрес 3D5h. Адреса портов контроллера ЭЛТ для видеоадаптеров EGA и VGA зависят от режима работы видеоадаптера (монохромный или цветной). В монохромном режиме адрес порта индексного регистра равен 3B4h, а регистра данных - 3B5h. В цветном режиме адреса соответственно равны 3D4h и 3D5h:
Видеоадаптер |
Адрес порта индексного регистра |
Адрес порта регистра данных |
CGA |
3D4h |
3D5h |
EGA, VGA, SVGA |
3B4h |
3B5h |
EGA, VGA, SVGA |
3D4h |
3D5h |
MDA, Hercules |
3B4h |
3B5h |
Так как в монохромных и цветных режимах регистры адресуются через различные порты ввода/вывода, то к компьютеру можно одновременно подключить два видеоадаптера.
Адрес порта индексного регистра записан в области переменных BIOS, по адресу 0000:0463h. Приведем фрагмент программы, определяющей адрес индексного порта контроллера ЭЛТ:
; Устанавливаем регистр ES на нулевой сегмент памяти xor ax,ax mov es,ax ; Записываем в регистр DX адрес порта индексного ; регистра контроллера ЭЛТ mov dx,es:[463]
Так как адреса портов индексного регистра и регистра данных контроллера ЭЛТ является смежными, то адрес порта регистра данных можно легко получить, прибавив единицу к адресу порта индексного регистра.
Регистр HTR относится к группе регистров контроллера ЭЛТ, которые управляют генерацией синхросигналов монитора. Необходимость модификации данной группы регистров возникает только при программировании нестандартных режимов работы видеоадаптера.
Кроме регистров, контроллер ЭЛТ использует при генерации синхросигналов два внутренних счетчика. Счетчик числа горизонтальных знакомест экрана увеличивается при выводе очередного символа на экран (регенерация экрана) и сбрасывается, когда его значение становится равным регистру общей длины линии горизонтальной развертки. Счетчик числа горизонтальных линий развертки увеличивается после окончания обратного горизонтального хода луча и сбрасывается, когда достигает величины, хранящейся в регистре числа горизонтальных линий растра.
Регистр HTR определяет число знакомест в одной строке развертки, включая обратный ход луча и нерабочую область развертки (рамку экрана). Для видеоадаптера EGA число знакомест по горизонтали на два, а для адаптеров VGA и SVGA на пять больше, чем значение, хранящееся в регистре.
При установке режима работы видеоадаптера, BIOS загружает в регистр HTR следующие значения:
Режим |
0,1,4,5,D |
2,3,6,E |
7, |
F |
10 |
Содержимое регистра |
37h |
70h |
60h |
5Bh |
Если используется улучшенный цветной монитор, то эти значения отличаются:
Режим |
0,1 |
2,3 |
Содержимое регистра |
2Dh |
5Bh |
Регистр задает длину отображаемого участка горизонтальной развертки. Величина, записанная в регистр должна быть единицу меньше, чем количество символов в строке экрана.
При установке режима работы видеоадаптера, BIOS загружает в регистр HDER следующие значения:
Режим |
0,1,4,5,D |
2,3,6,7,E,F,10 |
Содержимое регистра |
27h |
4Fh |
Регистр используется видеоадаптерами EGA, VGA и SVGA для определения начала импульса гашения луча горизонтальной развертки.
При установке режима работы видеоадаптера, BIOS загружает в регистр SHBR следующие значения:
Режим |
0,1,4,5,D |
2,3 |
6,E |
7,F |
10 |
Содержимое регистра |
2Dh |
5Ch |
59h |
56h |
53h |
Если используется улучшенный цветной монитор, то эти значения отличаются:
Режим |
0,1 |
2,3 |
Содержимое регистра |
2Bh |
53h |
D4-D0 Конец импульса гашения луча горизонтальной развертки. Гашение луча горизонтальной развертки происходит, когда биты D4-D0 равны счетчику длины отображаемой части горизонтальной развертки.
D6-D5 Биты смещения используются в текстовых режимах, чтобы разрешить отображение символов до разрешения вывода. Если величина битов смещения слишком маленькая, то символы на левой стороне экрана могут быть потеряны, а если она слишком большая, то символы на левой стороне экрана могут дублироваться по несколько раз.
D6 D5 0 0 - нет смещения 0 1 - смещение на один символ 1 0 - смещение на два символа 1 1 - смещение на три символа
D7 Бит D7 равен единице для видеоадаптера VGA и нулю для EGA.
При установке режима работы видеоадаптера, BIOS загружает в регистр EHBR следующие значения:
Режим |
0,1,4,5,D |
2,3 |
6,E |
7 |
F |
10 |
Содержимое регистра |
37h |
2Fh |
2Dh |
3Ah |
1Fh |
17h |
Если используется улучшенный цветной монитор, то эти значения отличаются:
Режим |
0,1 |
2,3 |
Содержимое регистра |
2Dh |
37h |
Для видеоадаптеров EGA, VGA и SVGA регистр задает момент начала импульса горизонтального обратного хода луча.
При установке режима работы видеоадаптера, BIOS загружает в регистр SHRR следующие значения:
Режим |
0,1 |
4,5,D |
2,3 |
6,E |
7 |
F,10 |
Содержимое регистра |
31h |
30h |
5Fh |
5Eh |
51h |
50h |
Если используется улучшенный цветной монитор, то эти значения отличаются:
Режим |
0,1 |
2,3 |
Содержимое регистра |
28h |
51h |
D4-D0 Конец импульса горизонтального обратного хода луча. Обратный горизонтальный хода луча завершается, когда значение счетчика символов в строке становится равным битам D4-D0.
D6-D5 Смещение импульса горизонтального обратного хода луча относительно отображаемого участка горизонтальной развертки. Биты используются видеоадаптером EGA.
D6 D5 0 0 - нет смещения 0 1 - смещение на один символ 1 0 - смещение на два символа 1 1 - смещение на три символа
D7 Для адаптера EGA с объемом видеопамяти меньшим 256 Кбайт, бит D7 используется для управления горизонтальной сверткой экрана (горизонтальным панорамированием), когда слои видеопамяти сцеплены. Если бит D7 равен нулю, то после обратного хода луча первый адрес видеопамяти для обновления экрана будет четным.
Для видеоадаптеров VGA и SVGA бит D7 является пятым битом регистра конца импульса гашения луча горизонтальной развертки (EHBR).
Регистр определяет общее число линий горизонтальной развертки в кадре вертикальной развертки, включая гашение вертикального хода луча и обратный вертикальный ход луча.
Для видеоадаптера EGA, регистр VTR содержит девять битов. Девятый бит находится в дополнительном регистре (OVR). Регистр VTR видеоадаптеров VGA и SVGA содержит десять битов. Десятый бит, также как и девятый, расположен в дополнительном регистре (OVR).
Многие регистры контроллера ЭЛТ, видеоадаптера EGA, имеют по девять, а для адаптеров VGA и SVGA по десять битов. Дополнительный регистр содержит биты, которые не помещаются в восьмиразрядную сетку основных регистров видеоадаптера.
D0 Бит 8 регистра числа горизонтальных линий растра (VTR).
D1 Бит 8 регистра начала гашения вертикальной развертки (VDER).
D2 Бит 8 регистра начала обратного вертикального хода луча (VRSR).
D3 Бит 8 регистра начала импульса гашения вертикальной развертки (SVBR).
D4 Бит 8 регистра сравнения линий (LCR).
D5 Бит 9 регистра количества горизонтальных линий в растре (VTR).
D6 Бит 9 регистра начала гашения вертикальной развертки (VDER).
D7 Бит 9 регистра начала обратного вертикального хода луча (VRSR).
Регистр позволяет в текстовых режимах выполнить плавную вертикальную свертку текста на экране монитора. В графических режимах регистр должен содержать нулевое значение.
D4-D0 Биты предварительной установки строчной развертки. Эти биты определяют номер линии развертки, начиная с которой начинают отображаться символы (рис. 8.1). Как видно из рисунка самая верхняя строка текста отображается только частично. Вы можете плавно перемешать изображение на экране увеличивая или уменьшая значение этих битов.
D6-D5 Биты управления побайтовой сверткой. Используются видеоадаптерами VGA и SVGA. Биты D6 D5 являются двумя дополнительными битами регистра горизонтального панорамирования контроллера атрибутов и позволяют сдвигать изображение на экране более чем на 8 пикселов.
D7 Не используется.
Рисунок 4.1 иллюстрирует использование регистра предварительной установки горизонтальной развертки для вертикальной свертки содержимого экрана. В левой части рисунка показано начальное состояние экрана монитора, когда биты D0-D4 регистра PRSR содержит нулевые значения. Справа представлен экран монитора после увеличения значения регистра PRSR до трех. Изображение на экране сдвигается на три пиксела вверх, в результате чего часть верхней строки пропадает.
Рисунок 4.1 Плавная свертка экрана
После установки режима работы видеоадаптера регистр PRSR содержит нулевое значение.
Регистр MSLR определяет высоту символов в пикселах. Значение регистра на единицу меньше, чем высота символов отображаемых на экране. Регистр MSLR используется только в текстовых режимах работы видеоадаптеров.
D4-D0 Биты задают высоту символа в пикселах (рис. 8.2 и 8.3).
D5 Бит 9 регистра начала импульса гашения вертикальной развертки (SVBR - индекс 15h). Используется только для видеоадаптеров VGA и SVGA.
D6 Бит 9 регистра сравнения линий (LCR индекс 18h). Используется только для видеоадаптеров VGA и SVGA.
D7 Бит управления двойным сканированием. Поддерживается только адаптерами VGA и SVGA. Если бит D7 равен единице, то в режимах, имеющих разрешение по вертикали 200 пикселов используется двойное сканирование. Это увеличивает разрешающую способность по вертикали до 400 пикселов.
Рисунок 4.2 демонстрирует использование регистра высоты символов текста. На левой половине рисунка символы шрифта имеют размер 8х8 пикселов, а регистр высоты символов содержит число семь. На правой половине рисунка, символы шрифта имеют размер 8х14, а значение регистра высоты символов текста равно тринадцати.
Рисунок 4.2 Высота символов текста 8 пикселов
Регистр CSR является доступным как для чтения, так и для записи. Регистр определяет линию сканирования символа, в которой начинается курсор. Вместе с регистром конечной линии курсора (CER) регистр CSR определяет размер и форму курсора.
D4-D0 Начальная линия курсора. (Рис. 4.3).
D5 Бит гашения курсора. Реализован только для видеоадаптеров VGA и SVGA. Если бит D5 содержит единицу, тогда текстовый курсор гаснет.
D7-D6 Не используются.
При установке режима работы видеоадаптера, BIOS загружает в регистр CSR следующие значения:
Режим |
0,1,2,3 |
4,5,6,D,E,F,10 |
7 |
Содержимое регистра |
06 |
00 |
0Bh |
Этот регистр, также как и регистр CSR, является доступным для чтения и для записи. Регистр задает линию сканирования символа, в которой кончается курсор.
D4-D0 Соответствует номеру последней линии курсора для видеоадаптеров VGA и SVGA (рис. 4.3). Для видеоадаптера EGA - номеру следующей линии.
D6-D5 Отклонение курсора. Задает смещение курсора относительно позиции, определенной регистром CLR.
00 - нет отклонения
01 - отклонение вправо на один символ
10 - отклонение вправо на два символа
11 - отклонение вправо на три символа
D7 Не используется.
При установке режима работы видеоадаптера BIOS загружает в регистр конечной линии курсора следующие значения:
Режим |
0,1,2,3 |
4,5,6,D,E,F,10 |
7 |
Содержимое регистра |
07 |
00 |
0Ch |
Изменяя значение регистров начальной и конечной линии курсора, можно менять его положение и размер (рис. 4.3). На левой части рисунка, приведенного ниже, регистр начальной линии курсора равен 0Ah, регистр конечной линии курсора равен 0Bh. На правой части рисунка значение регистров изменено. Регистр начальной линии равен 4, а регистр конечной линии - 5.
Рисунок 4.3 Изменение положения курсора
Следующая программа позволяет прочитать значение регистров начальной и конечной линии курсора:
Листинг 4.4. Файл GETCURS.C
#include <stdio.h> #include <conio.h> #include "sysp.h" // см. листинг 3.2 #include "sysgraph.h" // см. листинг 3.3 // Описания функций void main(void); void WriteReg(unsigned reg, unsigned char data); unsigned char ReadReg(unsigned reg); // Главная функция void main(void) { char top = 0, bottom = 0; unsigned crt_address; BIOS_VAR _far *bios_var_ptr; // Получаем указатель на область переменных BIOS bios_var_ptr = (BIOS_VAR _far *) FP_MAKE(0x0000, 0x0410); // Определяем адрес индексного регистра контроллера ЭЛТ crt_address = bios_var_ptr->wAddrCRT; // Считываем значения регистров начальной и конечной линии // курсора // Выбираем регистр начальной линии курсора WriteReg(crt_address++, 0x0A); // Считываем значение регистра top = (unsigned char) ReadReg(crt_address--); // Выбираем регистр конечной линии курсора WriteReg(crt_address++, 0x0B); // Считываем значение регистра bottom = (unsigned char) ReadReg(crt_address); // Отображаем на экране значение регистров printf("\nРегистр начальной линии курсора содержит: %d\n" "\nРегистр конечной линии курсора содержит: %d\n", top, bottom); getch(); }
Для доступа к регистрам видеоадаптера мы пользуемся функциями WriteReg и ReadReg, определенными в файле DESIGN.C (листинг 4.5).
Листинг 4.5. Файл DESIGN.C
//========================================================= // WriteReg(unsigned reg, unsigned char data) // Функция выводит данные в порт // // Параметры: // reg - номер порта // data - данные, записываемые в порт reg //========================================================= void WriteReg(unsigned reg, unsigned char data) { _asm { mov dx,reg mov al,data out dx,al } } //========================================================= // unsigned char ReadReg(unsigned reg) // Функция читает данные из определенного порта // // Параметры: // reg - номер порта // // Возвращаемое значение: // данные, считанные из порта reg //========================================================= unsigned char ReadReg(unsigned reg) { unsigned char data; _asm { mov dx,reg in al,dx mov data,al } return(data); }
Это группа из двух регистров: регистр старшего байта начального адреса (Start Address Register - SAR, high byte) (индекс 0Ch) и регистр младшего байта начального адреса (Start Address Register - SAR, low byte) (индекс 0Dh).
В регистрах SAR записан адрес видеоданных, которые отображаются в верхнем левом углу экрана монитора. Регистры начального адреса можно использовать для перемещения изображения по экрану (свертки) и для переключения активной страницы видеопамяти.
Если вы желаете использовать регистры для переключения страниц видеопамяти, то в регистры SAR надо записать смещение страницы видеопамяти (относительно начала видеопамяти), которую необходимо отобразить на экране.
На рисунке 4.4 показано, как происходит свертка экрана при изменении регистров начального адреса. В верхней части рисунка регистры начального адреса содержат ноль. Видеопамять отображается на экране с начала. В нижней части значение регистров начального адреса увеличено до 77h. В этом случае видеопамять отображается на экране начиная с данных, имеющих смещение 77h от начала видеопамяти. В нижней части экрана появляется изображение, ранее не помещающееся на экране.
Рисунок 4.4 Свертка изображения на экране
Регистры начального адреса доступны для чтения и для записи. При выборе режима работы видеоадаптера регистры обнуляются.
Два регистра - регистр старшего байта позиции курсора (Cursor Location Register - CLR_h, high byte) (индекс 0Eh) и регистр младшего байта позиции курсора (Cursor Location Register - CLR_l, low byte) (индекс 0Fh) определяют положение курсора на экране (рис. 4.5). Регистры доступны как для записи, так и для чтения.
Рисунок 4.5 Отображение курсора на экране
Программа CURSLOC, приведенная в листинге 4.6 переводит видеоадаптер в текстовый режим, устанавливает курсор в позицию 5 строки 10. Затем программа считывает значения регистров позиции курсора (на момент запуска программы) и отображает их на экране монитора. Вы должны получить значение 0325h (80 * 10 + 5 = 805 = 0325h).
Листинг 4.6. Файл CURSLOC.C
// Чтение регистра положения курсора #include <stdio.h> #include "sysp.h" #include "sysgraph.h" // Описания функций void main(void); // Функции WriteReg и ReadReg определены в файле // DESIGN.C. Смотри листинг 4.5 void WriteReg(unsigned reg, unsigned char data); unsigned char ReadReg(unsigned reg); // Главная функция void main(void) { int crt_port; unsigned char h_pos, l_pos; BIOS_VAR _far *bios_var_ptr; _asm { // Устанавливаем режим 3 mov ah,0 mov al,3 int 10h // Выбираем страницу видеоапамяти 0 mov ah,5 mov al,0 int 10h // Устанавливаем курсор в положение (20,10) mov ah,2 mov dh,10 // mov dl,5 // строка 10, позиция 5: // CLR = 80 * 10 + 5 = 805 = 325h xor bh,bh int 10h } // Получаем указатель на область переменных видеофункций BIOS bios_var_ptr = (BIOS_VAR _far *) FP_MAKE(0x0000, 0x0410); // Определяем адрес порта индексного регистра контроллера ЭЛТ crt_port = bios_var_ptr -> wAddrCRT; // Выбираем старший байт регистра положения курсора WriteReg(crt_port, 0x0E); // Читаем значение старшего байта регистра h_pos = ReadReg(crt_port + 1); // Выбираем младший байт регистра положения курсора WriteReg(crt_port, 0x0F); // Считываем значение младшего байта регистра l_pos = ReadReg(crt_port + 1); // Отображаем полученные значения printf("\nТекущий адрес курсора %2.2X%2.2Xh\n", (unsigned char) h_pos, (unsigned char) l_pos ); return; }
Регистр определяет начало обратного вертикального хода луча. У видеоадаптера EGA регистр имеет 9, а для видеоадаптеров VGA и SVGA - 10 разрядов. Дополнительные биты регистра VRSR расположены в регистре OVR. Регистр VRSR доступен только для записи.
Регистр устанавливает конец обратного вертикального хода луча, а также выполняет некоторые другие функции. Данный регистр доступен только для записи.
Биты |
Описание |
D3-D0 |
Конец обратного вертикального хода луча |
D4 |
Сброс вертикального прерывания |
D5 |
Разрешения вертикального прерывания |
D6 |
Изменение скорости регенерации экрана (видеоадаптеры VGA и SVGA) |
D7 |
Защита от записи (видеоадаптеры VGA и SVGA) |
D7 Если бит D7 равен единице, то регистры контроллера ЭЛТ, имеющие индексы от 0 до 7, будут защищены от записи. Защита от записи позволяет решить некоторые проблемы совместимости между адаптером VGA и видеоадаптерами, построенными на основе микросхемы 6845 (например CGA).
D6 Если бит D6 равен единице, то во время обратного горизонтального хода луча будет генерироваться пять циклов регенерации видеопамяти вместо обычных трех.
D5 Если бит равен нулю, то при каждом обратном вертикальном ходе луча на линии IRQ2 будет возникать прерывание. Сигнал прерывания сбрасывается при записи нуля в бит D4 данного регистра.
D4 Запись нуля в данный бит вызывает сброс прерывания на линии IRQ2 и переустановку флага незаконченного вертикального прерывания.
D3-D0 Сигнал обратного вертикального хода луча завершается, когда значение четырех младших бита счетчика горизонтальных линий совпадает с битами D3-D0
Это 16-битовый регистр видеоадаптеров CGA и EGA, доступный только для чтения. Регистр LPAR позволяет определить положение светового пера на экране монитора. Регистр, содержащий старший байт адреса светового пера, имеет индекс 10h, а регистр, содержащий младший байт, индекс 11h.
Регистр LPAR сохраняет адрес видеопамяти, которая регенерировалась в момент включения светового пера.
Регистр определяет момент, когда заканчивается видимая часть вертикальной развертки и происходит гашение луча. Регистр содержит число, на единицу меньшее, чем количество горизонтальных линий растра.
У видеоадаптера EGA регистр VDER имеет 9, а у адаптеров VGA и SVGA - 10 разрядов. Девятый и десятый биты регистра доступны через дополнительный регистр (OVR).
Регистр позволяет отобразить на экране больше символов в строке, чем в стандартных текстовых режимах. Например, вы можете воспользоваться регистром OFR при переводе видеоадаптера в режим отображения 132 символов в строке.
В текстовых режимах регистр содержит смещение между соседними строками экрана, заданное в 16-битных словах.
В графических режимах регистр OFR задает логическую длину (в 16-битных словах или 32-битных двойных словах) горизонтальной линии развертки. Если линия Num развертки начинается по адресу Adr, то следующая линия развертки Num+1 начинается по адресу Adr+Offset, где Offset является значением регистра OFR.
Использование регистра OFR иллюстрируется рисунком 4.6. На верхней части рисунка видеоадаптер находится в стандартном текстовом режиме с разрешением 80 символов в строке. При этом значение регистра логической ширины экрана равно 40. На нижней части рисунка представлен результат увеличения содержимого регистра до 41. Логическая ширина экрана в этом случае увеличивается до 82 символов в строке. Последние два символа каждой строки не помещаются на экране. Для их отображения надо выполнить горизонтальную свертку экрана.
Рисунок 4.6 Логическая ширина экрана
Регистр ULR используется только в текстовых режимах. Он определяет положение подчеркивания символа. Подчеркивание представляет собой одну из линий в матрице символа. Подчеркивание отображается, если установлен атрибут подчеркивания. Подчеркивание можно запретить, записав в регистр ULR величину большую, чем высота символов.
D4-D0 Определяют положение подчеркивания символа.
D5 Для видеоадаптеров VGA и SVGA установка этого бита означает, что для каждого знакоместа счетчик адреса регенерации будет увеличиваться на 4 вместо 1.
D6 Установка для видеоадаптеров VGA и SVGA этого бита выбирает адресацию видеопамяти по двойным словам.
D7 Не используется.
Программа, приведенная ниже, использует регистры контроллера ЭЛТ для перевода видеоадаптеров EGA и VGA в нестандартный текстовый режим, имеющий разрешение по вертикали 43 строки. Данная программа переводит видеоадаптер в текстовый режим с разрешением по вертикали 43 символа и затем отображает на экране монитора 43 строки текста.
Листинг 4.7. Файл MORESTR.ASM
#include <conio.h> // Описания функций void main(void); // Функция Set43Line опреелена в файле SET43.ASM // (листинг 4.8) void __pascal _far Set43Line(void); // Главная функция void main(void) { int i; // Увеличиваем количество отображаемых строк текста Set43Line(); // Отображаем на экране монитора несколько текстовых строк for(i = 0; i < 50; i++) printf("Text line number %d\n", i); getch(); return; }
Основная функция программы MORESTR - функция Set43Line определена в файле SET43.ASM. Исходный текст файла помещен в листинге 4.8.
Листинг 4.8. Файл SET43.ASM
TITLE SET43.ASM NAME SET43 PAGE 55,132 P286 IDEAL NOWARN BRK SEGMENT LINE_TEXT WORD PUBLIC 'CODE' ASSUME cs:LINE_TEXT ;============================================================ ; void Set43Line(void) ; Переводит адаптеры EGA и VGA в режим отображения 43 ; строк текста. ;============================================================ CHAR_SIZE EQU 8 PUBLIC SET43LINE PROC SET43LINE FAR enter 0, 0 ; Устанавливаем регистр es на начало оперативной памяти xor ax,ax mov es,ax ; Получаем адрес порта индексного регистра контроллера ЭЛТ ; (3B4h/3D4h), в монохромных режимах для адресации к ; индексному регистру используется порт с адресом 3B4h, ; а в цветных - порт 3D4h mov dx,es:[463h] ; Выбираем для обмена регистр максимальной линии ; сканирования этот регистр задает высоту символов на ; экране дисплея mov al,9 out dx,al ; Вычисляем адрес порта регистра данных контроллера ЭЛТ, ; в монохромных режимах для адресации к регистру данных ; используется порт с адресом 3B5h, в цветных - порт 3D5h inc dx ; Биты D4-D0, регистра максимальной линии сканирования ; содержат число, меньшее на единицу, чем высота символов ; в пикселах mov al,CHAR_SIZE-1 out dx,al ; Вычисляем адрес порта индексного регистра ; контроллера ЭЛТ dec dx ; Выбираем для обмена регистр положения подчеркивания mov al,14h out dx,al ; Вычисляем адрес порта регистра данных контроллера ЭЛТ inc dx ; Определяем положение подчеркивания символов mov al,CHAR_SIZE out dx,al ; Вычисляем адрес порта индексного регистра ; контроллера ЭЛТ dec dx ; Выбираем для обмена регистр завершения отображения ; вертикальной развертки ; Регистр завершения отображения вертикальной развертки ; содержит восемь младших бит, определяющих число ; отображаемых горизонтальных линий растра минус один mov al,12h out dx,al ; Вычисляем адрес порта регистра данных контроллера ЭЛТ inc dx ; Для отображения 43 текстовых символов, при высоте ; символов 8 пикселов, необходимо иметь 43 * 8 = 344 ; горизонтальных линий растра ; Помещаем в регистр завершения отображения вертикальной ; развертки младшие 8 бит числа 344 mov al,(43 * CHAR_SIZE - 1 - 256) out dx,al ; Устанавливаем новые значения переменных BIOS ; Количество символов в строке равно восьмидесяти mov WORD PTR es:[44Ah],80 ; Количество строк текста минус один mov BYTE PTR es:[484h],(350/CHAR_SIZE)-1 ; Высота символов в пикселах mov WORD PTR es:[485h],CHAR_SIZE ; Загружаем нулевую таблицу знакогенератора набором ; символов (размер 8х8) из ПЗУ BIOS mov ax,1112h xor bl,bl int 10h leave ret ENDP SET43LINE ENDS LINE_TEXT END
Регистр определяет момент гашения луча в процессе вертикальной развертки. У видеоадаптера EGA регистр имеет 9, а у видеоадаптера VGA - 10 разрядов. Девятый бит регистра SVBR расположен в дополнительном регистре (OVR). Десятый бит расположен в регистре высоты символов текста (MSLR).
Сигнал гашения вертикальной развертки завершается, когда счетчик горизонтальных линий соответствует значению регистра EVBR. Для видеоадаптера EGA регистр имеет 5 разрядов, а для VGA и SVGA 8 разрядов.
Регистр содержит набор битов, управляющих контроллером ЭЛТ.
D7 Бит D7 запрещает горизонтальный и вертикальный обратный ход луча.
D6 Если бит D6 равен единице, то установлен байтовый режим, а если он равен нулю - двухбайтовый. Двухбайтовый режим поддерживает разделение данных между двумя цветовыми слоями. Видеоадаптеры VGA и SVGA дополнительно поддерживают четырехбайтовый режим (см. регистр ULR).
Биты D6 D5 |
||
1х |
00 |
01 |
MA0 |
MA13 |
MA15 |
MA1 |
MA0 |
MA0 |
MA2 |
MA1 |
MA1 |
MA3 |
MA2 |
MA2 |
MA4 |
MA3 |
MA3 |
MA5 |
MA4 |
MA4 |
MA6 |
MA5 |
MA5 |
MA7 |
MA6 |
MA6 |
MA8 |
MA7 |
MA7 |
MA9 |
MA8 |
MA8 |
MA10 |
MA9 |
MA9 |
MA11 |
MA10 |
MA10 |
MA12 |
MA11 |
MA11 |
MA13 |
MA12 |
MA12 |
MA14 |
MA13 |
MA13 |
MA15 |
MA14 |
MA14 |
Бит D5 равен нулю только для видеоадаптеров EGA с объемом видеопамяти 64 Кбайт. В этом случае происходит сцепление слоев в графических режимах с высоким разрешением.
D4 Если бит D4 равен единице, то все выходные линии контроллера ЭЛТ переводятся в третье состояние. Этот бит используется при тестировании видеоадаптера.
D3 Если бит D3 равен нулю, то счетчик адреса регенерации изображения увеличивается на единицу на каждое знакоместо экрана, а если бит равен единице, то на каждые два знакоместа.
D2 Бит D2 может использоваться для увеличения в два раза вертикальной разрешающей способности. Если бит равен нулю, то счетчик числа линий экрана увеличивается после каждого обратного горизонтального хода луча, а если бит равен единице, то после двух обратных горизонтальных ходов луча.
D1 Используется для эмуляции графических режимов видеоадаптера Hercules. Запись нуля в этот бит приводит к замещению бита D14 адресного регистра битом D1 из регистра счетчика горизонтальных линий.
D0 Используется для эмуляции графических режимов CGA. Запись нуля в этот бит приводит к выделению в видеопамяти двух областей по 8 Кбайт каждая. Одна область соответствует четным, а другая нечетным строкам экрана. Такое отображение видеопамяти достигается в результате замещения бита D13 адресного регистра битом D0 из регистра счетчика горизонтальных строк.
Позволяет разделить изображение на две независимые части. При этом одну из них можно свертывать. Содержимое другой части экрана остается на месте.
Регистр LCR используют совместно с регистром начального адреса. Когда счетчик горизонтальных линий сканирования достигает значения, записанного в регистре LCR, происходит сброс счетчика адреса регенерируемой видеопамяти в ноль. В результате экран разбивается на две части. В верхней части экрана отображаются данные, на которые указывает регистр начального адреса, а в нижней - данные, находящиеся в начале видеопамяти. Процесс разделения экрана иллюстрируется рисунком 4.7.
Рисунок 4.7 Процесс разделения экрана
Изображение в верхней части экрана можно перемещать, изменяя содержимое регистра начального адреса.
У видеоадаптера EGA регистр сравнения линий имеет 9 разрядов. Девятый бит регистра доступен через дополнительный регистр (OVR) контроллера ЭЛТ. Регистр сравнения линий видеоадаптера VGA имеет 10 разрядов. Десятый бит регистра LCR расположен в регистре MSLR.
При изменении режима работы видеоадаптера, BIOS записывает в регистр сравнения линий значение 0FFh.
Программа, представленная ниже, выводит на экран монитора 25 строк текста, а затем, после нажатия любой клавиши, разделяет изображение на две части.
Листинг 4.9. Файл SCRSPLIT.C
#include <dos.h> #include <stdio.h> #include <conio.h> void __pascal __far Split(unsigned); void main(void); // Главная функция void main(void) { int i; for(i = 0; i < 25; i++) printf("Строка номер %d.\n",i); getch(); // Разделяем экран по линии 200 Split(200); // Ожидаем нажатие на клавиши клавиатуры getch(); // После завершения программы значения регистров не // восстанавливеются! }
Для разделения изображения на экране монитора предназначена функция Split. Исходный текст этой функции представлен в листинге 4.10.
Листинг 4.10. Файл SPLIT.ASM
TITLE SPLIT.ASM NAME SPLIT PAGE 55,132 P286 IDEAL NOWARN BRK SEGMENT SPLIT_TEXT WORD PUBLIC 'CODE' ASSUME cs:SPLIT_TEXT ;=========================================================== ; void Split(unsigned split_line) ; Функция разделяет экран на две части. Функция работает ; только на видеоадаптерах EGA и VGA. ; Параметр split_line определяет линию горизонтальной ; развертки, в которой происходит разделение экрана монитора ;=========================================================== split_line EQU [bp+6] PUBLIC SPLIT PROC SPLIT FAR enter 0, 0 ; Устанавливаем регистр ES на начало оперативной памяти xor ax,ax mov es,ax ; Получаем адрес порта индексного регистра контроллера ЭЛТ ; (3B4h/3D4h), в монохромных режимах для адресации к ; индексному регистру используется порт с адресом 3B4h, а ; в цветных - порт 3D4h mov dx,es:[463h] ; Вычисляем адрес порта регистра состояния 1, в ; монохромных режимах для адресации к регистру состояния 1 ; используется порт с адресом 3BAh, в цветных - порт 3DAh add dx,6 ; Ожидаем начало обратного вертикального хода луча in al,dx nop ; Если бит D3 равен единице, то происходит обратный ; вертикальный ход луча test al,8 jz wait_on wait_off: in al,dx nop test al,8 jnz wait_off wait_on: in al,dx nop test al,8 jz wait_on ; Вычисляем адрес порта индексного регистра ; контроллера ЭЛТ (3B4h/3D4h) sub dx,6 ; Выбираем для обмена регистр сравнения линий mov al,18h out dx,al ; Вычисляем адрес порта регистра данных контроллера ЭЛТ, ; в монохромных режимах для адресации к регистру данных ; используется порт с адресом 3B5h, а в цветных порт 3D5h inc dx ; Определяем линию горизонтальной развертки, в которой ; происходит разделение экрана дисплея mov ax,split_line ; У видеоадаптера EGA регистр сравнения линий состоит из 9 ; бит, доступ к девятому биту происходит через ; дополнительный регистр контроллера ЭЛТ; видеоадаптер ; VGA имеет еще и десятый бит, расположенный в регистре ; высоты символов текста ; Записываем младшие 8 битов в регистр сравнения линий out dx,al ; Вычисляем адрес порта индексного регистра ; контроллера ЭЛТ dec dx ; Вызываем функцию чтения конфигурации видеосистемы mov ax,1A00h int 10h ; Если после вызова функции регистр AL не равен 1Ah, то ; используемый видеодаптер не VGA cmp al,1Ah je vga jmp ega vga: ; Считываем в AL состояние дополнительнго регистра mov al,7 out dx,al inc dx in al,dx ; Модифицируем бит D4 дополнительного ргистра mov bx,split_line mov cl,4 shl bh,cl and bh,00010000b and al,11101111b or al,bh out dx,al ; Сбрасываем бит D6 регистра высоты символов текста dec dx mov al,9 out dx,al inc dx in al,dx and al,10111111b out dx,al jmp quit_split ega: mov bx,split_line mov cl,4 shl bh,cl and bh,00010000b cmp dx,3B4h ; монохромный режим? je default_1Fh ; Определяем наличие улучшенного цветного дисплея по ; положению переключателей на плате EGA mov al,es:[488h] and al,0Fh ; Положение переключателей "OFF OFF ON ON" ? cmp al,3 je default_1Fh ; Положение переключателей "OFF ON ON OFF" ? cmp al,9 je default_1Fh ; Для видиосистем с монохромным или цветным дисплеями, ; дополнительный регистр по умолчанию содержит 11h or bh,1 jmp set_overflow ; Для видиосистем с улучненным цветным дисплеем или в ; монохромных текстовых режимах дополнительный регистр по ; умолчанию содержит 1Fh default_1Fh: or bh,0Fh ; Устанавливаем дополнительный регистр set_overflow: mov al,07h out dx,al inc dx mov al,bh out dx,al quit_split: leave ret 2 ENDP SPLIT ENDS SPLIT_TEXT END
Синхронизатор управляет всеми временными параметрами видеоадаптера, а также разрешением и запрещением доступа к отдельным цветовым слоям видеопамяти. Синхронизатор содержит пять регистров. Их названия перечислены в таблице 4.12. У видеоадаптера EGA все пять регистров доступны только для записи, а у видеоадаптеров VGA и SVGA также и для чтения.
Индекс регистра |
Регистр синхронизатора |
0 |
Регистр сброса синхронизатора (Reset Register - RR) |
1 |
Регистр режима синхронизации (Clock Mode Register - CMR) |
2 |
Регистр разрешения записи цветового слоя (Color Plane Write Enable Register - CPWER) |
3 |
Регистр выбора знакогенератора (Character Generator Select Register - CGSR) |
4 |
Регистр определения структуры памяти (Memory Mode Register - MMR) |
Доступ к регистрам осуществляется через индексный порт с адресом 3C4h и через порт данных с адресом 3C5h.
Если регистр переведен в состояние сброса, то все процессы видеоадаптера приостанавливаются. В результате могут быть разрушены данные в видеопамяти.
D0 Бит асинхронного сброса. После записи в этот бит нуля происходит немедленный сброс и остановка синхронизатора. В результате информация из видеопамяти может быть потеряна.
D1 Бит синхронного сброса. Нулевое значение сбрасывает и останавливает синхронизатор в конце исполняемого цикла.
D7-D2 Не используются.
Для нормальной работы видеоадаптера биты D0 и D1 должны быть равны единице. Перед доступом к регистру режима синхронизации синхронизатор должен быть переведен в состояние синхронного сброса (бит D1 равен 0).
Регистр управляет временными циклами синхронизатора. При изменении его содержимого необходимо соблюдать осторожность. Меняя отдельные биты регистра, оставляйте значения остальных битов без изменения.
Перед модификацией регистра CMR надо сбросить бит D1 в регистре сброса синхронизатора, переведя, таким образом, синхронизатор в режим синхронного сброса и остановки.
D0 Бит определяет ширину символов в текстовых монохромных режимах с разрешением 720 пикселов по горизонтали. Если бит D0 равен нулю, то ширина матрицы символов составляет 9 пикселов, если единице - 8 пикселов.
D1 Бит используется видеоадаптером EGA для определения числа циклов, отводимых центральному процессору, для доступа к видеопамяти. При D1 равном единице, процессор может получить три из каждых пяти циклов, а при D1 равном нулю - только один из пяти циклов. Остальные циклы используются адаптером для регенерации видеопамяти.
D4-D2 Не используются.
D5 Используется только видеоадаптерами VGA и SVGA. Если бит D5 равен единице, то экран монитора гаснет и центральный процессор получает монополию на доступ к видеопамяти. Это несколько ускоряет процесс обмена процессора с видеопамятью.
D7-D6 Не используются.
Ниже приведены значения регистра CMR, устанавливаемые BIOS при установке режима работы адаптера:
Режим |
00,01,04,05,0Dh |
02,03,06,0Eh |
0Fh,10h |
Содержимое регистра |
0Bh |
01 |
05 |
При помощи данного регистра можно запретить запись данных в любые цветовые слои видеопамяти. На рисунке 4.8 показан механизм запрещения записи данных в отдельные слои видеопамяти. Рассмотрим процесс записи данных процессором в видеопамять:
ПЕРВЫЙ ШАГ
Процессор передает видеоадаптеру данные для записи в видеопамять. Они проходят через графический контроллер и попадают в синхронизатор. Графический контроллер выполняет над данными, записываемыми в видеопамять, операции, определяемые состоянием его регистров (смотри главу "Исполнение видеоадаптером операции записи" из раздела "Графический контроллер").
ВТОРОЙ ШАГ
Синхронизатор записывает данные в видеопамять в соответствии с содержимым регистра разрешения записи цветового слоя. Регистр разрешения записи цветового слоя содержит четыре бита, управляющие записью в цветовые слои видеопамяти. Если бит этого регистра, управляющий цветовым слоем равен нулю, то данный цветовой слой не изменяется. Если бит регистра равен единице, то в данный слой видеопамяти записываются значения, поступившие от графического контроллера.
Рисунок 4.8 Разрешение записи в цветовые слои
Биты регистра разрешения записи цветового слоя имеют следующие значения:
D0 Если бит D0 равен единице, то можно записывать данные в нулевой цветовой слой.
D1 Если бит D1 равен единице, то можно записывать данные в первый цветовой слой.
D2 Если бит D2 равен единице, то можно записывать данные в второй цветовой слой.
D3 Если бит D3 равен единице, то можно записывать данные в третий цветовой слой.
D7-D4 Не используются.
При установке режима работы адаптера BIOS загружает в регистр CPWE следующие значения:
Режим |
0,1,2,3,4,5,7 |
6 |
D,E,F,10 |
Содержимое регистра |
03 |
01 |
0Fh |
Видеоадаптер EGA позволяет загрузить в память четыре, а VGA и SVGA - восемь таблиц знакогенератора, каждая из которых определяет 256 символов. Одновременно могут использоваться символы одной или двух таблиц знакогенератора. Это позволяет одновременно отображать на экране монитора до 512 различных символов.
Если разрешено одновременное использование двух различных таблиц знакогенератора, тогда бит D3 байта атрибутов указывает, какая таблица будет использоваться при отображении символа с этим атрибутом.
Регистр выбора знакогенератора определяет два активных набора символов, расположенных во втором цветовом слое, символы которых могут одновременно отображаться на экране. Данный регистр используется только в текстовых режимах.
D1-D0 Выбор первой активной таблицы знакогенератора. Эта таблица используется для вывода символа на экран, если бит D3 байта атрибутов символа содержит ноль.
D3-D2 Выбор второй активной таблицы знакогенератора. Вторая таблица используется для вывода символа на экран, если бит D3 байта атрибутов символа содержит единицу.
D4 Дополнительный бит, доступный на видеоадаптерах VGA и SVGA. Используется для выбора первой таблицы знакогенератора.
D5 Дополнительный бит, доступный на видеоадаптерах VGA и SVGA. Используется для выбора второй таблицы знакогенератора.
D7-D6 Не используются.
Для выбора активных таблиц знакогенератора надо установить биты D0-D5 в соответствии со следующей таблицей:
D5 D3 D2 |
Номер таблицы знакогенератора, используемой, если бит D3 байта атрибутов равен 1 |
D4 D1 D0 |
Номер таблицы знакогенератора, используемой если бит D3 байта атрибутов равен 0 |
0 0 0 |
Первая таблица знакогенератора |
0 0 1 |
Вторая таблица знакогенератора |
0 1 0 |
Третья таблица знакогенератора |
0 1 1 |
Четвертая таблица знакогенератора |
1 0 0 |
Пятая таблица знакогенератора (видеоадаптеры VGA и SVGA) |
1 0 1 |
Шестая таблица знакогенератора (видеоадаптеры VGA и SVGA) |
1 1 0 |
Седьмая таблица знакогенератора (видеоадаптеры VGA и SVGA) |
1 1 1 |
Восьмая таблица знакогенератора (видеоадаптеры VGA и SVGA) |
Если нужна только одна активная таблица знакогенератора, то значения битов D5 D3 D2 и битов D4 D1 D0 должны совпадать.
Регистр инициализируется BIOS во время выбора режима работы видеоадаптера и определяет структуру видеопамяти в этом режиме.
D0 Для видеоадаптера EGA бит D0 содержит единицу, при использовании в текстовом режиме функции выбора знакогенератора. Для адаптера VGA этот бит обычно сброшен в ноль.
D1 Для видеоадаптера EGA бит D1 равен единице, если объем видеопамяти больше 64 Кбайт.
D2 Если бит D2 содержит ноль, то доступ по четным адресам происходит к нулевому цветовому слою, а по нечетным - к первому.
D7-D3 Не используются.
При выборе режима работы адаптера, BIOS загружает в регистр CPWE следующие значения:
Режим |
0,1,2,3,7 |
4,5 |
6,0Dh,0Eh |
0Fh,10h |
Содержимое регистра |
03 |
02 |
06 |
00 |
Графический контроллер поддерживает обмен данными между центральным процессором и видеопамятью. При этом он может выполнять простейшие логические операции над данными записываемыми в видеопамять. В графических режимах работы видеоадаптера графический контроллер передает данные из цветовых слоев видеопамяти контроллеру атрибутов.
Графический контроллер содержит девять регистров. Обращение к ним происходит через индексный порт с адресом 3CEh и порт данных с адресом 3CFh. Адаптер EGA имеет два дополнительных порта с адресами 3CAh и 3CCh, используемых при инициализации видеоадаптера.
Список регистров представлен в следующей таблице:
Индекс регистра |
Регистр графического контроллера |
0 |
Регистр установки/сброса (Set/Reset Register - SRR) |
1 |
Регистр разрешения установки/сброса (Set/Reset Enable Register - SRER) |
2 |
Регистр сравнения цветов (Color Compare Register - CCR) |
3 |
Регистр циклического сдвига и выбора функции (Data Rotate & Function Select - DRFS) |
4 |
Регистр выбора читаемого слоя (Read Plane Select Register - RPSR) |
5 |
Регистр режима работы (Mode Register - MDR) |
6 |
Регистр смешанного назначения (Miscellaneous Register - MIR) |
7 |
Регистр маскирования цветовых слоев (Color Don't Care Register - CDCR) |
8 |
Регистр битовой маски (Bit Mask Register - BMR) |
На рисунке 4.9, демонстрируются функции, выполняемые графическим контроллером. Рассмотрим функционирование графического адаптера.
Байт, записываемый центральным процессором в видеопамять (11100001b), поступает в графический контроллер. В соответствии со значением регистра циклического сдвига и выбора функции, происходит циклический сдвиг на один бит содержимого байта, записываемого в видеопамять.
Полученный результат складывается по логике ИЛИ с содержимым регистров-защелок. Вы можете применить другие булевы функции - И, ИСКЛЮЧАЮЩЕЕ ИЛИ. Используемая булева функция выбирается регистром циклического сдвига и выбора функции.
Дальнейшие преобразования происходят в соответствии со значениями регистра разрешения установки/сброса и регистра установки/сброса:
Затем в зависимости от состояния регистра битовой маски происходит запись данных в видеопамять:
Рисунок 4.9 Функции графического контроллера
Теперь рассмотрим регистры графического контроллера более подробно.
Регистр SRR совместно с регистром разрешения установки/сброса (Set/Reset Enable Register), управляет записью данных в видеопамять. Возможности использования регистра SRR разъясняются при описании регистра разрешения установки/сброса.
Приведем формат регистра установки/сброса:
D0 Данные, записываемые в цветовой слой 0.
D1 Данные, записываемые в цветовой слой 1.
D2 Данные, записываемые в цветовой слой 2.
D3 Данные, записываемые в цветовой слой 3.
D7-D4 Зарезервировано.
По умолчанию во все биты регистра записываются нулевые значения.
Регистр разрешения установки/сброса позволяет при записи в видеопамять для одних цветовых слоев использовать данные от центрального процессора, а для других - из регистра установки/сброса (рис. 4.10).
Если биты регистра, управляющие цветовыми слоями, содержат единицы, то при выполнении операции записи, в соответствующие цветовые слои записывается информация из регистра установки/сброса. В остальные слои видеопамяти заносятся данные процессора.
Теперь приведем формат регистра разрешения установки/сброса:
D0 Разрешение использования данных из регистра установки/сброса для цветового слоя 0.
D1 Разрешение использования данных из регистра установки/сброса для цветового слоя 1.
D2 Разрешение использования данных из регистра установки/сброса для цветового слоя 2.
D3 Разрешение использования данных из регистра установки/сброса для цветового слоя 3.
D7-D4 Зарезервировано.
По умолчанию во все биты регистра записываются нулевые значения.
Заметим, что возможность использования регистров установки/сброса можно реализовать только в нулевом режиме записи. Режим записи устанавливается регистром режима работы графического контроллера (Mode Register, индекс 5). В нулевом режиме записи, если запрещено выполнение операции маскирования пикселов (регистр битовой маски содержит значение 0FFh), то каждый байт, записываемый процессором в видеопамять определяет 8 пикселов в одном или нескольких цветовых слоях.
Рассмотрим на рисунке 4.10 применение регистров установки/сброса. Пусть графический контроллер находится в нулевом режиме работы, и регистр битовой маски равен 0FFh (используются только данные от процессора). В этом случае можно использовать регистры установки/сброса.
Допустим, что после преобразования данных, записываемых процессором в видеопамять, в соответствии со значением регистра циклического сдвига и выбора функций, данные имеют следующий вид:
байт 11110000b передается в третий слой видеопамяти,
байт 00000011b передается во второй слой видеопамяти,
байт 00110011b передается в первый слой видеопамяти,
байт 00110011b передается в нулевой слой видеопамяти.
Данные, записываемые в видеопамять зависят от значения регистра разрешения установки/сброса. Биты D3 и D0, регистра разрешения установки/сброса равны нулю, поэтому в третий слой и нулевой слой видеопамяти данные заносятся без изменения. Биты D2 и D1 регистра разрешения установки/сброса равны единице, значит во второй и первый слои видеопамяти записываются данные в соответствии со значением битов D2 и D1 регистра установки/сброса. То есть во второй слой записывается байт 00000000b, а в первый - 11111111b.
Рисунок 4.10 Использование регистров установки/сброса
Регистр CCR можно использовать для поиска на экране пикселов с определенным цветом. Без использования регистра CCR за один цикл чтения видеопамяти процессор может считать данные только из одного цветового слоя. Программирование регистра CCR позволяет за один цикл чтения прочитать все четыре цветовых слоя, сравнить считанные значения с искомыми и возвратить результат.
Ниже представлен формат регистра сравнения цветов:
D0 Искомая величина для нулевого цветового слоя.
D1 Искомая величина для первого цветового слоя.
D2 Искомая величина для второго цветового слоя.
D3 Искомая величина для третьего цветового слоя.
D7-D4 Не используются.
После выполнения BIOS установки режима работы видеоадаптера все биты регистра содержат нулевые значения.
Операция поиска пикселов данного цвета иллюстрируется рисунком 4.11.
Рисунок 4.11 Использование регистра CCR
Как видно из рисунка, в случае совпадения сравниваемых битов соответствующий бит результата равен единице.
Перед использованием регистра CCR для выполнения операции поиска пикселов определенного цвета необходимо установить регистр режима работы (Mode Register - MDR) и регистр маскирования цветовых слоев (Color Don't Care Register - CDCR), описанные ниже.
Регистр DRFS выполняет две различные функции, отраженные в его названии:
D2-D0 Счетчик сдвига. D4-D3 Биты выбора логической функции. D7-D5 Не используются.
После выполнения BIOS установки режима работы видеоадаптера биты регистра DRFS содержат нулевые значения.
При выполнении операции циклического сдвига биты счетчика сдвига могут иметь следующие значения:
D2 D1 D0 |
Данные циклически сдвигаются вправо на следующее количество битов |
0 0 0 |
Ноль, сдвиг не происходит |
0 0 1 |
Один бит |
0 1 0 |
Два бита |
0 1 1 |
Три бита |
1 0 0 |
Четыре бита |
1 0 1 |
Пять бит |
1 1 0 |
Шесть бит |
1 1 1 |
Семь бит |
Во время выполнения процессором операции чтения из видеопамяти одновременно происходит запись данных из всех четырех цветовых слоев (по считываемому адресу) в регистры-защелки. Каждому цветовому слою видеопамяти соответствует один 8-битовый регистр-защелка. Когда процессор начнет записывать данные в видеопамять (возможно уже по другому адресу), адаптер может комбинировать их с данными из регистров-защелок. Вид выполняемой логической операции будет зависеть от содержимого битов выбора логической функции:
D4 D3 |
Логическая операция |
0 0 |
Запись не модифицированных данных |
0 1 |
И |
1 0 |
ИЛИ |
1 1 |
ИСКЛЮЧАЮЩЕЕ ИЛИ |
Следует отметить, что операция циклического сдвига выполняется до выполнения логических функций.
Регистр DRFS можно использовать для быстрого копирования областей видеопамяти с возможной их модификацией.
Рисунок 4.12 иллюстрирует выполнение логической операции ИЛИ. Регистр циклического сдвига и выбора функции содержит число 00010000b. После операции чтения данные из всех четырех слоев записываются в регистры-защелки. Затем выполняется операция записи. Данные процессора в соответствии с состоянием регистра циклического сдвига и выбора функции складываются по логике ИЛИ со значением регистров-защелок и помещаются в видеопамять.
Рисунок 4.12 Логические операции и операция циклического сдвига
Регистр определяет номер цветового слоя видеопамяти, из которого процессор может читать данные. При выполнении операции сравнения цветов значение этого регистра безразлично.
Приведем формат регистра выбора читаемого слоя.
Биты |
Описание |
D1-D0 |
Номер читаемого цветового слоя видеопамяти |
D7-D2 |
Не используется |
При установке режима работы видеоадаптера BIOS заполняет все биты регистра нулями, что соответствует нулевому цветовому слою.
Чтение центральным процессором данных из видеопамяти иллюстрируется на рисунке 4.13. На этом рисунке регистр выбора читаемого слоя разрешает чтение второго слоя видеопамяти. Таким образом, при чтении процессором данных из видеопамяти, процессор считывает данные только из второго слоя. Остальные слои видеопамяти недоступны для чтения процессором, пока вы не измените состояние регистра читаемого слоя.
Рисунок 4.13 Операция чтения видеопамяти
Регистр управляет несколькими функциями графического контроллера. В частности он управляет режимом записи в видеопамять и режимом сравнения цветов (см. регистр сравнения цветов графического контроллера).
Биты |
Описание |
D1-D0 |
Режим записи |
D2 |
Не используется |
D3 |
Разрешение режима сравнения цветов |
D4 |
Четный/нечетный режим |
D5 |
Режим регистра сдвига |
D6 |
Управление режимом VGA с 256 цветами (режим номер 13h) |
D7 |
Не используется |
Ниже подробно рассмотрены отдельные биты регистра MDR. Изменение битов D4-D7, может привести к потере изображения на экране монитора. Обычно эти биты загружаются только при установке режима работы видеоадаптера.
D1, D0 Данные биты устанавливают режим записи в видеопамять. Вы можете выбрать один из трех режимов записи:
D1 D0 |
Номер режима |
Режим записи |
0 0 |
0 |
Режим непосредственной записи |
0 1 |
1 |
Использование для записи регистров-защелок |
1 0 |
2 |
Заполнение N-ого цветового слоя битом номер N из данных, записываемых процессором |
1 1 |
- |
Не используется |
Рисунок 4.14 Режим записи 0
Рисунок 4.15 Режим записи 1
Рисунок 4.16 Режим записи 2
D3 Бит D3 управляет режимом сравнения цветов (см. регистр сравнения цветов графического контроллера). Для перевода видеоадаптера в режим сравнения цветов бит D3 должен содержать единицу.
Остальные биты регистра модифицировать не рекомендуется.
D4 Бит D4 устанавливается в текстовых режимах. В этом случае доступ по четным адресам происходит к четным цветовым слоям, а по нечетным адресам - к нечетным цветовым слоям видеопамяти (см. видеопамять в текстовых режимах).
D5 Бит D5 используется в режимах видеоадаптера номер 4 и 5 для обработки видеоданных в формате "два бита на пиксел".
D6 Бит D6 используется видеоадаптерами VGA и SVGA в режиме с 256 цветами (режим 13h).
При установке режима работы видеоадаптера BIOS загружает в регистр MDR следующие значения, в зависимости от режима работы видеоадаптера:
Режим |
0,1,2,3,7,F,10 |
4,5 |
6,D,E |
Содержимое регистра |
10h |
30h |
00 |
Регистр управляет различными характеристиками видеоадаптера. В результате ошибочной модификации регистра возможна неправильная работа некоторых функций BIOS и конфликты между видеоадаптерами в системе с двумя мониторами.
D0 Бит разрешения графического режима. Бит должен содержать 1 для графического и 0 для текстового режима. В графическом режиме запрещается генерация символов и разрешается адресация к отдельным пикселам.
D1 Используется видеоадаптерами EGA, имеющими 64 Кбайт памяти. Если бит D1 установлен, то четыре слоя видеопамяти по 16 Кбайт каждый объединяются в два слоя по 32 Кбайт.
D3-D2 Биты D3 и D2 устанавливают начальный и конечный адреса, на которые отображается видеопамять адаптера EGA:
D3 D2 Адреса видеопамяти
0 0 A000:0000h-B000:FFFFh
0 1 A000:0000h-A000:FFFFh
1 0 B000:0000h-B000:7FFFh
0 1 B800:0000h-B000:FFFFh
D7-D4 Не используются.
При установке режима работы видеоадаптера BIOS загружает в регистр MIR следующие значения, в зависимости от режима работы видеоадаптера:
Режим |
3 |
7 |
F |
10 |
Содержимое регистра |
Eh |
Ah |
07 |
05 |
Регистр используется в режиме сравнения цветов (см. регистр сравнения цветов - CCR). Если какие-либо биты D3-D0 содержат ноль, то при операции сравнения цветов соответствующие цветовые слои в рассмотрение не принимаются.
D0 Управление нулевым цветовым слоем.
D1 Управление первым цветовым слоем.
D2 Управление вторым цветовым слоем.
D3 Управление третьим цветовым слоем.
D7-D4 Не используются.
При установке режима работы в регистр заносятся следующие значения:
Режим |
3 |
7 |
F |
10 |
Содержимое регистра |
00 |
00 |
0Fh |
0Fh |
Регистр управляет записью данных в видеопамять. Если бит регистра BMR содержит ноль, то соответствующий бит будет записываться в видеопамять из регистра-защелки. В противном случае данный бит поступает от центрального процессора (рис. 4.17). Регистр BMR используется только в нулевом режиме записи.
Рисунок 4.17 Использование регистра битовой маски
Напомним, что занести данные в регистр-защелку можно, если выполнить операцию чтения из видеопамяти. Во время выполнения операции чтения в каждый регистр-защелку записывается один байт из соответствующего цветового слоя видеопамяти.
По умолчанию, во всех режимах регистр BMR хранит число 0FFh.
Контроллер атрибутов управляет цветовыми характеристиками изображений. Контроллер атрибутов содержит двадцать один регистр. Названия регистров перечислены в следующей таблице:
Индекс |
Регистры контроллера атрибутов |
0 - 0Fh |
Шестнадцать регистров цветовой палитры (Color Palette Register's - CPR) |
10h |
Регистр управления режимом (Mode Control Register - MCR) |
11h |
Регистр цвета рамки экрана (Screen Border Color Register - SBCR) |
12h |
Регистр разрешения цветового слоя (Color Plane Enable Register - CPER) |
13h |
Регистр горизонтального панорамирования (Horizontal Panning Register - HPR) |
14h |
Регистр выбора цвета (Color Select Register - CSR) |
Доступ ко всем регистрам осуществляется через единственный порт с адресом 3C0h (в отличие от предыдущих рассмотренных нами регистров). Этот порт совмещает в себе функции индексного порта и порта данных, регулируемые внутренним триггером. Триггер переключается каждый раз записи данных в порт. В зависимости от состояния триггера записываемые данные воспринимаются либо как индекс регистра, либо как данные для обмена с регистром.
Установить триггер в исходное состояние можно, выполнив чтение из порта 3BAh для монохромного режима или из порта 3DAh - для цветного режима работы видеоадаптера. После установки триггера в исходное состояние данные, записываемые в регистр 3C0h, будут восприниматься, как индекс регистра.
Четыре цветовых слоя видеоадаптера EGA позволяют закодировать 16 различных цветов, однако улучшенный цветной монитор обеспечивает возможность отображения 64 цветов.
С помощью 16 регистров цветовой палитры можно выбрать любые 16 цветов из 64 возможных. Эти цвета будут использоваться для отображения на экране.
Если к видеоадаптеру EGA подключен улучшенный цветной монитор, то каждый регистр цветовой палитры содержит шесть битов, соответствующих шести линиям управления монитора.
Цветной и монохромный мониторы имеют меньшее число линий управления и регистр цветовой палитры также имеет другой формат.
Форматы регистров цветовой палитры для различных мониторов приведены ниже:
D0 Голубой.
D1 Зеленый.
D2 Красный.
D3 Второй голубой.
D4 Второй зеленый.
D5 Второй красный.
D7-D6 Не используются.
D0 Голубой.
D1 Зеленый.
D2 Красный.
D3 Не используется.
D4 Интенсивность.
D7-D5 Не используются.
D2-D0 Не используются.
D3 Видео выход.
D4 Интенсивность.
D7-D5 Не используются.
D0 P0
D1 P1
D2 P2
D3 P3
D4 P4
D5 P5
D7-D6 Не используются.
Регистр управления режимом управляет контроллером атрибутов.
D0 Бит D0 содержит ноль для текстовых режимов, единицу - для графических. Бит определяет метод интерпретации атрибутов.
D1 Бит D1 определяет тип атрибутов. Для монохромных режимов он должен быть равен единице, а для режимов - нулю.
D2 Бит используется в монохромных режимах с разрешением по горизонтали 720 пикселов для расширения горизонтального размера матриц символов псевдографики с 8 до 9 пикселов. Если бит D2 равен 1, то девятый пиксел в каждой строке будет повторять восьмой. В противном случае девятый пиксел отображается цветом фона.
D3 Бит D3 управляет назначением седьмого бита в байте атрибутов. Если бит установлен, то бит D7 байта атрибутов управляет миганием символа. Если бит D3 равен нулю, то - интенсивностью фона.
D4 Не используется.
D5 Доступен только для видеоадаптеров VGA и SVGA. Совместно с регистром разделения экрана монитора (регистр контроллера ЭЛТ) бит D5 управляет горизонтальной сверткой экрана. При установке бита D5 запрещается горизонтальная свертка стационарной части экрана.
D6 Бит D6 используется только видеоадаптерами VGA и SVGA. Бит должен быть равен нулю для режима с 256 цветами (режим 13h).
D7 Доступен только для видеоадаптеров VGA и SVGA. Выбор источника сигнала для видеовыходов Р4 И Р5. Если D7 равен нулю, то линии Р4 и Р5 управляются регистрами палитры. В противном случае сигналы на линии Р4 и Р5 поступают из битов D0 и D1 регистра выбора цветов.
По умолчанию регистр содержит следующие значения:
Режим |
0,1,2,3 |
4,5,6,D,E,10 |
7 |
F |
Содержимое регистра |
08 |
01 |
0Eh |
0Bh |
В текстовых режимах работы видеоадаптеров регистр SBCR определяет цвет рамки, расположенной вокруг текста. Назначение битов регистра соответствует регистрам цветовой палитры. По умолчанию регистр цвета рамки содержит нулевые значения для всех режимов работы.
Операция установки цвета рамки не работает на большинстве адаптеров EGA.
D3-D0 Биты разрешения цветовых слоем. Если бит равен нулю, то данные из соответствующего цветового слоя не поступают в регистры цветовой палитры. Таким образом, достигается эффект маскирования отдельных цветовых слоев.
D5-D4 Используются вместе с диагностическими битами регистра состояния 1 для чтения регистров палитры.
D7-D6 Не используются.
При установке режима работы видеоадаптера BIOS записывает в регистр следующие значения:
Режим |
0,1,2,3,7,D,E |
4,5 |
6 |
F,10 |
|
Содержимое регистра |
0Fh |
03 |
03 |
01 |
05 |
Регистр позволяет сдвинуть изображение на экране в горизонтальном направлении. При использовании регистра HPR совместно с регистром начального адреса контроллера атрибутов можно сдвигать изображение на любое количество пикселов.
Формат регистра горизонтального панорамирования представлен ниже:
D3-D0 Биты определяют величину горизонтального сдвига:
Биты |
Величина сдвига содержимого экрана (в пикселах) |
| ||
D3 D2 D1 D0 |
Монохромный текстовый режим |
Режим 13h |
Остальные режимы |
|
0 0 0 0 |
8 |
0 |
0 |
|
0 0 0 1 |
0 |
- |
1 |
|
0 0 1 0 |
1 |
1 |
2 |
|
0 0 1 1 |
2 |
- |
3 |
|
0 1 0 0 |
3 |
2 |
4 |
|
0 1 0 1 |
4 |
- |
5 |
|
0 1 1 0 |
5 |
3 |
6 |
|
0 1 1 1 |
6 |
- |
7 |
|
1 0 0 0 |
7 |
- |
- |
|
1 0 0 1 |
- |
- |
- |
|
1 0 1 0 |
- |
- |
- |
|
1 0 1 1 |
- |
- |
- |
|
1 1 0 0 |
- |
- |
- |
|
1 1 0 1 |
- |
- |
- |
|
1 1 1 0 |
- |
- |
- |
|
1 1 1 1 |
- |
- |
- |
D7-D4 Не используются.
По умолчанию для всех режимов работы видеоадаптера регистр горизонтального панорамирования содержит нулевые значения для всех битов.
На рисунке 8.18 иллюстрируется операция горизонтального сдвига содержимого экрана при различных значениях регистра HPR. На левой части рисунка регистр горизонтального панорамирования содержит ноль, а на правой части рисунка значение регистра увеличено до трех. Изображение на экране сдвигается на три пиксела влево.
Рисунок 4.18 Горизонтальный сдвиг экрана
Программа SCRSPLIT позволяет перемещать содержимое экрана по горизонтали и вертикали. Исходный текст программы представлен в листинге 4.11.
Листинг 4.11. Файл SCRSPLIT.C
// Смещение содержимого экрана по горизонтали и вертикали #include "sysgraph.h" #include <stdio.h> #include <stdlib.h> #include <graph.h> #include "sysp.h" #include <dos.h> void HorScroll(unsigned, unsigned); void VerScroll(unsigned); void SetColumn(unsigned char); void main(void) { struct videoconfig vc; unsigned char i,j; // выбираем текстовый режим работы видеоадаптера, // принятый по умолчанию _setvideomode(_DEFAULTMODE); // устанавливаем логическую ширину экрана в 100 символов SetColumn(100); // отображаем на экране монитора 24 строки текста for(i = 0; i < 24; i++) printf("\ntext text text"); // производим горизонтальное смещение экрана // на i пикселов при каждом нажатии на клавиатуру for(i = 0; i < 13; i++) { getch(); HorScroll(i,8); } // производим вертикальное смещение экрана // на i пикселов при каждом нажатии на клавиатуру for(i = 0; i < 13; i++) { getch(); VerScroll(i); } getch(); _setvideomode(_DEFAULTMODE); }
Сдвиг изображения на экране монитора выполняют функции HorScroll и VerScroll. Функция HorScroll сдвигает изображение в горизонтальном направлении, а функция VerScroll в вертикальном. Исходный текст функций представлен в листинге 4.12.
Листинг 4.12. Файл SPLIT.ASM
/** *.Name HorScroll * *.Title Горизонтальный сдвиг содержимого экрана. * *.Descr Функция смещает содержимое экрана влево на определенное * число пикселов. * *.Proto void HorScroll(unsigned offset, unsigned wide) * *.Params unsigned offset - величина смещения в пикселах, * * unsigned wide - ширина символов (8 или 9). * *.Return Не используется. * *.Sample scroll.c **/ void HorScroll(unsigned offset, unsigned wide) { unsigned start_addr_reg, panning_reg; div_t res; res = div(offset,wide); start_addr_reg = res.quot; panning_reg = (wide == 9) ? ((res.rem == 0) ? 8 : res.rem - 1 ) : res.rem; _asm { push ds ; вычисляем адрес регистра состояния 1 (3BAh/3DAh) xor ax,ax mov es,ax mov dx,es:[463h] add dx,6 ; ожидаем начало обратного вертикального хода луча in al,dx nop nop test al,08h jz wait_on wait_off: in al,dx nop nop test al,08h jnz wait_off wait_on: in al,dx nop nop test al,08h jz wait_on ; вычисляем адрес порта индексного регистра контроллера ЭЛТ sub dx,6 ; выбираем для доступа младший байт регистра начального адреса mov al,0Dh out dx,al ; вычисляем адрес порта регистра данных контроллера ЭЛТ inc dx ; устанавливаем новый начальный адрес mov ax,start_addr_reg out dx,al ; снова получаем адрес порта регистра состояния 1 add dx,5 ; сбрасываем внутренний триггер контроллера атрибутов, управляющий ; адресацией его регистров in al,dx nop nop ; выбираем регистр горизонтального панорамирования mov dx,3C0h mov al,13h out dx,al mov ax,panning_reg out dx,al pop ds } } /** *.Name VerScroll * *.Title Вертикальный сдвиг содержимого экрана. * *.Descr Функция смещает содержимое экрана вверх на определенное * число пикселов. * *.Proto void VerScroll(unsigned offset) * *.Params unsigned offset - величина смещения в пикслах. * *.Return Не используется. * *.Sample scroll.c **/ void VerScroll(unsigned offset) { unsigned start_addr_reg, preset_row_reg; div_t res; BIOS_VAR _far *bios_var_ptr; bios_var_ptr = (BIOS_VAR _far *) FP_MAKE(0x0000, 0x0410); res = div(offset,bios_var_ptr -> wCharHigh); start_addr_reg = res.quot * (bios_var_ptr -> wColumns); preset_row_reg = res.rem; _asm { push ds ; вычисляем адрес регистра состояния 1 (3BAh/3DAh) xor ax,ax mov es,ax mov dx,es:[463h] add dx,6 ; ожидаем начало обратного вертикального хода луча in al,dx nop nop test al,08h jz wait_on wait_off: in al,dx nop nop test al,08h jnz wait_off wait_on: in al,dx nop nop test al,08h jz wait_on ; вычисляем адрес порта индексного регистра контроллера ЭЛТ sub dx,6 ; модифицируем младший байт регистра начального адреса mov al,0Dh out dx,al inc dx mov ax,start_addr_reg out dx,al dec dx ; модифицируем старший байт регистра начального адреса mov al,0Ch out dx,al inc dx mov al,ah out dx,al ; вычисляем адрес порта регистра состояния 1 add dx,5 ; ожидаем вертикальный обратный ход луча wait_next: in al,dx nop nop test al,08h jz wait_next ; определяем адрес порта индексного регистра контроллера ЭЛТ sub dx,6 ; устанавливаем регистр предустановки линии сканирования mov al,8 out dx,al mov ax,preset_row_reg inc dx out dx,al pop ds } } /** *.Name SetColumn * *.Title Установка логической ширины экрана. * *.Descr Функция устанавливает логическую ширину экрана. * *.Proto void SetColumn(unsigned char col) * *.Params unsigned char col - логическая ширина экрана (в символах). * *.Return Не используется. * *.Sample scroll.c **/ void SetColumn(unsigned char col) { _asm { xor ax,ax mov es,ax ; получаем адрес порта индексного регистра ; контроллера ЭЛТ (3B4h/3D4h) mov dx,es:[463h] ; выбираем для обмена регистр логической ширины экрана mov al,13h out dx,al ; вычисляем адрес порта регистра данных контроллера ЭЛТ (3B5h/3D5h) inc dx ; модифицируем переменную BIOS, содержащую число символов в строке mov al,col mov es:[44Ah],al ; регистр логической ширины экрана в текстовых режимах содержит ; смещение между соседними строками текста в словах shr al,1 out dx,al } }
Регистр используется видеоадаптерами VGA и SVGA для управления цветом.
D0 Цвет Р4.
D1 Цвет Р5. Данные биты могут использоваться вместо линий Р5 и Р4 соответственно (см. регистры палитры и рис. 6.18).
D2 Цвет Р6.
D3 Цвет Р7. Биты используются контроллером атрибутов в качестве двух старших битов, передаваемых ЦАП (рис. 6.18). В режиме 13h биты D2 и D3 не используются.
D7-D4 Не используются.
Видеоадаптеры VGA и SVGA предназначены для подключения к аналоговым мониторам, имеющим три раздельных видеовхода. Сигнал на каждом из них управляет, соответственно, интенсивностью красного, зеленого и синего цвета изображения. Аналоговое напряжение для монитора формируется из двоичной цветовой информации при помощи трех ЦАП.
Цветовая 8-битовая информация, поступающая от контроллера атрибутов (рис. 4.19), преобразуется согласно таблице цветов в три 6-битовые сигнала для трех ЦАП. Такая схема позволяет одновременно отображать на экране 256 различных цветов, каждый из которых можно отдельно выбрать из 26+6+6 = 218 = 262144 возможных цветов.
Рисунок 4.19 Схема управления цветами видеоадаптера VGA
Таблица цветов фактически является набором из 256 18-битовых регистров. Используя регистры ЦАП, можно получить доступ для чтения и для записи к каждому регистру таблицы цветов.
ЦАП видеоадаптера VGA управляется пятью регистрами, перечисленными в следующей таблице:
Адрес |
Регистр |
3C6h |
Регистр маскирования пикселов (Pixel Mask Register - PMR) |
3C7h |
Регистр состояния ЦАП (для чтения) (DAC State Register - DAC_SR) |
3C7h |
Индекс читаемого регистра таблицы цветов (для записи) (Look-up Table Read Index Register - LTRIR) |
3C8h |
Индекс записываемого регистра таблицы цветов (Look-up Table Write Index Register - LTWIR) |
3C9h |
Регистр данных таблицы цветов (Look-up Table Data Register - LTDR) |
Фирма IBM в руководстве видеоадаптера VGA предупреждает, что доступ к регистру нежелателен. В противном случае могут разрушиться данные в таблице цветов.
Регистр адресуется при помощи порта с адресом 3C7h и доступен только для чтения. Прочитав данные из регистра, можно определить, доступны регистры цветовой таблицы для чтения или же они доступны для записи.
D1-D0 Если биты D0 D1 содержат двоичное число 11b, то регистры цветовой таблицы доступны для записи, если D0 D1 содержат двоичное число 00b (шестнадцатиричное 0), то регистры цветовой таблицы доступны для чтения.
D7-D2 Не используются.
Этот индексный регистр доступен через порт 3C7h только для записи. Запись в данный регистр индекса элемента цветовой таблицы позволяет прочитать его через регистр данных цветовой таблицы.
D7-D0 Индекс регистра таблицы цветов (0-255).
Данные из регистров таблицы цветов читаются через порт 3C9h, как три 6-битовых числа. После чтения третьего числа значение индексного регистра (LTRIR) автоматически увеличивается на единицу, что позволяет прочитать всю таблицу цветов, загрузив регистр индекса только один раз.
Во время операций чтения или записи таблицы цветов прерывания должны быть запрещены.
После записи в регистр LTWIR индекса регистра таблицы цветов можно записать в него новое значение через регистр данных таблицы цветов (см. ниже).
D7-D0 Индекс регистра таблицы цветов (0-255).
Данные записываются в регистры таблицы цветов через порт 3C9h, как три 6-битовых числа. После записи третьего числа значение индексного регистра (LTWIR) автоматически увеличивается на единицу, что позволяет прочитать таблицу цветов, загрузив регистр индекса только один раз.
Регистр используется для получения доступа к регистрам таблицы цветов. Для чтения и записи одного элемента таблицы цветов необходимо три раза прочитать (записать) содержимое регистра данных. При этом каждый раз считывается (записывается) шесть очередных битов. Первые шесть битов отвечают за интенсивность красного, вторые - зеленого и третьи - синего цвета.
Нельзя прерывать цикл чтения регистров таблицы цветов, состоящий из трех операций чтения, выполнением операции записи в другой регистр таблицы и наоборот. Во время доступа к регистру LTDR прерывания должны быть запрещены. Между операциями доступа к регистрам таблицы цвета необходимо выдержать временной интервал не менее 240 наносекунд.
D5-D0 Данные для обмена с регистрами таблицы цветов.
D7-D6 Не используется.
Программа VGA256 (листинг 4.13) записывает новые значения в таблицу цветов непосредственно через регистры цифро-аналогового преобразователя VGA. На экране монитора отображается пять вертикальных полос различного цвета. Каждая полоса состоит из 64 вертикальных линий. Интенсивность цвета этих линий плавно уменьшается слева на право.
Листинг 4.13. Файл VGA256.C
#include <stdio.h> #include <conio.h> #include "sysp.h" #include "sysgraph.h" #include <dos.h> // Описания функций int main( void ); void SetVideoMode( unsigned char ); void Hello(void); // Функция SetVgaDAC определена в файле DACTABLE.ASM void __pascal __far SetVgaDAC(unsigned, unsigned); //=========================================================== // Главная функция //=========================================================== int main( void ) { RGB color_table[256]; int error, x_num, y_num; unsigned i, j, iii; unsigned seg_table,off_table; unsigned char far *ptr; // Записываем в массив color_table новые значения для // регистров таблицы цветов for(j = 0; j < 4; j++) { for(i = 0; i < 64; i++) { (color_table[i+j*64]).red = (j == 0) ? i : 0; (color_table[i+j*64]).green = (j == 1) ? i : (j == 3) ? i : 0; (color_table[i+j*64]).blue = (j == 2) ? i : (j == 3) ? i : 0; } } // Устанавливаем режим видеоадаптера номер 13h (256 цветов) // данный режим поддерживается только VGA и Super VGA SetVideoMode( 0x13 ); // Определяем сегмент и смешение массива color_table ptr = (unsigned char far*) &color_table[0]; seg_table = FP_SEG(ptr); off_table = FP_OFF(ptr); // Загружаем новые значения в регистры таблицы цветов SetVgaDAC(seg_table,off_table); // Записываем в ptr указатель на начало видеопамяти ptr = (unsigned char far*) (FP_MAKE(0xA000, 0x0)); // Выводим на экран вертикальные линии различного цвета, // процессор записывает данные непосредственно в видеопамять for(y_num = 0; y_num < 200; y_num++) { for(x_num = 0; x_num < 320; x_num++) { *ptr = (unsigned char) x_num; ptr++; } } // Ожидаем нажатие на клавишу getch(); // Плавно гасим изображение на экране, уменьшая значения // регистров таблицы цветов for(i=0;i<320;i++){ for(iii=0;iii<256;iii++) { (color_table[iii]).red = ((color_table[iii]).red>6) ? color_table[iii].red-1 : 1; (color_table[iii]).green = ((color_table[iii]).green>6) ? color_table[iii].green-1 : 1; (color_table[iii]).blue = ((color_table[iii]).blue>6) ? color_table[iii].blue-1 : 1; } SetVgaDAC(seg_table,off_table); } // Ожидаем нажатие на клавишу SetVideoMode( 0x3 ); Hello(); return 0; } //=========================================================== // Функция SetVideoMode устанавливает режим работы // видеоадаптера, заданный параметром vmode //=========================================================== void SetVideoMode( unsigned char vmode ) { union REGS inregs, outregs; inregs.h.ah = 0x0; inregs.h.al = vmode; int86( 0x10, &inregs, &outregs ); } //=========================================================== // Функция Hello выводит на экран краткую справку о программе //=========================================================== void Hello(void) { printf("\nCopyright (C)Frolov G.V.,1995. " "E-mail: frolov@glas.apc.org\n"); }
Функция SetVgaDAC, предназначенная для заполнения таблицы цветов, представлена в листинге 4.14.
Листинг 4.14. Файл DACTABLE.ASM
TITLE DACTABLE.ASM NAME DACTABLE PAGE 55,132 P286 IDEAL NOWARN BRK SEGMENT VGA_TEXT WORD PUBLIC 'CODE' ASSUME cs:VGA_TEXT ;============================================================ ; Функция ; void SetVgaDAC(unsigned seg_table, unsigned off_table) ;============================================================ off_table EQU [bp+6] seg_table EQU [bp+8] PUBLIC SETVGADAC PROC SETVGADAC FAR enter 0, 0 ; Сохраняем регистры DS и ES push ds push es ; Устанавливаем регистр ES на начало оперативной памяти xor ax,ax mov es,ax ; Получаем адрес порта индексного регистра контроллера ЭЛТ ; (3B4h/3D4h), в монохромных режимах для адресации к ; индексному регистру используется порт с адресом 3B4h, а ; в цветных - порт 3D4h mov dx,es:[463h] ; Вычисляем адрес порта регистра состояния 1, в ; монохромных режимах для адресации к регистру состояния 1 ; используется порт с адресом 3BAh, а в цветных порт 3DAh add dx,6 pop es ; Ожидаем начало обратного вертикального хода луча in al,dx nop nop ; Если бит D3 равен единице, то происходит обратный ; вертикальный ход луча test al,08h jz wait_on wait_off: in al,dx nop nop test al,08h jnz wait_off wait_on: in al,dx nop nop test al,08h jz wait_on ; Устанавливаем индекс первого записываемого регистра ; таблицы цветов mov dx,3C8h ; Начинаем модифицировать таблицу цветов с первого ; регистра mov ax,1 out dx,al ; Задержка nop nop ; Устанавливаем DS:SI на массив данных, записываемых ; в регистры таблицы цветов mov ax,seg_table mov ds,ax mov si,off_table ; Загружаем 256 регистров (по 3 байта на регистр) mov cx,(256 * 3) ; Выбираем регистр данных таблицы цветов (порт 3C9h) mov dx,3C9h cld ; Загружаем все регистры таблицы цветов get_reg: lodsb out dx,al nop nop loop get_reg ; Восстанавливаем регистр DS pop ds leave ret 4 ENDP SETVGADAC ENDS VGA_TEXT END
В этой главе на примере видеоадаптера VGA мы рассмотрим программирование нестандартных режимов. Так как программирование нестандартных режимов видеоадаптеров требует непосредственного доступа к его регистрам, то перед чтением этой главы вам необходимо подробно изучить назначение регистров адаптера.
Мы рассмотрим два наиболее интересных с нашей точки зрения нестандартных режимов VGA: 320х400 и 360х480 пикселов при возможности одновременного отображения 256 цветов.
Нестандартные режимы нельзя установить на обычных видеоадаптерах VGA с помощью функций BIOS. С помощью BIOS можно установить только один режим с 256-цветной палитрой - режим номер 13h (разрешение 320х200 пикселов, 256 цветов). Однако если вы воспользуетесь возможностью непосредственного программирования адаптера через регистры, то любой адаптер VGA можно перевести в эти режимы.
Программирование всех трех описанных ниже нестандартных режимов мы будем проводить в два этапа:
Такой подход к установке нестандартных режимов позволяет программировать не все регистры адаптера, а только те, которые нуждаются в изменении.
Режим 13h использует простую линейную организацию видеопамяти, в которой по каждому адресу видеопамяти находится один байт данных, управляющий одним пикселом. Такая организация видеопамяти хотя и облегчает программирование, но не позволяет увеличить разрешающую способность. Дело в том, что в режиме 13h адресное пространство видеопамяти ограничено 64 Кбайт, которых хватает как раз для того, чтобы получить разрешающую способность 200х320 точек при 256 цветах (200*320 = 64000). Кроме того, такая организация видеопамяти не позволяет использовать для копирования видеоданных регистры-защелки, что может существенно повысить скорость работы программ.
Исходя из вышесказанного для нашего нестандартного режима используется другая структура видеопамяти, более схожая со структурой видеопамяти режимов 10h и 12h. На рисунке 4.20 представлена структура видеопамяти используемая нами во всех описываемых нестандартных режимах:
Рисунок 4.20 Структура видеопамяти в нестандартных, 256-цветовых режимах
Как видно из рисунка, первый пиксел экрана, отображаемый в левом верхнем углу, определяется байтом со смещением 0 из нулевого цветового слоя. Второй пиксел определяется байтом со смещением 0 из первого слоя, третий пиксел - байтом со смещением 0 из второго слоя, четвертый пиксел - байтом со смещением 0 из третьего слоя. Пятый пиксел определяется байтом со смещением 1 из нулевого слоя и так далее.
Таким образом, цвет пиксела с координатами x и y определяет байт видеопамяти, который расположен со смещением (x + y * PIXEL_PER_LINE) / 4, в цветовой плоскости (x + y * PIXEL_PER_LINE) mod 4. В этой формуле константа PIXEL_PER_LINE должна определять горизонтальную разрешающую способность экрана в данном режиме.
Такая организация видеопамяти неудобна для вычисления адреса пикселов, но дает другие неоспоримые преимущества.
Во первых, в режиме с разрешением 320х400 пикселов мы можем использовать две страницы видеопамяти. Первая из них имеет нулевое смещение, а вторая смещение 8000h от начала видеопамяти. Режим с разрешением 360х480 пикселов позволяет иметь только одну страницу, но так как он использует только 172800 байт из 256 Кбайт, то неиспользуемую память можно использовать для хранения пиктограмм и шрифтов.
Во вторых, организация видеопамяти в виде отдельных цветовых слоев позволяет использовать для операций копирования и заполнения областей видеопамяти регистры-защелки. Это дает возможность одновременно копировать четыре байта, и, следовательно, значительно увеличить скорость работы программ.
Мы начнем рассмотрение нестандартных режимов с режима, имеющего разрешение 320х400 пикселов. Программирование этого режима является самым простым и безопасным, так как при его установке нам не придется изменять содержимое регистров контроллера ЭЛТ.
Как мы указывали при описании режимов видеоадаптеров, в режиме 13h используется двойное сканирование. То есть в этом режиме - 320х200 пикселов на самом деле отображается не 200, а 400 линий сканирования. Перепрограммировав несколько регистров адаптера можно перевести его в режим 320х400 пикселов.
Рассмотрим последовательность действий, необходимую для перевода видеоадаптера в нестандартный режим с разрешением 320х400 пикселов:
Приведем программу E256MRES, реализующую изложенный алгоритм. Данная программа переводит видеоадаптер в режим отображающий 256 цветов при разрешающей способности 320х400 пикселов (листинг 4.15).
Листинг 4.15. Файл E256MRES.C
#include <conio.h> #include <stdlib.h> #include <stdio.h> #include <dos.h> // Описание функций void SetVideoMode(unsigned char); // Следующие функции определены в файле EVGAM.ASM void __pascal __far Set320x400Mode( void ); void __pascal __far FullScr(unsigned char); void __pascal __far WritePixel(unsigned, unsigned, unsigned char); unsigned char __pascal __far ReadPixel(unsigned, unsigned, unsigned char); // Главная функция void main( void ){ unsigned i; char ch = 13; // Устанавливаем режим 320х400 пикселов, 256 цветов Set320x400Mode(); // Загружаем регистры ЦАП VGA // LoadVGA256(); for(i = 0; i < 400; i++) WritePixel(160, (unsigned) i, (unsigned char)(i%256)); for(i = 0; i < 320; i++) WritePixel((unsigned) i, 200, (unsigned char)(i%256)); ch = getch(); if( ch == 27 ) exit(1); for(i = 0; i < 320; i++) WritePixel((unsigned) i,(unsigned) i, (unsigned char)(i%256)); ch = getch(); for(i = 0; ((i < 256) && (ch != 27)); i++) { FullScr( (unsigned char) i ); ch = getch(); } // Возвращаемся в текстовый режим SetVideoMode(3); printf("\n (C) Frolov G.V., 1992-1995 \n\n"); } //=========================================================== // Функция устанавливает режим работы видеоадаптера, заданный // параметром vmode //=========================================================== void SetVideoMode( unsigned char vmode ) { union REGS inregs, outregs; inregs.h.ah = 0x0; inregs.h.al = vmode; int86( 0x10, &inregs, &outregs ); }
Основные функции, предназначенные для выбора нестандартного режима, записи и чтения пикселов, а также заполнения экрана монитора, написаны на языке ассемблера. Исходный текст этих функций содержится в листинге 4.16.
Листинг 4.16. Файл EVGAM.ASM
TITLE EVGAM.ASM NAME EVGAM PAGE 55,132 P286 IDEAL NOWARN BRK INCLUDE "evga.inc" SEGMENT EVGA_TEXT WORD PUBLIC 'CODE' ASSUME cs:EVGA_TEXT ;============================================================ ; void Set320x400Mode( void ) ; Установка режима 320х400 пикселов, 256 цветов. ;============================================================ PUBLIC SET320X400MODE PROC SET320X400MODE FAR enter 0, 0 ; Сохраняем регистр di push di ; Устанавливаем стандартный режим 13h ; (320x200 пикселов, 256 цветов) mov ax,0013h int 10h ; Выбираем регистр определенияя структуры памяти mov dx,SC_INDEX mov al,MMR out dx,al ; Считываем значение регистра определения структуры памяти inc dx in al,dx ; Сбрасываем бит D4 and al,11110111b ; Устанавливаем бит D3, при этом выключается режим ; адресации по четным и нечетным адресам к разным слоям ; памяти or al,00000100b ; Записываем в регистр новое значение out dx,al ; После загрузки в этот регистр нового значения структура ; видеопамяти соответствует режимам 10h и 12h за ; исключением того, что каждому пикселу соответствует один ; байт видеопамяти ; Выбираем регистр режима работы графического контроллера mov dx,GC_INDEX mov al,MDR out dx,al ; Считываем его значение inc dx in al,dx ; Выключаем доступ по четным адресам к четным слоям, а по ; нечетным адресам к нечетным слоям and al,11101111b out dx,al ; Выбираем регистр смешанного назначения графического ; контроллера dec dx mov al,MIR out dx,al ; Считываем его значение inc dx in al,dx ; Сбрасываем бит управляющий сцеплением четных и нечетных ; слоев and al,11111101b out dx,al ; Разрешаем запись днных во все четыре цветовых слоя, ; записывая число 0fh в регистр разрешения записи ; цветового слоя mov dx,SC_INDEX mov al,CPWER out dx,al inc dx mov al,00001111b out dx,al ; Очищаем первую страницу видеопамяти, так как установка ; ржима 13h очищает только первые 64K mov ax,VGA_SEGMENT mov es,ax xor di,di mov ax,di mov cx,8000h cld rep stosb ; Выбираем регистр высоты символов текста контроллера ЭЛТ mov dx,CRTC_INDEX mov al,MSLR out dx,al inc dx in al,dx ; Устанавливаем высоту символа равную нулю ; !!! and al,not 1fh ; Запрещаем двойное сканирование and al,01100000b out dx,al ; Выбираем регистр положения подчеркивания символа dec dx mov al,ULR out dx,al ; Выключаем режим адресации видеопамяти по двойным словам inc dx in al,dx and al,10111111b out dx,al ; Выбираем регистр управления режимом dec dx mov al,MCR out dx,al ; Включаем байтовый режим адресации inc dx in al,dx or al,01000000b out dx,al pop di leave ret ENDP SET320X400MODE ;============================================================ ; void WritePixel(unsigned x, unsigned y, ; unsigned char color) ; ; Функция отображает на экране пиксел в заданных координатах, ; определенного цвета. ; x - x-координата пиксела (0-319), ; y - y-координата пиксела (0-399), ; color - цвет пиксела (0-255). ;============================================================ color EQU [bp+6] y EQU [bp+8] x EQU [bp+10] PUBLIC WRITEPIXEL PROC WRITEPIXEL FAR enter 0, 0 push di mov cx,x mov dx,y mov bl,color mov ax,VGA_SEGMENT mov es,ax mov ax,( SCREEN_WIDTH / 4 ) mul dx push cx shr cx,1 shr cx,1 add ax,cx mov di,ax pop cx and cl,3 mov ah,1 shl ah,cl mov dx,SC_INDEX mov al,CPWER out dx,ax mov es:[di],bl pop di leave ret 6 ENDP WRITEPIXEL ;============================================================ ; unsigned char ReadPixel(unsigned x, unsigned y, unsigned char color) ; Функция возвращает значение байта видеопамяти, определяющего пиксел ; с заданными координатами. ; x - x-координата пиксела (0-319), ; y - y-координата пиксела (0-399). ; Return цвет пиксела (0-255). ;============================================================ color EQU [bp+6] y EQU [bp+8] x EQU [bp+10] PUBLIC READPIXEL PROC READPIXEL FAR enter 0, 0 push si mov cx,x mov dx,y mov ax,VGA_SEGMENT mov es,ax mov ax,( SCREEN_WIDTH / 4 ) mul dx push cx shr cx,1 shr cx,1 add ax,cx mov si,ax pop ax and al,3 mov ah,al mov dx,GC_INDEX mov al,RPSR out dx,ax mov al,es:[si] xor ah,ah pop si leave ret 6 ENDP READPIXEL ;============================================================ ; void FullScr( unsigned char color ) ; Закрашивает экран заданным цветом. ; color - цвет экрана (0-255). ;============================================================ color EQU [bp+6] PUBLIC FULLSCR PROC FULLSCR FAR enter 0, 0 ;разрешаем запись данных во все четыре цветовых слоя push di mov dx,SC_INDEX mov al,CPWER out dx,al inc dx mov al,0fh out dx,al mov ax,VGA_SEGMENT mov es,ax xor di,di mov al,color mov cx,32000 cld rep stosb pop di leave ret 2 ENDP FULLSCR ENDS EVGA_TEXT END
Включаемый файл EVGA.INC, в котором определены различные константы для нестандартных режимов видеоадаптера, представлен в листинге 4.17.
Листинг 4.17. Файл EVGA.INC
; Сегмент видеопамяти для режима 13h VGA_SEGMENT EQU 0a000h ; Адрес индексного порта синхронизатора SC_INDEX EQU 3c4h ; Регистр разрешения записи цветового слоя CPWER EQU 2 ; Регистр определения структуры памяти MMR EQU 4 ; Адрес индексного порта графического контроллера GC_INDEX EQU 3ceh ; Регистр выбора читаемого слоя RPSR EQU 4 ; Регистр режима работы MDR EQU 5 ; Регистр смешанного назначения MIR EQU 6 ; Адрес индексного порта контроллера ЭЛТ (цветной режим) CRTC_INDEX EQU 3d4h ; Регистр высоты символов текста MSLR EQU 9 ; Регистр начального адреса SAR_h EQU 0ch ; Регистр положения подчеркивания символа ULR EQU 14h ; Регистр управления режимом MCR EQU 17h ; Регистр определения различных режимов работы MOR EQU 3c2h ; Режим 320х400 пикселов ; Количество пикселов по вертикали SCREEN_HEIGHT EQU 400 ; Количество пикселов по горизонтали SCREEN_WIDTH EQU 320 ; РЕЖИМ 360х480 пикселов ; Количество пикселов по вертикали (режим 320х400) SCREEN_HEIGHT_H EQU 480 ; Количество пикселов по горизонтали (режим 360х480) SCREEN_WIDTH_H EQU 360
Второй нестандартный режим, который мы рассмотрим, может отображать 256 цветов при разрешающей способности 360х480 пикселов. Ниже приведена программа E256HRES, которая переводит видеоадаптер в нестандартный режим с разрешением 360х480 пикселов (листинг 4.18):
Листинг 4.18. Файл E256HRES.C
#include <conio.h> #include <stdlib.h> #include <stdio.h> #include <dos.h> #include "vga_new.h" // Описание функций void main( void ); void SetVideoMode(unsigned char); // Следующие функции определены в файле EVGAH.ASM void __pascal __far Set360x480Mode( void ); void __pascal __far FullScrH(unsigned char); void __pascal __far WritePixelH(unsigned, unsigned, unsigned char); unsigned char __pascal __far ReadPixelH(unsigned, unsigned, unsigned char); // Главная функция void main( void ){ unsigned i; char ch = 13; // Устанавливаем режим 360х480 пикселов, 256 цветов Set360x480Mode(); // загружаем регистры ЦАП VGA // LoadVGA256(); for(i = 0; i < 480; i++) WritePixelH(180, (unsigned) i, (unsigned char)(i%256)); for(i = 0; i < 360; i++) WritePixelH((unsigned) i, 240, (unsigned char)(i%256)); ch = getch(); if( ch == 27 ) exit(1); for(i = 0; i < 360; i++) WritePixelH((unsigned) i, (unsigned) i, (unsigned char) (i % 256) ); ch = getch(); for(i = 0; ((i < 256) && (ch != 27)); i++) { FullScrH( (unsigned char) i ); ch = getch(); } // Возвращаемся в текстовый режим SetVideoMode(3); printf("\n (C) Frolov G.V., 1992\n\n"); } //=========================================================== // Функция устанавливает режим работы видеоадаптера, заданный // параметром vmode //=========================================================== void SetVideoMode( unsigned char vmode ) { union REGS inregs, outregs; inregs.h.ah = 0x0; inregs.h.al = vmode; int86( 0x10, &inregs, &outregs ); }
Основные функции, предназначенные для выбора нестандартного режима с разрешением 360х480 пикселов, записи и чтения пикселов, а также заполнения экрана монитора, написаны на языке ассемблера. Исходный текст этих функций представлен в листинге 4.19.
Листинг 4.19. Файл EVGAH.ASM
TITLE EVGAH.ASM NAME EVGAH PAGE 55,132 P286 IDEAL NOWARN BRK INCLUDE "evga.inc" // Смотри листинг 4.17 SEGMENT EVGA_TEXT WORD PUBLIC 'CODE' ASSUME cs:EVGA_TEXT ;============================================================ ; void Set360x480Mode( void ) ; Установка режима 360х480 пикселов, 256 цветов. ;============================================================ PUBLIC SET360X480MODE PROC SET360X480MODE FAR enter 0, 0 ; Устанавливаем режим 12h, чтобы очистить видеопамять mov ax,12h int 10h ; Устанавливаем стандартный режим 13h ; (320x200 пикселов, 256 цветов) mov ax,0013h int 10h ; Перепрограммируем регистр определения структуры памяти: ; запрещаем адресацию к разным слоям памяти в зависимости ; от кратности адреса памяти четырем (бит D4 chain4) mov dx,SC_INDEX mov ax,0604h out dx,ax ; Производим синхронный сброс и остановку синхронизатора mov ax,0100h out dx,ax ; Адресуемся к регистру определения различных режимов ; работы mov dx,MOR ; Устанавливаем частоту кадров 60Кц mov al,0e7h out dx,al ; Запускаем синхронизатор mov dx,SC_INDEX mov ax,0300h out dx,ax ; Выбираем регистр режима работы графического контроллера mov dx,GC_INDEX mov al,MDR out dx,al ; Считываем его значение inc dx in al,dx ; Выключаем доступ по четным адресам к четным слоям, а по ; нечетным адресам к нечетным слоям and al,11101111b out dx,al ; Выбираем регистр смешанного назначения графического ; контроллера dec dx mov al,MIR out dx,al ; Считываем его значение inc dx in al,dx ; Сбрасываем бит управляющий сцеплением четных и нечетных ; слоев and al,11111101b out dx,al ; Выбираем регистр конца обратного вертикального хода луча mov dx,3d4h mov al,11h out dx,al ; Снимаем защиту от записи с регистров контроллера ЭЛТ, ; имеющих индексы от 0 до 7 inc dx in al,dx and al,7fh out dx,al dec dx ; Программируем регистры контроллера ЭЛТ, втом числе ; регистры, определяющие временные параметры режима ; Устанавливаем регистр общей длины линии горизонтальной ; развертки mov ax,06b00h out dx,ax ; Устанавливаем регистр длины отображаемой части ; горизонтальной развертки mov ax,05901h out dx,ax ; Устанавливаем регистр начала импульса гашения луча ; горизонтальной развертки mov ax,05a02h out dx,ax ; Устанавливаем регистр конца импульса гашения луча ; горизонтальной развертки mov ax,08e03h out dx,ax ; Устанавливаем регистр начала импульса горизонтального ; обратного хода луча mov ax,05e04h out dx,ax ; Устанавливаем регистр конца импульса горизонтального ; обратного хода луча mov ax,08a05h out dx,ax ; Устанавливаем регистр числа горизонтальных линий ; растра mov ax,0d06h out dx,ax ; Устанавливаем дополнительный регистр mov ax,03e07h out dx,ax ; Устанавливаем регистр высоты символов текста mov ax,04009h out dx,ax ; Устанавливаем регистр начала обратного ; вертикального хода луча mov ax,0ea10h out dx,ax ; Устанавливаем регистр конца обратного ; вертикального хода луча mov ax,0ac11h out dx,ax ; Устанавливаем регистр начала гашения вертикальной ; развертки mov ax,0df12h out dx,ax ; Устанавливаем регистр логической ширины экрана mov ax,02d13h out dx,ax ; Устанавливаем регистр положения подчеркивания символа mov ax,014h out dx,ax ; Устанавливаем регистр начала импульса гашения ; вертикальной развертки mov ax,0e715h out dx,ax ; Устанавливаем регистр конца импульса гашения ; вертикальной развертки mov ax,0616h out dx,ax ; Устанавливаем регистр управления режимом mov ax,0e317h out dx,ax leave ret ENDP SET360X480MODE ;============================================================ ; void ; WritePixelH(unsigned x, unsigned y, unsigned char color) ; Функция отображает на экране пиксел в заданных координатах, ; определенного цвета. ; x - x-координата пиксела (0-319), ; y - y-координата пиксела (0-399), ; color - цвет пиксела (0-255). ;============================================================ color EQU [bp+6] y EQU [bp+8] x EQU [bp+10] PUBLIC WRITEPIXELH PROC WRITEPIXELH FAR enter 0, 0 push di mov cx,x mov dx,y mov bl,color mov ax,VGA_SEGMENT mov es,ax mov ax,( SCREEN_WIDTH_H / 4 ) mul dx push cx shr cx,1 shr cx,1 add ax,cx mov di,ax pop cx and cl,3 mov ah,1 shl ah,cl mov dx,SC_INDEX mov al,CPWER out dx,ax mov es:[di],bl pop di leave ret 6 ENDP WRITEPIXELH ;============================================================ ; unsigned char ; ReadPixelH(unsigned x, unsigned y, unsigned char color) ; Функция возвращает значение байта видеопамяти, ; определяющего пиксел с заданными координатами. ; x - x-координата пиксела (0-319), ; y - y-координата пиксела (0-399). ; Функция возвращает цвет пиксела (0-255). ;============================================================ color EQU [bp+6] y EQU [bp+8] x EQU [bp+10] PUBLIC READPIXELH PROC READPIXELH FAR enter 0, 0 push si mov cx,x mov dx,y mov ax,VGA_SEGMENT mov es,ax mov ax,( SCREEN_WIDTH_H / 4 ) mul dx push cx shr cx,1 shr cx,1 add ax,cx mov si,ax pop ax and al,3 mov ah,al mov dx,GC_INDEX mov al,RPSR out dx,ax mov al,es:[si] mov color,al xor ah,ah pop si leave ret 6 ENDP READPIXELH ;============================================================ ; void FullScrH( unsigned char color ) ; Закрашивает экран заданным цветом. ; color - цвет экрана (0-255). ;============================================================ color EQU [bp+6] PUBLIC FULLSCRH PROC FULLSCRH FAR enter 0, 0 ;Разрешаем запись данных во все четыре цветовых слоя push di ;Разрешаем запись данных во все четыре цветовых слоя mov dx,SC_INDEX mov al,CPWER out dx,al inc dx mov al,0fh out dx,al mov ax,VGA_SEGMENT mov es,ax xor di,di mov al,color mov cx,43200 cld rep stosb pop di leave ret 2 ENDP FULLSCRH ENDS EVGA_TEXT END