Category : Display Utilities
Archive   : SPDCRT.ZIP
Filename : SPEED.ASM

 
Output of file : SPEED.ASM contained in archive : SPDCRT.ZIP

title SPEED-CRT July 12, 1988

;equates

cr equ 0dh
lf equ 0ah
wp equ word ptr
by equ byte ptr
dwp equ dword ptr

crtc equ 463h ;ROM BIOS location of CRT controller
hi_curs_reg equ 0eh ;register-high byte cursor location
lo_curs_reg equ 0fh ;register-low byte cursor location
curs_loc equ 450h ;ROM BIOS location of cursor location
curs_mode equ 460h ;ROM BIOS location of cursor mode
crt_mode equ 449h ;ROM BIOS location of CRT mode
active_page equ 462h ;ROM BIOS location of active page
ega_status equ 87h ;ROM BIOS location EGA status byte


cseg segment para public 'code'
assume cs:cseg

org 100h

start: jmp initialize

curs_pos dw 0 ;current cursor location
old_10 dd ? ;segment and offset of INT 10h
vram_off dw 0 ;current offset into VRAM
vram_seg dw 0b800h ;segment of active VRAM buffer
on_off db 0 ;if 0, we are active

new_10h proc far
sti
cmp ah,0fh ;non-standard function?
ja our_fn ;yes, see if its ours
COMMENT |
*******************************************************************************
MARKER serves as a 'code' flag; it is changed by set_mode based on the new
mode being requested; if mode is compatible with SPEED-CRT, MARKER is STC;
if mode is not compatible, MARKER is changed to CLC; the conditional jump
behaves accordingly; the only compatible modes are 2, 3 and 7; when in
other modes, INT 10h calls are passed thru to the BIOS. Similar logic, though
different coding, applies to MARKER1.
*******************************************************************************
|
marker db 0f9h ;if 0f8h(CLC), will check only for fn 0
jnc ch_mod ;or for our function, 0eeh
marker1 db 0f5h ;if 90h(NOP), coding not active, if
;0f5h CMC) coding active
jc mrk1 ;not active, so out

new0: push ds ;yes, so process call
push si
xor si,si ;set ds to low memory segment
mov ds,si
mov si,ax ;hold ax
xor al,al ;zero out low byte
xchg al,ah ;swap
xchg si,ax ;function # to si
shl si,1 ;*2 for word displacement
jmp cs:[si+offset jmp_table] ;jump to proper function

jmp_table: dw offset set_mode ;function 0*
dw offset curs_type ;function 1
dw offset set_curs ;function 2 *
dw offset get_curs ;function 3 *
dw offset light_pen ;function 4
dw offset set_page ;function 5
dw offset scroll_up ;function 6
dw offset scroll_dwn ;function 7
dw offset read_ac ;function 8
dw offset write_ac ;function 9 *
dw offset write_c ;function 0ah*
dw offset graph ;function 0bh
dw offset graph ;function 0ch
dw offset graph ;function 0dh
dw offset write_tty ;function 0eh *
dw offset get_mode ;function 0fh *

ch_mod: or ah,ah ;check for function 0
jz sm_1 ;it is, go change mode

mrk1: jmp dwp cs:old_10 ;nope, let BIOS handle


our_fn: cmp ah,0eeh ;our install function?
jne mrk1 ;no, so out
mov bx,"KA" ;yes, return identifier
mov cx,cs ;return code segment
home: iret ;return

set_mode: pop si ;entry point for normal call
pop ds
sm_1: push ax ;entry point when MARKER is CLC
mov ah,0f9h ;assume good mode-MARKER to STC
cmp al,7 ;mono?
jne sm_2 ;no
mov cs:vram_seg,0b000h ;yes, adjust segment for monochrome
jmp sm_out

sm_2: mov cs:vram_seg,0b800h ;adjust for color
cmp al,2 ;cga text?
je sm_out ;yes
cmp al,3 ;ega text?
je sm_out ;yes
mov ah,0f8h ;not a good mode-set MARKER to CLC
sm_out: mov by cs:marker,ah ;set MARKER
pop ax
jmp dwp cs:old_10 ;let BIOS do the work


graph: ;functions not handled by SPEED-CRT
scroll_up:
curs_type:
read_ac:
light_pen:
set_page:
scroll_dwn:
pop si
pop ds
jmp dwp cs:old_10 ;let BIOS handle

