home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programming
/
powerprogramming1994.iso
/
progtool
/
screen
/
xflash1.arc
/
XFLASH.ASM
< prev
next >
Wrap
Assembly Source File
|
1987-03-17
|
11KB
|
433 lines
; XFLASH by David Hite - Optimized for 8088 Processor
; Eliminates the flash that occurs during scrolling on the CGA.
; XFLASH is FreeWare.
; Your machine may be able to move more characters or fewer
; characters during vertical retraces than mine.
; You can experiment by changing the values of max_vert and clr_max_vert.
; Max_horiz will probably not need to be changed, because it is
; based on the CGA's 200 scan lines.
; The difference between XFLASH and XFLASH-2, other than the different
; values for max_vert and clr_max_vert, is that XFLASH-2 moves a word
; during the horizontal retrace, while XFLASH can only move a byte.
; The code is therefore slightly different.
clr_max_vert equ 420 ; the maximum number of words to
; clear during a vertical retrace
max_vert equ 210 ; the maximum number of words to move in
; a vertical retrace
max_horiz equ 196 ; must be an even number!
; the maximum number of horizontal retraces
; to be used for moving 1 byte between
; vertical retraces. This is set to just
; less than the number of scan lines so that
; the next vertical retrace is not missed.
; Increasing this value can actually slow the
; program down because it will have to wait
; longer for the next vertical retrace.
vstat equ 3dah ; the video status register
v_retrace equ 00001000b ; vertical retrace bit mask
h_retrace equ 00000001b ; horizontal retrace bit mask
cseg segment para public 'code'
assume cs:cseg,ds:cseg,ss:cseg,es:nothing
org 100h
start:
jmp install ; install the program
savestack dw 0,0
request dw 0 ; ax from interrupt
fill_attrib dw 0 ; bx from interrupt
video_handler dd 0 ; address of the original video handler
apage db 0 ; active video page
amode db 3 ; active video mode
display_seg dw 0b800h ; addr of cga display memory
new_video_int proc far ; far label since it's entered by interrupt
; and thus must generate inter-segment ret
sti ; enable interrupts
cmp ah,0 ; check for mode switch
jne chk_mode
mov cs:amode,al ; remember new mode
jmp short not_ours ; and let bios change the mode
chk_mode:
cmp cs:amode,3 ; we don't scroll graphics modes
jg not_ours
chk_5:
cmp ah,5 ; check for page switch
jl not_ours
jne chk_6
mov cs:apage,al ; remember new page number
jmp short not_ours ; and let bios change the page
chk_6:
cmp ah,6
jne chk_7
chk_6a:
cmp cl,0 ; we do it only for complete lines
jne not_ours
cmp dl,79
jne not_ours
jmp short scroll
chk_7:
cmp ah,7
je chk_6a
not_ours:
pushf ; emulate int instruction
call dword ptr [cs:video_handler]
iret
scroll:
mov cs:savestack,sp
mov cs:savestack+2,ss
mov cs:request,ax
mov ax,cs
mov ss,ax
mov sp,100h
push bp ; set up a stack frame
mov bp,sp
sub sp,0eh
call savereg
mov ds,ax
mov ax,request
call main ; that's where the work is done
call restreg
add sp,0eh
pop bp
mov ss,cs:savestack+2
mov sp,cs:savestack
iret ; return from interrupt
new_video_int endp
inside proc near
fix_ch0:
mov ch,0
jmp short chk_dh
fix_ch24:
mov ch,24
jmp short chk_dh
fix_dh0:
mov dh,0
jmp short chk_al
fix_dh24:
mov dh,24
jmp short chk_al
fix_al25:
mov al,25
jmp short regs_ok
main:
mov fill_attrib,bx ; save fill attribute for much later (clr_area)
push dx ; because MUL uses it
cmp ch,0
jl fix_ch0
cmp ch,24
jg fix_ch24
chk_dh:
cmp dh,0
jl fix_dh0
cmp dh,24
jg fix_dh24
chk_al:
mov ax,request
cmp al,0
jle fix_al25
cmp al,25
jg fix_al25
regs_ok:
mov request,ax ; in case we fixed it
xor bh,bh
mov bl,apage ; get the current page number
mov ax,4096 ; the size of a a page
mul bx ; multiply by the page number to get offset
mov di,ax ; and put it in the destination index
; now calculate the offset of the window
mov bl,ch ; by getting the starting row
xor bh,bh
mov ax,160 ; we only handle full rows
mul bx ; and multiply by chars/row to get offset
add di,ax ; and adding to di to get address
mov ax,di
mov si,ax ; and put it in the source index as well
pop dx
mov ax,request ; get the original request
mov bh,dh ; move bottom line to bh
sub bh,ch ; subtract top line
inc bh ; bh now has number of lines in window
cld ; we'll move forward unless scroll is down
mov es,display_seg
cmp al,0 ; clear the area?
jbe m_1 ; yes
cmp al,bh
je m_1b ; we are clearing all the lines
jb m_2 ; we are clearing some of the lines
m_1: ; we are clearing more than all the lines!
mov al,bh ; move number of lines in window to al
mov request,ax
m_1b:
jmp clr_area
m_2: ; bh has lines in window, al has lines
; to scroll
cmp ah,6 ; up or down?
je up
down: ; we are scrolling down
std ; so we move backwards
sub al,bh ; the source is bh-al lines below si
neg al ; correct the sign
cbw ; convert to a word
mov cx,160
mul cx ; multiply by chars/row
sub ax,2 ; subtract a word to get end of line
add si,ax ; and add to si, the address of the up left
; the destination is the lower right which is bh lines
; below current di => di = di + bh*160 - 2
mov al,bh ; get lines in window into al
cbw
mov cx,160
mul cx
sub ax,2 ; subtract a word to get end of line
add di,ax ; di now has address of destination
jmp short movem
up: ; we are scrolling up
; the source is al lines below si which is al*160 chars below current si
cbw ; gets number of lines into ax
mov cx,160
mul cx
add si,ax ; si now has address of source
; the initial destination is correct, we don't need to change it
movem: ; now start to move words
; fix bx such that it is number of words to move
; = (number of lines in window minus number of lines to scroll)*80
mov ax,request ; get number of lines to scroll
cbw ; slightly faster than xor ah,ah
sub al,bh ; subtract lines in window from lines to scroll
neg al ; after correcting the sign, ax has lines to move
mov cx,80 ; words/line
mul cx ; multiply to get words to move
mov bx,ax ; bx now has number of words to move
push ds ; we're about to change it to display_seg
mov dx,vstat ; the video status register
mov ds,display_seg ; load address of display segment
mvm_vert: ; first wait for a vertical refresh
mov cx,bx ; move words remaining to cx
cmp cx,max_vert ; too many?
jle mvm_many ; no, go move'm
mov cx,max_vert ; yes, move max_vert more, maximum
mvm_many:
sub bx,cx ; that many will remain when rep movsw ends
mvm_v_refresh:
in al,dx
test al,v_retrace
jnz mvm_v_refresh ; wait for a non retrace period
mvm_v_wait:
in al,dx ; get the retrace status
test al,v_retrace ; check for retrace in progress
jz mvm_v_wait ; wait until retrace
; in a vertical retrace, we can move many
rep movsw
cmp bx,0
je mvm_end
mov cx,max_horiz
shl bx,1 ; to convert words to bytes
mvm_1:
dec bx
mvm_h_refresh:
in al,dx
test al,h_retrace
jnz mvm_h_refresh ; wait for a non retrace period
; the next statement is commented out to prevent comm char loss
; cli ; disable interrupts while waiting (not long)
mvm_h_wait:
in al,dx ; get the retrace status
test al,h_retrace ; check for retrace in progress
jz mvm_h_wait ; wait until retrace
movsb ; now move one byte
; sti ; and now enable interrupts again
cmp bx,0 ; are we finished?
je mvm_end
loop mvm_1 ; only if cx not 0
cmp bx,0
je mvm_end
mvm_do_cx_again:
shr bx,1 ; convert back to words
mov cx,bx ; move words remaining to cx
cmp cx,max_vert ; too many?
jle mvm_h_many ; no, go move'm
mov cx,max_vert ; yes, move max_vert more, maximum
mvm_h_many:
sub bx,cx ; that many will remain when rep movsw ends
jmp mvm_v_wait
mvm_end: ; we've finished moving
pop ds ; restore the data segment
clr_area:
; we're now ready to blank the number of lines that were scrolled.
; The direction flag and di and es are set correctly, given
; what we've done so far. All we need to do is calculate number of
; words to blank.
mov ax,request ; to get number lines to scroll
cbw
mov cx,80 ; words/line
mul cx ; ax now has words to blank
mov bx,ax ; put it in bx
mov dx,fill_attrib ; dh now has the fill attribute
mov dl,' ' ; move a space to dl
mov si,dx ; move clear char to si
; the following code sets the screen border to the fill attribute.
; un-comment it if you want to do this
; mov cl,4
; shr dh,cl
; mov al,dh
; or al,20h
; mov dx,03d9h ; set border to fill attribute
; out dx,al
; end of set border code
mov dx,vstat ; the video status register
clr_vert: ; first wait for a vertical refresh
mov cx,bx ; move words remaining to cx
cmp cx,clr_max_vert ; too many?
jle clr_many ; no, go move'm
mov cx,clr_max_vert ; yes, move clr_max_vert more, maximum
clr_many:
sub bx,cx ; that many will remain when rep stosw ends
clr_v_refresh:
in al,dx
test al,v_retrace
jnz clr_v_refresh ; wait for a non retrace period
clr_v_wait:
in al,dx ; get the retrace status
test al,v_retrace ; check for retrace in progress
jz clr_v_wait ; wait until retrace
xchg ax,si
rep stosw
xchg ax,si
cmp bx,0
je clr_end
mov cx,max_horiz
clr_1:
dec bx
clr_h_refresh:
in al,dx
test al,h_retrace
jnz clr_h_refresh ; wait for a non retrace period
; the next statement is commented out to prevent comm char loss
; cli ; disable interrupts while waiting (not long)
clr_h_wait:
in al,dx ; get the retrace status
test al,h_retrace ; check for retrace in progress
jz clr_h_wait ; wait until retrace
xchg ax,si
stosw ; now move one word
; sti ; and now enable interrupts again
xchg ax,si
cmp bx,0 ; are we finished?
je clr_end
loop clr_1
cmp bx,0
je clr_end
clr_do_cx_again:
mov cx,bx ; move words remaining to cx
cmp cx,clr_max_vert ; too many?
jle clr_h_many ; no, go move'm
mov cx,clr_max_vert ; yes, move clr_max_vert more, maximum
clr_h_many:
sub bx,cx ; that many will remain when rep movsw ends
jmp clr_v_wait
clr_end: ; we've finished moving
cld ; just for the heck of it
ret
savereg:
mov -2[bp],bx
mov -4[bp],cx
mov -6[bp],dx
mov -8[bp],si
mov -0ah[bp],di
mov -0ch[bp],ds
mov -0eh[bp],es
ret
restreg:
mov bx,-2[bp]
mov cx,-4[bp]
mov dx,-6[bp]
mov si,-8[bp]
mov di,-0ah[bp]
mov ds,-0ch[bp]
mov es,-0eh[bp]
ret
inside endp
install:
mov ax,3510h ; get interrupt 10 vector
int 21h
mov word ptr video_handler,bx
mov word ptr video_handler+2,es
mov ax,2510h
mov dx,offset new_video_int ; now put our routine there
int 21h
mov dx,offset install ; terminate and stay resident
mov cl,4
shr dx,cl
inc dx ; round up
mov ah,31h
int 21h
cseg ends
end start