230 lines
4.8 KiB
NASM
230 lines
4.8 KiB
NASM
; Program to illustrate operation of data rotate and bit mask
|
|
; features of Graphics Controller. Draws 8x8 character at
|
|
; specified location, using VGA's 8x8 ROM font. Designed
|
|
; for use with modes 0Dh, 0Eh, 0Fh, 10h, and 12h.
|
|
; 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.
|
|
;
|
|
GC_INDEX equ 3ceh ;GC index register
|
|
GC_ROTATE equ 3 ;GC data rotate/logical function
|
|
; register index
|
|
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
|
|
;
|
|
; 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
|
|
;
|
|
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 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.
|
|
;
|
|
mov si,offset TestString
|
|
mov bx,TEST_TEXT_ROW
|
|
mov cx,TEST_TEXT_COL
|
|
StringOutLoop:
|
|
lodsb
|
|
and al,al
|
|
jz StringOutDone
|
|
call DrawChar
|
|
add cx,TEST_TEXT_WIDTH
|
|
jmp StringOutLoop
|
|
StringOutDone:
|
|
;
|
|
; Reset the data rotate and bit mask registers.
|
|
;
|
|
SETGC GC_ROTATE, 0
|
|
SETGC GC_BIT_MASK, 0ffh
|
|
;
|
|
; Wait for a keystroke.
|
|
;
|
|
mov ah,1
|
|
int 21h
|
|
;
|
|
; Return to text mode.
|
|
;
|
|
mov ax,03h
|
|
int 10h
|
|
;
|
|
; 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).
|
|
; Font used should be pointed to by FontPointer.
|
|
;
|
|
; Input:
|
|
; AL = character to draw
|
|
; BX = row to draw text character at
|
|
; CX = column to draw text character at
|
|
;
|
|
; Forces ALU function to "move".
|
|
;
|
|
DrawChar proc near
|
|
push ax
|
|
push bx
|
|
push cx
|
|
push dx
|
|
push si
|
|
push di
|
|
push bp
|
|
push ds
|
|
;
|
|
; 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.
|
|
;
|
|
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.
|
|
;
|
|
mov dx,GC_INDEX
|
|
mov al,GC_ROTATE
|
|
mov ah,cl
|
|
out dx,ax
|
|
;
|
|
; 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 the bit mask to get the
|
|
; proper portion of the character into each byte.
|
|
; 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
|