PAGE    60,132  ;60 lines, 132 columns
TITLE   MSXTIPRO - Texas Instruments "Professional" code for KERMIT
REVLVL  EQU 3   ;Revision level for this module, 29-Nov-84

;************  REVISION HISTORY for MSXTIPRO.ASM  **********************
;
; REVLVL=1  29-Oct-84  First version to be able to transfer files
; REVLVL=2  14-Nov-84  Fixed bugs in version 1
; REVLVL=3  27-Nov-84  Added Tektronix-4010 emulation in CONNECT mode
;
;       -- CHANGES --
;
; MSXTIPRO has been tested with the Sync/Async Comm Card at all speeds from
; 110 to 9600 baud using SET PORT 1 thru SET PORT 4, and a 300-baud
; internal modem in port 3.
;
; To use the internal modem, SET PORT 3, SET BAUD 300, CONNECT.
; With external phone, type "O" to go into manual original mode.
; Or type "T1(617)467-7437X" to use the built-in dialer.  Capital T
; means to use touch-tones, capital X marks the end of the number.
;
; Terminal emulation works fine at 1200 baud, reasonably OK at 2400 baud
; if you use ".SET TERMINAL TYPE VT100 FILL 3" on TOPS-10.
;
; Can transfer file-packets at 9600 baud (but not 19.2 kbaud).
;
; The VT52 "identify yourself" sequence of ESC,'Z' triggers a response of
; ESC,'[?1;4c' which is a VT100 with graphics (but no STP, no printer).
;
;        -- BUGS --
;
; No known bugs at this time (28-Nov-84).
;
;        -- DEFICIENCIES --
;
; The STATUS command is wrong if you select port 2, 3, or 4.
;**** According to the MSXSYS.DOC, flags.comflg is supposed to be 0
;**** when using port 2.  This makes it difficult to use ports 3 and 4.
        extrn port3:byte, port4:byte            ;********
;**** MSCOMM.ASM must be edited to define PORT3 and PORT4 like PORT1 and 2.
;**** You MUST edit MSCOMM.ASM, and add the following at line 17:
;        port3   prtinfo <0FFFH,0,defpar,1,0,defhand,floxon>
;        port4   prtinfo <0FFFH,0,defpar,1,0,defhand,floxon>
;
; The SET HEATH-19 ON/OFF command needs to be replaced by a new command,
; SET TERMINAL-EMULATION ON/OFF/HEATH-19/VT52/VT100/VT102/ADM3A/TVI910/etc.
; In REVLVL=3, this command changes only the ID sequence for ESC-Z.
;
; ANSI.SYS is a part of the TI-BIOS, but it does not fully emulate a VT100.
;   FIX: Add more features to MSTEKTRM.ASM, rename it to MSVT241.ASM.
;   [I am working on this for version 4.  /Joe]
;
; Looses the 4th character after LF at 2400 baud when scrolling because DOS
; is so slow at outputing characters to the screen.  Looses even more at 9600
; baud.  (Although you can type "KERMIT SERVER" at transfer files at 9600.)
;   FIX: Use interrupt handling instead of polling USART, with XON/XOFF.
;        (Received a listing from Charlie Lindahl, not yet implemented)
;   [Feel free to add this, I will be working on MSVT241.  /Joe]
;
;*************************************************************************

;Credits:
; Joe Smith, Systems Programmer for DECsystem-10, CSM Computing Center
; Dan Smith, Microcomputer Programmer, CSM Computing Center
;   Colorado School of Mines, Golden CO 80401 (303)273-3448,273-3396
; Charlie Lindahl, Rusty Haddock, Steve Krueger, Larry Kroeker of TI
;   Texas Instruments Computer Science Laboratory
;   P.O. Box 226015 - MS 238, Dallas, TX 75266 (214)995-0376

        public  serini, serrst, clrbuf, outchr, coms, vts, dodel,
        public  ctlu, cmblnk, locate, lclini, prtchr, dobaud, clearl,
        public  dodisk, getbaud, beep
        public  count, xofsnt, puthlp, putmod, clrmod, poscur
        public  sendbr, term, machnam, setktab, setkhlp, showkey

        include msdefs.h
SUBTTL Constants used by Zilog Z-8530 Serial Communications Controller

;Taken from page 3-12 of the TI-PRO Technical Reference Manual 2223216-0001

SCC1_INTA EQU   0E0h    ;Port 1 interrupt acknowledge
SCC1_BCMD EQU   0E4h    ;Port 1 channel B command
SCC1_BDAT EQU   0E5h    ;Port 1 channel B data (not used)
SCC1_ACMD EQU   0E6h    ;Port 1 channel A command
SCC1_ADAT EQU   0E7h    ;Port 1 channel A data

SCC2_INTA EQU   0E8h    ;Port 2 interrupt acknowledge
SCC2_BCMD EQU   0ECh    ;Port 2 channel B command
SCC2_BDAT EQU   0EDh    ;Port 2 channel B data (not used)
SCC2_ACMD EQU   0EEh    ;Port 2 channel A command
SCC2_ADAT EQU   0EFh    ;Port 2 channel A data

SCC3_INTA EQU   0F0h    ;Port 3 interrupt acknowledge
SCC3_BCMD EQU   0F4h    ;Port 3 channel B command
SCC3_BDAT EQU   0F5h    ;Port 3 channel B data (not used)
SCC3_ACMD EQU   0F6h    ;Port 3 channel A command
SCC3_ADAT EQU   0F7h    ;Port 3 channel A data

SCC4_INTA EQU   0F8h    ;Port 4 interrupt acknowledge
SCC4_BCMD EQU   0FCh    ;Port 4 channel B command
SCC4_BDAT EQU   0FDh    ;Port 4 channel B data (not used)
SCC4_ACMD EQU   0FEh    ;Port 4 channel A command
SCC4_ADAT EQU   0FFh    ;Port 4 channel A data

;To send the INTACK signal to the Z8530, write anything to SCCx_INTA and then
;immdiately read from SCCx_INTA.  The 8-bit interrupt vector is returned.

;-------------------------------------------------------------------------------

;From ZILOG's Z8030/Z8050 SCC Serial Communications Controller Technical Manual

  ;Bits for WR0 - set by writing to SC1ACMD or SC1BCMD
SW0_SREG  EQU   00001111b       ;Set register pointer (if hi 4 bits all zero)
;;;_CMD1        --XXX---b       ;Command bits 1
  SW0_RESET EQU   010b*8          ;Reset EXT/STATUS (must be done twice)
  SW0_ABORT EQU   011b*8          ;Send ABORT (SDLC mode only)
  SW0_INTEN EQU   100b*8          ;Enable INT on next Rx character
  SW0_TXINT EQU   101b*8          ;Reset TxINT pending
  SW0_ERROR EQU   110b*8          ;Error reset (unlock FIFO)
  SW0_RHIUS EQU   111b*8          ;Reset highest IUS (interrupt under service)
;;;_CMD2        XX------b       ;Command bits 2
  SW0_RRCRC EQU 01b*64            ;Reset Rx CRC checker (SYNC)
  SW0_RTCRC EQU 10b*64            ;Reset Tx CRC generator (SYNC)
  SW0_RTEOM EQU 11b*64            ;Reset Tx underrun/EOM latch (SYNC)

  ;Bits for WR1 - Rx/Tx Interrupt and Data Transfer Mode