get_mode: mov ax, wp ds:[crt_mode] ;mode and cols to ax
mov bh,by ds:[active_page] ;page to bh
pop si
pop ds
iret

get_curs: cmp bh,0 ;page 0?
jnz graph ;no, BIOS to handle

mov dx,wp ds:[curs_loc] ;return cursor col/row in dx
mov cx,wp ds:[curs_mode] ;return cursor mode in cx
pop si
pop ds
iret

set_curs:
cmp bh,0 ;page 0?
jnz graph ;no, BIOS to handle

push bx ;calculate VRAM offset of new location
mov wp ds:[curs_loc],dx ;cursor location to BIOS data area
mov bx,dx ;also to bx
mov si,ax ;save ax
xor ax,ax ;zero out ax
xchg al,dl ;column number to al, 0 to dl
xchg dl,dh ;rows to dl
shl dx,1 ;for 80 cols, first multiply rows*16
shl dx,1
shl dx,1
shl dx,1
add ax,dx ;add intermediate product to columns
shl dx,1 ;now by 64
shl dx,1
add dx,ax ;add back intermediate to get offset
mov wp cs:[vram_off],dx ;save VRAM offset

crtc_update:
mov ax,wp ds:[crtc] ;address crtc
mov ds,bx ;hold bx in ds
mov bx,dx ;offset to bx
mov dx,ax ;crtc to dx
mov al,hi_curs_reg ;address high byte cursor register
mov ah,bh ;high byte to ah
out dx,ax ;output it
inc al ;change to low byte register
mov ah,bl ;low byte to ah
out dx,ax ;output it

mov dx,ds ;recover all registers
mov ax,si
pop bx
pop si
pop ds
iret

write_ac:
cmp bh,0 ;page 0?
jnz graph ;no, let BIOS do it

push cx ;save cx
mov si,ax ;save ax
mov ah,bl ;attrib=>ah
push di ;save di
lds di,dwp cs:[vram_off] ;ds:di=>VRAM location for this character
shl di,1 ;2 bytes per character

wr0: mov wp ds:[di],ax ;write character/attribute to VRAM
add di,2 ;increase to next location
loop wr0 ;loop if more than 1 character

wr2: pop di ;recover all registers
mov ax,si
pop cx
pop si
pop ds
iret

write_c:
cmp bh,0 ;page 0?
jnz wrc ;no, let BIOS handle

mov si,cx ;save cx
push di ;save di
lds di,dwp cs:[vram_off] ;ds:di=>VRAM location for this character
shl di,1 ;2 bytes per char

wrc0: mov by ds:[di],al ;write it to VRAM
add di,2 ;point to next location
loop wrc0 ;loop if more than 1 character

mov cx,si ;recover all registers
pop di
pop si
pop ds
iret

wrc: pop si
pop ds
jmp dwp cs:old_10


write_tty: cmp al,0eh ;we'll handle all characters
jl wtty ;let BIOS handle housekeeping
cmp by ds:[curs_loc],79 ;last column?
jge wtty ;yes, let BIOS handle
cmp by ds:[active_page],0;page 0?
jnz wtty ;no, let BIOS do it

push ax ;save what we use
push ax
mov si,bx
mov bx,wp ds:[curs_loc] ;bx has cursor location
inc bl ;now next location
mov by ds:[curs_loc],bl ;update ROM BIOS data area
mov by cs:[curs_pos],bl ;now ours
dec bl ;back to current location

;calculate VRAM offset

mov al,bh ;rows to al
xor bh,bh ;clear high byte
xor ah,ah ;clear high byte
shl ax,1 ;for 80 cols, first multiply rows*16
shl ax,1
shl ax,1
shl ax,1
add bx,ax ;add to columns
shl ax,1 ;now by 64
shl ax,1
add bx,ax ;bx now has VRAM offset

mov wp cs:[vram_off],bx ;save it

pop ax ;recover character
push di
push es
les di,dwp cs:[vram_off] ;ds:di=>VRAM location
inc bx ;increase offset
shl di,1 ;2 bytes per char
stosb
pop es
pop di
push dx

;update CRT controller

mov dx,wp ds:[crtc] ;address crtc
mov al,hi_curs_reg ;high byte cursor register
mov ah,bh ;high byte to ah
out dx,ax ;output it
inc al ;change to low byte register
mov ah,bl ;low byte to ah
out dx,ax ;output it

mov bx,si ;recover registers
pop dx
pop ax
pop si
pop ds
iret

