revlvl  equ     6                       ; Rev level 6, 12 March 1986
;;;REVLVL  EQU 5                           ;Revision level 6-25-85

;==============================================================================
;
; MSXTIPRO.ASM  This file contains system dependent routines for the
;               TI-Professional computer running MS-DOS version 2.10. This
;               version features interrupt driven I/O and H19/Tektronix 4010
;               emulation. This version has been tested at 9600 baud with
;               no loss of data.
;
; Credits:      Dan Smith       Computing Center        (303) 273-3396
;                               Colorado School of Mines
;                               Golden, Colorado 80241
;               Joe Smith (now at TYMSHARE, 39100 Liberty St, Fremont CA 94538)
;
;==============================================================================
; Add global entry point vtstat for use by Status in mssset.
; Clear terminal emulation flag, flags.vtflg, in procedure lclini.
; Add register save/restore in procedure getbaud.
; Bump rev level to 6. Joe R. Doupnik 12 March 1986

        include mssdef.h

        public  xofsnt, machnam, setktab, setkhlp, count

        public  serini, serrst, clrbuf, outchr, coms, vts, vtstat, dodel
        public  ctlu, cmblnk, locate, lclini, prtchr, dobaud, clearl
        public  dodisk, getbaud, beep, puthlp, poscur, putmod, clrmod
        public  sendbr, showkey

;=========================================================================
; Data Segment variables for Ti-Pro
;
; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
;    or port2)
; port1, port2 - portinfo structures for the corresponding ports
;
; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
;=========================================================================

datas   segment public 'datas'

        extrn   drives:byte,flags:byte
        extrn   portval:word,port1:byte,port2:byte,port3:byte,port4:byte

mntrgh  equ     bufsiz*3/4              ;High trigger point for XOFF

machnam db      'TI-PRO (Revision ',REVLVL+'0',')$'
badbd   db      cr,lf,'Unimplemented baud rate$'
shkmsg  db      'Not implemented.'
shklen  equ     $-shkmsg
setktab db      0               ;Must be defined. Used in Set Key command
setkhlp db      0               ;Must be defined. Used in Set Key ?
crlf    db      cr,lf,'$'
delstr  db      bs,bs,' ',bs,'$';Delete string.
clrlin  db      cr              ;Must be at clreol-1
clreol  db      esc,'[K$'       ;Clear line.
homeras db      esc,'[H',esc,'[J$' ;Home and erase
savint  dw      0,0             ;Place to save interrupt vector
invvid  db      esc,'[0;7m$'    ;Inverse video
norvid  db      esc,'[0;1m$'    ;Normal video (WHITE=BOLD, as opposed to GREEN)
xofsnt  db      0               ;Say if we sent an XOFF.
xofrcv  db      0               ;Say if we received an XOFF.
portin  db      0               ;Non-zero if port is initialized

source  db      bufsiz dup(?)   ;Circular buffer for data from port
savedi  dw      0               ;Input pointer for circular buffer
savesi  dw      0               ;Output pointer for circular buffer
count   dw      0               ;Number of characters in buffer

porttab db      04h             ;4 entries
        db      01h,'1$'
        dw      01h
        db      01h,'2$'
        dw      02h             ;*** NOTE: This is 2, not 0 ****
        db      01h,'3$'
        dw      03h
        db      01h,'4$'
        dw      04h

ontab   db      2               ;Number of entries
        db      03h,'OFF$'
        dw      0
        db      02h,'ON$'
        dw      1

modem   mdminfo <0e7h,0e6h,0e4h,0feh,001h,000h,40h*4>   ;Init to Port 1 parms

; Data to init Serial Controller
; Channel A parameters

parmta  db      09h             ;Select WR9
        db      0c0h            ;Reset 8530
        db      0bh             ;Select WR11
        db      50h             ;No XTAL, RxC=BRG=TxC, TRxC pin is an input
        db      0eh             ;Select WR14
        db      03h             ;BRG source is PCLK pin, enable BRG
        db      0fh             ;Select WR15
        db      0               ;Disable external status interrupts
        db      04h             ;Select WR4
        db      44h             ;x16 clock, 1 stop bit, no parity
        db      05h             ;Select WR5
        db      11101010b       ;Raise DTR+RTS, 8 bits, Tx enable
        db      03h             ;Select WR3
        db      0c1h            ;8 bits, enable receiver
        db      01h             ;Select WR1
        db      10h             ;Interrupt on all receive chars or spec. cond.
        db      9               ;Select WR9
        db      8               ;Master interrupt enable
