Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Программирование видеоадаптеров CGA, EGA и VGA

© Александр Фролов, Григорий Фролов
Том 3, М.: Диалог-МИФИ, 1992, 287 стр.

[Назад] [Содеожание] [Дальше]

5.2. Видеопамять

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

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

Для операции чтения в каждый момент времени может быть разрешен только один цветовой слой. Читаемый слой определяется регистром выбора читаемого цветового слоя.

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

Текстовый режим

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

Стандартные текстовые режимы работы видеоадаптеров позволяют вывести на экран 25 строк по 40 или 80 символов. Если перепрограммировать некоторые регистры видеоадаптера, то можно увеличить число отображаемых строк для EGA до 43, а для VGA до 50.

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

Рисунок 6.3 Структура видеопамяти в текстовых режимах.

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

Данная таблица знакогенератора хранится во втором слое видеопамяти:

Рисунок 6.4 Преобразование кода ASCII в образ символа на экране.

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

Рисунок 6.5 Отображение цветовых слоев.

Ниже приведен дамп видеопамяти в текстовом режиме с разрешением 80х25 символов:

Адрес      0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F    0123456789ABCDEF

B800:0000  91 07 E2 07 E0 07 AE 07-AA 07 A0 07 20 07 AD 07   С.т.р.о.к.а. .н.
B800:0010  AE 07 AC 07 A5 07 E0 07-20 07 30 07 20 07 20 07   о.м.е.р. .0. . .
B800:0020  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:0030  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:0040  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:0050  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:0060  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:0070  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:0080  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:0090  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .

B800:00A0  91 07 E2 07 E0 07 AE 07-AA 07 A0 07 20 07 AD 07   С.т.р.о.к.а. .н.
B800:00B0  AE 07 AC 07 A5 07 E0 07-20 07 31 07 20 07 20 07   о.м.е.р. .1. . .
B800:00C0  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:00D0  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:00E0  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:00F0  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:0100  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:0110  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:0120  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .
B800:0130  20 07 20 07 20 07 20 07-20 07 20 07 20 07 20 07    . . . . . . . .

Из этого дампа видно, что байты кодов символов из нулевого цветового слоя видеопамяти чередуются с байтами атрибутов символов из первого цветового слоя. Байты кодов символов расположены по четным адресам, а байты атрибутов, которые для данного участка видеопамяти имеют значение 07h - по нечетным.

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

Программа предназначена для копирования содержимого видеобуфера в файл. Запись в файл активизируется при нажатии комбинации клавиш Ctrl+PrtSc. После каждой записи имя файла изменяется.

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

При нажатии комбинации клавиш Ctrl+PrtSc вызывается функция write_buf. Функция write_buf определяет текущий номер видеорежима а также такие его параметры как число символов в строке и количество строк на экране. Эти параметры считыватся из области данных видеофункций BIOS. Определяется также адрес начала видеопамяти и смещение относительно нее области, отображаемой на экране. Далее, если видеоадаптер находится в текстовом режиме мы записываем данные из видеопамяти в файл. При этом записывается только каждый второй байт, так как в видеопамяти байты символов чередуются с байтами атрибутов. Естественно информация о цвете символов при этом теряется.

Подробное описание области данных видеофункций BIOS и регистра начального адреса контроллера ЭЛТ вы найдете в следующих главах книги.

Итак, текст программы:

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

// файл sysp.h приведен в приложении
#include "sysp.h"       


// Выключаем проверку стека и указателей

#pragma check_stack( off )
#pragma check_pointer( off )

// Макро для подачи звукового сигнала

#define BEEP() _asm { \
               _asm xor  bx, bx    \
               _asm mov  ax, 0E07h \
               _asm int  10h       \
            }

// Указатели на старые обработчики прерываний

void (_interrupt _far *old8)(void);  // Таймер
void (_interrupt _far *old9)(void);  // Клавиатура
void (_interrupt _far *old28)(void); // Занятость DOS
void (_interrupt _far *old2f)(void); // Мультиплексор

