4. Регистры видеоадаптеров EGA, VGA и SVGA

В этой главе мы опишем все основные регистры видеоадаптеров EGA, VGA и SVGA, которые могут быть полезны при написании программ. Программирование видеоадаптеров на уровне регистров позволяет увеличить скорость работы программ и решить некоторые задачи, которые нельзя решить только при помощи функций BIOS.

Непосредственное использование регистров может вызвать ряд проблем при переносе ваших программ на другие машины. Дело в том, что не все адаптеры совместимы на уровне регистров. Например, оригинальный видеоадаптер CGA создан на основе микросхемы Motorola 6845, а видеоадаптеры EGA и VGA используют более совершенный аналог этой микросхемы. Некоторые регистры CGA располагаются по другим адресам и могут выполнять какие-либо дополнительные функции, чем регистры EGA и VGA. Кроме того, в каждом новом видеоадаптере SVGA расширяется набор используемых регистров.

Существуют модели видеоадаптеров EGA, VGA и SVGA, поддерживающие режим совместимости, когда они эмулируют адаптеры более низкого уровня (например MDA, Hercules, CGA). Эмуляция обычно происходит на уровне регистров, что гарантирует полную их совместимость. Режимы совместимости, если они поддерживаются, описаны в руководстве данного видеоадаптера.

На практике, для управления видеоадаптерами, рекомендуется преимущественно использовать функции BIOS. Это избавит вас от неприятных минут, когда ваша работающая программа, при переносе на другую машину перестанет правильно выполняться.

Краткий обзор

Видеоадаптеры EGA, VGA и SVGA имеют большое количество регистров. Адаптер EGA имеет около шестидесяти регистров, а VGA и SVGA еще больше. Большая часть регистров EGA доступна только для записи, что создает определенные проблемы, особенно для мультизадачных систем.

Некоторые фирмы-изготовители видеоадаптеров выпускают платы видеоадаптеров совместимые с EGA, для регистров которых разрешена также и операция чтения. В адаптерах VGA и SVGA практически все регистры доступны как для записи, так и для чтения.

Доступ к большинству регистров видеоадаптеров осуществляется в два этапа: через один порт ввода/вывода выбирается номер интересующего вас регистра, а затем через другой порт ввода/вывода осуществляется обмен данными. Такая организация регистров позволяет сэкономить большое количество портов центрального процессора. Остальные регистры адресуются непосредственно через соответствующие порты ввода/вывода - каждому регистру соответствует один порт ввода/вывода.

Заметим, что в различных режимах работы видеоадаптера, его регистры могут иметь различные адреса.

Приведем список адресов регистров в монохромных режимах:

