В этой главе мы опишем все основные регистры видеоадаптеров EGA и VGA, которые могут быть полезны при написании программ. Необходимо указать, что хотя программирование видеоадаптеров на уровне регистров позволяет увеличить скорость работы программ и решить некоторые задачи, которые нельзя решить при помоши функций BIOS, это может вызвать ряд проблем при переносе ваших программ на другие машины. Дело в том, что не все адаптеры совместимы на уровне регистров. Например, оригинальный видеоадаптер CGA создан на основе микросхемы Motorola 6845, а видеоадаптеры EGA и VGA используют более совершенный аналог этой микросхемы. Хотя EGA и VGA имеют регистры, соответствующие регистрам CGA, некоторые из них располагаются по другим адресам и могут выполнять какие-либо дополнительные функции. Кроме того, в каждом новом видеоадаптере расширяется набор используемых регистров.
Существуют модели видеоадаптеров EGA, VGA, Super VGA поддерживающие режим совместимости, когда они эмулируют адаптеры более низкого уровня (например MDA, Hercules, CGA). При этом эмуляция обычно происходит на уровне регистров, что гарантирует полную их совместимость. Режимы совместимости, если они поддерживаются, описаны в руководстве этого видеоадаптера.
На практике, для управления видеоадаптерами, рекомендуется преимущественно использовать функции BIOS. Это избавит вас от неприятных минут, когда ваша работающая программа, при переносе на другую машину перестанет правильно выполняться.
Видеоадаптеры EGA и VGA содержат большое количество регистров. EGA имеет около шестидесяти регистров, а VGA и Super VGA еще больше. Большая часть регистров EGA доступна только для записи, что создает определенные проблемы, особенно для мультизадачных систем. Из-за этого некоторые фирмы-изготовители видеоадаптеров выпускают совместимые с EGA платы видеоадаптеров, для регистров которых разрешена также и операция чтения.
В новых адаптерах VGA и Super VGA практически все регистры доступны как для записи так и для чтения.
Условимся, что в тех случаях, когда VGA имеет отличия от EGA, мы будем на это специально указывать.
Доступ к большинству регистров видеоадаптеров осуществляется в два этапа: через один порт ввода/вывода выбирается номер интересующего вас регистра, а затем через другой порт ввода/вывода осуществляется обмен данными. Это позволяет сэкономить большое число портов процессора.
Заметим, что в различных режимах работы
видеоадаптера, его регистры могут иметь
различные адреса. В таблицах 8.1 и 8.2 приведен
список адресов регистров в монохромных и цветных
режимах.
Адрес |
Регистр |
3C2 |
регистр определения различных режимов
работы (Miscellaneous Output Register - MOR); |
|
регистр состояния 0 (Input Status Register 0 - ISR0) |
3BA |
регистр управления дополнительным
устройством (Feature Control Register) |
|
регистр состояния 1 (Input Status Register 1 - ISR1) |
3BB |
регистр очистки защелки светового пера
(Clear Light Pen Latch Register- CLPLR) |
3BC |
установка защелки светового пера (Set Light
Pen Latch Register - SLPLR) |
3C4, |
регистры синхронизатора |
3C5 |
(Sequencer Register's - SR) |
3B4, |
регистры контроллера ЭЛТ |
3B5 |
(CRT Controller Register's - CRT_CR) |
3CA, |
регистры графического контроллера |
3CC, |
(Graphics Controller Register's - GCR) |
3CE, |
|
3CF |
|
3C0 |
регистр контроллера атрибутов (Attribute
Controller Register - ACR) |
3C3 |
регистр разрешения работы системы VGA (VGA
Enable Register - VGA_ER) |
3C6, |
регистры цифро-аналогового
преобразователя (ЦАП) VGA |
3C7, |
(VGA Video DAC Register - VGA_DAC_R) |
3C8, |
|
3C9 |
|
Таблица 8.1 Карта портов ввода/вывода (монохромный режим).
Адрес |
Регистр |
3C2 |
регистр определения различных режимов
работы (Miscellaneous Output Register - MOR); |
|
регистр состояния 0 (Input Status Register 0 - ISR0). |
3DA |
регистр управления дополнительным
устройством Feature Control Register) |
|
регистр состояния 1 (Input Status Register 1 - ISR1) |
3DB |
регистр очистки защелки светового пера
(Clear Light Pen Latch Register- CLPLR) |
3DC |
установка защелки светового пера (Set Light
Pen Latch Register - SLPLR) |
3C4, |
регистры синхронизатора |
3C5 |
(Sequencer Register's - SR) |
3D4, |
регистры контроллера ЭЛТ |
3D5 |
(CRT Controller Register's - CRT_CR) |
3CA, |
регистры графического контроллера |
3CC, |
(Graphics Controller Register's - GCR) |
3CE, |
|
3CF |
|
3C0 |
регистр контроллера атрибутов (Attribute
Controller Register - ACR) |
3C3 |
регистр разрешения работы системы VGA (VGA
Enable Register - VGA_ER) |
3C6, |
регистры ЦАП VGA |
3C7, |
(VGA Video DAC Register - VGA_DAC_R) |
3C8, |
|
3C9 |
|
Таблица 8.2 Карта портов ввода/вывода (цветной режим).
Адресное пространство видеопамяти также
различается в разных режимах работы
видеоадаптера. В таблице 8.3 приведены адреса
памяти в зависимости от режима работы.
Номер режима работы |
Адрес памяти |
0,1,2,3,4,5,6 |
B000:8000-B000:FFFF |
7 |
B000:0000-B000:7FFF |
0Dh,0Eh,0Fh,10h,11h,12h,13h |
A000:0000-A000:FFFF |
Таблица 8.3 Распределение видеопамяти в различных режимах.
Функция Get_Seg_Vmem, приведенная ниже, при помощи функции 0Fh прерывания INT 10h определяет текущий режим работы видеоадаптера и возвращает сегмент начала видеопамяти. Если видеоадаптер работает в нестандартном режиме, функция возвращает ноль.
#include "sysp.h" unsigned Get_Seg_Vmem(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 все регистры находятся на одной микросхеме, но эти регистры традиционно называют "внешними".
Заметим, что в отличие от остальных регистров, внешние регистры адресуются непосредственно по адресам своих портов, без использования индексного регистра.
В видеоадаптере EGA данный регистр доступен по адресу 3C2h только для записи. Видеоадаптер VGA позволяет также считать содержимое регистра, но уже по адресу 3CCh.
Ниже приведено описание отдельных битов регистра MOR:
Улучшенный цветной дисплей и аналоговый дисплей используют биты D7 и D6 для определения скорости сканирования. Таблица 8.4 содержит допустимые значения для этих битов.
D7 D6 EGA VGA 0 0 200 линий не используется 0 1 350 линий 350 линий 1 0 не используется 400 линий 1 1 не используется 480 линий
Таблица 8.4 Соответствие полярности синхронизации и вертикальной разрешающей способности.
D3 D2 Режим 0 0 640 столбцов (или 320 столбцов) 0 1 720 столбцов 1 0 внешний генератор (доступен через разъем дополнительного устройства) 1 1 зарезервированно
Таблица 8.5 Установка битов D3 и D2.
Данные, первоначально записываемые BIOS в этот
регистр зависят от режима работы видеоадаптера:
Режим |
0-6,0Dh,0Eh |
7 |
Fh |
10h |
Содержимое регистра |
23h |
0A6h |
0A2h |
0A7h |
Для видеоадаптера EGA биты D1 и D0 данного регистра передают сигналы на разъем дополнительного устройства, соответственно, на линии FC0 (вывод 21) и FC1 (вывод 20) разъема. Этот регистр не используется для VGA, но бит D3 должен содержать ноль.
Адрес порта ввода/вывода данного регистра зависит от режима видеоадаптера. В монохромном режиме адрес порта 3BAh, а в цветном - 3DAh.
Регистр доступен только для записи, но VGA позволяет прочитать его содержимое через порт 3CAh.
Данный регистр, имеющий адрес 3C2h, доступен только для чтения.
Регистр позволяет получить различную информацию от видеоадаптера EGA. Формат регистра приведен ниже:
3-D0 Не используются. 4 Состояние переключателей. 5 Бит 0 дополнительного устройства (FEAT0). 6 Бит 1 дополнительного устройства (FEAT1). 7 Бит прерывания от ЭЛТ.
Бит D3 |
Бит D2 |
Считываемый переключатель |
0 |
0 |
переключатель 1 |
0 |
1 |
переключатель 2 |
1 |
0 |
переключатель 3 |
1 |
1 |
переключатель 4 |
Таблица 8.6 Установка битов D3 и D2.
Если бит D4 установлен в единицу, то переключатель, заданный битами D2 и D3 регистра определения различных режимов работы, находится в положении ON. Если бит сброшен в ноль, то переключатель находится в положении OFF.
Для EGA эти четыре переключателя определяют, какой дисплей используется с видеоадаптером и какой дополнительный видеоадаптер может быть подключен к компьютеру (cм. главу "Системы с двумя дисплеями").
Ниже показаны правильные варианты установки переключателей для различных конфигураций видеосистемы.
4 3 2 1 _________ Первичный: EGA с цветным дисплеем (40х25). ON ¦Ё Ё¦ OFF ¦ Ё Ё ¦ Дополнительный: MDA. _________ 4 3 2 1 _________ Первичный: EGA с цветным дисплеем (80х25). ON ¦Ё ¦ OFF ¦ Ё Ё Ё¦ Дополнительный: MDA. _________ 4 3 2 1 _________ Первичный: EGA с улучшенным цветным дисплеем. ON ¦ Ё Ё Ё¦ OFF ¦Ё ¦ Дополнительный: MDA. _________ 4 3 2 1 _________ Первичный: EGA с улучшенным цветным дисплеем. ON ¦ Ё Ё ¦ OFF ¦Ё Ё¦ Дополнительный: MDA. _________ 4 3 2 1 _________ Первичный: EGA с монохромным дисплеем. ON ¦ Ё Ё¦ OFF ¦Ё Ё ¦ Дополнительный: CGA с цветным дисплеем _________ (40х25). 4 3 2 1 _________ Первичный: EGA с монохромным дисплеем. ON ¦ Ё ¦ OFF ¦Ё Ё Ё¦ Дополнительный: CGA с цветным дисплеем _________ (80х25) 4 3 2 1 _________ Первичный: MDA. ON ¦Ё Ё Ё Ё¦ OFF ¦ ¦ Дополнительный: EGA с цветным дисплеем _________ (40х25). 4 3 2 1 _________ Первичный: MDA. ON ¦Ё Ё Ё ¦ OFF ¦ Ё¦ Дополнительный EGA с цветным дисплеем _________ (80х25). 4 3 2 1 _________ Первичный: MDA. ON ¦Ё Ё Ё¦ OFF ¦ Ё ¦ Дополнительный: EGA с улучшенным цветным _________ дисплеем. 4 3 2 1 _________ Первичный: MDA. ON ¦Ё Ё ¦ OFF ¦ Ё Ё¦ Дополнительный: EGA с улучшенным цветным _________ дисплеем. 4 3 2 1 _________ Первичный: CGA с цветным дисплеем 40х25 ON ¦Ё Ё Ё¦ OFF ¦ Ё ¦ Дополнительный: EGA с монохромным дисплеем. _________ 4 3 2 1 _________ Первичный: CGA с цветным дисплеем 80х25 ON ¦Ё Ё ¦ OFF ¦ Ё Ё¦ Дополнительный: EGA с монохромным дисплеем. _________
VGA использует бит D4 для определения типа используемого дисплея (цветной или монохромный).
Особенно подчеркнем, что положение этих переключателей может быть считано также из байта памяти с адресом 0000:0488h:
Следующая программа считывает значение регистра состояния 0, выделяет биты D5 и D6, поступающие с разъема дополнительного устройства и отображает значения этих битв на экране диспля.
// чтение битов дополнительного устройства // (битов D5 и D6 регистра состояния 0) #include <stdio.h> #include "sysp.h" #include "sysgraph.h" void main(void) { int feature_bits; unsigned crt_address; BIOS_VAR _far *bios_var_ptr; // читаем содержимое регистра состояния 0 и выделяем // биты D5 и D6 feature_bits = (ReadReg(0x3C2) & 0x60) >> 5; printf("Биты дополнительного устройства: %x\n", feature_bits); }
Функция ReadReg, используемая в программе, описана ранее.
Регистр позволяет получить различную информацию о состоянии видеоадаптера.
Для видеоадаптера CGA Содержимое регистраможно считать через порт, имеющий адрес 3DAh. Для адаптеров EGA и VGA данный регистр, имеет адрес 3BAh в монохромных режимах и адрес 3DAh - в цветных. Регистр состояния 1 доступен только для чтения.
Приведем формат регистра состояния 1:
D0 Бит разрешения отображения. D1 Бит тригера светового пера. D2 Бит переключателя светового пера. D3 Бит обратного вертикального хода D5-D4 Диагностические биты. D7-D6 Биты не используются.
Регистр разрешения Регистр состояния 1 цветового слоя D5 D4 D5 D4 0 0 красный синий 0 1 второй красный второй зеленый 1 0 второй синий зеленый 1 1 не используется не используется
Таблица 8.7 Считывание диагностических битов EGA.
Таблица 8.8 показывает, как можно считать два из восьми цветовых сигналов вырабатываемых контроллером атрибутов видеоадаптера VGA:
Регистр разрешения Регистр состояния 1 цветового слоя D5 D4 D5 D4 0 0 P2 P0 0 1 P5 P4 1 0 P3 P1 1 1 P7 P6
Таблица 8.8 Считывание диагностических битов VGA.
Фактически биты D5 и D4 представляют возможность прочитать содержимое регистров таблицы цветовой палитры для видеоадаптера EGA. Следует отметить, что некоторые адаптеры, совместимые с EGA, не поддерживают эти биты. По-этому их использование может наложить некоторые ограничения на работу программы.
Биты D2 и D1 относятся к управлению световым пером. Для видеоадаптеров VGA и Super VGA эти биты не используются, так как такие адаптеры не поддерживают световое перо.
Во многих случаях возникает необходимость синхронизовать выполнение некоторых действий с периодом вертикального или горизонтального обратного хода луча. Этого можно достичь обработкой прерывания IRQ2 или тестированием регистра состояния 1.
Ниже представлена программа, использующая функцию WaitVert, для определения частоты кадров. Функция WaitVert задерживает выполнение программы до начала обратного вертикального хода луча.
// программа определения частоты кадров #include <time.h> #include <stdio.h> #include <bios.h> #define NUM 200 void WaitVert(void); void main() { time_t t_start, t_end; int i; float 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 ); } /** *.Name WaitVert * *.Title Определение начала обратного вертикального хода луча. * *.Descr Функция ожидает начало обратного вертикального хода луча. * Использование функции позволяет синхронизировать работу * программы с периодами работы видеоадаптера. * *.Proto void WaitVert(void) * *.Params Отсутствуют. * *.Return Не используются. * *.Sample get_vert.c **/ void WaitVert(void) { unsigned count; _asm { ; устанавливаем регистр es на сегмент с нулевым адресом mov ax,0h mov es,ax ; определяем адрес порта индексного регистра ; контроллера ЭЛТ (3B4h/3D4h в ; зависимости от режима работы видеоадаптера - ; монохромный или цветной) mov dx,es:[463h] ; вычисляем адрес порта регистра состояния 1 (ISR1); ; это достигается добавлением к адресу порта ; индексного регистра 6, так как адрес порта регистра ; состояния 1 равен 3BAh или 3DAh в зависимости от режима ; работы видеоадаптера (монохромный или цветной) 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 ; ; здесь могут распологаться операции, которые необходимо ; выполнить во время обратного вертикального хода луча ; } }
Данный регистр имеет адрес 3С3h. Регистр используется только для VGA. Биты D1-D7 зарезервированны, а бит D0 управляет работой VGA. Если он равен нулю, то запрещен доступ к видеопамяти и портам ввода/вывода видеоадаптера (кроме самого регистра VGA_ER).
Доступ к регистру производится через порт 3DBh для цветного режима и через 3BBh для монохромного. Регистр используется только видеоадаптерами CGA и EGA. Любая операция записи (OUT) в этот регистр сбрасывает триггер-защелку светового пера.
Доступ к регистру производится через порт 3DCh для цветного режима и через 3BCh для монохромного. Регистр используется только видеоадаптерами CGA и EGA. Любая операция записи (OUT) в этот регистр вызывает установку триггера-защелки светового пера.
Регистры контроллера ЭЛТ управляют сигналами синхронизации, необходимыми для формирования растра, определяют формат данных на экране, форму курсора, а также для видеоадаптеров CGA и EGA управляют световым пером.
Большинство из этих регистров не предсталяют интереса для их непосредственного программирования. Более того, их неправильное использоване может послужить причиной физического разрушения дисплея. Поэтому мы подробно рассмотрим лишь наиболее полезные и безопасные регистры контроллера.
Назначение и формат ряда регистров контроллера ЭЛТ различаются для видеоадаптеров EGA, VGA и для видеоадаптеров MDA, Hercules и CGA. Кроме того, они могут различаться и для видеоадаптерв одного типа, но разных фирм-производителей. В результате могут возникнуть проблем совместимости на компьютерах, оснащенных другим видеоадаптером. Если вы все-таки решитесь их перепрограммировать, то обращайтесь к описанию вашего адаптера.
Регистры контроллера ЭЛТ составляют самую многочисленную группу регистров видеоадаптеров. Для видеоадаптеров EGA и VGA группа содержит 24 регистра.
В таблице 8.9 приведен список всех регистров
контроллера ЭЛТ и их индексы, используемые для
доступа к ним.
Индекс |
Регистр контроллера ЭЛТ |
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)
|
Таблица 8.9 Регистры EGA и VGA контроллера ЭЛТ.
В отличие от внешних регистров, адресация к регистрам контроллера ЭЛТ происходит через два порта. В первый порт (индексный) записывается индекс регистра, к которому осуществляетя доступ, а через второй порт (порт данных) можно производить обмен данными (запись или чтение). Заметим, что у видеоадаптера EGA большинство регистров контроллера ЭЛТ доступны только для записи.
У видеоадаптеров MDA и Hercules индексный порт имеет
адрес 3B4h, а порт данных - адрес 3B5h. Для CGA адреса
портов другие. Индексный порт имеет адрес 3D4h, а
порт данных - адрес 3D5h. Адреса портов контроллера
ЭЛТ для видеоадаптеров EGA и VGA зависят от режима
работы видеоадаптера (монохромный или цветной). В
монохромном режиме адрес порта индексного
регистра равен 3B4h, а регистра данных - 3B5h. В
цветном режиме адреса соответственно равны 3D4h и
3D5h:
Тип адаптера |
Адрес порта индексного регистра |
Адрес порта регистра данных |
MDA и Hercules |
3B4h |
3B5h |
CGA |
3D4h |
3D5h |
EGA и VGA (монохромный режим) |
3B4h |
3B5h |
EGA и VGA (цветной режим) |
3D4h |
3D5h |
Таблица 8.10 Адреса портов индексного регистра и регистра данных.
Использование видеоадаптерами различного адресного пространства для портов контроллера ЭЛТ необходимо, чтобы создать возможность одновременного подключения к компьютеру двух видеоадаптеров.
Адрес порта индексного регистра записан в области переменных видеофункций BIOS, по адресу 0000:0463. Приведем фрагмент программы, определяющей адрес индексного порта контроллера ЭЛТ:
; устанавливаем es на нулевой сегмент xor ax,ax mov es,ax ; записываем в dx адрес порта индексного регистра контроллера ЭЛТ mov dx,es:[463]
Так как адреса портов индексного регистра и регистра данных контроллера ЭЛТ является смежными, то адрес порта регистра данных можно получить, прибавив единицу к адресу порта индексного регистра.
Этот регистр относится к группе регистров контроллера ЭЛТ, которые управляют генерацией синхросигналов для дисплея. Необходимость модификации данной группы регистров возникает только при программировании нестандартных режимов работы видеоадаптера.
Кроме регистров, контроллер ЭЛТ использует еще два внутренних счетчика для управления синхросигналами. Счетчик числа горизонтальных знакомест экрана увеличивается при выводе очередного сивола на экран (регенерация экрана) и сбрасывается, когда его значение становится равным регистру общей длины линии горизонтальной развертки. Счетчик числа горизонтальных линий развертки увеличивается после окончания обратного горизонтального хода луча и сбрасывается, когда достигает величины, хранящейся в регистре числа горизонтальных линий растра.
Регистр HTR определяет число знакомест на одной линии сканирования, включая обратный ход луча и рамку экрана.
Для EGA число знакомест по горизонтали будет на два, а для VGA на пять больше, чем значение, хранящееся в регистре.
При установке режима работы видеоадаптера, 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 для определения начала импульса гашения луча горизонтальной развертки.
При установке режима работы видеоадаптера, 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 |
При установке режима работы видеоадаптера, 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 регистр задает момент начала импульса горизонтального обратного хода луча.
При установке режима работы видеоадаптера, 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 |
Регистр определяет общее число линий горизонтальной развертки в кадре вертикальной развертки, включая гашение вертикального хода луча и обратный вертикальный ход луча.
Для видеоадаптера EGA, регистр VTR содержит девять битов. Девятый бит находится в дополнительном регистре (OVR). Регистр VTR видеоадаптера VGA содержит десять битов. Десятый бит, также как и девятый, расположен в дополнительном регистре (OVR).
Многие регистры контроллера ЭЛТ, видеоадаптера EGA, имеют по девять, а для VGA и по десять битов. Дополнительный регистр содержит биты, которые не помещаются в восьмиразрядную сетку основных регистров.
Регистр позволяет производить плавную вертикальную прокрутку содержимого экрана дисплея в текстовых режимах (свертку). В графических режимах регистр должен содержать нулевое значение.
Следующий рисунок иллюстрирует использование регистра предварительной установки горизонтальной развертки для вертикальной свертки содержимого экрана. В левой части рисунка показно начальное состояние экрана диспля, когда регистр содержит нулевое значение для битов D0-D4. Справа показан экран дисплея после увеличения значения регистра до трех. При этом изображение на экране дисплея сдвигается на три пиксела вверх, в результате чего часть верхней строки пропадает.
Рисунок 8.1 Плавная прокрутка экрана.
После установки режима работы видеоадаптера данный регистр содержит нулевое значение.
Этот регистр определяет количество линий сканирования на один символ или, другими словами, высоту символов в пикселах. Регистр используется только в текстовых режимах работы видеоадаптеров.
На следующих двух рисунках показано использование регистра высоты символов текста. На первом рисунке, при использовании шрифта 8х8 пикселов, регистр высоты символов содержит число семь. Для второго рисунка, значение регистра равно тринадцати (используется шрифт 8х14). Как виднно из рисунков, значение регистра на один меньше, чем высота символов отображаемых на экране.
Рисунок 8.2 Изменение высоты символов текста.
Рисунок 8.3 Изменение высоты символов текста.
Этот регистр является доступным как для чтения, так и для записи.
Регистр задает линию сканирования символа, в которой начинается курсор. Вместе с регистром конечной линии курсора (CER) он определяет размер и форму курсора.
D4-D0 Начальная линия курсора. (см. рисунок 8.4). D5 Бит гашения курсора. Реализован только на VGA. Если D5 содержит единицу, курсор гаснет. D7-D6 Не используются.
При установке режима работы видеоадаптера, BIOS загружает в регистр CSR следующие значения:
Режим |
0,1,2,3 |
4,5,6,D,E,F,10 |
7 |
Содержимое регистра |
06 |
00 |
0Bh |
Этот регистр, также как и регистр CSR, является доступным для чтения и для записи.
Регистр задает последнюю линию сканирования символа, в которой кончается курсор.
При установке режима работы видеоадаптера BIOS
загружает в регистр конечной линии курсора
следующие значения:
Режим |
0,1,2,3 |
4,5,6,D,E,F,10 |
7 |
Содержимое регистра |
07 |
00 |
0Ch |
Изменяя значение регистров начальной и конечной линии курсора, можно менять его положение и размер. На левой части рисунка, приведенного ниже, регистр начальной линии курсора равен 0Ah, регистр конечной линии курсора равен 0Bh. На правой части рисунка значение регистров изменено: регистр начальной линии равен 4, а регистр конечной линии - 5.
Рисунок 8.4 Изменение положения курсора.
Следующая программа позволяет прочитать значение регистров начальной и конечной линии курсора:
#include <stdio.h> #include "sysp.h" #include "sysgraph.h" 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->crt_address; // считываем значения регистров начальной и // конечной линии курсора // выбираем регистр начальной линии курсора WriteReg(crt_address++, 0x0A); // считываем значение регистра top = (unsigned char) ReadReg(crt_address--); // выбираем регистр конечной линии курсора WriteReg(crt_address++, 0x0B); // считываем значение регистра bottom = (unsigned char) ReadReg(crt_address); // отображаем на экране значение регистров printf("\nРегистр начальной линии курсора содержит %x\n" "\nРегистр конечной линии курсора содержит %x\n", top, bottom); getch(); }
Это группа из двух регистров: регистр старшего байта начального адреса (Start Address Register - SAR, high byte) (индекс 0Ch) и регистр младшего байта начального адреса (Start Address Register - SAR, low byte) (индекс 0Dh).
Регистры SAR содержат адрес данных видеопамяти, которые будут отображаться в верхнем левом углу экрана дисплея. Регистры начального адреса можно использовать для перемещения изображения по экрану (панорамирования) и для переключения активной страницы памяти.
Если вы хотите использовать регистры для переключения страниц видеопамяти, то в данные регистры надо записать смещение страницы, которую вы желаете отобразить на экране, относительно начала видеопамяти.
На рисунке 8.5 показано, как происходит панарамирование экрана при изменении регистров начального адреса. В верхней части рисунка регистры начального адреса содержат ноль. В этом случае видеопамять отображается на экране с начала. В нижней части значение регистров начального адреса увеличено до 77. Как видно из рисунка, в этом случае видеопамять отображается на экране начиная с данных, имеющих смещение 77 от начала видеопамяти. При этом снизу экрана возникает изображение, ранее не помещавщееся на экране.
Рисунок 8.5 Процесс панорамирования экрана.
Регистры начального адреса доступны для чтения и для записи. При установке режима работы видеоадаптера регистры обнуляются.
Два регистра - регистр старшего байта позиции курсора (Cursor Location Register - CLR_h, high byte) (индекс 0Eh) и регистр младшего байта позиции курсора (Cursor Location Register - CLR_l, low byte) (индекс 0Fh) определяют положение курсора на экране (cм. рисунок 8.6). Регистры доступны как для записи, так и для чтения.
Рисунок 8.6 Отображение курсора на экране.
Программа, приведенная ниже считывает значения из регистров позиции курсора (на момент запуска программы) и отображает их на экране дисплея:
// чтение регистра положения курсора #include <stdio.h> #include <graph.h> #include "sysp.h" #include "sysgraph.h" void main(void) { int crt_port; unsigned char h_pos, l_pos; BIOS_VAR _far *bios_var_ptr; // получаем указатель на область переменных видеофункций BIOS bios_var_ptr = (BIOS_VAR _far *) FP_MAKE(0x0000, 0x0410); // определяем адрес порта индексного регистра контроллера ЭЛТ crt_port = bios_var_ptr -> crt_address; // выбираем старший байт регистра положения курсора WriteReg(crt_port, 0x0E); // считываем значение старшего байта регистра положения курсора h_pos = ReadReg(crt_port + 1); // выбираем младший байт регистра положения курсора WriteReg(crt_port, 0x0F); // считываем значение младшего байта регистра положения курсора l_pos = ReadReg(crt_port + 1); printf("\nТекущий адрес курсора %X:%X\n", (unsigned char) h_pos, (unsigned char) l_pos ); }
Регистр определяет начало обратного вертикального хода луча. Для EGA этот регистр содержит 9, а для VGA - 10 битов. Дополнительные биты расположены в регистре OVR.
Данный регистр доступен только для записи.
Данный регистр видеоадаптеров EGA и VGA доступен только для записи.
Регистр устанавливает конец обратного вертикального хода луча, а также выполняет некоторые другие функции.
D3-D0 Конец обратного вертикального хода луча. D4 Сброс вертикального прерывания. D5 Разрешения вертикального прерывания. D6 Изменение скорости регенирации экрана. (Только VGA.) D7 Защита от записи. (Только VGA.)
Это 16-битовый регистр, который имеется в видеоадаптерах CGA и EGA, доступен только для чтения. Регистр LPAR дает возможность определить положение светового пера на экране. Регистр содержащий старший байт адреса светового пера имеет индекс 10h, а регистр содержащий младший байт - индекс 11h.
LPAR сохраняет адрес видеопамяти, которая регенерировалась в момент включения светового пера.
Регистр определяет момент, когда заканчивается видемая часть вертикальной развертки и происходит гашение луча. Регистр содержит число, на единицу меньшее, чем количество горизонтальных линий растра.
Для видеоадаптера EGA регистр VDER содержит 9, а для VGA - 10 бит. Девятыи и десятый биты доступны через дополнительный регистр (OVR).
Регистр может быть использован для отображения большего, чем обычно, количества символов в строке. Например, для перевода видеоадаптера в режим отображения 132 симвов в строке.
В графических режимах регистр OFR задает логическую длину (в 16-битных словах или 32-битных двойных словах) горизонтальной линии развертки. Если линия num развертки начинается по адресу adr, то следующая линия развертки num+1 начинается по адресу adr+offset, где offset это значение регистра OFR.
В текстовых режимах регистр содержит смещение между соседними строками текста, заданное в 16-битных словах.
Использование регистраа OFR иллюстрируется рисунком 8.7. На верхней части рисунка видеоадаптер находится в стандартном текстовом режиме с разрешением 80 символов в строке. При этом значение регистра логической ширины экрана равно 40. На нижней части рисунка представлен результат увеличения содержимого регистра до 41. Логическая ширина экрана в этом случае увеличивается до 82 символов в строке. Последние два символа каждой строки не помещаются на экране. Для их отображения надо выполнить горизонтальную свертку экрана.
Рисунок 8.7 Логическая ширина экрана.
Регистр ULR используется только в текстовых режимах. Он определяет положение подчеркивания символа. Подчеркивание предстовляет собой одну из линий в матрице символа. Подчеркивание отображается, если установлен атрибут подчеркивания. Отображение подчеркивания можно запретить, записав в регистр ULR величину большую, чем высота символов.
Программа, приведенная ниже, использует регистры контроллера ЭЛТ для перевода видеоадаптеров EGA и VGA в нестандартный текстовый режим, имеющий разрешение по вертикали 43 строки. Данная программа переводит видеоадаптер в текстовый режим с разрешением по вертикали 43 символа и затем отображает на экране диспля 43 строки текста.
#include <graph.h> void Set43Line(void); void main(void) { int i; // устанавливаем текстовый режим, принятый по умолчанию; // функция _setvideomode определена в графической библиотеке // трансляторов Microsoft Quick C 2.5 и C 6.0 _setvideomode(_DEFAULTMODE); // перепрограммируем видеоадаптер для отображения 43 строк Set43Line(); // выводим на экран дисплея 43 строки текста for(i = 0; i < 43; i++) printf("text line number %d\n", i); getch(); // восстанавливаем режим с 25 текстовыми строками _setvideomode(_DEFAULTMODE); } /** *.Name Set43Line * *.Title Установка текстового режима, использующего 43 строки. * *.Descr Переводит адаптеры EGA и VGA в режим отображения 43 * строк текста. * *.Proto void Set43Line(void) * *.Params Отсутствуют. * * *.Return Не используется. * *.Sample 43line.c **/ void Set43Line(void) { #define CHAR_SIZE 8 // новая высота символов _asm { ; устанавливаем регистр 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 ; процесс загрузки шрифтов более подробно описан в разделе "Загрузка ; таблиц знакогенератора" из главы "Дополнительные средства BIOS для ; управлния EGA и VGA" mov ax,1112h xor bl,bl int 10h } }
Регистр определяет момент начала гашения луча в прцессе вертикальной развертки.
Для EGA регистр имеет 9, а для VGA - 10 битов. Девятый бит и для EGA и для VGA расположен в дополнительном регистре (OVR). Десятый бит для VGA расположен в регистре высоты символов текста (MSLR).
В момент, когда младшие 5 битов регистра для EGA или все 8 битов для VGA равны счетчику горизонтальных линий, заканчивается сигнал гашения вертикальной развертки.
Регистр содержит набор битов, управляющих контроллером ЭЛТ.
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 |
Таблица 8.11 Преобразование адреса.
Бит D5 равен нулю только для видеоадаптеров EGA с объемом видеопамяти 64К байт. При этом происходит сцепление слоев в графических режимах с высоким разрешением.
Обеспечивает разделение экрана на две независимые части. При этом одну из них можно свертывать, содержимое другой части экрана остается на месте.
Данный регистр используют совместно с регистром начального адреса. Когда счетчик горизонтальных линий сканирования достигает значения, записанного в регистре LCR, происходит сброс счетчика адреса регенерируемой видеопамяти в ноль. В результате экран разбивается на две части, где в верхней отображаются данные, на которые указывает регистр начального адреса, а в нижней - данные, находящиеся в начале видеопамяти. На рисунке 8.8 иллюстрируется процесс разделения экрана:
Рисунок 8.8 Процесс разделения экрана.
Содержимое верхнего окна можно перемещать, изменяя содержимое регистра начального адреса.
Заметим, что у видеоадаптера EGA регистр сравнения линий состоит из 9 бит. Доступ к девятому биту возможен через дополнительный регистр (OVR) контроллера ЭЛТ. Видеоадаптер VGA имеет дополнительно еще и десятый бит, расположенный в регистре MSLR.
При изменении режима работы видеоадаптера, BIOS записывает в регистр сравнения линий значение 0FFh.
Следующая программа выводит на экран дисплея 25 строк текста, а затем, после нажатия любой клавиши, разделяет экран на две части.
// пример разделения экрана дисплея на две части при помоши // регистра сравнения линий контроллера ЭЛТ #include <dos.h> #include <stdio.h> void Split(unsigned); void main(void) { int i; // выводим на экран дисплея 25 строк текста for(i = 0; i < 25; i++) printf("Строка номер %d.",i); getch(); // разделяем экран по линии 200 Split(200); getch(); // после завершения программы // значения регистров не восстанавливаются! } /** *.Name Split * *.Title Разделение экрана. * *.Descr Функция разделяет экран на две части. Функция работает * только на EGA и VGA. * *.Proto void Split(unsigned split_line) * *.Params unsigned split_line - линия горизонтальной развертки, * в которой происходит разделение экрана дисплея. * *.Return Не используется. * *.Sample split.c **/ void Split(unsigned split_line) { _asm { ; устанавливаем регистр 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 ; вызываем функцию чтения конфигурации видеосистемы, ; данная функция подробно описана в главе ; "Дополнительные средства BIOS для управлния EGA и VGA" 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 ; если да, то переходим ; на метку 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,bl out dx,al quit_split: } }
Синхронизатор управляет всеми временными
параметрами видеоадаптера, а также разрешением и
запрещением доступа к отдельным цветовым слоям.
Синхронизатор имеет пять регистров, они
перечислены в таблице 8.12. У видеоадаптера EGA все
пять регистров доступны только для записи, а у VGA
и Super VGA также и для чтения.
Индекс регистра |
Регистр синхронизатора |
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) |
Таблица 8.12 Регистры синхронизатора.
Доступ к регистрам осуществляется через индексный порт с адресом 3C4h и через порт данных с адресом 3C5h.
Как и в случае описания регистров контроллера ЭЛТ мы будем подробно рассказывать только о безопасных и наиболее полезных регистрах синхронизатора.
Если регистр переведен в состояние сброса, то все процессы видеоадаптера приостанавливаются. В результате могут быть разрушены данные в видеопамяти.
Для нормальной работы видеоадаптера биты D0 и D1 должны быть равны единице. Перед доступом к регистру режима синхронизации синхронизатор должен быть переведен в состояние синхронного сброса (бит D1 равен 0).
Регистр управляет временными циклами синхронизатора. При изменении его содержимого необходимо соблюдать осторожность. Изменяя отдельные биты регистра, сохраняйте значения остальных битов.
Перед модификацией регистра CMR надо сбросить бит D1 в регистре сброса синхронизатора, переведя таким образом синхронизатор в режим сброса и остановки.
Ниже приведены значения регистра CMR,
устанавливаемые BIOS при установке режима работы
адаптера:
Режим |
00,01,04,05,0Dh |
02,03,06,0Eh |
0Fh,10h |
Содержимое регистра |
0Bh |
01 |
05 |
При помощи данного регистра можно запретить запись процессором данных в любые цветовые слои видеопамяти. На рисунке 8.9 показан механизм запрещения записи данных в отдельные слои видеопамяти. Рассмотрим процесс записи данных процессором в видеопамять:
Рисунок 8.9 Разрешение записи в цветовые слои.
Биты регистра разрешения записи цветового слоя имеют следующие значения:
При установке режима работы адаптера BIOS
загружает в регистр CPWE следующие значения:
Режим |
0,1,2,3,4,5,7 |
6 |
D,E,F,10 |
Содержимое регистра |
03 |
01 |
0Fh |
Видеоадаптер EGA позволяет загрузить в память четыре, а VGA - восемь таблиц знакогенератора, каждая из которых опрделяет 256 символов.
Одновременно могут использоваться символы одной или двух таблиц знакогенератора. Это позволяет отображать до 512 различных символов.
Если разрешено одновременное использование двух различных таблиц знакогенератора, то бит D3 байта атрибутов определяет какая таблица будет использоваться при отображении символа с этим атрибутом.
Регистр выбора знакогенератора определяет два набора символов, расположенных во втором цветовом слое, символы которых могут одновременно отображаться на экране. Данный регистр используется только в текстовых режимах.
Для выбора активных (используемых в данный
момент для отображения символов) таблиц
знакогенератора надо установить биты 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) |
1 0 1 |
шестая таблица знакогенератора (VGA) |
1 1 0 |
седьмая таблица знакогенератора (VGA) |
1 1 1 |
восьмая таблица знакогенератора (VGA) |
Таблица 8.13 Выбор таблиц знакогенератора.
Если нужна только одна активная таблица знакогенератора, то значеня битов D5 D3 D2 и битов D4 D1 D0 должны совпадать.
Для установки номеров активных таблиц знакогенератора рекомендуется использовать соответствующую функцию BIOS.
Регистр инициализируется BIOS при выполнении операции выбора режима работы видеоадаптера и определяет структуру видеопамяти в этом режиме.
При выборе режима работы адаптера, BIOS загружает
в регистр CPWE следующие значения:
Режим |
0,1,2,3,7 |
4,5 |
6,0Dh,0Eh |
0Fh,10h |
Содержимое регистра |
03 |
02 |
06 |
00 |
Как мы уже указывали, графический контроллер поддерживает обмен данными между процессором и видеопамятью. При этом он может выполнять простейшие логические операции над записываемыми в видеопамять данными. Грфический контроллер передает также данные из цветовых слоев видеопамяти - контроллеру атрибутов в случае использования графического режима работы видеоадаптера.
Графический контроллер содержит девять регистров. Обращение к ним происходит через индексный порт с адресом 3CEh и порт данных с адресом 3CFh. Список регистров приведен в таблице 8.14.
Адаптер 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) |
Таблица 8.14 Регистры графического контроллера.
Большинство регистров графического контроллера могут использоваться при программировании, поэтому регистры графического контроллера будут описаны полностью.
Ниже, на рисунке 8.10, демонстрируются функции, выполняемые графическим контроллером. Рассмотрм функционирование графического адаптера.
Байт, записываемый процесором в видеопамять (11100001b), поступает в графический контроллер. В соответствии со значением регистра циклического сдвига и выбора функции, происходит циклический сдвиг на один бит содержимого записываемого в видеопамять байта. Затем результат складывается по логике ИЛИ с содержимым регистров-защелок. Какая булева функция используется - ИЛИ, И, ИСКЛЮЧАЮЩЕЕ ИЛИ также определяется регистром циклического сдвига и выбора функции.
Дальнейшие преобразования происходят в соответствии со значениями регистра разрешения установки/сброса и регистра установки/сброса:
Затем в соответствии с состоянем регистра битовой маски происходит запись данных в видеопамять:
Рисунок 8.10 Функции графического контроллера.
Теперь рассмотрим регистры графического контроллера более подробно.
Использовав данный регистр совместно с регистром разрешения установки/сброса (Set/Reset Enable Register), можно определить данные, размещаемые в цветовых слоях видеопамяти при выполнении процессором записи любых данных в видеопамять. Данные процессора при этом игнорируются.
Приведем формат регистра установки/сброса:
По умолчанию во все биты регистра записываются нулевые значения.
Возможности использования данного регистра разъясняются при описании регистра разрешения установки/сброса.
Регистр разрешения установки/сброса позволяет при операции записи в видеопамять для одних цветовых слоев использовать данные от процессора, а для других - из регистра установки/сброса (см. рисунок 8.11).
Если биты регистра, управляющие цветовыми слоями, содержат единицы, то при выполнении операции записи, в соответствующие цветовые слои записывается информация из регистра установки/сброса. В остальные слои видеопамяти заносятся данные от процессора.
Теперь приведем формат регистра разрешения установки/сброса:
По умолчанию во все биты регистра записываются нулевые значения.
Заметим, что возможность использования регистров установки/сброса можно реализовать только в нулевом режиме записи. Режим записи устанавливается регистром режима работы графического контроллера (Mode Register, индекс 5). В нулевом режиме записи, если запрещено выполнение операции маскирования пикселов (регистр битовой маски содержит значение 0FFh), то каждый байт, записываемый процессором в видеопамять определяет параметры 8 пикселов в одном или нескольких цветовых слоях. Более подрбное описание регистра режима работы графического контроллера и регистра битовой маски приведено ниже.
Рассмотрим на рисунке 8.11 применение регистров установки/сброса. Пусть графический контроллер находится в нулевом режиме работы, и регистр битовой маски равен 0FFh (используются только данные от процессора). В этом случае можно использовать регистры установки/сброса.
Допустим, что после преобразования данных, записываемых процессором в видеопамять, в соответствии со значением регистра циклического сдвига и выбора функций, данные имеют следующий вид:
Данные, непосредственно поступающие в видеопамять зависят от значения регистра разрешения установки/сброса. Биты D3 и D0, регистра разрешения установки/сброса равны нулю, поэтому в третий слой и нулевой слой видеопамяти данные заносятся без изменения. Биты D2 и D1 регистра разрешения установки/сброса равны единице, значит во второй и первый слои видеопамяти записываются данные в соответствии со значением битов D2 и D1 регистра установки/сброса. То есть во второй слой записывается байт 00000000b, а в первый - 11111111b.
Рисунок 8.11 Использование регистров установки/сброса.
Регистр CCR используется программами, осуществляющими поиск на экране пикселов с определенным цветом. Без использования регистра CCR за один цикл чтения видеопамяти процессор может считать данные только из одного цветового слоя. Программирование данного регистра позволяет за один цикл чтения произвести чтение всех четырех цветовых слоев, сравнение считанных значений с искомыми и возвращение результата.
Ниже приведен формат регистра сравнения цветов:
После выполнения BIOS устаноки режима работы видеоадаптера все биты регистра содержат нулевые значения.
Операция поиска пикселов данного цвета иллюстрируется рисунком 8.12.
Рисунок 8.12 Использование регистра CCR.
Как видно из рисунка, в случае совпадения сравниваемых битов соответствующий бит результата равен единице.
Заметим, что перед использованием регистра CCR для операции поиска пикселов определенного цвета необходимо установить регистр режима работы (Mode Register - MDR) и регистр маскирования цветовых слоев (Color Don't Care Register - CDCR), описанные ниже.
Регистр DRFS выполняет две различные функции, отраженные в его названии:
После выполнения 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.15 Циклический сдвиг.
Теперь рассмотрим возможности графического контроллера по выполнению логических операций над записываемыми в видеопамять данными.
Во время выполнения процессором операции
чтения из видеопамяти одновременно происходит
запись данных из всех четырех цветовых слоев (по
считываемому адресу) в регистры-защелки. Каждому
цветовому слою видеопамяти соответствует один
8-битовый регистр-защелка. Когда процессор начнет
записывать в видеопамять (возможно уже по
другому адресу) данные, можно комбинировать их с
данными из регистров-защелок. Вид выполняемой
логической операции будет зависеть от
содержимого битов выбора логической функции
(таблица 8.16):
D4 D3 |
Выполняемая логическая операция |
0 0 |
запись немодифицированных данных |
0 1 |
И |
1 0 |
ИЛИ |
1 1 |
ИСКЛЮЧАЮЩЕЕ ИЛИ |
Таблица 8.16 Возможные логические операции.
Следует отметить, что операция циклического сдвига выполняется до выполнения логических функций.
Регистр DRFS можно использовать для быстрого копирования областей видеопамяти с возможной их модификацией.
Рисунок 8.13 иллюстрирует выполнение логической операции ИЛИ. Регистр циклического сдвига и выбора функции содержит число 00010000b. После операции чтения данные из всех четырех слоев записываются в регистрах-защелках. Затем выполняется операция записи. При этом данные процессора в соответствии с состоянием регистра циклического сдвига и выбора функции складываются по логике ИЛИ со значением регистров-защелок и помещаются в видеопамять.
Рисунок 8.13 Логические операции и операция циклического сдвига.
Заметим, что логические операции можно производить только в нулевом и втором режиме записи.
Определяет номер цветового слоя видеопамяти, из которого процессор может читать данные. Заметим, что при выполнении операции сравнения цветов значение этого регистра безразлично.
Приведем формат регистра выбора читаемого слоя.
При установке режима работы видеоадаптера BIOS заполняет все биты регистра нулями, что соответствует нулевому цветовому слою.
Операция чтения видеопамяти процессором иллюстрируется на рисунке 8.14. На этом рисунке регистр выбора читаемого слоя разрешает чтение второго слоя видеопамяти. Таким образом при чтении процессором данных из видеопамяти, процессор считывает данные только из второго слоя. Остальные слои будут недоступны для чтения процессором, пока вы не измените состояние регистра читаемого слоя.
Рисунок 8.14 Операция чтения из видеопамяти.
Регистр управляет несколькими различными функциями графического контроллера. В частности он управляет режимом записи в видеопамять, а также разрешением режима сравнния цветов (см. регистр сравнения цветов графического контроллера).
D1-D0 Режим записи. D2 Не используется. D3 Разрешение режима сравнения цветов. D4 Четный/нечетный режим. D5 Режим регистра сдвига. D6 Управление режимом VGA с 256 цветами. D7 Не используется.
Ниже подробно рассмотрены отдельные биты регистра. Мы не рекомендуем изменять состояние битов D4-D7, так как это может привести к потере изображения на экране дисплея.
D1 D0 |
Номер режима |
Режим записи |
0 0 |
0 |
режим непосредственной записи |
0 1 |
1 |
использование для записи
регистров-защелок |
1 0 |
2 |
заполнение N-ого цветового слоя битом
номер N из данных, записываемых процессором |
1 1 |
- |
не используется |
Процесс записи в видеопамять в каждом из перечисленных выше режимов показан на рисунке 8.14.
Рисунок 8.14 Различные режимы записи в видеопамять.
Остальные биты регистра модифицировать не рекомендуется.
При установке режима работы видеоадаптера BIOS
загружает в регистр MDR следующие значения, в
зависимости от режима работы видеоадаптера:
Режим |
0,1,2,3,7,F,10 |
4,5 |
6,D,E |
Содержимое регистра |
10h |
30h |
00 |
Регистр управляет видеопамятью и регистром-защелкой для адреса знакогенератора. В результате неправильной модификации регистра возможна неправильная работа некоторых функций BIOS и конфликты между видеоадаптерами в системе с двумя дисплеями.
При установке режима работы видеоадаптера BIOS
загружает в регистр MIR следующие значения, в
зависимости от режима работы видеоадаптера:
Режим |
3 |
7 |
F |
10 |
Содержимое регистра |
Eh |
Ah |
07 |
05 |
Регистр используется в режиме сравнения цветов (см. регистр сравнения цветов - CCR). Если какие-либо биты D3-D0 содержат ноль, то при операции сравнения цветов соответствующие цветовые слои в рассмотрение не принимаются.
При установке режима работы в регистр
заносятся следующие значения:
Режим |
3 |
7 |
F |
10 |
Содержимое регистра |
00 |
00 |
0Fh |
0Fh |
Регистр управляет записью данных в видеопамять. Если какой-то бит регистра BMR содержит ноль, то соответствующий бит будет записываться в видеопамять из регистра-защелки. В противном случае данный бит поступает от процессора (см. рисунок 8.15). Этот регистр используется только в нулевом режиме записи.
Рисунок 8.15 Использование регистра битовой маски.
Напомним, что занести данные в регистр-защелку можно, если выполнить операцию чтения из видеопамяти. При этом в каждый регистр-защелку считывается один байт из соответствующего цветового слоя.
По умолчанию, во всех режимах регистр хранит число 0FFh.
Контроллер атрибутов управляет цветовыми характеристиками изображений.
Контроллер атрибутов содержит двадцать один регистр. Регистры перечисленны в таблице 8.17. Доступ к ним осуществляется через один порт - 3C0h (в отличие от предыдущих рассмотренных нами регистров). Этот порт совмещает в себе функции индексного порта и порта данных, регулируемые внутренним триггером. Триггер переключается при каждой операции записи в порт и записываемые данные воспринимаются либо как индекс регистра, либо как данные для обмена с регистром.
Установить триггер в исходное состояние можно,
выполнив чтение из порта 3BAh для монохромного
режима или из порта 3DAh - для цветного режима
работы видеоадаптера. После установки триггера
данные, записываемые в регистр 3C0h, будут
восприниматься, как индекс регистра.
Индекс |
Регистры контроллера атрибутов |
0 - 0Fh |
регистры цветовой палитры (0-15) (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) |
Таблица 8.17 Регистры контроллера атрибутов.
Четыре цветовых слоя видеоадаптера EGA позволяют закодировать 16 различных цветов, однако улучшенный цветной дисплей обеспечивает возможность отображения 64 цветов.
16 регистров цветовой палитры предоставляют возможность выбора любых 16 цветов из 64 возможных, которые будут использоваться видеоадаптером EGA в данный моент.
При использовании улучшенного цветного дисплея каждый регистр цветовой палитры содержит шесть битов, соответствующих шести линиям управления дисплея.
Другие дисплеи - цветной (CD) и монохромный (MD), имеют меньшее число линий управления и регистр цветовой палитры также имеет другой формат.
Форматы регистров цветовой палитры для различных дисплеев приведены ниже:
Регистр управления режимом управляет контроллером атрибутов.
По умолчанию регистр содержит следующие
значения:
Режим |
0,1,2,3 |
4,5,6,D,E,10 |
7 |
F |
Содержимое регистра |
08 |
01 |
0Eh |
0Bh |
В текстовых режимах работы видеоадаптеров регистр задает цвет рамки, расположенной вокруг текста. Назначение битов регистра соответствует регистрам цветовой палитры. По умолчанию регистр цвета рамки содержит нулевые значения для всех режимов работы.
К сожалению операция установки цвета рамки работает не правильно на большинстве адаптеров EGA.
При установке режима работы видеоадаптера BIOS
записывает в регистр следующие значения:
Режим |
0,1,2,3,7,D,E |
4,5 |
6 |
F,10 |
|
Содержимое регистра |
0Fh |
03 |
03 |
01 |
05 |
Регистр позволяет сдвигать в горизонтальном направлении содержимое экрана на один пиксел. При использовании регистра HPR совместно с регистром начального адреса контроллера атрибутов можно производить горизонтальный сдвиг экрана влево на любое число пикселов.
Формат регистра горизонтального панорамирования представлен ниже:
|
Величина сдвига содержимого крана (в пикселах) |
||
D3 D2 D1 D0 |
монохромный текстовый |
VGA, режим 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 |
- |
- |
- |
Таблица 8.18 Величина горизонтального сдвига в различных режимах работы видеоадаптера.
По умолчанию для всех режимов работы видеоадаптера регистр горизонтального панорамирования содержит нулевые значения для всех битов.
На рисунке 8.16 иллюстрируется операция горизонтального сдвига содержимого экрана при различных значениях регистра HPR. На левой части рисунка регистр горизонтального панорамирования содержит ноль, а на правой части рисунка значение регистра увеличено до трех, при этом изображение на экране сдвигается на три пиксела влево.
Рисунок 8.16 Горизонтальный сдвиг экрана.
Следующая программа позволяет перемещать содержимое экрана по горизонтали и вертикали. Функции HorScroll и VerScroll реализуют, соответственно, горизонтальный и вертикальный сдвиг экрана.
// смещение содержимого экрана по горизонтали и вертикали #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); } /** *.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 -> char_height); start_addr_reg = res.quot * (bios_var_ptr -> columns); 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 для управления цветом.
VGA работает с аналоговыми дисплеями, имеющими три раздельных видеовхода. Величина напряжения на каждом из них управляет, соответственно, интенсивностью красного, зеленого и голубого цвета изображения. Аналоговое напряжение для дисплея формируется из двоичной цветовой информации при помощи трех ЦАП.
Цветовая 8-битовая информация, поступающая от контроллера атрибутов (см. рисунок 8.17), преобразуется согласно таблице цветов в три 6-битовые сигнала для трех ЦАП. Такая схема позволяет одновременно отображать на экране 256 различных цветов, каждый из которых можно отдельно выбрать из 26+6+6 = 218 = 262144 возможных цветов.
Рисунок 8.17 Схема управления цветами (VGA).
Таблица цветов фактически является набором из 256 18-битовых регистров. Используя регистры ЦАП, можно получить доступ для чтения и для записи к каждому регистру таблицы цветов.
ЦАП видеоадаптера VGA управляется пятью
регистрами, перечисленными в таблице 8.19.
Адрес |
Регистр |
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) |
Таблица 8.19 Регистры управления ЦАП.
Фирма IBM в руководстве по VGA предупреждает, что доступ к регистру нежелателен. В противном случае могут разрушиться данные в таблице цветов.
Регистр адресуется при помоши порта с адресом 3C7h и доступен только для чтения. Прочитав данные из регистра, можно определить, доступны регистры цветовой таблицы для чтения или же они доступны для записи.
Это индексный регистр доступен через порт 3C7h только для записи. Запись в данный регистр индекса элемента цветовой таблицы позволяет прочитать его содержимое через регистр данных цветовой таблицы.
Данные из регистров таблицы цветов читаются через порт 3C9h, как три 6-битовых числа. После чтения третьего числа значение индексного регистра (LTRIR) автоматически увеличивается на единицу, что позволяет прочитать всю таблицу цветов, загрузив регистр индекса только один раз.
Особо подчеркнем, что во время операций чтения или записи таблицы цветов прерывания должны быть запрещены.
После записи в регистр LTWIR индекса регистра таблицы цветов можно записать в него новое значение через регистр данных таблицы цветов (см. ниже).
Данные записываются в регистры таблицы цветов через порт 3C9h, как три 6-битовых числа. После записи третьего числа значение индексного регистра (LTWIR) автоматически увеличивается на единицу, что позволяет прочитать таблицу цветов, загрузив регистр индекса только один раз.
Регистр используется для получения доступа к регистрам таблицы цветов. Для чтения из (записи в) таблицы цветов необходимо три раз прочитать (записать) содержимое регистра данных. При этом каждый раз считывается (записывается) шесть очередных битов. Первые шесть битов отвечают за интенсивность красного, вторые - зеленого и третьи - голубого цвета.
Нельзя прерывать цикл чтения регистров таблицы цветов, состоящий из трех операциий чтения, выполнением операции записи в другой регистр таблицы и наоборот. Во время доступа к данному регистру прерывания должны быть запрещены. Между операциями доступа к регистрам таблицы цвета должен существовать временной интервал не менее 240 наносекунд.
Следующая программа записывет новые значения в таблицу цветов непосредственно через регистры цифро-аналогового преобразователя VGA. На экране дисплея отображается пять вертикальных полос различного цвета. Каждая полоса состоит из 64 вертикальных линий. Интенсивность цвета этих линий плавно уменьшается слева на право.
// программа демонстрирует использование регистров таблицы цветов #include <conio.h> #include <stdio.h> #include <graph.h> #include "sysp.h" #include "sysgraph.h" #include <dos.h> void SetVgaDAC(unsigned, unsigned); viod main(void) { struct videoconfig vc; // структура описана в graph.h RGB color_table[256]; unsigned char i, j; unsigned char far *ptr; int error, x_num, y_num; unsigned seg_table,off_table; // записываем в массив 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 error = _setvideomode( _MRES256COLOR ); // если режим не установлен, завершаем выполнение программы if(!error) exit(1); ptr = (unsigned char far*) &color_table[0]; // определяем сегмент и смешение массива color_table 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(); // устанавливаем режим видеодаптера, используемый по умолчанию _setvideomode( _DEFAULTMODE ); } /** *.Name SetVgaDAC * *.Title Запись регистров таблицы цветов * *.Descr Функция устанавливает новые значения для всех регистров * таблицы цветов. * * *.Proto void SetVgaDAC(unsigned seg_table, unsigned off_table) * *.Params unsigned seg_table - сегмент таблицы, содержащей новые * значения регистров таблицы цветов, * * unsigned off_table - смещение таблицы, содержащей новые * значения регистров таблицы цветов. *.Return Не используется. * *.Sample vga256.c **/ void SetVgaDAC(unsigned seg_table, unsigned off_table) { _asm { ; сохраняем регистры 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 } }
В этой главе на примере видеоадаптера VGA мы рассмотрим программирование нестандартных режимов. Так как программирование нестандартных режимов видеоадаптеров требует непосредственного доступа к его регистрам, то перед чтением этой главы вам необходимо подробно изучить назначение регистров адаптера.
Мы рассмотрим два наиболее интересных с нашей точки зрения нестандартных режимов VGA: 320х400 и 360х480 пикселов при 256 цветах.
Эти режимы нельзя установить на обычных VGA адаптерах с помощью функций BIOS. С помощью BIOS можно установить только один режим с 256-цветной палитрой - 13h (320х200 пикселов, 256 цветов). Однако если вы воспользуетесь возможностью непосредственного программирования адаптера через регистры, то любой адаптер VGA можно перевести в эти режимы.
Программирование всех трех описанных ниже нестандартных режимов мы проведем в два этапа:
Такой подход к установке нестандартных режимов позволяет нам программировать не все регистры адаптера, а только те, которые нуждаются в изменении.
Режим 13h использует простую линейную организацию видеопамяти, в которой по каждому адресу в видеопамяти находится один байт управляющий одним пикселом. Такая организация видеопамяти хотя и облегчает программирование, но не позволяет увеличить разрешающую способность. Дело в том, что в режиме 13h адресное пространство видеопамяти ограничено 64K, которых хватает как раз для того, чтобы получить разрешающую способность 200х320 точек при 256 цветах (200*320 = 64000). Кроме того такая организация видеопамяти не позволяет использовать для копирования видеоданных регистры-защелки, что может существенно повысить скорость работы программ.
Исходя из вышесказонного для нашего нестандартного режима используется другая структура видеопамяти, более схожая со структурой видеопамяти режимов 10h и 12h. На следующем рисунке представлена структура видеопамяти используемая нами во всех описываемых нестандартных режимах:
Рисунок 8.18 Структура видеопамяти в нестандартных, 256-цветовых режимах.
Как видно из рисунка первый пиксел экрана, отображаемый в левом верхнем углу, определяется байт со смещением 0 из нулевого цветового слоя. Второй пиксел определяется байтом со смещением 0 из первого слоя, третий пиксел - байтом со смещением 0 из второго слоя, четвертый пиксел - байтом со смещением 0 из третьего слоя. Пятый пиксел определяется байтом со смещением 1 из нулевого слоя и так далее.
Таким образом для пиксела с координатами x и y байт, который определяет его цвет, расположен со смещением (x + y * PIXEL_PER_LINE) / 4, в цветовой плоскости (x + y * PIXEL_PER_LINE) mod 4. В этой формуле константа PIXEL_PER_LINE должна определять горизонтальную разрешающую способность экрана в данном режиме.
Такая организация видеопамяти, хотя и более неудобна для вычисления адреса пикселов, чем линейная организация памяти режима 13h, но дает другие неоспаримые преимущества.
Во первых, в режиме с разрешением 320х400 пикселов мы можем использовать две страницы видеопамяти, первая из них имеет нулевое смещение, а вторая смещение 8000h от начала видеопамяти. Режим с разрешением 360х480 пикселов позволяет иметь только одну страницу, но так как он использует только 172800 байт из 256 килобайт, то неиспользуемую память можно использовать для хранения пиктограмм и шрифтов.
Во вторых, организация видеопамяти в виде отдельных цветовых слоев позволяет использовать для операций копирования и заполнения областей видеопамяти регистры-защелки. Это дает возможность одновременно копировать четыре байта, и следовательно значительно увеличить скорость работы программ.
Мы начнем рассмотрение нестандартных режимов с режима, имеющего разрешение 320х400 пикселов. Программирование этого режима является самым простым и безопасным, так как при его установке нам не придется изменять содержимое регистров контроллера ЭЛТ.
Как мы указывали при описании режимов видеоадаптеров, в режиме 13h используется двойное сканирование. То есть в этом режиме - 320х200 пикселов на самом деле отображается не 200, а 400 линий сканирования. Перепрограммировав несколько регистров адаптера можно перевести его в режим 320х400 пикселов.
Рассмотрим последовательность действий, необходимую для перевода видеоадаптера в нестандартный режим с разрешением 320х400 пикселов:
Теперь мы приведем программу, которая реализует изложенный алгоритм и переводит видеоадаптер в режим отображающий 256 цветов при разрешающей способности 320х400 пикселов.
/** * Включаемый файл vga_new.h **/ // сегмент видеопамяти для режима 13h #define VGA_SEGMENT 0a000h // регистр определения различных режимов работы #define MOR 3c2h // адрес индексного порта синхронизатора #define SC_INDEX 3c4h // регистр разрешения записи цветового слоя #define CPWER 2 // регистр определения структуры памяти #define MMR 4 // адрес индексного порта графического контроллера #define GC_INDEX 3ceh // регистр выбора читаемого слоя #define RPSR 4 // регистр режима работы #define MDR 5 // регистр смешанного назначения #define MIR 6 // адрес индексного порта контроллера ЭЛТ (цветной режим) #define CRTC_INDEX 3d4h // регистр высоты символов текста #define MSLR 9 // регистр начального адреса #define SAR_h 0ch // регистр положения подчеркивания символа #define ULR 14h // регистр управления режимом #define MCR 17h // режим 320х400 пикселов // число пикселов по вертикали #define SCREEN_HEIGHT 400 // число пикселов по горизонтали #define SCREEN_WIDTH 320 // режим 360х480 пикселов // число пикселов по вертикали #define SCREEN_HEIGHT_H 480 // число пикселов по горизонтали #define SCREEN_WIDTH_H 360 /** * Файл e256mres.c **/ #include "sysp.h" #include "sysgraph.h" #include <dos.h> #include <graph.h> #include "vga_new.h" /** *.Name Set320x400Mode * *.Title Установка режима 320х400 пикселов, 256 цветов. * *.Proto void Set320x400Mode( void ) * *.Params Не используются. * *.Return Не используетя. * *.Sample e256mres.c **/ void Set320x400Mode( void ) { _asm { // сохраняем регистр 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,11101111 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,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 } } /** *.Name WritePixel * *.Title Отображение пиксела. * *.Descr Функция отображает на экране пиксел в заданных * координатах, * определенного цвета. * *.Proto void WritePixel(unsigned x, unsigned y, unsigned * char color) * *.Params x - x-координата пиксела (0-319), * * y - y-координата пиксела (0-399), * * color - цвет пиксела (0-255). * *.Return Не используетя. * *.Sample e256mres.c **/ void WritePixel(unsigned x, unsigned y, unsigned char color) { _asm { 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 } } /** *.Name ReadPixel * *.Title Определение цвета пиксела. * *.Descr Функция возвращает значение байта видеопамяти, * определяющего пиксел * с заданными координатами. * *.Proto unsigned char ReadPixel(unsigned x, unsigned y, * unsigned char color) * *.Params x - x-координата пиксела (0-319), * * y - y-координата пиксела (0-399). * *.Return цвет пиксела (0-255). * *.Sample e256mres.c **/ unsigned char ReadPixel( unsigned x, unsigned y ) { unsigned char color; _asm { 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] mov color,al pop si } return( color ); } /** *.Name Full_Scr * *.Title Закрашивает экран заданным цветом. * *.Proto void Full_Scr( unsigned char color ) * *.Params color - цвет экрана (0-255). * *.Return Не используетя. * *.Sample e256mres.c **/ void Full_Scr( unsigned char color ) { _asm { ;разрешаем запись данных во все четыре цветовых ;слоя 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 } } // функция LoadVGA256 загружает регистры таблицы цветов // цифро-аналогового преобразователя новыми значениями void LoadVGA256(void) { RGB color_table[256]; unsigned char i, j; unsigned char far *ptr; unsigned seg_table,off_table; // записываем в массив 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; } } ptr = (unsigned char far*) &color_table[0]; // определяем сегмент и смешение массива color_table seg_table = FP_SEG(ptr); off_table = FP_OFF(ptr); // загружаем новые значения в регистры таблицы цветов SetVgaDAC(seg_table,off_table); // функция SetVgaDAC загружает регистры таблицы цветов // цифро-аналогового преобразователя // исходный текст функции приведен при описании регистра // данных таблицы цветов ЦАП VGA (файл vga256.c) } // // главная функция // void main( void ){ unsigned i; char ch = 13; struct videoconfig vc; // заполняем поля структуры vc printf("\n (C) Frolov G.V., 1992 \n\n"); _getvideoconfig( &vc ); // завершаем программу если нет VGA адаптера if(vc.adapter != _VGA) { printf("Для выполнения программы необходим" " адаптер VGA.\n"); exit(0); } // устанавливаем режим 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++) { Full_Scr( (unsigned char) i ); ch = getch(); } // возвращаемся в текстовый режим _setvideomode(_DEFAULTMODE); printf("Привет всем!!!\n"); }
Второй рассматриваемый нами нестандартный режим может отображать 256 цветов при разрешающей способности 360х480 пикселов. Программирование этого режима является менее простыми безопасным, чем предыдущего режима, так как нам придется изменять содержимое регистров контроллера ЭЛТ, отвечающих за временные характеристики видеоадаптера. В остальном программирование видеоадаптера осуществляется по тем же правилам, что и в режиме с разрешающей способностью 320х400 пикселов.
Ниже приведена программа, которая переводит видеоадаптер в нестрандартный режим с разрешением 360х480 пикселов:
/** * Файл e256hres.c **/ #include "sysp.h" #include "sysgraph.h" #include <dos.h> #include <graph.h> #include "vga_new.h" /** *.Name Set360x480Mode * *.Title Установка режима 360х480 пикселов, 256 цветов. * *.Proto void Set360x480Mode( void ) * *.Params Не используются. * *.Return Не используетя. * *.Sample e256hres.c **/ void Set360x480Mode( void ) { _asm { // устанавливаем режим 12h, чтобы очистить видеопамять mov ax,12h int 10h // устанавливаем стандартный режим 13h 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,11101111 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 } } /** *.Name WritePixel_H * *.Title Отображение пиксела. * *.Descr Функция отображает на экране пиксел в заданных * координатах, определенного цвета. * *.Proto void WritePixel_H(unsigned x, unsigned y, unsigned * char color) * *.Params x - x-координата пиксела (0-319), * * y - y-координата пиксела (0-399), * * color - цвет пиксела (0-255). * *.Return Не используетя. * *.Sample e256hres.c **/ void WritePixel_H(unsigned x, unsigned y, unsigned char color) { _asm { 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 } } /** *.Name ReadPixel_H * *.Title Определение цвета пиксела. * *.Descr Функция возвращает значение байта видеопамяти, * определяющего пиксел с заданными координатами. * *.Proto unsigned char ReadPixel_H(unsigned x, unsigned y, unsigned char color) * *.Params x - x-координата пиксела (0-319), * * y - y-координата пиксела (0-399). * *.Return цвет пиксела (0-255). * *.Sample e256hres.c **/ unsigned char ReadPixel_H( unsigned x, unsigned y ) { unsigned char color; _asm { 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 pop si } return( color ); } /** *.Name Full_Scr_H * *.Title Закрашивает экран заданным цветом. * *.Proto void Full_Scr_H( unsigned char color ) * *.Params color - цвет экрана (0-255). * *.Return Не используетя. * *.Sample e256hres.c **/ void Full_Scr_H( unsigned char color ) { _asm { push di ;разрешаем запись данных во все четыре цветовых слоя mov dx,SC_INDEX mov al,CPWER out dx,al 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 } } // функция LoadVGA256 загружает регистры таблицы цветов // цифро-аналогового преобразователя новыми значениями void LoadVGA256(void) { RGB color_table[256]; unsigned char i, j; unsigned char far *ptr; unsigned seg_table,off_table; // записываем в массив 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; } } ptr = (unsigned char far*) &color_table[0]; // определяем сегмент и смешение массива color_table seg_table = FP_SEG(ptr); off_table = FP_OFF(ptr); // загружаем новые значения в регистры таблицы цветов SetVgaDAC(seg_table,off_table); // функция SetVgaDAC загружает регистры таблицы цветов // цифро-аналогового преобразователя // исходный текст функции приведен при описании регистра // данных таблицы цветов ЦАП VGA (файл vga256.c) } // // главная функция // void main( void ){ unsigned i; char ch = 13; struct videoconfig vc; // заполняем поля структуры vc printf("\n (C) Frolov G.V., 1992\n\n"); _getvideoconfig( &vc ); // завершаем программу если нет VGA адаптера if(vc.adapter != _VGA) { printf("Для выполнения программы нобходим" " адаптер VGA\n"); exit(0); } // устанавливаем режим 360х480 пикселов, 256 цветов Set360x480Mode(); // загружаем регистры ЦАП VGA LoadVGA256(); for(i = 0; i < 480; i++) WritePixel_H(180, (unsigned) i, (unsigned char) (i % 256) ); for(i = 0; i < 360; i++) WritePixel_H((unsigned) i, 240, (unsigned char) (i % 256) ); ch = getch(); if( ch == 27 ) exit(1); for(i = 0; i < 360; i++) WritePixel_H((unsigned) i, (unsigned) i, (unsigned char) (i % 256) ); ch = getch(); for(i = 0; ((i < 256) && (ch != 27)); i++) { Full_Scr_H( (unsigned char) i ); ch = getch(); } // возвращаемся в текстовый режим _setvideomode(_DEFAULTMODE); printf("Привет всем!!!\n"); }