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


Режим 320х400 пикселов, 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"); }









Начало  Назад  Вперед