// Новые обработчики прерываний

void _interrupt _far new8(void);
void _interrupt _far new9(void);
void _interrupt _far new28(void);
void _interrupt _far new2f(unsigned _es, unsigned _ds,
                 unsigned _di, unsigned _si,
                 unsigned _bp, unsigned _sp,
                 unsigned _bx, unsigned _dx,
                 unsigned _cx, unsigned _ax,
                 unsigned _ip, unsigned _cs,
                 unsigned flags);

int iniflag; // Флаг запроса на вывод экрана в файл
int outflag; // Флаг начала вывода в файл
int name_counter; // Номер текущего выводимого файла
char _far *crit;  // Адрес флага критической секции DOS


// =======================================

void main(void);
void main(void) {

    union REGS inregs, outregs;
    struct SREGS segregs;

    unsigned size; // Размер резидентной части
                   // TSR-программы

   // Вызываем прерывание мультиплексора с AX = FF00
   // Если программа GRAB уже запускалась, то новый
   // обработчик прерывания мультиплексора вернет
   // в регистре AX значение 00FF.
   // Таким способом мы избегаем повторного изменения
   // содержимого векторной таблицы прерываний.

   inregs.x.ax = 0xff00;
   int86(0x2f, &inregs, &outregs);

   if(outregs.x.ax == 0x00ff) {
      printf("\nПрограмма GRAB уже загружена\n");
      hello();
      exit(-1);
   }

   // Выдаем инструкцию по работе с программой GRAB

   hello();

   // Вычисляем размер программы в параграфах
   // Добавляем 1 параграф на случай
   // некратной параграфу длины

   size = (12000 >> 4) + 1;


   // Устанавливаем начальные значения флагов

   outflag=iniflag=0;

   // Сбрасываем счетчик файлов. Первый файл будет
   // иметь имя GRAB0.DOC. В дальнейшем этот счетчик
   // будет увеличивать свое значение на 1.

   name_counter=0;

   // Получаем указатель на флаг критической секции DOS.
   // Когда этот флаг равен 0, TSR-программа может
   // пользоваться функциями DOS

   inregs.h.ah = 0x34;
   intdosx( &inregs, &outregs, &segregs );
   crit=(char _far *)FP_MAKE(segregs.es,outregs.x.bx);

   // Устанавливаем собственные обработчики прерываний.

   old9 = _dos_getvect(0x9);
   _dos_setvect(0x9, new9);

   old8 = _dos_getvect(0x8);
   _dos_setvect(0x8, new8);

   old28 = _dos_getvect(0x28);
   _dos_setvect(0x28, new28);

   old2f = _dos_getvect(0x2f);
   _dos_setvect(0x2f, new2f);


   // Завершаем программу и остаемся в памяти

   _dos_keep(0, size);
}

// =======================================

// Новый обработчик прерывания мультиплексора.
// Используется для предохранения программы
// от повторного встраивания в систему как резидентной.

void _interrupt _far new2f(unsigned _es, unsigned _ds,
                 unsigned _di, unsigned _si,
                 unsigned _bp, unsigned _sp,
                 unsigned _bx, unsigned _dx,
                 unsigned _cx, unsigned _ax,
                 unsigned _ip, unsigned _cs,
                 unsigned flags)
{
      // Если прерывание вызвано с содержимым
      // регистра AX, равным FF00, возвращаем
      // в регистре AX значение 00FF,
      // в противном случае передаем управление
      // старому обработчику прерывания

      if(_ax != 0xff00) _chain_intr(old2f);
      else _ax = 0x00ff;

}

// =======================================

// Новый обработчик аппаратного прерывания таймера

