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

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

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

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

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

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

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

Рисунок 8.17 Схема управления цветами (VGA).

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

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

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

Таблица 8.19 Регистры управления ЦАП.

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

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

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

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

  • D1-D0 Если биты D0 D1 содержат двоичное число 11B (шестнадцатиричное 3), то регистры цветовой таблицы доступны для записи, если 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)

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

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

  • D5-D0 Данные для обмена с регистрами таблицы цветов.
  • D7-D6 Не используется.

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

// программа демонстрирует использование регистров таблицы цветов

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


void SetVgaDAC(unsigned, unsigned);


viod main(void) {

   struct videoconfig vc;       // структура описана в graph.h
   RGB color_table[256];
   unsigned char   i, j;
   unsigned char   far *ptr;
   int error, x_num, y_num;
   unsigned seg_table,off_table;

// записываем в массив color_table новые значения для
// регистров таблицы цветов

   for(j = 0; j < 4; j++) {
      for(i = 0; i < 64; i++) {
         (color_table[i+j*64]).red = (j == 0) ? i : 0;
         (color_table[i+j*64]).green = (j == 1) ? i : (j == 3) ? i : 0;
         (color_table[i+j*64]).blue = (j == 2) ? i : (j == 3) ? i : 0;
      }
   }

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

   error = _setvideomode( _MRES256COLOR );

// если режим не установлен, завершаем выполнение программы

   if(!error) exit(1);

   ptr = (unsigned char far*) &color_table[0];

// определяем сегмент и смешение массива color_table

   seg_table = FP_SEG(ptr);
   off_table = FP_OFF(ptr);

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

   SetVgaDAC(seg_table,off_table);

// выводим на экран вертикальные линии различного цвета,
// процессор записывает данные непосредственно в видеопамять

// получаем в ptr указатель на начало видеопамяти

   ptr = (unsigned char far*) (FP_MAKE(0xA000, 0x0));

// записываем данные непосредственно в видеопамять

   for(y_num = 0; y_num < 200; y_num++) {
      for(x_num = 0; x_num < 320; x_num++) {
         *ptr = (unsigned char) x_num;
         ptr++;
      }
   }

// ожидаем нажатия на любую клавишу

   getch();

// устанавливаем режим видеодаптера, используемый по умолчанию
   _setvideomode( _DEFAULTMODE );
}



/**
*.Name   SetVgaDAC
*
*.Title   Запись регистров таблицы цветов
*
*.Descr   Функция устанавливает новые значения для всех регистров
*      таблицы цветов.
*
*
*.Proto   void SetVgaDAC(unsigned seg_table, unsigned off_table)
*
*.Params   unsigned  seg_table - сегмент таблицы, содержащей новые
*                        значения регистров таблицы цветов,
*
*      unsigned  off_table - смещение таблицы, содержащей новые
*                        значения регистров таблицы цветов.

*.Return   Не используется.
*
*.Sample   vga256.c
**/
void SetVgaDAC(unsigned seg_table, unsigned off_table) {

   _asm {

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

      push  ds
      push  es

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

          xor   ax,ax
          mov   es,ax

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

          mov   dx,es:[463h]

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

      add   dx,6

      pop   es


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

      in    al,dx
      nop
      nop

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

      test  al,08h
      jz    wait_on

   wait_off:

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

   wait_on:

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

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

      mov   dx,3C8h

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

      mov   ax,1   
      out   dx,al

   ; задержка

      nop
      nop

; устанавливаем ds:si на массив данных, записываемых
; в регистры таблицы цветов

      mov   ax,seg_table
      mov   ds,ax
      mov   si,off_table

; загружаем 256 регистров (по 3 байта на регистр)

      mov   cx,(256 * 3)

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

      mov   dx,3C9h

      cld

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

   get_reg:

      lodsb
      out   dx,al
      nop         
      nop
      loop  get_reg

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

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