SW1_NOINT EQU   00000000b       ;Disable interrupts
SW1_EXINT EQU   00000001b       ;External/Status interrupt enable
SW1_TXINT EQU   00000010b       ;Transmit interrupt enable
SW1_PAREN EQU   00000100b       ;Parity error activates special condition
;;;_CMD         ---XX---b       ;Receive Interrupt Modes
  SW1_NORI  EQU    00b*16         ;Receive Interrupts Disabled
  SW1_I1ST  EQU    01b*16         ;Interrupt on 1st character or special condition
  SW1_IALL  EQU    10b*16         ;Interrupt on all character or special condition
  SW1_ISPC  EQU    11b*16         ;Interrupt on special condition only
SW1_REC   EQU   00100000b       ;Activate receive request (1 for transmit)
SW1_WAIT  EQU   01000000b       ;Activate the DMA request (0 for WAIT request)
SW1_DMAEN EQU   10000000b       ;Enable WAIT/DMA as selected by bits 5 & 6

  ;Bits for WR2 - Interrupt vector
SW2_VECT  EQU   11111111b       ;8-bits of interrupt vector

  ;Bits for WR3 - Receive Parameters and Control
SW3_RXEN  EQU   00000001b       ;Rx Enable (set only after all other parameters)
SW3_NSYNC EQU   00000010b       ;Sync character load inhibit (SYNC only)
SW3_ADDR  EQU   00000100b       ;Address search mode (SDLC only)
SW3_RXCRC EQU   00001000b       ;Enable Rx CRC (SDLC only)
SW3_HUNT  EQU   00010000b       ;Enter hunt mode (SYNC)
SW3_AUTOE EQU   00100000b       ;Autoenable, CTS for Tx, DCD for Rx enable
;;;_BITS        XX------b       ;Receive bits per character
  SW3_5BITS EQU 00b*64            ;5 bits per character
  SW3_6BITS EQU 01b*64            ;6 bits per character
  SW3_7BITS EQU 10b*64            ;7 bits per character
  SW3_8BITS EQU 11b*64            ;8 bits per character

  ;Bits for WR4 - Tx/Rx misc parameters and modes
SW4_PAREN EQU   00000001b       ;Parity enable (transmit and receive both)
SW4_EVENP EQU   00000010b       ;Even Parity (0 for Odd)
;;;_STOPB       ----XX--b         ;Number of stop bits
  SW4_SYNC  EQU     00b*4         ;Synchronous mode enable
  SW4_1STOP EQU     01b*4         ;1 stop bit
  SW4_1HALF EQU     10b*4         ;1.5 stop bits
  SW4_2STOP EQU     11b*4         ;2 stop bits
;;;_SYNCM       --XX----b       ;Sync modes
  SW4_8BIT  EQU   00b*16          ;8-bit sync character
  SW4_16BIT EQU   01b*16          ;16-bit sync character
  SW4_SDLC  EQU   10b*16          ;SDLC mode (pattern 01111110)
  SW4_EXTS  EQU   11b*16          ;External sync mode
;;;_CLOCK       XX------b       ;Clock rate
  SW4_X1    EQU 00b*64            ;Clock rate = data rate
  SW4_X16   EQU 01b*64            ;Clock rate = 16 times the data rate
  SW4_X32   EQU 10b*64            ;Clock rate = 32 times the data rate
  SW4_X64   EQU 11b*64            ;Clock rate = 64 times the data rate

  ;Bits for WR5 - Transmit parameters and control
SW5_TCRC  EQU   00000001b       ;Calculate and transmit CRC (SYNC only)
SW5_RTS   EQU   00000010b       ;Raise RTS (set RCNTL for B)
SW5_CRC16 EQU   00000100b       ;CRC-16 polynomial (0 for SDLC) (SYNC only)
SW5_TXEN  EQU   00001000b       ;Tx Enable (set only after all other parameters)
SW5_BREAK EQU   00010000b       ;Send a BREAK condition
;;;_BITS        -XX-----b       ;Transmit bits per character
  SW5_5BITS EQU  00b*32           ;5 or fewer bits per character
  SW5_6BITS EQU  01b*32           ;6 bits per character
  SW5_7BITS EQU  10b*32           ;7 bits per character
  SW5_8BITS EQU  11b*32           ;8 bits per character
SW5_DTR   EQU   10000000b       ;Raise DTR (set speed indicator for B)

  ;Bits for WR6 - SYNC character 0
SW6_SYNC  EQU   11111111b       ;Sync character

  ;Bits for WR7 - SYNC character 1
SW7_SYNC  EQU   11111111b       ;Sync character

  ;Bits for WR8 - Transmit data
SW8_DATA  EQU   11111111b       ;Same as writing to SCCx_xDAT

  ;Bits for WR9 - Master interrupt control
SW9_VSTAT EQU   00000001b       ;Int vector modified depending on status
SW9_NOVEC EQU   00000010b       ;No vector during interrupt acknowledge
SW9_IEOL  EQU   00000100b       ;Force Interrupt Enable Out low
SW9_MIEN  EQU   00001000b       ;Master Interrupt Enable
SW9_VEC16 EQU   00010000b       ;Int vector multiple of 16 (0 for mult of 2)
;;;_BIT5  EQU   00100000b       ;Unused, must be 0
;;;_RESET       XX------b       ;Reset channel commands
  SW9_CBR   EQU 01b*64            ;Channel A reset
  SW9_CAR   EQU 10b*64            ;Channel B reset
  SW9_RESET EQU 11b*64            ;Force hardware reset

  ;Bits for WR10 - Miscellaneous Transmit/Receive control bits
SWA_6BIT  EQU   00000001b       ;Use only 6 of 8 bits to detect sync character
SWA_LOOP  EQU   00000010b       ;Synchronous loop-back mode
SWA_ABORT EQU   00000100b       ;Sent abort on transmit underrun
SWA_MARK  EQU   00001000b       ;Send mark when idle (0 to send flag)
SWA_GAOP  EQU   00010000b       ;Go active on poll (SYNC only)
;;;_CODE        -XX-----b       ;Data encoding
  SWA_NRZ   EQU  00b*32           ;NRZ (1=1, 0=0) (ASYNC)
  SWA_NRZI  EQU  01b*32           ;NRZI (1=no change, 0=invert)
  SWA_FM1   EQU  10b*32           ;FM1 (1=high frequency, 0=low frequency)
  SWA_FM0   EQU  11b*32           ;FM0 (1=low frequency, 1=high frequency)
SWA_PCRC  EQU   10000000b       ;Preset CRC to all ones (0 for all zeros)

  ;Bits for WR11 - Clock mode control
;;;_TRXC        ------XXb       ;TRxC output control
  SWB_XTALO EQU       00b         ;TRxC output same as XTAL oscillator
  SWB_TRANS EQU       01b         ;TRxC output same as transmitter clock
  SWB_BRGO  EQU       10b         ;TRxC output same as baud rate generator
  SWB_DPLLO EQU       11b         ;TRxC output same as digital phase-locked-loop