parmas  equ     $-parmta

; Channel B parameters

parmtb  db      0fh             ;Select WR15
        db      00h             ;Disable external status interrupts
        db      01h             ;Select WR1
        db      00h             ;Disable all other interrupts
        db      05h             ;Select WR5
        db      02h             ;Raise RTSB (RCNTL) for internal modem
parmbs  equ     $-parmtb

baudat  label   word            ;Divisors for Z-8530 with 4.9152-MHz oscillator
        dw      0696h           ; 0   45.5 baud
        dw      05FEh           ; 1   50 baud
        dw      03FEh           ; 2   75 baud
        dw      02B8h           ; 3  110 baud (+0.03%)
        dw      0239h           ; 4  134.5 baud (Selectric)
        dw      01FEh           ; 5  150 baud
        dw      00FEh           ; 6  300 baud
        dw      007Eh           ; 7  600 baud
        dw      003Eh           ; 8 1200 baud
        dw      0029h           ; 9 1800 baud (-0.78%)
        dw      0024h           ;10 2000 baud (+1.05%)
        dw      001Eh           ;11 2400 baud
        dw      000Eh           ;12 4800 baud
        dw      0006h           ;13 9600 baud
        dw      0002h           ;14 19.2 kbaud
        dw      0000h           ;15 38.4 kbaud - not supported
baudlen equ     $-baudat        ;Size of table in bytes

datas   ends


; Serial port routines -- Initialize

code    segment public
        assume  cs:code,ds:datas

        extrn   comnd:near,dopar:near

;==============================================================================
; Initialization for using serial port.  Returns normally.
; This is called for by SEND, RECEIVE, and CONNECT commands.
;==============================================================================
        db      'serini'
serini  proc    near
        cmp     portin,2                ;Is it initialized already?
        jz      serinc                  ;Yes, skip all this
        cli                             ;Disable interrupts
        cld                             ;Do increments in string operations
        push    es                      ;Set interrupt vector
        xor     ax,ax
        mov     es,ax                   ;Point to vector segment
        mov     bx,modem.mdintv         ;Get vector address for this com port
        mov     ax,es:[bx]
        mov     savint,ax               ;Save old vector offset
        mov     ax,offset serint
        mov     es:[bx],ax              ;Replace with my offset
        mov     ax,es:[bx+2]
        mov     savint+2,ax             ;Save old vector segment
        mov     es:[bx+2],cs            ;Replace with my segment
        pop     es
        call    clrbuf                  ;Clear 8530 and memory buffers

        mov     si,offset parmta        ;Addr of port A parameter table
        cmp     portin,1                ;1 means reset but dont hang up modem
        jnz     sini10
        add     si,2                    ;Skip over hardware reset to avoid
                                        ;hanging up TI internal modems
sini10: mov     dx,modem.mdstat         ;Port A command/status addr
        in      al,dx                   ;Make sure it's pointing to WR0
        mov     cx,parmas               ;Table size
serina: lodsb                           ;Get a byte
        out     dx,al                   ;Send it to 8530
        loop    serina                  ;Do all of port A

        mov     si,offset parmtb        ;Addr of port-B parameter table
        mov     dx,modem.mdcom          ;Port B command/status addr
        in      al,dx                   ;Make sure it's pointing to WR0
        mov     cx,parmbs
serinb: lodsb                           ;Get a byte
        out     dx,al                   ;Send it to 8530
        loop    serinb

        in      al,19h                  ;Set up 8259a interrupt controller
        and     al,modem.mden           ;Enable IR0, IR1, IR2, or IR4
        out     19h,al

        sti                             ;Allow interrupts
serinc: mov     portin,2                ;Flag that port is set up
        ret
serini  endp

