home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / WBIOS.ZIP / WBIOS.ASM
Encoding:
Assembly Source File  |  1986-10-31  |  22.0 KB  |  1,046 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. ;;; Code Segment
  78. ;;;
  79.  
  80. cseg    segment    para public 'code'
  81.     assume    cs:cseg,ds:cseg,ss:cseg,es:nothing
  82.  
  83.     org    100H
  84. ;;;
  85. ;;; COM program startup
  86. ;;;
  87.  
  88. cpstart    proc    far
  89.     jmp    near ptr start
  90. cpstart    endp
  91.  
  92. ;;;
  93. ;;; Local Procedures
  94. ;;;
  95.  
  96. lcpos    dw    0E60H
  97.  
  98. putc    proc    near        ; write a string to display W/O DOS intervention
  99.     push    es
  100.     push    ax
  101.     mov    ax,crt_seg
  102.     mov    es,ax
  103.     mov    di,cs:lcpos
  104. putc1:
  105.     mov    al,cs:[si]
  106.     cmp    al,'$'
  107.     je    putc2
  108.     cmp    al,0dH
  109.     jne    putc3
  110.     mov    cs:lcpos,0E60H
  111.     mov    di,0E60H
  112.     jmp    putc4
  113.  
  114. putc3:    mov    es:[di],al
  115.     inc    di
  116.     inc    di
  117.  
  118. putc4:    inc    si
  119.     jmp    putc1
  120.  
  121. putc2:    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. temp    dw      ?        ; used when fixing up stack for return
  248.  
  249. ;;;
  250. ;;; jump table for our BIOS functions
  251. ;;;
  252.  
  253. jmptab    label    word
  254.     dw    offset    setwindow
  255.     dw    offset    pushwindow
  256.     dw    offset    rstwindow
  257.     dw    offset    frame
  258. tablen    equ    $-jmptab
  259.  
  260. ;;;
  261. ;;; the dispatcher
  262. ;;;
  263.  
  264. disp    proc    far
  265.  
  266. ;;;
  267. ;;; see if it's one of our functions
  268. ;;;
  269.  
  270.     cmp    ah,14        ; write TTY function
  271.      jne    tryrcp
  272.     jmp    ourfn
  273. tryrcp:    cmp    ah,3        ; read cursor position
  274.      jne    tryscp
  275.     jmp    readcsr
  276. tryscp:    cmp    ah,2        ; set cursor position
  277.      je    adjxy        ; have to adjust coordinates
  278.     cmp    ah,6        ; scroll screen up
  279.      jne    trysd        ; have to adjust corners
  280.     jmp    adjsc
  281. trysd:    cmp    ah,7        ; scroll screen down
  282.      jne    tryus        ; adjust corners
  283.     jmp    adjsc
  284. tryus:    cmp    ah,40H        ; one of our new functions?
  285.      jl    callbios    ; no, call the BIOS
  286.     jmp    ourfn
  287.  
  288. callbios:
  289.     push    cs:romseg    ; not one of ours; call BIOS
  290.     push    cs:romoff
  291.     ret
  292.  
  293. ;;;
  294. ;;; adjust x and y coordinates for set-cursor-position
  295. ;;;
  296.  
  297. adjxy:    push    dx        ; save caller's dx
  298.  
  299.     add    dh,cs:top_edge    ; adjust the coordinates
  300.     cmp    dh,cs:bot_edge
  301.      jle    adjxy1
  302.  
  303. ;;; if below the bottom edge, scroll up a line
  304.  
  305.     push    ax        ; save caller's registers
  306.     push    bx
  307.     push    cx
  308.     push    dx
  309.     push    si
  310.     push    di
  311.     mov    ax,0601H    ; scroll up one line
  312.     mov    cx,0        ; in the current window
  313.     mov    dh,cs:wd_height
  314.     mov    dl,cs:wd_width
  315.     mov    bh,cs:color
  316.     int    10H
  317.     pop    di        ; restore caller's registers
  318.     pop    si
  319.     pop    dx
  320.     pop    cx
  321.     pop    bx
  322.     pop    ax
  323.  
  324.     mov    dh,cs:bot_edge    ; now set cursor to bottom
  325.  
  326. adjxy1:    add    dl,cs:lf_edge
  327.     cmp    dl,cs:rt_edge
  328.     jle    adjxy2
  329.     mov    dl,cs:rt_edge
  330.  
  331. ;;; fix up stack so BIOS's IRET will return to
  332. ;;; our adjxy3 label
  333.  
  334. adjxy2:    mov    cs:temp,ax    ; save ax (can't push it!)
  335.     push    ax        ; a dummy flag register save
  336.     push    cs        ; return cs
  337.     mov    ax,offset adjxy3    ; return ip
  338.     push    ax
  339.     mov    ax,cs:temp    ; restore saved ax
  340.     jmp    callbios    ; and call the BIOS
  341.  
  342. adjxy3:    pop    dx        ; back from BIOS now: restore caller's
  343.     iret            ; dx, and return.
  344.  
  345. ;;;
  346. ;;; adjust corners for scroll
  347. ;;;
  348. adjsc:    push    bx
  349.     add    ch,cs:top_edge    ; adjust row posn of upper left
  350.     cmp    ch,cs:bot_edge
  351.      jle    adjsc1
  352.     mov    ch,cs:bot_edge
  353. adjsc1:    add    cl,cs:lf_edge    ; adjust column posn of upper left
  354.     cmp    cl,cs:rt_edge
  355.      jle    adjsc2
  356.     mov    cl,cs:rt_edge
  357. adjsc2:    add    dh,cs:top_edge    ; adjust row posn of lower right
  358.     cmp    dh,cs:bot_edge
  359.      jle    adjsc3
  360.     mov    dh,cs:bot_edge
  361. adjsc3:    add    dl,cs:lf_edge    ; adjust column posn of lower right
  362.     cmp    dl,cs:rt_edge
  363.      jle    adjsc4
  364.     mov    dl,cs:rt_edge
  365. adjsc4:    mov    bl,cs:bot_edge    ; adjust number of lines to scroll
  366.     sub    bl,cs:top_edge
  367.     cmp    al,bl
  368.      jle    adjsc5
  369.     mov    al,bl
  370. adjsc5:    pop    bx
  371.     jmp    callbios
  372.  
  373. readcsr:            ; read cursor position
  374.     push    ds        ; save registers that must be kept
  375.     push    bx
  376.  
  377.     mov    ax,40H        ; switch to ROM BIOS data segment
  378.     mov    ds,ax
  379.     mov    bl,bh        ; get param page number into bx
  380.     xor    bh,bh
  381.     sal    bx,1        ; convert to cursor table offset
  382.     mov    dx,[bx+50H]    ; read csr posn from cursor table
  383.     mov    cx,word ptr 60H ; read csr mode from mode word
  384.     push    cs        ; switch to our data segment
  385.     pop    ds
  386.     sub    dh,top_edge    ; adjust position for window corner
  387.     sub    dl,lf_edge
  388.  
  389. ;;; make sure cursor address is in range -- adjust if not
  390.  
  391.     cmp    dh,0        ; check not above first row
  392.      jge    lrowok
  393.     mov    dh,0
  394. lrowok:    cmp    dh,wd_height    ; check not below last row
  395.      jle    hrowok
  396.     mov    dh,wd_height
  397. hrowok:    cmp    dl,0        ; check not left of first column
  398.      jge    lcolok
  399.     mov    dl,0
  400. lcolok:    cmp    dl,wd_width    ; check not right of last column
  401.      jle    hcolok
  402.     mov    dl,wd_width
  403. hcolok:    pop    bx        ; restore bx register
  404.     pop    ds        ; switch to caller's data segment
  405.     iret            ; and return
  406.  
  407.  
  408. ourfn:
  409. ;;;
  410. ;;; Process one of our functions.
  411. ;;;
  412.  
  413.     cld            ; save all registers except ax
  414.     push    es
  415.     push    ds
  416.     push    dx
  417.     push    cx
  418.     push    bx
  419.     push    si
  420.     push    di
  421.  
  422.     push    cs        ; switch to our data/code segment
  423.     push    cs
  424.     pop    ds
  425.     pop    es
  426.  
  427. ;;; find what routine they are invoking and call it
  428.  
  429.     cmp    ah,14
  430.      jne    newfns
  431.  
  432.     call    wtty
  433.     jmp    ourret
  434.  
  435. newfns:    mov    al,ah
  436.     xor    ah,ah
  437.     sub    al,40H
  438.     sal    ax,1
  439.     mov    si,ax
  440.     cmp    ax,tablen
  441.      jb    validjmp
  442.     jmp    ourret
  443. validjmp:
  444.     call    word ptr [si+offset jmptab]
  445.  
  446. ourret:    pop    di
  447.     pop    si
  448.     pop    bx
  449.     pop    cx
  450.     pop    dx
  451.     pop    ds
  452.     pop    es
  453.     clc
  454.     cmp    ax,0        ; did we return an error code?
  455.      je    ourretok    ; no, leave carry cleared
  456.     stc            ; set carry
  457. ourretok:
  458.     ret    2        ; discard flags from interrupt
  459.  
  460. disp    endp
  461.  
  462. ;;;
  463. ;;; setwindow - set corners of the current display window.
  464. ;;; (ch,cl) = (row,column) of upper left corner
  465. ;;; (dh,dl) = (row,column) of lower right corner
  466. ;;;
  467.  
  468. setwindow proc    near
  469.  
  470.     mov    lf_edge,cl
  471.     mov    top_edge,ch
  472.     mov    rt_edge,dl
  473.     mov    bot_edge,dh
  474.     mov    al,dh        ; compute relative bottom corner of window
  475.     sub    al,ch
  476.     mov    wd_height,al
  477.     mov    al,dl
  478.     sub    al,cl
  479.     mov    wd_width,al
  480.     mov    ax,0        ; always return successful
  481.     ret
  482.  
  483. setwindow endp
  484.  
  485. ;;;
  486. ;;; setcolor - set attribute byte for display to al
  487. ;;;
  488.  
  489. setcolor proc    near
  490.  
  491.     mov    color,al
  492.     ret
  493.  
  494. setcolor endp
  495.  
  496. ;;;
  497. ;;; cls - clear the current window
  498. ;;;
  499.  
  500. cls    proc    near
  501.  
  502.     mov    cx,0
  503.     mov    dh,bot_edge
  504.     sub    dh,top_edge
  505.     mov    dl,rt_edge
  506.     sub    dl,lf_edge
  507.     mov    ax,0600H
  508.     mov    bh,color
  509.     int    10H
  510.     ret
  511.  
  512. cls    endp
  513.  
  514. ;;;
  515. ;;; savqcalc - compute parameters for the save/restore window operation
  516. ;;; No input parameters.
  517. ;;; results: cx = number of words to xfer
  518. ;;;    bl = number of words to transfer per line
  519. ;;;    bh = zero, used in counting words xferred on this line
  520. ;;;    dx = amount to add to screen pointer to wrap to next line
  521. ;;;    ax = same as cx
  522. ;;;
  523. savqcalc proc    near
  524.  
  525.     mov    al,bot_edge    ; get number of words to xfer
  526.     sub    al,top_edge    ; compute number of lines in al
  527.     inc    al
  528.     mov    bl,rt_edge    ; compute number of words per line in bl
  529.     sub    bl,lf_edge
  530.     inc    bl
  531.     mov    dl,80        ; get wraparound increment in dx = 80-bl
  532.     xor    dh,dh
  533.     sub    dl,bl        ; compute word increment
  534.     shl    dx,1        ; convert to byte increment
  535.     mul    bl        ; multiply ax = al*bl
  536.     mov    cx,ax        ; gives word count to xfer, store in cx
  537.                 ; bl still contains # words to xfer per line
  538.     xor    bh,bh        ; zero out bh to count up to bl before wrapping
  539.     ret
  540.  
  541. savqcalc    endp
  542.  
  543. ;;;
  544. ;;; pushwindow - push the current window state onto the window stack
  545. ;;;
  546.  
  547. pushwindow proc    near
  548.  
  549. ;;; first, save the new corners on stack
  550.  
  551.     push    cx
  552.     push    dx
  553.  
  554. ;;; now see if there's room in the window queue:
  555. ;;; compute ax = (endrow-strtrow+1)*(endcol-strtcol+1)*2
  556. ;;; add ax to queue pointer and see if it overflows qlim
  557.  
  558.     mov    al,dh        ; get ending row
  559.     sub    al,ch        ; subtract starting row
  560.     inc    al        ; add 1
  561.  
  562.     mov    bl,dl        ; get ending column
  563.     sub    bl,cl        ; subtract starting column
  564.     inc    bl        ; add 1
  565.  
  566.     mul    bl        ; multiply the dimensions
  567.     shl    ax,1        ; and mult by 2 to convert to byte count
  568.  
  569.     add    ax,wqp        ; add the byte count to the queue pointer
  570.     cmp    ax,qlim        ; compare against end of queue
  571.      jl      pushok    ; if less, go ahead
  572.  
  573.     pop    dx        ; no room.  get back dx and cx
  574.     pop    cx
  575.     mov    ax,1        ; set error code in ax
  576.     jmp    nosav        ; and don't do the save
  577.  
  578. ;;; save window corners and cursor position
  579. pushok:    sub    wsp,wssize    ; adjust the stack pointer down a frame
  580.     mov    bx,wsp
  581.     mov    al,lf_edge
  582.     mov    [bx],al
  583.     mov    al,top_edge
  584.     mov    1[bx],al
  585.     mov    al,rt_edge
  586.     mov    2[bx],al
  587.     mov    al,bot_edge
  588.     mov    3[bx],al
  589.     mov    ah,3
  590.     mov    bh,0
  591.     int    10H        ; get current cursor position
  592.     mov    bx,wsp        ; get window stack pointer back
  593.     mov    4[bx],dx    ; save current cursor position
  594.  
  595. ;;; set up the new window
  596.  
  597.     pop    dx        ; get back the new window corners
  598.     pop    cx
  599.  
  600.     call    setwindow    ; set the window corners
  601.  
  602. ;;; now, save the area occupied by new window
  603. ;;; compute area to be saved
  604.  
  605.     mov    al,top_edge    ; get starting address in CRT segment
  606.     mov    bl,160
  607.     mul    bl
  608.     add    al,lf_edge    ; ax = top_edge*160 * lf_edge*2
  609.     adc    ah,0
  610.     add    al,lf_edge
  611.     adc    ah,0
  612.     mov    si,ax        ; store it in the si
  613.  
  614.     call    savqcalc    ; compute size of save area, etc.
  615.  
  616.     mov    di,wqp        ; set di to next byte in window queue
  617.  
  618.     push    ds        ; save ds for switch to screen segment
  619.     mov    ax,crt_seg    ; switch ds to screen segment
  620.     mov    ds,ax
  621.  
  622. ;;;    assume     ds:0B000H
  623.  
  624.     cld
  625.                 ; save address of screen save area on stack
  626.     push    di        ; so we can get it back later
  627.  
  628. pshmov:    movsw            ; move a word
  629.     inc    bh        ; inc count of words moved
  630.     cmp    bh,bl        ; done with this line?
  631.      jge    pshnxt        ; yes, go move to next line
  632.     loop    pshmov
  633.     jmp    pshdon
  634. pshnxt:    add    si,dx        ; increment si by wraparound increment
  635.     xor    bh,bh        ; zero out the words-per-line counter
  636.     loop    pshmov        ; and go move next word
  637.  
  638. pshdon:                ; here when finished saving
  639.     mov    ax,di        ; remember next free mem address
  640.  
  641.     pop    di         ; get back the starting address of save area
  642.     pop    ds         ; get back our data segment
  643.  
  644. ;;;    assume     ds:dseg
  645.  
  646.     mov    wqp,ax        ; now set wqp to next free mem address
  647.     mov    bx,wsp        ; get window stack pointer back again
  648.     mov    6[bx],di    ; save screen save area address on stack
  649.     mov    8[bx],es    ; (this word is currently always our ds)
  650.  
  651.     mov    ax,0        ; set no-error code
  652. nosav:    ret
  653.  
  654. pushwindow    endp
  655.  
  656.  
  657. ;;;
  658. ;;; rstwindow - restore most recent window state from stack
  659. ;;;
  660.  
  661. rstwindow proc    near
  662.  
  663. ;;; first make sure there's a window on the stack
  664.  
  665.     cmp    wsp,offset wsend
  666.      jl    rstok
  667.     mov    ax,1        ; nothing on stack. set error code in ax
  668.     jmp    norst        ; and don't restore
  669.  
  670. rstok:
  671. ;;; restore screen contents
  672.  
  673.     mov    bx,wsp        ; get window stack pointer
  674.     mov    al,10[bx]    ; delete the frames around the window
  675.     sub    lf_edge,al
  676.     sub    top_edge,al
  677.     add    rt_edge,al
  678.     add    bot_edge,al
  679.     shl    al,1
  680.     add    wd_width,al
  681.     add    wd_height,al
  682.     mov    byte ptr 10[bx],0 ; now there are no frames around the window
  683.  
  684.     push    es
  685.     mov    di,crt_seg    ; get address of screen segment into es
  686.     mov    es,di
  687.  
  688. ;;;    assume     es:0B000H
  689.  
  690. ;;; compute area to be restored
  691.  
  692.     mov    al,top_edge    ; get starting address in CRT segment
  693.     mov    bl,160
  694.     mul    bl
  695.     add    al,lf_edge    ; ax = top_edge*160 + lf_edge*2
  696.     adc    ah,0
  697.     add    al,lf_edge
  698.     adc    ah,0
  699.     mov    di,ax        ; store it in the di
  700.  
  701.     mov    bx,wsp        ; get back our window stack pointer
  702.     mov    si,6[bx]    ; get address of window save area
  703.     mov    wqp,si        ; delete save area while we've got the address
  704.  
  705.     call    savqcalc
  706.  
  707.     cld
  708. rstmov:    movsw            ; move a word
  709.     inc    bh        ; inc count of words moved
  710.     cmp    bh,bl        ; done with this line?
  711.      jge    rstnxt        ; yes, go move to next line
  712.     loop    rstmov
  713.     jmp    rstdon
  714. rstnxt:    add    di,dx        ; increment si by wraparound increment
  715.     xor    bh,bh        ; zero out the words-per-line counter
  716.     loop    rstmov        ; and go move next word
  717.  
  718. rstdon:                ; here when finished saving
  719.     pop    es        ; get our es back
  720.  
  721. ;;;    assume     es:dseg
  722.  
  723. ;;; restore the screen corners and cursor position
  724.  
  725.     mov    bx,wsp        ; get stack frame
  726.     mov    al,[bx]        ; restore corners
  727.     mov    lf_edge,al
  728.     mov    al,1[bx]
  729.     mov    top_edge,al
  730.     mov    al,2[bx]
  731.     mov    rt_edge,al
  732.     mov    al,3[bx]
  733.     mov    bot_edge,al
  734.  
  735.     mov    al,bot_edge    ; compute relative window edges
  736.     sub    al,top_edge
  737.     mov    wd_height,al
  738.     mov    al,rt_edge
  739.     sub    al,lf_edge
  740.     mov    wd_width,al
  741.  
  742.     mov    dx,4[bx]    ; set cursor position
  743.     mov    ah,2
  744.     mov    bh,0
  745.     int    10H
  746.  
  747.     add    wsp,wssize    ; delete this stack frame
  748.     mov    ax,0        ; return no-error code
  749. norst:    ret            ; and return
  750.  
  751. rstwindow    endp
  752.  
  753. ;;;
  754. ;;; frame - draw a frame around the current window
  755. ;;;
  756.  
  757. frame    proc     near
  758.  
  759.     push    es        ; switch es to crt segment
  760.     mov    ax,crt_seg
  761.     mov    es,ax
  762.  
  763.     mov    al,top_edge    ; find starting address of window
  764.     mov    bl,160        ; ax = top_edge*160 + lf_edge*2
  765.     mul    bl
  766.     mov    bl,lf_edge
  767.     shl    bl,1
  768.     add    al,bl
  769.     adc    ah,0
  770.     mov    si,ax        ; store it in the si for horizontals
  771.     mov    di,ax        ; and in di for drawing verticals
  772.  
  773.     mov    al,wd_height    ; find distance to bottom line of window
  774.     mov    bl,160        ; ax = wd_height*160
  775.     mul    bl
  776.     mov    bx,ax        ; store it in the bx
  777.  
  778.     mov    byte ptr es:[si],0daH    ; put on the top and bottom corners
  779.     mov    byte ptr es:[si+bx],0c0H
  780.     inc    si
  781.     mov    ah,color    ; fill in attributes for corners
  782.     mov    byte ptr es:[si],ah
  783.     mov    byte ptr es:[si+bx],ah
  784.     inc    si
  785.  
  786.     mov    cl,wd_width    ; get width of window, minus 2
  787.     xor    ch,ch
  788.     dec    cx
  789.     mov    al,0c4H        ; get horizontal line into ax
  790.     mov    ah,color
  791.  
  792. ;;; draw the 2 horizontals
  793.  
  794. horiz:    mov    word ptr es:[si],ax
  795.     mov    word ptr es:[si+bx],ax
  796.     add    si,2
  797.     loop    horiz
  798.  
  799.     mov    al,0bfH        ; top right corner
  800.     mov    word ptr es:[si],ax
  801.     mov    al,0d9H        ; bottom right corner
  802.     mov    word ptr es:[si+bx],ax
  803.  
  804.     mov    si,di        ; get back starting address of window
  805.     mov    bl,wd_width    ; get width of window minus 1 into bx
  806.     xor    bh,bh
  807.     shl    bx,1
  808.     add    si,160        ; move down a line (don't overwrite corners)
  809.     mov    cl,wd_height    ; get height of window, minus 2, into cx
  810.     xor    ch,ch
  811.     dec    cx
  812.     mov    al,0B3H        ; get vertical line into al
  813.     mov    ah,color    ; get attribute into ah
  814.  
  815. ;;; draw the two verticals
  816. vert:    mov    word ptr es:[si],ax
  817.     mov    word ptr es:[si+bx],ax
  818.     add    si,160
  819.     loop    vert
  820.  
  821.     inc    lf_edge        ; shrink the window
  822.     inc    top_edge
  823.     dec    rt_edge
  824.     dec    bot_edge
  825.     sub    wd_width,2
  826.     sub    wd_height,2
  827.     mov    bx,wsp
  828.     inc    byte ptr 10[bx] ; increment count of frames
  829.  
  830.     pop    es
  831.     ret
  832.  
  833. frame    endp
  834.  
  835. ;;;
  836. ;;; wtty - same as function 14 in ROM BIOS, but uses windows.
  837. ;;;
  838.  
  839. wtty    proc    near
  840.  
  841. ;;; get CRT mode into ah and crt_mode
  842. ;;; get active page into active_page
  843.  
  844.     push    es
  845.     push    bx
  846.     mov    bx,40H
  847.     mov    es,bx
  848.     mov    bx,62H        ; 62H = offset active page
  849.     mov    ah,es:[bx]
  850.     mov    active_page,ah
  851.     mov    bx,49H        ; 49H = offset CRT mode
  852.     mov    ah,es:[bx]
  853.     mov    crt_mode,ah
  854.     pop    bx
  855.     pop    es
  856.  
  857.     push    ax        ; save registers
  858.     push    ax        ; save char to write
  859.  
  860. ;;; read cursor position (inline for speed)
  861.  
  862.     push    ds        ; save registers that must be kept
  863.     push    bx
  864.  
  865.     mov    ax,40H        ; switch to ROM BIOS data segment
  866.     mov    ds,ax
  867.     mov    bl,bh        ; get param page number into bx
  868.     xor    bh,bh
  869.     sal    bx,1        ; convert to cursor table offset
  870.     mov    dx,[bx+50H]    ; read csr posn from cursor table
  871.     mov    cx,word ptr 60H ; read csr mode from mode word
  872.     push    cs        ; switch to our data segment
  873.     pop    ds
  874.     sub    dh,top_edge    ; adjust position for window corner
  875.     sub    dl,lf_edge
  876.  
  877.     pop    bx        ; restore bx register
  878.     pop    ds        ; switch to caller's data segment
  879.  
  880. ;;; end of read-cursor-position
  881.  
  882.     pop    ax        ; get back character
  883.  
  884.     cmp    raw,0        ; raw I/O mode?
  885.      jne    rawio        ; yes, no special char xlation
  886.  
  887.     cmp    al,8        ; BS?
  888.      je    dobsp
  889.     cmp    al,0dH        ; CR?
  890.      je    docr
  891.     cmp    al,0aH        ; LF?
  892.      je    dolf
  893.     cmp    al,07H        ; BEL?
  894.      je    dobel
  895.     cmp    al,09H        ; TAB?
  896.      je    dotab
  897.  
  898. rawio:    mov    bh,active_page    ; set active page into bh which we got above
  899.     mov    bl,color    ; get color also (attribute byte)
  900.  
  901.     mov    ah,9        ; write character/attribute BIOS call
  902.     mov    cx,1        ; write only once
  903.     int    10H
  904.  
  905.     inc    dl        ; advance cursor one position
  906.     cmp    wrap,0        ; wrap-around on?
  907.      je    scrpos        ; no, don't wrap
  908.     cmp    dl,wd_width    ; at the right edge of the screen?
  909.      jnz    scrpos        ; no, don't wrap
  910.     mov    dl,0        ; yes, move it to left edge
  911.     cmp    dh,wd_height    ; at bottom of screen?
  912.      jnz    down1        ; no, just move it down a line
  913.  
  914. sclreq:                ; have to scroll
  915.     mov    ah,2        ; jmp here to set cursor position also
  916.     mov    bh,0
  917.     int    10H
  918.  
  919.     mov    al,crt_mode    ; get the crt mode
  920.     cmp    al,4
  921.      jc    gcolor
  922.     cmp    al,7
  923.     mov    bh,color    ; fill with proper fg/bg
  924.      jne    scrl1
  925.  
  926. gcolor:    mov    bh,color    ; get filler fg/bg
  927.  
  928. scrl1:    mov    ax,601H        ; scroll one line
  929.     mov    cx,0        ; get current screen corners
  930.     mov    dh,wd_height
  931.     mov    dl,wd_width
  932. xint10:    int    10h        ; do scroll - here also for gen'l int 10 call
  933. wtret1:                ; jmp here to return from wtty
  934.     pop    ax        ; restore the character we wrote
  935.     ret
  936.  
  937. down1:                ; move cursor down a line
  938.     inc    dh
  939. scrpos:                ; jmp here to do set-cursor call
  940.     mov    ah,2
  941.     jmp    xint10
  942.  
  943. dobsp:                ; backspace
  944.     cmp    dl,0        ; do nothing if already at left edge
  945.      je    scrpos
  946.     dec    dl        ; move back one position
  947.     jmp    scrpos
  948.  
  949. docr:                ; carriage return
  950.     mov    dl,0
  951.     jmp    scrpos
  952.  
  953. dolf:                ; linefeed
  954.     cmp    dh,wd_height
  955.      jl    down1        ; just move down
  956.     jmp    sclreq        ; scroll (*** fix- makes redundant set csr call!)
  957.  
  958. dobel:                ; bell
  959.     mov    bl,2
  960.     call    beep
  961.     jmp    wtret1
  962.  
  963. dotab:                ; tab
  964.     mov    ah,3
  965.     mov    bh,0        ; get cursor position
  966.     int    10H
  967.     add    dl,8        ; increment it by 8
  968.     and    dl,0F8H        ; mask it down
  969.     mov    ah,2        ; set cursor position
  970.     int    10H
  971.     jmp    wtret1        ; and return from call
  972.  
  973. wtty    endp
  974.  
  975. ;;;
  976. ;;; beep the speaker for desired interval.  This is how IBM does it -- kind
  977. ;;;of a mystery why they didn't put a counter in the clk int routine to turn
  978. ;;; the beeper off to avoid busy-waiting...
  979. ;;; This beeper is set up to sound like the Z19 beeper, which I especially like.
  980. ;;;
  981.  
  982. beep    proc    near
  983.     mov    al,10110110B    ; command to timer - generate square wave
  984.     out    43H,al
  985.     mov    ax,0700H    ; count to produce beep frequency
  986.     out    42H,al
  987.     mov    al,ah
  988.     out    42H,al
  989.     in    al,61H        ; get orig. value in PPI with spkr enable bit
  990.     mov    ah,al
  991.     or    al,03        ; turn on speaker enable, starting beep
  992.     out    61H,al
  993.     mov    cx,2000H    ; this determines beep duration
  994. bpwt:    loop     bpwt
  995.     mov    al,ah        ; turn speaker enable off, stopping beep
  996.     out    61H,al
  997.     ret
  998. beep    endp
  999.  
  1000. ;;;
  1001. ;;; everything below this point will be deleted from memory once the initial
  1002. ;;; command exits
  1003. ;;;
  1004.  
  1005. qbase    equ    this word
  1006. start    proc    near
  1007.  
  1008. ;;; determine what kind of CRT is in use
  1009.  
  1010.     int    11H
  1011.     and    ax,0030H
  1012.     cmp    ax,0030H
  1013.     jne    iscolor
  1014.     mov    crt_seg,0B000H
  1015.     jmp    setvec
  1016. iscolor:
  1017.     mov    crt_seg,0B800H
  1018.  
  1019. setvec:
  1020.  
  1021. ;;; set up the BIOS vectors
  1022.  
  1023.     mov    ax,0
  1024.     mov    es,ax
  1025.     mov    ax,word ptr es:40H
  1026.     mov    romoff,ax
  1027.     mov    ax,word ptr es:42H
  1028.     mov    romseg,ax
  1029.  
  1030.     mov    ax,offset disp
  1031.     mov    word ptr es:40H,ax
  1032.     mov    ax,cs
  1033.     mov    word ptr es:42H,ax
  1034.  
  1035.     mov    dx,offset qbase ; get starting address for window queue
  1036.     add    dx,wqsize    ; allocate space for window queue
  1037.     mov    qlim,dx        ; save end of queue to test later
  1038.  
  1039.     int    27H
  1040.  
  1041. start    endp
  1042.  
  1043. cseg    ends
  1044.  
  1045.     end    cpstart
  1046.