SWB_TRXCO EQU   00000100b       ;TRxC pin is an output (0=TRxC is an input)
;;;_TXC         ---XX---b       ;Transmit clock
  SWB_TRTXC EQU    00b*8          ;Transmit clock = RTxC pin
  SWB_TTRXC EQU    01b*8          ;Transmit clock = TRxC pin
  SWB_TBRG  EQU    10b*8          ;Transmit clock = baud rate generator output
  SWB_TDPLL EQU    11b*8          ;Transmit clock = digital phase-locked-loop
;;;_RXC         -XX-----b       ;Receive clock
  SWB_RRTXC EQU  00b*32           ;Receive clock = RTxC pin
  SWB_RTRXC EQU  01b*32           ;Receive clock = TRxC pin
  SWB_RBRG  EQU  10b*32           ;Receive clock = baud rate generator output
  SWB_RDPLL EQU  11b*32           ;Receive clock = digital phase-locked-loop
SWB_XTAL  EQU   10000000b       ;Crystal is connected between RTxC and SYNC pins

  ;Bits for WR12 (low byte of divisor) and WR13 (high byte) in decimal.
SWC_BAUD  EQU   11111111b       ;Low byte
SWD_BAUD  EQU   11111111b       ;High byte

;Taken from page 3-10 of the TI-PRO Technical Reference Manual 2223216-0001
SCC_0045  EQU   1686    ;  45.5 baud
SCC_0050  EQU   1534    ;  50 baud
SCC_0075  EQU   1022    ;  75 baud
SCC_0100  EQU   0696    ; 110 baud (+0.03%)
SCC_0134  EQU   0569    ; 134.5 baud (Selectric)
SCC_0150  EQU   0510    ; 150 baud
SCC_0200  EQU   0382    ; 200 baud
SCC_0300  EQU   0254    ; 300 baud
SCC_0600  EQU   0126    ; 600 baud
SCC_1200  EQU   0062    ;1200 baud
SCC_1800  EQU   0041    ;1800 baud (-0.78%)
SCC_2000  EQU   0036    ;2000 baud (+1.05%)
SCC_2400  EQU   0030    ;2400 baud
SCC_3600  EQU   0019    ;3600 baud (+1.59%)
SCC_4800  EQU   0014    ;4800 baud
SCC_7200  EQU   0009    ;7200 baud (-3.03%)
SCC_9600  EQU   0006    ;9600 baud
SCC_19K2  EQU   0002    ;19.2 kbaud
  ;Divisor = (256*300/BAUD)-2 for 16x async clock with 4.9152 MHz crystal

  ;Bits for WR14 - Miscellaneous control bits
SWE_BRENA EQU   00000001b       ;Baud Rate Generator enable
SWE_PCLK  EQU   00000010b       ;BRG source is PCLK pin (1 for RTxC/XTAL)
SWE_DTREQ EQU   00000100b       ;DTR/REQ pin triggers DMA output cycle
SWE_AECHO EQU   00001000b       ;Auto Echo, TxD connected to RxD
SWE_LLOOP EQU   00010000b       ;Local Loopback on the digital side
;;;_DPLL        XXX-----b       ;Command field
  SWE_NUL  EQU  000b*32           ;Null command
  SWE_SEA  EQU  001b*32           ;DPLL enters search mode
  SWE_RMC  EQU  010b*32           ;Reset Missing Clock in FM mode
  SWE_DPL  EQU  011b*32           ;Disable DPLL
  SWE_SBR  EQU  100b*32           ;Set DPLL source = BRG clock
  SWE_STC  EQU  101b*32           ;Set DPLL source = RTxC clock
  SWE_SFM  EQU  110b*32           ;Set DPLL to FM mode
  SWE_SNR  EQU  111b*32           ;Set DPLL to NRZI mode

  ;Bits for WR15 - External/Status Interrupt Control
SWF_NOINT EQU   00000000b       ;Disable interrupts
;;;_BIT0  EQU   00000001b       ;Not used, must be 0
SWF_ZEROC EQU   00000010b       ;Interrupt when BRG count goes to zero
;;;_BIT2  EQU   00000100b       ;Not used, must be 0
SWF_DCD   EQU   00001000b       ;Interrupt when DCD changes state
SWF_SYNC  EQU   00010000b       ;Interrupt when SYNC changes state
SWF_CTS   EQU   00100000b       ;Interrupt when CTS changes state
SWF_EOM   EQU   01000000b       ;Interrupt when transmit underrun or EOM
SWF_BREAK EQU   10000000b       ;Interrupt when BREAK or ABORT condition

;-------------------------------------------------------------------------------

  ;Bits for RR0 - available by reading SC1ACMD or SC1BCMD
SR0_RBUFA EQU   00000001b       ;Receive buffer has character(s) available
SR0_ZEROC EQU   00000010b       ;Baud Rate Generator count is zero
SR0_TBUFE EQU   00000100b       ;Transmitter buffer empty (double-buffered)
SR0_DCD   EQU   00001000b       ;DCD is on (channel-B DCD connected to DSR)
SR0_SYNC  EQU   00010000b       ;SYNC in on (ACNTL or modem detected hi speed)
SR0_CTS   EQU   00100000b       ;CTS in on (channel-B CTS connected to RING)
SR0_EOM   EQU   01000000b       ;Transmitter underrun or EOM (SYNC only)
SR0_BREAK EQU   10000000b       ;BREAK (async) or ABORT (sync) condition

  ;Bits for RR1 - Special receive conditions
SR1_SENT  EQU   00000001b       ;Last transmit bit has left TxD pin
SR1_RES   EQU   00001110b       ;Residue from I-field (SDLC only)
SR1_PAR   EQU   00010000b       ;Parity error
SR1_OVER  EQU   00100000b       ;Receive overrun (FIFO overflowed)
SR1_FRAME EQU   01000000b       ;CRC or framing error
SR1_EOF   EQU   10000000b       ;End of Frame (SDLC only)

  ;Bits for RR3 - Interrupt Pending
SR3_BEXT  EQU   00000001b       ;Channel B external/status
SR3_BTX   EQU   00000010b       ;Channel B transmitter empty
SR3_BRX   EQU   00000100b       ;Channel B receiver full
SR3_AEXT  EQU   00001000b       ;Channel A external/status
SR3_ATX   EQU   00010000b       ;Channel A transmitter empty
SR3_ARX   EQU   00100000b       ;Channel A receiver full
;;;_BIT6  EQU   01000000b       ;Not used, always zero
;;;_BIT7  EQU   10000000b       ;Not used, always zero

  ;Bits for RR8 - Receive data
SR8_DATA  EQU   SW8_DATA        ;Same as writing to SCCx_xDAT

  ;Bits for RR10 - Miscellaneous status bits
;;;_BIT0  EQU   00000001b       ;Not used, always zero
SRA_LOOP  EQU   00000010b       ;On-loop condition (SDLC only)
;;;_BIT2  EQU   00000100b       ;Not used, always zero
;;;_BIT3  EQU   00001000b       ;Not used, always zero
SRA_SEND  EQU   00010000b       ;SCC is actively on-loop and sending now
;;;_BIT5  EQU   00100000b       ;Not used, always zero
SRA_2MISS EQU   01000000b       ;FM mode, 2 clocks missing
SRA_1MISS EQU   10000000b       ;FM mode, 1 clock missing

  ;Bits for RR12 - Low divisor