;==============================================================================
; Serial port interrupt handler. This routine gets all serial port interrupts
; and stores any data in a circular buffer.
;==============================================================================
        db      'serint'
serint  proc    near
        sti                             ;Enable interrupts
        push    ax                      ;Save registers used
        push    bx
        push    dx
        push    di
        push    ds
        push    es
        cld                             ;Auto increment
        mov     ax,seg datas
        mov     ds,ax                   ;Set segment registers
        mov     es,ax
        mov     dx,modem.mdstat         ;Get status register
        in      al,dx                   ;Read RR0 contents
        and     al,1                    ;See if any characters in receive FIFO
        jz      sint50                  ;Jump if not
        mov     dx,modem.mddat          ;Point to data register
        in      al,dx                   ;Get received character
        mov     bx,portval              ;Point to port data structure
        cmp     [bx].parflg,parnon      ;Is parity off?
        jz      sint5                   ;Jump if it is
        and     al,7fh                  ;Strip off parity
sint5:  or      al,al                   ;Throw away nulls
        jz      sint50
        cmp     [bx].floflg,0           ;Doing flow control?
        je      sint20                  ;No
        mov     dx,[bx].flowc           ;Flow control char, dh=XON, dl=XOFF
        cmp     al,dl                   ;Is it an XOFF?
        jne     sint10                  ;No, go on
        mov     xofrcv,1                ;Set flag
        jmp     short sint50
sint10: cmp     al,dh                   ;Did we get an XON?
        jne     sint20                  ;No, go on
        mov     xofrcv,0                ;Clear XOFF flag
        jmp     short sint50
sint20: mov     di,savedi               ;Point to buffer location
        stosb                           ;Store new char in circular buffer
        cmp     di,offset source+bufsiz ;Is buffer pointer at end?
        jb      sint30                  ;No, carry on
        mov     di,offset source        ;Wrap buffer pointer to start of buffer
sint30: inc     count                   ;Increment number of chars in buffer
        cmp     [bx].floflg,0           ;Doing flow control?
        je      sint40                  ;No, just leave
        cmp     xofsnt,1                ;Have we sent an XOFF already?
        je      sint40                  ;Yes, don't send another
        cmp     count,mntrgh            ;Past the high trigger point?
        jbe     sint40                  ;No, the buffer still has room
        mov     ah,dl                   ;Get the XOFF character
        call    outchr                  ;Send it
        nop                             ;Waste 3 bytes for skip returns
        nop                             ;  and ignore failures
        nop
        mov     xofsnt,1                ;Remember we sent it
sint40: mov     savedi,di               ;Update buffer pointer
sint50: cli
        mov     al,20h                  ;Get end of interrupt code
        out     18h,al                  ;Send End-of-Interrupt to 8259
        pop     es                      ;Restore registers
        pop     ds
        pop     di
        pop     dx
        pop     bx
        pop     ax
        iret
serint  endp

;==============================================================================
; Reset the serial port.  This is the opposite of SERINI.  Calling
; this twice without intervening calls to SERINI should be harmless.
; Returns normally.
;==============================================================================
serrst  proc    near
        mov     portin,1                ;1 means reset all but don't hangup
        cli                             ;  internal modem
        mov     dx,modem.mdstat         ;Point to channel A WR0
        mov     al,9
        out     dx,al                   ;Register 9 write
        xor     al,al
        nop
        out     dx,al                   ;disable 8530 interrupts
        in      al,19h                  ;Disable 8259a IR line
        or      al,modem.mddis
        out     19h,al
        push    es                      ;Reset interrupt vector
        xor     bx,bx
        mov     es,bx
        mov     bx,modem.mdintv         ;Get vector address
        mov     ax,savint
        mov     es:[bx],ax              ;Restore saved vector
        mov     ax,savint+2
        mov     es:[bx+2],ax
        pop     es
        sti
        ret                             ;All done.
serrst  endp

;==============================================================================
; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer.  This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
;==============================================================================
clrbuf  proc    near
        mov     ax,offset source
        mov     savedi,ax               ;Place to put next character received
        mov     savesi,ax               ;Place to get next character from
        mov     cx,8
        mov     dx,modem.mddat          ;Address channel-A data register
