6. Регистры видеоадаптера CGA

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

Рассмотрим совместимость видеоадаптера CGA и видеоадаптеров EGA и VGA. Видеоадаптер CGA создан на основе микросхемы Motorola 6845, а видеоадаптеры EGA и VGA используют специализированные БИС-ы. Хотя EGA и VGA имеют регистры, соответствующие регистрам CGA, некоторые из них располагаются по другим адресам и могут выполнять дополнительные функции. Например видеоадаптеры EGA и VGA могут вызывать аппаратное прерывание по линии IRQ2 в начале каждого обратного вертикального хода луча. Кроме того, в каждом новом видеоадаптере расширяется набор используемых регистров.

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

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

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

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

Ниже, в таблице 7.1, приведен список адресов регистров видеоадаптера CGA.

Адрес Регистр
3D4, Регистры контроллера ЭЛТ
3D5 (CRT Controller Register's - CRT_CR)
3D8 Регистр установки режима
3D9 Регистр установки цвета
3DA Регистр состояния (Input Status Register - ISR)
3DB Регистр очистки тригера-защелки светового пера (Clear Light Pen Latch Register- CLPLR)
3DC Установка тригера-защелки светового пера (Set Light Pen Latch Register - SLPLR)

Таблица 7.1 Карта портов ввода/вывода CGA.

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

Номер режима работы Адрес памяти
0,1,2,3,4,5,6 B000:8000-B000:FFFF

Таблица 7.2 Распределение памяти в разных режимах.

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

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

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

Для видеоадаптеров, построенных на основе микросхемы Motorola 6845 - MDA, CGA и Hercules, контроллер ЭЛТ содержит 18 регистров. В таблице 7.3 приведен список всех регистров контроллера ЭЛТ и их индексы, используемые для доступа к ним.

Индекс Регистр контроллера ЭЛТ
0 общая длина линии горизонтальной развертки (Horizontal Total Register - HTR)
1 длина отображаемой части горизонтальной развертки (Horizontal Displayed - HDR)
2 положение горизонтальной синхронизации (Horizontal Sync Position - HSR)
3 ширина горизонтального синхросигнала (Horizontal Sync Pulse Width Register - HSPWR)
4 число горизонтальных линий растра (Vertical Total Register - VTR)
5 выравнивание ратстра (Vertical Total Adjust Register - VTAR)
6 длина отображаемой части вертикальной развертки (Vertical Displayed - VDR)
7 положение вертикальной синхронизации (Vertical Sync Position Register - VSPR)
8 режим соединения (Interlase Mode Register - IMR)
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 старший байт адреса светового пера (Light Pen Address Register - LPAR, high byte)
11h младший байт адреса светового пера (Light Pen Address Register - LPAR, low byte)

Таблица 7.3 Регистры контроллеров ЭЛТ, построенных на основе микросхемы Motorola 6845 или ее аналогов.

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

Учтите, что у видеоадаптера CGA большинство регистров контроллера ЭЛТ являются доступными только для записи. Только регистры SAR и CLR доступны как для записи, так и для чтения.

У видеоадаптеров MDA и Hercules индексный порт имеет адрес 3B4h, а порт данных - адрес 3B5h. Для CGA адреса портов другие. Индексный порт имеет адрес 3D4h, а порт данных - адрес 3D5h.

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

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

; устанавливаем es на нулевой сегмент

xor   ax,ax
mov   es,ax

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

mov   dx,es:[463h]

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

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

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

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

Для CGA количество знакомест по горизонтали будет на одно больше, чем значение, записанное в регистре.

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

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

Положение горизонтальной синхронизации (Horizontal Sync Position - SHBR) (индекс 2)

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

Ширина горизонтального синхросигнала (Horizontal Sync Pulse Width Register - HSPWR) (индекс 3)

Для видеоадаптеров MDA, CGA и Hercules регистр определяет продолжительность обратного хода луча в символах.

Число горизонтальных линий растра (VTR) (индекс 4)

Определяет число текстовых строк в растре.

Выравнивание растра (Vertical Total Adjust Register - VTAR) (индекс 5)

Определяет количество текстовых строк в растре, отведенных под рамку экрана.

Длина отображаемой части вертикальной развертки (Vertical Displayed - VDR) (индекс 6)

Регистр CGA, задающий число отображаемых текстовых строк.

Положение вертикальной синхронизации (Vertical Sync Position Register - VSPR) (индекс 7)

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

Режим соединения (Interlase Mode Register - IMR) (индекс 8)

Регистр CGA. Биты D4 и D5 задают режим соединения. Биты D6 и D7 определяют отклонение экрана. Регистр всегда содержит 2.

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

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

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

Рисунок 7.1 Использование регистра высоты символов текста.

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

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

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

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

Режим                0,1,2,3            4,5,6

Содержимое регистра  6                  0

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

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

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

Режим 0,1,2,3 4,5,6
Содержимое регистра 7 0

Изменяя значение регистров начальной и конечной линии курсора можно менять его положение и размер.

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

// изменение размеров курсора

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

void main(void) {

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

   // получаем указатель на область переменных видеофункций BIOS

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

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

   crt_address = bios_var_ptr->crt_address;

   printf("Введите верхнюю границу курсора:");
   scanf("%d", &top);
   printf("Введите нижнюю границу курсора:");
   scanf("%d", &bottom);

   // изменение формы курсора

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

   WriteReg(crt_address++, 0x0A);

   // записываем в регистр значение переменной top

   WriteReg(crt_address--, (unsigned char) top);

   // выбираем регистр конечной линии курсора

   WriteReg(crt_address++, 0x0B);

   // записываем в регистр значение переменной bottom

   WriteReg(crt_address, (unsigned char)bottom);

   getch();
}

Данная программа, а также часть программ, приведенных ниже, использует для доступа к регистрам видеоадаптера функции ReadReg и WriteReg:

/**
*.Name   WriteReg
*
*.Title   Запись в порт.
*
*.Descr   Функция выводит данные в порт.
*
*.Proto   WriteReg(unsigned reg, unsigned char data)
*
*.Params   unsigned  reg - номер регистра,
*
*      unsigned char  data - данные, записываемые в регистр.
*
*.Return   Не ипользуется.
*
*.Sample   get_curs.c
**/

WriteReg(unsigned reg, unsigned char data) {
   _asm {
      mov   dx,reg
      mov   al,data
      out   dx,al
   }
}


/**
*.Name   ReadReg
*
*.Title   Чтение регистра.
*
*.Descr   Функция читает данные из определенного порта.
*
*.Proto   unsigned char ReadReg(unsigned reg)
*
*.Params   unsigned  reg - номер регистра.
*
*.Return   считанные данные.
*
*.Sample   get_curs.c
**/
unsigned char ReadReg(unsigned reg) {

   unsigned char  data;

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

Вместо этих функций для доступа к регистрам можно использовать функции inp и outp, из стандартных библиотек трансляторов Microsoft Quick C 2.5 и C 6.0.

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

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

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

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

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

Рисунок 7.2 Использование регистров начального адреса.

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

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

Это единственные регистры видеоадаптера CGA, доступные как для записи, так и для чтения.

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

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

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

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


void main(void) {

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


   // получаем указатель на область переменных видеофункций BIOS

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

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

   crt_port = bios_var_ptr -> crt_address;

   // выбираем старший байт регистра положения курсора

   WriteReg(crt_port, 0x0E);

   // считываем значение старшего байта регистра положения курсора

   h_pos = ReadReg(crt_port + 1);

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

   WriteReg(crt_port, 0x0F);

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

   l_pos = ReadReg(crt_port + 1);

   printf("\nТекущий адрес курсора %X:%X\n",
            (unsigned char) h_pos, (unsigned char) l_pos );
}

Регистр адреса светового пера (LPAR)

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

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

6.3. Регистр выбора режима. (Mode Select Register)

Этот регистр, доступный для записи через порт 3D8h, используется видеоадаптером CGA, для установки режима работы.

6.4. Регистр выбора цвета. (Color Select Register)

Этот регистр, доступный для записи через порт 3D9h, используется видеоадаптером CGA для установки цвета рамки экрана и установки цветовой палитры. Цвет рамки может быть выбран из 16 возможных цветов. А цветовая палитра устанавливается либо стандартной, либо дополнительной.

Для режимов 4 и 5 цвет рамки соответствует цвету фона (пикселы со значением 0), а для режима 6 - пикселам со значением 1.

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

Регистр позволяет получить различную информацию о состоянии видеоадаптера. Содержимое регистраможно прочитать через порт, имеющий адрес 3DAh. Регистр состояния доступен только для чтения.

Регистр состояния имеет следующий формат:

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

Для устранения "снега" на видеоадаптере CGA, возникает необходимость синхронизовать доступ процессора к видеопамяти с периодом вертикального или горизонтального обратного хода луча. Этого можно достичь тестированием данного регистра.

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

Доступ к регистру производится через порт 3DBh. Любая операция записи (OUT) в этот регистр сбрасывает триггер-защелку светового пера.

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

Доступ к регистру производится через порт 3DCh. Любая операция записи (OUT) в этот регистр вызывает установку триггера-защелки светового пера.