SRC_BAUD  EQU   SWC_BAUD        ;Returns current baud rate divisor

  ;Bits for RR13 - High divisor
SRD_BAUD  EQU   SWD_BAUD        ;Returns current baud rate divisor

  ;Bits for RR15 - Interrupt enable bits
;RR15 returns the bits written to WR15
SRF_NOINT EQU   SWF_NOINT       ;Interrupts are disabled
SRF_ZEROC EQU   SWF_ZEROC       ;Interrupt when BRG count is zero
SRF_DCD   EQU   SWF_DCD         ;Interrupt when DCD changes state
SRF_SYNC  EQU   SWF_SYNC        ;Interrupt when SYNC changes state
SRF_CTS   EQU   SWF_CTS         ;Interrupt when CTS changes state
SRF_EOM   EQU   SWF_EOM         ;Interrupt when transmit underrun or EOM

;-------------------------------------------------------------------------------

  ;Output to RS-232 connector  (pin 2 has channel A transmit data)
SCC_RTS   EQU   SW5_RTS  ;Pin 4,  A-WR5 bit 1, Request To Send
SCC_RCNTL EQU   SW5_RTS  ;(RTSB)  B-WR5 bit 1  (internal modem, request control)
SCC_DTR   EQU   SW5_DTR  ;Pin 20, A-WR5 bit 7, Data Terminal Ready
SCC_SPDO  EQU   SW5_DTR  ;Pin 11, B-WR5 bit 7, Speed select out (also Pin 23)
  ;Input from RS-232 connector (pin 3 has channel A receive data)
SCC_DCD   EQU   SR0_DCD  ;Pin 8,  A-RR0 bit 3, Data Carrier Detect
SCC_DSR   EQU   SR0_DCD  ;Pin 6,  B-RR0 bit 3, Data Set Ready, pin 6
SCC_ACNTL EQU   SR0_SYNC ;(SYNCA) A-RR0 bit 4  (internal modem, ack control)
SCC_SPDI  EQU   SR0_SYNC ;Pin 12, B-RR0 bit 4, Speed select in, pin 12
SCC_CTS   EQU   SR0_CTS  ;Pin 5,  A-RR0 bit 5, Clear To Send, pin 5
SCC_RI    EQU   SR0_CTS  ;Pin 22, B-RR0 bit 5, Ring Indicator, pin 22
  ;Taken from page E-1 of the TI-PRO Technical Reference Manual 2223216-0001

;End if TI-Professional Sync/Async Comm Card definitions
SUBTTL Configuration info

;To get the system configuration, execute an INT 4Fh.  The number returned
;in BX is the size of contiguous RAM (in paragraphs).  The bits returned
;in AX are:
SYS_INT   EQU   4Fh     ;INT number
SYS_DSKA  EQU   0001h   ;Diskette A (internal) installed
SYS_DSKB  EQU   0002h   ;Diskette B (internal) installed
SYS_DSKC  EQU   0004h   ;Diskette C (external) installed
SYS_DSKD  EQU   0008h   ;Diskette D (external) installed
SYS_1SID  EQU   0010h   ;E1-E2 jumper (0 indicates drive A is double sided)
SYS_40TK  EQU   0020h   ;E3-E4 jumper (0 indicates drive A has 80 tracks)
SYS_60HZ  EQU   0040h   ;E5-E6 jumper (0 indicates 50 Hz system)
SYS_HARD  EQU   0080h   ;Winchester disk controller installed
SYS_PRT1  EQU   0100h   ;Serial port 1 installed
SYS_PRT2  EQU   0200h   ;Serial port 2 installed
SYS_PRT3  EQU   0400h   ;Serial port 3 installed
SYS_PRT4  EQU   0800h   ;Serial port 4 installed
SYS_GRFA  EQU   1000h   ;Graphics RAM bank A installed
SYS_GRFB  EQU   2000h   ;Graphics RAM bank B installed
SYS_GRFC  EQU   4000h   ;Graphics RAM bank C installed
SYS_RSVD  EQU   8000h   ;Reserved

;Speaker control - Put code in AH and execute INT 48h

SPK_INT   EQU   48h     ;INT number
SPK_BEEP  EQU   0h      ;Sound speaker, AL has number of 25ms ticks (40=1 sec)
SPK_STAT  EQU   1h      ;Get speaker status, Z-flag is set if enabled
SPK_FREQ  EQU   2h      ;Set speaker frequency from CX (1563 = 800 Hz)
SPK_ON    EQU   3h      ;Turn on speaker until SPK_OFF or SKP_BEEP
SPK_OFF   EQU   4h      ;Turn off speaker
SUBTTL  Data segment

; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct 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, trans:byte
        extrn   portval:word, port1:byte, port2:byte

false   equ     0
true    equ     1

machnam db      'TI-PRO (rev ',REVLVL+'0',')$'
badbd   db      cr,lf,'Unimplemented baud rate$'
noimp   db      cr,lf,'Command not implemented.$'
shkmsg  db      'Not implemented.'
shklen  equ     $-shkmsg
setktab db      0
setkhlp db      0
crlf    db      cr,lf,'$'
delstr  db      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
posseq  db      esc,'[00;00H$'  ; Escape sequence to position cursor
  rowhi equ posseq+2
  rowlo equ posseq+3
  colhi equ posseq+5            ; Modified by POSCUR routine
  collo equ posseq+6
invvid  db      esc,'[0;7m($'   ; Inverse video
norvid  db      ')',esc,'[0;1m$'; Normal video (WHITE=BOLD, as opposed to GREEN)

  ;For IBM-PC, numbers are 12,20,5,20,199 for coordinates to 613,194
xmult   dw      9               ; Scale TEK to TI by 9/13
xdiv    dw      13              ;  so that 0-1023 converts to 0-708
ymult   dw      5               ; Scale TEK to TI by 5/13
ydiv    dw      13              ;  so that 0-779 converts to 299-0
ybot    dw      299             ; Bottom of screen is Y=299
oldx    dw      0               ; Previous scaled coordinates
oldy    dw      0

palnorm db      0,1,2,3,4,5,6,7 ;Normal colors
pal1pln db      0,7,2,3,4,5,6,1 ;For single-plane machines, 0=Black,1=White
pal3pln db      0,4,2,3,1,5,6,7 ;For three-plane machines,  0=Black,1=Green

sysdata dw      0               ;AX from SYS_INT
syssize dw      0               ;BX from SYS_INT

xofsnt  db      0               ; Say if we sent an XOFF.
xofrcv  db      0               ; Say if we received an XOFF.
count   dw      0               ; Number of chars in int buffer.
portin  db      0               ; Non-zero if port is initialized

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

