; Program to illustrate high-speed text-drawing operation of ; write mode 3 of the VGA. ; Draws a string of 8x14 characters at arbitrary locations ; without disturbing the background, using VGA's 8x14 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 14 ;# 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_COLOR equ 0fh ;high intensity white 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 8x14 font. ; mov ah,11h ;VGA BIOS character generator function, mov al,30h ; return info subfunction mov bh,2 ;get 8x14 font pointer int 10h call SelectFont ; ; Print the test string. ; mov si,offset TestString mov bx,TEST_TEXT_ROW mov cx,TEST_TEXT_COL mov ah,TEST_TEXT_COLOR call DrawString ; ; 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 string left-to-right in a linear ; graphics mode (0Dh, 0Eh, 0Fh, 010h, 012h) with 8-dot-wide ; characters. Background around the pixels that make up the ; characters is preserved. ; Font used should be pointed to by FontPointer. ; ; Input: ; AH = color to draw string in ; BX = row to draw string on ; CX = column to start string at ; DS:SI = string to draw ; ; Forces ALU function to "move". ; Forces write mode 3. ; DrawString proc near push ax push bx push cx push dx push si push di push bp push ds ; ; 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 mov dx,VGA_VIDEO_SEGMENT mov es,dx ;point to display memory ; ; Calculate screen address of byte character starts in. ; push ds ;point to BIOS data segment sub dx,dx mov ds,dx mov di,ds:[SCREEN_WIDTH_IN_BYTES] ;retrieve BIOS ; screen width pop ds mov ax,bx ;row 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 ; ; 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 all characters, left portion first, then right portion 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. ; ; Draw the left portion of each character in the string. ; pop cx ;get back screen width push si push di push bx ; ; Set the bit mask for the left half of the character. ; mov dx,GC_INDEX mov al,GC_BIT_MASK mov ah,bh out dx,ax LeftHalfLoop: lodsb and al,al jz LeftHalfLoopDone call CharacterUp inc di ;point to next character location jmp LeftHalfLoop LeftHalfLoopDone: pop bx pop di pop si ; ; Draw the right portion of each character in the string. ; inc di ;right portion of each character is across ; byte boundary ; ; Set the bit mask for the right half of the character. ; mov dx,GC_INDEX mov al,GC_BIT_MASK mov ah,bl out dx,ax RightHalfLoop: lodsb and al,al jz RightHalfLoopDone call CharacterUp inc di ;point to next character location jmp RightHalfLoop RightHalfLoopDone: ; pop ds pop bp pop di pop si pop dx pop cx pop bx pop ax ret DrawString endp ; ; Draw a character. ; ; Input: ; AL = character ; CX = screen width ; ES:DI = address to draw character at ; CharacterUp proc near push cx push si push di push ds ; ; Set DS:SI to point to font and ES to point to display memory. ; lds si,[FontPointer] ;point to font ; ; Calculate font address of character. ; mov bl,14 ;14 bytes per character mul bl add si,ax ;offset in font segment of character mov bp,FONT_CHARACTER_SIZE dec cx ; -1 because one byte per char CharacterLoop: 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 di pop si pop cx ret CharacterUp 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