clrbf1: in      al,dx                   ;Clear out anything in the receive FIFO
        loop    clrbf1
        mov     count,cx                ;Set count to zero
        ret
clrbuf  endp

;==============================================================================
; Put the char in AH to the serial port.  This assumes the
; port has been initialized.  Should honor xon/xoff.  Skip returns on
; success, returns normally if the character cannot be written.
;==============================================================================
        db      'outchr'
outchr  proc    near
        push    bx
        push    cx
        push    dx
        mov     bx,portval
        cmp     [bx].floflg,0           ;Are we doing flow control.
        je      outch2                  ;No, just continue.
        xor     cx,cx                   ;clear counter
outch1: cmp     xofrcv,1                ;Are we being held?
        jne     outch2                  ;No - it's OK to go on.
        loop    outch1                  ;held, try for a while
        mov     xofrcv,0                ;timed out, force it off and fall thru.
outch2: mov     al,ah                   ;Parity routine works on AL.
        call    dopar                   ;Set parity appropriately.

        mov     ah,al                   ;Preserve character for a bit
        xor     cx,cx                   ;Set loop counter to max
        mov     dx,modem.mdstat         ;Port 1 channel A command/status address
outch3: in      al,dx                   ;Get RR0 contents
        and     al,04h                  ;Transmit buffer empty?
        jnz     outch4                  ;Yes, output char
        loop    outch3                  ;No, try again
        jmp     outch5                  ;Loop counter expired, give up
outch4: mov     dx,modem.mddat          ;Get port 1 channel A data address
        mov     al,ah                   ;Get the character
        out     dx,al                   ;Send it
        pop     dx
        pop     cx
        pop     bx
        jmp     rskp                    ;Skip return for OK

outch5: pop     dx
        pop     cx
        pop     bx
        ret                             ;Non-skip return due to timeout
outchr  endp

;==============================================================================
; Set the current port.  Called from SET PORT command
;==============================================================================
coms    proc    near
        mov     dx,offset porttab       ;Point to list of port number keywords
        mov     bx,0                    ;No help
        mov     ah,cmkey                ;Parse a keyword
        call    comnd
        jmp r                           ;Return for errors
        push    bx                      ;Save port number
        mov     ah,cmcfm
        call    comnd                   ;Get a confirm.
        jmp     comx                    ;Didn't get a confirm. error
        nop                             ;Need 3 bytes in here
        call    serrst                  ;Reset previous serial port
        pop     bx                      ;Restore desired comm port
        mov     flags.comflg,bl         ;Set the comm port flag.

        cmp     flags.comflg,1          ;Port 1?
        jne     coms2                   ;No, try another
        mov     portval,offset port1
        mov     modem.mddat,0e7h        ;Data reg
        mov     modem.mdstat,0e6h       ;Channel A command/status
        mov     modem.mdcom,0e4h        ;Channel B command/status
        mov     modem.mddis,01h         ;Mask to disable IR0
        mov     modem.mden,0feh         ;Mask to enable IR0
        mov     modem.mdintv,40h*4      ;Vector for IR0
        call    serini
        ret

coms2:  cmp     flags.comflg,2          ;Port 2?
        jne     coms3                   ;No, try another
        mov     portval,offset port2
        mov     modem.mddat,0efh        ;Data reg
        mov     modem.mdstat,0eeh       ;Channel A command/status
        mov     modem.mdcom,0ech        ;Channel B command/status
        mov     modem.mddis,02h         ;Mask to disable IR1
        mov     modem.mden,0fdh         ;Mask to enable IR1
        mov     modem.mdintv,41h*4      ;Vector for IR1
        call    serini
        ret

coms3:  cmp     flags.comflg,3          ;Port 3?
        jne     coms4                   ;No, try another
        mov     portval,offset port3
        mov     modem.mddat,0f7h        ;Data reg
        mov     modem.mdstat,0f6h       ;Channel A command/status
        mov     modem.mdcom,0f4h        ;Channel B command/status
        mov     modem.mddis,04h         ;Mask to disable IR2
        mov     modem.mden,0fbh         ;Mask to enable IR2
        mov     modem.mdintv,42h*4      ;Vector for IR2
        call    serini
        ret

