рицы (битовые массивы) защищены от изменения. Направление числа
между 0 и 15 в регистр маски матрицы запишет в битовые матрицы
EGA цвет, соответствующий этому числу. Тем не менее, прежнее со-
держание битовых массивов не стирается. Оно должно быть стерто
перед установкой нового значения цвета маски матрицы, но после
установки маски бита, записью нуля в байт, содержащий изменяемый
элемент изображения. Регистр маски матрицы является частью чипа
планировщика EGA. Он доступен посредством направления индекса 2 в
порт 0х3С4 и направлением маски матрицы в порт 0х3С5. Влияние
маски бита и маски матрицы проиллюстрировано на рисунке 9-2.
- 9-14 -
ЪД¬ ЪДВДВДВДВДВДВДВД¬ ЪДВДВДВДВДВДВДВДВДДДДДДДДДД¬
ЪДДґ1ГДДґ ¦ ¦1¦ ¦ ¦ ¦ ¦ ГДДДДДДДДДДДДДДґ ¦ ¦1¦ ¦ ¦ ¦ ¦ ¦ Битовая ¦
¦ АДЩ АДБДБДБДБДБДБДБДЩ ГДБДБДБДБДБДБДБДЩ матрица 3¦
¦ ЪД¬ ЪДВДВДВДВДВДВДВД¬ ЪД†ДВДВДВДВДВДВДВДДДДДДДДДД¬ ¦
ГДДґ1ГДДґ ¦ ¦1¦ ¦ ¦ ¦ ¦ ГДДДДДДДДДДДДґ ¦ ¦1¦ ¦ ¦ ¦ ¦ ¦ Битовая ¦ ¦
¦ АДЩ АДБДБДБДБДБДБДБДЩ ГДБДБДБДБДБДБДБДЩ матрица 2¦ ¦
¦ ЪД¬ ЪДВДВДВДВДВДВДВД¬ ЪД†ДВДВДВДВДВДВДВДДДДДДДДДД¬ ¦ ¦
ГДДґ0ГДДґ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ГДДДДДДДДДДґ ¦ ¦ ¦ ¦ ¦ ¦ ¦ ¦ Битовая ¦ ¦ ¦
¦ АДЩ АДБДБДБДБДБДБДБДЩ ГДБДБДБДБДБДБДБДЩ матрица 1¦ ¦ ¦
¦ ЪД¬ ЪДВДВДВДВДВДВДВД¬ ЪД†ДВДВДВДВДВДВДВДДДДДДДДДД¬ ¦ ¦ ¦
ГДДґ1ГДДґ ¦ ¦1¦ ¦ ¦ ¦ ¦ ГДДДДДДДДґ ¦ ¦1¦ ¦ ¦ ¦ ¦ ¦ Битовая ¦ ¦ ГДЩ
¦ АДЩ АДБДБДБДБДБДБДБДЩ ГДБДБДБДБДБДБДБДЩ матрица 0¦ ¦ ¦
АДДДДДДДДДДДДДД¬ ¦ ¦ ГДЩ
ЪДВБВДВДВДВДВДВД¬ ¦ ¦ ¦
¦0¦0¦1¦0¦0¦0¦0¦0¦ ¦ ГДЩ
АДБДБДБВБДБДБДБДЩ ¦ ¦
ЪДВДВДВБВДВДВДВД¬ АДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
¦1¦1¦1¦1¦1¦1¦1¦1¦
АДБДБДБДБДБДБДБДЩ
Рис.9-2. Регистры битовой маски и маски матрицы
Прямая запись на экран
Зная о регистрах маски бита и маски матрицы, а также о ре-
гистрах-защелках EGA, мы имеем достаточно информации для создания
программы на языке Си, которая пишет точку непосредственно в эк-
ранную память. Эта программа работает быстрее, чем аналогичная ей
программа BIOS адаптера EGA. При работе с 8-МГц персональным
компьютером АТ, EGA BIOS поместит на дисплей в течении 1 миллисе-
кунды 2.56 точки (2.56 точек/мс). Программа, представленная в
листинге 9-3, помещает на дисплей 7.55 точек/ мс - скорость воз-
растает на 185 процентов. Недостатком является то, что fastdot()
может работать только в графических режимах EGA, и для работы с
другой дисплейной картой необходимо переписать программу.
Следующие макрокоманды позволят программе 9-3 установить мас-
ку бита, маску матрицы, а также другие внутренние регистры.
#define EGA_GRFX(index, value) { outp(0X3CE, index) ; \
outp(0x3CF, value) ;}
#define EGA_SQNC(index, value) { outp(0X3C4, index) ; \
outp(0x3C5, value) ;}
Первая макрокоманда, EGA_GRFX, принимает в качестве аргумен-
тов номер индекса, соответствующего функции, выбранной из чипа
контроллера графики 1 и 2, а также значение, направляемое чипу.
Графические чипы 1 и 2 EGA управляют доступом к битовым массивам.
(Тем не менее, они реально представляют собой два чипа, располо-
женные по одному адресу, и могут считаться одним чипом.) Адрес
индекса графических чипов 1 и 2 0x3CE, а адрес данных 0x3CF. Мак-
рокоманда охватывает два оператора языка Си. Первый оператор по-
сылает чипам значение индекса, а второй оператор посылает данные.
Вторая макрокоманда, EGA_SQNC, сходна с EGA_GRFG. Однако,
- 9-15 -
EGA_SQNC имеет доступ к другому чипу, чипу планировщика EGA, нап-
равляя индекс и данные различным портам вывода. Наибольший инте-
рес для чипа планировщика представляет регистр маски матрицы.
Следующие две макрокоманды дают подпрограмме доступ к адресу
сегмент:смещение в любом месте адресного пространства персональ-
ного компьютера:
#define PEEK_BYTE(s,o) (*(char far *) ( (long)(s)<<16 | (o) ))
#define PEEK_WORD(s,o) (*(int far *) ( (long)(s)<<16 | (o) ))
Заключительные макрокоманды комбинируют предыдущие. Макроко-
манда GET_CRT_COLS() возвращает значение для использования в ка-
честве числа битов на линию в графических режимах EGA. Число би-
тов на линию равно числу символов на линию, и это число является
адресом 0x40:0x4A в области данных BIOS. Макрокоманды
EGA_BIT_MASK и EGA_MAP_MASK устанавливают соответственно регистры
маски бита и маски матрицы.
#define GET_CRT_COLS() PEEK_WORD(0x40, 0x4A)
#define EGA_BIT_MASK(mask) EGA_GRFX(8, mask)
#define EGA_MAP_MASK(mask) EGA_SQNC(2, mask)
Вместе эти макрокоманды облегчают чтение и понимание кодов
программы, написанной для манипулирования аппаратными средствами
EGA. Эти макрокоманды далее используются во всех программах этой
главы.
Большинство регистров EGA доступны только для записи. Каждая
программа, использующая дисплей, нуждается в информации о состоя-
нии EGA, так как только записываемые регистры нельзя считать. По-
этому, самым безопасным состоянием регистров EGA является состоя-
ние EGA BIOS, установленное по умолчанию. Кроме того, EGA BIOS
предполагает, что при записи символов на дисплей регистры EGA на-
ходятся в состоянии, установленном по умолчанию. Если регистр
маски бита установлен в состояние маскировки бита, символы будут
нечитаемыми. Для маски бита и маски матрицы состоянием, установ-
ленным по умолчанию, является выключенный режим маскировки, поэ-
тому, установка маски 0xF и 0xFF в последних двух строках
fastdot() восстанавливает состояние по умолчанию. Преимуществом
регистров VGA является то, что они доступны и для чтения и для
записи. (Различия между EGA и VGA были использованы в программе
EGACHECK.C для обнаружения карты VGA.) Поэтому, регистры VGA
должны быть оставлены в состоянии по умолчанию.
Убедитесь, что Вы понимаете, как вычисляется в программе,
приведенной в листинге 9-3, адрес байта элемента изображения:
char far *rgen = (char far *)(0xA0000000L +
(col >> 3) +
(row * GET_CRT_COLS()) );
Адрес бита вычисляется как ((строка х байты на строку) + столбцы
/ 8 бит на байт). В целях повышения скорости деления колонок на 8
используется оператор правого сдвига языка Си, >>.
Листинг 9-3. Программа FASTDOT.C
---------------------------------------------------------------
/* fastdot.c */
#include
- 9-16 -
fastdot(row, col, color)
/* Эта программа поместит точку в буфер дисплейной памяти EGA
** Использовать только в графических режимах EGA (13, 14, 15
** или 16) и с памятью EGA от 128К
** ИЛИ с VGA в режимах 13, 14, 15, 16, 17 или 18
*/
int row, col, color;
{
char latch ;
/* Установить адрес изменяемого байта */
/* Байт буфера = А000:((строка*байтов/строка)+столбец/8) */
unsigned char far *rgen = (char far *)(0xA0000000L +
(col >> 3) +
(row * GET_CRT_COLS()) ) ;
/* Вычислить изменяемый бит: */
char bit_mask = (char)(0x80 >> (col & 7)) ;
EGA_BIT_MASK(bit_mask) ; /* установить маску бита */
latch = *(rgen) ; /* подготовить защелки */
*(rgen) = 0 ; /* очистить бит */
EGA_MAP_MASK(color) ; /* установить цвет */
*(rgen) = 0xFF ; /* установить бит */
EGA_MAP_MASK(0xF) ; /* сбросить маску матрицы */
EGA_BIT_MASK(0xFF) ; /* сбросить маску бита */
}
---------------------------------------------------------------
Для того, чтобы узнать число бит на строку, значение которого мо-
жет быть равно 40 байтам в видеорежиме 13 или 80 байтам в режимах
с 14 по 16, посмотрите на значение числа символов на строку в об-
ласти данных BIOS (адрес 0х40:0х4A). Число бит на строку и число
символов на строку в графических режимах EGA одно и то же. Ре-
зультат всего вычисления добавляется к 0xA0000000L, представляю-
щим собой сегмент графических режимов EGA. Полное значение затем
сбрасывается в указатель far.
Номер бита в байте, соответствующем изменяемому элементу
изображения, вычисляется как (col~&~7). Как только будет известен
номер бита, маска бита устанавливается в значение 0х80 >> номер
бита (0х80 - это 010000000b).
Предыдущая программа предполагает, что используется страница
0. Для того, чтобы получить возможность адресации к странице, от-
личной от 0, вставьте следующие строки:
while(page){
rgen += PEEK_WORD(0x40, 0x4C) ; /* добавить длину страницы */
--page ;}
где page - номер адресуемой страницы. Слово по адресу 0х40:0х4С
содержит длину в байтах дисплейного буфера, используемого под-
программами EGA BIOS.
Испытайте программу, приведенную в листинге 9-2, заменив опе-
ратор dot оператором fastdot(). Она в два-три раза быстрее, чем
подпрограмма BIOS.
- 9-17 -
Много точек
Для достижения максимальной производительности уникальных ап-
паратных средств EGA необходимо написать много функций. Например,
подпрограмма fastdot() устанавливает маску бита и маску матрицы в
требуемые значения в начале, а затем в конце сбрасывает эти ре-
гистры в первоначальное состояние BIOS. Если функция вызывает
подпрограмму fastdot неоднократно, сброс регистра в конце fastdot
повторять необязательно. Это замедляет работу функции.
Программа, представленная в листинге 9-4, включает подпрог-
рамму вычерчивания линий, основанную на алгоритме Бресенгама.
Этот алгоритм первоначально использовался для управления цифровы-
ми плоттерами, но он также приемлем для дисплейной графики с би-
товыми матрицами. Алгоритм всегда увеличивается (или уменьшается)
на 1 в направлении или X или Y. Выбор направления X или Y осу-
ществляется увеличением наклона линии. Если подъем (направление
Y) больше, то увеличивается (или уменьшается) Y; если прогон
(направление X) больше, то увеличивается (или уменьшается) X.
Увеличение или уменьшение X или Y выбирается направлением линии.
Термин "совокупная ошибка" используется при увеличении или умень-