Previous | Table of Contents | Next

LISTING 24.1 L24-1.ASM

    ; Program to illustrate operation of ALUs and latches of the VGA’s
    ;  Graphics Controller.  Draws a variety of patterns against
    ;  a horizontally striped background, using each of the 4 available
    ;  logical functions (data unmodified, AND, OR, XOR) in turn to combine
    ;  the images with the background.
    ; By Michael Abrash.
    ;
    stack   segment para stack ‘STACK’
            db      512 dup(?)
    stack   ends
    ;
    VGA_VIDEO_SEGMENT       equ     0a000h  ;VGA display memory segment
    SCREEN_HEIGHT           equ     350
    SCREEN_WIDTH_IN_BYTES   equ     80
    DEMO_AREA_HEIGHT        equ     336     ;# of scan lines in area
                                            ; logical function operation
                                            ; is demonstrated in
    DEMO_AREA_WIDTH_IN_BYTES equ    40      ;width in bytes of area
                                            ; logical function operation
                                            ; is demonstrated in
    VERTICAL_BOX_WIDTH_IN_BYTES equ 10      ;width in bytes of the box used to
                                            ; demonstrate each logical function
    ;
    ; VGA register equates.
    ;
    GC_INDEX        equ     3ceh    ;GC index register
    GC_ROTATE       equ     3       ;GC data rotate/logical function
                                    ; register index
    GC_MODE         equ     5       ;GC mode register index
    ;
    dseg    segment para common ‘DATA’
    ;
    ; String used to label logical functions.
    ;
    LabelString     label   byte
            db      ‘UNMODIFIED    AND       OR        XOR   ’
    LABEL_STRING_LENGTH     equ     $-LabelString
    ;
    ; Strings used to label fill patterns.
    ;
    FillPatternFF   db      ‘Fill Pattern: 0FFh’
    FILL_PATTERN_FF_LENGTH  equ     $ - FillPatternFF
    FillPattern00   db      ‘Fill Pattern: 000h’
    FILL_PATTERN_00_LENGTH  equ     $ - FillPattern00
    FillPatternVert db      ‘Fill Pattern: Vertical Bar’
    FILL_PATTERN_VERT_LENGTH        equ     $ - FillPatternVert
    FillPatternHorz db      ‘Fill Pattern: Horizontal Bar’
    FILL_PATTERN_HORZ_LENGTH equ    $ - FillPatternHorz
    ;
    dseg    ends
    ;
    ; Macro to set indexed register INDEX of GC chip to SETTING.
    ;
    SETGC   macro   INDEX, SETTING
            mov     dx,GC_INDEX
            mov     ax,(SETTING SHL 8) OR INDEX
            out     dx,ax
            endm
    ;
    ;
    ; Macro to call BIOS write string function to display text string
    ;  TEXT_STRING, of length TEXT_LENGTH, at location ROW,COLUMN.
    ;
    TEXT_UP macro   TEXT_STRING, TEXT_LENGTH, ROW, COLUMN
            mov     ah,13h                  ;BIOS write string function
            mov     bp,offset TEXT_STRING   ;ES:BP points to string
            mov     cx,TEXT_LENGTH
            mov     dx,(ROW SHL 8) OR COLUMN        ;position
            sub     al,al           ;string is chars only, cursor not moved
            mov     bl,7            ;text attribute is white (light gray)
            int     10h
            endm
    ;
    cseg    segment para public ‘CODE’
            assume  cs:cseg, ds:dseg
    start   proc    near
            mov     ax,dseg
            mov     ds,ax
    ;
    ; Select 640x350 graphics mode.
    ;
            mov     ax,010h
            int     10h
    ;
    ; ES points to VGA memory.
    ;
            mov     ax,VGA_VIDEO_SEGMENT
            mov     es,ax
    ;
    ; Draw background of horizontal bars.
    ;
            mov     dx,SCREEN_HEIGHT/4
                                    ;# of bars to draw (each 4 pixels high)
            sub     di,di           ;start at offset 0 in display memory
            mov     ax,0ffffh       ;fill pattern for light areas of bars
            mov     bx,DEMO_AREA_WIDTH_IN_BYTES / 2 ;length of each bar
            mov     si,SCREEN_WIDTH_IN_BYTES - DEMO_AREA_WIDTH_IN_BYTES
            mov     bp,(SCREEN_WIDTH_IN_BYTES * 3) - DEMO_AREA_WIDTH_IN_BYTES
    BackgroundLoop:
            mov     cx,bx           ;length of bar
        rep stosw                   ;draw top half of bar
            add     di,si           ;point to start of bottom half of bar
            mov     cx,bx           ;length of bar
        rep stosw                   ;draw bottom half of bar
            add     di,bp           ;point to start of top of next bar
            dec     dx
            jnz     BackgroundLoop
    ;
    ; Draw vertical boxes filled with a variety of fill patterns
    ;  using each of the 4 logical functions in turn.
    ;
            SETGC   GC_ROTATE, 0            ;select data unmodified
                                            ; logical function...
            mov     di,0
            call    DrawVerticalBox         ;...and draw box
    ;
            SETGC   GC_ROTATE, 08h          ;select AND logical function...
            mov     di,10
            call    DrawVerticalBox         ;...and draw box
    ;
            SETGC   GC_ROTATE, 10h          ;select OR logical function...
            mov     di,20
            call    DrawVerticalBox         ;...and draw box
    ;
            SETGC   GC_ROTATE, 18h          ;select XOR logical function...
            mov     di,30
            call    DrawVerticalBox         ;...and draw box
    ;
    ; Reset the logical function to data unmodified, the default state.
    ;
            SETGC   GC_ROTATE, 0
    ;
    ; Label the screen.
    ;
            push    ds
            pop     es      ;strings we’ll display are passed to BIOS
                            ; by pointing ES:BP to them
    ;
    ; Label the logical functions, using the VGA BIOS’s
    ;  write string function.
    ;
            TEXT_UP LabelString, LABEL_STRING_LENGTH, 24, 0
    ;
    ; Label the fill patterns, using the VGA BIOS’s
    ;  write string function.
    ;
            TEXT_UP FillPatternFF, FILL_PATTERN_FF_LENGTH, 3, 42
            TEXT_UP FillPattern00, FILL_PATTERN_00_LENGTH, 9, 42
            TEXT_UP FillPatternVert, FILL_PATTERN_VERT_LENGTH, 15, 42
            TEXT_UP FillPatternHorz, FILL_PATTERN_HORZ_LENGTH, 21, 42
    ;
    ; Wait until a key’s been hit to reset screen mode & exit.
    ;
    WaitForKey:
            mov     ah,1
            int     16h
            jz      WaitForKey
    ;
    ; Finished.  Clear key, reset screen mode and exit.
    ;
    Done:
            mov     ah,0    ;clear key that we just detected
            int     16h
    ;
            mov     ax,3    ;reset to text mode
            int     10h
    ;
            mov     ah,4ch  ;exit to DOS
            int     21h
    ;
    start   endp
    ;
    ; Subroutine to draw a box 80x336 in size, using currently selected
    ;  logical function, with upper left corner at the display memory offset
    ;  in DI.  Box is filled with four patterns.  Top quarter of area is
    ;  filled with 0FFh (solid) pattern, next quarter is filled with 00h
    ;  (empty) pattern, next quarter is filled with 33h (double pixel wide
    ;  vertical bar) pattern, and bottom quarter is filled with double pixel
    ;  high horizontal bar pattern.
    ;
    ; Macro to draw a column of the specified width in bytes, one-quarter
    ;  of the height of the box, with the specified fill pattern.
    ;
    DRAW_BOX_QUARTER        macro   FILL, WIDTH
            local   RowLoop, ColumnLoop
            mov     al,FILL                 ;fill pattern
            mov     dx,DEMO_AREA_HEIGHT / 4 ;1/4 of the full box height
    RowLoop:
            mov     cx,WIDTH
    ColumnLoop:
            mov     ah,es:[di]      ;load display memory contents into
                                    ; GC latches (we don’t actually care
                                    ; about value read into AH)
            stosb                   ;write pattern, which is logically
                                    ; combined with latch contents for each
                                    ; plane and then written to display
                                    ; memory
            loop    ColumnLoop
            add     di,SCREEN_WIDTH_IN_BYTES - WIDTH
                                    ;point to start of next line down in box
            dec     dx
            jnz     RowLoop
            endm
    ;
    DrawVerticalBox proc    near
            DRAW_BOX_QUARTER        0ffh, VERTICAL_BOX_WIDTH_IN_BYTES
                                            ;first fill pattern: solid fill
            DRAW_BOX_QUARTER        0, VERTICAL_BOX_WIDTH_IN_BYTES
                                            ;second fill pattern: empty fill
            DRAW_BOX_QUARTER        033h, VERTICAL_BOX_WIDTH_IN_BYTES
                                            ;third fill pattern: double-pixel
                                            ; wide vertical bars
            mov     dx,DEMO_AREA_HEIGHT / 4 / 4
                                    ;fourth fill pattern: horizontal bars in
                                    ; sets of 4 scan lines
            sub     ax,ax
            mov     si,VERTICAL_BOX_WIDTH_IN_BYTES  ;width of fill area
    HorzBarLoop:
            dec     ax              ;0ffh fill (smaller to do word than byte DEC)
            mov     cx,si           ;width to fill
    HBLoop1:
            mov     bl,es:[di]      ;load latches (don’t care about value)
            stosb                   ;write solid pattern, through ALUs
            loop    HBLoop1
            add     di,SCREEN_WIDTH_IN_BYTES - VERTICAL_BOX_WIDTH_IN_BYTES
            mov     cx,si           ;width to fill
    HBLoop2:
            mov     bl,es:[di]      ;load latches
            stosb                   ;write solid pattern, through ALUs
            loop    HBLoop2
            add     di,SCREEN_WIDTH_IN_BYTES - VERTICAL_BOX_WIDTH_IN_BYTES
            inc     ax              ;0 fill (smaller to do word than byte DEC)
            mov     cx,si           ;width to fill
    HBLoop3:
            mov     bl,es:[di]      ;load latches
            stosb                   ;write empty pattern, through ALUs
            loop    HBLoop3
            add     di,SCREEN_WIDTH_IN_BYTES - VERTICAL_BOX_WIDTH_IN_BYTES
            mov     cx,si           ;width to fill
    HBLoop4:
            mov     bl,es:[di]      ;load latches
            stosb                   ;write empty pattern, through ALUs
            loop    HBLoop4
            add     di,SCREEN_WIDTH_IN_BYTES - VERTICAL_BOX_WIDTH_IN_BYTES
            dec     dx
            jnz     HorzBarLoop
    ;
            ret
    DrawVerticalBox endp
    cseg    ends
            end     start

Previous | Table of Contents | Next

Graphics Programming Black Book © 2001 Michael Abrash