void _interrupt _far new8(void) {

   // Вызываем старый обработчик

   (*old8)();

   // Если была нажата комбинация клавиш Ctrl+PrtSc
   // (iniflag при этом устанавливается в 1
   // новым обработчиком прерывания 9) и
   // если запись в файл уже не началась,
   // то при значении флага критической секции
   // DOS, равном 0, выводим содержимое экрана
   // в файл

   if((iniflag != 0) && (outflag == 0) && *crit == 0) {

      outflag=1;   // Устанавливаем флаг начала вывода
      _enable();   // Разрешаем прерывания

      write_buf(); // Записываем содержимое
               // буфера экрана в файл

      outflag=0;   // Сбрасываем флаги в исходное
      iniflag=0;   //    состояние
   }
}

// =======================================

// Новый обработчик прерывания 28h, которое вызывает
// DOS, если она ожидает ввода от клавиатуры.
// В этот момент TSR-программа может пользоваться
// функциями DOS.

void _interrupt _far new28(void) {

   // Если была нажата комбинация клавиш Ctrl+PrtSc
   // (iniflag при этом устанавливается в 1
   // новым обработчиком прерывания 9) и
   // если уже не началась запись в файл,
   // то выводим содержимое экрана в файл

   if((iniflag != 0) && (outflag == 0)) {

      outflag=1; // Устанавливаем флаг начала вывода
      _enable(); // Разрешаем прерывания

      write_buf(); // Записываем содержимое видеобуфера
               // в файл

      outflag=0;   // Сбрасываем флаги в исходное
      iniflag=0;   //   состояние
   }

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

   _chain_intr(old28);
}

// =======================================

// Новый обработчик клавиатурного прерывания.
// Он фиксирует нажатие комбинации клавиш Ctrl+PrtSc
// и устанавливает флаг iniflag, который сигнализирует
// о необходимости выбрать подходящий момент и
// записать содержимое видеобуфера в файл

void _interrupt _far new9(void) {

 // Если SCAN-код равен 0x37 (клавиша PrtSc),
 // нажата клавиша Ctrl (бит 4 байта состояния
 // клавиатуры, находящийся в области данных
 // BIOS по адресу 0040:0017 установлен в 1)
 // и если не установлен флаг iniflag,
 // то устанавливаем флаг iniflag в 1.

 if((inp(0x60) == 0x37) && (iniflag == 0) &&
   (*(char _far *)FP_MAKE(0x40,0x17) & 4) != 0) {

      // Выдаем звуковой сигнал

      BEEP();
      BEEP();
      BEEP();

      _disable(); // Запрещаем прерывания

      // Разблокируем клавиатуру
      // и разрешаем прерывания

      _asm {
         in  al,61h
         mov ah,al
         or  al,80h
         out 61h,al
         xchg ah,al
         out 61h,al

         mov al,20h
         out 20h,al
      }

      // Устанавливаем флаг запроса
      // на запись содержимого видеобуфера
      // в файл

      iniflag = 1;
      _enable();  // Разрешаем прерывания
 }

 // Если нажали не Ctrl+PrtSc, то
 // передаем управление старому
 // обработчику прерывания 9

 else _chain_intr(old9);

}

// =======================================

// Функция возвращает номер
// текущего видеорежима

int get_vmode(void) {

   char _far *ptr;

   ptr = FP_MAKE(0x40,0x49); // Указатель на байт
                     // текущего видеорежима
   return(*ptr);
}

// =======================================

// Функция возвращает сегментный адрес
// видеобуфера. Учитывается содержимое
// регистров начального адреса видеобуфера.

int get_vbuf(int vmode) {

   unsigned vbase;
   unsigned adr_6845;
   unsigned high;
   unsigned low;
   unsigned offs;

   // В зависимости от видеорежима базовый адрес
   // видеобуфера может быть 0xb000 или 0xb800

   vbase = (vmode == 7) ? 0xb000 : 0xb800;

   // получаем адрес порта контроллера ЭЛТ

   adr_6845 = *(unsigned _far *)(FP_MAKE(0x40,0x63));

   // Считываем содержимое регистров 12 и 13
   // контроллера ЭЛТ (регистров начального адреса)

   outp(adr_6845,0xc);
   high = inp(adr_6845+1);

   outp(adr_6845,0xd);
   low = inp(adr_6845+1);

   offs = ((high << 8) + low) >> 4;

   // Добавляем к базовому адресу видеобуфера
   // смещение, взятое из регистров видеоконтроллера

   vbase += offs;

   return(vbase);

}

