home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / screen / wbios.asm < prev    next >
Assembly Source File  |  1994-03-05  |  21KB  |  1,065 lines

  1.     page    56,132
  2.     title    WBIOS   Window BIOS extension
  3.     .sall
  4. ;
  5. ; Written 1984 By J. Eric Roskos; public domain.
  6. ; No support is provided by the author; you must make any desired
  7. ; revisions yourself.
  8. ;
  9. ; This program provides an extension to the BIOS function calls,
  10. ; functions 40H-43H.  For a description of the calls, see the Turbo
  11. ; Pascal program WDEMO.PAS, which also shows the preferred way of
  12. ; using the functions.  Note, however, that this BIOS extension is
  13. ; independent of any particular language, and will work with any
  14. ; program that does its I/O through the ROM BIOS's "WRITE_TTY"
  15. ; function (the plain MS-DOS display driver does this, for instance).
  16. ;
  17. ; There are a few enhancements to the IBM BIOS call: TABs are handled
  18. ; properly, BELs produce a more bell-like sound, and there is a "Raw"
  19. ; mode (although you'll have to add the function call to set it your-
  20. ; self) in which all characters are displayed as-is, without translation
  21. ; for CR, LF, BEL, etc.  There is also an option to turn end-of-line
  22. ; wraps on or off, although again you must add the function call.
  23. ; To turn these modes on, set the variables "wrap" and "raw" as
  24. ; explained below in the comments.  (These features were included in
  25. ; the program for future expansion, but have never been tested, and
  26. ; aren't guaranteed to work).
  27. ;
  28.  
  29. ;
  30. ; Macros
  31. ;
  32.  
  33. ;
  34. ; wto: write message to display.  Append cr/lf unless crsup=nocr
  35. ;
  36.  
  37. wto    macro    msg,crsup
  38.     local    msgstr,around
  39.  
  40.     jmp    around
  41.  
  42. msgstr    db    msg
  43.     ifb    <crsup>
  44.     db    0DH,0AH
  45.     endif
  46.     db    '$'
  47.  
  48. around:    push    ax
  49.     push    bx
  50.     push    si
  51.     push    di
  52.     push    bp
  53.  
  54.     mov    si,offset msgstr
  55.     call    putc
  56.  
  57.     pop    bp
  58.     pop    di
  59.     pop    si
  60.     pop    bx
  61.     pop    ax
  62.  
  63.     endm
  64.  
  65. prtreg    macro    rg,msg    ; put register rg with message msg on display
  66.  
  67.     push    ax
  68.  
  69.     mov    ax,rg
  70.     call    prtax
  71.     wto    msg,nocr
  72.  
  73.     pop    ax
  74.     endm
  75.  
  76.  
  77. ;
  78. ; Code Segment
  79. ;
  80.  
  81. cseg        segment para public 'code'
  82.         assume    cs:cseg,ds:cseg,ss:cseg,es:nothing
  83.  
  84.         org    100H
  85. ;
  86. ; COM program startup
  87. ;
  88. cpstart        proc    far
  89.         jmp    near ptr start
  90. cpstart        endp
  91.  
  92. ;
  93. ; Local Procedures
  94. ;
  95. lcpos        dw    0E60H
  96.  
  97. putc        proc    near    ; write a string to display W/O DOS intervention
  98.         push    es
  99.         push    ax
  100.         mov    ax,crt_seg
  101.         mov    es,ax
  102.         mov    di,cs:lcpos
  103. putc1:
  104.         mov    al,cs:[si]
  105.         cmp    al,'$'
  106.         je    putc2
  107.         cmp    al,0dH
  108.         jne    putc3
  109.         mov    cs:lcpos,0E60H
  110.         mov    di,0E60H
  111.         jmp    putc4
  112. putc3:
  113.         mov    es:[di],al
  114.         inc    di
  115.         inc    di
  116. putc4:
  117.         inc    si
  118.         jmp    putc1
  119.  
  120. putc2:
  121.         mov    cs:lcpos,di
  122.         pop    ax
  123.         pop    es
  124.         ret
  125.  
  126. putc        endp
  127.  
  128. prtnum        proc    near    ; print half a byte on screen
  129.         push    ds    ; this procedure is used by prtax below
  130.         push    es
  131.  
  132.         push    cs
  133.         pop    ds
  134.  
  135.         push    bx
  136.         mov    bx,crt_seg
  137.         mov    es,bx
  138.         mov    bx,offset xltab
  139.         xlatb
  140.         mov    bx,cs:lcpos
  141.         mov    es:[bx],al
  142.         inc    cs:lcpos
  143.         inc    cs:lcpos
  144.  
  145.         pop    bx
  146.         pop    es
  147.         pop    ds
  148.         ret
  149. xltab        db    '0123456789ABCDEF'
  150. prtnum        endp
  151.  
  152. prtax        proc    near    ; print contents of ax register on screen
  153.         push    cx    ; all registers are preserved
  154.         push    ax
  155.         mov    al,ah
  156.         mov    cl,4
  157.         shr    al,cl
  158.         call    prtnum
  159.         pop    ax
  160.         push    ax
  161.         mov    al,ah
  162.         and    al,0Fh
  163.         call    prtnum
  164.         pop    ax
  165.         push    ax
  166.         mov    cl,4
  167.         shr    al,cl
  168.         call    prtnum
  169.         pop    ax
  170.         push    ax
  171.         and    al,0Fh
  172.         call    prtnum
  173.         pop    ax
  174.         pop    cx
  175.         ret
  176. prtax        endp
  177.  
  178. ;
  179. ; BIOS call dispatcher
  180. ;
  181.  
  182. ;
  183. ; data area
  184. ;
  185.  
  186. ;
  187. ; vector to ROM BIOS
  188. ;
  189.  
  190. romoff        dw    ?
  191. romseg        dw    ?
  192.  
  193. ;
  194. ; display variables
  195. ;
  196.  
  197. active_page    db    ?    ; parameters for wtty (window I/O) proc.
  198. crt_mode    db    ?
  199. color        db    7
  200. rt_edge        db    79
  201. bot_edge    db    24
  202. lf_edge        db    0
  203. top_edge    db    0
  204. wd_width    db    79    ; window width and height (really the coords of
  205. wd_height    db    24    ; bottom corner relative to strt of window)
  206. wrap        db    0    ; 0=don't CRLF at right margin, 1=do
  207. raw        db    0    ; 0=xlate cr, lf, etc, 1=display w/o xlation
  208. crt_seg        dw    ?    ; segment for CRT display RAM
  209.  
  210. ;
  211. ; clock
  212. ;
  213.  
  214. tick        dw    0    ; 1/18th second counter
  215. tock        dw    0    ; every-5-seconds counter (18.2 Hz adjust)
  216. clk_oset    dw    0    ; save area for displaced clock int handler
  217. clk_seg        dw    0
  218.  
  219. ;
  220. ; window stack:
  221. ;   0[wsp] = left edge of window
  222. ;   1[wsp] = top edge of window
  223. ;   2[wsp] = right edge of window
  224. ;   3[wsp] = bottom edge of window
  225. ;   4[wsp] = cursor address (2 bytes)
  226. ;   6[wsp] = offset of window save area (2 bytes)
  227. ;   8[wsp] = segment of window save area (2 bytes)
  228. ;  10[wsp] = number of frames (1 byte)
  229. ;
  230.  
  231. wssize        equ    13         ; number of bytes in window stack frame
  232. wsframes    equ    15         ; number of windows that can be stacked
  233.  
  234. wsp        dw    offset wsend ; display window stack pointer
  235. wstack        db    wssize*wsframes dup (?) ; display window save stack
  236. wsend         equ    this word    ; bottom of stack
  237.         db    wssize dup (?) ; extra frame in case of user error
  238.  
  239. ;
  240. ; window queue: save area for windows
  241. ;
  242.  
  243. wqp        dw    offset qbase ; next avail byte in window queue
  244. wqsize        equ    8192         ; size of window queue - ok to tune
  245. qlim        dw    ?         ; max address in window queue
  246.  
  247. ;
  248. ;
  249.  
  250. temp        dw    ?         ; used when fixing up stack for return
  251.  
  252. ;
  253. ; jump table for our BIOS functions
  254. ;
  255.  
  256. jmptab        label    word
  257.         dw    offset    setwindow
  258.         dw    offset    pushwindow
  259.         dw    offset    rstwindow
  260.         dw    offset    frame
  261. tablen        equ    $-jmptab
  262.  
  263.  
  264. ;
  265. ; the dispatcher
  266. ;
  267.  
  268. disp        proc    far
  269.  
  270.         ;
  271.         ; see if it's one of our functions
  272.         ;
  273.  
  274.         cmp    ah,14        ; write TTY function
  275.         jne    tryrcp
  276.         jmp    ourfn
  277. tryrcp:        cmp    ah,3        ; read cursor position
  278.         jne    tryscp
  279.         jmp    readcsr
  280. tryscp:        cmp    ah,2        ; set cursor position
  281.         je    adjxy        ; have to adjust coordinates
  282.         cmp    ah,6        ; scroll screen up
  283.         jne    trysd        ; have to adjust corners
  284.         jmp    adjsc
  285. trysd:        cmp    ah,7        ; scroll screen down
  286.         jne    tryus        ; adjust corners
  287.         jmp    adjsc
  288. tryus:        cmp    ah,40H        ; one of our new functions?
  289.         jl    callbios    ; no, call the BIOS
  290.         jmp    ourfn
  291.  
  292. callbios:
  293.         push    cs:romseg    ; not one of ours; call BIOS
  294.         push    cs:romoff
  295.         ret
  296.  
  297. ;
  298. ; adjust x and y coordinates for set-cursor-position
  299. ;
  300. adjxy:
  301.         push    dx        ; save caller's dx
  302.  
  303.         add    dh,cs:top_edge    ; adjust the coordinates
  304.         cmp    dh,cs:bot_edge
  305.         jle    adjxy1
  306.  
  307.         ; if below the bottom edge, scroll up a line
  308.  
  309.         push    ax        ; save caller's registers
  310.         push    bx
  311.         push    cx
  312.         push    dx
  313.         push    si
  314.         push    di
  315.         mov    ax,0601H    ; scroll up one line
  316.         mov    cx,0        ; in the current window
  317.         mov    dh,cs:wd_height
  318.         mov    dl,cs:wd_width
  319.         mov    bh,cs:color
  320.         int    10H
  321.         pop    di        ; restore caller's registers
  322.         pop    si
  323.         pop    dx
  324.         pop    cx
  325.         pop    bx
  326.         pop    ax
  327.  
  328.         mov    dh,cs:bot_edge        ; now set cursor to bottom
  329.  
  330. adjxy1:        add    dl,cs:lf_edge
  331.         cmp    dl,cs:rt_edge
  332.         jle    adjxy2
  333.         mov    dl,cs:rt_edge
  334.  
  335.         ; fix up stack so BIOS's IRET will return to
  336.         ; our adjxy3 label
  337.  
  338. adjxy2:        mov    cs:temp,ax    ; save ax (can't push it!)
  339.         push    ax        ; a dummy flag register save
  340.         push    cs        ; return cs
  341.         mov    ax,offset adjxy3 ; return ip
  342.         push    ax
  343.         mov    ax,cs:temp    ; restore saved ax
  344.         jmp    callbios    ; and call the BIOS
  345.  
  346. adjxy3:
  347.         pop    dx        ; back from BIOS now: restore caller's
  348.         iret            ; dx, and return.
  349.  
  350. ;
  351. ; adjust corners for scroll
  352. ;
  353. adjsc:
  354.         push    bx
  355.         add    ch,cs:top_edge    ; adjust row posn of upper left
  356.         cmp    ch,cs:bot_edge
  357.         jle    adjsc1
  358.         mov    ch,cs:bot_edge
  359. adjsc1:        add    cl,cs:lf_edge    ; adjust column posn of upper left
  360.         cmp    cl,cs:rt_edge
  361.         jle    adjsc2
  362.         mov    cl,cs:rt_edge
  363. adjsc2:        add    dh,cs:top_edge    ; adjust row posn of lower right
  364.         cmp    dh,cs:bot_edge
  365.         jle    adjsc3
  366.         mov    dh,cs:bot_edge
  367. adjsc3:        add    dl,cs:lf_edge    ; adjust column posn of lower right
  368.         cmp    dl,cs:rt_edge
  369.         jle    adjsc4
  370.         mov    dl,cs:rt_edge
  371. adjsc4:        mov    bl,cs:bot_edge    ; adjust number of lines to scroll
  372.         sub    bl,cs:top_edge
  373.         cmp    al,bl
  374.         jle    adjsc5
  375.         mov    al,bl
  376. adjsc5:        pop    bx
  377.         jmp    callbios
  378.  
  379. readcsr:                ; read cursor position
  380.         push    ds        ; save registers that must be kept
  381.         push    bx
  382.  
  383.         mov    ax,40H        ; switch to ROM BIOS data segment
  384.         mov    ds,ax
  385.         mov    bl,bh        ; get param page number into bx
  386.         xor    bh,bh
  387.         sal    bx,1        ; convert to cursor table offset
  388.         mov    dx,[bx+50H]    ; read csr posn from cursor table
  389.         mov    cx,word ptr 60H ; read csr mode from mode word
  390.         push    cs        ; switch to our data segment
  391.         pop    ds
  392.         sub    dh,top_edge    ; adjust position for window corner
  393.         sub    dl,lf_edge
  394.  
  395.         ; make sure cursor address is in range -- adjust if not
  396.  
  397.         cmp    dh,0        ; check not above first row
  398.         jge    lrowok
  399.         mov    dh,0
  400. lrowok:        cmp    dh,wd_height    ; check not below last row
  401.         jle    hrowok
  402.         mov    dh,wd_height
  403. hrowok:        cmp    dl,0        ; check not left of first column
  404.         jge    lcolok
  405.         mov    dl,0
  406. lcolok:        cmp    dl,wd_width    ; check not right of last column
  407.         jle    hcolok
  408.         mov    dl,wd_width
  409. hcolok:
  410.         pop    bx        ; restore bx register
  411.         pop    ds        ; switch to caller's data segment
  412.         iret            ; and return
  413.  
  414.  
  415. ourfn:
  416.         ;
  417.         ; Process one of our functions.
  418.         ;
  419.  
  420.         cld        ; save all registers except ax
  421.         push    es
  422.         push    ds
  423.         push    dx
  424.         push    cx
  425.         push    bx
  426.         push    si
  427.         push    di
  428.  
  429.         push    cs    ; switch to our data/code segment
  430.         push    cs
  431.         pop    ds
  432.         pop    es
  433.  
  434.         ; find what routine they are invoking and call it
  435.  
  436.         cmp    ah,14
  437.         jne    newfns
  438.  
  439.         call    wtty
  440.         jmp    ourret
  441.  
  442. newfns:
  443.         mov    al,ah
  444.         xor    ah,ah
  445.         sub    al,40H
  446.         sal    ax,1
  447.         mov    si,ax
  448.         cmp    ax,tablen
  449.         jb    validjmp
  450.         jmp    ourret
  451. validjmp:
  452.         call    word ptr [si+offset jmptab]
  453.  
  454. ourret:
  455.         pop    di
  456.         pop    si
  457.         pop    bx
  458.         pop    cx
  459.         pop    dx
  460.         pop    ds
  461.         pop    es
  462.         clc
  463.         cmp    ax,0    ; did we return an error code?
  464.         je    ourretok ; no, leave carry cleared
  465.         stc        ; set carry
  466. ourretok:
  467.         ret    2    ; discard flags from interrupt
  468.  
  469. disp        endp
  470.  
  471. ;
  472. ; setwindow - set corners of the current display window.
  473. ; (ch,cl) = (row,column) of upper left corner
  474. ; (dh,dl) = (row,column) of lower right corner
  475. ;
  476.  
  477. setwindow    proc    near
  478.  
  479.     mov    lf_edge,cl
  480.     mov    top_edge,ch
  481.     mov    rt_edge,dl
  482.     mov    bot_edge,dh
  483.     mov    al,dh        ; compute relative bottom corner of window
  484.     sub    al,ch
  485.     mov    wd_height,al
  486.     mov    al,dl
  487.     sub    al,cl
  488.     mov    wd_width,al
  489.     mov    ax,0        ; always return successful
  490.     ret
  491.  
  492. setwindow    endp
  493.  
  494. ;
  495. ; setcolor - set attribute byte for display to al
  496. ;
  497.  
  498. setcolor    proc    near
  499.  
  500.     mov    color,al
  501.     ret
  502.  
  503. setcolor    endp
  504.  
  505. ;
  506. ; cls - clear the current window
  507. ;
  508.  
  509. cls    proc    near
  510.  
  511.     mov    cx,0
  512.     mov    dh,bot_edge
  513.     sub    dh,top_edge
  514.     mov    dl,rt_edge
  515.     sub    dl,lf_edge
  516.     mov    ax,0600H
  517.     mov    bh,color
  518.     int    10H
  519.     ret
  520.  
  521. cls    endp
  522.  
  523. ;
  524. ; savqcalc - compute parameters for the save/restore window operation
  525. ; No input parameters.
  526. ; results: cx = number of words to xfer
  527. ;          bl = number of words to transfer per line
  528. ;       bh = zero, used in counting words xferred on this line
  529. ;       dx = amount to add to screen pointer to wrap to next line
  530. ;       ax = same as cx
  531. ;
  532. savqcalc    proc    near
  533.  
  534.     mov    al,bot_edge    ; get number of words to xfer
  535.     sub    al,top_edge    ; compute number of lines in al
  536.     inc    al
  537.     mov    bl,rt_edge    ; compute number of words per line in bl
  538.     sub    bl,lf_edge
  539.     inc    bl
  540.     mov    dl,80        ; get wraparound increment in dx = 80-bl
  541.     xor    dh,dh
  542.     sub    dl,bl        ; compute word increment
  543.     shl    dx,1        ; convert to byte increment
  544.     mul    bl        ; multiply ax = al*bl
  545.     mov    cx,ax        ; gives word count to xfer, store in cx
  546.                 ; bl still contains # words to xfer per line
  547.     xor    bh,bh        ; zero out bh to count up to bl before wrapping
  548.     ret
  549.  
  550. savqcalc    endp
  551. ;
  552. ; pushwindow - push the current window state onto the window stack
  553. ;
  554.  
  555. pushwindow    proc    near
  556.  
  557.     ; first, save the new corners on stack
  558.  
  559.     push    cx
  560.     push    dx
  561.  
  562.     ; now see if there's room in the window queue:
  563.     ; compute ax = (endrow-strtrow+1)*(endcol-strtcol+1)*2
  564.     ; add ax to queue pointer and see if it overflows qlim
  565.  
  566.     mov    al,dh        ; get ending row
  567.     sub    al,ch        ; subtract starting row
  568.     inc    al        ; add 1
  569.  
  570.     mov    bl,dl        ; get ending column
  571.     sub    bl,cl        ; subtract starting column
  572.     inc    bl        ; add 1
  573.  
  574.     mul    bl        ; multiply the dimensions
  575.     shl    ax,1        ; and mult by 2 to convert to byte count
  576.  
  577.     add    ax,wqp        ; add the byte count to the queue pointer
  578.     cmp    ax,qlim        ; compare against end of queue
  579.     jl    pushok        ; if less, go ahead
  580.  
  581.     pop    dx        ; no room.  get back dx and cx
  582.     pop    cx
  583.     mov    ax,1        ; set error code in ax
  584.     jmp    nosav        ; and don't do the save
  585.  
  586.  
  587.     ; save window corners and cursor position
  588. pushok:
  589.     sub    wsp,wssize    ; adjust the stack pointer down a frame
  590.     mov    bx,wsp
  591.     mov    al,lf_edge
  592.     mov    [bx],al
  593.     mov    al,top_edge
  594.     mov    1[bx],al
  595.     mov    al,rt_edge
  596.     mov    2[bx],al
  597.     mov    al,bot_edge
  598.     mov    3[bx],al
  599.     mov    ah,3
  600.     mov    bh,0
  601.     int    10H        ; get current cursor position
  602.     mov    bx,wsp        ; get window stack pointer back
  603.     mov    4[bx],dx    ; save current cursor position
  604.  
  605.     ; set up the new window
  606.  
  607.     pop    dx        ; get back the new window corners
  608.     pop    cx
  609.  
  610.     call    setwindow    ; set the window corners
  611.  
  612.     ; now, save the area occupied by new window
  613.  
  614.     ; compute area to be saved
  615.  
  616.     mov    al,top_edge    ; get starting address in CRT segment
  617.     mov    bl,160
  618.     mul    bl
  619.     add    al,lf_edge    ; ax = top_edge*160 * lf_edge*2
  620.     adc    ah,0
  621.     add    al,lf_edge
  622.     adc    ah,0
  623.     mov    si,ax        ; store it in the si
  624.  
  625.     call    savqcalc    ; compute size of save area, etc.
  626.  
  627.     mov    di,wqp        ; set di to next byte in window queue
  628.  
  629.     push    ds        ; save ds for switch to screen segment
  630.     mov    ax,crt_seg    ; switch ds to screen segment
  631.     mov    ds,ax
  632.  
  633. ;;;    assume    ds:0B000H
  634.  
  635.     cld
  636.                 ; save address of screen save area on stack
  637.     push    di        ; so we can get it back later
  638.  
  639. pshmov:
  640.     movsw            ; move a word
  641.     inc    bh        ; inc count of words moved
  642.     cmp    bh,bl        ; done with this line?
  643.     jge    pshnxt        ; yes, go move to next line
  644.     loop    pshmov
  645.     jmp    pshdon
  646. pshnxt:
  647.     add    si,dx        ; increment si by wraparound increment
  648.     xor    bh,bh        ; zero out the words-per-line counter
  649.     loop    pshmov        ; and go move next word
  650.  
  651. pshdon:                ; here when finished saving
  652.     mov    ax,di        ; remember next free mem address
  653.  
  654.     pop    di        ; get back the starting address of save area
  655.     pop    ds        ; get back our data segment
  656.  
  657. ;;;    assume    ds:dseg
  658.  
  659.     mov    wqp,ax        ; now set wqp to next free mem address
  660.     mov    bx,wsp        ; get window stack pointer back again
  661.     mov    6[bx],di    ; save screen save area address on stack
  662.     mov    8[bx],es    ; (this word is currently always our ds)
  663.  
  664.     mov    ax,0        ; set no-error code
  665. nosav:
  666.     ret
  667.  
  668. pushwindow    endp
  669.  
  670.  
  671. ;
  672. ; rstwindow - restore most recent window state from stack
  673. ;
  674. rstwindow    proc    near
  675.  
  676.     ; first make sure there's a window on the stack
  677.  
  678.     cmp    wsp,offset wsend
  679.     jl    rstok
  680.     mov    ax,1        ; nothing on stack. set error code in ax
  681.     jmp    norst        ; and don't restore
  682.  
  683. rstok:
  684.     ; restore screen contents
  685.  
  686.     mov    bx,wsp        ; get window stack pointer
  687.     mov    al,10[bx]    ; delete the frames around the window
  688.     sub    lf_edge,al
  689.     sub    top_edge,al
  690.     add    rt_edge,al
  691.     add    bot_edge,al
  692.     shl    al,1
  693.     add    wd_width,al
  694.     add    wd_height,al
  695.     mov    byte ptr 10[bx],0 ; now there are no frames around the window
  696.  
  697.     push    es
  698.     mov    di,crt_seg    ; get address of screen segment into es
  699.     mov    es,di
  700.  
  701. ;;;    assume    es:0B000H
  702.  
  703.     ; compute area to be restored
  704.  
  705.     mov    al,top_edge    ; get starting address in CRT segment
  706.     mov    bl,160
  707.     mul    bl
  708.     add    al,lf_edge    ; ax = top_edge*160 + lf_edge*2
  709.     adc    ah,0
  710.     add    al,lf_edge
  711.     adc    ah,0
  712.     mov    di,ax        ; store it in the di
  713.  
  714.     mov    bx,wsp        ; get back our window stack pointer
  715.     mov    si,6[bx]    ; get address of window save area
  716.     mov    wqp,si        ; delete save area while we've got the address
  717.  
  718.     call    savqcalc
  719.  
  720.     cld
  721. rstmov:
  722.     movsw            ; move a word
  723.     inc    bh        ; inc count of words moved
  724.     cmp    bh,bl        ; done with this line?
  725.     jge    rstnxt        ; yes, go move to next line
  726.     loop    rstmov
  727.     jmp    rstdon
  728. rstnxt:
  729.     add    di,dx        ; increment si by wraparound increment
  730.     xor    bh,bh        ; zero out the words-per-line counter
  731.     loop    rstmov        ; and go move next word
  732.  
  733. rstdon:                ; here when finished saving
  734.     pop    es        ; get our es back
  735.  
  736. ;;;    assume    es:dseg
  737.  
  738.     ; restore the screen corners and cursor position
  739.  
  740.     mov    bx,wsp        ; get stack frame
  741.     mov    al,[bx]        ; restore corners
  742.     mov    lf_edge,al
  743.     mov    al,1[bx]
  744.     mov    top_edge,al
  745.     mov    al,2[bx]
  746.     mov    rt_edge,al
  747.     mov    al,3[bx]
  748.     mov    bot_edge,al
  749.  
  750.     mov    al,bot_edge    ; compute relative window edges
  751.     sub    al,top_edge
  752.     mov    wd_height,al
  753.     mov    al,rt_edge
  754.     sub    al,lf_edge
  755.     mov    wd_width,al
  756.  
  757.     mov    dx,4[bx]    ; set cursor position
  758.     mov    ah,2
  759.     mov    bh,0
  760.     int    10H
  761.  
  762.  
  763.     add    wsp,wssize    ; delete this stack frame
  764.     mov    ax,0        ; return no-error code
  765. norst:
  766.     ret            ; and return
  767.  
  768. rstwindow    endp
  769.  
  770. ;
  771. ; frame - draw a frame around the current window
  772. ;
  773.  
  774. frame    proc    near
  775.  
  776.     push    es        ; switch es to crt segment
  777.     mov    ax,crt_seg
  778.     mov    es,ax
  779.  
  780.     mov    al,top_edge    ; find starting address of window
  781.     mov    bl,160        ; ax = top_edge*160 + lf_edge*2
  782.     mul    bl
  783.     mov    bl,lf_edge
  784.     shl    bl,1
  785.     add    al,bl
  786.     adc    ah,0
  787.     mov    si,ax        ; store it in the si for horizontals
  788.     mov    di,ax        ; and in di for drawing verticals
  789.  
  790.     mov    al,wd_height    ; find distance to bottom line of window
  791.     mov    bl,160        ; ax = wd_height*160
  792.     mul    bl
  793.     mov    bx,ax        ; store it in the bx
  794.  
  795.     mov    byte ptr es:[si],0daH ; put on the top and bottom corners
  796.     mov    byte ptr es:[si+bx],0c0H
  797.     inc    si
  798.     mov    ah,color    ; fill in attributes for corners
  799.     mov    byte ptr es:[si],ah
  800.     mov    byte ptr es:[si+bx],ah
  801.     inc    si
  802.  
  803.     mov    cl,wd_width    ; get width of window, minus 2
  804.     xor    ch,ch
  805.     dec    cx
  806.     mov    al,0c4H        ; get horizontal line into ax
  807.     mov    ah,color
  808.  
  809. horiz:                ; draw the 2 horizontals
  810.     mov    word ptr es:[si],ax
  811.     mov    word ptr es:[si+bx],ax
  812.     add    si,2
  813.     loop    horiz
  814.  
  815.     mov    al,0bfH        ; top right corner
  816.     mov    word ptr es:[si],ax
  817.     mov    al,0d9H        ; bottom right corner
  818.     mov    word ptr es:[si+bx],ax
  819.  
  820.     mov    si,di        ; get back starting address of window
  821.     mov    bl,wd_width    ; get width of window minus 1 into bx
  822.     xor    bh,bh
  823.     shl    bx,1
  824.     add    si,160        ; move down a line (don't overwrite corners)
  825.     mov    cl,wd_height    ; get height of window, minus 2, into cx
  826.     xor    ch,ch
  827.     dec    cx
  828.     mov    al,0B3H        ; get vertical line into al
  829.     mov    ah,color    ; get attribute into ah
  830.  
  831. vert:                ; draw the two verticals
  832.     mov    word ptr es:[si],ax
  833.     mov    word ptr es:[si+bx],ax
  834.     add    si,160
  835.     loop    vert
  836.  
  837.     inc    lf_edge        ; shrink the window
  838.     inc    top_edge
  839.     dec    rt_edge
  840.     dec    bot_edge
  841.     sub    wd_width,2
  842.     sub    wd_height,2
  843.     mov    bx,wsp
  844.     inc    byte ptr 10[bx] ; increment count of frames
  845.  
  846.     pop    es
  847.     ret
  848.  
  849. frame    endp
  850.  
  851.  
  852. ;
  853. ; wtty - same as function 14 in ROM BIOS, but uses windows.
  854. ;
  855. wtty    proc    near
  856.  
  857.     ; get CRT mode into ah and crt_mode
  858.     ; get active page into active_page
  859.  
  860.     push    es
  861.     push    bx
  862.     mov    bx,40H
  863.     mov    es,bx
  864.     mov    bx,62H        ; 62H = offset active page
  865.     mov    ah,es:[bx]
  866.     mov    active_page,ah
  867.     mov    bx,49H        ; 49H = offset CRT mode
  868.     mov    ah,es:[bx]
  869.     mov    crt_mode,ah
  870.     pop    bx
  871.     pop    es
  872.  
  873.     push    ax        ; save registers
  874.     push    ax        ; save char to write
  875.  
  876.     ; read cursor position (inline for speed)
  877.  
  878.     push    ds        ; save registers that must be kept
  879.     push    bx
  880.  
  881.     mov    ax,40H        ; switch to ROM BIOS data segment
  882.     mov    ds,ax
  883.     mov    bl,bh        ; get param page number into bx
  884.     xor    bh,bh
  885.     sal    bx,1        ; convert to cursor table offset
  886.     mov    dx,[bx+50H]    ; read csr posn from cursor table
  887.     mov    cx,word ptr 60H ; read csr mode from mode word
  888.     push    cs        ; switch to our data segment
  889.     pop    ds
  890.     sub    dh,top_edge    ; adjust position for window corner
  891.     sub    dl,lf_edge
  892.  
  893.     pop    bx        ; restore bx register
  894.     pop    ds        ; switch to caller's data segment
  895.  
  896.     ; end of read-cursor-position
  897.  
  898.     pop    ax        ; get back character
  899.  
  900.     cmp    raw,0        ; raw I/O mode?
  901.     jne    rawio        ; yes, no special char xlation
  902.  
  903.     cmp    al,8        ; BS?
  904.     je    dobsp
  905.     cmp    al,0dH        ; CR?
  906.     je    docr
  907.     cmp    al,0aH        ; LF?
  908.     je    dolf
  909.     cmp    al,07H        ; BEL?
  910.     je    dobel
  911.     cmp    al,09H        ; TAB?
  912.     je    dotab
  913.  
  914. rawio:
  915.     mov    bh,active_page    ; set active page into bh which we got above
  916.     mov    bl,color    ; get color also (attribute byte)
  917.  
  918.     mov    ah,9        ; write character/attribute BIOS call
  919.     mov    cx,1        ; write only once
  920.     int    10H
  921.  
  922.     inc    dl        ; advance cursor one position
  923.     cmp    wrap,0        ; wrap-around on?
  924.     je    scrpos        ; no, don't wrap
  925.     cmp    dl,wd_width    ; at the right edge of the screen?
  926.     jnz    scrpos        ; no, don't wrap
  927.     mov    dl,0        ; yes, move it to left edge
  928.     cmp    dh,wd_height    ; at bottom of screen?
  929.     jnz    down1        ; no, just move it down a line
  930.  
  931. sclreq:                ; have to scroll
  932.     mov    ah,2        ; jmp here to set cursor position also
  933.     mov    bh,0
  934.     int    10H
  935.  
  936.     mov    al,crt_mode    ; get the crt mode
  937.     cmp    al,4
  938.     jc    gcolor
  939.     cmp    al,7
  940.     mov    bh,color     ; fill with proper fg/bg 
  941.     jne    scrl1
  942.  
  943. gcolor:
  944.     mov    bh,color    ; get filler fg/bg
  945.  
  946. scrl1:
  947.     mov    ax,601H        ; scroll one line
  948.     mov    cx,0        ; get current screen corners
  949.     mov    dh,wd_height
  950.     mov    dl,wd_width
  951. xint10:
  952.     int    10h        ; do scroll - here also for gen'l int 10 call
  953. wtret1:             ; jmp here to return from wtty
  954.     pop    ax        ; restore the character we wrote
  955.     ret
  956.  
  957. down1:                ; move cursor down a line
  958.     inc    dh
  959. scrpos:                ; jmp here to do set-cursor call
  960.     mov    ah,2
  961.     jmp    xint10
  962.  
  963. dobsp:                ; backspace
  964.     cmp    dl,0        ; do nothing if already at left edge
  965.     je    scrpos
  966.     dec    dl        ; move back one position
  967.     jmp    scrpos
  968.  
  969. docr:                ; carriage return
  970.     mov    dl,0
  971.     jmp    scrpos
  972.  
  973. dolf:                ; linefeed
  974.     cmp    dh,wd_height
  975.     jl    down1        ; just move down
  976.     jmp    sclreq        ; scroll (*** fix- makes redundant set csr call!)
  977.  
  978. dobel:                ; bell
  979.     mov    bl,2
  980.     call    beep
  981.     jmp    wtret1
  982.  
  983. dotab:                ; tab
  984.     mov    ah,3
  985.     mov    bh,0        ; get cursor position
  986.     int    10H
  987.     add    dl,8        ; increment it by 8
  988.     and    dl,0F8H        ; mask it down
  989.     mov    ah,2        ; set cursor position
  990.     int    10H
  991.     jmp    wtret1        ; and return from call
  992.  
  993. wtty    endp
  994.  
  995. ;
  996. ; beep the speaker for desired interval.  This is how IBM does it -- kind
  997. ; of a mystery why they didn't put a counter in the clk int routine to turn
  998. ; the beeper off to avoid busy-waiting...
  999. ; This beeper is set up to sound like the Z19 beeper, which I especially like.
  1000. ;
  1001.  
  1002. beep    proc    near
  1003.     mov    al,10110110B    ; command to timer - generate square wave
  1004.     out    43H,al
  1005.     mov    ax,0700H    ; count to produce beep frequency
  1006.     out    42H,al
  1007.     mov    al,ah
  1008.     out    42H,al
  1009.     in    al,61H        ; get orig. value in PPI with spkr enable bit
  1010.     mov    ah,al
  1011.     or    al,03        ; turn on speaker enable, starting beep
  1012.     out    61H,al
  1013.     mov    cx,2000H    ; this determines beep duration
  1014. bpwt:    loop    bpwt
  1015.     mov    al,ah        ; turn speaker enable off, stopping beep
  1016.     out    61H,al
  1017.     ret
  1018. beep    endp
  1019.  
  1020. ;
  1021. ; everything below this point will be deleted from memory once the initial
  1022. ; command exits
  1023. ;
  1024.  
  1025. qbase        equ    this word
  1026. start        proc    near
  1027.  
  1028.         ; determine what kind of CRT is in use
  1029.  
  1030.         int    11H
  1031.         and    ax,0030H
  1032.         cmp    ax,0030H
  1033.         jne    iscolor
  1034.         mov    crt_seg,0B000H
  1035.         jmp    setvec
  1036. iscolor:
  1037.         mov    crt_seg,0B800H
  1038.  
  1039. setvec:
  1040.         ; set up the BIOS vectors
  1041.  
  1042.         mov    ax,0
  1043.         mov    es,ax
  1044.         mov    ax,word ptr es:40H
  1045.         mov    romoff,ax
  1046.         mov    ax,word ptr es:42H
  1047.         mov    romseg,ax
  1048.  
  1049.         mov    ax,offset disp
  1050.         mov    word ptr es:40H,ax
  1051.         mov    ax,cs
  1052.         mov    word ptr es:42H,ax
  1053.  
  1054.         mov    dx,offset qbase ; get starting address for window queue
  1055.         add    dx,wqsize    ; allocate space for window queue
  1056.         mov    qlim,dx        ; save end of queue to test later
  1057.  
  1058.         int    27H
  1059.  
  1060. start        endp
  1061.  
  1062. cseg        ends
  1063.  
  1064.         end    cpstart
  1065.