|
|
|
|
Соображения по установке и проверка наличия
Возможности EGA зависят от типа монитора и объема памяти на
плате EGA. Тип монитора определяет, какой видеорежим использовать
для графики или текста, а объем памяти EGA определяет число доступных цветов и страниц. Для Ваших программ очень важно узнать,
имеется ли в персональном компьютере в наличии EGA, до того, как
Вы попытаетесь ее использовать, а также тип применяемого монитора
и объем доступной памяти. Это делает программа, приведенная в
листинге 9-1. Для указания на структуру с информацией по EGA вызывается функция get_ega_info(&info). Байт 0х40:0х87 преобразует
информацию о конфигурации EGA, памяти и мониторе. Этот байт является одним из байтов состояния, которые EGA BIOS содержит для
внутреннего использования и обеспечения программ необходимой им
информацией.
Мы интересуемся битами 5 и 6, которые показывают полную память
EGA; битом 3, который показывает, является ли EGA активным дисплеем; и битом 1, который указывает тип используемого монитора.
Функция также вызывает один из новых вызовов BIOS EGA, альтернативную функцию 10, которая возвращает информацию EGA. EGA
вызывается помещением 0х12 в регистр АН и 0х10 в регистр BL, а
также использованием прерывания 10h. Вызов EGA BIOS содержит следующую информацию:
Возвращаемая информация о EGA
Результат: Int 0x10
Вызывается: AH = 0х12
для выбора альтернативных функций EGA
BL = 0x10
Альтернативная функция для информации EGA
Возвращает: BH = 0 = Цветной монитор
1 = Монохромный монитор
BL = Расшифрованная память EGA:
0 = 64К
1 = 128К
2 = 192К
3 = 256К
СН = Биты признаков
CL = Установки переключателей платы EGA
|
Так как BIOS персонального компьютера не использует видеофункцию 0х12, этот вызов может быть использован в качестве проверки наличия EGA.
BIOS персонального компьютера спокойно отклонит неизвестное ей прерывание 10h и не изменит состояния
регистров. Таким образом, если выходящие регистры не изменяются
вызовом или входящие регистры не соответствуют данным о байте информации EGA, значит EGA отсутствует. Если EGA имеется в наличии,
то тип используемого монитора определяется считыванием положения
установочных переключателей. Вы предполагаете, что пользователь
правильно установил переключатели и их положение соответствует
типу монитора.
После обнаружения EGA функция проведет тестирование системы
на наличие карты VGA. Большинство регистров EGA только записываемые, в то время как в VGA они являются считываемыми/записываемыми. Регистр
устанавливается в определенное значение и затем делается попытка считать это значение. Если считанный байт не
соответствует записанному, то имеющаяся карта - EGA, в противном
случае - VGA. Используемый регистр является регистром маски бита,
который далее будет детально рассмотрен.
Программа EGACHECK.C, приведенная в листинге 9-1, выполняет
проверку активной карты EGA. (В системе может присутствовать другая дисплейная карта. Если активна другая карта, то бит 3 байта
0х40:0х87 будет иметь значение 1). Если обнаружена активная карта
EGA, то сохраняется информация об установке.
Макрокоманда PEEK_BYTE(seg,off), представленная в листинге
9-1, позволяет выбирать байт из любого места памяти персонального
компьютера. Макрокоманда работает путем сдвига значения сегмента
влево на одно слово (16 бит) с последующим логическим сложением
бита смещения для формирования длинного прерывания. Это прерывание затем сбрасывается в указатель far.
Листинг 9-1. Программа EGACHECK.C
----------------------------------------------------------------
/* egacheck.c */
/* Проверяет наличие карты EGA или VGA */
/* При нахождении одной из них, информация сохраняется */
#include
#include
#include
#define PEEK_BYTE(seg,off) \
(*(char far *) ( (long)(seg)<<16 | (off) ) )
struct Ega_info /* для хранения информации о EGA */
{
char card ; /* для хранения типа карты */
char monitor ; /* для хранения типа монитора */
int memory ; /* объем памяти: 64, 128, 192, 256К */
char high_res_graphics ;
char text_mode ;
} ;
int get_ega_info(struct Ega_info *) ;
main()
{
struct Ega_info info ;
if(get_ega_info(&info)) /* тест на наличие EGA */
{
if(info.card == 'E')
{
printf("\n\nИспользуется EGA.") ;
printf("\nПодключена к") ;
switch(info.monit)
{
case 'C': puts(" цветному монитору") ;
break ;
case 'M': puts(" монохромному монитору") ;
break ;
case 'H': puts("усовершенствованному цветному монитору");
break ;
default: break ; /* не определен */
}
printf("n\%iK байт памяти EGA.", info.memory);
}
else
printf("\n\nИспользуется VGA.") ;
printf("\nРежим %#2i - графика с высоким разрешением.",
(int)info.high_res_graphics) ;
printf("\nРежим %#2i - текстовый режим.\n\n",
(int)info.text_mode) ;
}
else
puts("\nНет активного EGA.") ;
} /* конец main() */
int get_ega_info(info)
struct Ega_info *info ;
/* Эта функция проверяет, есть ли в системе активный EGA */
{
union REGS regs ;
int i, test_mask = 1 ;
/* Принять байт информации EGA из области данных BIOS */
char bios_info = PEEK_BYTE(0x40,0x87) ;
/* Бит 3 показывает, активный EGA или нет
* если нет, то проверить наличие */
if(bios_info & 0x8)
return (0) ; /* если бит 3 = 1, EGA не активный */
regs.h.ah = 0x12 ; /* альтернативная функция BIOS EGA */
regs.h.bl = 0x10 ; /* получить информацию */
regs.h.bh = 0xFF ; /* не возможное значение */
int86(0x10, ®s, ®s) ; /* видео вызов EGA BIOS */
/* bios_info биты 5 + 6 и BL(расшифрованная память EGA) и */
/* bios_info бит 1 и ВН должны быть равны для EGA */
if((regs.h.bl != ((bios_info & 0x60) >> 5 || /* память */
(regs.h.bh != ((bios_info & 0x2) >> 1 || /* монитор */
(regs.h.bh == 0xFF)) /* ВН должен изменить*/
/* EGA есть, сохранить тип монитора */
/* Код тип монитора:
'C' для цветного,
'M' для монохромного,
'H' для hercules */
switch(regs.h.cl) /* cl имеет установку переключателей EGA */
{
case 0: /* первоначально моно, EGA цветной 40х25 */
case 6: /* моно второй, EGA цветной 40х25 */
info->monitor = 'C' ;
info->high_res_graphics = 0xD ;
info->text_mode = 0x1 ;
break ;
case 1: /* первоначально моно, EGA цветной 80х25 */
case 2: /* то же, что 1 */
case 7: /* моно второй, EGA цветной 80х25 */
case 8: /* то же, что 7 */
info->monitor = 'C' ;
info->high_res_graphics = 0xE ;
info->text_mode = 0x3 ;
break ;
case 3: /* первоначально моно, EGA с высоким разрешением */
case 9: /* сначала EGA с высоким разрешением, потом моно */
info->monitor = 'H' ;
info->high_res_graphics = 0x10 ;
info->text_mode = 0x3 ;
break ;
case 4: /* сначала 40 цветной, EGA моно */
case 5: /* сначала 80 цветной, EGA моно */
case 10: /* сначала EGA моно, затем 40 цветной */
case 11: /* сначала EGA моно, затем 80 цветной */
info->monitor = 'M' ;
info->high_res_graphics = 0xF ;
info->text_mode = 0x7 ;
break ;
default: /* зарезервированные установки переключателей */
return (0) ;
}
info->memory = 64 * (regs.h.bl + 1) ;
/* Различить EGA и VGA: */
/* Это выполняется посредством записи значения в только
считываемый регистр в EGA, но считываемый/записываемый
в VGA */
outp(0x3CE, 8) ; /* маска бита EGA/VGA */
outp(0x3CF, test_mask) ; /* направить значение теста */
outp(0x3CE, 8) ; /* снова маска бита */
if(inp(0x3CF) == test_mask)
{
info->card = 'V' ; /* регистр можно считать */
if(info->monitor != 'M')
{
info->high_res_graphics = 0x12 ;
info->text_mode = 0x3 ;
}
/* Если подключено к монохромному, то значения уже
* установлены.
*/
}
else
info->card = 'E' ; /* EGA */
outp(0x3CE, 8) ; /* сбросить маску бита */
outp(0x3CF, 0xFF) ;
/* В этой системе активен EGA/VGA, вернуть память */
return(info->memory) ;
}
---------------------------------------------------------------
|
В новый заглавный файл, названный ega.h, должны быть добавлены прототип функции get_ega_info() и скелет структуры Ega_info.
Эти функция и скелет будут использованы в последующих примерах.
Теперь мы знаем, какой режим надо использовать для графики и
можем изобразить что-нибудь на дисплее. EGA BIOS, также как и
BIOS персонального компьютера имеет вызов Write Dot (писать точку). Этот вызов работает медленно, но очень полезен во всех графических картах IBM.
Вот некоторые характеристики вызова EGA BIOS
Write Dot:
Write Dot
Результат: Int 0x10
Вызывается: AН = 0хС для выбора функции Write Dot
BH = Страница
DX = Номер строки
СХ = Номер столбца
AL = Значение цвета
Возвращает: Ничего
|
Обратите внимание на добавление в ВН номера страницы. Если Вы
преобразуете старое программное обеспечение для работы с EGA, то
убедитесь, что номер страницы находится в ВН перед вызовом прерывания 10h. Программы, написанные для монохромного адаптера или
CGA в графическом режиме, наиболее чувствительны к этому недостатку.
Вызов BIOS для переключения в графический режим точно такой
же, как и функция 0 прерывания 10h персонального компьютера. Тем
не менее, BIOS не выполняет проверку на предмет того, не повредит
ли выбранный Вами режим Ваш монитор. Монохромный монитор, подключенный к EGA, может быть поврежден сигналом режима цветного текста или графики,
поэтому важно проверить совместимость монитора и
режима работы. В программе 9-1 функция get_ega_info(&info) используется для проверки монитора и нахождения безопасного в использовании режима
работы с высокой разрешающей способностью.
Программа, представленная в листинге 9-2, демонстрирует использование функции set_crt_mode() для установки графического режима и
использование dot(), которая применяет функцию BIOS Write Dot.
Эта программа начертит серию параллельных диагональных линий.
Листинг 9-2. Программа DIAGONAL.C
---------------------------------------------------------------
/* diagonal.c */
/* Демонстрирует графический режим с высоким разрешением */
#include
#include
#include
void set_crt_mode( char ) ; /* добавить это в "ega.h" */
void dot( int, int, int, int ) ;
main()
{
registr i,j ;
struct Ega_info info ;
if(get_ega_info(&info))
set_crt_mode(info.high_res_graphics);
else
return(1) ;
for(j = 0; j <= 500; j += 5)
for(i = 0; i <= 100; ++i)
dot(i,i+j,13,0) ;
getch() ; /* ожидать символ, который надо изобразить */
set_crt_mode(info.text_mode) ;
return(0) ;
}
/*==========================================================*/
void dot(row,col,color,page)
int row, col, color, page;
{
union REGS regs ;
regs.x.dx = row ;
regs.x.cx = col ;
regs.h.al = (char)color ;
regs.h.ah = (char)0xC ; /* Вызов Write Dot */
regs.h.bh = (char)page ;
int86(0x10, ®s, ®s) ;
}
/*==========================================================*/
void set_crt_mode(mode)
char mode ;
{
union REGS regs ;
regs.h.al = mode ; /* al = установить режим */
regs.h.ah = (char)0 ; /* Функция "установить режим" */
int86(0x10, ®s, ®s); /*Выполнить прерывание BIOS 10h*/
}
/*==========================================================*/
---------------------------------------------------------------
|
Как только Вы увидите, как медленно работает функция BIOS
Write Dot, то, вероятно, спросите, можно ли ускорить ее работу.
Реализация этого требует обхода EGA BIOS и помещения элементов
изображения непосредственно в память EGA. Тем не менее, сначала
Вы должны понять, каким образом организована память EGA, и то,
как можно ею управлять.
|
|