// =======================================

// Функция возвращает количество символов в строке
// для текущего видеорежима

int get_column(void) {

   return(*(int _far *)(FP_MAKE(0x40,0x4a)));
}

// =======================================

// Функция возвращает количество строк
// для текущего видеорежима

int get_row(void) {

   unsigned char ega_info;

   ega_info = *(unsigned char _far *)(FP_MAKE(0x40,0x87));

   // Если нет EGA, то используется 25 строк,
   // если EGA присутствует, считываем число
   // строк. Это число находится в области данных
   // BIOS по адресу 0040:0084.

   if(ega_info == 0 || ( (ega_info & 8) != 0) ) {
      return(25);
   }
   else {
      return(*(unsigned char _far *)
          (FP_MAKE(0x40,0x84)) + 1);
   }

}

// =======================================

// Функция записи содержимого видеобуфера в
// файл

int write_buf(void) {

// Видеопамять состоит из байтов символов и байтов
// атрибутов. Нам нужны байты символов chr.

typedef struct _VIDEOBUF_ {
    unsigned char chr;
    unsigned char attr;
} VIDEOBUF;

   VIDEOBUF _far *vbuf;
   int i, j, k, max_col, max_row;
   FILE *out_file;
   char fname[20],ext[8];

   i=get_vmode(); // Получаем номер текущего
            // видеорежима

   // Для графического режима ничего не записываем

   if(i > 3 && i != 7) return(-1);

   // Устанавливаем указатель vbuf на видеобуфер

   vbuf=(VIDEOBUF _far *)FP_MAKE(get_vbuf(i),0);

   // Определяем размеры экрана

   max_col = get_column();
   max_row = get_row();

   // Формируем имя файла для записи образа экрана

   itoa(name_counter++,ext,10);
   strcpy(fname,"!grab");
   strcat(fname,ext);
   strcat(fname,".doc");

   out_file=fopen(fname,"wb+");

   // Записываем содержимое видеобуфера в файл

   for(i=0; i<max_row; i++) {
      for(j=0; j<max_col; j++) {

         fputc(vbuf->chr,out_file);
         vbuf++;

      }

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

      fputc(0xd,out_file);
      fputc(0xa,out_file);
   }
   fclose(out_file);
   return(0);
}

// =======================================

// Функция выводит на экран инструкцию по
// использованию программы GRAB

int hello(void) {
   printf("\nУтилита копирования содержимого"
          "\nэкрана в файл GRAB<n>.DOC"
          "\nCopyright (C)Frolov A.,1990"
          "\n"
          "\nДля копирования нажмите Ctrl+PrtSc"
          "\n");
}

Знакогенератор

При установке текстовых режимов работы видеоадаптеров EGA и VGA, BIOS загружает таблицы знакогенератора из ПЗУ во второй цветовой слой видеопамяти. Впоследствии эти таблицы используются при отображении символов на экране.

Благодаря этому, можно легко заменить стандартную таблицу знакогенератора своей собственной. Эта особенность EGA и VGA, в частности, широко применяется при "русификации" компьютеров. В CGA, где знакогенератор находится в ПЗУ, отображать русские буквы можно только в графическом режиме.

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

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

Рисунок 6.6 Активные таблицы знакогенераторов.

EGA поддерживает два размера для матриц символов: стандартный - 8 пикселов в ширину и 8 пикселов в высоту, а также улучшенный - 8 пикселов в ширину и 14 пикселов в высоту. Один из этих наборов символов автоматически загружается BIOS в видеопамять при выборе текстового режима. Так как VGA имеет большую разрешающую способность, то его набор символов имеет в ширину 9 пикселов, а в высоту - 16.

Адреса таблиц знакогенератора для EGA и VGA приведены в таблице 6.1. Как видно из этой таблицы, на каждый символ отводится 32 байта.

