{$A+,B-,D-,E-,F-,G-,I-,L-,N-,O-,P-,Q-,R-,S-,T-,V-,X+,Y+} UNIT VGA; {============================================================================= Unit VGA Provides VGA specific functions. - VGA detection - Setting palette - Setting fonts & loading ... =============================================================================} {ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß} INTERFACE {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} CONST VGA_CRTC = $03D4; { Port address CRTC } VGA_STATUS = $03DA; { Port address for Status register } VGA_AC = $03C0; { Port address Attribute controller } VGA_AC_READ = $03C1; { Read address Attribute controller } VGA_SR = $03C4; { Port address Sequencer register } VGA_GC = $03CE; { Port address Graphics controller } VGA_PEL_WRITE = $03C8; { Port address PEL Address Write } VGA_PEL_READ = $03C7; { Port address PEL Address Read } VGA_PEL_DATA = $03C9; { Port address PEL Data register } FUNCTION VGA_IsPresent : BOOLEAN; PROCEDURE VGA_Mode (Mode : Byte); PROCEDURE VGA_SetPalette (StartColor, NumColors:Byte; VAR Palette); PROCEDURE VGA_SetFlatTextPal; PROCEDURE VGA_SetBlink (BlinkMode : BOOLEAN); PROCEDURE VGA_SetActiveFont (Font0, Font1 : Byte); PROCEDURE VGA_SetFontSize (FontSize:Byte); PROCEDURE VGA_SetFont (StartChar,NumChars, FontSize, VideoOffset : Word; VAR Font); PROCEDURE VGA_Set8PixelFont; {ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß} IMPLEMENTATION {ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ} { RETURN TRUE if VGA card is present } FUNCTION VGA_IsPresent : BOOLEAN; ASSEMBLER; ASM MOV AX,01A00h { Â> Display Combination Code } INT 10h { Ù } CMP AL,01Ah { Is AL=01Ah then it's a VGA } MOV AL,TRUE { Assume it'll be true } JE @Return { We were right, quit now } MOV AL,FALSE { We were wrong, return false } @Return: END; PROCEDURE VGA_Mode (Mode : Byte); ASSEMBLER; ASM MOV AH,0 MOV AL,Mode INT 10h END; PROCEDURE VGA_SetPalette (StartColor, NumColors:Byte; VAR Palette); ASSEMBLER; ASM PUSH DS { Save DS } MOV DX,VGA_PEL_WRITE { DX = Palette address register } MOV AL,[StartColor] { AL = First Color to set } OUT DX,AL { Activate StartColor } MOV AH,[NumColors] { Get number of colors to modify } CMP AH,0 { Is it Zero ? } JE @SetDone { Yes, we don't need to do anything} LDS SI,Palette { DS:SI points to palette data } CLD { Increment SI on LODSB } MOV DX,VGA_PEL_DATA { DX = Pallette data register } @SetColor: LODSB { Load RED } OUT DX,AL { Set RED } LODSB { Load GREEN } OUT DX,AL { Set Green } LODSB { LOAD BLUE } OUT DX,AL { Set BLUE } DEC AH { One color done } JNZ @SetColor { Need to do more ? } @SetDone: POP DS { Restore DS } END; PROCEDURE VGA_SetFlatTextPal; ASSEMBLER; ASM MOV DX,VGA_STATUS { CRTC Status register } IN AL,DX { Read CRTC Status. (This'll reset } { Attribute controller flip-flop) } { Set EGA palette to color 0-15 } MOV DX,VGA_AC { Attribute controller } MOV AL,0 { Color 0. (and Clears PAS field) } @NxtPalEGA: OUT DX,AL { Set paletteregister to change } OUT DX,AL { Set value for palette register } INC AL { Next color } CMP AL,0Fh { All colors done ? } JBE @NxtPalEGA { Nope. } MOV AL,20h OUT DX,AL { Set PAS field (Video has access } { to palette) } END; PROCEDURE VGA_SetBlink (BlinkMode : BOOLEAN); ASSEMBLER; ASM MOV DX,VGA_STATUS { CRTC Status register } IN AL,DX { Read CRTC Status. (This'll reset } { Attribute controller flip-flop) } { Set blink bit } MOV DX,VGA_AC { Attribute controller (Write port)} MOV AL,10h+20h { Register 10h (Mode control) } { leave PAS field enabled. } OUT DX,AL { Activate register 10h } MOV DX,VGA_AC_READ { DX=003C1h (Attribute READ port) } IN AL,DX { Read Mode control register } MOV DX,VGA_AC { DX=003C0h (Attribute Write port) } CMP [BlinkMode],TRUE { BlinkMode = TRUE ? } JE @SetBlinkBit { Yes jump to SetBlinkBit } @BlinkOff: AND AL,NOT 008h { Clear the Blink bit } JMP @SetBlinkBit { And go tell the VGA card } @BlinkOn: OR AL,008h { Clear the Blink bit } @SetBlinkBit: OUT DX,AL { Rewrite Mode control register } END; PROCEDURE VGA_SetActiveFont (Font0, Font1 : Byte); ASSEMBLER; ASM MOV DX,VGA_SR { Sequencer register } MOV AL,03 { Character Map Select } MOV BL,[Font0] { Prepare 'Font0' for Character } MOV BH,BL { Generator B } AND BL,003h AND BH,004h SHL BH,1 SHL BH,1 OR BL,BH MOV CL,[Font1] { Prepare 'Font1' for Character } MOV CH,CL { Generator A } AND CL,003h AND CH,004h SHL CH,1 OR CL,CH SHL CX,1 SHL CX,1 MOV AH,BL { Combine bits for Char Gen A and B } OR AH,CL { Ù } OUT DX,AX { And activate the requested Char } { maps } END; PROCEDURE VGA_SetFontSize (FontSize:Byte); ASSEMBLER; ASM MOV DX,VGA_CRTC { CRTC address register } MOV AL,9 { Index for Max Scanline Register } OUT DX,AL { set MSL as active register } INC DX { Set DX to CRTC Data register } IN AL,DX { read current MSL } AND AL,011100000b { set MSL to 0, preserve others bits} MOV AH,[FontSize] { get required size } DEC AH { minus one. } OR AL,AH { set size in MSL field } OUT DX,AL { Writeback modified value } END; PROCEDURE VGA_SetFont(StartChar, NumChars, FontSize, VideoOffset : Word; VAR Font); ASSEMBLER; ASM { === Switch VGA into linear/planar more, ready for receiving font data === } CLI { No interrupts allowed } MOV DX,VGA_SR { Sequencer register } MOV AX,0100h { Â> Synchronous reset } OUT DX,AX { Ù } MOV AX,0402h { Â> Select Plane 2 for WRITE } OUT DX,AX { Ù } MOV AX,0704h { Â> Sequential Addressing mode } OUT DX,AX { Ù } MOV AX,0300h { Â> Release Synchronous reset } OUT DX,AX { Ù } MOV DX,VGA_GC { Graphics controller register } MOV AX,0204h { Â> Select Plane 2 for READ } OUT DX,AX { Ù } MOV AX,0005h { Â> Disable odd addressing mode } OUT DX,AX { Ù } MOV AX,0006h { Â> Memory range is A000:0000 } OUT DX,AX { Ù } STI { Interrupts enabled } { === LOAD the font ======================================================= } MOV DI,[SegA000] { ¿ } MOV ES,DI { Ã> ES:DI -> Video Address where } MOV DI,[StartChar] { ³ to load font } SHL DI,1 { ³ } SHL DI,1 { ³ DS=VideoOffset + Offset for } SHL DI,1 { ³ starting at } SHL DI,1 { ³ } SHL DI,1 { ³ } ADD DI,[VideoOffset] { Ù } PUSH DS { Save DS } LDS SI,[Font] { DS:SI -> Font } MOV BX,[NumChars] { Number of characters to load } CMP BX,0 JE @DoneLoad { No characters to load, we're done } MOV AX,[FontSize] CLD { Increment pointers on MOVSB } MOV DX,32 { Â> DX= 32-FontSize (Size of gap in} SUB DX,AX { ³ between two videomemory } { Ù characters } @NextChar: MOV CX,AX { Copy FontSize in CX } REP MOVSB { Copy current character } ADD DI,DX { Skip gap in videomemory } DEC BX { One character done } JNZ @NextChar { Still more to do ? } @DoneLoad: POP DS { === Switch VGA back into normal textmode operation ====================== } CLI { No interrupts allowed. } MOV DX,VGA_SR { Sequence controller register } MOV AX,0100h { Â> Synchronous reset } OUT DX,AX { Ù } MOV AX,0302h { Â> Select Plane 0 & 1 for WRITE } OUT DX,AX { Ù } MOV AX,0304h { Â> Odd/Even Addressing mode } OUT DX,AX { Ù } MOV AX,0300h { Â> Release Synchronous reset } OUT DX,AX { Ù } MOV DX,VGA_GC { Graphics controller register } MOV AX,0004h { Â> Select Plane 0 for READ } OUT DX,AX { Ù } MOV AX,1005h { Â> Enable odd addressing mode } OUT DX,AX { Ù } MOV AX,0E06h { Â> Memory range is B800:0000 } OUT DX,AX { Ù } STI { Interrupts enabled } END; PROCEDURE VGA_Set8PixelFont; ASSEMBLER; ASM MOV DX,003CCh { Misc output register READ port } IN AL,DX { Read value. } AND AL,0F3h { Bits 2 & 3 off (Clock select 0). } MOV DX,003C2h { Misc Output Write port } OUT DX,AL { Writeback modified value } CLI { NO interrupts for a while } MOV DX,03C4h { Sequencer register } MOV AX,100h { \ Generate and hold Synchronous } OUT DX,AX { / reset } MOV AL,001h { Clocking mode register } OUT DX,AL { Activate Clocking mode register } INC DX { Data register } IN AL,DX { Read value } OR AL,1 { Set Bit 0 (8/9) } OUT DX,AL { Writeback. } DEC DX { Back to Address register } MOV AX,300h { \ Release Reset state. (normal) } OUT DX,AX { / } MOV DX,VGA_STATUS { CRTC Status register } IN AL,DX { Read CRTC Status. (This'll reset } { Attribute controller flip-flop) } MOV DX,VGA_AC { Attribute controller } MOV AL,13h { Horizontal Pixel Pan } OUT DX,AL { Activate HPP } MOV AL,0 { \ Set HPP to 0 } OUT DX,AL { / } MOV AL,20h OUT DX,AL { Set PAS field (Video has access } { to palette) } STI { Interrupts allowed again } END; END.