termtab db      11              ;Number of entries
        db      05h,'ADM3A$'
        dw      tty_adm3a
        db      04h,'GIGI$'
        dw      tty_gigi
        db      08h,'HEATH-19$'
        dw      tty_heath
        db      03h,'OFF$'
        dw      tty_dos
        db      02h,'ON$'
        dw      tty_heath       ;Same as HEATH-19
        db      06h,'TI-PRO$'
        dw      tty_tipro
        db      06h,'TVI910$'
        dw      tty_tvi910
        db      05h,'VT100$'
        dw      tty_vt100
        db      05h,'VT102$'
        dw      tty_vt102
        db      05h,'VT125$'
        dw      tty_vt125
        db      04h,'VT52$'
        dw      tty_vt52

tty_heath  dw   ctl_vt52        ;Control table
        db      01h,'HEATH19'   ;Type, name
        db      esc,'/K',0      ;VT52 superset

tty_vt52   dw   ctl_vt52
        db      02h,'VT52   '
        db      esc,'/Z',0      ;ANSI terminal in VT52 mode

tty_tipro  label word
tty_dos    dw   ctl_none        ;Use ANSI.SYS that is build into the BIOS
        db      03h,'TIPRO  '
        db      esc,'[?1;4c',0  ;Like a VT100 with graphics but no STP

tty_gigi   dw   ctl_ansi
        db      04h,'GIGI   '
        db      esc,'[?5c',0

tty_vt100  dw   ctl_ansi
        db      05h,'VT100  '
        db      esc,'[?1;0c',0

tty_vt102  dw   ctl_ansi
        db      06h,'VT102  '
        db      esc,'[?6c',0

tty_vt125  dw   ctl_ansi
        db      07h,'VT125  '
        db      esc,'[?12;7;0;102c',0

tty_adm3a  dw   ctl_adm
        db      08h,'ADM3A  '
        db      esc,']3',0      ; Something I made up

tty_tvi910 dw   ctl_adm
        db      09h,'TVI910 '
        db      esc,']0',0      ; Something I made up

IDSEQ   dw      tty_dos+10      ; Public pointer to string
CTLTAB  dw      ctl_none        ; Public pointer to control table

ctl_vt52 dw     0
ctl_ansi dw     0
ctl_none dw     0
ctl_adm  dw     0

modem   mdminfo <SCC1_ADAT,SCC1_ACMD,SCC1_BCMD>

tmp     db      ?,'$'
temp    dw      0
temp1   dw      ?               ; Temporary storage.
temp2   dw      ?               ; Temporary storage.
rdbuf   db      20 dup(?)       ; Buffer for input.

ourarg  termarg <>
SUBTTL  Data to init Serial Controller

PARMTA  DB 09h                  ;Select WR9
        DB SW9_RESET            ;Reset 8530
        DB 0Bh                  ;Select WR11
        DB SWB_RBRG+SWB_TBRG+0  ;No XTAL, RxC=BRG=TxC, TRxC pin is an input
        DB 0Eh                  ;Select WR14
        DB SWE_PCLK+SWE_BRENA   ;BRG source is PCLK pin, enable BRG
        DB 0Fh                  ;Select WR15
        DB SWF_NOINT            ;Disable external status interrupts
        DB 01h                  ;Select WR1
        DB SW1_NOINT            ;Disable all other interupts
        DB 03h                  ;Select WR3
        DB SW3_8BITS+SW3_RXEN   ;8 bits, enable receiver
        DB 04h                  ;Select WR4
        DB SW4_X16+SW4_1STOP+0  ;x16 clock, 1 stop bit, no parity
        DB 05h                  ;Select WR5
        DB SW5_DTR+SW5_8BITS+SW5_TXEN+SW5_RTS ;Raise DTR+RTS, 8 bits, Tx enable
PARMAS  EQU $-PARMTA
        ;The baud rate is set via GETBAUD and/or DOBAUD

  ;Channel B parameters
PARMTB  DB 0Fh                  ;Select WR15
        DB SWF_NOINT            ;Disable external status interrupts
        DB 01h                  ;Select WR1
        DB SW1_NOINT            ;Disable all other interrupts
        DB 05H                  ;Select WR5
        DB SW5_RTS              ;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
;End of init data

datas   ends
SUBTTL  Serial port routines -- Initialize

code    segment public
        extrn   comnd:near, dopar:near, prserr:near, atoi:near, prompt:near
        extrn   nout:near
        extrn   TERMEMU:near            ;Terminal emulator for TEK and VT100
        public  CLS,TEKDRAW,CROSHAIR    ;Graphics routines
        public  INMODEM,OUTMODEM        ;I/O to communications port
        public  INKEYB,OUTSCRN          ;I/O to console
        public  IDSEQ,CTLTAB            ;Used by TERMEMU routine
        assume  cs:code,ds:datas

;============================================================================
;  Serial-port routines - talks to the Async COMM card.
;============================================================================

; Initialization for using serial port.  Returns normally.
; This is called for by SEND, RECEIVE, and CONNECT commands.

SERINI  PROC    NEAR
        cld                     ; Do increments in string operations
        cmp portin,0            ; Is it initialized already?
        jne serinc              ; Yes, skip all this

        mov si,offset PARMTA    ; Addr of port A parameter table
        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: lods PARMTA             ; 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: lods PARMTB             ; Get a byte
        out dx,al               ; Send it to 8530
        loop serinb

serinc: mov portin,0FFh         ; Flag that port is set up
        ret
SERINI  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,00h          ; Port is not set up
        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.
; Do nothing since we are not interrupt driven.  Returns normally.

CLRBUF  PROC    NEAR
        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
SUBTTL  Serial port routines -- Output to the port

; 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.

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,true         ; Are we being held?
        jne outch2              ; No - it's OK to go on.
        loop outch1             ; held, try for a while
        mov xofrcv,false        ; 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,SR0_TBUFE        ; 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
SUBTTL  Serial port routines -- Input from port

; Port read character.  Check the port status.  If no data, skip
; return.  Else, read in a char and return.

PRTCHR  PROC    NEAR
        push bx
        push dx
        call chkxon

        mov dx,modem.mdstat     ; Port 1 channel A command address
prtch1: in al,dx                ; Read RR0 contents
        and al,SR0_RBUFA        ; Any characters in receive FIFO?
        jz prtch4               ; No, exit without waiting
        mov dx,modem.mddat      ; Yes, get port 1 channel A data address
        in al,dx                ; Get the character

        mov bx,portval
        cmp [bx].parflg,PARNON  ; no parity?
        je prtch3               ; then don't strip
        and al,7fh              ; else turn off parity
prtch3: pop dx
        pop bx
        ret

prtch4: pop dx                  ; Here when no character is available
        pop bx
        jmp RSKP                ; no chars...
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,false    ; have we sent an xoff?
        je      chkxo1          ; no, forget it
        mov     ax,[bx].flowc   ; ah gets xon
        call    outchr          ; send it
        nop
        nop
        nop                     ; in case it skips
        mov     xofsnt,false    ; remember we've sent the xon.
chkxo1: pop     bx              ; restore register
        ret                     ; and return
CHKXON  ENDP
SUBTTL  Serial port routines -- Send a break

; 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,SW5_BREAK        ; 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
SUBTTL  Serial port routines -- Change baud rate