Первая таблица знакогенератора Вторая таблица знакогенератора
cимвол 0 0000h-001Fh символ 0 2000h-201Fh
символ 1 0020h-003Fh символ 1 2020h-203Fh
символ 2 0040h-005Fh символ 2 2040h-205Fh
... ... ... ...
символ 255 1FE0h-1FFFh символ 255 3FE0h-3FFFh
Третья таблица знакогенератора Четвертая таблица знакогенератора
cимвол 0 4000h-401Fh символ 0 6000h-601Fh
символ 1 4020h-403Fh символ 1 6020h-603Fh
символ 2 4040h-405Fh символ 2 6040h-605Fh
... ... ... ...
символ 255 5FE0h-1FFFh символ 255 7FE0h-7FFFh
Пятая таблица знакогенератора (только VGA) Шестая таблица знакогенератора (только VGA)
cимвол 0 8000h-801Fh символ 0 A000h-A01Fh
символ 1 8020h-803Fh символ 1 A020h-A03Fh
символ 2 8040h-805Fh символ 2 A040h-A05Fh
... ... ... ...
символ 255 9FE0h-9FFFh символ 255 BFE0h-BFFFh
Седьмая таблица знакогенератора (только VGA) Восьмая таблица знакогенератора (только VGA)
cимвол 0 C000h-C01Fh символ 0 E000h-E01Fh
символ 1 C020h-C03Fh символ 1 E020h-E03Fh
символ 2 C040h-C05Fh символ 2 E040h-E05Fh
... ... ... ...
символ 255 DFE0h-DFFFh символ 255 FFE0h-FFFFh

Таблица 6.1 Размещение таблиц знакогенератра в видеопамяти.

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

Атрибуты символов

Каждый символ, отображаемый на экране в текстовом режиме, определяется не только своим кодом ASCII, но и байтом атрибутов. Атрибуты задют цвет символа, цвет фона а также некоторые другие параметры.

На рисунке 6.7 представлен формат байта атрибутов. Биты D0-D2 задают цвет символа, D4-D6 определяют цвет фона на котором отображается символ. Таким образом можно независимо задавать до 23 = 8 различных цветов для текста и фона.

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

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

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

D2-D0 Цвет символа.
D3 Интенсивность символа и выбор таблицы знакогенератора.
D6-D4 Цвет фона символа.
D7 Мигание символа или интенсивность фона символа.

Рисунок 6.7 Байт атрибутов символа.

В таблице 6.2 приведено соответствие цветов символов и фона значениям поля цвета символа байта атрибутов:


Код цвета в          Стандартный цвет        Цвет с повышенной
байте атрибутов                              интенсивностью

000                  черный                  серый
001                  синий                   светло-синий
010                  зеленый                 светло-зеленый
011                  морской волны           голубой
100                  красный                 светло-красный
101                  фиолетовый              малиновый
110                  коричневый              желтый
111                  белый                   ярко-белый


Таблица 6.2 Стандартные цветовые атрибуты.

Атрибуты символов (монохромный режим)

Назначение полей байта атрибутов в монохромном режиме сходно с их назначениями в цветном режиме.

На рисунке 6.7 представлен формат байта атрибутов. Биты D0-D2 управляют типом символа, который может быть обычным, мигающим или подчеркнутым; D4-D6 могут выбрать обратный (инвертированный) символ.

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

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

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

В таблице 6.3 представлны все возможные значения для атрибутов символов в текством монохромном режиме. В случае использования другх значений атрибутов могут возникнуть проблемы совместимости для различных видеоадаптеров (MDA, CGA, EGA, VGA, Hercules).

Атрибут Что означает
00000000b (00h) черный символ на черном фоне
00000001b (01h) подчеркнутый символ
00000111b (07h) обычный символ (светлый символ на черном фоне)
00001001b (09h) подчеркнутый символ с повышенной интенсивностью
00001111b (0Fh) символ с повышенной интенсивностью
01110000b (70h) обратное отображение символа (черный символ на светлом фоне)
10000001b (81h) подчеркнутый мигающий символ
10000111b (87h) мигающий символ
10001001b (89h) подчеркнутый мигающий символ с повышенной интенсивностью
11110000b (0F0h) мигающее обратное отображение символа