coms4:  mov     portval,offset port4
        mov     modem.mddat,0ffh        ;Data reg
        mov     modem.mdstat,0feh       ;Channel A command/status
        mov     modem.mdcom,0fch        ;Channel B command/status
        mov     modem.mddis,10h         ;Mask to disable IR4
        mov     modem.mden,0efh         ;Mask to enable IR4
        mov     modem.mdintv,44h*4      ;Vector for IR4
        call    serini
        ret

comx:   pop bx
        ret
coms    endp

;==============================================================================
; Set heath emulation on/off.  Called from SET TERMINAL-EMULATION command
;==============================================================================
vts     proc    near
        mov     dx,offset ontab         ;Table containing OFF ON keywords
        mov     bx,0                    ;No help
        mov     ah,cmkey                ;Means parse a keyword
        call    comnd                   ;Parse for ON or OFF
        jmp     r                       ;Jump for errors
        push    bx                      ;Save returned code for ON or OFF
        mov     ah,cmcfm                ;Means parse a confirm
        call    comnd                   ;Wait for confirm
        jmp     short vt0               ;Jump for error
        nop                             ;Needs 3 bytes here
        pop     bx                      ;Restore return status
        mov     flags.vtflg,bl          ;Set H19 on/off global variable
        ret
vt0:    pop     bx
        ret
vts     endp

VTSTAT  PROC    NEAR    ; For Status display [jrd]
        ret             ; no emulator status to display
VTSTAT  ENDP


;==============================================================================
; Delete a character from the terminal.  This works by printing
; backspaces and spaces.  Returns normally.
;==============================================================================
dodel   proc    near
        mov     ah,9
        mov     dx,offset delstr        ;Backspace-space-backspace
        int     21h
        ret
dodel   endp

;==============================================================================
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
;==============================================================================
ctlu    proc    near
        mov     ah,9
        mov     dx,offset clrlin        ;Output CR, then clear to end of line
        int     21h
        ret
ctlu    endp

;==============================================================================
; This routine blanks the screen.  Returns normally.
;==============================================================================
cmblnk  proc    near
        mov     ah,13h          ;Function 13h of INT 49h clears the screen
        int     49h
        ret
cmblnk  endp

;==============================================================================
; Homes the cursor.  Returns normally.
;==============================================================================
locate  proc    near
        xor     dx,dx                   ;Go to top left corner of screen.
        jmp     poscur
locate  endp

;==============================================================================
; Local initialization
;==============================================================================
lclini  proc    near
        mov     flags.vtflg,0   ; no terminal emulation. [jrd]
        call    beep1           ;In case BASIC left the speaker messed up
        ret
lclini  endp

;==============================================================================
; Port read character.  Check the port status.  If no data, skip
; return.  Else, read in a char and return.
;==============================================================================
        db      'prtchr'
prtchr  proc    near
        call    chkxon                  ;See if we need to XON first
        cmp     count,0                 ;See if anything in buffer
        jnz     pc10                    ;Jump if something there
        jmp     rskp                    ;Skip return since nothing there
pc10:   mov     si,savesi               ;Get buffer pointer
        lodsb                           ;Get char from buffer
        cmp     si,offset source+bufsiz ;See if past end of buffer
        jb      pc20                    ;Jump if not
        mov     si,offset source        ;Wrap pointer to start of buffer
pc20:   dec     count                   ;1 less char in buffer
        mov     savesi,si               ;Save buffer pointer
        mov     dx,count                ;Return remaining count in DX
        ret
prtchr  endp

;==============================================================================
; Local routine to see if we have to transmit an xon
;==============================================================================
chkxon  proc    near
        push    bx
        mov     bx,portval
        cmp     [bx].floflg,0           ;Doing flow control?
        je      chkxo1                  ;No, skip all this
        cmp     xofsnt,0                ;Have we sent an xoff?
        je      chkxo1                  ;No, forget it
        cmp     count,mntrgh            ;Below trigger?
        jae     chkxo1                  ;No forget it
        mov     ax,[bx].flowc           ;AH gets xon
        call    outchr                  ;Send XON character
        nop
        nop
        nop                             ;In case it skips
        mov     xofsnt,0                ;Remember we've sent the XON.
