Referát PZ - VGA Rudolf Marek K laboratorní uloze stačilo přidat několik procedur tak aby bylo docíleno požadované funkce. Jakmile byla implementována rutina putpixel/getpixel dalo se po obrazovce kreslit již standartním způsobem. Dříve než uvedu požadované funkce a procedury chtěl bych zmínit možnost řešení úlohy pod operačním systémem LINUX. Prvním problémem co jsem musel vyřešit byl přístup k I/O portům počítače. Zajistit ho můžeme systémovým voláním ioperm a iopl. Režim 640x480x16 by šel nastavit i přímým přeprogramováním VGA adaptéru ovšem pod linuxem lze zpětně namapovat ROM BIOS a použít int 0x10. zajišťuje to knihova LRMI, která je součástí balíku svgalib. Poslední podmínkou chodu bylo uzamčení přepínání konzole tak aby se nám ve VGA nikdo nevrtal. ioctl(0, KDSETMODE, KD_GRAPHICS); Celý kód vypadá takto: /* This program is in the public domain. */ #include #include #include #include #include #include #include #include "lrmi.h" #include "vbe.h" void set_reg(int kam,int co) { outb(kam,0x3CE); outb(co,0x3CF); } void put_pixbit(int x, int y,int c) { int addr,bit; char *p = (char *)(0xA0000); addr=(y*80) + (x >> 3); bit=0x80 >> (x & 7); set_reg(5,2); //mode set_reg(8,bit); //bitmask p+=addr; *p = *p; *p=(char) c; } void putpixel(int x,int y,int c) { } struct { struct vbe_info_block *info; struct vbe_mode_info_block *mode; } vbe; void text_mode(void) { struct LRMI_regs r; memset(&r, 0, sizeof(r)); r.eax = 3; if (!LRMI_int(0x10, &r)) { fprintf(stderr, "Can't set text mode (vm86 failure)\n"); } } void set_mode(void) { struct LRMI_regs r; char *p = (char *)(0xA0000); int i; memset(&r, 0, sizeof(r)); r.eax = 0x12; if (!LRMI_int(0x10, &r)) { fprintf(stderr, "Can't set video mode (vm86 failure)\n"); } memset(&r, 0, sizeof(r)); { int x,y,c; for (c=0;c<16;c++) for (y=0;y<480;y++) for (x=0;x<640;x++) put_pixbit(x,y,c); } } int main(void) { struct LRMI_regs r; short int *mode_list; void *state; if (!LRMI_init()) return 1; /* Allow read/write to all IO ports */ ioperm(0, 0x400 , 1); iopl(3); memset(&r, 0, sizeof(r)); ioctl(0, KDSETMODE, KD_GRAPHICS); if (state == NULL) return 1; set_mode(); // sleep(5); getchar(); text_mode(); ioctl(0, KDSETMODE, KD_TEXT); return 0; } Následuje řešení v Pascalu: procedure PutPixel( x, y: word; color: byte ); var offset : word; bitmask : byte; begin offset := y * (SizeX div 8) + (x div 8); bitmask := $80 shr ( x and 7 ); SetReg( ModeRegister, 0 ); SetReg( BitMaskReg, bitmask ); SetReg( DataRotate, 0 ); SetReg( SetReset, color ); SetReg( EnableSetReset, $ff ); screen[offset] := screen[offset]; end; procedure PutBitmap2(x,y:word; color:byte); var offset : word; i : integer; bitmask : byte; begin offset := y * (SizeX div 8) + (x div 8); { timto ziskam tu cast z prvniho bytu, kterou je treba vybarvit } bitmask := $ff shr (x and 7); SetReg( ModeRegister, 0 ); SetReg( DataRotate, 0 ); SetReg( SetReset, color ); SetReg( BitMaskReg, bitmask ); SetReg( EnableSetReset, $0f ); screen[offset] := screen[offset]; { pomoci operace not ziskam cast v druhem bajtu, tyto jsou navzajem disjunktni } SetReg( BitMaskReg, not bitmask ); screen[offset + 1] := screen[offset + 1]; end; function GetPixel(x,y : word):byte; var bitmask : byte; offset : word; color, rovina, pom : byte; begin color := 0; bitmask := $80 shr (x and 7); offset := y * (SizeX div 8) + (x div 8); SetReg( ModeRegister, 0 ); SetReg( DataRotate, 0 ); for rovina := 0 to 3 do begin SetReg( ReadMapSelect, rovina ); pom := screen[offset]; { takto si postupne skladam barvu } if (pom and bitmask) <> 0 then color := color + (1 shl rovina); end; GetPixel := color; end;