;routine to call BIOS to do the housekeeping and then do local data update

wtty: pushf
call dwp cs:old_10
push ax
mov si,bx
mov bx,wp ds:[curs_loc] ;dx has cursor location
mov wp cs:[curs_pos],bx

mov al,bh
xor bh,bh
xor ah,ah
shl ax,1
shl ax,1
shl ax,1
shl ax,1
add bx,ax
shl ax,1
shl ax,1
add bx,ax

mov wp cs:[vram_off],bx
pop ax
mov bx,si
pop si
pop ds
iret

new_10h endp

initialize proc near

mov ah,0eeh ;call our int10h fn
int 10h
cmp bx,'KA' ;check for signature
jne ega_check ;not installed
call parse ;check for toggle
jnc init_0 ;none, so out
call toggle ;need to toggle
mov ah,9 ;show message
int 21h
mov ax,4c00h ;and out
int 21h

init_0: lea dx,installed ;already installed msg
jmp err_out

ega_check: mov ax,40h
mov es,ax ;es=>BIOS data segment
mov al,by es:[ega_status] ;get ega status byte
cmp al,0 ;if zero, no ega
jnz ega_1 ;board OK, see if its active
lea dx,no_ega ;load error msg
jmp err_out

ega_1: test al,8 ;if bit 3 clear, ega active
jz monochrome ;everything's go, check for mono
mov marker,0f8h ;install, but wait for mode change
jmp install


err_out: mov ah,9
int 21h
mov ax,4cffh ;and out with error
int 21h

monochrome:
mov ah,0fh
int 10h
cmp al,7
jnz install
mov cs:vram_seg,0b000h

install:
mov ax,3510h ;get and store 10h vectors
int 21h
mov wp [old_10],bx ;save offset
mov wp [old_10].2,es ;save segement
mov ax,2510h ;set new vector
lea dx,new_10h ;our coding
int 21h

lea dx,sign_on ;show sign on message
mov ah,9
int 21h

mov ax,wp ds:[02ch] ;get environment segment
mov es,ax ;into es
mov ah,49h ;free allocated memory
int 21h

lea dx,initialize ;get ready to tsr
mov cx,4 ;convert bytes to paragraphs
shr dx,cl ;in dx
inc dx ;plus one
mov ax,3100h ;tsr
int 21h
initialize endp

parse proc near
mov dl,by ds:[80h] ;tail length ->dl
cmp dl,2 ;must be at least 1 char +
jl parse_out ;not there, so return
mov si,82h ;si->1st char in command tail
cmp by ds:[si],"-" ;should we toggle SPEED?
jnz parse_out ;no, bad parameter
stc ;set flag
ret
parse_out: clc
ret
parse endp

toggle proc near
mov es,cx ;resident segment to es
mov di,offset marker1 ;es:di->resident flag
cmp by es:[di],0f5h ;is it on?
jz tgl_0 ;yes, so turn it off
mov by es:[di],0f5h ;no, so turn it on
mov dx,offset on_msg ;show off msg
jmp tgl_1

tgl_0: mov by es:[di],90h ;turn it off
mov dx,offset off_msg ;show on message
tgl_1: ret
toggle endp

installed db lf,cr,'*SPEED-CRT* - Already installed',lf,cr,'$'
sign_on db lf,lf,cr,'*SPEED-CRT* - Installed',lf,cr,'$'
no_ega db lf,cr,'*SPEED-CRT* - No EGA board present - cannot install'
db lf,cr,'$'
off_msg db lf,cr,'*SPEED-CRT* - Toggled off',lf,cr,'$'
on_msg db lf,cr,'*SPEED-CRT* - Toggled on',lf,cr,'$'
cseg ends
end start

comment | ;these 2 routines seem to run at the same speed
mov ax,bx ;cursor position to ax
mov al,ah ;rows to al
xor ah,ah ;clear high byte
shl ax,1 ;for 80 cols, first multiply rows*16
shl ax,1
shl ax,1
shl ax,1
mov bx,ax ;intermediate product to bx
shl ax,1 ;now by 64
shl ax,1
add bx,ax ;bx has rows x 80
xor dh,dh ;zero out rows
add bx,dx ;add columns to get position

|
comment |
mov bx,dx ;cursor position to bx
xor ah,ah
mov al,50h ;80 chars per row
mul bh ;times the number of rows
xor bh,bh
add bx,ax ;plus the column position
mov wp cs:[vram_off],bx ;save vram offset
|