Таблица 6.3 Стандартные монохромные атрибуты.

Видеопамять в графических режимах

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

Ниже рассмотрена структура видеопамяти отдельно для каждого графического режима.

Режимы 4 и 5

Это режимы низкого разрешения (320х200), используются 4 цвета. Поддерживаются видеоадаптерами CGA, EGA и VGA. У адаптеров EGA и VGA видеоданные расположены в нулевом цветовом слое. Остальные три цветовых слоя не используются.

Для совместимости с видеоадаптером CGA, отображение видеопамяти на экран не является непрерывным: первая половина видеопамяти (начальный адрес B800:0000) содержит данные относительно всех нечетных линий экрана, а вторая половина (начальный адрес B800:2000) - относительно всех четных линий. Каждому пикселу изображения соответствуют два бита видеопамяти. За верхний левый пиксел экрана отвечают биты D7 и D6 нулевого байта видеопамяти. На рисунке 6.8 изображено соответствие видеопамяти пикселам экрана.

Рисунок 6.8 Структура видеопамяти для режимов 4 и 5.

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

Следующие формулы позволяют определить смещение байта от начала станицы видеопамяти и номера битов в нем, управляющие пикселом с координатами (x,y):

Если y четное число, то смещение байта = 50h*(y/2)+(x/4)
Если y нечетное число, то смещение байта = 2000h+50h*((y-1)/2)+(x/4)

Номер первого бита = 7-mod(x/4)*2

Ниже представлена таблица соответствия значений битов, определяющих пиксел цвету пиксела:

Значение битов пиксела Стандартный цвет Альтернативный цвет
00 черный черный
01 светло-синий зеленый
10 малиновый красный
11 ярко-белый коричневый

Таблица 6.4

В режимах 4 и 5 имеются два набора цветов - стандартный и альтернативный. Для выбора используемого набора цветов можно воспользоваться функцией 0Bh прерывания INT 10h.

Режим 6

Режим 6 (640х200) является режимом наибольшего разрешения для видеоадаптера CGA. Видеоадаптеры EGA и VGA используют для хранения информаци только нулевой цветовой слой.

На рисунке 6.9 отображено соответствие видеопамяти и пикселов экрана.

Как и в режимах 4 и 5, первая половина видеопамяти содержит данные относительно всех нечетных линий экрана, а вторая половина - относительно всех четных линий.

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

Рисунок 6.9 Структура видеопамяти в режиме 6.

При непосредственном доступе к видеопамяти вы можете воспользоваться следующими формулами:

Если y четное число, то смещение байта = 50h*(y/2)+(x/8)
Если y нечетное число, то смещение байта = 2000h+50h*((y-1)/2)+(x/8)

Номер бита = 7-mod(x/8)

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

Режимы 0Dh и 0Eh

Разрешающая способность в режиме 0Dh составляет 320 пикселов по горизонтали и 200 пикселов по вертикали, а в режиме 0Eh соответственно 640 и 200 пикселов.

Данный режим поддерживают только видеоадаптеры EGA и VGA. На рисунке 6.10 представлена cтруктура видеопамяти для этого режима.

Для хранения видеоданных используются все четыре цветовых слоя. Адресу видеопамяти соответствует четыре байта, которые вместе определяют восемь пикселов. Каждому пикселу соответствует четыре бита - по одному биту из каждого цветового слоя. Четыре бита на пиксел, используемые в данных режимах, позволяют отображать 16 различных цветов.

Рисунок 6.10 Структура видеопамяти в режимах 0Dh и 0Eh.

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

Смещение байта = 50h*y+x/8

Номер бита = 7-mod(x/8)

