Работа адаптеров CGA/EGA в графическом режиме
Адаптер CGA всегда располагается в видеопамяти по адресу 8000000h. Адаптер EGA имеет аналогичное расположение для тех режимов, которые совместимы с режимами CGA (более полную информацию о аппаратных средствах поддержки графики вы можете получить в руководстве "IBM Technical Reference"). В 4 графическом режиме каждый байт содержит информацию о цвете для 4 точек растра (для каждой точки растра по 2 бита). Следовательно, для работы с экраном размерностью 320 на 200 требуется 16К памяти. Так как два бита могут содержать только 4 различных значения, в 4 видеорежиме поддерживаются только 4 цвета. Значение каждого двухбитового блока определяет цвет в соответствии с таблицей, приведенной ниже:
Значение
Цвет в палитре
0
Цвет в палитре
1
1
2
3
фон
желтый
красный
зеленый
фон
голубой
пурпурный
булый
Особенность адаптера CGA заключается в том, что четные точки растра будут располагаться по адресу B8000000h, а нечетные - на 2000h (8152 - в десятичном виде) байтов выше, т.е. по адресу B8002000h. Следовательно, каждая строка точек растра требует 80 байтов (40 для четных точек растра, 40 - для нечетных). Внутри каждого байта точки располагаются слева направо, как они появляются на экране терминала. Это означает, что точка растра с номером 0 занимает 6 и 7 биты, в то время, как точка растра с номером 3 - 0 и 1 биты.
Так как каждый байт кодирует значение четырех точек растра, вы должны сохранять значение трех точек при изменении одной из них. Лучший способ сделать это - создание битовой маски со всеми битами, установленными в 1, кроме тех, которые будут изменяться. Значение битовой маски складывается по схеме "И" с действительным значением байта, а затем полученное значение складывается по схеме "ИЛИ" с новым значением. Однако ситуация несколько меняется, если вы хотите сложить по схеме "НЕ-ИЛИ" новое и старое значения. В этом случае вы просто складываете по схеме "ИЛИ" старое значение байта с 0, а затем складываете по схеме "НЕ-ИЛИ" новое двоичное представление цвета и получаете результат. Адрес требуемого байта определяется путем умножения значения координаты X на 40, а затем добавляется значение координаты Y, деленное на
4. Для того, чтобы определить, находится ли точка растра в четном или нечетном блоке памяти, используется остаток от деления значения координаты Х на 2. Если остаток равен 0, блок является четным (используется первый блок), в противном случае - блок нечетный (используется второй блок). Требуемые биты внутри байта вычисляются путем выполнения деления по модулю 4. Остаток
определяет номер двухбитового пакета, который содержит информацию о требуемых точках растра. Для установки байта режима цвета и битовой маски используются операторы побитового сдвига. Хотя манипулирование битами в функции mempoint() несколько запутано, вы, однако, без труда разберетесь в ней, если тщательно изучите что именно и как она делает.
/* Запись точки в CGA/EGA */
void mempoint(x,y,color_code)
int x,y,color_code;
union mask
char c[2];
int i;
bit_mask;
int i,index,bit_position;
unsigned char t;
char xor; /* "НЕ-ИЛИ" цвета в случае его изменения */
char far *ptr=(char far *) 0xB8000000; /* точка в памяти CGA */
bit_mask.i=0xFF3F; /* 11111111 00111111 в двоичном коде */
if (x<0 || x>199 || y<0 || y>319) return;
xor=color_code & 128; /* проверка, устанавливался ли
режим "НЕ-ИЛИ" */ color_code=color_code & 127; /* маска старших битов */
/* установка битовой маски и битов режима цвета
в правую позицию */
bit_position=y%4; /* вычисление нужной позиции
в байте */ color_code<<=2*(3-bit_position); /* сдвиг кода цвета
в нужную позицию */ bit_mask.i>>=2*bit_position; /* сдвиг битовой маски в
нужную позицию */
/* определение требуемого байта в памяти терминала */
index=x*40+(y%4);
if (x%2) index+=8152; /* если нечетный, используется
второй блок */
/* запись цвета */
if (!xor) /* режим изменения цвета */
t=*(ptr+index) & bit_mask.c[0];
*(ptr+index)=t|color_code;
else
t=*(ptr+index) | (char)0;
*(ptr+index)=t & color_code;
Заметим, что тип указателя видеопамяти объявлен как far; это необходимо, если вы транслируете в модели маленькой (small) памяти. Вы так же должны заметить, что специальный маркер режима записи XOR, определенный в функциях ROM-BIOS, используется и в функции mempoint().