home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / screen / xflash1.arc / XFLASH.ASM < prev    next >
Assembly Source File  |  1987-03-17  |  11KB  |  433 lines

  1. ; XFLASH by David Hite     -    Optimized for 8088 Processor
  2. ; Eliminates the flash that occurs during scrolling on the CGA.
  3. ; XFLASH is FreeWare.
  4.  
  5. ; Your machine may be able to move more characters or fewer
  6. ; characters during vertical retraces than mine.
  7. ; You can experiment by changing the values of max_vert and clr_max_vert.
  8. ; Max_horiz will probably not need to be changed, because it is
  9. ; based on the CGA's 200 scan lines.
  10.  
  11. ; The difference between XFLASH and XFLASH-2, other than the different
  12. ; values for max_vert and clr_max_vert, is that XFLASH-2 moves a word
  13. ; during the horizontal retrace, while XFLASH can only move a byte.
  14. ; The code is therefore slightly different.
  15.  
  16. clr_max_vert    equ    420        ; the maximum number of words to
  17.                         ; clear during a vertical retrace
  18. max_vert        equ    210        ; the maximum number of words to move in 
  19.                         ; a vertical retrace
  20. max_horiz    equ    196        ; must be an even number!
  21.                         ; the maximum number of horizontal retraces
  22.                         ; to be used for moving 1 byte between 
  23.                         ; vertical retraces.  This is set to just
  24.                         ; less than the number of scan lines so that
  25.                         ; the next vertical retrace is not missed.  
  26.                         ; Increasing this value can actually slow the
  27.                         ; program down because it will have to wait
  28.                         ; longer for the next vertical retrace.
  29.  
  30. vstat        equ    3dah            ; the video status register
  31. v_retrace    equ    00001000b        ; vertical retrace bit mask
  32. h_retrace    equ    00000001b        ; horizontal retrace bit mask
  33.  
  34.  
  35. cseg    segment para public 'code'
  36.     assume cs:cseg,ds:cseg,ss:cseg,es:nothing
  37.     org    100h
  38.  
  39. start:
  40.     jmp install                ; install the program
  41.  
  42. savestack    dw    0,0
  43. request        dw    0            ; ax from interrupt
  44. fill_attrib    dw    0            ; bx from interrupt
  45. video_handler dd    0            ; address of the original video handler
  46. apage        db    0            ; active video page
  47. amode        db    3            ; active video mode
  48. display_seg     dw     0b800h        ; addr of cga display memory
  49.  
  50. new_video_int proc far            ; far label since it's entered by interrupt
  51.                             ; and thus must generate inter-segment ret
  52.     sti                        ; enable interrupts
  53.  
  54.     cmp    ah,0                    ; check for mode switch
  55.     jne    chk_mode
  56.     mov    cs:amode,al            ; remember new mode
  57.     jmp    short not_ours            ; and let bios change the mode
  58.  
  59. chk_mode:
  60.     cmp    cs:amode,3            ; we don't scroll graphics modes
  61.     jg    not_ours
  62.  
  63. chk_5:
  64.     cmp    ah,5                    ; check for page switch
  65.     jl    not_ours
  66.     jne    chk_6
  67.     mov    cs:apage,al            ; remember new page number
  68.     jmp    short not_ours            ; and let bios change the page
  69.  
  70. chk_6:
  71.     cmp    ah,6
  72.     jne    chk_7
  73. chk_6a:
  74.     cmp    cl,0                    ; we do it only for complete lines
  75.     jne    not_ours
  76.     cmp    dl,79
  77.     jne    not_ours
  78.     jmp    short scroll
  79.  
  80. chk_7:
  81.     cmp    ah,7
  82.     je    chk_6a
  83.  
  84. not_ours:
  85.     pushf                ; emulate int instruction
  86.     call dword ptr    [cs:video_handler]
  87.     iret
  88.  
  89. scroll:
  90.     mov cs:savestack,sp
  91.     mov cs:savestack+2,ss
  92.  
  93.     mov    cs:request,ax
  94.     mov    ax,cs
  95.     mov    ss,ax
  96.     mov    sp,100h
  97.  
  98.     push bp                ; set up a stack frame
  99.     mov    bp,sp
  100.     sub    sp,0eh
  101.     call savereg
  102.     mov    ds,ax
  103.     mov    ax,request
  104.  
  105.     call    main                ; that's where the work is done
  106.  
  107.     call restreg
  108.      add    sp,0eh
  109.     pop    bp
  110.  
  111.     mov ss,cs:savestack+2
  112.     mov sp,cs:savestack
  113.  
  114.     iret                ; return from interrupt
  115.  
  116. new_video_int    endp
  117.  
  118. inside proc near
  119. fix_ch0:
  120.     mov    ch,0
  121.     jmp    short chk_dh
  122. fix_ch24:
  123.     mov    ch,24
  124.     jmp    short chk_dh
  125. fix_dh0:
  126.     mov    dh,0
  127.     jmp    short chk_al
  128. fix_dh24:
  129.     mov    dh,24
  130.     jmp    short chk_al
  131. fix_al25:
  132.     mov    al,25
  133.     jmp    short regs_ok
  134.  
  135. main:
  136.     mov    fill_attrib,bx        ; save fill attribute for much later (clr_area)
  137.     push    dx                ; because MUL uses it
  138.     cmp    ch,0
  139.     jl    fix_ch0
  140.     cmp    ch,24
  141.     jg    fix_ch24
  142. chk_dh:
  143.     cmp    dh,0
  144.     jl    fix_dh0    
  145.     cmp    dh,24
  146.     jg    fix_dh24
  147. chk_al:
  148.     mov    ax,request
  149.     cmp    al,0
  150.     jle    fix_al25
  151.     cmp    al,25
  152.     jg    fix_al25
  153. regs_ok:
  154.     mov    request,ax        ; in case we fixed it
  155.     xor    bh,bh
  156.     mov    bl,apage            ; get the current page number
  157.     mov    ax,4096            ; the size of a a page
  158.     mul    bx                ; multiply by the page number to get offset
  159.     mov    di,ax            ; and put it in the destination index
  160.                         ; now calculate the offset of the window
  161.     mov    bl,ch            ; by getting the starting row
  162.     xor    bh,bh
  163.     mov    ax,160            ; we only handle full rows
  164.     mul    bx                ; and multiply by chars/row to get offset
  165.     add    di,ax            ; and adding to di to get address
  166.     mov    ax,di
  167.     mov    si,ax            ; and put it in the source index as well
  168.     pop    dx
  169.     mov    ax,request        ; get the original request
  170.     mov    bh,dh            ; move bottom line to bh
  171.     sub    bh,ch            ; subtract top line
  172.     inc    bh                ; bh now has number of lines in window
  173.  
  174.     cld                    ; we'll move forward unless scroll is down
  175.     mov    es,display_seg
  176.     cmp    al,0                ; clear the area?
  177.     jbe    m_1                ; yes
  178.     cmp    al,bh
  179.     je    m_1b                ; we are clearing all the lines
  180.     jb    m_2                ; we are clearing some of the lines
  181. m_1:                    ; we are clearing more than all the lines!
  182.     mov    al,bh            ; move number of lines in window to al
  183.     mov    request,ax
  184. m_1b:
  185.     jmp    clr_area
  186.  
  187. m_2:                    ; bh has lines in window, al has lines
  188.                         ; to scroll
  189.     cmp    ah,6                ; up or down?
  190.     je    up
  191. down:                    ; we are scrolling down
  192.     std                    ; so we move backwards
  193.  
  194.     sub    al,bh            ; the source is bh-al lines below si
  195.     neg    al                ; correct the sign
  196.     cbw                    ; convert to a word
  197.     mov    cx,160
  198.     mul    cx                ; multiply by chars/row
  199.     sub    ax,2                ; subtract a word to get end of line
  200.     add    si,ax            ; and add to si, the address of the up left
  201.  
  202.     ; the destination is the lower right which is bh lines 
  203.     ; below current di => di = di + bh*160 - 2
  204.  
  205.     mov    al,bh            ; get lines in window into al
  206.     cbw
  207.     mov    cx,160
  208.     mul    cx
  209.     sub    ax,2                ; subtract a word to get end of line
  210.     add    di,ax            ; di now has address of destination
  211.     
  212.     jmp    short movem
  213.  
  214. up:                        ; we are scrolling up
  215.     ; the source is al lines below si which is al*160 chars below current si
  216.  
  217.     cbw                    ; gets number of lines into ax
  218.     mov    cx,160
  219.     mul    cx
  220.     add    si,ax            ; si now has address of source
  221.  
  222.     ; the initial destination is correct, we don't need to change it
  223.  
  224. movem:                    ; now start to move words
  225.     ; fix bx such that it is number of words to move 
  226.     ; = (number of lines in window minus number of lines to scroll)*80
  227.  
  228.     mov    ax,request        ; get number of lines to scroll
  229.     cbw                    ; slightly faster than xor ah,ah
  230.     sub    al,bh            ; subtract lines in window from lines to scroll
  231.     neg    al                ; after correcting the sign, ax has lines to move
  232.     mov    cx,80            ; words/line
  233.     mul    cx                ; multiply to get words to move
  234.     mov    bx,ax            ; bx now has number of words to move
  235.  
  236.     push    ds                ; we're about to change it to display_seg
  237.     mov    dx,vstat            ; the video status register
  238.     mov    ds,display_seg        ; load address of display segment
  239.  
  240. mvm_vert:                ; first wait for a vertical refresh
  241.     mov    cx,bx            ; move words remaining to cx
  242.     cmp    cx,max_vert        ; too  many?
  243.     jle    mvm_many            ; no, go move'm
  244.     mov    cx,max_vert        ; yes, move max_vert more, maximum
  245. mvm_many:
  246.     sub    bx,cx            ; that many will remain when rep movsw ends
  247.  
  248. mvm_v_refresh:
  249.     in    al,dx
  250.     test    al,v_retrace
  251.     jnz    mvm_v_refresh        ; wait for a non retrace period
  252.  
  253. mvm_v_wait:
  254.     in    al,dx            ; get the retrace status
  255.     test    al,v_retrace        ; check for retrace in progress
  256.     jz    mvm_v_wait        ; wait until retrace
  257.  
  258.     ; in a vertical retrace, we can move many
  259.     rep    movsw
  260.     cmp    bx,0
  261.     je    mvm_end
  262.  
  263.     mov    cx,max_horiz
  264.     shl    bx,1                ; to convert words to bytes
  265. mvm_1:
  266.     dec    bx
  267. mvm_h_refresh:
  268.     in    al,dx
  269.     test    al,h_retrace
  270.     jnz    mvm_h_refresh        ; wait for a non retrace period
  271.  
  272. ;    the next statement is commented out to prevent comm char loss 
  273. ;    cli                    ; disable interrupts while waiting (not long)
  274. mvm_h_wait:
  275.     in    al,dx            ; get the retrace status
  276.     test    al,h_retrace        ; check for retrace in progress
  277.     jz    mvm_h_wait        ; wait until retrace
  278.  
  279.     movsb                ; now move one byte
  280. ;    sti                    ; and now enable interrupts again
  281.  
  282.     cmp    bx,0                ; are we finished?
  283.     je    mvm_end
  284.     loop    mvm_1            ; only if cx not 0
  285.     cmp    bx,0
  286.     je    mvm_end
  287.  
  288. mvm_do_cx_again:
  289.     shr    bx,1                ; convert back to words
  290.     mov    cx,bx            ; move words remaining to cx
  291.     cmp    cx,max_vert        ; too  many?
  292.     jle    mvm_h_many        ; no, go move'm
  293.     mov    cx,max_vert        ; yes, move max_vert more, maximum
  294. mvm_h_many:
  295.     sub    bx,cx            ; that many will remain when rep movsw ends
  296.     jmp    mvm_v_wait
  297.  
  298. mvm_end:                    ; we've finished moving
  299.     pop    ds                ; restore the data segment
  300.  
  301. clr_area:
  302. ;    we're now ready to blank the number of lines that were scrolled.
  303. ;    The direction flag and di and es are set correctly, given
  304. ;    what we've done so far.  All we need to do is calculate number of 
  305. ;    words to blank.
  306.  
  307.     mov    ax,request        ; to get number lines to scroll
  308.     cbw
  309.     mov    cx,80            ; words/line
  310.     mul    cx                ; ax now has words to blank
  311.     mov    bx,ax            ; put it in bx
  312.  
  313.     mov    dx,fill_attrib        ; dh now has the fill attribute
  314.     mov    dl,' '            ; move a space to dl
  315.  
  316.     mov    si,dx            ; move clear char to si
  317.  
  318. ;    the following code sets the screen border to the fill attribute.
  319. ;    un-comment it if you want to do this
  320. ;    mov    cl,4
  321. ;    shr    dh,cl
  322. ;    mov    al,dh
  323. ;    or    al,20h
  324. ;    mov    dx,03d9h            ; set border to fill attribute
  325. ;    out    dx,al
  326. ;    end of set border code
  327.  
  328.     mov    dx,vstat            ; the video status register
  329.  
  330. clr_vert:                ; first wait for a vertical refresh
  331.     mov    cx,bx            ; move words remaining to cx
  332.     cmp    cx,clr_max_vert    ; too  many?
  333.     jle    clr_many            ; no, go move'm
  334.     mov    cx,clr_max_vert    ; yes, move clr_max_vert more, maximum
  335. clr_many:
  336.     sub    bx,cx            ; that many will remain when rep stosw ends
  337.  
  338. clr_v_refresh:
  339.     in    al,dx
  340.     test    al,v_retrace
  341.     jnz    clr_v_refresh        ; wait for a non retrace period
  342.  
  343. clr_v_wait:
  344.     in    al,dx            ; get the retrace status
  345.     test    al,v_retrace        ; check for retrace in progress
  346.     jz    clr_v_wait        ; wait until retrace
  347.     xchg    ax,si
  348.     rep    stosw
  349.     xchg    ax,si
  350.     cmp    bx,0
  351.     je    clr_end
  352.  
  353.     mov    cx,max_horiz
  354. clr_1:
  355.     dec    bx
  356. clr_h_refresh:
  357.     in    al,dx
  358.     test    al,h_retrace
  359.     jnz    clr_h_refresh        ; wait for a non retrace period
  360.  
  361. ;    the next statement is commented out to prevent comm char loss 
  362. ;    cli                    ; disable interrupts while waiting (not long)
  363. clr_h_wait:
  364.     in    al,dx            ; get the retrace status
  365.     test    al,h_retrace        ; check for retrace in progress
  366.     jz    clr_h_wait        ; wait until retrace
  367.     xchg    ax,si
  368.     stosw                ; now move one word
  369. ;    sti                    ; and now enable interrupts again
  370.     xchg    ax,si
  371.     cmp    bx,0                ; are we finished?
  372.     je    clr_end
  373.     loop    clr_1
  374.     cmp    bx,0
  375.     je    clr_end
  376.  
  377. clr_do_cx_again:
  378.     mov    cx,bx            ; move words remaining to cx
  379.     cmp    cx,clr_max_vert    ; too  many?
  380.     jle    clr_h_many        ; no, go move'm
  381.     mov    cx,clr_max_vert    ; yes, move clr_max_vert more, maximum
  382. clr_h_many:
  383.     sub    bx,cx            ; that many will remain when rep movsw ends
  384.     jmp    clr_v_wait
  385.  
  386. clr_end:                    ; we've finished moving
  387.  
  388.     cld                    ; just for the heck of it
  389.     ret
  390.  
  391.  
  392. savereg:
  393.     mov    -2[bp],bx
  394.     mov    -4[bp],cx
  395.     mov    -6[bp],dx
  396.     mov    -8[bp],si
  397.     mov    -0ah[bp],di
  398.     mov    -0ch[bp],ds
  399.     mov    -0eh[bp],es
  400.     ret
  401. restreg:
  402.     mov    bx,-2[bp]
  403.     mov    cx,-4[bp]
  404.     mov    dx,-6[bp]
  405.     mov    si,-8[bp]
  406.     mov    di,-0ah[bp]
  407.     mov    ds,-0ch[bp]
  408.     mov    es,-0eh[bp]
  409.     ret
  410. inside    endp
  411.  
  412. install:
  413.  
  414.     mov ax,3510h            ; get interrupt 10 vector
  415.     int 21h
  416.     mov word ptr video_handler,bx
  417.     mov word ptr video_handler+2,es
  418.  
  419.     mov ax,2510h
  420.     mov dx,offset new_video_int    ; now put our routine there
  421.     int 21h
  422.  
  423.     mov dx,offset install    ; terminate and stay resident
  424.     mov cl,4
  425.     shr dx,cl
  426.     inc dx                ; round up
  427.     mov ah,31h
  428.     int 21h
  429.  
  430.  
  431. cseg ends
  432.     end start
  433.