; 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

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,prstr
        mov dx,offset badbd     ;Bad baud rate
        int dos
        pop bx
        ret

dobod1: mov ax,BAUDAT[bx]       ;Get BRG divisor
        call SETBAUD            ;Send AX to baud-rate-divisor
        pop bx
        ret
DOBAUD  ENDP


;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


; 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
        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
        ret
GETBAUD ENDP
SUBTTL  Machine-dependent screen update routines

;============================================================================
;  Screen handling routines
;============================================================================


; Delete a character from the terminal.  This works by printing
; backspaces and spaces.  Returns normally.

DODEL   PROC    NEAR
        mov ah,prstr
        mov dx,offset delstr    ; Backspace-space-backspace
        int dos
        ret
DODEL   ENDP


; Move the cursor to the left margin, then clear to end of line.
; Returns normally.

CTLU    PROC    NEAR
        mov ah,prstr
        mov dx,offset clrlin    ;Output CR, then clear to end of line
        int dos
        ret
CTLU    ENDP

; Clear to the end of the current line.  Returns normally.

CLEARL  PROC    NEAR
        mov ah,prstr
        mov dx,offset clreol    ;Erase from cursor position to end of line
        int dos
        ret
CLEARL  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


; 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,SPK_FREQ         ; Set speaker frequency
        mov cx,1000             ; Approx 1.5 kHz
        int SPK_INT
        ret
BEEP1   ENDP

BEEP    PROC    NEAR
        call BEEP1              ; Set the frequency
        mov ah,SPK_BEEP         ; Timed beep function
        mov al,5                ; 5/40 = 1/8 second
        int SPK_INT
        ret
BEEP    ENDP


; Homes the cursor.  Returns normally.

LOCATE  PROC    NEAR
        mov dx,0                ; Go to top left corner of screen.
        jmp poscur
LOCATE  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,prstr
        int     dos             ;Set inverse video
        pop     dx              ; get message back
        mov     ah,prstr
        int     dos             ; write it out
        mov     dx,offset norvid
        mov     ah,prstr
        int     dos             ;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


; 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,prstr
        mov     dx,offset crlf
        int     dos
        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,dconio
        int     dos             ; else write to screen
        jmp     puthl3          ; and keep going
puthl4: mov     ah,prstr
        mov     dx,offset crlf
        int     dos
        ret
PUTHLP  ENDP


; Position the cursor according to contents of DX:
; DH contains row, DL contains column.  Returns normally.

POSCUR  PROC    NEAR
        mov al,dh               ;Get row
        inc al                  ;Top row is row #1, not zero
        aam                     ;ah gets tens, al gets units
        add ax,'00'             ;Convert to ASCII
        mov rowhi,ah            ;Store in ESCape sequence
        mov rowlo,al
        mov al,dl               ;Get column
        inc al
        aam
        add ax,'00'
        mov colhi,ah
        mov collo,al
        mov ah,prstr
        mov dx,offset posseq    ;Output ESC,'[',row,';',col,'H'
        int     dos
        ret
POSCUR  ENDP
SUBTTL TEKTRONIX-4010 emulation


;**** NOTE: This version of TERM really belongs in MSCOMM.ASM ****
TERM    PROC    NEAR
        mov si,ax               ; this is source
        mov di,offset ourarg    ; place to store arguments
        mov ax,ds
        mov es,ax               ; address destination segment
        mov cx,size termarg
        rep movsb               ; copy into our arg blk
        call TERMINI            ; Set 25th line, graphics bright

; Get a character from the modem, send it to the screen

term1:  call INMODEM            ; Input from modem
          jmp short term2       ; No input available
          nop                   ; 3rd byte
        push ax
        call TERMEMU            ; Call terminal emulation routines
        pop ax
        test ourarg.flgs,capt   ; capturing output?
        jz term2                ; no, forget it
        call ourarg.captr       ; else call the routine

; Get character from the keyboard, send it to the modem port

term2:  call INKEYB             ; Get char from keyboard (with translation)
          jmp short term1       ; No input available
          nop                   ; 3rd byte
        cmp al,ourarg.escc      ; Match our escape character?
        je term3                ; yes, exit
        call OUTMODEM           ; output the character
        test ourarg.flgs,lclecho ; echoing?
        jz term1                ; no, continue loop
        push ax
        call TERMEMU
        pop ax
        and al,7Fh              ; Ignore parity
        cmp al,CR               ; Was the RETURN key pressed?
        jne term1
        mov al,LF               ; Yes, echo a linefeed to the screen
        call TERMEMU
        jmp term1

term3:  call TERMEND            ; Undo line 25 or graphics
        ret
TERM    ENDP
;**** NOTE: This version of TERM really belongs in MSCOMM.ASM ****


;Routine to make graphics more visible.
;For a 1-plane monochrome display, draw bright lines on a black background
;For a 3-plane color display, draw green lines on a black background
;(It is better to use only one color on a color monitor, so as to avoid
;any problems if the convergence is not exact.)
;Line 25 is not given any special treatment.

TERMINI PROC NEAR
        mov si,offset pal3pln   ;New palette if 3 planes
        test sysdata,SYS_GRFC   ;Graphics plane C installed ?
        jnz termin1             ;Yes
        mov si,offset pal1pln   ;No, only single plane graphics
termin1:call palette            ;Set up so that color 1 is more visible
        ret
TERMINI ENDP


;Routine to make graphics dimmer.
;For a 1-plane monochrome display, graphics will be very dim
;For a 3-plane color display, graphics will be blue (text will be white)
;Line 25 is not given any special treatment

TERMEND PROC NEAR
        mov si,offset palnorm   ;Reset to normal palette
        call palette
        ret
TERMEND ENDP


;Routine to input a character from the keyboard with translation.
;Skip return if input was available, character in AL.

INKEYB  PROC NEAR               ;Input from the keyboard
        mov ah,dconio
        mov dl,0ffh
        int dos
        jc  inkey1              ;Carry set if no character available
        and al,7Fh              ;No meta characters (yet)
        je  inkey1              ;*HACK* No char if null
        jmp RSKP                ;Skip return of char is available
inkey1: ret                     ;Error return if no input
INKEYB  ENDP


;Routine to output character in AL to the screen.

OUTSCRN PROC NEAR               ;Output one character to the screen
        mov dl,al
        mov ah,conout
        int dos                 ; go print it
        ret
OUTSCRN ENDP


;Routine to input a character from the modem port.
;Skip return if input was available, character in AL.

INMODEM PROC NEAR               ;Input from the modem
        call PRTCHR
          jmp RSKP              ;Skip return if char is available
        ret
INMODEM ENDP


;Routine to output character in AL to the modem port.

OUTMODEM PROC NEAR              ;Output one character to the modem
        push ax                 ;Preserve character in AL
        mov ah,al
        call OUTCHR             ;Output char in AH
        nop                     ;Ignore non-skip return
        nop
        nop
        pop ax
        ret
OUTMODEM ENDP


;Routine to draw a line on the screen, using TEKTRONIX coordinates.
;X coordinate in AX, 0=left edge of screen, 1023=right edge of screen.
;Y coordinate in BX, 0=bottom of screen, 779=top of screen.
;Visiblity flag in CL, 0=move invisible, 1=draw a line.