chkxo1: pop     bx                      ;Restore register
        ret                             ;And return
chkxon  endp

;==============================================================================
; Set the baud rate for the current port, based on the value
; in the portinfo structure.  Returns normally.
; Called from SET BAUD command with new index in PORT.BAUD, previous in AX
;==============================================================================
        db      'dobaud'
dobaud  proc    near
        push    bx
        mov     bx,portval              ;Get pointer
        mov     bx,[bx].baud            ;Get new baud-rate index
        shl     bx,1                    ;Multiply by 2
        cmp     baudat[bx],0            ;Test for zero
        jne     dobod1                  ;Nonzero is OK
        mov     bx,portval              ;Error, get back to data structure
        mov     [bx].baud,ax            ;Restore previous baud rate number
        mov     ah,9
        mov     dx,offset badbd         ;Bad baud rate
        int     21h
        pop     bx
        ret

dobod1: mov     ax,baudat[bx]           ;Get BRG divisor
        call    setbaud                 ;Send AX to baud-rate-divisor
        pop     bx
        ret
dobaud  endp

;==============================================================================
; Local routine to send AX to the Baud Rate Generator.  Preserves all regs
;==============================================================================
setbaud proc    near
        push    dx
        push    ax                      ;Save rate
        mov     dx,modem.mdstat         ;Address the channel-A command port
        mov     al,13                   ;Point to register 13
        out     dx,al
        jmp     short $+2               ;Slight delay to let hardware respond
        mov     al,ah                   ;High-order part of divisor
        out     dx,al
        jmp     short $+2
        mov     al,12                   ;Point to register 12
        out     dx,al
        jmp     short $+2
        pop     ax
        out     dx,al                   ;Low-order part of divisor
        pop     dx
        ret
setbaud endp

;==============================================================================
; Clear to the end of the current line.  Returns normally.
;==============================================================================
clearl  proc    near
        mov     ah,9
        mov     dx,offset clreol        ;Erase from cursor to end of line
        int     21h
        ret
clearl  endp

;==============================================================================
; this is called by Kermit initialization.  It checks the
; number of disks on the system, sets the drives variable
; appropriately.  Returns normally.
;==============================================================================
dodisk  proc    near
        mov ah,gcurdsk                  ;Current disk value to AL.
        int 21h
        mov dl,al                       ;Put current disk in DL.
        mov ah,seldsk                   ;Select current disk.
        int 21h                         ;Returns number of drives in AL.
        mov drives,al                   ;Set global variable
        ret
dodisk  endp

;==============================================================================
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port.  Returns normally.
; This is used during initialization.
;==============================================================================
getbaud proc    near
        push    ax                      ; save some regs. [jrd]
        push    bx                      ; [jrd]
        push    cx                      ; [jrd]
        push    dx                      ; [jrd]
        mov     dx,modem.mdstat         ;Address channel-A command port
        mov     al,13                   ;Point to register 13
        out     dx,al
        jmp     short $+2               ;Small delay
        in      al,dx                   ;Read RR13
        mov     ah,al                   ;Save high-order part
        mov     al,12                   ;Point to register 12
        out     dx,al
        jmp     short $+2
        in      al,dx                   ;Read RR12
;Baud rate = (300*256)/(AX+2)
        mov     bx,0                    ;Index value
getbd1: cmp     ax,baudat[bx]           ;See if known value
        je      getbd2                  ;Found it
        add     bx,2                    ;Point to next word
        cmp     bl,baudlen              ;End of table?
        jl      getbd1                  ;No, keep looking
        mov     bx,B1200*2              ;Yes, force it to 1200 baud
        mov     ax,baudat[bx]
        call    setbaud

getbd2: mov     ax,bx                   ;Get the byte index
        shr     ax,1                    ;Reduce to number from 0 to 15
        mov     bx,portval              ;Point to structure
        mov     [bx].baud,ax            ;Store where SHOW processor can see it
        pop     dx                      ; restore regs. [jrd]
        pop     cx                      ; [jrd]
        pop     bx                      ; [jrd]
        pop     ax                      ; [jrd]
        ret
