295 lines
10 KiB
Markdown
295 lines
10 KiB
Markdown
**LISTING 26.1 L26-1.ASM**
|
||
|
||
; 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
|