;The TI-PRO has (719,299) as the coordinate of the lower-right corner.
;Calculate endpoint X=(9/13)*(HIX*32+LOX), Y=299-(5/13)*(HIY*32+LOY)

;The IBM-PC has (639,199) as the coordinate of the lower-right corner.
;Calculate endpoint X=(12/20)*(HIX*32+LOX), Y=199-(5/20)*(HIY*32+LOY)

TEKDRAW PROC NEAR
        imul xmult              ; Multiply by 9
        idiv xdiv               ; Divide by 13
        push ax                 ; X is now between 0 and 708
        mov ax,bx
        imul ymult              ; Multiply by 5
        idiv ydiv               ; Divide by 13
        mov  bx,ybot            ; Y is now between 0 and 299
        sub  bx,ax              ; Put new Y in right reg
        pop  ax                 ; Put new X in right reg
        mov  si,oldx            ; Previous position
        mov  di,oldy
        mov  dl,cl              ; Draw a line in 1 plane if DL=1
        or   dl,80h             ; Use fast line drawing routine
        call LINE
        mov  oldx,si            ; Update position
        mov  oldy,di
        ret
TEKDRAW ENDP


;Routine to trigger the crosshairs, wait for a key to be struck, and send
;5 byte out the modem port.

CROSHAIR PROC NEAR
        ret
CROSHAIR ENDP
SUBTTL  Screen routines -- Graphics
;Note: All arguments to these 3 routines are passed in the registers.

        public  CLS, PALETTE, LINE
;==============================================================================
; CLS   Subroutine to clear the screen.  Call with 0 in AL to clear both,
;       1 to clear graphics only, 2 to clear text only.
;==============================================================================

CLS     PROC    NEAR            ;0=both, 1=graphics, 2=text
        push    ax
        test    al,1            ;CLS 1 does not clear text
        jnz     cls1
        mov     ah,13h          ;CLS 0 or CLS 2 clears text screen
        int     49h
cls1:   pop     ax
        test    al,2            ;CLS 2 does not clear graphics
        jnz     cls2
        mov     ah,14h          ;CLS 0 or CLS 1 clears graphics screen
        int     49h
cls2:   ret
CLS     ENDP

; Colors 0=Black, 1=Blue, 2=Red, 3=Magenta, 4=Green, 5=Cyan, 6=Yellow, 7=White
planea  equ     0C000h          ;1st graphics plane (blue)
planeb  equ     0C800h          ;2nd graphics plane (red)
planec  equ     0D000h          ;3rd graphics plane (green)
  ; The colors listed above are assuming that the PALETTE is not changed.
latchs  equ     0DF00h          ;Segment number of color latches
latchb  equ     00010h          ;Blue output latch
latchg  equ     00020h          ;Green output latch
latchr  equ     00030h          ;Red output latch
palblue equ     10101010b       ;Default blue latch
palgren equ     11001100b       ;Default green latch
palred  equ     11110000b       ;Default red latch

;==============================================================================
; PALETTE Subroutine to change the color palette (ala BASIC)
;       Call with DS:SI pointing to 8 bytes defining the new colors
;       Preserves all but AX,SI.
;==============================================================================

PALETTE PROC    NEAR
        push bx
        push cx
        mov bx,0                ;Start at 1st byte
        mov ah,0                ;Code for blue latch
        mov cx,0                ;Code for red and green latches

palet1: mov al,CS:PALBITS[bx]   ;Bit to be set
        test byte ptr [bx+si],01h ;Check blue component of this color
        jz palet2
        or  ah,al               ;Set the bit
palet2: test byte ptr [bx+si],02h ;Check red component
        jz palet3
        or  ch,al               ;Set the bit
palet3: test byte ptr [bx+si],04h ;Check the green component
        jz palet4
        or  cl,al
palet4: shl al,1                ;Do next bit
        add bx,1                ;Point to next input data byte
        cmp bl,8                ;Done all 8?
        jl  palet1

        push ds
        mov bx,latchs           ;Address the latch segment
        mov ds,bx
        mov DS:[latchb],ah      ;Set the hardware latches
        mov DS:[latchg],cl
        mov DS:[latchr],ch
        pop ds
        pop cx
        pop bx
        ret
PALBITS db 01h,02h,10h,20h,04h,08h,40h,80h   ;Red & Green bits swapped
PALETTE ENDP

;==============================================================================
; LINE  Subroutine to plot a line with endpoints in BX,CX and SI,DI. The method
;       used is an adaptation of the octantal dynamic differential analyzer(DDA).
;
; Registers at CALL             Registers on return
; -----------------             -------------------
; SI=Start X coord              SI=End X coord (start for next time)
; DI=Start Y coord              DI=End Y coord
; AX=End X coord                AX=garbage
; BX=End Y coord                BX=garbage
; CX=anything                   CX=unchanged (for loop counter)
; DX=Color code, 0-7 or 80-87   DX=unchanged
; BP,SP,CS,DS,ES,SS are all unchanged
;
; I considered returning meaningful data in AX and BX (such as the last bit
; and word address drawn), but that is complicated by the fact that the lines
; are always drawn left to right.
;==============================================================================

LINE    proc    near
        push    ax                      ;End coords in (AX,BX) will be returned
        push    bx                      ; in (SI,DI)
        push    cx                      ;Preserve CX,BP,DS
        push    bp
        push    ds
;       call    clip                    ;Clip line to fit in screen bounds
;       jnz     done                    ;Jump if line is on screen
        cmp     ax,si                   ;Compare X1 to X2
        jl      plusx                   ;Jump if X1 is to left of X2
        xchg    ax,si                   ;Swap points so point 1 is to left
        xchg    bx,di                   ;  This mirrors quadrants 2,3 to 1,4
plusx:  sub     si,ax                   ;Get delta X into SI
        sub     di,bx                   ;Get delta Y into DI

; Left-hand coordinate in (AX,BX), delta movement in (SI,DI)
; Map X1,Y1 in AX,BX to an offset into the video buffer in BX and bit pos in AX

        shl     bx,1                    ;2*Y
        shl     bx,1                    ;4*Y
        mov     bp,bx                   ;Save 4*Y
        shl     bx,1                    ;8*Y
        shl     bx,1                    ;16*Y
        shl     bx,1                    ;32*Y
        add     bp,bx                   ;DX = 36*Y
        shl     bx,1                    ;64*Y
        shl     bx,1                    ;128*Y
        sub     bx,bp                   ;128Y - 36Y = 92*Y
        mov     cl,al                   ;Low 4 bits of X position
        and     cl,0Fh
        shr     ax,1                    ;Divide by 8 bits per byte
        shr     ax,1
        shr     ax,1
        and     ax,0fffeh               ;Truncate down to word boundary
        add     bx,ax
        mov     ax,8000h                ;Start with set bit on left edge
        shr     ax,cl                   ;Shift it over the correct amount

;AX has bit in position, BX has word address, SI has delta-X, DI has delta-Y

        mov     bp,92                   ;Offset from 1 pixel to one below it
        or      di,di                   ;See if delta y is below zero
        jg      quad3                   ;Yes, already on quadrant 3
        neg     di                      ;Get absolute value of delta y
        neg     bp                      ;Move toward top of screen