Запись в каждый из этих черырех слоев можно разрешить или запретить при помощи регистра разрешения записи цветового слоя. Смотри раздел "Регистры видеоадаптеров EGA и VGA".

Режим 0Fh

Графический монохромный режим с разрешением 640х350 пикселов. Данный режим поддерживают только видеоадаптеры EGA и VGA.

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

На рисунке 6.11 представлена cтруктура видеопамяти для этого режима.

Рисунок 6.11 Структура видеопамяти режима 0Fh.

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

Смещение байта = 50h*y+x/8

Номер бита = 7-mod(x/8)

Режим 10h

Графический цветной режим с разрешением 640х350 пикселов. Данный режим поддерживают только видеоадаптеры EGA и VGA.

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

На рисунке 6.12 представлена cтруктура видеопамяти для этого режима.

Рисунок 6.12 Структура видеопамяти режима 10h.

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

Смещение байта = 50h*y+x/8

Номер бита = 7-mod(x/8)

Режим 11h

Графический цветной режим с разрешением 640х480 пикселов. Данный режим поддерживает только видеоадаптер VGA.

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

На рисунке 6.13 представлена cтруктура видеопамяти для этого режима.

Рисунок 6.13 Структура видеопамяти режима 11h.

При непосредственном доступе к видеопамяти вы можете воспользоваться следующими формулами:

Смещение байта = 50h*y+x/8

Номер бита = 7-mod(x/8)

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

Режим 12h

Данный режим является уникальным для VGA. Режим 12h похож на режим 10h, за исключением того, что он имеет большую разрешающую способность - 640х480 пикселов.

В видеопамяти задействованы все четыре цветовых слоя. Структура видеопамяти показана на рисунке 6.14.

Рисунок 6.14 Структура видеопамяти режима 12h.

Формулы, используемые для вычисления битов, управляющих данным пикселом экрана, соответствуют формулам режима 10h.

Режим 13h

Этот режим, как и режим 12h, поддерживается только VGA. Он обеспечивает 256 цветов при разрешающей способности 320х200 пикселов.

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

Рисунок 6.15 Структура видеопамяти в режиме 13h.

Следующая формула позволяет определить смещение от начала видеопамяти байта, управляющего пикселом с координатами (x,y):

Смещение байта = 140h*y+x

Графический контроллер

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

Исполнение видеоадаптером операции записи

При чтении процессором данных из видеопамяти они также запоминаются в регистрах-защелках, расположенных на плате видеоадаптера. Когда затем выполняется цикл записи, то над данными, находящимися в этих регистрах, и над данными, поступающими от процессора могут производится следующие логические операции:

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

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

Рисунок 6.16 иллюстрирует выполнение графическим контроллером операции записи данных в видеопамять:

Рисунок 6.16 Запись данных в видеопамять.

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

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

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

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

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

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

Выполнение видеоадаптером операции чтения

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

Последовательный преобразватель

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

Контроллер атрибутов

Контроллер атрибутов в графических и текстовых режимах работы видеоадаптера управляет цветами. Значениям цветовых атрибутов ставится в соответствие определенный цвет при помощи таблицы цветовой палитры (Color Lock-up Table). Таблица цветовой палитры ставит в соответствие четырем битам, взятым из видеопамяти, 6 битов цветовой информации. Если к видеоадаптеру EGA подключен цветной дисплей, то используются только четыре младших бита из шести.

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

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

На рисунках 6.17 и 6.18 показана работа контроллера атрибутов в графическом и текстовом режимах.

Рисунок 6.17 Контроллер атрибутов в текстовых режимах.

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

Аналогично битам, определяющим цвет фона символа, четыре младших бита задают цвет самого символа.

Рисунок 6.18 Контроллер атрибутов в графических режимах.

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

Контоллер атрибутов подробно описан в разделе "Регистры видеоадаптеров EGA и VGA".

Контроллер ЭЛТ

Контроллер ЭЛТ выполняет следующие функции:

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

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

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

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

Синхронизатор

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

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

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

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

[Назад] [Содеожание] [Дальше]