getbaud endp

;==============================================================================
; Produce a short beep.  The PC DOS bell is long enough to cause a loss
; of data at the port.  Returns normally.
;==============================================================================
beep1   proc    near
        mov     ah,2                    ;Set speaker frequency
        mov     cx,1000                 ;Approx 1.5 kHz
        int     48h
        ret
beep1   endp

beep    proc    near
        call    beep1                   ;Set the frequency
        mov     ah,0                    ;Timed beep function
        mov     al,5                    ;5/40 = 1/8 second
        int     48h
        ret
beep    endp

;==============================================================================
; Put a help message on the screen.
; Pass the message in ax, terminated by a null.  Returns normally.
;==============================================================================
puthlp  proc    near
        push    ax                      ;preserve this
        mov     ah,9
        mov     dx,offset crlf
        int     21h
        pop     si                      ;point to string again
puthl3: lodsb                           ;get a byte
        cmp     al,0                    ;end of string?
        je      puthl4                  ;yes, stop
        mov     dl,al
        mov     ah,6
        int     21h                     ;else write to screen
        jmp     puthl3                  ;and keep going
puthl4: mov     ah,9
        mov     dx,offset crlf
        int     21h
        ret
puthlp  endp

;==============================================================================
; Write a line at the bottom of the screen...
; the line is passed in dx, terminated by a $.  Returns normally.
;==============================================================================
putmod  proc    near
        push    dx                      ;preserve message
        mov     dx,24*100h              ;now address line 24
        call    poscur
        mov     dx,offset invvid
        mov     ah,9
        int     21h                     ;Set inverse video
        pop     dx                      ;get message back
        mov     ah,9
        int     21h                     ;write it out
        mov     dx,offset norvid
        mov     ah,9
        int     21h                     ;Normal video
        ret                             ;and return
putmod  endp

;==============================================================================
; Clear the mode line written by PUTMOD.  Returns normally.
;==============================================================================
clrmod  proc    near
        mov     dx,1800h
        call    poscur                  ;Go to bottom row.
        call    clearl                  ;Clear to end of line.
        ret
clrmod  endp

;==============================================================================
; Position the cursor according to contents of DX:
; DH contains row, DL contains column.  Returns normally.
;==============================================================================
poscur  proc    near
        xchg    dh,dl                   ;BIOS wants row in DL, Col in DH
        mov     ah,2                    ;Locate cursor function
        int     49h
        ret
poscur  endp

;==============================================================================
; Send a break out the current serial port.  Returns normally.
;==============================================================================
sendbr  proc    near
        push    cx
        push    dx
        push    ax
        xor     cx,cx                   ;Clear loop counter.
        mov     dx,modem.mdstat         ;Address channel-A command port
        mov     al,5                    ;Point to register 5
        out     dx,al
        jmp     short $+2
        in      al,dx                   ;Get current setting.
        mov     ah,al                   ;Copy the bits
        mov     al,5                    ;Point back to register 5
        out     dx,al
        mov     al,ah                   ;Get old bits
        or      al,10h                  ;Set send-break bit
        out     dx,al                   ;Start the break
pause:  loop    pause                   ;Wait a while.
        mov     al,5                    ;Point to register 5
        out     dx,al
        jmp     short $+2
        mov     al,ah                   ;Clear send-break bit
        out     dx,al                   ;Stop the break
        pop     ax
        pop     dx
        pop     cx
        ret                             ;And return.
        ret
sendbr  endp

;==============================================================================
; Called by the SHOW KEY command
;==============================================================================
showkey proc    near
        mov ax,offset shkmsg
        mov cx,shklen
        ret
showkey endp

;==============================================================================
; Jumping to this location is like retskp.  It assumes the instruction
; after the call is a jmp addr.
;==============================================================================
rskp    proc    near
        pop bp
        add bp,3
        push bp
        ret
rskp    endp

;==============================================================================
; Jumping here is the same as a ret. The jump to here uses up the 3 bytes
;==============================================================================
r       proc    near
        ret
r       endp

code    ends
        end