Адрес Регистр
3C2h Регистр определения различных режимов работы (Miscellaneous Output Register - MOR),
Регистр состояния 0 (Input Status Register 0 - ISR0)
3BAh Регистр управления дополнительным устройством (Feature Control Register),
Регистр состояния 1 (Input Status Register 1 - ISR1)
3BBh Регистр очистки защелки светового пера (Clear Light Pen Latch Register- CLPLR)
3BCh Установка защелки светового пера (Set Light Pen Latch Register - SLPLR)
3C4h, 3C5h Регистры синхронизатора (Sequencer Register's - SR)
3B4h, 3B5h Регистры контроллера ЭЛТ (CRT Controller Register's - CRT_CR)
3CAh, 3CCh, 3CEh, 3CFh Регистры графического контроллера (Graphics Controller Register's - GCR)
3C0h Регистр контроллера атрибутов (Attribute Controller Register - ACR)
3C3h Регистр разрешения работы системы VGA (VGA Enable Register - VGA_ER)
3C6h, 3C7h, 3C8h, 3C9h Регистры цифро-аналогового преобразователя (ЦАП) VGA (VGA Video DAC Register - VGA_DAC_R)

А теперь перечислим адреса тех же регистров, но уже для цветных режимов видеоадаптера:

Адрес Регистр
3C2h Регистр определения различных режимов работы (Miscellaneous Output Register - MOR),
Регистр состояния 0 (Input Status Register 0 - ISR0)
3DAh Регистр управления дополнительным устройством Feature Control Register),
Регистр состояния 1 (Input Status Register 1 - ISR1)
3DBh Регистр очистки защелки светового пера (Clear Light Pen Latch Register- CLPLR)
3DCh Установка защелки светового пера (Set Light Pen Latch Register - SLPLR)
3C4h, 3C5h Регистры синхронизатора (Sequencer Register's - SR)
3D4h, 3D5h Регистры контроллера ЭЛТ (CRT Controller Register's - CRT_CR)
3CAh, 3CCh, 3CEh, 3CFh Регистры графического контроллера (Graphics Controller Register's - GCR)
3C0h Регистр контроллера атрибутов (Attribute Controller Register - ACR)
3C3h Регистр разрешения работы системы VGA (VGA Enable Register - VGA_ER)
3C6h, 3C7h, 3C8h, 3C9h Регистры ЦАП VGA (VGA Video DAC Register - VGA_DAC_R)

В зависимости от режима работы видеопамять адаптера занимает различное адресное пространство:

Номер режима работы Адрес памяти
0,1,2,3,4,5,6 B000:8000h-B000:FFFFh
7 B000:0000h-B000:7FFFh
0Dh,0Eh,0Fh,10h,11h,12h,13h A000:0000h-A000:FFFFh

Ниже мы привели исходный текст функции Get_Seg_Vmem. Данная функция определяет текущий режим работы видеоадаптера и возвращает сегментный адрес начала видеопамяти. Если видеоадаптер работает в нестандартном режиме, функция возвращает нулевое значение.

Чтобы узнать номер текущего режима видеоадаптера, используется функция 0Fh прерывания INT 10h. Пример вызова данной функции представлен в листинге 4.1.

Листинг 4.1. Файл SEGVMEM.C


// Файл SYSP.H представлен в листинге 3.2
#include "sysp.h"

unsigned GetSegVmem(void) {

	unsigned char	mode;
	unsigned			seg_address;

	// Определяем текущий режим видеоадаптера
	_asm {
		mov ah,0Fh
		int 10h
		mov mode,al
	}

	// Если видеоадаптер находится в режимах 0, 1, 2, 3,
	// 4, 5, 6 то видеопамять начинается с сегмента B800h
	if((mode >= 0) && (mode <= 6))
		seg_address = 0xB800;

	// Если видеоадаптер находится в режиме 7,
	// то видеопамять начинается с сегмента B000h
	else if(mode == 7)
		seg_address = 0xB000;

	// Если видеоадаптер находится в режимах 0Dh - 13h,
	// то видеопамять начинается с сегмента A000h
	else if((mode >= 0x0D) && (mode <= 0x13))
		seg_address = 0xA000;

	// Если видеоадаптер не находится в стандартном режиме
	// возвращаем ноль
	else seg_address = 0x0;

	return(seg_address);
}

Ниже подробно рассмотрены регистры видеоадаптеров EGA и VGA. Мы выделили следующие группы регистров:

Внешние регистры

Видеоадаптер EGA содержит большинство регистров внутри одной центральной микросхемы. В ней расположены контроллер атрибутов, контроллер ЭЛТ, графический контроллер и преобразователь последовательности. Только несколько регистров размешены в отдельной микросхеме. Они стали называться внешними.

При разработке видеоадаптеров VGA и SVGA внешние регистры были объединены с остальными регистрами в одной микросхеме, но название внешние сохранилось.

Каждому внешнему регистру соответствует порт ввода/вывода.

Регистр определения различных режимов работы
(Miscellaneous Output Register - MOR)

У видеоадаптера EGA данный регистр доступен только для записи. Вы можете записать в него новое значение через порт ввода/вывода с адресом 3C2h. Видеоадаптер VGA позволяет прочитать содержимое регистра MOR, но уже по адресу 3CCh. Ниже представлено описание отдельных битов регистра MOR:

Биты Описание
D0 Выбор адресов портов ввода/вывода
D1 Разрешение доступа к видеопамяти
D2, D3 Выбор частоты
D4 Запрещение управления видеоадаптером
D5 Бит четной/нечетной страницы
D6 Полярность сигнала горизонтальной синхронизации
D7 Полярность сигнала вертикальной синхронизации

D7 Полярность сигнала вертикальной синхронизации. Нулевая величина для данного бита устанавливает положительную полярность сигнала, единичная - отрицательную. Монохромный, цветной и улучшенный цветной мониторы используют положительную полярность сигнала синхронизации.

D6 Полярность сигнала горизонтальной синхронизации. Нулевая величина для данного бита устанавливает положительную полярность, единичная - отрицательную. Монохромный монитор использует отрицательную полярность сигнала синхронизации, а цветной - положительную.

Улучшенный цветной монитор и аналоговый монитор используют биты D7 и D6 для определения частоты развертки. Следующая таблица содержит допустимые значения для этих битов:

D7 D6 EGA VGA
00 200 линий Не используется
01 350 линий 350 линий
10 Не используется 400 линий
11 Не используется 480 линий

D5 Бит четной/нечетной страницы используется для режимов, которые передают данные по четным адресам в нулевой цветовой слой, а по нечетным - в первый. Все текстовые режимы устанавливают этот бит. Бит D5 выбирает одну из двух страниц видеопамяти.

D4 Управление видеоадаптером. Бит доступен только для видеоадаптера EGA. Видеоадаптеры VGA и SVGA этот бит не используют. Обычно бит D4 имеет значение 0. В этом случае управление монитором осуществляет видеоадаптер. Если бит D4 принимает значение 1, то монитор управляется сигналами, поступающими от разъема дополнительного устройства.

D2, D3 Биты выбора частоты управляют тактовой частотой видеоадаптера. Таблица, расположенная ниже, представляет правильные варианты установки битов D3 и D2:

D3 D2 Режим
0 0 640 пикселов в строке
0 1 720 пикселов в строке
1 0 Используется внешний генератор. Внешний генератор подключается через разъем дополнительного устройства)
1 1 Зарезервировано

D1 Доступ к видеопамяти. Данный бит может запретить доступ процессора к видеопамяти. Если бит равен нулю, то доступ центрального процессора к видеопамяти запрещен.

D0 Выбор адресов портов ввода/вывода. Бит D0 определяет адрес регистра управления дополнительным устройством (Feature Control Register), регистра состояния 1 (Input Status Register 1) и регистров контроллера ЭЛТ (CRT Controller). Когда бит D0 равен нулю, происходит выбор адресного пространства монохромного режима (адреса 3Bхh). Если бит равен единице, то используется адресное пространство цветного режима работы видеоадаптера (адреса 3Dхh).

Данные, первоначально записываемые BIOS в этот регистр зависят от режима работы видеоадаптера:

Режим 0-6,0Dh,0Eh 7 Fh 10h
Содержимое регистра 23h 0A6h 0A2h 0A7h

Регистр управления дополнительным устройством
(Feature Control Register - FCR)

Для видеоадаптера EGA биты D1 и D0 данного регистра передают сигналы на разъем дополнительного устройства. Бит D0 соответствует линии FC0 (вывод 21 разъема дополнительного устройства), а бит D1 линии FC1 (вывод 20 разъема дополнительного устройства).

Регистр не используется для видеоадаптеров VGA и SVGA, однако бит D3 в этом случае должен содержать ноль.

Адрес порта ввода/вывода регистра FCR зависит от режима работы видеоадаптера. В монохромных режимах адрес порта 3BAh, а в цветных - 3DAh. У видеоадаптера EGA регистр FCR доступен только для записи. Видеоадаптеры VGA и SVGA позволяют прочитать его содержимое через порт 3CAh.

Регистр состояния 0
(Input Status Register 0 - ISR0)

Регистр ISR0 доступен через порт 3C2h только для чтения. Формат регистра приведен ниже:

Биты Описание
D3-D0 Не используются
D4 Состояние переключателей
D5 Бит 0 дополнительного устройства (FEAT0)
D6 Бит 1 дополнительного устройства (FEAT1)
D7 Бит прерывания от ЭЛТ

D7 Бит установлен в 1, во время обратного вертикального хода луча (погашенный луч перемещается из правого нижнего угла экрана в левый верхний). Бит D7 устанавливается в начале обратного вертикального хода луча и сбрасывается при записи в регистр конца вертикального хода луча.

D6 Бит 1 дополнительного устройства. Используется только видеоадаптерами EGA. Бит D6 регистра управляет уровнем сигнала FEAT0 (вывод 17 разъема дополнительного устройства).

D5 Бит 0 дополнительного устройства. Используется только видеоадаптерами EGA. Бит регистра управляет уровнем сигнала FEAT1 (вывод 19 разъема дополнительного устройства).

D4 Состояние переключателей. Проанализировав бит D4, функции BIOS EGA могут определить состояние четырех переключателей, находящихся на плате видеоадаптера. Номер считываемого переключателя задается двумя битами выбора частоты (D2 и D3) регистра определения различных режимов работы (MOR), согласно следующей таблице:

Бит D3 Бит D2 Номер переключателя
0 0 1
0 1 2
1 0 3
1 1 4

Если бит D4 установлен в единицу, то переключатель, заданный битами D2 и D3 регистра определения различных режимов работы, находится в положении ON. Если бит сброшен в ноль, то переключатель находится в положении OFF.

К компьютеру могут быть подключены две различные видеосистемы - два видеоадаптера и два монитора. На плате адаптеров EGA расположены четыре переключателя. Их положение определяет, какие видеоадаптеры и мониторы могут быть подключены одновременно.

Если к компьютеру подключены два видеоадаптера, то один из них является первичным, а другой дополнительным. Первичный видеоадаптер используется по умолчанию сразу после включения компьютера.

Ниже представлены правильные варианты установки переключателей для различных конфигураций видеосистемы компьютера.

  4 3 2 1  
ON .     . Первичный: EGA с цветным монитором (40х25)
OFF   . .   Дополнительный: MDA
  4 3 2 1  
ON .       Первичный: EGA с цветным монитором (80х25)
OFF   . . . Дополнительный: MDA
  4 3 2 1  
ON   . . . Первичный: EGA с улучшенным цветным монитором
OFF .       Дополнительный: MDA
  4 3 2 1  
ON   . .   Первичный: EGA с улучшенным цветным монитором
OFF .     . Дополнительный: MDA
  4 3 2 1  
ON   .   . Первичный: EGA с монохромным монитором
OFF .   .   Дополнительный: CGA с цветным монитором (40х25)
  4 3 2 1  
ON   .     Первичный: EGA с монохромным монитором
OFF .   . . Дополнительный: CGA с цветным монитором (80х25)
  4 3 2 1  
ON . . . . Первичный: MDA
OFF         Дополнительный: EGA с цветным монитором (40х25)
  4 3 2 1  
ON . . .   Первичный: MDA
OFF       . Дополнительный: EGA с цветным монитором (80х25)
  4 3 2 1  
ON . .   . Первичный: MDA
OFF     .   Дополнительный: EGA с цветным монитором (80х25)
  4 3 2 1  
ON . .     Первичный: MDA
OFF     . . Дополнительный: EGA с цветным монитором
  4 3 2 1  
ON .   . . Первичный: CGA с цветным монитором 40х25
OFF   .     Дополнительный: EGA с монохромным монитором
  4 3 2 1  
ON .   .   Первичный: CGA с цветным монитором 80х25
OFF   .   . Дополнительный: EGA с монохромным монитором

Видеоадаптеры VGA и SVGA используют бит D4 для определения типа монитора (цветной или монохромный). Положение этих переключателей может быть считано из оперативной памяти по адресу 0000:0488h:

Биты Описание
D3-D0 Биты, соответствующие переключателям. Если бит установлен в единицу, то соответствующий переключатель находится в положении ON. Если бит сброшен в ноль, то переключатель находится в положении OFF
D7-D4 Не используются

Регистр состояния 1
(Input Status Register 1 - ISR0)

Регистр позволяет получить различную информацию о состоянии видеоадаптера. Для видеоадаптера CGA содержимое регистра можно считать через порт, имеющий адрес 3DAh. Для адаптеров EGA, VGA и SVGA данный регистр, имеет адрес 3BAh в монохромных режимах и адрес 3DAh - в цветных. Регистр состояния 1 доступен только для чтения.

Приведем формат регистра состояния 1:

Биты Описание
D0 Бит разрешения отображения
D1 Бит триггера светового пера
D2 Бит переключателя светового пера
D3 Бит обратного вертикального хода
D5-D4 Диагностические биты
D7-D6 Биты не используются

D7, D6 Биты не используются

D5, D4 Диагностические биты позволяют проверить два из шести цветовых выходных сигналов передаваемых монитору (для видеоадаптера EGA). Для выбора проверяемых сигналов используют регистр разрешения цветового слоя контроллера атрибутов:

Регистр разрешения цветового слоя Регистр состояния 1
D5 D4 D5 D4
0 0 Красный Синий
0 1 Второй красный Второй зеленый
1 0 Второй синий Зеленый
1 1 Не используется Не используется

Следующая таблица показывает, как можно считать два из восьми цветовых сигналов, вырабатываемых контроллером атрибутов видеоадаптера VGA:

Регистр разрешения цветового слоя Регистр состояния 1
D5 D4 D5 D4
0 0 P2 P0
0 1 P5 P4
1 0 P3 P1
1 1 P7 P6

Биты D5 и D4 позволяют прочитать содержимое регистров таблицы цветовой палитры видеоадаптера EGA. Следует отметить, что некоторые адаптеры, совместимые с EGA, не поддерживают эти биты. Поэтому их использование может наложить ограничения на работу программы.

D3 Бит обратного вертикального хода луча. Бит принимает значение 1 в течение обратного вертикального хода луча по кадру. Данный бит также установлен в случае, если разрешено прерывание IRQ2, и любое устройство компьютера выдает запрос на это прерывание.

Биты D2 и D1 управляют световым пером. Видеоадаптеры VGA и SVGA не поддерживают световое перо, поэтому биты D2 и D1 не используются.

D2 Бит переключателя светового пера. Если переключатель светового пера находится в положении ON (включено), то бит D2 равен единице. Если переключатель находится в положении OFF (выключено), то бит D2 равен нулю.

D1 Бит триггера светового пера. Бит равен единице, если триггер светового пера установлен. Сброс бита происходит при записи нуля через порт с адресом 3BBh для монохромного режима, или через порт 3DBh - для цветного режима.

D0 Бит разрешения отображения. Бит принимает значение единицы во время интервала активности монитора (когда адаптер читает данные из видеопамяти), и равен нулю во время горизонтального и вертикального обратного хода луча.

Во многих случаях возникает необходимость синхронизовать программирование регистров видеоадаптера с периодом вертикального или горизонтального обратного хода луча. Этого можно достичь периодической проверкой регистра состояния 1.

Листинг 4.2 содержит программу, использующую функцию WaitVert для определения частоты кадров. Функция WaitVert задерживает выполнение программы до начала обратного вертикального хода луча.

Листинг 4.2. Файл RASTR.C


// Программа определения частоты кадров

#include  <time.h>
#include  <stdio.h>
#include  <bios.h>

#define   NUM  200

// Описания функций. Смотри файл DISPLAY.ASM
void		__pascal __far WaitVert(void);
unsigned	__pascal __far HorByVer(void);

//===========================================================
// Главная функция
//===========================================================
void main() {

	time_t	t_start, t_end;
	int		i;
	float		fr;
	unsigned	vert_fr;

	// Определяем начальное время
	t_start = clock();

	// Ожидаем исполнения NUM вертикальных разверток
	for(i = 0; i < NUM; i++) WaitVert();

	// Определяем конечное время
	t_end = clock();

	// Вычисляем частоту кадров
	fr = NUM/(((float)t_end - t_start) / CLK_TCK);

	printf( "\nЧастота кадров = %4.1f \n", (float)fr );
}

Исходный текст функции WaitVert представлен в листинге 4.3. Функция WaitVert периодически проверяет регистр состояния 1 (ISR1), ожидая начало обратного вертикального хода луча по экрану монитора.

Листинг 4.3. Файл DISPLAY.ASM


TITLE	DISPLAY.ASM
NAME	DISPLAY
PAGE	55,132

P286
IDEAL
NOWARN BRK

SEGMENT WAIT_TEXT WORD PUBLIC 'CODE'
ASSUME	cs:WAIT_TEXT
;===========================================================
; Функция void WaitVert(void)
;===========================================================
PUBLIC	WAITVERT
PROC	WAITVERT FAR

	enter	0, 0

	mov  ax,0h
	mov  es,ax

	; Определяем адрес порта индексного регистра контроллера
	; ЭЛТ (3B4h/3D4h)
	mov  dx,es:[463h]

	; Вычисляем адрес порта регистра состояния 1 (ISR1)
	add  dl,6

	; Читаем содержимое порта регистра состояния 1
	in   al,dx

	; Тестируем бит D3 регистра состояния 1
	; бит D3 = 1 при обратном вертикальном ходе луча
	test al,8
	jz   wait_on

wait_off:

	in   al,dx

	; Тестируем бит D3
	test al,8

	; Ожидаем конец обратного вертикального хода луча
	jnz  wait_off

wait_on:

	in   al,dx
	test al,8

	; Ожидаем начало обратного вертикального хода луча
	jz   wait_on

	; +------------------------------------------------------+
	;  Здесь могут распологаться операции, которые необходимо
	;  выполнить  во время обратного  вертикального хода луча
	; +------------------------------------------------------+

	leave
	ret

	ENDP	WAITVERT

ENDS	WAIT_TEXT

END

Регистр разрешения работы системы VGA
(VGA Enable Register - VGA_ER)

Данный регистр имеет адрес 3С3h. Регистр используется только видеоадаптерами VGA и SVGA. Биты D1-D7 зарезервированы, а бит D0 управляет работой адаптера. Если бит D0 равен нулю, тогда запрещен доступ к видеопамяти и портам ввода/вывода видеоадаптера (кроме регистра VGA_ER).

Регистр сброса триггера-защелки светового пера (Light Pen Latch Reset Register - LPLRR)

В цветных режимах регистр LPLRR доступен через порт 3DBh, а в монохромных режимах через порт 3BBh. Регистр используется только видеоадаптерами CGA и EGA. Любая операция записи в регистр LPLRR сбрасывает триггер-защелку светового пера.

Регистр установки триггера-защелки светового пера (Light Pen Latch Set Register - LPLSR)

В цветных режимах регистр LPLSR доступен через порт 3DCh, а в монохромных режимах через порт 3BCh. Регистр используется только видеоадаптерами CGA и EGA. Любая операция записи в этот регистр вызывает установку триггера-защелки светового пера.

Регистры контроллера ЭЛТ

Регистры контроллера ЭЛТ управляют сигналами синхронизации, необходимыми для формирования растра, определяют формат данных на экране и форму курсора. Для видеоадаптеров CGA и EGA регистры контроллера ЭЛТ также управляют световым пером.

Большинство из регистров ЭЛТ не представляют интереса. Более того, их неправильное использование может послужить причиной физического разрушения монитора. Поэтому мы подробно рассмотрим лишь наиболее полезные и безопасные регистры контроллера. Назначение и формат ряда регистров контроллера ЭЛТ различаются для видеоадаптеров EGA, VGA, SVGA и для видеоадаптеров MDA, Hercules, CGA.

При программировании регистров контроллера ЭЛТ используется понятие одного знакоместа (characters) и времени необходимого для отображения одного символа (character clock). При вычислении значений регистров следует учесть, что ширина одного символа составляет 8 пикселов.

Растр состоит из совокупности строк развертки, следующих одна за другой. Электронный луч включается в начале каждой строки и выключается в конце. Включение и выключение электронного луча выполняется сигналом разрешения отображения (Display Enable), вырабатываемым контроллером ЭЛТ.

Когда электронный луч включен (разрешено отображение) видеоадаптер читает данные из видеопамяти и соответствующим образом модулирует интенсивность и цвет электронного луча.

После того как луч прочертит весь экран монитора справа налево, он перемещается в начало следующей строки. Контроллер ЭЛТ снова включает электронный луч, в ответ на сигнал разрешения отображения и выводит на экран следующую строку видеоинформации.

Промежуток времени между окончанием отображения видеоинформации на одной строке и началом отображения следующей строки называется горизонтальным неотображаемым интервалом. Промежуток времени отводимый для обратного хода луча меньше горизонтального неотображаемого интервала. Поэтому на правой и левой границе экрана образуются неотображаемые области.

Контроллер ЭЛТ позволяет оставить электронный луч включенным во время перемещения по не отражаемой области. При этом вокруг изображения образуется цветная рамка. Размер и цвет рамки вы можете задавать сами.

После того как электронный луч прочертит все горизонтальные линии растра, контроллер ЭЛТ отключает сигнал разрешения отображения (электронный луч гаснет) и вырабатывает сигнал вертикального обратного хода луча. Электронный луч перемещается с нижней части экрана в верхний левый угол. Продолжительность вертикального обратного хода луча меньше, чем период вертикального неотображаемого интервала. В результате в нижней и верхней части экрана возникают неотображаемые области.

Одной из основополагающих величин, определяющих разрешающую способность режимов видеоадаптера, является частота вывода пикселов на экран монитора. Эта частота определяется генератором синхросигналов видеоадаптера. Чем выше частота вывода, тем больше пикселов может уместиться на экране при известной частоте кадров и частоте строчной развертки.

Генераторы синхросигналов видеоадаптеров MDA, CGA и Hercules работают только на одной частоте. Для видеоадаптеров EGA, VGA и SVGA доступно несколько различных частот.

Старые модели мониторов могут работать только с фиксированными значениями частоты горизонтальной и вертикальной развертки. Практически все современные мониторы могут работать в некотором диапазоне частот. Поэтому они называются мультичастотными.

Видеоадаптер Режим Частота вывода пикселов, Мгц Частота горизонтальной развертки, Кгц Частота вертикальной развертки, Гц
MDA 720х350 16257 18430 50
CGA 640х200 14318 15750 60
EGA 640х200 14318 15750 60
640х350 16257 21850 60
720х350 16257 18430 50
VGA 640х400 25175 31500 70
720х400 28322 31500 70
640х480 25175 31500 60
640х350 25175 31500 70
SVGA 640х480 31500 37861 72,809
800х600 40000 37879 60,317
800х600 50000 48077 72,187
1024х768 65000 48363 60,000
1024х768 75000 56476 70,069

Чтобы вычислить, сколько пикселов помещается на каждой строке развертки разделите частоту вывода точек на частоту горизонтальной развертки. Затем разделите полученное значение на 8 и вы узнаете, сколько символов помещается в строке развертки.

Если вы самостоятельно программируете регистры ЭЛТ видеоадаптеров VGA или SVGA вы должны отнять от полученной величины число 5 (для адаптера EGA следует отнять 2) и записать результат в регистр общей длинны линии горизонтальной развертки (Horizontal Total Register - HTR).

Во время выполнения горизонтальной развертки отображаются только пикселы в рабочей области экрана. Например, для режима VGA 640х480 пикселов, на одной линии горизонтальной развертки отображается только 640 пикселов. Разделите количество пикселов отображаемых в одной строке на 8 и вы узнаете, сколько символов выводится в каждой строке. Полученное значение записывается при выборе режима работы адаптера в регистр длины отображаемой части горизонтальной развертки (Horizontal Display Enable End Register - HDER).

Вы видите, что общая длина горизонтальной развертки больше длины отображаемой части горизонтальной развертки. Разница между этими двумя значениями определяет, сколько времени отводится на обратный ход луча и на нерабочую область развертки.

Регистры начала импульса гашения луча горизонтальной развертки (Start Horizontal Blank Register - SHBR) и конца импульса гашения луча горизонтальной развертки (End Horizontal Blank Register - EHBR) определяют размер нерабочей области горизонтальной развертки.

Регистры начала горизонтального обратного хода луча (Start Horizontal Retrace Register - SHRR) и конца импульса горизонтального обратного хода луча (End Horizontal Retrace Register - EHRR) определяют момент начала и окончания горизонтального обратного хода луча.

При вычислении значений регистров SHRR и EHRR следует учитывать, что для большинства мониторов, совместимых с видеоадаптерами VGA требуется отвести на горизонтальный обратный ход луча 2-4 микросекунды. Значения регистров SHRR и EHRR, как и других регистров контроллера ЭЛТ, необходимо записать в символах. Вычислим промежуток времени, в течение которого отображается один символ. Для этого следует разделить 1 на частоту вывода точек и умножить полученное число на 8 (горизонтальный размер символа в пикселах). Если частота вывода точек составляет 25,175 Мгц, тогда на отображение одного символа затрачивается 8/25175 = 0,318 микросекунд. Отсюда вычисляем, что для горизонтального обратного хода луча достаточно времени затрачиваемого на отображение 7 (2/0,318) символов.

Выберите значение для регистра начала горизонтального обратного хода луча (SHRR) таким образом, чтобы растр был отцентрован на экране. Участки нерабочей области до и после горизонтального обратного хода луча должны иметь одинаковый размер.

Всего в строке развертки 100 символов. Из них 80 символов отводится для видимой области строки растра и 12 символов для горизонтального обратного хода луча. Остаток - 8 символов (100-80-12) относится к нерабочей области строки развертки. Значит горизонтальный обратный ход луча должен начинаться по прошествии времени, необходимого для отображения 80+8/2=84 символов.

Регистры контроллера ЭЛТ составляют самую многочисленную группу регистров видеоадаптеров. Для видеоадаптеров EGA и VGA группа содержит 24 регистра. В следующей таблице приведен список всех регистров контроллера ЭЛТ и их индексы, используемые для доступа к ним.

Индекс Регистр контроллера ЭЛТ
0 Общая длина линии горизонтальной развертки (Horizontal Total Register - HTR)
1 Длина отображаемой части горизонтальной развертки (Horizontal Display Enable End Register - HDER)
2 Начало импульса гашения луча горизонтальной развертки (Start Horizontal Blank Register - SHBR)
3 Конец импульса гашения луча горизонтальной развертки (End Horizontal Blank Register - EHBR)
4 Начало импульса горизонтального обратного хода луча (Start Horizontal Retrace Register - SHRR)
5 Конец импульса горизонтального обратного хода луча (End Horizontal Retrace Register - EHRR)
6 Количество горизонтальных линий растра (Vertical Total Register - VTR)
7 Дополнительный регистр (Overflow Register - OVR)
8 Предварительная установка горизонтальной развертки (Preset Row Scan Register - PRSR)
9 Высота символов текста (Max Scan Line Register - MSLR)
0Ah Начальная линия курсора (Cursor Start Register - CSR)
0Bh Конечная линия курсора (Cursor End Register - CER)
0Ch Старший байт начального адреса (Start Address Register - SAR, high byte)
0Dh Младший байт начального адреса (Start address Register - SAR, low byte)
0Eh Старший байт позиции курсора (Cursor Location Register - CLR, high byte)
0Fh Младший байт позиции курсора (Cursor Location Register - CLR, low byte)
10h Начало обратного вертикального хода луча (Vertical Retrace Start Register - VRSR)
11h Конец обратного вертикального хода луча (Vertical Retrace End Register - VRER)
10h Старший байт адреса светового пера (Light Pen Address Register - LPAR, high byte)
11h Младший байт адреса светового пера (Light Pen Address Register - LPAR, low byte)
12h Начало гашения вертикальной развертки (Vertical Display End Register - VDER)
13h Логическая ширина экрана (Offset Register - OFR)
14h Положение подчеркивания символа (Underline Location Register - ULR)
15h Начало импульса гашения вертикальной развертки (Start Vertical Blank Register - SVBR)
16h Конец импульса гашения вертикальной развертки (End Vertical Blank Register - EVBR)
17h Управление режимом (Mode Control Register - MCR)
18h Регистр сравнения линий (Line Compare Register - LCR)

В отличие от внешних регистров, адресация к регистрам контроллера ЭЛТ происходит через два порта. В первый порт (индексный) записывается индекс регистра, к которому осуществляется доступ, а через второй порт (порт данных) можно выполнять обмен данными (запись или чтение).

У видеоадаптеров MDA и Hercules индексный порт имеет адрес 3B4h, а порт данных - адрес 3B5h. Для CGA адреса портов другие. Индексный порт имеет адрес 3D4h, а порт данных - адрес 3D5h. Адреса портов контроллера ЭЛТ для видеоадаптеров EGA и VGA зависят от режима работы видеоадаптера (монохромный или цветной). В монохромном режиме адрес порта индексного регистра равен 3B4h, а регистра данных - 3B5h. В цветном режиме адреса соответственно равны 3D4h и 3D5h:

Видеоадаптер Адрес порта индексного регистра Адрес порта регистра данных
CGA 3D4h 3D5h
EGA, VGA, SVGA
(монохромный режим)
3B4h 3B5h
EGA, VGA, SVGA
(цветной режим)
3D4h 3D5h
MDA, Hercules 3B4h 3B5h

Так как в монохромных и цветных режимах регистры адресуются через различные порты ввода/вывода, то к компьютеру можно одновременно подключить два видеоадаптера.

Адрес порта индексного регистра записан в области переменных BIOS, по адресу 0000:0463h. Приведем фрагмент программы, определяющей адрес индексного порта контроллера ЭЛТ:


; Устанавливаем регистр ES на нулевой сегмент памяти
xor	ax,ax
mov	es,ax

; Записываем в регистр DX адрес порта индексного
; регистра контроллера ЭЛТ
mov	dx,es:[463]

Так как адреса портов индексного регистра и регистра данных контроллера ЭЛТ является смежными, то адрес порта регистра данных можно легко получить, прибавив единицу к адресу порта индексного регистра.

Общая длина линии горизонтальной развертки (Horizontal Total Register - HTR) (индекс 0)

Регистр HTR относится к группе регистров контроллера ЭЛТ, которые управляют генерацией синхросигналов монитора. Необходимость модификации данной группы регистров возникает только при программировании нестандартных режимов работы видеоадаптера.

Кроме регистров, контроллер ЭЛТ использует при генерации синхросигналов два внутренних счетчика. Счетчик числа горизонтальных знакомест экрана увеличивается при выводе очередного символа на экран (регенерация экрана) и сбрасывается, когда его значение становится равным регистру общей длины линии горизонтальной развертки. Счетчик числа горизонтальных линий развертки увеличивается после окончания обратного горизонтального хода луча и сбрасывается, когда достигает величины, хранящейся в регистре числа горизонтальных линий растра.

Регистр HTR определяет число знакомест в одной строке развертки, включая обратный ход луча и нерабочую область развертки (рамку экрана). Для видеоадаптера EGA число знакомест по горизонтали на два, а для адаптеров VGA и SVGA на пять больше, чем значение, хранящееся в регистре.

При установке режима работы видеоадаптера, BIOS загружает в регистр HTR следующие значения:

Режим 0,1,4,5,D 2,3,6,E 7, F 10
Содержимое регистра 37h 70h 60h 5Bh

Если используется улучшенный цветной монитор, то эти значения отличаются:

Режим 0,1 2,3
Содержимое регистра 2Dh 5Bh

Длина отображаемой части горизонтальной развертки (Horizontal Display Enable End Register - HDER) (индекс 1)

Регистр задает длину отображаемого участка горизонтальной развертки. Величина, записанная в регистр должна быть единицу меньше, чем количество символов в строке экрана.

При установке режима работы видеоадаптера, BIOS загружает в регистр HDER следующие значения:

Режим 0,1,4,5,D 2,3,6,7,E,F,10
Содержимое регистра 27h 4Fh

Начало импульса гашения луча горизонтальной развертки (Start Horizontal Blank Register - SHBR) (индекс 2)

Регистр используется видеоадаптерами EGA, VGA и SVGA для определения начала импульса гашения луча горизонтальной развертки.

При установке режима работы видеоадаптера, BIOS загружает в регистр SHBR следующие значения:

Режим 0,1,4,5,D 2,3 6,E 7,F 10
Содержимое регистра 2Dh 5Ch 59h 56h 53h

Если используется улучшенный цветной монитор, то эти значения отличаются:

Режим 0,1 2,3
Содержимое регистра 2Bh 53h

Конец импульса гашения луча горизонтальной развертки (End Horizontal Blank Register - EHBR) (индекс 3)

D4-D0 Конец импульса гашения луча горизонтальной развертки. Гашение луча горизонтальной развертки происходит, когда биты D4-D0 равны счетчику длины отображаемой части горизонтальной развертки.

D6-D5 Биты смещения используются в текстовых режимах, чтобы разрешить отображение символов до разрешения вывода. Если величина битов смещения слишком маленькая, то символы на левой стороне экрана могут быть потеряны, а если она слишком большая, то символы на левой стороне экрана могут дублироваться по несколько раз.

D6 D5
0  0   - нет смещения
0  1   - смещение на один символ
1  0   - смещение на два символа
1  1   - смещение на три символа

D7 Бит D7 равен единице для видеоадаптера VGA и нулю для EGA.

При установке режима работы видеоадаптера, BIOS загружает в регистр EHBR следующие значения:

Режим 0,1,4,5,D 2,3 6,E 7 F 10
Содержимое регистра 37h 2Fh 2Dh 3Ah 1Fh 17h

Если используется улучшенный цветной монитор, то эти значения отличаются:

Режим 0,1 2,3
Содержимое регистра 2Dh 37h

Начало импульса горизонтального обратного хода луча (Start Horizontal Retrace Register - SHRR) (индекс 4)

Для видеоадаптеров EGA, VGA и SVGA регистр задает момент начала импульса горизонтального обратного хода луча.

При установке режима работы видеоадаптера, BIOS загружает в регистр SHRR следующие значения:

Режим 0,1 4,5,D 2,3 6,E 7 F,10
Содержимое регистра 31h 30h 5Fh 5Eh 51h 50h

Если используется улучшенный цветной монитор, то эти значения отличаются:

Режим 0,1 2,3
Содержимое регистра 28h 51h

Конец импульса горизонтального обратного хода луча (End Horizontal Retrace Register - EHRR) (индекс 5)

D4-D0 Конец импульса горизонтального обратного хода луча. Обратный горизонтальный хода луча завершается, когда значение счетчика символов в строке становится равным битам D4-D0.

D6-D5 Смещение импульса горизонтального обратного хода луча относительно отображаемого участка горизонтальной развертки. Биты используются видеоадаптером EGA.

D6 D5
0  0   - нет смещения
0  1   - смещение на один символ
1  0   - смещение на два символа
1  1   - смещение на три символа

D7 Для адаптера EGA с объемом видеопамяти меньшим 256 Кбайт, бит D7 используется для управления горизонтальной сверткой экрана (горизонтальным панорамированием), когда слои видеопамяти сцеплены. Если бит D7 равен нулю, то после обратного хода луча первый адрес видеопамяти для обновления экрана будет четным.

Для видеоадаптеров VGA и SVGA бит D7 является пятым битом регистра конца импульса гашения луча горизонтальной развертки (EHBR).

Число горизонтальных линий растра (Vertical Total Register - VTR) (индекс 6)

Регистр определяет общее число линий горизонтальной развертки в кадре вертикальной развертки, включая гашение вертикального хода луча и обратный вертикальный ход луча.

Для видеоадаптера EGA, регистр VTR содержит девять битов. Девятый бит находится в дополнительном регистре (OVR). Регистр VTR видеоадаптеров VGA и SVGA содержит десять битов. Десятый бит, также как и девятый, расположен в дополнительном регистре (OVR).

Дополнительный регистр (Overflow Register - OVR) (индекс 7)

Многие регистры контроллера ЭЛТ, видеоадаптера EGA, имеют по девять, а для адаптеров VGA и SVGA по десять битов. Дополнительный регистр содержит биты, которые не помещаются в восьмиразрядную сетку основных регистров видеоадаптера.

D0 Бит 8 регистра числа горизонтальных линий растра (VTR).

D1 Бит 8 регистра начала гашения вертикальной развертки (VDER).

D2 Бит 8 регистра начала обратного вертикального хода луча (VRSR).

D3 Бит 8 регистра начала импульса гашения вертикальной развертки (SVBR).

D4 Бит 8 регистра сравнения линий (LCR).

D5 Бит 9 регистра количества горизонтальных линий в растре (VTR).

D6 Бит 9 регистра начала гашения вертикальной развертки (VDER).

D7 Бит 9 регистра начала обратного вертикального хода луча (VRSR).

Предварительная установка горизонтальной развертки
(Preset Row Scan Register - PRSR) (индекс 8)

Регистр позволяет в текстовых режимах выполнить плавную вертикальную свертку текста на экране монитора. В графических режимах регистр должен содержать нулевое значение.

D4-D0 Биты предварительной установки строчной развертки. Эти биты определяют номер линии развертки, начиная с которой начинают отображаться символы (рис. 8.1). Как видно из рисунка самая верхняя строка текста отображается только частично. Вы можете плавно перемешать изображение на экране увеличивая или уменьшая значение этих битов.

D6-D5 Биты управления побайтовой сверткой. Используются видеоадаптерами VGA и SVGA. Биты D6 D5 являются двумя дополнительными битами регистра горизонтального панорамирования контроллера атрибутов и позволяют сдвигать изображение на экране более чем на 8 пикселов.

D7 Не используется.

Рисунок 4.1 иллюстрирует использование регистра предварительной установки горизонтальной развертки для вертикальной свертки содержимого экрана. В левой части рисунка показано начальное состояние экрана монитора, когда биты D0-D4 регистра PRSR содержит нулевые значения. Справа представлен экран монитора после увеличения значения регистра PRSR до трех. Изображение на экране сдвигается на три пиксела вверх, в результате чего часть верхней строки пропадает.

Рисунок 4.1 Плавная свертка экрана

После установки режима работы видеоадаптера регистр PRSR содержит нулевое значение.

Высота символов текста
(Max Scan Line Register - MSLR) (индекс 9)

Регистр MSLR определяет высоту символов в пикселах. Значение регистра на единицу меньше, чем высота символов отображаемых на экране. Регистр MSLR используется только в текстовых режимах работы видеоадаптеров.

D4-D0 Биты задают высоту символа в пикселах (рис. 8.2 и 8.3).

D5 Бит 9 регистра начала импульса гашения вертикальной развертки (SVBR - индекс 15h). Используется только для видеоадаптеров VGA и SVGA.

D6 Бит 9 регистра сравнения линий (LCR индекс 18h). Используется только для видеоадаптеров VGA и SVGA.

D7 Бит управления двойным сканированием. Поддерживается только адаптерами VGA и SVGA. Если бит D7 равен единице, то в режимах, имеющих разрешение по вертикали 200 пикселов используется двойное сканирование. Это увеличивает разрешающую способность по вертикали до 400 пикселов.

Рисунок 4.2 демонстрирует использование регистра высоты символов текста. На левой половине рисунка символы шрифта имеют размер 8х8 пикселов, а регистр высоты символов содержит число семь. На правой половине рисунка, символы шрифта имеют размер 8х14, а значение регистра высоты символов текста равно тринадцати.

Рисунок 4.2 Высота символов текста 8 пикселов

Начальная линия курсора
(Cursor Start Register - CSR) (индекс 0Ah)

Регистр CSR является доступным как для чтения, так и для записи. Регистр определяет линию сканирования символа, в которой начинается курсор. Вместе с регистром конечной линии курсора (CER) регистр CSR определяет размер и форму курсора.

D4-D0 Начальная линия курсора. (Рис. 4.3).

D5 Бит гашения курсора. Реализован только для видеоадаптеров VGA и SVGA. Если бит D5 содержит единицу, тогда текстовый курсор гаснет.

D7-D6 Не используются.

При установке режима работы видеоадаптера, BIOS загружает в регистр CSR следующие значения:

Режим 0,1,2,3 4,5,6,D,E,F,10 7
Содержимое регистра 06 00 0Bh

Конечная линия курсора
(Cursor End Register - CER) (индекс 0Bh)

Этот регистр, также как и регистр CSR, является доступным для чтения и для записи. Регистр задает линию сканирования символа, в которой кончается курсор.

D4-D0 Соответствует номеру последней линии курсора для видеоадаптеров VGA и SVGA (рис. 4.3). Для видеоадаптера EGA - номеру следующей линии.

D6-D5 Отклонение курсора. Задает смещение курсора относительно позиции, определенной регистром CLR.

00 - нет отклонения
01 - отклонение вправо на один символ
10 - отклонение вправо на два символа
11 - отклонение вправо на три символа

D7 Не используется.

При установке режима работы видеоадаптера BIOS загружает в регистр конечной линии курсора следующие значения:

Режим 0,1,2,3 4,5,6,D,E,F,10 7
Содержимое регистра 07 00 0Ch

Изменяя значение регистров начальной и конечной линии курсора, можно менять его положение и размер (рис. 4.3). На левой части рисунка, приведенного ниже, регистр начальной линии курсора равен 0Ah, регистр конечной линии курсора равен 0Bh. На правой части рисунка значение регистров изменено. Регистр начальной линии равен 4, а регистр конечной линии - 5.

Рисунок 4.3 Изменение положения курсора

Следующая программа позволяет прочитать значение регистров начальной и конечной линии курсора:

Листинг 4.4. Файл GETCURS.C


#include <stdio.h>
#include <conio.h>
#include "sysp.h"			// см. листинг 3.2
#include "sysgraph.h"	// см. листинг 3.3

// Описания функций
void	main(void);
void	WriteReg(unsigned reg, unsigned char data);
unsigned char	ReadReg(unsigned reg);

// Главная функция
void main(void) {

	char           top = 0, bottom = 0;
	unsigned       crt_address;
	BIOS_VAR _far  *bios_var_ptr;

	// Получаем указатель на область переменных BIOS
	bios_var_ptr = (BIOS_VAR _far *) FP_MAKE(0x0000, 0x0410);

	// Определяем адрес индексного регистра контроллера ЭЛТ
	crt_address = bios_var_ptr->wAddrCRT;

	// Считываем значения регистров начальной и конечной линии
	// курсора

	// Выбираем регистр начальной линии курсора
	WriteReg(crt_address++, 0x0A);

	// Считываем значение регистра
	top = (unsigned char) ReadReg(crt_address--);

	// Выбираем регистр конечной линии курсора
	WriteReg(crt_address++, 0x0B);

	// Считываем значение регистра
	bottom = (unsigned char) ReadReg(crt_address);

	// Отображаем на экране значение регистров
	printf("\nРегистр начальной линии курсора содержит: %d\n"
			 "\nРегистр конечной линии курсора содержит: %d\n",
			top, bottom);

	getch();
}

Для доступа к регистрам видеоадаптера мы пользуемся функциями WriteReg и ReadReg, определенными в файле DESIGN.C (листинг 4.5).

Листинг 4.5. Файл DESIGN.C


//=========================================================
// WriteReg(unsigned reg, unsigned char data)
// Функция выводит данные в порт
//
// Параметры:
//		reg - номер порта
//		data - данные, записываемые в порт reg
//=========================================================
void WriteReg(unsigned reg, unsigned char data) {
	_asm {
		mov  dx,reg
		mov  al,data
		out  dx,al
	}
}

//=========================================================
// unsigned char ReadReg(unsigned reg)
// Функция читает данные из определенного порта
//
// Параметры:
//		reg - номер порта
//
//	Возвращаемое значение:
//		данные, считанные из порта reg
//=========================================================
unsigned char ReadReg(unsigned reg) {

	unsigned char  data;

	_asm {
		mov  dx,reg
		in   al,dx
		mov  data,al
	}
	return(data);
}

Регистры начального адреса

Это группа из двух регистров: регистр старшего байта начального адреса (Start Address Register - SAR, high byte) (индекс 0Ch) и регистр младшего байта начального адреса (Start Address Register - SAR, low byte) (индекс 0Dh).

В регистрах SAR записан адрес видеоданных, которые отображаются в верхнем левом углу экрана монитора. Регистры начального адреса можно использовать для перемещения изображения по экрану (свертки) и для переключения активной страницы видеопамяти.

Если вы желаете использовать регистры для переключения страниц видеопамяти, то в регистры SAR надо записать смещение страницы видеопамяти (относительно начала видеопамяти), которую необходимо отобразить на экране.

На рисунке 4.4 показано, как происходит свертка экрана при изменении регистров начального адреса. В верхней части рисунка регистры начального адреса содержат ноль. Видеопамять отображается на экране с начала. В нижней части значение регистров начального адреса увеличено до 77h. В этом случае видеопамять отображается на экране начиная с данных, имеющих смещение 77h от начала видеопамяти. В нижней части экрана появляется изображение, ранее не помещающееся на экране.

Рисунок 4.4 Свертка изображения на экране

Регистры начального адреса доступны для чтения и для записи. При выборе режима работы видеоадаптера регистры обнуляются.

Регистры, определяющие положение курсора

Два регистра - регистр старшего байта позиции курсора (Cursor Location Register - CLR_h, high byte) (индекс 0Eh) и регистр младшего байта позиции курсора (Cursor Location Register - CLR_l, low byte) (индекс 0Fh) определяют положение курсора на экране (рис. 4.5). Регистры доступны как для записи, так и для чтения.

Рисунок 4.5 Отображение курсора на экране

Программа CURSLOC, приведенная в листинге 4.6 переводит видеоадаптер в текстовый режим, устанавливает курсор в позицию 5 строки 10. Затем программа считывает значения регистров позиции курсора (на момент запуска программы) и отображает их на экране монитора. Вы должны получить значение 0325h (80 * 10 + 5 = 805 = 0325h).

Листинг 4.6. Файл CURSLOC.C


// Чтение регистра положения курсора

#include <stdio.h>
#include "sysp.h"
#include "sysgraph.h"

// Описания функций
void	main(void);

// Функции WriteReg и ReadReg определены в файле
// DESIGN.C. Смотри листинг 4.5
void	WriteReg(unsigned reg, unsigned char data);
unsigned char	ReadReg(unsigned reg);

// Главная функция
void main(void) {

	int				crt_port;
	unsigned char	h_pos, l_pos;
	BIOS_VAR _far	*bios_var_ptr;

	_asm {
		// Устанавливаем режим 3
		mov	ah,0
		mov	al,3
		int	10h

		//	Выбираем страницу видеоапамяти 0
		mov	ah,5
		mov	al,0
		int	10h

		// Устанавливаем курсор в положение (20,10)
		mov	ah,2
		mov	dh,10	//
		mov	dl,5	// строка 10, позиция 5:
						// CLR = 80 * 10 + 5 = 805 = 325h
		xor	bh,bh
		int	10h
	}

// Получаем указатель на область переменных видеофункций BIOS
	bios_var_ptr = (BIOS_VAR _far *) FP_MAKE(0x0000, 0x0410);

// Определяем адрес порта индексного регистра контроллера ЭЛТ
	crt_port = bios_var_ptr -> wAddrCRT;

// Выбираем старший байт регистра положения курсора
	WriteReg(crt_port, 0x0E);

// Читаем значение старшего байта регистра
	h_pos = ReadReg(crt_port + 1);

// Выбираем младший байт регистра положения курсора
	WriteReg(crt_port, 0x0F);

// Считываем значение младшего байта регистра
	l_pos = ReadReg(crt_port + 1);

// Отображаем полученные значения
	printf("\nТекущий адрес курсора %2.2X%2.2Xh\n",
		(unsigned char) h_pos, (unsigned char) l_pos );

	return;
}

Начало обратного вертикального хода луча (Vertical Retrace Start Register - VRSR) (индекс 10h)

Регистр определяет начало обратного вертикального хода луча. У видеоадаптера EGA регистр имеет 9, а для видеоадаптеров VGA и SVGA - 10 разрядов. Дополнительные биты регистра VRSR расположены в регистре OVR. Регистр VRSR доступен только для записи.

Конец обратного вертикального хода луча (Vertical Retrace End Register - VRER) (индекс 11h)

Регистр устанавливает конец обратного вертикального хода луча, а также выполняет некоторые другие функции. Данный регистр доступен только для записи.

Биты Описание
D3-D0 Конец обратного вертикального хода луча
D4 Сброс вертикального прерывания
D5 Разрешения вертикального прерывания
D6 Изменение скорости регенерации экрана (видеоадаптеры VGA и SVGA)
D7 Защита от записи (видеоадаптеры VGA и SVGA)

D7 Если бит D7 равен единице, то регистры контроллера ЭЛТ, имеющие индексы от 0 до 7, будут защищены от записи. Защита от записи позволяет решить некоторые проблемы совместимости между адаптером VGA и видеоадаптерами, построенными на основе микросхемы 6845 (например CGA).

D6 Если бит D6 равен единице, то во время обратного горизонтального хода луча будет генерироваться пять циклов регенерации видеопамяти вместо обычных трех.

D5 Если бит равен нулю, то при каждом обратном вертикальном ходе луча на линии IRQ2 будет возникать прерывание. Сигнал прерывания сбрасывается при записи нуля в бит D4 данного регистра.

D4 Запись нуля в данный бит вызывает сброс прерывания на линии IRQ2 и переустановку флага незаконченного вертикального прерывания.

D3-D0 Сигнал обратного вертикального хода луча завершается, когда значение четырех младших бита счетчика горизонтальных линий совпадает с битами D3-D0

Регистр адреса светового пера (Light Pen Address Register - LPAR)

Это 16-битовый регистр видеоадаптеров CGA и EGA, доступный только для чтения. Регистр LPAR позволяет определить положение светового пера на экране монитора. Регистр, содержащий старший байт адреса светового пера, имеет индекс 10h, а регистр, содержащий младший байт, индекс 11h.

Регистр LPAR сохраняет адрес видеопамяти, которая регенерировалась в момент включения светового пера.

Завершение отображения вертикальной развертки (Vertical Display End Register - VDER) (индекс 12h)

Регистр определяет момент, когда заканчивается видимая часть вертикальной развертки и происходит гашение луча. Регистр содержит число, на единицу меньшее, чем количество горизонтальных линий растра.

У видеоадаптера EGA регистр VDER имеет 9, а у адаптеров VGA и SVGA - 10 разрядов. Девятый и десятый биты регистра доступны через дополнительный регистр (OVR).

Логическая ширина экрана (Offset Register - OFR) (индекс 13h)

Регистр позволяет отобразить на экране больше символов в строке, чем в стандартных текстовых режимах. Например, вы можете воспользоваться регистром OFR при переводе видеоадаптера в режим отображения 132 символов в строке.

В текстовых режимах регистр содержит смещение между соседними строками экрана, заданное в 16-битных словах.

В графических режимах регистр OFR задает логическую длину (в 16-битных словах или 32-битных двойных словах) горизонтальной линии развертки. Если линия Num развертки начинается по адресу Adr, то следующая линия развертки Num+1 начинается по адресу Adr+Offset, где Offset является значением регистра OFR.

Использование регистра OFR иллюстрируется рисунком 4.6. На верхней части рисунка видеоадаптер находится в стандартном текстовом режиме с разрешением 80 символов в строке. При этом значение регистра логической ширины экрана равно 40. На нижней части рисунка представлен результат увеличения содержимого регистра до 41. Логическая ширина экрана в этом случае увеличивается до 82 символов в строке. Последние два символа каждой строки не помещаются на экране. Для их отображения надо выполнить горизонтальную свертку экрана.

Рисунок 4.6 Логическая ширина экрана

Положение подчеркивания символа (Underline Location Register - ULR) (индекс 14h)

Регистр ULR используется только в текстовых режимах. Он определяет положение подчеркивания символа. Подчеркивание представляет собой одну из линий в матрице символа. Подчеркивание отображается, если установлен атрибут подчеркивания. Подчеркивание можно запретить, записав в регистр ULR величину большую, чем высота символов.

D4-D0 Определяют положение подчеркивания символа.

D5 Для видеоадаптеров VGA и SVGA установка этого бита означает, что для каждого знакоместа счетчик адреса регенерации будет увеличиваться на 4 вместо 1.

D6 Установка для видеоадаптеров VGA и SVGA этого бита выбирает адресацию видеопамяти по двойным словам.

D7 Не используется.

Программа, приведенная ниже, использует регистры контроллера ЭЛТ для перевода видеоадаптеров EGA и VGA в нестандартный текстовый режим, имеющий разрешение по вертикали 43 строки. Данная программа переводит видеоадаптер в текстовый режим с разрешением по вертикали 43 символа и затем отображает на экране монитора 43 строки текста.

Листинг 4.7. Файл MORESTR.ASM


#include <conio.h>

// Описания функций
void	main(void);

// Функция Set43Line опреелена в файле SET43.ASM
// (листинг 4.8)
void	__pascal _far Set43Line(void);

// Главная функция
void main(void) {

	int  i;

	// Увеличиваем количество отображаемых строк текста
	Set43Line();

	// Отображаем на экране монитора несколько текстовых строк
	for(i = 0; i < 50; i++)
		 printf("Text line number %d\n", i);

	getch();
	return;
}

Основная функция программы MORESTR - функция Set43Line определена в файле SET43.ASM. Исходный текст файла помещен в листинге 4.8.

Листинг 4.8. Файл SET43.ASM


TITLE	SET43.ASM
NAME	SET43
PAGE	55,132

P286
IDEAL
NOWARN BRK

SEGMENT LINE_TEXT WORD PUBLIC 'CODE'
ASSUME	cs:LINE_TEXT

;============================================================
; void Set43Line(void)
; Переводит адаптеры EGA и VGA в режим отображения 43
; строк текста.
;============================================================

	CHAR_SIZE EQU 8

	PUBLIC	SET43LINE
	PROC	SET43LINE FAR

	enter	0, 0

	; Устанавливаем регистр es на начало оперативной памяти
	xor  ax,ax
	mov  es,ax

	; Получаем адрес порта индексного регистра контроллера ЭЛТ
	; (3B4h/3D4h), в монохромных режимах для адресации к
	; индексному регистру используется порт с адресом 3B4h,
	; а в цветных - порт 3D4h
	mov  dx,es:[463h]

	; Выбираем для обмена регистр максимальной линии
	; сканирования этот регистр задает высоту символов на
	; экране дисплея
	mov  al,9
	out  dx,al

	; Вычисляем адрес порта регистра данных контроллера ЭЛТ,
	; в монохромных режимах для адресации к регистру данных
	; используется порт с адресом 3B5h, в цветных - порт 3D5h
	inc  dx

	; Биты D4-D0, регистра максимальной линии сканирования
	; содержат число, меньшее на единицу, чем высота символов
	; в пикселах
	mov  al,CHAR_SIZE-1
	out  dx,al

	; Вычисляем адрес порта индексного регистра
	; контроллера ЭЛТ
	dec  dx

	; Выбираем для обмена регистр положения подчеркивания
	mov  al,14h
	out  dx,al

	; Вычисляем адрес порта регистра данных контроллера ЭЛТ
	inc  dx

	; Определяем положение подчеркивания символов
	mov  al,CHAR_SIZE
	out  dx,al

	; Вычисляем адрес порта индексного регистра
	; контроллера ЭЛТ
	dec  dx

	; Выбираем для обмена регистр завершения отображения
	; вертикальной развертки

	; Регистр завершения отображения вертикальной развертки
	; содержит восемь младших бит, определяющих число
	; отображаемых горизонтальных линий растра минус один
	mov  al,12h
	out  dx,al

	; Вычисляем адрес порта регистра данных контроллера ЭЛТ
	inc  dx

	; Для отображения 43 текстовых символов, при высоте
	; символов 8 пикселов, необходимо иметь 43 * 8 = 344
	; горизонтальных линий растра

	; Помещаем в регистр завершения отображения вертикальной
	; развертки младшие 8 бит числа 344

	mov  al,(43 * CHAR_SIZE - 1 - 256)
	out  dx,al

	; Устанавливаем новые значения переменных BIOS
	; Количество символов в строке равно восьмидесяти
	mov  WORD PTR es:[44Ah],80

	; Количество строк текста минус один
	mov  BYTE PTR es:[484h],(350/CHAR_SIZE)-1

	; Высота символов в пикселах
	mov  WORD PTR es:[485h],CHAR_SIZE

	; Загружаем нулевую таблицу знакогенератора набором
	; символов (размер 8х8) из ПЗУ BIOS
	mov  ax,1112h
	xor  bl,bl
	int  10h

	leave
	ret

	ENDP	SET43LINE

ENDS	LINE_TEXT

END

Начало импульса гашения вертикальной развертки (Start Vertical Blank Register - SVBR) (индекс 15h)

Регистр определяет момент гашения луча в процессе вертикальной развертки. У видеоадаптера EGA регистр имеет 9, а у видеоадаптера VGA - 10 разрядов. Девятый бит регистра SVBR расположен в дополнительном регистре (OVR). Десятый бит расположен в регистре высоты символов текста (MSLR).

Конец импульса гашения вертикальной развертки (End Vertical Blank Register - EVBR) (индекс 16h)

Сигнал гашения вертикальной развертки завершается, когда счетчик горизонтальных линий соответствует значению регистра EVBR. Для видеоадаптера EGA регистр имеет 5 разрядов, а для VGA и SVGA 8 разрядов.

Управление режимом (Mode Control Register - MCR) (индекс 17h)

Регистр содержит набор битов, управляющих контроллером ЭЛТ.

D7 Бит D7 запрещает горизонтальный и вертикальный обратный ход луча.

D6 Если бит D6 равен единице, то установлен байтовый режим, а если он равен нулю - двухбайтовый. Двухбайтовый режим поддерживает разделение данных между двумя цветовыми слоями. Видеоадаптеры VGA и SVGA дополнительно поддерживают четырехбайтовый режим (см. регистр ULR).

Биты D6 D5
00 01
MA0 MA13 MA15
MA1 MA0 MA0
MA2 MA1 MA1
MA3 MA2 MA2
MA4 MA3 MA3
MA5 MA4 MA4
MA6 MA5 MA5
MA7 MA6 MA6
MA8 MA7 MA7
MA9 MA8 MA8
MA10 MA9 MA9
MA11 MA10 MA10
MA12 MA11 MA11
MA13 MA12 MA12
MA14 MA13 MA13
MA15 MA14 MA14

Бит D5 равен нулю только для видеоадаптеров EGA с объемом видеопамяти 64 Кбайт. В этом случае происходит сцепление слоев в графических режимах с высоким разрешением.

D4 Если бит D4 равен единице, то все выходные линии контроллера ЭЛТ переводятся в третье состояние. Этот бит используется при тестировании видеоадаптера.

D3 Если бит D3 равен нулю, то счетчик адреса регенерации изображения увеличивается на единицу на каждое знакоместо экрана, а если бит равен единице, то на каждые два знакоместа.

D2 Бит D2 может использоваться для увеличения в два раза вертикальной разрешающей способности. Если бит равен нулю, то счетчик числа линий экрана увеличивается после каждого обратного горизонтального хода луча, а если бит равен единице, то после двух обратных горизонтальных ходов луча.

D1 Используется для эмуляции графических режимов видеоадаптера Hercules. Запись нуля в этот бит приводит к замещению бита D14 адресного регистра битом D1 из регистра счетчика горизонтальных линий.

D0 Используется для эмуляции графических режимов CGA. Запись нуля в этот бит приводит к выделению в видеопамяти двух областей по 8 Кбайт каждая. Одна область соответствует четным, а другая нечетным строкам экрана. Такое отображение видеопамяти достигается в результате замещения бита D13 адресного регистра битом D0 из регистра счетчика горизонтальных строк.

Регистр сравнения линий (Line Compare Register - LCR) (индекс 18h)

Позволяет разделить изображение на две независимые части. При этом одну из них можно свертывать. Содержимое другой части экрана остается на месте.

Регистр LCR используют совместно с регистром начального адреса. Когда счетчик горизонтальных линий сканирования достигает значения, записанного в регистре LCR, происходит сброс счетчика адреса регенерируемой видеопамяти в ноль. В результате экран разбивается на две части. В верхней части экрана отображаются данные, на которые указывает регистр начального адреса, а в нижней - данные, находящиеся в начале видеопамяти. Процесс разделения экрана иллюстрируется рисунком 4.7.

Рисунок 4.7 Процесс разделения экрана

Изображение в верхней части экрана можно перемещать, изменяя содержимое регистра начального адреса.

У видеоадаптера EGA регистр сравнения линий имеет 9 разрядов. Девятый бит регистра доступен через дополнительный регистр (OVR) контроллера ЭЛТ. Регистр сравнения линий видеоадаптера VGA имеет 10 разрядов. Десятый бит регистра LCR расположен в регистре MSLR.

При изменении режима работы видеоадаптера, BIOS записывает в регистр сравнения линий значение 0FFh.

Программа, представленная ниже, выводит на экран монитора 25 строк текста, а затем, после нажатия любой клавиши, разделяет изображение на две части.

Листинг 4.9. Файл SCRSPLIT.C


#include <dos.h>
#include <stdio.h>
#include <conio.h>

void	__pascal __far Split(unsigned);
void	main(void);

// Главная функция
void main(void) {

	int   i;

	for(i = 0; i < 25; i++)
			 printf("Строка номер %d.\n",i);

	getch();

// Разделяем экран по линии 200
	Split(200);

// Ожидаем нажатие на клавиши клавиатуры
	getch();

// После завершения программы значения регистров не
// восстанавливеются!
}

Для разделения изображения на экране монитора предназначена функция Split. Исходный текст этой функции представлен в листинге 4.10.

Листинг 4.10. Файл SPLIT.ASM


TITLE	SPLIT.ASM
NAME	SPLIT
PAGE	55,132

P286
IDEAL
NOWARN BRK

SEGMENT SPLIT_TEXT WORD PUBLIC 'CODE'
ASSUME	cs:SPLIT_TEXT

;===========================================================
; void Split(unsigned split_line)
; Функция разделяет экран на две части. Функция работает
; только на видеоадаптерах EGA и VGA.
; Параметр split_line определяет линию горизонтальной
; развертки, в которой происходит разделение экрана монитора
;===========================================================

split_line	EQU	[bp+6]

PUBLIC	SPLIT
PROC	SPLIT FAR

	enter	0, 0

	; Устанавливаем регистр ES на начало оперативной памяти
	xor   ax,ax
	mov   es,ax

	; Получаем адрес порта индексного регистра контроллера ЭЛТ
	; (3B4h/3D4h), в монохромных режимах для адресации к
	; индексному регистру используется порт с адресом 3B4h, а
	; в цветных - порт 3D4h
	mov   dx,es:[463h]

	; Вычисляем адрес порта регистра состояния 1, в
	; монохромных режимах для адресации к регистру состояния 1
	; используется порт с адресом 3BAh, в цветных - порт 3DAh
	add   dx,6

	; Ожидаем начало обратного вертикального хода луча
	in    al,dx
	nop

	; Если бит D3 равен единице, то происходит обратный
	; вертикальный ход луча
	test  al,8
	jz    wait_on

wait_off:

	in    al,dx
	nop
	test  al,8
	jnz    wait_off

wait_on:

	in    al,dx
	nop
	test  al,8
	jz    wait_on


	; Вычисляем адрес порта индексного регистра
	; контроллера ЭЛТ (3B4h/3D4h)
	sub   dx,6

	; Выбираем для обмена регистр сравнения линий
	mov   al,18h
	out   dx,al

	; Вычисляем адрес порта регистра данных контроллера ЭЛТ,
	; в монохромных режимах для адресации к регистру данных
	; используется порт с адресом 3B5h, а в цветных порт 3D5h
	inc   dx

	; Определяем линию горизонтальной развертки, в которой
	; происходит разделение экрана дисплея
	mov   ax,split_line

	; У видеоадаптера EGA регистр сравнения линий состоит из 9
	; бит, доступ к девятому биту происходит через
	; дополнительный регистр контроллера ЭЛТ; видеоадаптер
	; VGA имеет еще и десятый бит, расположенный в регистре
	; высоты символов текста

	; Записываем младшие 8 битов в регистр сравнения линий
	out   dx,al

	; Вычисляем адрес порта индексного регистра
	; контроллера ЭЛТ
	dec   dx

	; Вызываем функцию чтения конфигурации видеосистемы
	mov   ax,1A00h
	int   10h

	; Если после вызова функции регистр AL не равен 1Ah, то
	; используемый видеодаптер не VGA
	cmp   al,1Ah
	je    vga
	jmp   ega

vga:

	; Считываем в AL состояние дополнительнго регистра
	mov   al,7
	out   dx,al
	inc   dx
	in    al,dx

	; Модифицируем бит D4 дополнительного ргистра
	mov   bx,split_line
	mov   cl,4
	shl   bh,cl
	and   bh,00010000b

	and   al,11101111b
	or    al,bh
	out   dx,al

	; Сбрасываем бит D6 регистра высоты символов текста
	dec   dx
	mov   al,9
	out   dx,al
	inc   dx
	in    al,dx
	and   al,10111111b
	out   dx,al
	jmp   quit_split

ega:

	mov   bx,split_line
	mov   cl,4
	shl   bh,cl
	and   bh,00010000b

	cmp   dx,3B4h       ; монохромный режим?
	je    default_1Fh

	; Определяем наличие улучшенного цветного дисплея по
	; положению переключателей на плате EGA
	mov   al,es:[488h]
	and   al,0Fh

	; Положение переключателей "OFF OFF ON ON" ?
	cmp   al,3
	je    default_1Fh

	; Положение переключателей "OFF ON ON OFF" ?
	cmp   al,9
	je    default_1Fh

	; Для видиосистем с монохромным или цветным дисплеями,
	; дополнительный регистр по умолчанию содержит 11h
	or    bh,1
	jmp   set_overflow

	; Для видиосистем с улучненным цветным дисплеем или в
	; монохромных текстовых режимах дополнительный регистр по
	; умолчанию содержит 1Fh

default_1Fh:

	or    bh,0Fh

	; Устанавливаем дополнительный регистр

set_overflow:

	mov   al,07h
	out   dx,al
	inc   dx
	mov   al,bh
	out   dx,al

quit_split:

	leave
	ret 2

ENDP	SPLIT

ENDS	SPLIT_TEXT

END

Регистры синхронизатора

Синхронизатор управляет всеми временными параметрами видеоадаптера, а также разрешением и запрещением доступа к отдельным цветовым слоям видеопамяти. Синхронизатор содержит пять регистров. Их названия перечислены в таблице 4.12. У видеоадаптера EGA все пять регистров доступны только для записи, а у видеоадаптеров VGA и SVGA также и для чтения.

Индекс регистра Регистр синхронизатора
0 Регистр сброса синхронизатора (Reset Register - RR)
1 Регистр режима синхронизации (Clock Mode Register - CMR)
2 Регистр разрешения записи цветового слоя (Color Plane Write Enable Register - CPWER)
3 Регистр выбора знакогенератора (Character Generator Select Register - CGSR)
4 Регистр определения структуры памяти (Memory Mode Register - MMR)

Доступ к регистрам осуществляется через индексный порт с адресом 3C4h и через порт данных с адресом 3C5h.

Регистр сброса синхронизатора (Reset Register - RR) (индекс 0)

Если регистр переведен в состояние сброса, то все процессы видеоадаптера приостанавливаются. В результате могут быть разрушены данные в видеопамяти.

D0 Бит асинхронного сброса. После записи в этот бит нуля происходит немедленный сброс и остановка синхронизатора. В результате информация из видеопамяти может быть потеряна.

D1 Бит синхронного сброса. Нулевое значение сбрасывает и останавливает синхронизатор в конце исполняемого цикла.

D7-D2 Не используются.

Для нормальной работы видеоадаптера биты D0 и D1 должны быть равны единице. Перед доступом к регистру режима синхронизации синхронизатор должен быть переведен в состояние синхронного сброса (бит D1 равен 0).

Регистр режима синхронизации (Clock Mode Register - CMR) (индекс 1)

Регистр управляет временными циклами синхронизатора. При изменении его содержимого необходимо соблюдать осторожность. Меняя отдельные биты регистра, оставляйте значения остальных битов без изменения.

Перед модификацией регистра CMR надо сбросить бит D1 в регистре сброса синхронизатора, переведя, таким образом, синхронизатор в режим синхронного сброса и остановки.

D0 Бит определяет ширину символов в текстовых монохромных режимах с разрешением 720 пикселов по горизонтали. Если бит D0 равен нулю, то ширина матрицы символов составляет 9 пикселов, если единице - 8 пикселов.

D1 Бит используется видеоадаптером EGA для определения числа циклов, отводимых центральному процессору, для доступа к видеопамяти. При D1 равном единице, процессор может получить три из каждых пяти циклов, а при D1 равном нулю - только один из пяти циклов. Остальные циклы используются адаптером для регенерации видеопамяти.

D4-D2 Не используются.

D5 Используется только видеоадаптерами VGA и SVGA. Если бит D5 равен единице, то экран монитора гаснет и центральный процессор получает монополию на доступ к видеопамяти. Это несколько ускоряет процесс обмена процессора с видеопамятью.

D7-D6 Не используются.

Ниже приведены значения регистра CMR, устанавливаемые BIOS при установке режима работы адаптера:

Режим 00,01,04,05,0Dh 02,03,06,0Eh 0Fh,10h
Содержимое регистра 0Bh 01 05

Регистр разрешения записи цветового слоя
(Color Plane Write Enable - CPWE) (индекс 2)

При помощи данного регистра можно запретить запись данных в любые цветовые слои видеопамяти. На рисунке 4.8 показан механизм запрещения записи данных в отдельные слои видеопамяти. Рассмотрим процесс записи данных процессором в видеопамять:

ПЕРВЫЙ ШАГ

Процессор передает видеоадаптеру данные для записи в видеопамять. Они проходят через графический контроллер и попадают в синхронизатор. Графический контроллер выполняет над данными, записываемыми в видеопамять, операции, определяемые состоянием его регистров (смотри главу "Исполнение видеоадаптером операции записи" из раздела "Графический контроллер").

ВТОРОЙ ШАГ

Синхронизатор записывает данные в видеопамять в соответствии с содержимым регистра разрешения записи цветового слоя. Регистр разрешения записи цветового слоя содержит четыре бита, управляющие записью в цветовые слои видеопамяти. Если бит этого регистра, управляющий цветовым слоем равен нулю, то данный цветовой слой не изменяется. Если бит регистра равен единице, то в данный слой видеопамяти записываются значения, поступившие от графического контроллера.

Рисунок 4.8 Разрешение записи в цветовые слои

Биты регистра разрешения записи цветового слоя имеют следующие значения:

D0 Если бит D0 равен единице, то можно записывать данные в нулевой цветовой слой.

D1 Если бит D1 равен единице, то можно записывать данные в первый цветовой слой.

D2 Если бит D2 равен единице, то можно записывать данные в второй цветовой слой.

D3 Если бит D3 равен единице, то можно записывать данные в третий цветовой слой.

D7-D4 Не используются.

При установке режима работы адаптера BIOS загружает в регистр CPWE следующие значения:

Режим 0,1,2,3,4,5,7 6 D,E,F,10
Содержимое регистра 03 01 0Fh

Регистр выбора знакогенератора (Character Generator Select Register - CGSR) (индекс 3)

Видеоадаптер EGA позволяет загрузить в память четыре, а VGA и SVGA - восемь таблиц знакогенератора, каждая из которых определяет 256 символов. Одновременно могут использоваться символы одной или двух таблиц знакогенератора. Это позволяет одновременно отображать на экране монитора до 512 различных символов.

Если разрешено одновременное использование двух различных таблиц знакогенератора, тогда бит D3 байта атрибутов указывает, какая таблица будет использоваться при отображении символа с этим атрибутом.

Регистр выбора знакогенератора определяет два активных набора символов, расположенных во втором цветовом слое, символы которых могут одновременно отображаться на экране. Данный регистр используется только в текстовых режимах.

D1-D0 Выбор первой активной таблицы знакогенератора. Эта таблица используется для вывода символа на экран, если бит D3 байта атрибутов символа содержит ноль.

D3-D2 Выбор второй активной таблицы знакогенератора. Вторая таблица используется для вывода символа на экран, если бит D3 байта атрибутов символа содержит единицу.

D4 Дополнительный бит, доступный на видеоадаптерах VGA и SVGA. Используется для выбора первой таблицы знакогенератора.

D5 Дополнительный бит, доступный на видеоадаптерах VGA и SVGA. Используется для выбора второй таблицы знакогенератора.

D7-D6 Не используются.

Для выбора активных таблиц знакогенератора надо установить биты D0-D5 в соответствии со следующей таблицей:

D5 D3 D2 Номер таблицы знакогенератора, используемой, если бит D3 байта атрибутов равен 1
D4 D1 D0 Номер таблицы знакогенератора, используемой если бит D3 байта атрибутов равен 0
0 0 0 Первая таблица знакогенератора
0 0 1 Вторая таблица знакогенератора
0 1 0 Третья таблица знакогенератора
0 1 1 Четвертая таблица знакогенератора
1 0 0 Пятая таблица знакогенератора (видеоадаптеры VGA и SVGA)
1 0 1 Шестая таблица знакогенератора (видеоадаптеры VGA и SVGA)
1 1 0 Седьмая таблица знакогенератора (видеоадаптеры VGA и SVGA)
1 1 1 Восьмая таблица знакогенератора (видеоадаптеры VGA и SVGA)

Если нужна только одна активная таблица знакогенератора, то значения битов D5 D3 D2 и битов D4 D1 D0 должны совпадать.

Регистр определения структуры памяти (Memory Mode Register - MMR) (индекс 4)

Регистр инициализируется BIOS во время выбора режима работы видеоадаптера и определяет структуру видеопамяти в этом режиме.

D0 Для видеоадаптера EGA бит D0 содержит единицу, при использовании в текстовом режиме функции выбора знакогенератора. Для адаптера VGA этот бит обычно сброшен в ноль.

D1 Для видеоадаптера EGA бит D1 равен единице, если объем видеопамяти больше 64 Кбайт.

D2 Если бит D2 содержит ноль, то доступ по четным адресам происходит к нулевому цветовому слою, а по нечетным - к первому.

D7-D3 Не используются.

При выборе режима работы адаптера, BIOS загружает в регистр CPWE следующие значения:

Режим 0,1,2,3,7 4,5 6,0Dh,0Eh 0Fh,10h
Содержимое регистра 03 02 06 00

Регистры графического контроллера

Графический контроллер поддерживает обмен данными между центральным процессором и видеопамятью. При этом он может выполнять простейшие логические операции над данными записываемыми в видеопамять. В графических режимах работы видеоадаптера графический контроллер передает данные из цветовых слоев видеопамяти контроллеру атрибутов.

Графический контроллер содержит девять регистров. Обращение к ним происходит через индексный порт с адресом 3CEh и порт данных с адресом 3CFh. Адаптер EGA имеет два дополнительных порта с адресами 3CAh и 3CCh, используемых при инициализации видеоадаптера.

Список регистров представлен в следующей таблице:

Индекс регистра Регистр графического контроллера
0 Регистр установки/сброса (Set/Reset Register - SRR)
1 Регистр разрешения установки/сброса (Set/Reset Enable Register - SRER)
2 Регистр сравнения цветов (Color Compare Register - CCR)
3 Регистр циклического сдвига и выбора функции (Data Rotate & Function Select - DRFS)
4 Регистр выбора читаемого слоя (Read Plane Select Register - RPSR)
5 Регистр режима работы (Mode Register - MDR)
6 Регистр смешанного назначения (Miscellaneous Register - MIR)
7 Регистр маскирования цветовых слоев (Color Don't Care Register - CDCR)
8 Регистр битовой маски (Bit Mask Register - BMR)

На рисунке 4.9, демонстрируются функции, выполняемые графическим контроллером. Рассмотрим функционирование графического адаптера.

Байт, записываемый центральным процессором в видеопамять (11100001b), поступает в графический контроллер. В соответствии со значением регистра циклического сдвига и выбора функции, происходит циклический сдвиг на один бит содержимого байта, записываемого в видеопамять.

Полученный результат складывается по логике ИЛИ с содержимым регистров-защелок. Вы можете применить другие булевы функции - И, ИСКЛЮЧАЮЩЕЕ ИЛИ. Используемая булева функция выбирается регистром циклического сдвига и выбора функции.

Дальнейшие преобразования происходят в соответствии со значениями регистра разрешения установки/сброса и регистра установки/сброса:

Затем в зависимости от состояния регистра битовой маски происходит запись данных в видеопамять:

Рисунок 4.9 Функции графического контроллера

Теперь рассмотрим регистры графического контроллера более подробно.

Регистр установки/сброса
(Set/Reset Register - SRR) (индекс 0)

Регистр SRR совместно с регистром разрешения установки/сброса (Set/Reset Enable Register), управляет записью данных в видеопамять. Возможности использования регистра SRR разъясняются при описании регистра разрешения установки/сброса.

Приведем формат регистра установки/сброса:

D0 Данные, записываемые в цветовой слой 0.

D1 Данные, записываемые в цветовой слой 1.

D2 Данные, записываемые в цветовой слой 2.

D3 Данные, записываемые в цветовой слой 3.

D7-D4 Зарезервировано.

По умолчанию во все биты регистра записываются нулевые значения.

Регистр разрешения установки/сброса
(Set/Reset Enable Register - SRER) (индекс 1)

Регистр разрешения установки/сброса позволяет при записи в видеопамять для одних цветовых слоев использовать данные от центрального процессора, а для других - из регистра установки/сброса (рис. 4.10).

Если биты регистра, управляющие цветовыми слоями, содержат единицы, то при выполнении операции записи, в соответствующие цветовые слои записывается информация из регистра установки/сброса. В остальные слои видеопамяти заносятся данные процессора.

Теперь приведем формат регистра разрешения установки/сброса:

D0 Разрешение использования данных из регистра установки/сброса для цветового слоя 0.

D1 Разрешение использования данных из регистра установки/сброса для цветового слоя 1.

D2 Разрешение использования данных из регистра установки/сброса для цветового слоя 2.

D3 Разрешение использования данных из регистра установки/сброса для цветового слоя 3.

D7-D4 Зарезервировано.

По умолчанию во все биты регистра записываются нулевые значения.

Заметим, что возможность использования регистров установки/сброса можно реализовать только в нулевом режиме записи. Режим записи устанавливается регистром режима работы графического контроллера (Mode Register, индекс 5). В нулевом режиме записи, если запрещено выполнение операции маскирования пикселов (регистр битовой маски содержит значение 0FFh), то каждый байт, записываемый процессором в видеопамять определяет 8 пикселов в одном или нескольких цветовых слоях.

Рассмотрим на рисунке 4.10 применение регистров установки/сброса. Пусть графический контроллер находится в нулевом режиме работы, и регистр битовой маски равен 0FFh (используются только данные от процессора). В этом случае можно использовать регистры установки/сброса.

Допустим, что после преобразования данных, записываемых процессором в видеопамять, в соответствии со значением регистра циклического сдвига и выбора функций, данные имеют следующий вид:

байт 11110000b передается в третий слой видеопамяти,

байт 00000011b передается во второй слой видеопамяти,

байт 00110011b передается в первый слой видеопамяти,

байт 00110011b передается в нулевой слой видеопамяти.

Данные, записываемые в видеопамять зависят от значения регистра разрешения установки/сброса. Биты D3 и D0, регистра разрешения установки/сброса равны нулю, поэтому в третий слой и нулевой слой видеопамяти данные заносятся без изменения. Биты D2 и D1 регистра разрешения установки/сброса равны единице, значит во второй и первый слои видеопамяти записываются данные в соответствии со значением битов D2 и D1 регистра установки/сброса. То есть во второй слой записывается байт 00000000b, а в первый - 11111111b.

Рисунок 4.10 Использование регистров установки/сброса

Регистр сравнения цветов
(Color Compare Register - CCR) (индекс 2)

Регистр CCR можно использовать для поиска на экране пикселов с определенным цветом. Без использования регистра CCR за один цикл чтения видеопамяти процессор может считать данные только из одного цветового слоя. Программирование регистра CCR позволяет за один цикл чтения прочитать все четыре цветовых слоя, сравнить считанные значения с искомыми и возвратить результат.

Ниже представлен формат регистра сравнения цветов:

D0 Искомая величина для нулевого цветового слоя.

D1 Искомая величина для первого цветового слоя.

D2 Искомая величина для второго цветового слоя.

D3 Искомая величина для третьего цветового слоя.

D7-D4 Не используются.

После выполнения BIOS установки режима работы видеоадаптера все биты регистра содержат нулевые значения.

Операция поиска пикселов данного цвета иллюстрируется рисунком 4.11.

Рисунок 4.11 Использование регистра CCR

Как видно из рисунка, в случае совпадения сравниваемых битов соответствующий бит результата равен единице.

Перед использованием регистра CCR для выполнения операции поиска пикселов определенного цвета необходимо установить регистр режима работы (Mode Register - MDR) и регистр маскирования цветовых слоев (Color Don't Care Register - CDCR), описанные ниже.

Регистр циклического сдвига и выбора функции
(Data Rotate & Function Select - DRFS) (индекс 3)

Регистр 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-битовый регистр-защелка. Когда процессор начнет записывать данные в видеопамять (возможно уже по другому адресу), адаптер может комбинировать их с данными из регистров-защелок. Вид выполняемой логической операции будет зависеть от содержимого битов выбора логической функции:

D4  D3 Логическая операция
0 0 Запись не модифицированных данных
0 1 И
1 0 ИЛИ
1 1 ИСКЛЮЧАЮЩЕЕ ИЛИ

Следует отметить, что операция циклического сдвига выполняется до выполнения логических функций.

Регистр DRFS можно использовать для быстрого копирования областей видеопамяти с возможной их модификацией.

Рисунок 4.12 иллюстрирует выполнение логической операции ИЛИ. Регистр циклического сдвига и выбора функции содержит число 00010000b. После операции чтения данные из всех четырех слоев записываются в регистры-защелки. Затем выполняется операция записи. Данные процессора в соответствии с состоянием регистра циклического сдвига и выбора функции складываются по логике ИЛИ со значением регистров-защелок и помещаются в видеопамять.

Рисунок 4.12 Логические операции и операция циклического сдвига

Регистр выбора читаемого слоя
(Read Plane Select Register - RPSR) (индекс 4)

Регистр определяет номер цветового слоя видеопамяти, из которого процессор может читать данные. При выполнении операции сравнения цветов значение этого регистра безразлично.

Приведем формат регистра выбора читаемого слоя.

Биты Описание
D1-D0 Номер читаемого цветового слоя видеопамяти
D7-D2 Не используется

При установке режима работы видеоадаптера BIOS заполняет все биты регистра нулями, что соответствует нулевому цветовому слою.

Чтение центральным процессором данных из видеопамяти иллюстрируется на рисунке 4.13. На этом рисунке регистр выбора читаемого слоя разрешает чтение второго слоя видеопамяти. Таким образом, при чтении процессором данных из видеопамяти, процессор считывает данные только из второго слоя. Остальные слои видеопамяти недоступны для чтения процессором, пока вы не измените состояние регистра читаемого слоя.

Рисунок 4.13 Операция чтения видеопамяти

Регистр режима работы
(Mode Register - MDR) (индекс 5)

Регистр управляет несколькими функциями графического контроллера. В частности он управляет режимом записи в видеопамять и режимом сравнения цветов (см. регистр сравнения цветов графического контроллера).

Биты Описание
D1-D0 Режим записи
D2 Не используется
D3 Разрешение режима сравнения цветов
D4 Четный/нечетный режим
D5 Режим регистра сдвига
D6 Управление режимом VGA с 256 цветами (режим номер 13h)
D7 Не используется

Ниже подробно рассмотрены отдельные биты регистра MDR. Изменение битов D4-D7, может привести к потере изображения на экране монитора. Обычно эти биты загружаются только при установке режима работы видеоадаптера.

D1, D0 Данные биты устанавливают режим записи в видеопамять. Вы можете выбрать один из трех режимов записи:

D1 D0 Номер режима Режим записи
0 0 0 Режим непосредственной записи
0 1 1 Использование для записи регистров-защелок
1 0 2 Заполнение N-ого цветового слоя битом номер N из данных, записываемых процессором
1 1 - Не используется

Рисунок 4.14 Режим записи 0

Рисунок 4.15 Режим записи 1

Рисунок 4.16 Режим записи 2

D3 Бит D3 управляет режимом сравнения цветов (см. регистр сравнения цветов графического контроллера). Для перевода видеоадаптера в режим сравнения цветов бит D3 должен содержать единицу.

Остальные биты регистра модифицировать не рекомендуется.

D4 Бит D4 устанавливается в текстовых режимах. В этом случае доступ по четным адресам происходит к четным цветовым слоям, а по нечетным адресам - к нечетным цветовым слоям видеопамяти (см. видеопамять в текстовых режимах).

D5 Бит D5 используется в режимах видеоадаптера номер 4 и 5 для обработки видеоданных в формате "два бита на пиксел".

D6 Бит D6 используется видеоадаптерами VGA и SVGA в режиме с 256 цветами (режим 13h).

При установке режима работы видеоадаптера BIOS загружает в регистр MDR следующие значения, в зависимости от режима работы видеоадаптера:

Режим 0,1,2,3,7,F,10 4,5 6,D,E
Содержимое регистра 10h 30h 00

Регистр смешанного назначения
(Miscellaneous Register - MIR) (индекс 6)

Регистр управляет различными характеристиками видеоадаптера. В результате ошибочной модификации регистра возможна неправильная работа некоторых функций BIOS и конфликты между видеоадаптерами в системе с двумя мониторами.

D0 Бит разрешения графического режима. Бит должен содержать 1 для графического и 0 для текстового режима. В графическом режиме запрещается генерация символов и разрешается адресация к отдельным пикселам.

D1 Используется видеоадаптерами EGA, имеющими 64 Кбайт памяти. Если бит D1 установлен, то четыре слоя видеопамяти по 16 Кбайт каждый объединяются в два слоя по 32 Кбайт.

D3-D2 Биты D3 и D2 устанавливают начальный и конечный адреса, на которые отображается видеопамять адаптера EGA:

D3 D2 Адреса видеопамяти

0 0 A000:0000h-B000:FFFFh
0 1 A000:0000h-A000:FFFFh
1 0 B000:0000h-B000:7FFFh
0 1 B800:0000h-B000:FFFFh

D7-D4 Не используются.

При установке режима работы видеоадаптера BIOS загружает в регистр MIR следующие значения, в зависимости от режима работы видеоадаптера:

Режим 3 7 F 10
Содержимое регистра Eh Ah 07 05

Регистр маскирования цветовых слоев
(Color Don't Care Register - CDCR) (индекс 7)

Регистр используется в режиме сравнения цветов (см. регистр сравнения цветов - CCR). Если какие-либо биты D3-D0 содержат ноль, то при операции сравнения цветов соответствующие цветовые слои в рассмотрение не принимаются.

D0 Управление нулевым цветовым слоем.

D1 Управление первым цветовым слоем.

D2 Управление вторым цветовым слоем.

D3 Управление третьим цветовым слоем.

D7-D4 Не используются.

При установке режима работы в регистр заносятся следующие значения:

Режим 3 7 F 10
Содержимое регистра 00 00 0Fh 0Fh

Регистр битовой маски
(Bit Mask Register - BMR) (индекс 8)

Регистр управляет записью данных в видеопамять. Если бит регистра BMR содержит ноль, то соответствующий бит будет записываться в видеопамять из регистра-защелки. В противном случае данный бит поступает от центрального процессора (рис. 4.17). Регистр BMR используется только в нулевом режиме записи.

Рисунок 4.17 Использование регистра битовой маски

Напомним, что занести данные в регистр-защелку можно, если выполнить операцию чтения из видеопамяти. Во время выполнения операции чтения в каждый регистр-защелку записывается один байт из соответствующего цветового слоя видеопамяти.

По умолчанию, во всех режимах регистр BMR хранит число 0FFh.

Регистры контроллера атрибутов

Контроллер атрибутов управляет цветовыми характеристиками изображений. Контроллер атрибутов содержит двадцать один регистр. Названия регистров перечислены в следующей таблице:

Индекс Регистры контроллера атрибутов
0 - 0Fh Шестнадцать регистров цветовой палитры (Color Palette Register's - CPR)
10h Регистр управления режимом (Mode Control Register - MCR)
11h Регистр цвета рамки экрана (Screen Border Color Register - SBCR)
12h Регистр разрешения цветового слоя (Color Plane Enable Register - CPER)
13h Регистр горизонтального панорамирования (Horizontal Panning Register - HPR)
14h Регистр выбора цвета (Color Select Register - CSR)

Доступ ко всем регистрам осуществляется через единственный порт с адресом 3C0h (в отличие от предыдущих рассмотренных нами регистров). Этот порт совмещает в себе функции индексного порта и порта данных, регулируемые внутренним триггером. Триггер переключается каждый раз записи данных в порт. В зависимости от состояния триггера записываемые данные воспринимаются либо как индекс регистра, либо как данные для обмена с регистром.

Установить триггер в исходное состояние можно, выполнив чтение из порта 3BAh для монохромного режима или из порта 3DAh - для цветного режима работы видеоадаптера. После установки триггера в исходное состояние данные, записываемые в регистр 3C0h, будут восприниматься, как индекс регистра.

Регистры цветовой палитры (0-15)
(Color Palette Register's - CPR)

Четыре цветовых слоя видеоадаптера EGA позволяют закодировать 16 различных цветов, однако улучшенный цветной монитор обеспечивает возможность отображения 64 цветов.

С помощью 16 регистров цветовой палитры можно выбрать любые 16 цветов из 64 возможных. Эти цвета будут использоваться для отображения на экране.

Если к видеоадаптеру EGA подключен улучшенный цветной монитор, то каждый регистр цветовой палитры содержит шесть битов, соответствующих шести линиям управления монитора.

Цветной и монохромный мониторы имеют меньшее число линий управления и регистр цветовой палитры также имеет другой формат.

Форматы регистров цветовой палитры для различных мониторов приведены ниже:

Улучшенный цветной монитор

D0 Голубой.

D1 Зеленый.

D2 Красный.

D3 Второй голубой.

D4 Второй зеленый.

D5 Второй красный.

D7-D6 Не используются.

Цветной монитор

D0 Голубой.

D1 Зеленый.

D2 Красный.

D3 Не используется.

D4 Интенсивность.

D7-D5 Не используются.

Монохромный монитор

D2-D0 Не используются.

D3 Видео выход.

D4 Интенсивность.

D7-D5 Не используются.

Монитор VGA

D0 P0

D1 P1

D2 P2

D3 P3

D4 P4

D5 P5

D7-D6 Не используются.

Регистр управления режимом
(Mode Control Register - MCR) (индекс 10h)

Регистр управления режимом управляет контроллером атрибутов.

D0 Бит D0 содержит ноль для текстовых режимов, единицу - для графических. Бит определяет метод интерпретации атрибутов.

D1 Бит D1 определяет тип атрибутов. Для монохромных режимов он должен быть равен единице, а для режимов - нулю.

D2 Бит используется в монохромных режимах с разрешением по горизонтали 720 пикселов для расширения горизонтального размера матриц символов псевдографики с 8 до 9 пикселов. Если бит D2 равен 1, то девятый пиксел в каждой строке будет повторять восьмой. В противном случае девятый пиксел отображается цветом фона.

D3 Бит D3 управляет назначением седьмого бита в байте атрибутов. Если бит установлен, то бит D7 байта атрибутов управляет миганием символа. Если бит D3 равен нулю, то - интенсивностью фона.

D4 Не используется.

D5 Доступен только для видеоадаптеров VGA и SVGA. Совместно с регистром разделения экрана монитора (регистр контроллера ЭЛТ) бит D5 управляет горизонтальной сверткой экрана. При установке бита D5 запрещается горизонтальная свертка стационарной части экрана.

D6 Бит D6 используется только видеоадаптерами VGA и SVGA. Бит должен быть равен нулю для режима с 256 цветами (режим 13h).

D7 Доступен только для видеоадаптеров VGA и SVGA. Выбор источника сигнала для видеовыходов Р4 И Р5. Если D7 равен нулю, то линии Р4 и Р5 управляются регистрами палитры. В противном случае сигналы на линии Р4 и Р5 поступают из битов D0 и D1 регистра выбора цветов.

По умолчанию регистр содержит следующие значения:

Режим 0,1,2,3 4,5,6,D,E,10 7 F
Содержимое регистра 08 01 0Eh 0Bh

Регистр цвета рамки экрана
(Screen Border Color Register - SBCR) (индекс 11)

В текстовых режимах работы видеоадаптеров регистр SBCR определяет цвет рамки, расположенной вокруг текста. Назначение битов регистра соответствует регистрам цветовой палитры. По умолчанию регистр цвета рамки содержит нулевые значения для всех режимов работы.

Операция установки цвета рамки не работает на большинстве адаптеров EGA.

Регистр разрешения цветового слоя
(Color Plane Enable Register - CPER) (индекс 12)

D3-D0 Биты разрешения цветовых слоем. Если бит равен нулю, то данные из соответствующего цветового слоя не поступают в регистры цветовой палитры. Таким образом, достигается эффект маскирования отдельных цветовых слоев.

D5-D4 Используются вместе с диагностическими битами регистра состояния 1 для чтения регистров палитры.

D7-D6 Не используются.

При установке режима работы видеоадаптера BIOS записывает в регистр следующие значения:

Режим 0,1,2,3,7,D,E 4,5 6 F,10
Содержимое регистра 0Fh 03 03 01 05

Регистр горизонтального панорамирования
(Horizontal Panning Register - HPR) (индекс 13)

Регистр позволяет сдвинуть изображение на экране в горизонтальном направлении. При использовании регистра HPR совместно с регистром начального адреса контроллера атрибутов можно сдвигать изображение на любое количество пикселов.

Формат регистра горизонтального панорамирования представлен ниже:

D3-D0 Биты определяют величину горизонтального сдвига:

Биты Величина сдвига содержимого экрана (в пикселах)  
D3 D2 D1 D0 Монохромный текстовый режим Режим 13h Остальные режимы
0 0 0 0 8 0 0
0 0 0 1 0 - 1
0 0 1 0 1 1 2
0 0 1 1 2 - 3
0 1 0 0 3 2 4
0 1 0 1 4 - 5
0 1 1 0 5 3 6
0 1 1 1 6 - 7
1 0 0 0 7 - -
1 0 0 1 - - -
1 0 1 0 - - -
1 0 1 1 - - -
1 1 0 0 - - -
1 1 0 1 - - -
1 1 1 0 - - -
1 1 1 1 - - -

D7-D4 Не используются.

По умолчанию для всех режимов работы видеоадаптера регистр горизонтального панорамирования содержит нулевые значения для всех битов.

На рисунке 8.18 иллюстрируется операция горизонтального сдвига содержимого экрана при различных значениях регистра HPR. На левой части рисунка регистр горизонтального панорамирования содержит ноль, а на правой части рисунка значение регистра увеличено до трех. Изображение на экране сдвигается на три пиксела влево.

Рисунок 4.18 Горизонтальный сдвиг экрана

Программа SCRSPLIT позволяет перемещать содержимое экрана по горизонтали и вертикали. Исходный текст программы представлен в листинге 4.11.

Листинг 4.11. Файл SCRSPLIT.C


// Смещение содержимого экрана по горизонтали и вертикали

#include "sysgraph.h"
#include <stdio.h>
#include <stdlib.h>
#include <graph.h>
#include "sysp.h"
#include <dos.h>

void HorScroll(unsigned, unsigned);
void VerScroll(unsigned);
void SetColumn(unsigned char);

void main(void) {

	struct videoconfig vc;
	unsigned char   i,j;

	// выбираем текстовый режим работы видеоадаптера,
	// принятый по умолчанию

	_setvideomode(_DEFAULTMODE);

	// устанавливаем логическую ширину экрана в 100 символов

	SetColumn(100);

	// отображаем на экране монитора 24 строки текста

	for(i = 0; i < 24; i++)
		printf("\ntext text text");

	// производим горизонтальное смещение экрана
	// на i пикселов при каждом нажатии на клавиатуру

	for(i = 0; i < 13; i++) {
		getch();
		HorScroll(i,8);
	}

	// производим вертикальное смещение экрана
	// на i пикселов при каждом нажатии на клавиатуру


	for(i = 0; i < 13; i++) {
		getch();
		VerScroll(i);
	}
	getch();

_setvideomode(_DEFAULTMODE);
}

Сдвиг изображения на экране монитора выполняют функции HorScroll и VerScroll. Функция HorScroll сдвигает изображение в горизонтальном направлении, а функция VerScroll в вертикальном. Исходный текст функций представлен в листинге 4.12.

Листинг 4.12. Файл SPLIT.ASM


/**
*.Name	HorScroll
*
*.Title	Горизонтальный сдвиг содержимого экрана.
*
*.Descr	Функция смещает содержимое экрана влево на определенное
*		число пикселов.
*
*.Proto	void HorScroll(unsigned offset, unsigned wide)
*
*.Params	unsigned  offset - величина смещения в пикселах,
*
*		unsigned  wide   - ширина символов (8 или 9).
*
*.Return	Не используется.
*
*.Sample	scroll.c
**/
void HorScroll(unsigned offset, unsigned wide) {

	unsigned start_addr_reg, panning_reg;
	div_t res;

	res = div(offset,wide);

	start_addr_reg = res.quot;
	panning_reg = (wide == 9) ?
				((res.rem == 0) ? 8 : res.rem - 1 ) : res.rem;

	_asm {
		push	ds

; вычисляем адрес регистра состояния 1 (3BAh/3DAh)

		xor	ax,ax
		mov	es,ax
		mov	dx,es:[463h]
		add	dx,6

; ожидаем начало обратного вертикального хода луча

		in	al,dx
		nop
		nop
		test	al,08h
		jz	wait_on

	wait_off:

		in	al,dx
		nop
		nop
		test	al,08h
		jnz	wait_off

	wait_on:

		in	al,dx
		nop
		nop
		test	al,08h
		jz	wait_on

; вычисляем адрес порта индексного регистра контроллера ЭЛТ

		sub	dx,6

; выбираем для доступа младший байт регистра начального адреса

		mov	al,0Dh
		out	dx,al

; вычисляем адрес порта регистра данных контроллера ЭЛТ

		inc	dx

; устанавливаем новый начальный адрес

		mov	ax,start_addr_reg
		out	dx,al

; снова получаем адрес порта регистра состояния 1

		add	dx,5

; сбрасываем внутренний триггер контроллера атрибутов, управляющий
; адресацией его регистров

		in	al,dx
		nop
		nop

; выбираем регистр горизонтального панорамирования

		mov	dx,3C0h
		mov	al,13h
		out	dx,al

		mov	ax,panning_reg
		out	dx,al

		pop	ds
	}
}



/**
*.Name	VerScroll
*
*.Title	Вертикальный сдвиг содержимого экрана.
*
*.Descr	Функция смещает содержимое экрана вверх на определенное
*		число пикселов.
*
*.Proto	void VerScroll(unsigned offset)
*
*.Params	unsigned  offset - величина смещения в пикслах.
*
*.Return	Не используется.
*
*.Sample	scroll.c
**/
void VerScroll(unsigned offset) {

	unsigned start_addr_reg, preset_row_reg;
	div_t res;
	BIOS_VAR _far  *bios_var_ptr;


	bios_var_ptr = (BIOS_VAR _far *) FP_MAKE(0x0000, 0x0410);

	res = div(offset,bios_var_ptr -> wCharHigh);

	start_addr_reg = res.quot * (bios_var_ptr -> wColumns);
	preset_row_reg = res.rem;


	_asm {
		push	ds

; вычисляем адрес регистра состояния 1 (3BAh/3DAh)

		xor	ax,ax
		mov	es,ax
		mov	dx,es:[463h]
		add	dx,6

; ожидаем начало обратного вертикального хода луча

		in	al,dx
		nop
		nop
		test	al,08h
		jz	wait_on

	wait_off:

		in	al,dx
		nop
		nop
		test	al,08h
		jnz	wait_off

	wait_on:

		in	al,dx
		nop
		nop
		test	al,08h
		jz	wait_on

; вычисляем адрес порта индексного регистра контроллера ЭЛТ

		sub	dx,6

; модифицируем младший байт регистра начального адреса

		mov	al,0Dh
		out	dx,al
		inc	dx
		mov	ax,start_addr_reg
		out	dx,al

		dec	dx

; модифицируем старший байт регистра начального адреса

		mov	al,0Ch
		out	dx,al
		inc	dx
		mov	al,ah
		out	dx,al

; вычисляем адрес порта регистра состояния 1

		add	dx,5

; ожидаем вертикальный обратный ход луча

wait_next:

		in	al,dx
		nop
		nop
		test	al,08h
		jz	wait_next

; определяем адрес порта индексного регистра контроллера ЭЛТ

		sub	dx,6

; устанавливаем регистр предустановки линии сканирования

		mov	al,8
		out	dx,al
		mov	ax,preset_row_reg
		inc	dx
		out	dx,al

		pop	ds
	}
}


/**
*.Name	SetColumn
*
*.Title	Установка логической ширины экрана.
*
*.Descr	Функция устанавливает логическую ширину экрана.
*
*.Proto	void SetColumn(unsigned char col)
*
*.Params	unsigned char  col - логическая ширина экрана (в символах).
*
*.Return	Не используется.
*
*.Sample	scroll.c
**/
void SetColumn(unsigned char col) {

	_asm {
		xor	ax,ax
		mov	es,ax

; получаем адрес порта индексного регистра
; контроллера ЭЛТ (3B4h/3D4h)
		mov	dx,es:[463h]

; выбираем для обмена регистр логической ширины экрана

		mov	al,13h
		out	dx,al

; вычисляем адрес порта регистра данных контроллера ЭЛТ (3B5h/3D5h)

		inc	dx

; модифицируем переменную BIOS, содержащую число символов в строке

		mov	al,col
		mov	es:[44Ah],al

; регистр логической ширины экрана в текстовых режимах содержит
; смещение между соседними строками текста в словах

		shr	al,1
		out	dx,al
	}
}

Регистр выбора цвета
(Color Select Register - CSR) (индекс 14)

Регистр используется видеоадаптерами VGA и SVGA для управления цветом.

D0 Цвет Р4.

D1 Цвет Р5. Данные биты могут использоваться вместо линий Р5 и Р4 соответственно (см. регистры палитры и рис. 6.18).

D2 Цвет Р6.

D3 Цвет Р7. Биты используются контроллером атрибутов в качестве двух старших битов, передаваемых ЦАП (рис. 6.18). В режиме 13h биты D2 и D3 не используются.

D7-D4 Не используются.

Регистры цифро-аналогового преобразователя VGA

Видеоадаптеры VGA и SVGA предназначены для подключения к аналоговым мониторам, имеющим три раздельных видеовхода. Сигнал на каждом из них управляет, соответственно, интенсивностью красного, зеленого и синего цвета изображения. Аналоговое напряжение для монитора формируется из двоичной цветовой информации при помощи трех ЦАП.

Цветовая 8-битовая информация, поступающая от контроллера атрибутов (рис. 4.19), преобразуется согласно таблице цветов в три 6-битовые сигнала для трех ЦАП. Такая схема позволяет одновременно отображать на экране 256 различных цветов, каждый из которых можно отдельно выбрать из 26+6+6 = 218 = 262144 возможных цветов.

Рисунок 4.19 Схема управления цветами видеоадаптера VGA

Таблица цветов фактически является набором из 256 18-битовых регистров. Используя регистры ЦАП, можно получить доступ для чтения и для записи к каждому регистру таблицы цветов.

ЦАП видеоадаптера VGA управляется пятью регистрами, перечисленными в следующей таблице:

Адрес Регистр
3C6h Регистр маскирования пикселов (Pixel Mask Register - PMR)
3C7h Регистр состояния ЦАП (для чтения) (DAC State Register - DAC_SR)
3C7h Индекс читаемого регистра таблицы цветов (для записи) (Look-up Table Read Index Register - LTRIR)
3C8h Индекс записываемого регистра таблицы цветов (Look-up Table Write Index Register - LTWIR)
3C9h Регистр данных таблицы цветов (Look-up Table Data Register - LTDR)

Регистр маскирования пикселов
(Pixel Mask Register - PMR)

Фирма IBM в руководстве видеоадаптера VGA предупреждает, что доступ к регистру нежелателен. В противном случае могут разрушиться данные в таблице цветов.

Регистр состояния ЦАП
(DAC State Register - DAC_SR)

Регистр адресуется при помощи порта с адресом 3C7h и доступен только для чтения. Прочитав данные из регистра, можно определить, доступны регистры цветовой таблицы для чтения или же они доступны для записи.

D1-D0 Если биты D0 D1 содержат двоичное число 11b, то регистры цветовой таблицы доступны для записи, если D0 D1 содержат двоичное число 00b (шестнадцатиричное 0), то регистры цветовой таблицы доступны для чтения.

D7-D2 Не используются.

Индекс читаемого регистра таблицы цветов
(Look-up Table Read Index Register - LTRIR)

Этот индексный регистр доступен через порт 3C7h только для записи. Запись в данный регистр индекса элемента цветовой таблицы позволяет прочитать его через регистр данных цветовой таблицы.

D7-D0 Индекс регистра таблицы цветов (0-255).

Данные из регистров таблицы цветов читаются через порт 3C9h, как три 6-битовых числа. После чтения третьего числа значение индексного регистра (LTRIR) автоматически увеличивается на единицу, что позволяет прочитать всю таблицу цветов, загрузив регистр индекса только один раз.

Во время операций чтения или записи таблицы цветов прерывания должны быть запрещены.

Индекс записываемого регистра таблицы цветов
(Look-up Table Write Index Register - LTWIR)

После записи в регистр LTWIR индекса регистра таблицы цветов можно записать в него новое значение через регистр данных таблицы цветов (см. ниже).

D7-D0 Индекс регистра таблицы цветов (0-255).

Данные записываются в регистры таблицы цветов через порт 3C9h, как три 6-битовых числа. После записи третьего числа значение индексного регистра (LTWIR) автоматически увеличивается на единицу, что позволяет прочитать таблицу цветов, загрузив регистр индекса только один раз.

Регистр данных таблицы цветов
(Look-up Table Data Register - LTDR)

Регистр используется для получения доступа к регистрам таблицы цветов. Для чтения и записи одного элемента таблицы цветов необходимо три раза прочитать (записать) содержимое регистра данных. При этом каждый раз считывается (записывается) шесть очередных битов. Первые шесть битов отвечают за интенсивность красного, вторые - зеленого и третьи - синего цвета.

Нельзя прерывать цикл чтения регистров таблицы цветов, состоящий из трех операций чтения, выполнением операции записи в другой регистр таблицы и наоборот. Во время доступа к регистру LTDR прерывания должны быть запрещены. Между операциями доступа к регистрам таблицы цвета необходимо выдержать временной интервал не менее 240 наносекунд.

D5-D0 Данные для обмена с регистрами таблицы цветов.

D7-D6 Не используется.

Программа VGA256 (листинг 4.13) записывает новые значения в таблицу цветов непосредственно через регистры цифро-аналогового преобразователя VGA. На экране монитора отображается пять вертикальных полос различного цвета. Каждая полоса состоит из 64 вертикальных линий. Интенсивность цвета этих линий плавно уменьшается слева на право.

Листинг 4.13. Файл VGA256.C


#include	<stdio.h>
#include	<conio.h>
#include	"sysp.h"
#include	"sysgraph.h"
#include	<dos.h>

// Описания функций
int	main( void );
void	SetVideoMode( unsigned char );
void	Hello(void);

// Функция SetVgaDAC определена в файле DACTABLE.ASM
void __pascal __far	SetVgaDAC(unsigned, unsigned);

//===========================================================
// Главная функция
//===========================================================
int main( void )
{
	RGB	color_table[256];
	int	error, x_num, y_num;
	unsigned	i, j, iii;
	unsigned	seg_table,off_table;
	unsigned char	far *ptr;

// Записываем в массив color_table новые значения для
// регистров таблицы цветов
	for(j = 0; j < 4; j++) {
		for(i = 0; i < 64; i++) {
			(color_table[i+j*64]).red =
				(j == 0) ? i : 0;
			(color_table[i+j*64]).green =
				(j == 1) ? i : (j == 3) ? i : 0;
			(color_table[i+j*64]).blue =
				(j == 2) ? i : (j == 3) ? i : 0;
		}
	}

// Устанавливаем режим видеоадаптера номер 13h (256 цветов)
// данный режим поддерживается только VGA и Super VGA
	SetVideoMode( 0x13 );

// Определяем сегмент и смешение массива color_table
	ptr = (unsigned char far*) &color_table[0];
	seg_table = FP_SEG(ptr);
	off_table = FP_OFF(ptr);

// Загружаем новые значения в регистры таблицы цветов
	SetVgaDAC(seg_table,off_table);

// Записываем в ptr указатель на начало видеопамяти
	ptr = (unsigned char far*) (FP_MAKE(0xA000, 0x0));

// Выводим на экран вертикальные линии различного цвета,
// процессор записывает данные непосредственно в видеопамять
	for(y_num = 0; y_num < 200; y_num++) {
		for(x_num = 0; x_num < 320; x_num++) {
			*ptr = (unsigned char) x_num;
			ptr++;
		}
	}

// Ожидаем нажатие на клавишу
	getch();

// Плавно гасим изображение на экране, уменьшая значения
// регистров таблицы цветов
	for(i=0;i<320;i++){
		for(iii=0;iii<256;iii++)  {

			(color_table[iii]).red =
				((color_table[iii]).red>6) ?
				color_table[iii].red-1 : 1;

			(color_table[iii]).green =
				((color_table[iii]).green>6) ?
				color_table[iii].green-1 : 1;

			(color_table[iii]).blue =
				((color_table[iii]).blue>6) ?
				color_table[iii].blue-1 : 1;
		}
		SetVgaDAC(seg_table,off_table);
	}

// Ожидаем нажатие на клавишу
	SetVideoMode( 0x3 );
	Hello();

	return 0;
}


//===========================================================
// Функция SetVideoMode устанавливает режим работы
// видеоадаптера, заданный параметром vmode
//===========================================================
void SetVideoMode( unsigned char vmode ) {

	union  REGS    inregs, outregs;

	inregs.h.ah = 0x0;
	inregs.h.al = vmode;
	int86( 0x10, &inregs, &outregs );
}


//===========================================================
// Функция Hello выводит на экран краткую справку о программе
//===========================================================
void Hello(void) {

	printf("\nCopyright (C)Frolov G.V.,1995. "
			 "E-mail: frolov@glas.apc.org\n");
}

Функция SetVgaDAC, предназначенная для заполнения таблицы цветов, представлена в листинге 4.14.

Листинг 4.14. Файл DACTABLE.ASM

TITLE	DACTABLE.ASM
NAME	DACTABLE
PAGE	55,132

P286
IDEAL
NOWARN BRK

SEGMENT VGA_TEXT WORD PUBLIC 'CODE'
ASSUME	cs:VGA_TEXT

;============================================================
; Функция
; void SetVgaDAC(unsigned seg_table, unsigned off_table)
;============================================================

off_table	EQU	[bp+6]
seg_table	EQU	[bp+8]

	PUBLIC	SETVGADAC
	PROC	SETVGADAC FAR

	enter	0, 0

	; Сохраняем регистры DS и ES
	push  ds
	push  es

	; Устанавливаем регистр ES на начало оперативной памяти
	xor   ax,ax
	mov   es,ax

	; Получаем адрес порта индексного регистра контроллера ЭЛТ
	; (3B4h/3D4h), в монохромных режимах для адресации к
	; индексному регистру используется порт с адресом 3B4h, а
	; в цветных - порт 3D4h
	mov   dx,es:[463h]

	; Вычисляем адрес порта регистра состояния 1, в
	; монохромных режимах для адресации к регистру состояния 1
	; используется порт с адресом 3BAh, а в цветных порт 3DAh
	add   dx,6

	pop   es

	; Ожидаем начало обратного вертикального хода луча
	in    al,dx
	nop
	nop

	; Если бит D3 равен единице, то происходит обратный
	; вертикальный ход луча
	test  al,08h
	jz    wait_on

wait_off:

	in    al,dx
	nop
	nop
	test  al,08h
	jnz   wait_off

wait_on:

	in    al,dx
	nop
	nop
	test  al,08h
	jz    wait_on

	; Устанавливаем индекс первого записываемого регистра
	; таблицы цветов

	mov   dx,3C8h

	; Начинаем модифицировать таблицу цветов с первого
	; регистра

	mov   ax,1
	out   dx,al

	; Задержка

	nop
	nop

	; Устанавливаем DS:SI на массив данных, записываемых
	; в регистры таблицы цветов
	mov   ax,seg_table
	mov   ds,ax
	mov   si,off_table

	; Загружаем 256 регистров (по 3 байта на регистр)
	mov   cx,(256 * 3)

	; Выбираем регистр данных таблицы цветов (порт 3C9h)
	mov   dx,3C9h

	cld

	; Загружаем все регистры таблицы цветов

get_reg:

	lodsb
	out   dx,al
	nop
	nop
	loop  get_reg

	; Восстанавливаем регистр DS
	pop   ds

	leave
	ret 4

	ENDP	SETVGADAC

ENDS	VGA_TEXT

END

Нестандартные режимы видеоадаптера VGA

В этой главе на примере видеоадаптера VGA мы рассмотрим программирование нестандартных режимов. Так как программирование нестандартных режимов видеоадаптеров требует непосредственного доступа к его регистрам, то перед чтением этой главы вам необходимо подробно изучить назначение регистров адаптера.

Мы рассмотрим два наиболее интересных с нашей точки зрения нестандартных режимов VGA: 320х400 и 360х480 пикселов при возможности одновременного отображения 256 цветов.

Нестандартные режимы нельзя установить на обычных видеоадаптерах VGA с помощью функций BIOS. С помощью BIOS можно установить только один режим с 256-цветной палитрой - режим номер 13h (разрешение 320х200 пикселов, 256 цветов). Однако если вы воспользуетесь возможностью непосредственного программирования адаптера через регистры, то любой адаптер VGA можно перевести в эти режимы.

Программирование всех трех описанных ниже нестандартных режимов мы будем проводить в два этапа:

Такой подход к установке нестандартных режимов позволяет программировать не все регистры адаптера, а только те, которые нуждаются в изменении.

Организация видеопамяти

Режим 13h использует простую линейную организацию видеопамяти, в которой по каждому адресу видеопамяти находится один байт данных, управляющий одним пикселом. Такая организация видеопамяти хотя и облегчает программирование, но не позволяет увеличить разрешающую способность. Дело в том, что в режиме 13h адресное пространство видеопамяти ограничено 64 Кбайт, которых хватает как раз для того, чтобы получить разрешающую способность 200х320 точек при 256 цветах (200*320 = 64000). Кроме того, такая организация видеопамяти не позволяет использовать для копирования видеоданных регистры-защелки, что может существенно повысить скорость работы программ.

Исходя из вышесказанного для нашего нестандартного режима используется другая структура видеопамяти, более схожая со структурой видеопамяти режимов 10h и 12h. На рисунке 4.20 представлена структура видеопамяти используемая нами во всех описываемых нестандартных режимах:

Рисунок 4.20 Структура видеопамяти в нестандартных, 256-цветовых режимах

Как видно из рисунка, первый пиксел экрана, отображаемый в левом верхнем углу, определяется байтом со смещением 0 из нулевого цветового слоя. Второй пиксел определяется байтом со смещением 0 из первого слоя, третий пиксел - байтом со смещением 0 из второго слоя, четвертый пиксел - байтом со смещением 0 из третьего слоя. Пятый пиксел определяется байтом со смещением 1 из нулевого слоя и так далее.

Таким образом, цвет пиксела с координатами x и y определяет байт видеопамяти, который расположен со смещением (x + y * PIXEL_PER_LINE) / 4, в цветовой плоскости (x + y * PIXEL_PER_LINE) mod 4. В этой формуле константа PIXEL_PER_LINE должна определять горизонтальную разрешающую способность экрана в данном режиме.

Такая организация видеопамяти неудобна для вычисления адреса пикселов, но дает другие неоспоримые преимущества.

Во первых, в режиме с разрешением 320х400 пикселов мы можем использовать две страницы видеопамяти. Первая из них имеет нулевое смещение, а вторая смещение 8000h от начала видеопамяти. Режим с разрешением 360х480 пикселов позволяет иметь только одну страницу, но так как он использует только 172800 байт из 256 Кбайт, то неиспользуемую память можно использовать для хранения пиктограмм и шрифтов.

Во вторых, организация видеопамяти в виде отдельных цветовых слоев позволяет использовать для операций копирования и заполнения областей видеопамяти регистры-защелки. Это дает возможность одновременно копировать четыре байта, и, следовательно, значительно увеличить скорость работы программ.

Режим 320х400 пикселов, 256 цветов

Мы начнем рассмотрение нестандартных режимов с режима, имеющего разрешение 320х400 пикселов. Программирование этого режима является самым простым и безопасным, так как при его установке нам не придется изменять содержимое регистров контроллера ЭЛТ.

Как мы указывали при описании режимов видеоадаптеров, в режиме 13h используется двойное сканирование. То есть в этом режиме - 320х200 пикселов на самом деле отображается не 200, а 400 линий сканирования. Перепрограммировав несколько регистров адаптера можно перевести его в режим 320х400 пикселов.

Рассмотрим последовательность действий, необходимую для перевода видеоадаптера в нестандартный режим с разрешением 320х400 пикселов:

Приведем программу E256MRES, реализующую изложенный алгоритм. Данная программа переводит видеоадаптер в режим отображающий 256 цветов при разрешающей способности 320х400 пикселов (листинг 4.15).

Листинг 4.15. Файл E256MRES.C


#include    <conio.h>
#include    <stdlib.h>
#include    <stdio.h>
#include    <dos.h>

// Описание функций
void SetVideoMode(unsigned char);

// Следующие функции определены в файле EVGAM.ASM
void __pascal __far Set320x400Mode( void );
void __pascal __far FullScr(unsigned char);

void __pascal __far
WritePixel(unsigned, unsigned, unsigned char);

unsigned char __pascal __far
ReadPixel(unsigned, unsigned, unsigned char);

// Главная функция
void main( void ){

	unsigned	i;
	char		ch = 13;

	// Устанавливаем режим 320х400 пикселов, 256 цветов
	Set320x400Mode();

	// Загружаем регистры ЦАП VGA
	//	LoadVGA256();

	for(i = 0; i < 400; i++)
		WritePixel(160, (unsigned) i, (unsigned char)(i%256));

	for(i = 0; i < 320; i++)
		WritePixel((unsigned) i, 200, (unsigned char)(i%256));

	ch = getch();
	if( ch == 27 ) exit(1);

	for(i = 0; i < 320; i++)
		WritePixel((unsigned) i,(unsigned) i,
						(unsigned char)(i%256));

	ch = getch();

	for(i = 0; ((i < 256) && (ch != 27)); i++) {
		FullScr( (unsigned char) i );
		ch = getch();
	}


	// Возвращаемся в текстовый режим
	SetVideoMode(3);
	printf("\n   (C) Frolov G.V., 1992-1995 \n\n");
}

//===========================================================
// Функция устанавливает режим работы видеоадаптера, заданный
// параметром vmode
//===========================================================
void SetVideoMode( unsigned char vmode ) {

	union  REGS    inregs, outregs;

	inregs.h.ah = 0x0;
	inregs.h.al = vmode;
	int86( 0x10, &inregs, &outregs );
}

Основные функции, предназначенные для выбора нестандартного режима, записи и чтения пикселов, а также заполнения экрана монитора, написаны на языке ассемблера. Исходный текст этих функций содержится в листинге 4.16.

Листинг 4.16. Файл EVGAM.ASM


TITLE	EVGAM.ASM
NAME	EVGAM
PAGE	55,132

P286
IDEAL
NOWARN BRK

INCLUDE "evga.inc"

SEGMENT EVGA_TEXT WORD PUBLIC 'CODE'
ASSUME	cs:EVGA_TEXT

;============================================================
; void Set320x400Mode( void )
; Установка режима 320х400 пикселов, 256 цветов.
;============================================================
PUBLIC	SET320X400MODE
PROC	SET320X400MODE FAR

	enter	0, 0

	; Сохраняем регистр di
	push	di

	; Устанавливаем стандартный режим 13h
	; (320x200 пикселов, 256 цветов)
	mov	ax,0013h
	int	10h

	; Выбираем регистр определенияя структуры памяти
	mov	dx,SC_INDEX
	mov	al,MMR
	out	dx,al

	; Считываем значение регистра определения структуры памяти
	inc	dx
	in		al,dx

	; Сбрасываем бит D4
	and	al,11110111b

	; Устанавливаем бит D3, при этом выключается режим
	; адресации по четным и нечетным адресам к разным слоям
	; памяти
	or 	al,00000100b

	; Записываем в регистр новое значение
	out	dx,al

	; После загрузки в этот регистр нового значения структура
	; видеопамяти соответствует режимам 10h и 12h за
	; исключением того, что каждому пикселу соответствует один
	; байт видеопамяти

	; Выбираем регистр режима работы графического контроллера
	mov	dx,GC_INDEX
	mov	al,MDR
	out	dx,al

	; Считываем его значение
	inc	dx
	in 	al,dx

	; Выключаем доступ по четным адресам к четным слоям, а по
	; нечетным адресам к нечетным слоям
	and	al,11101111b
	out	dx,al

	; Выбираем регистр смешанного назначения графического
	; контроллера
	dec	dx
	mov	al,MIR
	out	dx,al

	; Считываем его значение
	inc	dx
	in 	al,dx

	; Сбрасываем бит управляющий сцеплением четных и нечетных
	; слоев
	and	al,11111101b
	out	dx,al

	; Разрешаем запись днных во все четыре цветовых слоя,
	; записывая число 0fh в регистр разрешения записи
	; цветового слоя
	mov	dx,SC_INDEX
	mov	al,CPWER
	out	dx,al

	inc	dx
	mov	al,00001111b
	out	dx,al

	; Очищаем первую страницу видеопамяти, так как установка
	; ржима 13h очищает только первые 64K

	mov	ax,VGA_SEGMENT
	mov	es,ax

	xor	di,di
	mov	ax,di

	mov	cx,8000h
	cld
	rep	stosb

	; Выбираем регистр высоты символов текста контроллера ЭЛТ
	mov	dx,CRTC_INDEX
	mov	al,MSLR
	out	dx,al

	inc	dx
	in 	al,dx

	; Устанавливаем высоту символа равную нулю
	; !!! and     al,not 1fh

	; Запрещаем двойное сканирование
	and	al,01100000b
	out	dx,al

	; Выбираем регистр положения подчеркивания символа
	dec	dx
	mov	al,ULR
	out	dx,al

	; Выключаем режим адресации видеопамяти по двойным словам
	inc	dx
	in 	al,dx
	and	al,10111111b
	out	dx,al

	; Выбираем регистр управления режимом
	dec	dx
	mov	al,MCR
	out	dx,al

	; Включаем байтовый режим адресации
	inc	dx
	in 	al,dx
	or 	al,01000000b
	out	dx,al

	pop	di

	leave
	ret

ENDP	SET320X400MODE

;============================================================
; void WritePixel(unsigned x, unsigned y,
; unsigned char color)
;
; Функция отображает на экране пиксел в заданных координатах,
; определенного цвета.
; x - x-координата пиксела (0-319),
; y - y-координата пиксела (0-399),
; color - цвет пиксела (0-255).
;============================================================
color	EQU	[bp+6]
y		EQU	[bp+8]
x		EQU	[bp+10]

PUBLIC	WRITEPIXEL
PROC	WRITEPIXEL FAR

	enter	0, 0

	push	di

	mov	cx,x
	mov	dx,y
	mov	bl,color

	mov	ax,VGA_SEGMENT
	mov	es,ax

	mov	ax,( SCREEN_WIDTH / 4 )
	mul	dx

	push	cx

	shr	cx,1
	shr	cx,1

	add	ax,cx
	mov	di,ax

	pop	cx

	and	cl,3
	mov	ah,1
	shl	ah,cl

	mov	dx,SC_INDEX
	mov	al,CPWER
	out	dx,ax

	mov	es:[di],bl

	pop	di

	leave
	ret 6


ENDP	WRITEPIXEL

;============================================================
; unsigned char ReadPixel(unsigned x, unsigned y, unsigned char color)
; Функция возвращает значение байта видеопамяти, определяющего пиксел
; с заданными координатами.
; x - x-координата пиксела (0-319),
; y - y-координата пиксела (0-399).
; Return  цвет пиксела (0-255).
;============================================================

color	EQU	[bp+6]
y		EQU	[bp+8]
x		EQU	[bp+10]

PUBLIC	READPIXEL
PROC	READPIXEL FAR

	enter	0, 0

	push	si

	mov	cx,x
	mov	dx,y

	mov	ax,VGA_SEGMENT
	mov	es,ax

	mov	ax,( SCREEN_WIDTH / 4 )
	mul	dx

	push	cx

	shr	cx,1
	shr	cx,1

	add	ax,cx
	mov	si,ax

	pop	ax

	and	al,3
	mov	ah,al

	mov	dx,GC_INDEX
	mov	al,RPSR
	out	dx,ax

	mov	al,es:[si]
	xor	ah,ah

	pop	si

	leave
	ret 6

ENDP	READPIXEL

;============================================================
; void FullScr( unsigned char color )
; Закрашивает экран заданным цветом.
; color - цвет экрана (0-255).
;============================================================

color	EQU	[bp+6]

PUBLIC	FULLSCR
PROC	FULLSCR FAR

	enter	0, 0

	;разрешаем запись данных во все четыре цветовых слоя
	push	di

	mov	dx,SC_INDEX
	mov	al,CPWER
	out	dx,al

	inc	dx
	mov	al,0fh
	out	dx,al

	mov	ax,VGA_SEGMENT
	mov	es,ax

	xor	di,di
	mov	al,color

	mov	cx,32000
	cld
	rep	stosb

	pop	di

	leave
	ret 2

ENDP FULLSCR

ENDS	EVGA_TEXT

END

Включаемый файл EVGA.INC, в котором определены различные константы для нестандартных режимов видеоадаптера, представлен в листинге 4.17.

Листинг 4.17. Файл EVGA.INC

; Сегмент видеопамяти для режима 13h
VGA_SEGMENT	EQU	0a000h

; Адрес индексного порта синхронизатора
SC_INDEX	EQU	3c4h

	; Регистр разрешения записи цветового слоя
	CPWER	EQU	2
	; Регистр определения структуры памяти
	MMR	EQU	4

; Адрес индексного порта графического контроллера
GC_INDEX	EQU	3ceh

	; Регистр выбора читаемого слоя
	RPSR	EQU	4
	; Регистр режима работы
	MDR	EQU	5
	; Регистр смешанного назначения
	MIR	EQU	6

; Адрес индексного порта контроллера ЭЛТ (цветной режим)
CRTC_INDEX	EQU	3d4h

	; Регистр высоты символов текста
	MSLR	EQU	9
	; Регистр начального адреса
	SAR_h	EQU	0ch
	; Регистр положения подчеркивания символа
	ULR	EQU	14h
	; Регистр управления режимом
	MCR	EQU	17h

; Регистр определения различных режимов работы
MOR	EQU	3c2h

; Режим 320х400 пикселов

	; Количество пикселов по вертикали
	SCREEN_HEIGHT	EQU	400
	; Количество пикселов по горизонтали
	SCREEN_WIDTH	EQU	320

; РЕЖИМ 360х480 пикселов

	; Количество пикселов по вертикали (режим 320х400)
	SCREEN_HEIGHT_H	EQU	480
	; Количество пикселов по горизонтали (режим 360х480)
	SCREEN_WIDTH_H	EQU	360

Режим 360х480 пикселов, 256 цветов

Второй нестандартный режим, который мы рассмотрим, может отображать 256 цветов при разрешающей способности 360х480 пикселов. Ниже приведена программа E256HRES, которая переводит видеоадаптер в нестандартный режим с разрешением 360х480 пикселов (листинг 4.18):

Листинг 4.18. Файл E256HRES.C


#include	<conio.h>
#include	<stdlib.h>
#include	<stdio.h>
#include	<dos.h>
#include	"vga_new.h"

// Описание функций
void main( void );
void SetVideoMode(unsigned char);

// Следующие функции определены в файле EVGAH.ASM
void __pascal __far Set360x480Mode( void );
void __pascal __far FullScrH(unsigned char);

void __pascal __far
WritePixelH(unsigned, unsigned, unsigned char);

unsigned char __pascal __far
ReadPixelH(unsigned, unsigned, unsigned char);

// Главная функция
void main( void ){

	unsigned i;
	char ch = 13;

	// Устанавливаем режим 360х480 пикселов, 256 цветов
	Set360x480Mode();

	// загружаем регистры ЦАП VGA
	//	LoadVGA256();

	for(i = 0; i < 480; i++)
		WritePixelH(180, (unsigned) i, (unsigned char)(i%256));

	for(i = 0; i < 360; i++)
		WritePixelH((unsigned) i, 240, (unsigned char)(i%256));

	ch = getch();
	if( ch == 27 ) exit(1);

	for(i = 0; i < 360; i++)
		WritePixelH((unsigned) i, (unsigned) i,
			(unsigned char) (i % 256) );

	ch = getch();

	for(i = 0; ((i < 256) && (ch != 27)); i++) {
		FullScrH( (unsigned char) i );
		ch = getch();
	}

	// Возвращаемся в текстовый режим
	SetVideoMode(3);
	printf("\n   (C) Frolov G.V., 1992\n\n");
}

//===========================================================
// Функция устанавливает режим работы видеоадаптера, заданный
// параметром vmode
//===========================================================
void SetVideoMode( unsigned char vmode ) {

	union  REGS    inregs, outregs;

	inregs.h.ah = 0x0;
	inregs.h.al = vmode;
	int86( 0x10, &inregs, &outregs );
}

Основные функции, предназначенные для выбора нестандартного режима с разрешением 360х480 пикселов, записи и чтения пикселов, а также заполнения экрана монитора, написаны на языке ассемблера. Исходный текст этих функций представлен в листинге 4.19.

Листинг 4.19. Файл EVGAH.ASM

TITLE	EVGAH.ASM
NAME	EVGAH
PAGE	55,132

P286
IDEAL
NOWARN BRK

INCLUDE "evga.inc"	// Смотри листинг 4.17

SEGMENT EVGA_TEXT WORD PUBLIC 'CODE'
ASSUME	cs:EVGA_TEXT

;============================================================
; void Set360x480Mode( void )
; Установка режима 360х480 пикселов, 256 цветов.
;============================================================

PUBLIC	SET360X480MODE
PROC	SET360X480MODE FAR

	enter	0, 0

; Устанавливаем режим 12h, чтобы очистить видеопамять
	mov	ax,12h
	int	10h

; Устанавливаем стандартный режим 13h
; (320x200 пикселов, 256 цветов)
	mov	ax,0013h
	int	10h

	; Перепрограммируем регистр определения структуры памяти:
	; запрещаем адресацию к разным слоям памяти в зависимости
	; от кратности адреса памяти четырем (бит D4 chain4)
	mov	dx,SC_INDEX
	mov	ax,0604h
	out	dx,ax

	; Производим синхронный сброс и остановку синхронизатора
	mov	ax,0100h
	out	dx,ax

	; Адресуемся к регистру определения различных режимов
	; работы
	mov	dx,MOR

	; Устанавливаем частоту кадров 60Кц
	mov	al,0e7h
	out	dx,al

	; Запускаем синхронизатор
	mov	dx,SC_INDEX
	mov	ax,0300h
	out	dx,ax

	; Выбираем регистр режима работы графического контроллера
	mov	dx,GC_INDEX
	mov	al,MDR
	out	dx,al

	; Считываем его значение
	inc	dx
	in 	al,dx

	; Выключаем доступ по четным адресам к четным слоям, а по
	; нечетным адресам к нечетным слоям
	and	al,11101111b
	out	dx,al

	; Выбираем регистр смешанного назначения графического
	; контроллера
	dec	dx
	mov	al,MIR
	out	dx,al

	; Считываем его значение
	inc	dx
	in	 al,dx

	; Сбрасываем бит управляющий сцеплением четных и нечетных
	; слоев
	and	al,11111101b
	out	dx,al

	; Выбираем регистр конца обратного вертикального хода луча
	mov	dx,3d4h
	mov	al,11h
	out	dx,al

	; Снимаем защиту от записи с регистров контроллера ЭЛТ,
	; имеющих индексы от 0 до 7
	inc	dx
	in	al,dx
	and	al,7fh
	out	dx,al

	dec	dx

	; Программируем регистры контроллера ЭЛТ, втом числе
	; регистры, определяющие временные параметры режима

	; Устанавливаем регистр общей длины линии горизонтальной
	; развертки
	mov	ax,06b00h
	out	dx,ax

	; Устанавливаем регистр длины отображаемой части
	; горизонтальной развертки
	mov	ax,05901h
	out	dx,ax

	; Устанавливаем регистр начала импульса гашения луча
	; горизонтальной развертки
	mov	ax,05a02h
	out	dx,ax

	; Устанавливаем регистр конца импульса гашения луча
	; горизонтальной развертки
	mov	ax,08e03h
	out	dx,ax

	; Устанавливаем регистр начала импульса горизонтального
	; обратного хода луча
	mov	ax,05e04h
	out	dx,ax

	; Устанавливаем регистр конца импульса горизонтального
	; обратного хода луча
	mov	ax,08a05h
	out	dx,ax

	; Устанавливаем регистр числа горизонтальных линий
	; растра
	mov	ax,0d06h
	out	dx,ax

	; Устанавливаем дополнительный регистр
	mov	ax,03e07h
	out	dx,ax

	; Устанавливаем регистр высоты символов текста
	mov	ax,04009h
	out	dx,ax

	; Устанавливаем регистр начала обратного
	; вертикального хода луча
	mov	ax,0ea10h
	out	dx,ax

	; Устанавливаем регистр конца обратного
	; вертикального хода луча
	mov	ax,0ac11h
	out	dx,ax

	; Устанавливаем регистр начала гашения вертикальной
	; развертки
	mov	ax,0df12h
	out	dx,ax

	; Устанавливаем регистр логической ширины экрана
	mov	ax,02d13h
	out	dx,ax

	; Устанавливаем регистр положения подчеркивания символа
	mov	ax,014h
	out	dx,ax

	; Устанавливаем регистр начала импульса гашения
	; вертикальной развертки
	mov	ax,0e715h
	out	dx,ax

	; Устанавливаем регистр конца импульса гашения
	; вертикальной развертки
	mov	ax,0616h
	out	dx,ax

	; Устанавливаем регистр управления режимом
	mov	ax,0e317h
	out	dx,ax

	leave
	ret

ENDP	SET360X480MODE

;============================================================
; void
; WritePixelH(unsigned x, unsigned y, unsigned char color)
; Функция отображает на экране пиксел в заданных координатах,
; определенного цвета.
; x - x-координата пиксела (0-319),
; y - y-координата пиксела (0-399),
; color - цвет пиксела (0-255).
;============================================================

color	EQU	[bp+6]
y		EQU	[bp+8]
x		EQU	[bp+10]

PUBLIC	WRITEPIXELH
PROC	WRITEPIXELH FAR

	enter	0, 0

	push	di

	mov	cx,x
	mov	dx,y
	mov	bl,color

	mov	ax,VGA_SEGMENT
	mov	es,ax

	mov	ax,( SCREEN_WIDTH_H / 4 )
	mul	dx

	push	cx

	shr	cx,1
	shr	cx,1

	add	ax,cx
	mov	di,ax

	pop	cx

	and	cl,3
	mov	ah,1
	shl	ah,cl

	mov	dx,SC_INDEX
	mov	al,CPWER
	out	dx,ax

	mov	es:[di],bl

	pop	di

	leave
	ret 6

ENDP	WRITEPIXELH

;============================================================
; unsigned char
; ReadPixelH(unsigned x, unsigned y, unsigned char color)
; Функция возвращает значение байта видеопамяти,
; определяющего пиксел с заданными координатами.
; x - x-координата пиксела (0-319),
; y - y-координата пиксела (0-399).
; Функция возвращает цвет пиксела (0-255).
;============================================================

color	EQU	[bp+6]
y		EQU	[bp+8]
x		EQU	[bp+10]

PUBLIC	READPIXELH
PROC	READPIXELH FAR

	enter	0, 0

	push	si

	mov	cx,x
	mov	dx,y

	mov	ax,VGA_SEGMENT
	mov	es,ax

	mov	ax,( SCREEN_WIDTH_H / 4 )
	mul	dx

	push	cx

	shr	cx,1
	shr	cx,1

	add	ax,cx
	mov	si,ax

	pop	ax

	and	al,3
	mov	ah,al

	mov	dx,GC_INDEX
	mov	al,RPSR
	out	dx,ax

	mov	al,es:[si]
	mov	color,al
	xor	  ah,ah

	pop	si

	leave
	ret 6

ENDP	READPIXELH

;============================================================
; void FullScrH( unsigned char color )
; Закрашивает экран заданным цветом.
; color - цвет экрана (0-255).
;============================================================

color	EQU	[bp+6]

PUBLIC	FULLSCRH
PROC	FULLSCRH FAR

	enter	0, 0

	;Разрешаем запись данных во все четыре цветовых слоя
	push	di

	;Разрешаем запись данных во все четыре цветовых слоя
	mov	dx,SC_INDEX
	mov	al,CPWER
	out	dx,al

	inc	  dx
	mov	al,0fh
	out	dx,al

	mov	ax,VGA_SEGMENT
	mov	es,ax

	xor	di,di
	mov	al,color

	mov	cx,43200
	cld
	rep	stosb

	pop	di

	leave
	ret 2

ENDP FULLSCRH

ENDS	EVGA_TEXT

END