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

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

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

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

  • 7.1. Краткий обзор
  • 7.2. Внешние регистры
  • 7.3. Регистры контроллера ЭЛТ
  • 7.4. Регистры синхронизатора
  • 7.5. Регистры графического контроллера
  • 7.6. Регистры контроллера атрибутов
  • 7.7. Регистры цифро-аналогового преобразователя VGA
  • 7.8. Нестандартные режимы видеоадаптера VGA
  • В этой главе мы опишем все основные регистры видеоадаптеров EGA и VGA, которые могут быть полезны при написании программ. Необходимо указать, что хотя программирование видеоадаптеров на уровне регистров позволяет увеличить скорость работы программ и решить некоторые задачи, которые нельзя решить при помоши функций BIOS, это может вызвать ряд проблем при переносе ваших программ на другие машины. Дело в том, что не все адаптеры совместимы на уровне регистров. Например, оригинальный видеоадаптер CGA создан на основе микросхемы Motorola 6845, а видеоадаптеры EGA и VGA используют более совершенный аналог этой микросхемы. Хотя EGA и VGA имеют регистры, соответствующие регистрам CGA, некоторые из них располагаются по другим адресам и могут выполнять какие-либо дополнительные функции. Кроме того, в каждом новом видеоадаптере расширяется набор используемых регистров.

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

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

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

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

    В новых адаптерах VGA и Super VGA практически все регистры доступны как для записи так и для чтения.

    Условимся, что в тех случаях, когда VGA имеет отличия от EGA, мы будем на это специально указывать.

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

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

    Адрес Регистр
    3C2 регистр определения различных режимов работы (Miscellaneous Output Register - MOR);
      регистр состояния 0 (Input Status Register 0 - ISR0)
    3BA регистр управления дополнительным устройством (Feature Control Register)
      регистр состояния 1 (Input Status Register 1 - ISR1)
    3BB регистр очистки защелки светового пера (Clear Light Pen Latch Register- CLPLR)
    3BC установка защелки светового пера (Set Light Pen Latch Register - SLPLR)
    3C4, регистры синхронизатора
    3C5 (Sequencer Register's - SR)
    3B4, регистры контроллера ЭЛТ
    3B5 (CRT Controller Register's - CRT_CR)
    3CA, регистры графического контроллера
    3CC, (Graphics Controller Register's - GCR)
    3CE,  
    3CF  
    3C0 регистр контроллера атрибутов (Attribute Controller Register - ACR)
    3C3 регистр разрешения работы системы VGA (VGA Enable Register - VGA_ER)
    3C6, регистры цифро-аналогового преобразователя (ЦАП) VGA
    3C7, (VGA Video DAC Register - VGA_DAC_R)
    3C8,  
    3C9  

    Таблица 8.1 Карта портов ввода/вывода (монохромный режим).

    Адрес Регистр
    3C2 регистр определения различных режимов работы (Miscellaneous Output Register - MOR);
      регистр состояния 0 (Input Status Register 0 - ISR0).
    3DA регистр управления дополнительным устройством Feature Control Register)
      регистр состояния 1 (Input Status Register 1 - ISR1)
    3DB регистр очистки защелки светового пера (Clear Light Pen Latch Register- CLPLR)
    3DC установка защелки светового пера (Set Light Pen Latch Register - SLPLR)
    3C4, регистры синхронизатора
    3C5 (Sequencer Register's - SR)
    3D4, регистры контроллера ЭЛТ
    3D5 (CRT Controller Register's - CRT_CR)
    3CA, регистры графического контроллера
    3CC, (Graphics Controller Register's - GCR)
    3CE,  
    3CF  
    3C0 регистр контроллера атрибутов (Attribute Controller Register - ACR)
    3C3 регистр разрешения работы системы VGA (VGA Enable Register - VGA_ER)
    3C6, регистры ЦАП VGA
    3C7, (VGA Video DAC Register - VGA_DAC_R)
    3C8,  
    3C9  

    Таблица 8.2 Карта портов ввода/вывода (цветной режим).

    Адресное пространство видеопамяти также различается в разных режимах работы видеоадаптера. В таблице 8.3 приведены адреса памяти в зависимости от режима работы.

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

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

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

    #include "sysp.h"
    
    unsigned Get_Seg_Vmem(void) {
    
       unsigned char   mode;
       unsigned seg_address;
    
       // определяем текущий режим видеоадаптера
    
       _asm {
          mov ah,0Fh
          int 10h
          mov mode,al
       }
    
       // если видеоадаптер находится в режимах 0, 1, 2, 3,
       // 4, 5, 6 то видеопамять начинается с сегмента B800h
    
       if((mode >= 0) && (mode <= 6))
          seg_address = 0xB800;
    
       // если видеоадаптер находится в режиме 7,
       // то видеопамять начинается с сегмента B000h
    
       else if(mode == 7)
          seg_address = 0xB000;
    
       // если видеоадаптер находится в режимах 0Dh - 13h,
       // то видеопамять начинается с сегмента A000h
    
       else if((mode >= 0x0D) && (mode <= 0x13))
          seg_address = 0xA000;
    
       // если видеоадаптер не находится в стандартном режиме
       // возвращаем ноль
    
       else seg_address = 0x0;
    
       return(seg_address);
    }
    

    Ниже подробно рассмотрены регистры видеоадаптеров EGA и VGA. Регистры сгруппированы по признаку выполняемых ими функций. Мы выделили следующие группы регистров:

    • Внешние регистры.
    • Регистры контроллера ЭЛТ.
    • Регистры графического контроллера.
    • Регистры контроллера атрибутов.
    • Регистры синхронизатора
    • Регистры цифро-аналогового преобразователя VGA.

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

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

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

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

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

    Ниже приведено описание отдельных битов регистра MOR:

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

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


    D7   D6          EGA                  VGA
    
    0    0           200 линий            не используется
    
    0    1           350 линий            350 линий
    
    1    0           не используется      400 линий
    
    1    1           не используется      480 линий
    

    Таблица 8.4 Соответствие полярности синхронизации и вертикальной разрешающей способности.

    • D5 Бит четной/нечетной страницы используется для режимов, которые передают четные адреса в нулевой цветовой слой, а нечетные - в первый. Все текстовые режимы устанавливают этот бит. Данный бит выбирает одну из двух 64К байтных страниц видеопамяти.
    • D4 Запрещение управления видеоадаптером. Используется только для EGA. При работе на VGA и Super VGA этот бит не используется. Обычно бит D4 имеет значение 0. В этом случае управление дисплеем осуществляет EGA. Если же бит D4 принимает значение 1, то дисплей управляется сигналами, поступающими от выходных выводов разъема дополнительного устройства.
    • D2, D3 Биты выбора частоты управляют тактовой частотой. Таблица 8.5 представляет правильные варианты установки этих битов.
    D3 D2 Режим
    0 0 640 столбцов (или 320 столбцов)
    0 1 720 столбцов
    1 0 внешний генератор (доступен через разъем дополнительного устройства)
    1 1 зарезервированно

    Таблица 8.5 Установка битов D3 и D2.

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

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

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

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

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

    Адрес порта ввода/вывода данного регистра зависит от режима видеоадаптера. В монохромном режиме адрес порта 3BAh, а в цветном - 3DAh.

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

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

    Данный регистр, имеющий адрес 3C2h, доступен только для чтения.

    Регистр позволяет получить различную информацию от видеоадаптера EGA. Формат регистра приведен ниже:

    3-D0   Не используются.
    4   Состояние переключателей.
    5   Бит 0 дополнительного устройства (FEAT0).
    6   Бит 1 дополнительного устройства (FEAT1).
    7   Бит прерывания от ЭЛТ.
    
    • D7 Бит прерывания от ЭЛТ. Бит установлен в 1, когда произошло вертикальное прерывание (по линии IRQ2) из-за обратного вертикального хода луча по кадру (погашеный луч перемещается из правого нижнего угла экрана в левый верхний). Этот бит устанавливается в начале обратного вертикального хода луча и сбрасывается записью в регистр конца вертикального хода луча.
    • D6 Бит 1 дополнительного устройства. Используется только EGA. Бит регистра подключен к 17-му выводу разъема дополнительного устройства.
    • D5 Бит 0 дополнительного устройства. Используется только EGA. Бит регистра подключен к 19-му выводу разъема дополнительного устройства.
    • D4 Состояние переключателей. При помощи данного бита регистра, BIOS EGA считывает состояние четырех переключателей, находящихся на плате видеоадаптера и определяющих его конфигурацию. Номер считываемого переключателя задается двумя битами выбора частоты (Бтиы D2 и D3) регистра определения различных режимов работы (MOR), согласно следующей таблице:
    Бит D3 Бит D2 Считываемый переключатель
    0 0 переключатель 1
    0 1 переключатель 2
    1 0 переключатель 3
    1 1 переключатель 4

    Таблица 8.6 Установка битов D3 и D2.

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

    Для EGA эти четыре переключателя определяют, какой дисплей используется с видеоадаптером и какой дополнительный видеоадаптер может быть подключен к компьютеру (cм. главу "Системы с двумя дисплеями").

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

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

    VGA использует бит D4 для определения типа используемого дисплея (цветной или монохромный).

    Особенно подчеркнем, что положение этих переключателей может быть считано также из байта памяти с адресом 0000:0488h:

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

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

    // чтение битов дополнительного устройства
    // (битов D5 и D6 регистра состояния 0)
    
    #include <stdio.h>
    #include "sysp.h"
    #include "sysgraph.h"
    
    void main(void) {
       int            feature_bits;
       unsigned       crt_address;
       BIOS_VAR _far  *bios_var_ptr;
    
       // читаем содержимое регистра состояния 0 и выделяем 
       // биты D5 и D6
    
       feature_bits = (ReadReg(0x3C2) & 0x60) >> 5;
    
       printf("Биты дополнительного устройства: %x\n", feature_bits);
    }
    

    Функция ReadReg, используемая в программе, описана ранее.

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

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

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

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

    D0   Бит разрешения отображения.
    D1   Бит тригера светового пера.
    D2   Бит переключателя светового пера.
    D3   Бит обратного вертикального хода 
    D5-D4   Диагностические биты.
    D7-D6   Биты не используются.
    
    
    • D7, D6 Биты не используются.
    • D5, D4 Диагностические биты, применяемые для получения двух из шести цветовых выходных сигналов передаваемых на дисплей (для EGA). Какие два сигнала из шести будут диагностироваться, определяют с помощью регистра разрешения цветового слоя контролленра атрибутов (Таблица 8.7):

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

    Таблица 8.7 Считывание диагностических битов EGA.

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


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

    Таблица 8.8 Считывание диагностических битов VGA.

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

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

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

    • D2 Бит переключателя светового пера. Если переключатель светового пера находится в положении ON (включено), то бит D2 равен единице. Если же переключатель находится в положении OFF (выключено), то бит D2 равен нулю.
    • D1 Бит триггера светового пера. Бит равен единице, если триггер светового пера установлен. Этот бит будет сохранять единицу до записи нуля через порт с адресом 3BBh для монохромного режима, или через порт 3DBh - для цветного режима.
    • D0 Бит разрешения отображения. Бит принимает значение единицы во время интервала активности дисплея (когда адаптер читает данные из видеопамяти), и равен нулю во время горизонтального и вертикального обратного хода луча.

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

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

    // программа определения частоты кадров
    
    #include   <time.h>
    #include   <stdio.h>
    #include   <bios.h>
    
    #define   NUM   200
    
    void WaitVert(void);
    
    
    void main() {
    
       time_t   t_start, t_end;
       int      i;
       float   fr;
    
    // определяем время запуска процесса
    
       t_start = clock();
    
    // ожидаем когда процесс вертикальной разверти выполнится NUM раз
    
       for(i = 0; i < NUM; i++) WaitVert();
    
    // определяем время завершения процесса
    
       t_end = clock();
    
    // вычисляем частоту кадров
    
       fr = NUM/(((float)t_end - t_start) / CLK_TCK);
       printf( "\nЧастота кадров = %4.1f \n", (float)fr );
    }
    
    
    /**
    *.Name   WaitVert
    *
    *.Title   Определение начала обратного вертикального хода луча.
    *
    *.Descr   Функция ожидает начало обратного вертикального хода луча.
    *      Использование функции позволяет синхронизировать работу 
    *      программы с периодами работы видеоадаптера.
    *
    *.Proto   void WaitVert(void)
    *
    *.Params   Отсутствуют.
    *
    *.Return   Не используются.
    *
    *.Sample   get_vert.c
    **/
    void WaitVert(void) {
       unsigned count;
       _asm {
    
    ; устанавливаем регистр es на сегмент с нулевым адресом
    
          mov   ax,0h
          mov   es,ax
    
    ; определяем адрес порта индексного регистра
    ;  контроллера ЭЛТ (3B4h/3D4h в 
    ; зависимости от режима работы видеоадаптера -
    ;  монохромный или цветной)
    
          mov   dx,es:[463h]
    
    ; вычисляем адрес порта регистра состояния 1 (ISR1);
    ; это достигается добавлением к адресу порта
    ; индексного регистра 6, так как адрес  порта регистра
    ; состояния 1 равен 3BAh или 3DAh в зависимости от режима
    ; работы видеоадаптера (монохромный или цветной)
    
          add   dl,6
    
    ; читаем содержимое порта регистра состояния 1
    
          in   al,dx
    
    ; тестируем бит D3 регистра состояния 1
    ; бит D3 = 1 во время обратного вертикального хода луча
    
          test   al,8
          jz   wait_on
    
       wait_off:
    
          in   al,dx
    
    ; тестируем бит D3
    
          test   al,8
    
    ; ожидаем конец обратного вертикального хода луча
    
          jnz   wait_off
    
       wait_on:
    
          in   al,dx
          test   al,8
    
    ; ожидаем начало обратного вертикального хода луча
    
          jz   wait_on
    ; 
    ;  здесь могут распологаться операции, которые необходимо 
    ;  выполнить  во время обратного  вертикального хода луча 
    ;
       }
    }
    

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

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

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

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

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

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

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

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

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

    Назначение и формат ряда регистров контроллера ЭЛТ различаются для видеоадаптеров EGA, VGA и для видеоадаптеров MDA, Hercules и CGA. Кроме того, они могут различаться и для видеоадаптерв одного типа, но разных фирм-производителей. В результате могут возникнуть проблем совместимости на компьютерах, оснащенных другим видеоадаптером. Если вы все-таки решитесь их перепрограммировать, то обращайтесь к описанию вашего адаптера.

    Регистры контроллера ЭЛТ составляют самую многочисленную группу регистров видеоадаптеров. Для видеоадаптеров EGA и VGA группа содержит 24 регистра.

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

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

    Таблица 8.9 Регистры EGA и VGA контроллера ЭЛТ.

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

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

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

    Таблица 8.10 Адреса портов индексного регистра и регистра данных.

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

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

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

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

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

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

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

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

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

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

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

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

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

    Длина отображаемой части горизонтальной развертки (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 для определения начала импульса гашения луча горизонтальной развертки.

    При установке режима работы видеоадаптера, 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 регистр задает момент начала импульса горизонтального обратного хода луча.

    При установке режима работы видеоадаптера, 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 бит D7 является пятым битом регистра конца импульса гашения луча горизонтальной развертки (EHBR).

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

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

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

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

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

    • D0 Регистр числа горизонтальных линий растра (VTR). Бит 8.
    • D1 Регистр начала гашения вертикальной развертки (VDER). Бит 8.
    • D2 Регистр начала обратного вертикального хода луча (VRSR). Бит 8.
    • D3 Регистр начала импульса гашения вертикальной развертки (SVBR). Бит 8.
    • D4 Регистр сравнения линий (LCR). Бит 8.
    • D5 Регистр количества горизонтальных линий в растре (VTR). Бит 9.
    • D6 Регистр начала гашения вертикальной развертки (VDER) Бит 9.
    • D7 Регистр начала обратного вертикального хода луча (VRSR). Бит 9.

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

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

    • D4-D0 Биты предварительной установки строчной развертки. Эти биты задают для самой верхней строки текста на экране номер линии в матрице символов, начиная с которой начинают отображаться символы (см. рисунок 8.1). Как видно из рисунка самая верхняя строка текста отображается не полностью. Плавную прокрутку экрана можно производить увеличивая или уменьшая
      значение этих битов.
    • D6-D5 Биты управления побайтовым панорамированием. Используются только VGA. Они являются двумя дополнительными битами регистра горизонтального панорамирования контроллера атрибутов и позволяют сдвигать экран более, чем на 8 пикселов.
    • D7 Не используется.

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

    Рисунок 8.1 Плавная прокрутка экрана.

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

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

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

    • D4-D0 Максимальная линия сканирования. Эти биты задают высоту символа в пикселах (см. рисунок 8.2 и 8.3).
    • D5 Бит 9 регистра начала импульса гашения вертикальной развертки (SVBR - индекс 15h). Только для VGA.
    • D6 Бит 9 регистра сравнения линий (LCR индекс 18h). Только для VGA.
    • D7 Бит управления двойным сканированием. Поддерживается только адаптерами VGA. Если бит D7 равен единице, то в режимах с разрешением по вертикали 200 пикселов, для каждой линии растра применяется двойное сканирование, что фактически увеличивает разрешающую способность по вертикали до 400 пикселов.

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

    Рисунок 8.2 Изменение высоты символов текста.

    Рисунок 8.3 Изменение высоты символов текста.

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

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

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

    D4-D0   Начальная линия курсора. (см. рисунок 8.4).
    D5   Бит гашения курсора. Реализован только на VGA. Если D5 содержит единицу, курсор гаснет.
    D7-D6   Не используются.
    

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

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

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

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

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

    • D4-D0 Соответствует номеру последней линии курсора для VGA (см. рисунок 8.4). Для 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

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

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

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

    #include <stdio.h>
    #include "sysp.h"
    #include "sysgraph.h"
    
    void main(void) {
    
       char           top = 0, bottom = 0;
       unsigned       crt_address;
       BIOS_VAR _far  *bios_var_ptr;
    
       // получаем указатель на область переменных видеофункций BIOS
    
       bios_var_ptr = (BIOS_VAR _far *) FP_MAKE(0x0000, 0x0410);
    
       // определяем адрес порта индексного регистра контроллера ЭЛТ
    
       crt_address = bios_var_ptr->crt_address;
    
       // считываем значения регистров начальной и
       // конечной линии курсора
    
       // выбираем регистр начальной линии курсора
    
       WriteReg(crt_address++, 0x0A);
    
       // считываем значение регистра
    
       top = (unsigned char) ReadReg(crt_address--);
    
       // выбираем регистр конечной линии курсора
    
       WriteReg(crt_address++, 0x0B);
    
       // считываем значение регистра
    
       bottom = (unsigned char) ReadReg(crt_address);
    
       // отображаем на экране значение регистров
    
       printf("\nРегистр начальной линии курсора содержит %x\n"
              "\nРегистр конечной линии курсора содержит %x\n", 
              top, bottom);
    
       getch();
    }
    

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

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

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

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

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

    Рисунок 8.5 Процесс панорамирования экрана.

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

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

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

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

    Программа, приведенная ниже считывает значения из регистров позиции курсора (на момент запуска программы) и отображает их на экране дисплея:

    // чтение регистра положения курсора
    
    #include <stdio.h>
    #include <graph.h>
    #include "sysp.h"
    #include "sysgraph.h"
    
    
    void main(void) {
    
       int            crt_port;
       unsigned char  h_pos, l_pos;
       BIOS_VAR _far  *bios_var_ptr;
    
    
       // получаем указатель на область переменных видеофункций BIOS
    
       bios_var_ptr = (BIOS_VAR _far *) FP_MAKE(0x0000, 0x0410);
    
       // определяем адрес порта индексного регистра контроллера ЭЛТ
    
       crt_port = bios_var_ptr -> crt_address;
    
       // выбираем старший байт регистра положения курсора
    
       WriteReg(crt_port, 0x0E);
    
       // считываем значение старшего байта регистра положения курсора
    
       h_pos = ReadReg(crt_port + 1);
    
       // выбираем младший байт регистра положения курсора
    
       WriteReg(crt_port, 0x0F);
    
       // считываем значение младшего байта регистра положения курсора
    
       l_pos = ReadReg(crt_port + 1);
    
       printf("\nТекущий адрес курсора %X:%X\n",
                (unsigned char) h_pos, (unsigned char) l_pos );
    }
    

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

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

    Данный регистр доступен только для записи.

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

    Данный регистр видеоадаптеров EGA и VGA доступен только для записи.

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

    D3-D0   Конец обратного вертикального хода луча.
    D4   Сброс вертикального прерывания.
    D5   Разрешения вертикального прерывания.
    D6   Изменение скорости регенирации экрана. (Только VGA.)
    D7   Защита от записи. (Только VGA.)
    
    • D7 Этот бит позволяет решить некоторые проблеммы совместимости между VGA и видеоадаптерами, построенными на основе микросхемы 6845 (например CGA). Если бит D7 равен единице, то регистры контроллера ЭЛТ, имеющие индексы от 0 до 7, будут защищены от записи в них.
    • D6 Если бит равен единице, то во время обратного горизонтального хода луча будет генерироваться пять циклов регенерации видеопамяти вместо обычных трех.?
    • D5 Если бит равен нулю, то при каждом обратном вертикальном ходе луча на линии IRQ2 будет возникать прерывание. Сигнал прерывания сбрасывается записью нуля в бит D4 данного регистра.
    • D4 Запись нуля в данный бит вызывает сброс вертикального прерывания и переустановку флага незаконченного вертикального прерывания.
    • D3-D0 Когда значение этих битов поразрядно равны четырем младшим битам счетчика горизонтальных линий, сигнал обратного вертикального хода луча будет окончен.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    • D4-D0 Определяют положение подчеркивания символа (0-13).
    • D5 Для VGA установка этого бита означает, что для каждого знакоместа счетчик адреса регенерации будет увеличиваться на 4 вместо 1.
    • D6 Установка для VGA этого бита выбирает адресацию видеопамяти по двойным словам.
    • D7 Не используется.

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

    #include <graph.h>
    
    void Set43Line(void);
    
    
    void main(void) {
    
       int   i;
    
    
       // устанавливаем текстовый режим, принятый по умолчанию;
       // функция _setvideomode определена в графической библиотеке
       // трансляторов Microsoft Quick C 2.5 и C 6.0 
    
       _setvideomode(_DEFAULTMODE);
    
       // перепрограммируем видеоадаптер для отображения 43 строк
    
       Set43Line();
    
       // выводим на экран дисплея 43 строки текста
    
       for(i = 0; i < 43; i++)
          printf("text line number %d\n", i);
    
       getch();
    
       // восстанавливаем режим с 25 текстовыми строками   
    
       _setvideomode(_DEFAULTMODE);
    }
    
    
    /**
    *.Name   Set43Line
    *
    *.Title   Установка текстового режима, использующего 43 строки.
    *
    *.Descr   Переводит адаптеры EGA и VGA в режим отображения 43 
    *      строк текста.
    *
    *.Proto   void Set43Line(void)
    *
    *.Params   Отсутствуют.
    *
    *
    *.Return   Не используется.
    *
    *.Sample   43line.c
    **/
    void Set43Line(void) {
    
       #define   CHAR_SIZE   8      // новая высота символов
    
       _asm {
    
          ; устанавливаем регистр es на начало оперативной памяти
    
          xor   ax,ax
          mov   es,ax
    
    ; получаем адрес порта индексного регистра контроллера ЭЛТ
    ; (3B4h/3D4h),
    ; в монохромных режимах для адресации к индексному регистру
    ; используется порт с адресом 3B4h, а в цветных - порт 3D4h
    
          mov   dx,es:[463h]
    
    ; выбираем для обмена регистр максимальной линии сканирования
    ; этот регистр задает высоту символов на экране дисплея
    
          mov   al,9
          out   dx,al
    
    ; вычисляем адрес порта регистра данных контроллера ЭЛТ,
    ; в монохромных режимах для адресации к регистру данных
    ; используется порт с адресом 3B5h, а в цветных - порт 3D5h
    
          inc   dx
    
    ; биты D4-D0, регистра максимальной линии сканирования содержат
    ; число, меньшее на единицу, чем высота символов в пикселах
    
          mov   al,CHAR_SIZE-1
          out   dx,al
    
    ; вычисляем адрес порта индексного регистра контроллера ЭЛТ
    
          dec   dx
    
    ; выбираем для обмена регистр положения подчеркивания
    
          mov   al,14h
          out   dx,al
    
    ; вычисляем адрес порта регистра данных контроллера ЭЛТ
    
          inc   dx
    
    ; определяем положение подчеркивания символов
    
          mov   al,CHAR_SIZE
          out   dx,al
    
    ; вычисляем адрес порта индексного регистра контроллера ЭЛТ
    
          dec   dx
    
    
    ; выбираем для обмена регистр завершения отображения
    ; вертикальной развертки
    
    ; регистр завершения отображения вертикальной развертки
    ; содержит восемь младших бит, определяющих число отображаемых
    ; горизонтальных линий растра минус один
    
          mov   al,12h
          out   dx,al
    
    ; вычисляем адрес порта регистра данных контроллера ЭЛТ
    
          inc   dx
    
    ; для отображения 43 текстовых символов, при высоте символов
    ; 8 пикселов, необходимо иметь 43 * 8 = 344 горизонтальных
    ; линий растра
    
    ; помещаем в регистр завершения отображения вертикальной
    ; развертки младшие 8 бит числа 344
    
          mov   al,(43 * CHAR_SIZE - 1 - 256)
          out   dx,al
    
    ; устанавливаем новые значения переменных BIOS
    
    ; число символов в строке равно восьмидесяти
    
          mov   WORD PTR es:[44Ah],80
    
    ; число строк текста минус один
    
          mov   BYTE PTR es:[484h],(350/CHAR_SIZE)-1
    
    ; высота символов в пикселах
    
          mov   WORD PTR es:[485h],CHAR_SIZE
    
    ; загружаем нулевую таблицу знакогенератора, расположенную во втором 
    ; цветовом слое, набором символов (размера 8х8 пикселов) из ПЗУ BIOS
    
    ; процесс загрузки шрифтов более подробно описан в разделе "Загрузка 
    ; таблиц знакогенератора" из главы "Дополнительные средства BIOS для 
    ; управлния EGA и VGA"
    
          mov   ax,1112h
          xor   bl,bl
          int   10h
       }
    }
    

    Начало импульса гашения вертикальной развертки (SVBR) (byltrc 15h)

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

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

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

    В момент, когда младшие 5 битов регистра для EGA или все 8 битов для VGA равны счетчику горизонтальных линий, заканчивается сигнал гашения вертикальной развертки.

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

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

    • D7 Если бит равен нулю, то горизонтальный и вертикальный обратный ход луча невозможен.
    • D6 Если данный бит равен единице, то установлен байтовый режим, а если он равен нулю - двух-байтовый. Двух-байтовый режим поддерживает разделение данных между двумя цветовыми слоями. VGA дополнительно поддерживает четырех-байтовый режим (см. регистр 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

    Таблица 8.11 Преобразование адреса.

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

    • D4 Если бит равен единице, то все выходные линии контроллера ЭЛТ переводятся в третье состояние. Этот бит используется только при тестировании видеоадаптера.
    • D3 Если бит равен нулю, то счетчик адреса регенерации изображения увеличивается на единицу на каждое знакоместо экрана, а если бит равен единице, то на каждые два знакоместа.
    • D2 Бит может использоваться для увеличения в два раза вертикальной разрешающей способности. Если бит равен нулю, то счетчик числа линий экрана увеличивается после каждого обратного горизонтального хода луча, а если бит равен единице, то после каждых двух.
    • D1 Используется при эмуляции графических режимов видеоадаптера Hercules. Запись в этот бит нуля приводит к замещению бита D14 адресного регистра битом D1 из регистра счетчика горизонтальных строк.
    • D0 Используется при эмуляции графических режимов CGA. Запись в этот бит нуля приводит к выделению в видеопамяти двух областей по 8 Кбайт. Одна содержит даннные для четных, а другая для нечетных строк экрана. Это достигается путем замещения бита D13 адресного регистра битом D0 из регистра счетчика горизонтальных строк.

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

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

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

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

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

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

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

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

    // пример разделения экрана дисплея на две части при помоши
    // регистра сравнения линий контроллера ЭЛТ
    
    #include <dos.h>
    #include <stdio.h>
    
    void Split(unsigned);
    
    
    void main(void) {
    
         int   i;
    
       // выводим на экран дисплея 25 строк текста
    
         for(i = 0; i < 25; i++) 
          printf("Строка номер %d.",i);
    
       getch();
    
    // разделяем экран по линии 200
    
       Split(200);
    
       getch();
    // после завершения программы
    // значения регистров не восстанавливаются!
    }
    
    
    /**
    *.Name   Split
    *
    *.Title   Разделение экрана.
    *
    *.Descr   Функция разделяет экран на две части. Функция работает
    *      только на EGA и VGA.
    *
    *.Proto   void Split(unsigned split_line)
    *
    *.Params   unsigned  split_line - линия горизонтальной развертки, 
    *               в которой происходит разделение экрана 
                   дисплея.
    *
    *.Return   Не используется.
    *
    *.Sample   split.c
    **/
    void Split(unsigned split_line) {
    
         _asm {
    
    ; устанавливаем регистр es на начало оперативной памяти
    
              xor   ax,ax
              mov   es,ax
    
    ; получаем адрес порта индексного регистра контроллера ЭЛТ
    ; (3B4h/3D4h),
    ; в монохромных режимах для адресации к индексному регистру
    ; используется порт с адресом 3B4h, а в цветных - порт 3D4h
    
              mov   dx,es:[463h]
    
    ; вычисляем адрес порта регистра состояния 1,
    ; в монохромных режимах для адресации к регистру состояния 1
    ; используется порт с адресом 3BAh, а в цветных - порт 3DAh
    
              add   dx,6
    
    
    ; ожидаем начало обратного вертикального хода луча
    
              in    al,dx
              nop
    
          ; если бит D3 равен единице, то происходит обратный
          ; вертикальный ход луча
    
              test  al,8
              jz    wait_on
    
         wait_off:
    
              in    al,dx
    
              ; задержка
    
              nop
              test  al,8
              jnz    wait_off
    
         wait_on:
    
              in    al,dx
              nop
              test  al,8
              jz    wait_on
    
    
    ; вычисляем адрес порта индексного регистра контроллера ЭЛТ
    ; (3B4h/3D4h)
    
              sub   dx,6
    
    ; выбираем для обмена регистр сравнения линий
    
              mov   al,18h
              out   dx,al
    
    ; вычисляем адрес порта регистра данных контроллера ЭЛТ,
    ; в монохромных режимах для адресации к регистру данных
    ; используется порт с адресом 3B5h, а в цветных - порт 3D5h
    
              inc   dx
    
    
    ; определяем линию горизонтальной развертки, в которой происходит
    ; разделение экрана дисплея
    
              mov   ax,split_line
    
    ; у видеоадаптера EGA регистр сравнения линий состоит из 9 бит,
    ; доступ к девятому биту происходит через дополнительный регистр
    ; контроллера ЭЛТ;
    ; видеоадаптер VGA имеет еще и десятый бит, расположенный в регистре
    ; высоты символов текста
    
    ; записываем младшие 8 битов в регистр сравнения линий
    
              out   dx,al
    
    ; вычисляем адрес порта индексного регистра контроллера ЭЛТ
    
              dec   dx
    
    ; вызываем функцию чтения конфигурации видеосистемы,
    ; данная функция подробно описана в главе
    ; "Дополнительные средства BIOS для управлния EGA и VGA"
    
              mov   ax,1A00h
              int   10h
    
    ; если после вызова функции регистр al не равен 1Ah, то используемый
    ; видеодаптер не VGA
    
              cmp   al,1Ah
              je    vga
              jmp   ega
    
         vga:
    
    ; считываем в al состояние дополнительного регистра
    
              mov   al,7
              out   dx,al
              inc   dx
              in    al,dx
    
    ; модифицируем бит D4 дополнительного регистра
    
              mov   bx,split_line
              mov   cl,4
              shl   bh,cl
              and   bh,00010000b
    
              and   al,11101111b
              or    al,bh
              out   dx,al
    
    ; сбрасываем бит D6 регистра высоты символов текста
    
              dec   dx
              mov   al,9
              out   dx,al
              inc   dx
              in    al,dx
              and   al,10111111b
              out   dx,al
              jmp   quit_split
    
         ega:
    
              mov   bx,split_line
              mov   cl,4
              shl   bh,cl
              and   bh,00010000b
    
              cmp   dx,3B4h         ; монохромный режим?
              je    default_1Fh     ; если да, то переходим
                      ; на метку default_1Fh
    ; определяем наличие улучшенного цветного дисплея по положению
    ; переключателей на плате EGA
    
              mov   al,es:[488h]
              and   al,0Fh
    
    ; положение переключателей "off off on on" ?
    
              cmp   al,3
              je    default_1Fh
    
    ; положение переключателей "off on on off" ?
    
              cmp   al,9
              je    default_1Fh
    
    ; для видеосистем с монохромным или цветным дисплеями,
    ; дополнительный регистр по умолчанию содержит 11h
    
              or    bh,1
              jmp   set_overflow
    
    ; для видеосистем с улучненным цветным дисплеем или в монохромных
    ; текстовых режимах дополнительный регистр по умолчанию содержит 
    ; значение 1Fh
    
         default_1Fh:
    
              or    bh,0Fh
    
    ; устанавливаем дополнительный регистр
    
         set_overflow:
    
              mov   al,07h
              out   dx,al
              inc   dx
              mov   al,bl
              out   dx,al
    
         quit_split:
    
         }
    }
    

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

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

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

    Таблица 8.12 Регистры синхронизатора.

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

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

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

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

    • D0 Бит асинхронного сброса. После записи в этот бит нуля происходит немедленный сброс и остановка синхронизатора. В результате могут быть потеряны видеоданные.
    • D1 Бит синхронного сброса. Нулевое значение сбрасывает и останавливает синхронизатор в конце исполняемого цикла.
    • D7-D2 Не используются.

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

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

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

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

    • D0 Бит задает ширину символов в текстовых монохромных режимах с разрешением 720 пикселов по горизонтали. Если бит равен нулю, то ширина матрицы символов равна 9 пикселов, если единице - 8 пикселов.
    • D1 Бит используется EGA для определения числа циклов, используемых процессором, для доступа к видеопамяти . При D1
      равном единице, процессор может получить три из каждых пяти циклов, а при D1 равном нулю - только один из пяти циклов. Остальные циклы используются адаптером для обновления экрана.
    • D4-D2 Не используются.
    • D5 Для VGA: если этот бит равен единице, то экран гаснет и процессор получает монополию на доступ к видеопамяти. Это несколько ускоряет процесс обмена процессора с видеопамятью.
    • D7-D6 Не используются.

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

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

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

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

    • ПЕРВЫЙ ШАГ. Процессор передает видеоадаптеру данные для записи в видеопамять. Они проходят через графическиий контроллер и попадают в синхронизатор. Графический контроллер производит над записываемыми в видеопамять данными операции, определяемые состоянием его регистров (смотри главу "Исполнение видеоадаптером операции записи" из раздела "Графический контроллер").
    • ВТОРОЙ ШАГ. Синхронизатор записывает поступившие ему данные в видеопамять в соответствии с содержимым регистра разрешения записи цветового слоя. Регистр разрешения записи цветового слоя содержит четыре бита, управляющие записью в цветовые слои видеопамяти. Если бит этого регистра, управляющий цветовым слоем равен нулю, то данный цветовой слой не изменяется. Если бит регистра равен единице, то в данный слой видеопамяти записываются значения, поступившие от графического контроллера.

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

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

    • D0 Если бит равен единице, то можно записывать данные в нулевой цветовой слой.
    • D1 Если бит равен единице, то можно записывать данные в первый цветовой слой.
    • D2 Если бит равен единице, то можно записывать данные в второй цветовой слой.
    • 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 - восемь таблиц знакогенератора, каждая из которых опрделяет 256 символов.

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

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

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

    • D1-D0 Выбор таблицы знакогенератора, используемой адаптерами EGA/VGA при выводе символа на экран, когда бит D3 байта атрибутов символа сброшен в ноль.
    • D3-D2 Выбор таблицы знакогенератора, используемой адаптерами EGA/VGA при выводе символа на экран, когда бит D3 байта атрибутов символа установлен в единицу.
    • D4 Выбор таблицы знакогенератора, используемой адаптером VGA при выводе символа на экран, когда бит D3 байта атрибутов символа сброшен в ноль.
    • D5 Выбор таблицы знакогенератора, используемой адаптером VGA при выводе символа на экран, когда бит D3 байта атрибутов символа установлен в единицу.
    • 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)
    1 0 1 шестая таблица знакогенератора (VGA)
    1 1 0 седьмая таблица знакогенератора (VGA)
    1 1 1 восьмая таблица знакогенератора (VGA)

    Таблица 8.13 Выбор таблиц знакогенератора.

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

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

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

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

    • D0 Для EGA бит устанавливается в единицу, при использовании в текстовом режиме функции выбора знакогенератора. Для VGA этот бит обычно сброшен в ноль.
    • D1 Для EGA данный бит равен единице, если объем видеопамяти больше 64К байт.
    • D2 Если D2 содержит ноль, то доступ по четным адресам происходит к нулевому цветовому слою, а по нечетным - к первому.
    • D7-D3 Не используются.

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

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

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

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

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

    Адаптер EGA имеет еще два порта с адресами 3CAh и 3CCh, используемых при инициализации видеоадаптера.

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

    Таблица 8.14 Регистры графического контроллера.

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

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

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

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

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

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

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

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

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

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

    Использовав данный регистр совместно с регистром разрешения установки/сброса (Set/Reset Enable Register), можно определить данные, размещаемые в цветовых слоях видеопамяти при выполнении процессором записи любых данных в видеопамять. Данные процессора при этом игнорируются.

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

    • D0 Данные, записываемые в цветовой слой 0.
    • D1 Данные, записываемые в цветовой слой 1.
    • D2 Данные, записываемые в цветовой слой 2.
    • D3 Данные, записываемые в цветовой слой 3.
    • D7-D4 Зарезервировано.

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

    Возможности использования данного регистра разъясняются при описании регистра разрешения установки/сброса.

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

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

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

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

    • D0 Разрешение использования данных из регистра установки/сброса для цветового слоя 0.
    • D1 Разрешение использования данных из регистра установки/сброса для цветового слоя 1.
    • D2 Разрешение использования данных из регистра установки/сброса для цветового слоя 2.
    • D3 Разрешение использования данных из регистра установки/сброса для цветового слоя 3.
    • D7-D4 Зарезервированно.

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

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

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

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

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

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

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

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

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

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

    • D0 Искомая величина для нулевого цветового слоя.
    • D1 Искомая величина для первого цветового слоя.
    • D2 Искомая величина для второго цветового слоя.
    • D3 Искомая величина для третьего цветового слоя.
    • D7-D4 Не используются.

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

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

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

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

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

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

    Регистр DRFS выполняет две различные функции, отраженные в его названии:

    • Циклический сдвиг данных, записываемых процессором в видеопамятять.
    • Выполнение над записываемыми в видеопамять данными и содержимым регистров-защелок некоторых логических операций.
    • D2-D0 Счетчик сдвига.
    • D4-D3 Биты выбора логической функции.
    • D7-D5 Не используются.

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

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

    D2 D1 D0 Данные циклически сдвигаются вправо на следующее количество битов
    0 0 0 ноль, сдвиг не происходит
    0 0 1 один бит
    0 1 0 два бита
    0 1 1 три бита
    1 0 0 четыре бита
    1 0 1 пять битов
    1 1 0 шесть битов
    1 1 1 семь битов

    Таблица 8.15 Циклический сдвиг.

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

    Во время выполнения процессором операции чтения из видеопамяти одновременно происходит запись данных из всех четырех цветовых слоев (по считываемому адресу) в регистры-защелки. Каждому цветовому слою видеопамяти соответствует один 8-битовый регистр-защелка. Когда процессор начнет записывать в видеопамять (возможно уже по другому адресу) данные, можно комбинировать их с данными из регистров-защелок. Вид выполняемой логической операции будет зависеть от содержимого битов выбора логической функции (таблица 8.16):

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

    Таблица 8.16 Возможные логические операции.

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

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

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

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

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

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

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

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

    • D1-D0 Номер читаемого цветового слоя видеопамяти.
    • D7-D2 Не используются.

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

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

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

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

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

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

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

    • D1, D0 Данные биты определяют режим записи в видеопамять. Возможно использование трех различных режимов записи:
    D1 D0 Номер режима Режим записи
    0 0 0 режим непосредственной записи
    0 1 1 использование для записи регистров-защелок
    1 0 2 заполнение N-ого цветового слоя битом номер N из данных, записываемых процессором
    1 1 - не используется
    • Режим 0 - режим непосредственной записи. Процессор имеет доступ к видеопамяти и возможно использование следующих операциий: установки/сброса, циклического сдвига и всех логических функций. В этом режиме также возможно использование регистра битовой маски.
    • Режим 1 - режим записи, использующий регистр-защелку. При чтении данных из видеопамяти происходит запись восьми битов из каждого цветового слоя в регистры-защелки. Затем, при выполнении операции записи содержимое регистров-защелок может быть записано обратно в видеопамять, но уже по другому адресу. Этот режим полезно использовать для быстрого копирования данных из одной области видеопамяти в другую.
    • Режим 2. В этом режиме происходит заполнение N-ого цветового слоя битом с порядковым номером N из байта данных, переданного процессором видеоадаптеру для записи. Отсюда следует, что содержимое четырех старших битов записываемого байта (то есть битов D4-D7) значения не имеет.

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

    Рисунок 8.14 Различные режимы записи в видеопамять.

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

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

    • D4 Данный бит устанавливается в текстовых режмимах. При этом доступ по четным адресам происходит к четным цветовым слоям, а по нечетным адресам - к нечетным цветовым слоям видеопамяти (см. видеопамять в текстовых режимах).
    • D5 Используется в режимах 4 и 5 для обработки видеоданных в формате "два бита на пиксел".
    • D6 Используется VGA в режиме с 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К байт памяти. Если бит установлен, то четыре 16К байтных слоя объединяются в два слоя по 32К байт.
    • D3-D2 Эти биты устанавливают начальный и конечный адреса, на которые отображается видеопамять адаптера EGA согласно следующей таблице:

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

      0 0 A000:0000-B000:FFFF
      0 1 A000:0000-A000:FFFF
      1 0 B000:0000-B000:7FFF
      0 1 B800:0000-B000:FFFF
    • 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 содержит ноль, то соответствующий бит будет записываться в видеопамять из регистра-защелки. В противном случае данный бит поступает от процессора (см. рисунок 8.15). Этот регистр используется только в нулевом режиме записи.

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

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

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

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

    Контроллер атрибутов управляет цветовыми характеристиками изображений.

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

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

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

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

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

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

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

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

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

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

    Улучшенный цветной дисплей.

    • 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 ноль для текствых режимов, единица - для графических. Бит определяет спсособ раскодирования атрибутов.
    • D1 Бит определяет тип атрибутов. Для монохромных атрибутов он должен быть равен единице, а для цветных - нулю.
    • D2 Бит используется в монохромных режимах с разрешением по горизонтали 720 пикселов при расширении матриц символов псевдографики с 8 до 9 пикселов по горизонтали. Если бит равен 1, то девятый пиксел в каждой строке будет повторять восьмой. В противном случае девятый пиксел отображаетя цветом фона.
    • D3 Бит D3 управляет назначением седьмого бита в байте атртбутов. Если бит установлен, то бит D7 байта атрибутов управляет миганием символа. Если бит D3 равен нулю, то - интенсивностью фона.
    • D4 Не используется.
    • D5 Доступен только на VGA. Совместно с регистром разделения экрана дисплея контроллера ЭЛТ бит D5 управляет горизонтальным панорамированием экрана. При установке бита D5 запрещается горизонтальное панорамирование стационарной частью экрана.
    • D6 Доступен только на VGA. Бит должен быть равен нулю для режима видеоадаптера VGA с 256 цветами (режим 13h).
    • D7 Доступен только на VGA. Выбор источника сигнала для видеовыходов Р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)

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

    К сожалению операция установки цвета рамки работает не правильно на большинстве адаптеров 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 Биты задают величину горизонтального сдвига. Соответствие содержимого регистра и величины сдвига для различных режимов приведены в таблице 8.18.
    • D7-D4 Не используются.
    D3 D2 D1 D0 Величина сдвига содержимого экрана (в пикселах)
      монохромный текстовый VGA, режим 13h остальные режимы
    0 0 0 0 8 0 0
    0 0 0 1 0 - 1
    0 0 1 0 1 1 2
    0 0 1 1 2 - 3
    0 1 0 0 3 2 4
    0 1 0 1 4 - 5
    0 1 1 0 5 3 6
    0 1 1 1 6 - 7
    1 0 0 0 7 - -
    1 0 0 1 - - -
    1 0 1 0 - - -
    1 0 1 1 - - -
    1 1 0 0 - - -
    1 1 0 1 - - -
    1 1 1 0 - - -
    1 1 1 1 - - -

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

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

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

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

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

    // смещение содержимого экрана по горизонтали и вертикали
    
    #include "sysgraph.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <graph.h>
    #include "sysp.h"
    #include <dos.h>
    
    void HorScroll(unsigned, unsigned);
    void VerScroll(unsigned);
    void SetColumn(unsigned char);
    
    void main(void) {
    
       struct videoconfig vc;
       unsigned char   i,j;
    
       // выбираем текстовый режим работы видеоадаптера,
       // принятый по умолчанию
    
       _setvideomode(_DEFAULTMODE);
    
       // устанавливаем логическую ширину экрана в 100 символов
    
       SetColumn(100);
    
       // отображаем на экране дисплея 24 строки текста
    
       for(i = 0; i < 24; i++)
          printf("\ntext text text");
    
       // производим горизонтальное смещение экрана
       // на i пикселов при каждом нажатии на клавиатуру
    
       for(i = 0; i < 13; i++) {
          getch();
          HorScroll(i,8);
       }
    
       // производим вертикальное смещение экрана
       // на i пикселов при каждом нажатии на клавиатуру
    
    
       for(i = 0; i < 13; i++) {
          getch();
          VerScroll(i);
       }
       getch();
    
    _setvideomode(_DEFAULTMODE);
    }
    
    
    /**
    *.Name   HorScroll
    *
    *.Title   Горизонтальный сдвиг содержимого экрана.
    *
    *.Descr   Функция смещает содержимое экрана влево на определенное
    *      число пикселов.
    *
    *.Proto   void HorScroll(unsigned offset, unsigned wide)
    *
    *.Params   unsigned  offset - величина смещения в пикселах,
    *
    *      unsigned  wide   - ширина символов (8 или 9).
    *
    *.Return   Не используется.
    *
    *.Sample   scroll.c
    **/
    void HorScroll(unsigned offset, unsigned wide) {
    
       unsigned start_addr_reg, panning_reg;
       div_t res;
    
       res = div(offset,wide);
    
       start_addr_reg = res.quot;
       panning_reg = (wide == 9) ? 
                ((res.rem == 0) ? 8 : res.rem - 1 ) : res.rem;
    
       _asm {
          push   ds
    
    ; вычисляем адрес регистра состояния 1 (3BAh/3DAh)
    
          xor   ax,ax
          mov   es,ax
          mov   dx,es:[463h]
          add   dx,6
    
    ; ожидаем начало обратного вертикального хода луча
    
          in   al,dx
          nop
          nop
          test   al,08h
          jz   wait_on
    
       wait_off:
    
          in   al,dx
          nop
          nop
          test   al,08h
          jnz   wait_off
    
       wait_on:
    
          in   al,dx
          nop
          nop
          test   al,08h
          jz   wait_on
    
    ; вычисляем адрес порта индексного регистра контроллера ЭЛТ
    
          sub   dx,6
    
    ; выбираем для доступа младший байт регистра начального адреса
    
          mov   al,0Dh
          out   dx,al
    
    ; вычисляем адрес порта регистра данных контроллера ЭЛТ
    
          inc   dx
    
    ; устанавливаем новый начальный адрес
    
          mov   ax,start_addr_reg
          out   dx,al
    
    ; снова получаем адрес порта регистра состояния 1
    
          add   dx,5
    
    ; сбрасываем внутренний триггер контроллера атрибутов, управляющий
    ; адресацией его регистров
    
          in   al,dx
          nop
          nop
    
    ; выбираем регистр горизонтального панорамирования
    
          mov   dx,3C0h
          mov   al,13h
          out   dx,al
    
          mov   ax,panning_reg
          out   dx,al
    
          pop   ds
       }
    }
    
    
    
    /**
    *.Name   VerScroll
    *
    *.Title   Вертикальный сдвиг содержимого экрана.
    *
    *.Descr   Функция смещает содержимое экрана вверх на определенное
    *      число пикселов.
    *
    *.Proto   void VerScroll(unsigned offset)
    *
    *.Params   unsigned  offset - величина смещения в пикслах.
    *
    *.Return   Не используется.
    *
    *.Sample   scroll.c
    **/
    void VerScroll(unsigned offset) {
    
       unsigned start_addr_reg, preset_row_reg;
       div_t res;
       BIOS_VAR _far  *bios_var_ptr;
    
    
       bios_var_ptr = (BIOS_VAR _far *) FP_MAKE(0x0000, 0x0410);
    
       res = div(offset,bios_var_ptr -> char_height);
    
       start_addr_reg = res.quot * (bios_var_ptr -> columns);
       preset_row_reg = res.rem;
    
    
       _asm {
          push   ds
    
    ; вычисляем адрес регистра состояния 1 (3BAh/3DAh)
    
          xor   ax,ax
          mov   es,ax
          mov   dx,es:[463h]
          add   dx,6
    
    ; ожидаем начало обратного вертикального хода луча
    
          in   al,dx
          nop
          nop
          test   al,08h
          jz   wait_on
    
       wait_off:
    
          in   al,dx
          nop
          nop
          test   al,08h
          jnz   wait_off
    
       wait_on:
    
          in   al,dx
          nop
          nop
          test   al,08h
          jz   wait_on
    
    ; вычисляем адрес порта индексного регистра контроллера ЭЛТ
    
          sub   dx,6
    
    ; модифицируем младший байт регистра начального адреса
    
          mov   al,0Dh
          out   dx,al
          inc   dx
          mov   ax,start_addr_reg
          out   dx,al
    
          dec   dx
    
    ; модифицируем старший байт регистра начального адреса
    
          mov   al,0Ch
          out   dx,al
          inc   dx
          mov   al,ah
          out   dx,al
    
    ; вычисляем адрес порта регистра состояния 1
    
          add   dx,5
    
    ; ожидаем вертикальный обратный ход луча
    
    wait_next:
    
          in   al,dx
          nop
          nop
          test   al,08h
          jz   wait_next
    
    ; определяем адрес порта индексного регистра контроллера ЭЛТ
    
          sub   dx,6
    
    ; устанавливаем регистр предустановки линии сканирования
    
          mov   al,8
          out   dx,al
          mov   ax,preset_row_reg
          inc   dx
          out   dx,al
    
          pop   ds
       }
    }
    
    
    /**
    *.Name   SetColumn
    *
    *.Title   Установка логической ширины экрана.
    *
    *.Descr   Функция устанавливает логическую ширину экрана.
    *
    *.Proto   void SetColumn(unsigned char col)
    *
    *.Params   unsigned char  col - логическая ширина экрана (в символах).
    *
    *.Return   Не используется.
    *
    *.Sample   scroll.c
    **/
    void SetColumn(unsigned char col) {
    
       _asm {
          xor   ax,ax
          mov   es,ax
    
    ; получаем адрес порта индексного регистра
    ; контроллера ЭЛТ (3B4h/3D4h)
          mov   dx,es:[463h]
    
    ; выбираем для обмена регистр логической ширины экрана
    
          mov   al,13h
          out   dx,al
    
    ; вычисляем адрес порта регистра данных контроллера ЭЛТ (3B5h/3D5h)
    
          inc   dx
    
    ; модифицируем переменную BIOS, содержащую число символов в строке
    
          mov   al,col
          mov   es:[44Ah],al
    
    ; регистр логической ширины экрана в текстовых режимах содержит
    ; смещение между соседними строками текста в словах
    
          shr   al,1
          out   dx,al
       }
    }
    

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

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

    • D0 Цвет Р4.
    • D1 Цвет Р5. Данные биты могут использоваться вместо линий Р5 и Р4 соответственно (см. регистры палитры и рисунок 6.18).
    • D2 Цвет Р6.
    • D3 Цвет Р7. Биты используются контроллером атрибутов в качестве двух старших битов, передаваемых ЦАП (см. рисунок 6.18). В режиме 256-цветном режиме VGA данные биты не используются.
    • D7-D4 Не используются.

    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
       }
    }
    

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    • Устанавливаем при помощи BIOS стандартный режим 13h (320х200 пикселов, 256 цветов), при этом программируются все регистры видеоадаптера. Затем мы изменим содержимое только нескольких регистров. Такой подход значительно облегчит нам задачу, так как уменьшится количество регистров, которые необходимо изменить.
    • Изменяем структуру видеопамяти, чтобы иметь воможность адресоваться к 256 килобайтам. Для этого в регистре определения структуры памяти синхронизатора запрещаем режимы в которых доступ по разным адресам (кратным двум и/или кратным четырем) осуществляется к различным цветовым слоям памяти. А в регистре режима работы графического контроллера сбрасываем в ноль бит управления четным/нечетным режимом. Это запрещает доступ по четным адресам к четным цветовым слоям, а по нечетным адресам - к нечетным цветовым слоям видеопамяти. Затем в регистре смешанного назначения графического контроллера сбрасываем бит управляющий сцеплением четных и нечетных слоев памяти. После этих действий видеопамять по своей структуре напоминает режим 10h, за исключением того, что каждый пиксел управляется одним байтом, расположенном в одной из слоев видеопамяти.
    • Очищаем видеопамять (для одной или двух страниц по необходимости), так как при установке режима 13h BIOS очищает только первые 64K из 256K. Остальная видеопамять может содержать мусор который отобразится на экране после перепрограммирования контроллера ЭЛТ.
    • Выключаем режим двойного сканирования. Для этого сбрасываем в ноль бит управления двойным сканированием и устанавливаем высоту символов равную единице.
    • Переводим контроллер ЭЛТ в режим адресации видеопамяти по байтам. Для этого выключаем режим адресации по двойным словам в регистре положения подчеркивания символа и включаем режим адресации по байтам в регистре управления режимом работы. Теперь по каждому адресу расположено четыре байта в различных цветовых слоях видеопамяти.

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

    /**
    *      Включаемый файл vga_new.h
    **/
    
    // сегмент видеопамяти для режима 13h
    #define VGA_SEGMENT     0a000h     
    
    
    // регистр определения различных режимов работы
    #define MOR  3c2h    
    
    // адрес индексного порта синхронизатора
    #define SC_INDEX   3c4h  
    
       // регистр разрешения записи цветового слоя
       #define CPWER   2    
    
       // регистр определения структуры памяти
       #define MMR     4    
    
    
    // адрес индексного порта графического контроллера
    #define GC_INDEX   3ceh  
    
       // регистр выбора читаемого слоя
       #define RPSR    4   
    
       // регистр режима работы
       #define MDR     5   
    
       // регистр смешанного назначения
       #define MIR     6   
    
    
    // адрес индексного порта контроллера ЭЛТ (цветной режим)   
    #define CRTC_INDEX      3d4h     
    
       // регистр высоты символов текста
       #define MSLR    9    
    
       // регистр начального адреса
       #define SAR_h   0ch  
    
       // регистр положения подчеркивания символа
       #define ULR     14h  
    
       // регистр управления режимом
       #define MCR     17h  
    
    
    // режим 320х400 пикселов
    
    // число пикселов по вертикали 
    #define SCREEN_HEIGHT  400 
    
    // число пикселов по горизонтали  
    #define SCREEN_WIDTH   320 
    
    
    // режим 360х480 пикселов
    
    // число пикселов по вертикали 
    #define SCREEN_HEIGHT_H 480 
    
    // число пикселов по горизонтали 
    #define SCREEN_WIDTH_H  360 
    /**
    *      Файл   e256mres.c
    **/
    #include "sysp.h"
    #include "sysgraph.h"
    #include <dos.h>
    
    #include    <graph.h>
    #include    "vga_new.h"
    
    /**
    *.Name    Set320x400Mode
    *
    *.Title   Установка режима 320х400 пикселов, 256 цветов.
    *
    *.Proto   void Set320x400Mode( void )
    *
    *.Params  Не используются.
    *
    *.Return  Не используетя.
    *
    *.Sample  e256mres.c
    **/
    
    void    Set320x400Mode( void ) {
    
       _asm  {
    
          // сохраняем регистр di
          push    di
    
          // устанавливаем стандартный режим 13h (320x200
          // пикселов, 256 цветов)
          mov     ax,0013h
          int     10h
    
          // выбираем регистр определенияя структуры памяти
          mov     dx,SC_INDEX
          mov     al,MMR
          out     dx,al
    
          // считываем значение регистра определения
          // структуры памяти
          inc     dx
          in      al,dx
    
          // сбрасываем бит D4
          and     al,11110111b
    
          // устанавливаем бит D3, при этом выключается
          // режим адресации по четным и нечетным адресам к
          // разным слоям памяти
          or      al,00000100b
    
          // записываем в регистр новое значение
          out     dx,al
    
    
          // после загрузки в этот регистр нового значения
          // структура видеопамяти соответствует режимам 10h
          // и 12h за исключением того, что каждому пикселу
          // соответствует один байт видеопамяти
    
          // выбираем регистр режима работы графического
          // контроллера
    
          mov     dx,GC_INDEX
          mov     al,MDR
          out     dx,al
    
          // считываем его значение
          inc     dx
          in      al,dx
          
          // выключаем доступ по четным адресам к четным
          // слоям, а по нечетным адресам к нечетным слоям
          and     al,11101111
          out     dx,al
    
          // выбираем регистр смешанного назначения
          // графического контроллера
          dec     dx
          mov     al,MIR
          out     dx,al
    
          // считываем его значение
          inc     dx
          in      al,dx
    
          // сбрасываем бит управляющий сцеплением четных и
          // нечетных слоев
          and     al,11111101b
          out     dx,al
    
          // разрешаем запись днных во все четыре цветовых
          // слоя, записывая число 0fh в регистр разрешения
          // записи цветового слоя
    
          mov     dx,SC_INDEX
          mov     al,CPWER
          out     dx,al
    
          inc     dx
          mov     al,00001111b
          out     dx,al
    
          // очищаем первую страницу видеопамяти, так как
          // установка ржима 13h очищает только первые 64K
    
          mov     ax,VGA_SEGMENT
          mov     es,ax
    
          xor     di,di
          mov     ax,di
    
          mov     cx,8000h
          cld
          rep     stosb
    
          // выбираем регистр высоты символов текста
          // контроллера ЭЛТ
          mov     dx,CRTC_INDEX
          mov     al,MSLR
          out     dx,al
    
          inc     dx
          in      al,dx
    
          // запрещаем двойное сканирование
          and     al,01100000b
          out     dx,al
    
          // выбираем регистр положения подчеркивания
          // символа
          dec     dx
          mov     al,ULR
          out     dx,al
    
          // выключаем режим адресации видеопамяти по
          // двойным словам
          inc     dx
          in      al,dx
          and     al,10111111b
          out     dx,al
    
          // выбираем регистр управления режимом
          dec     dx
          mov     al,MCR
          out     dx,al
    
          // включаем байтовый режим адресации
          inc     dx
          in      al,dx
          or      al,01000000b
          out     dx,al
    
          pop     di
       }
    }
    
    
    
    
    /**
    *.Name    WritePixel
    *
    *.Title   Отображение пиксела.
    *
    *.Descr   Функция отображает на экране пиксел в заданных
    *      координатах,
    *         определенного цвета.
    *
    *.Proto   void WritePixel(unsigned x, unsigned y, unsigned
    *                char color)
    *
    *.Params  x - x-координата пиксела (0-319),
    *
    *         y - y-координата пиксела (0-399),
    *
    *         color - цвет пиксела (0-255).
    *
    *.Return  Не используетя.
    *
    *.Sample  e256mres.c
    **/
    
    void  WritePixel(unsigned x, unsigned y,
               unsigned char color) {
    
       _asm  {
    
          push    di
    
          mov     cx,x
          mov     dx,y
          mov     bl,color
    
          mov     ax,VGA_SEGMENT
          mov     es,ax
    
          mov     ax,( SCREEN_WIDTH / 4 )
          mul     dx
    
          push    cx
    
          shr     cx,1
          shr     cx,1
    
          add     ax,cx
          mov     di,ax
    
          pop     cx
    
          and     cl,3
          mov     ah,1
          shl     ah,cl
    
          mov     dx,SC_INDEX
          mov     al,CPWER
          out     dx,ax
    
          mov     es:[di],bl
    
          pop     di
       }
    }
    
    
    
    /**
    *.Name    ReadPixel
    *
    *.Title   Определение цвета пиксела.
    *
    *.Descr   Функция возвращает значение байта видеопамяти,
    *      определяющего пиксел 
    *         с заданными координатами.
    *
    *.Proto   unsigned char ReadPixel(unsigned x, unsigned y,
    *                       unsigned char color)
    *
    *.Params  x - x-координата пиксела (0-319),
    *
    *         y - y-координата пиксела (0-399).
    *
    *.Return  цвет пиксела (0-255).
    *
    *.Sample  e256mres.c
    **/
    
    unsigned char   ReadPixel( unsigned x, unsigned y ) {
    
       unsigned char  color;
    
       _asm  {
    
          push    si
    
          mov     cx,x
          mov     dx,y
    
          mov     ax,VGA_SEGMENT
          mov     es,ax
    
          mov     ax,( SCREEN_WIDTH / 4 )
          mul     dx
    
          push    cx
    
          shr     cx,1
          shr     cx,1
    
          add     ax,cx
          mov     si,ax
    
          pop     ax
    
          and     al,3
          mov     ah,al
    
          mov     dx,GC_INDEX
          mov     al,RPSR
          out     dx,ax
    
          mov     al,es:[si]
          mov     color,al
    
          pop     si
       }
    
       return( color );
    }
    
    
    /**
    *.Name    Full_Scr
    *
    *.Title   Закрашивает экран заданным цветом.
    *
    *.Proto   void Full_Scr( unsigned char color )
    *
    *.Params  color - цвет экрана (0-255).
    *
    *.Return  Не используетя.
    *
    *.Sample  e256mres.c
    **/
    
    void Full_Scr( unsigned char color ) {
    
       _asm {
    
          ;разрешаем запись данных во все четыре цветовых
          ;слоя
    
          push    di
    
          mov     dx,SC_INDEX
          mov     al,CPWER
          out     dx,al
    
          inc     dx
          mov     al,0fh
          out     dx,al
    
    
          mov     ax,VGA_SEGMENT
          mov     es,ax
    
          xor     di,di
          mov     al,color
    
          mov     cx,32000
          cld
          rep     stosb
    
          pop     di
       }
    }
    
    
    
    // функция LoadVGA256 загружает регистры таблицы цветов
    // цифро-аналогового преобразователя новыми значениями
    
    void LoadVGA256(void) {
    
       RGB color_table[256];
       unsigned char   i, j;
       unsigned char   far *ptr;
       unsigned seg_table,off_table;
    
    // записываем в массив color_table новые значения для
    // регистров таблицы цветов
    
       for(j = 0; j < 4; j++) {
          for(i = 0; i < 64; i++) {
             (color_table[i+j*64]).red = (j == 0) ? i : 0;
    
             (color_table[i+j*64]).green = 
                   (j == 1) ? i : (j == 3) ? i : 0;
    
             (color_table[i+j*64]).blue = 
                   (j == 2) ? i : (j == 3) ? i : 0;
          }
       }
    
       ptr = (unsigned char far*) &color_table[0];
    
    // определяем сегмент и смешение массива color_table
    
       seg_table = FP_SEG(ptr);
       off_table = FP_OFF(ptr);
    
    // загружаем новые значения в регистры таблицы цветов
    
       SetVgaDAC(seg_table,off_table);
    
    // функция SetVgaDAC загружает регистры таблицы цветов 
    // цифро-аналогового преобразователя
    // исходный текст функции приведен при описании регистра
    // данных таблицы цветов ЦАП VGA (файл vga256.c)
    }
    
    
    //
    //   главная функция
    //
    void main( void ){
    
       unsigned i;
       char ch = 13;
    
       struct videoconfig vc;
    
       // заполняем поля структуры vc
    
       printf("\n   (C) Frolov G.V., 1992 \n\n");
       _getvideoconfig( &vc );
    
       // завершаем программу если нет VGA адаптера
    
       if(vc.adapter != _VGA) {
          printf("Для выполнения программы необходим"
               " адаптер VGA.\n");
    
          exit(0);
       }
    
       // устанавливаем режим 320х400 пикселов, 256 цветов
    
       Set320x400Mode();
    
       // загружаем регистры ЦАП VGA
    
       LoadVGA256();
    
    
       for(i = 0; i < 400; i++)
          WritePixel(160, (unsigned) i,
                       (unsigned char) (i % 256) );
    
       for(i = 0; i < 320; i++)
          WritePixel((unsigned) i, 200,
                       (unsigned char) (i % 256) );
    
       ch = getch();
       if( ch == 27 ) exit(1);
    
       for(i = 0; i < 320; i++)
          WritePixel((unsigned) i, (unsigned) i,
                       (unsigned char) (i % 256) );
    
       ch = getch();
    
       for(i = 0; ((i < 256) && (ch != 27)); i++) {
          Full_Scr( (unsigned char) i );
          ch = getch();
       }
    
    
       // возвращаемся в текстовый режим
    
       _setvideomode(_DEFAULTMODE);
    
       printf("Привет всем!!!\n");
    }
    

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

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

    Ниже приведена программа, которая переводит видеоадаптер в нестрандартный режим с разрешением 360х480 пикселов:

    /**
    *      Файл    e256hres.c
    **/
    #include "sysp.h"
    #include "sysgraph.h"
    #include <dos.h>
    
    #include    <graph.h>
    #include    "vga_new.h"
    
    /**
    *.Name    Set360x480Mode
    *
    *.Title   Установка режима 360х480 пикселов, 256 цветов.
    *
    *.Proto   void Set360x480Mode( void )
    *
    *.Params  Не используются.
    *
    *.Return  Не используетя.
    *
    *.Sample  e256hres.c
    **/
    
    void    Set360x480Mode( void ) {
    
       _asm  {
    
       // устанавливаем режим 12h, чтобы очистить видеопамять
          mov     ax,12h
          int     10h
    
       // устанавливаем стандартный режим 13h 
          mov     ax,0013h
          int     10h
    
       // перепрограммируем регистр определения структуры
       //  памяти: запрещаем адресацию к разным слоям памяти в
       // зависимости от кратности адреса памяти четырем (бит
       // D4 - chain4)
          mov   dx,SC_INDEX
          mov   ax,0604h
          out   dx,ax
    
       // производим синхронный сброс и остановку
       // синхронизатора
          mov   ax,0100h
          out   dx,ax
    
       // адресуемся к регистру определения различных режимов
       // работы
          mov   dx,MOR
    
       // устанавливаем частоту кадров 60Кц
          mov   al,0e7h
          out   dx,al
    
       // запускаем синхронизатор
          mov   dx,SC_INDEX
          mov   ax,0300h
          out   dx,ax
    
    
       // выбираем регистр режима работы графического
       // контроллера
          mov     dx,GC_INDEX
          mov     al,MDR
          out     dx,al
    
       // считываем его значение
          inc     dx
          in      al,dx
    
       // выключаем доступ по четным адресам к четным слоям, а
       // по нечетным адресам к нечетным слоям
          and     al,11101111
          out     dx,al
    
       // выбираем регистр смешанного назначения графического
       // контроллера
          dec     dx
          mov     al,MIR
          out     dx,al
    
       // считываем его значение
          inc     dx
          in      al,dx
    
       // сбрасываем бит управляющий сцеплением четных и
       // нечетных слоев
          and     al,11111101b
          out     dx,al
    
    
       // выбираем регистр конца обратного вертикального хода
       // луча
          mov   dx,3d4h
          mov   al,11h
          out   dx,al
    
       // снимаем защиту от записи с регистров контроллера
       // ЭЛТ, имеющих индексы от 0 до 7
          inc   dx
          in    al,dx
          and   al,7fh
          out   dx,al
    
          dec   dx
    
       // программируем регистры контроллера ЭЛТ, втом числе
       // регистры, определяющие временные параметры режима
    
       // устанавливаем регистр общей длины линии
       // горизонтальной развертки
          mov   ax,06b00h
          out   dx,ax
    
       // устанавливаем регистр длины отображаемой части
       // горизонтальной развертки
          mov   ax,05901h
          out   dx,ax
    
       // устанавливаем регистр начала импульса гашения луча
       // горизонтальной развертки
          mov   ax,05a02h
          out   dx,ax
    
       // устанавливаем регистр конца импульса гашения луча
       // горизонтальной развертки
          mov   ax,08e03h
          out   dx,ax
    
       // устанавливаем регистр начала импульса
       // горизонтального обратного хода луча
          mov   ax,05e04h
          out   dx,ax
    
       // устанавливаем регистр конца импульса горизонтального
       // обратного хода луча
          mov   ax,08a05h
          out   dx,ax
    
       // устанавливаем регистр числа горизонтальных линий
       // растра
          mov   ax,0d06h
          out   dx,ax
    
       // устанавливаем дополнительный регистр
          mov   ax,03e07h
          out   dx,ax
    
       // устанавливаем регистр высоты символов текста
          mov   ax,04009h
          out   dx,ax
    
       // устанавливаем регистр начала обратного
       // вертикального хода луча
          mov   ax,0ea10h
          out   dx,ax
    
       // устанавливаем регистр конца обратного
       // вертикального хода луча
          mov   ax,0ac11h
          out   dx,ax
    
       // устанавливаем регистр начала гашения вертикальной
       // развертки
          mov   ax,0df12h
          out   dx,ax
    
       // устанавливаем регистр логической ширины экрана
          mov   ax,02d13h
          out   dx,ax
    
       // устанавливаем регистр положения подчеркивания
       // символа
          mov   ax,014h
          out   dx,ax
    
       // устанавливаем регистр начала импульса гашения
       // вертикальной развертки
          mov   ax,0e715h
          out   dx,ax
    
       // устанавливаем регистр конца импульса гашения
       // вертикальной развертки
          mov   ax,0616h
          out   dx,ax
    
       // устанавливаем регистр управления режимом
          mov   ax,0e317h
          out   dx,ax
       }
    }
    
    
    /**
    *.Name    WritePixel_H
    *
    *.Title   Отображение пиксела.
    *
    *.Descr   Функция отображает на экране пиксел в заданных
    *       координатах, определенного цвета.
    *
    *.Proto   void WritePixel_H(unsigned x, unsigned y, unsigned
    *                  char color)
    *
    *.Params  x - x-координата пиксела (0-319),
    *
    *         y - y-координата пиксела (0-399),
    *
    *         color - цвет пиксела (0-255).
    *
    *.Return  Не используетя.
    *
    *.Sample  e256hres.c
    **/
    
    void  WritePixel_H(unsigned x, unsigned y, 
                       unsigned char color) {
    
       _asm  {
    
          push    di
    
          mov     cx,x
          mov     dx,y
          mov     bl,color
    
    
          mov     ax,VGA_SEGMENT
          mov     es,ax
    
          mov     ax,( SCREEN_WIDTH_H / 4 )
          mul     dx
    
          push    cx
    
          shr     cx,1
          shr     cx,1
    
          add     ax,cx
          mov     di,ax
    
          pop     cx
    
          and     cl,3
          mov     ah,1
          shl     ah,cl
    
          mov     dx,SC_INDEX
          mov     al,CPWER
          out     dx,ax
    
          mov     es:[di],bl
    
          pop     di
       }
    }
    
    
    /**
    *.Name    ReadPixel_H
    *
    *.Title   Определение цвета пиксела.
    *
    *.Descr   Функция возвращает значение байта видеопамяти,
    *      определяющего пиксел с заданными координатами.
    *
    *.Proto   unsigned char ReadPixel_H(unsigned x, unsigned y,
                          unsigned char color)
    *
    *.Params  x - x-координата пиксела (0-319),
    *
    *         y - y-координата пиксела (0-399).
    *
    *.Return  цвет пиксела (0-255).
    *
    *.Sample  e256hres.c
    **/
    
    unsigned char   ReadPixel_H( unsigned x, unsigned y ) {
    
       unsigned char  color;
    
       _asm  {
    
          push    si
    
          mov     cx,x
          mov     dx,y
    
          mov     ax,VGA_SEGMENT
          mov     es,ax
    
          mov     ax,( SCREEN_WIDTH_H / 4 )
          mul     dx
    
          push    cx
    
          shr     cx,1
          shr     cx,1
    
          add     ax,cx
          mov     si,ax
    
          pop     ax
    
          and     al,3
          mov     ah,al
    
          mov     dx,GC_INDEX
          mov     al,RPSR
          out     dx,ax
    
          mov     al,es:[si]
          mov     color,al
    
          pop     si
       }
    
       return( color );
    }
    
    
    /**
    *.Name    Full_Scr_H
    *
    *.Title   Закрашивает экран заданным цветом.
    *
    *.Proto   void Full_Scr_H( unsigned char color )
    *
    *.Params  color - цвет экрана (0-255).
    *
    *.Return  Не используетя.
    *
    *.Sample  e256hres.c
    **/
    
    void Full_Scr_H( unsigned char color ) {
    
       _asm {
    
          push    di
    
          ;разрешаем запись данных во все четыре цветовых слоя
    
          mov     dx,SC_INDEX
          mov     al,CPWER
          out     dx,al
    
          mov     al,0fh
          out     dx,al
    
    
          mov     ax,VGA_SEGMENT
          mov     es,ax
    
          xor     di,di
          mov     al,color
    
          mov     cx,43200
          cld
          rep     stosb
    
          pop     di
       }
    }
    
    
    // функция LoadVGA256 загружает регистры таблицы цветов
    // цифро-аналогового преобразователя новыми значениями
    
    void LoadVGA256(void) {
    
       RGB color_table[256];
       unsigned char   i, j;
       unsigned char   far *ptr;
       unsigned seg_table,off_table;
    
    // записываем в массив color_table новые значения для
    // регистров таблицы цветов
    
       for(j = 0; j < 4; j++) {
          for(i = 0; i < 64; i++) {
             (color_table[i+j*64]).red = (j == 0) ? i : 0;
    
             (color_table[i+j*64]).green = 
                   (j == 1) ? i : (j == 3) ? i : 0;
    
             (color_table[i+j*64]).blue = 
                   (j == 2) ? i : (j == 3) ? i : 0;
          }
       }
    
       ptr = (unsigned char far*) &color_table[0];
    
    // определяем сегмент и смешение массива color_table
    
       seg_table = FP_SEG(ptr);
       off_table = FP_OFF(ptr);
    
    // загружаем новые значения в регистры таблицы цветов
    
       SetVgaDAC(seg_table,off_table);
    
    // функция SetVgaDAC загружает регистры таблицы цветов 
    // цифро-аналогового преобразователя
    // исходный текст функции приведен при описании регистра
    // данных таблицы цветов ЦАП VGA (файл vga256.c)
    }
    
    //
    //   главная функция
    //
    void main( void ){
    
       unsigned i;
       char ch = 13;
    
       struct videoconfig vc;
    
       // заполняем поля структуры vc
    
       printf("\n   (C) Frolov G.V., 1992\n\n");
       _getvideoconfig( &vc );
    
       // завершаем программу если нет VGA адаптера
    
       if(vc.adapter != _VGA) {
          printf("Для выполнения программы нобходим"
                " адаптер VGA\n");
          exit(0);
       }
    
    
       // устанавливаем режим 360х480 пикселов, 256 цветов
    
       Set360x480Mode();
    
       // загружаем регистры ЦАП VGA
    
       LoadVGA256();
    
       for(i = 0; i < 480; i++)
          WritePixel_H(180, (unsigned) i,
                      (unsigned char) (i % 256) );
    
       for(i = 0; i < 360; i++)
          WritePixel_H((unsigned) i, 240,
                      (unsigned char) (i % 256) );
    
       ch = getch();
       if( ch == 27 ) exit(1);
    
       for(i = 0; i < 360; i++)
          WritePixel_H((unsigned) i, (unsigned) i,
                   (unsigned char) (i % 256) );
    
       ch = getch();
    
       for(i = 0; ((i < 256) && (ch != 27)); i++) {
          Full_Scr_H( (unsigned char) i );
          ch = getch();
       }
    
    
       // возвращаемся в текстовый режим
    
       _setvideomode(_DEFAULTMODE);
    
       printf("Привет всем!!!\n");
    }
    
    
    
    
    
    [Назад] [Содеожание] [Дальше]