; Program to illustrate operation of write mode 3 of the VGA. ; Draws 8x8 characters at arbitrary locations without disturbing ; the background, using VGA's 8x8 ROM font. Designed ; for use with modes 0Dh, 0Eh, 0Fh, 10h, and 12h. ; Runs only on VGAs (in Models 50 & up and IBM Display Adapter ; and 100% compatibles). ; Assembled with MASM ; By Michael Abrash ; stack segment para stack 'STACK' db 512 dup(?) stack ends ; VGA_VIDEO_SEGMENT equ 0a000h ;VGA display memory segment SCREEN_WIDTH_IN_BYTES equ 044ah ;offset of BIOS variable FONT_CHARACTER_SIZE equ 8 ;# bytes in each font char ; ; VGA register equates. ; SC_INDEX equ 3c4h ;SC index register SC_MAP_MASK equ 2 ;SC map mask register index GC_INDEX equ 3ceh ;GC index register GC_SET_RESET equ 0 ;GC set/reset register index GC_ENABLE_SET_RESET equ 1 ;GC enable set/reset register index GC_ROTATE equ 3 ;GC data rotate/logical function ; register index GC_MODE equ 5 ;GC Mode register GC_BIT_MASK equ 8 ;GC bit mask register index ; dseg segment para common 'DATA' TEST_TEXT_ROW equ 69 ;row to display test text at TEST_TEXT_COL equ 17 ;column to display test text at TEST_TEXT_WIDTH equ 8 ;width of a character in pixels TestString label byte db 'Hello, world!',0 ;test string to print. FontPointer dd ? ;font offset dseg ends ; cseg segment para public 'CODE' assume cs:cseg, ds:dseg start proc near mov ax,dseg mov ds,ax ; ; Select 640x480 graphics mode. ; mov ax,012h int 10h ; ; Set the screen to all blue, using the readability of VGA registers ; to preserve reserved bits. ; mov dx,GC_INDEX mov al,GC_SET_RESET out dx,al inc dx in al,dx and al,0f0h or al,1 ;blue plane only set, others reset out dx,al dec dx mov al,GC_ENABLE_SET_RESET out dx,al inc dx in al,dx and al,0f0h or al,0fh ;enable set/reset for all planes out dx,al mov dx,VGA_VIDEO_SEGMENT mov es,dx ;point to display memory mov di,0 mov cx,8000h ;fill all 32k words mov ax,0ffffh ;because of set/reset, the value ; written actually doesn't matter rep stosw ;fill with blue ; ; Set driver to use the 8x8 font. ; mov ah,11h ;VGA BIOS character generator function, mov al,30h ; return info subfunction mov bh,3 ;get 8x8 font pointer int 10h call SelectFont ; ; Print the test string, cycling through colors. ; mov si,offset TestString mov bx,TEST_TEXT_ROW mov cx,TEST_TEXT_COL mov ah,0 ;start with color 0 StringOutLoop: lodsb and al,al jz StringOutDone push ax ;preserve color call DrawChar pop ax ;restore color inc ah ;next color and ah,0fh ;colors range from 0 to 15 add cx,TEST_TEXT_WIDTH jmp StringOutLoop StringOutDone: ; ; Wait for a key, then set to text mode & end. ; mov ah,1 int 21h ;wait for a key mov ax,3 int 10h ;restore text mode ; ; Exit to DOS. ; mov ah,4ch int 21h Start endp ; ; Subroutine to draw a text character in a linear graphics mode ; (0Dh, 0Eh, 0Fh, 010h, 012h). Background around the pixels that ; make up the character is preserved. ; Font used should be pointed to by FontPointer. ; ; Input: ; AL = character to draw ; AH = color to draw character in (0-15) ; BX = row to draw text character at ; CX = column to draw text character at ; ; Forces ALU function to "move". ; Forces write mode 3. ; DrawChar proc near push ax push bx push cx push dx push si push di push bp push ds push ax ;preserve character to draw in AL ; ; Set up set/reset to produce character color, using the readability ; of VGA register to preserve the setting of reserved bits 7-4. ; mov dx,GC_INDEX mov al,GC_SET_RESET out dx,al inc dx in al,dx and al,0f0h and ah,0fh or al,ah out dx,al ; ; Select write mode 3, using the readability of VGA registers ; to leave bits other than the write mode bits unchanged. ; mov dx,GC_INDEX mov al,GC_MODE out dx,al inc dx in al,dx or al,3 out dx,al ; ; Set DS:SI to point to font and ES to point to display memory. ; lds si,[FontPointer] ;point to font mov dx,VGA_VIDEO_SEGMENT mov es,dx ;point to display memory ; ; Calculate screen address of byte character starts in. ; pop ax ;get back character to draw in AL push ds ;point to BIOS data segment sub dx,dx mov ds,dx xchg ax,bx mov di,ds:[SCREEN_WIDTH_IN_BYTES] ;retrieve BIOS ; screen width pop ds mul di ;calculate offset of start of row push di ;set aside screen width mov di,cx ;set aside the column and cl,0111b ;keep only the column in-byte address shr di,1 shr di,1 shr di,1 ;divide column by 8 to make a byte address add di,ax ;and point to byte ; ; Calculate font address of character. ; sub bh,bh shl bx,1 ;assumes 8 bytes per character; use shl bx,1 ; a multiply otherwise shl bx,1 ;offset in font of character add si,bx ;offset in font segment of character ; ; Set up the GC rotation. In write mode 3, this is the rotation ; of CPU data before it is ANDed with the Bit Mask register to ; form the bit mask. Force the ALU function to "move". Uses the ; readability of VGA registers to leave reserved bits unchanged. ; mov dx,GC_INDEX mov al,GC_ROTATE out dx,al inc dx in al,dx and al,0e0h or al,cl out dx,al ; ; Set up BH as bit mask for left half, BL as rotation for right half. ; mov bx,0ffffh shr bh,cl neg cl add cl,8 shl bl,cl ; ; Draw the character, left half first, then right half in the ; succeeding byte, using the data rotation to position the character ; across the byte boundary and then using write mode 3 to combine the ; character data with the bit mask to allow the set/reset value (the ; character color) through only for the proper portion (where the ; font bits for the character are 1) of the character for each byte. ; Wherever the font bits for the character are 0, the background ; color is preserved. ; Does not check for case where character is byte-aligned and ; no rotation and only one write is required. ; mov bp,FONT_CHARACTER_SIZE mov dx,GC_INDEX pop cx ;get back screen width dec cx dec cx ; -2 because do two bytes for each char CharacterLoop: ; ; Set the bit mask for the left half of the character. ; mov al,GC_BIT_MASK mov ah,bh out dx,ax ; ; Get the next character byte & write it to display memory. ; (Left half of character.) ; mov al,[si] ;get character byte mov ah,es:[di] ;load latches stosb ;write character byte ; ; Set the bit mask for the right half of the character. ; mov al,GC_BIT_MASK mov ah,bl out dx,ax ; ; Get the character byte again & write it to display memory. ; (Right half of character.) ; lodsb ;get character byte mov ah,es:[di] ;load latches stosb ;write character byte ; ; Point to next line of character in display memory. ; add di,cx ; dec bp jnz CharacterLoop ; pop ds pop bp pop di pop si pop dx pop cx pop bx pop ax ret DrawChar endp ; ; Set the pointer to the font to draw from to ES:BP. ; SelectFont proc near mov word ptr [FontPointer],bp ;save pointer mov word ptr [FontPointer+2],es ret SelectFont endp ; cseg ends end start