quad3:  test    dl,1                    ;Want color 1?
        jz      try2                    ;No
        mov     cx,planea               ;Yes, do BLUE
        call    line1
try2:   test    dl,2                    ;Want color 2?
        jz      try3                    ;No
        mov     cx,planeb               ;Yes, do RED
        call    line1
try3:   test    dl,4                    ;Want color with this bit on?
        jz      lindone                 ;No
        mov     cx,planec               ;Yes, do GREEN
        call    line1

lindone:pop     ds
        pop     bp
        pop     cx
        pop     di                      ;Return end points (formerly in AX,BX)
        pop     si                      ; in (SI,DI)
        ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

line1:  mov     ds,cx                   ;Segment for video buffer
        push    ax                      ;Starting bit position
        push    bx                      ;Starting address
        push    dx                      ;Color bits (SI and DI not modified)

        cmp     di,si                   ;Compare delta-Y with delta-X
        jg      line1a                  ;Greater than +/- 45 degrees
        call    line2                   ;Flat line, count with delta-X
        jmp     short line1b
line1a: call    line3                   ;Steep line, count with delta-Y

line1b: pop     dx
        pop     bx
        pop     ax
        ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Here when slop is less than +/- 45 degrees

line2:  mov     cx,si                   ;Number of pixels to plot = delta x
        inc     cx                      ;  + 1
        mov     dx,si                   ;Initialize line error to -(deltax)/2
        shr     dx,1                    ;
        neg     dx                      ;

line2a: or      [bx],ax                 ;Turn on pixel pointed to by BX and Al
        ror     ax,1                    ;Increment X direction
        jnc     line2b                  ;
        add     bx,2                    ;
line2b: add     dx,di                   ;Add delta y to line error
        jl      line2c                  ;Jump for next pixel if error < 0
        add     bx,bp                   ;Go up (or down) one pixel
        sub     dx,si                   ;Subtract delta x from line error
line2c: loop    line2a                  ;Set next pixel
        ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Here when slope is greater than +/- 45 degrees

line3:  mov     cx,di                   ;Number of pixels to plot = delta y
        inc     cx                      ;  + 1 (Delta Y was negated above)
        mov     dx,di                   ;Initialize line error to -(deltay)/2
        shr     dx,1                    ;
        neg     dx                      ;

line3a: or      [bx],ax                 ;Turn on pixel pointed to by BX and Al
        add     bx,bp                   ;Move up (or down) 1 pixel
        add     dx,si                   ;Add delta x to line error
        jl      line3c                  ;Jump for next pixel if error < 0
        ror     ax,1                    ;Time to increment X direction
        jnc     line3b                  ;
        add     bx,2                    ;
line3b: sub     dx,di                   ;Subtract delta y from line error
line3c: loop    line3a                  ;Set next pixel
        ret

LINE    endp
SUBTTL  Interface to KERMIT's command parser

;============================================================================
;  General KERMIT or MS-DOS routines.
;============================================================================

; 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 dos
        mov dl,al                       ; Put current disk in DL.
        mov ah,seldsk                   ; Select current disk.
        int dos                         ; Get number of drives in AL.
        mov drives,al
        ret
DODISK  ENDP


; Initialize variables to values used by the TI PROFESSIONAL version.

LCLINI  PROC    NEAR
        int     SYS_INT         ;Get system configuration info
        mov     sysdata,ax      ;Bit mask of installed devices
        mov     syssize,bx      ;Size of RAM
        call    BEEP1           ;In case BASIC left the speaker messed up
        mov     flags.vtflg,0   ;HEATH-19 emulation is off
        ret
LCLINI  ENDP


; Get a file handle for the communications port.  Use DOS call to get the
; next available handle.  If it fails, ask user what value to use (there
; should be a predefined handle for the port, generally 3).  The open
; will fail if the system uses names other than "COM1" or "COM2".

OPNPRT  PROC    NEAR
        ret
OPNPRT  ENDP



SHOWKEY PROC    NEAR
        mov ax,offset shkmsg
        mov cx,shklen
        ret
SHOWKEY ENDP


; Set heath emulation on/off.  Called from SET TERMINAL-EMULATION command

VTS     PROC    NEAR
        mov dx,offset termtab
        mov bx,0
        mov ah,cmkey
        call comnd              ;Keyword, HEATH-19, VT102, ADM3A, or OFF
          jmp r
        push bx
        mov ah,cmcfm
        call comnd
          jmp short vt0
          nop
        pop bx
        mov ax,0[bx]            ; Get the control table address
        mov CTLTAB,ax
        mov al,2[bx]            ; Get terminal type
        mov flags.vtflg,al
        add bx,2+8              ; Get addr of ID sequence
        mov IDSEQ,bx
        ret

vt0:    pop bx
        ret
VTS     ENDP


notimp: mov ah,prstr
        mov dx,offset noimp
        int dos
        jmp prserr


; Set the current port.  Called from SET PORT command

COMS    PROC    NEAR
        mov dx,offset porttab
        mov bx,0
        mov ah,cmkey
        call comnd
         jmp r
        push bx
        mov ah,cmcfm
        call comnd              ; Get a confirm.
         jmp comx               ;  Didn't get a confirm.
         nop
        call SERRST             ; Reset previous serial port
        pop bx
        mov flags.comflg,bl     ; Set the comm port flag.

;**** According to the MSXSYS.DOC, flags.comflg is supposed to be 0
;**** when using port 2.  This makes it difficult to use ports 3 and 4.

        cmp flags.comflg,1              ;Port 1?
        jne coms2
        mov ax,offset port1
        mov portval,ax
        mov modem.mddat,SCC1_ADAT       ;Data reg
        mov modem.mdstat,SCC1_ACMD      ;Channel A command/status
        mov modem.mdcom,SCC1_BCMD       ;Channel B command/status
        call SERINI
        ret

coms2:  cmp flags.comflg,2              ;Port 2?
        jne coms3
        mov ax,offset port2
        mov portval,ax
        mov modem.mddat,SCC2_ADAT       ;Data reg
        mov modem.mdstat,SCC2_ACMD      ;Channel A command/status
        mov modem.mdcom,SCC2_BCMD       ;Channel B command/status
        call SERINI
        ret

coms3:  cmp flags.comflg,3              ;Port 3?
        jne coms4
        mov ax,offset port3
        mov portval,ax
        mov modem.mddat,SCC3_ADAT       ;Data reg
        mov modem.mdstat,SCC3_ACMD      ;Channel A command/status
        mov modem.mdcom,SCC3_BCMD       ;Channel B command/status
        call SERINI
        ret

coms4:  mov ax,offset port4             ;Port 4
        mov portval,ax
        mov modem.mddat,SCC4_ADAT       ;Data reg
        mov modem.mdstat,SCC4_ACMD      ;Channel A command/status
        mov modem.mdcom,SCC4_BCMD       ;Channel B command/status
        call SERINI
        ret

comx:   pop bx
        ret
COMS    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.

R       PROC    NEAR
        ret
R       ENDP

code    ends
        end
