254 lines
7.1 KiB
NASM
254 lines
7.1 KiB
NASM
; 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
|