Previous | Table of Contents | Next

LISTING 26.1 L26-1.ASM

    ; Program to illustrate operation of write mode 3 of the VGA.
    ;  Draws 8×8 characters at arbitrary locations without disturbing
    ;  the background, using VGA’s 8×8 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 640×480 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 8×8 font.
    ;
            mov     ah,11h          ;VGA BIOS character generator function,
            mov     al,30h          ; return info subfunction
            mov     bh,3            ;get 8×8 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

Previous | Table of Contents | Next

Graphics Programming Black Book © 2001 Michael Abrash