IF NOT lasm
.printx * CPXSY2.ASM *
ENDIF	;NOT lasm
;       KERMIT - (Celtic for "FREE")
;
;       This is the CP/M-80 implementation of the Columbia University
;       KERMIT file transfer protocol.
;
;       Version 4.0
;
;       Copyright June 1981,1982,1983,1984,1985
;       Columbia University
;
; Originally written by Bill Catchings of the Columbia University Center for
; Computing Activities, 612 W. 115th St., New York, NY 10025.
;
; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,
; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many
; others.
;
;       This file contains the system-dependent code and data for KERMIT.
;       It will be probably be broken into independent files to generate
;       overlays for the various systems, one or more overlay possible
;       from each file.  For now, we will leave it in one piece.
;
; revision history:
;
;
;       This is the system-dependent command to change the baud rate.
;       DE contains the two-byte value from the baud rate table; this
;       value is also stored in 'speed'.
sysspd:


IF px8 ; [29]
        push    d
        call    rsclose        ; baud rate can only be set on opening rs232
        pop     d
        mov     a, e
        sta     px8blk+4       ; set param block
        call    rsopen         ; to set rate
        ret
ENDIF ; px8 [29]

; Set the speed for the Osborne I
IF osbrn1
        mvi     a,osbin1        ;Reset the ACIA
        call    osstst          ;Write the control port
osbs1:  inr     c               ;Waiting loop
        jnz     osbs1
        mov     a,e             ; get the specified speed
        jmp     osstst          ;Write the control reg.
ENDIF;osbrn1

;[hh] set the speed for a lobo MAX-80
IF lobo
        mov     a,e             ;[hh] get the parsed value
setbd:  sta     baudrt          ;[hh] and send it to the baud rate port
        ret                     ;[hh]
ENDIF;lobo

; Set the speed for bigboard I or the delphi or the CPT-85xx
; or Cromemco (TU-ART)
IF delphi OR cpt85xx OR cmemco OR mmate ;[22] [29]
        mov     a,e             ; get the parsed value
        out     baudrt          ; Tell the baud rate generator.
        ret
ENDIF;delphi OR cpt85xx OR cmemco OR mmate [22] [29]

;[22] Set the speed for Acorn BBC
IF bbc
        mov     l,e
        mvi     a,7             ;Set receive baud rate
        call    osbyte          ;*FX7,?e
        mov     l,e
        mvi     a,8             ;Set transmit baud rate
        call    osbyte          ;*FX8,?e
        ret
ENDIF;[22] bbc

;[22] Set speed for RM 380Z
IF rm380z
        mvi     a,4             ;device type (SI/O4) in A
        rst     6               ; EMT
        db      29h             ;     SETLST
        ret
ENDIF;[22] rm380z

; Set the speed for MicroMikko.  DE is baud rate multiplier
IF mikko
        di
        lxi     h,txclk
        mov     m,d             ;LSB first (swapped in memory)
        mov     m,e             ;MSB last
        lxi     h,rxclk
        mov     m,d
        mov     m,e
        mvi     b,0             ;"modifier" for 1 stop bit
        mvi     a,2             ;Test MSB of speed >2 (110 bps or less)
        cmp     e
        jp      miksp1
        mvi     b,00001000B     ;"modifier" for 2 stop bits
miksp1: mvi     a,4             ;Select SIO Reg 4
        lxi     h,sioac
        mov     m,a
        mvi     a,sion4         ;Get values
        ora     b               ;Add modifier
        mov     m,a             ;Set value (stop bits)
        ei
        ret
ENDIF;mikko


; Set the speed for the Decision I
IF mdI
        call    selmdm          ;Let's be absolutely sure, huh?
        mvi     a,dlab+wls1+wls0+stb ;Set data latch access bit
        out     lcr             ;Out to Line Control Register
        lhld    speed           ;Load baudrate multiplier
        xchg
        mov     a,d             ;Get low order byte for baud rate
        out     dlm             ;Out to the MSB divisor port
        mov     a,e             ;...and the high order byte
        out     dll             ;Out to the LSB divisor port
        mvi     a,wls1+wls0+stb ;Enable Divisor Access Latch
        out     lcr             ;Out to ACE Line Control Register
        xra     a               ;Clear A
        out     ier             ;Set no interrupts
        out     lsr             ;Clear status
        in      msr             ;Clear Modem Status Register
        in      lsr             ;Clear Line Status Register
        in      rbr             ;Clear Receiver Buffers
        in      rbr
        ret
ENDIF   ;mdI    [Toad Hall]

IF teletek
	di
	mov	a,e		; first speed byte
	out	baudrt
	mov	a,d		; second speed byte
	out	baudrt
	ei
	ret
ENDIF	;teletek

IF access       ;[29]
        mov     a,e             ;Get the parsed time constant
;The following code is derived from the Access  initialization code
        sta     savspd          ;Save  the time constant
        mvi     a,14h           ;Code for 'monitor' to set channel A baudrate
        call    monitor
        lda     savspd          ;Get the time constant
        call    monitor         ; and send it to the CRT
        ret
savspd: ds      1
monitor:                        ;Routine to do CRT functions
        out     90h             ;Output the data to the CRT
        mvi     a,1             ;Set DRDY true
        out     23h
mon1:   in      0a0h            ;Wait for CACK* true
        rlc
        jc      mon1
        in      80h             ;Read the input data latch
        push    psw             ;Save the input data
        xra     a               ;Set DRDY false
        out     23h
mon2:   in      0a0h            ;Wait for CACK* false
        rlc
        jc      mon2
        pop     psw
        sta     0ee02h          ;Save the input data
        ret
ENDIF;access [29]


IF disc ;[29]
; Assuming that parsing of value from speed table puts low order
; byte of time constant in the e register and high byte in d.
        mvi     a,12            ;Register 12
        out     mnprts
        mov     a,e             ;Low order byte of time constant
        out     mnprts
        mvi     a,13            ;Register 13
        out     mnprts
        mov     a,d             ;High order byte of time constant
        out     mnprts
        mvi     a,14            ;Register 14
        out     mnprts
        mvi     a,3             ;Enable baud rate generator
        out     mnprts
        mvi     a,11            ;Register 11
        out     mnprts
        mvi     a,52h           ;no Xtal, tclk=rclk=/trxc out=br gen
        out     mnprts
        ret
ENDIF;disc [29]
;       Speed tables
; (Note that speed tables MUST be in alphabetical order for later
; lookup procedures, and must begin with a value showing the total
; number of entries.  The speed help tables are just for us poor
; humans.

;       db      string length,string,divisor (2 identical bytes or 1 word)
; [Toad Hall]

IF delphi OR lobo    ;[hh]
spdtbl: db      10h                     ;16 entries
        db      03h,'110$',     02h,02h
        db      04h,'1200$',    07h,07h
        db      05h,'134.5$',   03h,03h
        db      03h,'150$',     04h,04h
        db      04h,'1800$',    08h,08h
        db      05h,'19200$',   0fh,0fh
        db      04h,'2000$',    09h,09h
        db      04h,'2400$',    0ah,0ah
        db      03h,'300$',     05h,05h
        db      04h,'3600$',    0bh,0bh
        db      04h,'4800$',    0ch,0ch
        db      02h,'50$',      00h,00h
        db      03h,'600$',     06h,06h
        db      04h,'7200$',    0dh,0dh
        db      02h,'75$',      01h,01h
        db      04h,'9600$',    0eh,0eh

sphtbl: db      cr,lf,'   50     75    110    134.5  150    300    600   1200'
        db      cr,lf,' 1800   2000   2400   3600   4800   7200   9600  19200$'
ENDIF;delphi OR lobo    ;[hh]

IF cpt85xx
spdtbl: db      15                      ; 15 entries
        db      03,'110$',      03h,03h
        db      04,'1200$',     09h,09h
        db      05,'134.5$',    04h,04h
        db      03,'150$',      05h,05h
        db      04,'1800$',     0Ah,0Ah
        db      04,'2400$',     0Bh,0Bh
        db      03,'300$',      06h,06h
        db      04,'3600$',     0Ch,0Ch
        db      04,'4800$',     0Dh,0Dh
        db      02,'50$',       01h,01h
        db      03,'600$',      07h,07h
        db      04,'7200$',     0Eh,0Eh
        db      02,'75$',       02h,02h
        db      03,'900$',      08h,08h
        db      04,'9600$',     0Fh,0Fh

sphtbl: db      cr,lf,'   50     75    110    134.5  150    300    600    900'
        db      cr,lf,' 1200   1800   2400   3600   4800   7200   9600$'
ENDIF;cpt85xx

IF bbc          ;[22]
spdtbl: db      8                       ; 8 entries
        db      04,'1200$',     04h,04h
        db      03,'150$',      02h,02h
        db      05,'19200$',    08h,08h
        db      04,'2400$',     05h,05h
        db      03,'300$',      03h,03h
        db      04,'4800$',     06h,06h
        db      02,'75$',       01h,01h
        db      04,'9600$',     07h,07h

sphtbl: db      cr,lf,'   75   150   300   1200   2400   4800   9600   19200$'
ENDIF;[22] bbc

IF rm380z       ;[22]
spdtbl: db      7                       ; 7 entries
        db      03,'110$',      00h,00h
        db      04,'1200$',     03h,03h
        db      04,'2400$',     04h,04h
        db      03,'300$',      01h,01h
        db      04,'4800$',     05h,05h
        db      03,'600$',      02h,02h
        db      04,'9600$',     06h,06h

sphtbl: db      cr,lf,'   110   300   600   1200   2400   4800   9600$'
ENDIF;[22] rm380z

IF px8 ; [29]
spdtbl: db      9                       ; 9 entries
        db      03,'110$',      02h,02h
        db      04,'1200$',     0ah,0ah
        db      03,'150$',      04h,04h
        db      05,'19200$',    0fh,0fh
        db      04,'2400$',     0ch,0ch
        db      03,'300$',      06h,06h
        db      04,'4800$',     0dh,0dh
        db      03,'600$',      08h,08h
        db      04,'9600$',     0eh,0eh
sphtbl: db      cr, lf
        db  '   100   150   300   600   1200   2400   4800   9600   19200$'
ENDIF ; px8 [29]

IF mikko
spdtbl: db      9h                      ;9 entries
        db      03h,'110$'
        dw      0369h
        db      04h,'1200$'
        dw      0050h
        db      03h,'150$'
        dw      0280h
        db      04h,'2400$'
        dw      0028h
        db      03h,'300$'
        dw      0140h
        db      04h,'4800$'
        dw      0014h
        db      03h,'600$'
        dw      00A0H
        db      02h,'75$'
        dw      0500h
        db      04h,'9600$'
        dw      000ah

sphtbl: db      cr,lf,'  75  110  150  300  600  1200  2400  4800  9600$'
ENDIF;mikko

IF osbrn1
spdtbl: db      02h                     ;2 entries
        db      04h,'1200$',    OSBI12,OSBI12
        db      03h,'300$',     OSBI03,OSBI03

sphtbl: db      cr,lf,'  300',cr,lf,' 1200$'
ENDIF;osbrn1


IF mdI
spdtbl: db      0dh                     ; 13 entries
        db      03h,  '110$'
                dw              1047
        db      04h, '1200$'
                dw              96
        db      03h,  '150$'
                dw              768
        db      05h,'19200$'
                dw              6
        db      04h, '2400$'
                dw              48
        db      03h,  '300$'
                dw              384
        db      05h,'38400$'
                dw              3
        db      03h,  '450$'
                dw              288
        db      04h, '4800$'
                dw              24
        db      05h,'56000$'
                dw              2
        db      03h,  '600$'
                dw              192
        db      02h,   '75$'
                dw              1536
        db      04h, '9600$'
                dw              12

sphtbl: db      cr,lf,'   75    110    150    300    450    600   1200'
        db      cr,lf,' 2400   4800   9600  19200  38400  56000$'

;(Lord knows what you'll be communicating with at 56000 baud, but the
;Multi-I/O board literature says it'll do it, so what the heck....
;might as well throw it in here just to show off...sure hope the
;port don't melt...)

ENDIF   ;mdI    [Toad Hall]

IF cmemco                       ;[25]
spdtbl: db      7               ; 7 entries
        db      3,'110$',       01H,01H
        db      4,'1200$',      88H,88H
        db      3,'150$',       82H,82H
        db      4,'2400$',      90H,90H
        db      3,'300$',       84H,84H
        db      4,'4800$',      0A0H,0A0H
        db      4,'9600$',      0C0H,0C0H

sphtbl: db      cr,lf
        db      '   110   150   300  1200  2400  4800  9600$'
ENDIF;cmemco

IF access ;Similar to bbI with different values [29]
spdtbl: db      6h                      ;6 entries
        db      04h,'1200$',    28h,28h
        db      04h,'2400$',    14h,14h
        db      03h,'300$',     0a0h,0a0h
        db      04h,'4800$',    0ah,0ah
        db      03h,'600$',     50h,50h
        db      04h,'9600$',    5,5

sphtbl: db      cr,lf,'  300  600  1200  2400  4800  9600$'
ENDIF;access [29]

IF mmate        ;[29]
spdtbl: db      10h                     ;16 entries
        db      03h,'110$',     0e2h,0e2h
        db      04h,'1200$',    0e7h,0e7h
        db      05h,'134.5$',   0e3h,0e3h
        db      03h,'150$',     0e4h,0e4h
        db      04h,'1800$',    0e8h,0e8h
        db      05h,'19200$',   0efh,0efh
        db      04h,'2000$',    0e9h,0e9h
        db      04h,'2400$',    0eah,0eah
        db      03h,'300$',     0e5h,0e5h
        db      04h,'3600$',    0ebh,0ebh
        db      04h,'4800$',    0ech,0ech
        db      02h,'50$',      0e0h,0e0h
        db      03h,'600$',     0e6h,0e6h
        db      04h,'7200$',    0edh,0edh
        db      02h,'75$',      0e1h,0e1h
        db      04h,'9600$',    0eeh,0eeh

sphtbl: db      cr,lf,'   50  75    110    134.5  150    300    600   1200'
        db      cr,lf,' 1800   2000   2400   3600   4800   7200   9600  19200$'
ENDIF;mmate [29]

IF disc ;[29]
; Similar to mikko table but with different time constant values
spdtbl: db      9h                      ;9 entries
        db      03h,'110$'
        dw      1134
        db      04h,'1200$'
        dw      102h
        db      03h,'150$'
        dw      831
        db      04h,'2400$'
        dw      50
        db      03h,'300$'
        dw      415
        db      04h,'4800$'
        dw      24
        db      03h,'600$'
        dw      206
        db      02h,'75$'
        dw      1665
        db      04h,'9600$'
        dw      11

sphtbl: db      cr,lf,'  75  110  150  300  600  1200  2400  4800  9600$'
ENDIF;disc      [29]

IF teletek
spdtbl:	db	7		; 7 entries
	db	4, '1200$',	47h,40h
	db	5,'19200$',	47h,04h
	db	4, '2400$',	47h,20h
	db	3,  '300$',	47h,00h
	db	4, '4800$',	47h,10h
	db	3,  '600$',	47h,80h
	db	4, '9600$',	47h,08h

sphtbl:	db	cr,lf
	db      '   300   600  1200   2400   4800   9600  19200$'
ENDIF	;teletk


; The following conditionals were once a huge if not statement.  There
; wasn't enough room to add the lobo to the list, so it had to be broken
; into 2, which you can't do with an if not.  I redid it as two ifs and
; applied them to those that wouldn't set baud. [Hal Hostetler]
IF robin OR gener OR dmII OR vector OR trs80;[32]
spdtbl  equ     0               ; SET BAUD not supported.
sphtbl  equ     0
ENDIF;robin OR gener OR dmII OR vector OR trs80 
;
IF mmdI OR osi OR cpm3 OR S1008 ; [29]
spdtbl  EQU     0               ;[hh] SET BAUD not supported.
sphtbl  EQU     0               ;[hh] ran out of room above...
ENDIF;mmdI OR osi OR cpm3 OR S1008 [29]
;
IF hp125			;[MF]
spdtbl  equ     0               ; SET BAUD not supported.
sphtbl  equ     0
ENDIF;hp125 [MF]
;
;       This is the system-dependent SET PORT command.
;       HL contains the argument from the command table.
sysprt:
IF lobo ;[hh]
        mov     a,l             ;[hh] get the data port value and store at
        sta     outmd3+1        ;[hh] the two places we use...
        sta     inpmd2+1        ;[hh] MNPORT in the overlay
        sta     port            ;[hh] inform program of the change in ports
        inr     a               ;[hh] status port = data port + 1 in the Lobo
        sta     outmd1+1        ;[hh] store it at the three places...
        sta     inpmd1+1        ;[hh] we use MNPRTS...
        sta     outctl+1        ;[hh] in the overlay
        mov     a,h             ;[hh] now get the baud rate port value
        sta     getbd+1         ;[hh] store it in the two places we use...
        sta     setbd+1         ;[hh] BAUDRT in the overlay
        sta     port+1          ;[hh] don't need to, but keeps it consistant
getbd:  lda     baudrt          ;[hh] get baud rate value from port
        sta     speed           ;[hh] tell STAT. baud rate for each port
                                ;[hh] is independant of the other
ENDIF   ;lobo

IF iobyt
        mov     a,m             ;Get the I/O byte
        sta     prtiob          ;Save the desired IO byte for this port
        inx     h               ;Point at next entry
        mov     a,m             ;Get the output function
        sta     prtfun          ;Save it
ENDIF;iobyt

IF iobyt AND robin
        inx     h               ;Point at next entry
        mov     a,m             ;Get the hardware address for the port
        sta     prtadr          ;Store it
ENDIF;iobyt AND robin
;
IF hp125			;[MF]
	push	psw
	push	b
	push	d
	push	h
	xchg			;Put port connect sequence address in DE
	call	prtstr		;Connect proper port
	pop	h
	pop	d
	pop	b
	pop	psw
ENDIF;hp125 [MF]
;
        ret
;
;       Port tables for Lobo MAX-80
IF lobo ;[hh]
; help text
prhtbl: db      cr,lf,'RS-232 port A or B$'
;
; command table
prttbl: db      02H                     ;[hh] two entries
        db      01H,'A$',0E4H,0D0H
        db      01H,'B$',0E6H,0D4H
ENDIF   ;lobo
;
;       Port tables for GENERIC CPM 2.2
IF gener
; help text
prhtbl: db      cr,lf,'CRT device'
        db      cr,lf,'PTR device'
        db      cr,lf,'TTY device'
        db      cr,lf,'UC1 device'
        db      cr,lf,'UR1 device'
        db      cr,lf,'UR2 device$'

; command table
prttbl: db      06H             ;Six devices to choose from
        db      03H,'CRT$'
                dw      crtptb
        db      03H,'PTR$'
                dw      ptrptb
        db      03H,'TTY$'
                dw      ttyptb
        db      03H,'UC1$'
                dw      uc1ptb
        db      03H,'UR1$'
                dw      ur1ptb
        db      03H,'UR2$'
                dw      ur2ptb

; port entry table
; table entries are:
;       db      iobyte-value, BDOS output function, reserved
crtptb: db      crtio,conout,0
ptrptb: db      ptrio,punout,0
ttyptb: db      ttyio,conout,0
uc1ptb: db      uc1io,conout,0
ur1ptb: db      ur1io,punout,0
ur2ptb: db      ur2io,punout,0
ENDIF;gener

;
;       Port tables for DECmate II or MicroMikko or Acorn BBC
;
IF dmII OR mikko OR bbc ;[22]
; help text
prhtbl: db      cr,lf,'COMMUNICATIONS port$'

; command table
prttbl: db      01H             ;Only one port known at this point
        db      0EH,'COMMUNICATIONS$'
                dw      comptb  ;address of info

; port entry table
; table entries are:
;       db      iobyte-value, BDOS output function, reserved
comptb: db      batio,punout,0

ENDIF;[22] dmII OR mikko OR bbc
;
;       Port tables for Robin
;
IF robin
; help text
prhtbl: db      cr,lf,'COMMUNICATIONS port'
        db      cr,lf,'GENERAL purpose port'
        db      cr,lf,'PRINTER port$'

; command table
prttbl: db      03H             ;Three entries
        db      0EH,'COMMUNICATIONS$'
                dw      comptb
        db      07H,'GENERAL$'
                dw      gppptb
        db      07H,'PRINTER$'
                dw      prnptb

; port entry table
; table entries are:
;       db      iobyte-value, BDOS output function, hardware port address
;                                                   (control/status)
;
;At present, the hardware port address is only used for sending a break.
comptb: db      batio,punout,comtst
gppptb: db      gppio,conout,gentst
prnptb: db      lptio,conout,prntst

prtadr: db      comtst          ;space for current hardware port address
ENDIF;robin

IF iobyt
prtfun: db      punout          ;Function to use for output to comm port
prtiob: db      batio           ;I/O byte to use for communicating
coniob: db      defio           ;I/O byte to use for console
ENDIF;iobyt
;
IF hp125			;[MF]
; Help table
prhtbl:	db	cr,lf,'Communications port'
	db	cr,lf,'Printer port$'
; command table
prttbl:	db	02H		;2 entries
	db	0eH,'COMMUNICATIONS$'
	dw	mapon1
	db	07H,'PRINTER$'
	dw	mapon2
;Port table entries are the addresses of the escape sequences to connect
;the ports.
;
ENDIF;hp125 [MF]

IF NOT (iobyt OR lobo OR hp125)          ;[hh] [MF]
prttbl  equ     0               ; SET PORT is not supported
prhtbl  equ     0
ENDIF;NOT iobyt OR lobo OR hp125 [MF]
;
;       selmdm - select modem port
;       selcon - select console port
;       selmdm is called before using inpmdm or outmdm;
;       selcon is called before using inpcon or outcon.
;       For iobyt systems, diddle the I/O byte to select console or comm port;
;       For Decision I, switches Multi I/O board to console or modem serial
;       port.  [Toad Hall]
;       For the rest, does nothing.
;       preserves bc, de, hl.
selmdm:
IF iobyt
	lda     prtiob          ;Set up for output to go to the comm port
        sta     iobyte          ;Switch byte directly
ENDIF;iobyt

IF mdI
        lda     group
        ori     mdmgrp          ;Mask modem serial port
        out     grpsel
ENDIF;mdI  [Toad Hall]

        ret

selcon:
IF iobyt
        lda     coniob          ;Set up for output to go to the console port
        sta     iobyte          ;Switch directly
ENDIF;iobyt

IF mdI
        lda     group
        ori     congrp          ;Mask console serial port (1)
        out     grpsel
ENDIF;mdI  [Toad Hall]

        ret
;       Get character from console, or return zero.
;       result is returned in A.  destroys bc, de, hl.
;
inpcon:
IF NOT iobyt
        mvi     c,dconio        ;Direct console I/O BDOS call.
        mvi     e,0FFH          ;Input.
        call    BDOS
ENDIF;NOT iobyt

IF iobyt
        call    bconst          ;Get the status
        ora     a               ;Anything there?
        rz                      ;No, forget it
        call    bconin          ;Yes, get the character
ENDIF;iobyt
        ret
;
;       Output character in E to the console.
;       destroys bc, de, hl
;
outcon:

IF rm380z       ;[22]
        mov     a,e
        cpi     cr              ;cr produces cr + lf
        jnz     outcn1
        mvi     e,'N'-100O      ;Control-N produces cr only
outcn1:                         ;continue
ENDIF;[22] rm380z

IF NOT iobyt
        mvi     c,dconio        ;Console output bdos call.
        call    bdos            ;Output the char to the console.
ENDIF;NOT iobyt

IF iobyt
        mov     c,e             ;Character
        call    bcnout          ;to Console
ENDIF;iobyt
        ret
;
;       outmdm - output a char from E to the modem.
;               the parity bit has been set as necessary.
;       returns nonskip; bc, de, hl preserved.
outmdm:
IF osi OR lobo         ;[hh]
        push    h
outmd1: lxi     h,mnprts        ;address of the port status register
outmd2: mov     a,m             ; get port status in A
        ani     output          ;Loop till ready.
        jz      outmd2
outmd3: lxi     h,mnport        ;address of port data register
        mov     m,e             ; write the character
        pop     h
        ret
ENDIF;osi OR lobo

IF osbrn1
        call    osldst          ;Read the status port
        ani     output          ;Loop till ready.
        jz      outmdm
        mov     a,e
        jmp     osstda          ;Write to the data port
ENDIF;osbrn1

IF px8 ; [29]
        push    h
        push    b
        push    d
outmd1: call    rsoutst         ; get the output status
        ora     a
        jz      outmd1          ; check if output enabled
        pop     d
        mov     c, e            ; char in C
        push    d
        call    rsput
        pop     d
        pop     b
        pop     h
        ret
ENDIF; px8 [29]

IF inout
        in      mnprts          ;Get the output done flag.
        ani     output          ;Is it set?
        jz      outmdm          ;If not, loop until it is.
        mov     a,e
        out     mnport          ;Output it.
        ret
ENDIF;inout

IF iobyt
;**** Note that we enter from outpkt with the I/O byte already set up for
;  output to go to the comm port
        push    h
        push    b
        lda     prtfun          ;Get the output function
        mov     c,a             ;Into C
        call    bdos            ;And output the character
        pop     b
        pop     h
        ret
ENDIF;iobyt

IF cpm3 OR hp125 ;[MF]
        push    h
        push    b
        mvi     c,auxout        ;Output to the aux output device
        call    bdos
        pop     b
        pop     h
        ret
ENDIF;cpm3 OR hp125 [MF]

;org	$+100h AND 0FF00h	; get rid of phase error

;
;       get character from modem; return zero if none available.
;       for IOBYT systems, the modem port has already been selected.
;       destroys bc, de, hl.
inpmdm:
IF iobyt
        call    bconst          ;Is Char at COMM-Port?
        ora     a               ;something there?
        rz                      ; return if nothing there
        call    bconin          ; data present. read data.
ENDIF;iobyt

IF cpm3
        mvi     c,auxist
        call    bdos            ;is char at auxin?
        ora     a               ;something there?
        rz                      ;no
        mvi     c,auxin
        call    bdos            ;read char from auxin
ENDIF;cpm3
;
IF hp125			;[MF]
	lxi	b,70ffh		;SEt subfunction to get RDR (auxin) status
        call    bdos            ;is char at RDR?
        ora     a               ;something there?
        rz                      ;no
        mvi     c,auxin
        call    bdos            ;read char from RDR
ENDIF;hp125 [MF]

IF osi OR lobo         ;[hh]
inpmd1: lda     mnprts          ;Get the port status into A.
        ani     input           ;See if the input ready bit is on.
        rz                      ;If not then return.
inpmd2: lda     mnport          ;If so, get the char.
ENDIF;osi OR lobo 

IF osbrn1
        call    osldst          ;Read the status port
        ani     input           ;Something there?
        rz                      ;Nope
        call    osldda          ;Read the data port
ENDIF;osbrn1

IF inout
;Note: modem port should already be selected for mdI.  [Toad Hall]
        in      mnprts          ;Get the port status into A.
        ani     input           ;See if the input ready bit is on.
        rz                      ;If not then return.
        in      mnport          ;If so, get the char.
ENDIF;inout

IF px8 ; [29]
        call    rserst          ; check error status
        ani     64h             ; this assumes 'not open' cannot occur
        jnz     inpmd1          ; error has occurred!
        call    rsinst          ; any chars outstanding?
        ora     a
        rz                      ; exit if none
        call    rsget           ; get char in A
        ret
; return the 'no char outstanding' indication on error
inpmd1: mvi     a, 0
ENDIF; px8 [29]

	ret                     ; return with character in A


;
;       flsmdm - flush comm line.
;       Modem is selected.
;       Currently, just gets characters until none are available.

flsmdm: call    inpmdm          ; Try to get a character
        ora     a               ; Got one?
        jnz     flsmdm          ; If so, try for another
        ret                     ; Receiver is drained.  Return.
;
;       lptstat - get the printer status. Return a=0ffh if ok, or 0 if not.
lptstat:
IF iobyt                        ;[33]
        call    bprtst          ;
call    bprtst          ; get status
ENDIF   ;iobyt[33]
IF NOT iobyt    ;[33]
        xra     a               ; assume it is ok.. this may not be necessary
ENDIF   ;iobyt [33]
        ret

;
;       outlpt - output character in E to printer
;       console is selected.
;       preserves de.
outlpt:
        push    d               ; save DE in either case
        call    prtflt          ; go through printer filter [30]
        ana     a               ; if A = 0 do nothing,
        jz      outlp1          ; [30] if a=0 do nothing

IF NOT iobyt
        mvi     c,lstout
        call    bdos            ;Char to printer
ENDIF;NOT iobyt
IF iobyt
        mov     c,e
        call    blsout
ENDIF;iobyt

outlp1: pop     d               ; restore saved register pair
        ret
;
;       Screen manipulation routines
;       csrpos - move to row B, column C
;
;       csrpos for terminals that use a leadin sequence followed
;        by (row + 31.) and (column + 31.)
;
IF NOT (robin OR dmII OR osi OR vector OR termin OR hp125)
				;[MF] Terminals code in CPXVDU
csrpos: push    b               ; save coordinates
        lxi     d,curldn        ; get cursor leadin sequence
        call    prtstr          ; print it
        pop     h               ; restore coordinates
        mov     a,h             ; get row
        adi     (' '-1)         ; space is row one
        mov     e,a
        push    h
        call    outcon          ; output row
        pop     h
        mov     a,l             ; get column
        adi     (' '-1)         ; space is column one
        mov     e,a
        jmp     outcon          ; output it and return
ENDIF;NOT (robin OR dmII OR osi OR vector OR termin OR hp125)[MF]
;
;
;
;       csrpos for ANSI terminals
;
IF robin OR dmII 
csrpos: push    b               ; save coordinates
        lxi     d,curldn        ; get cursor leadin sequence
        call    prtstr          ; print it
        pop     h               ; peek at coordinates
        push    h               ;  then save away again
        mov     l,h             ; l = row
        mvi     h,0             ; hl = row
        call    nout            ; output in decimal
        mvi     e,';'           ; follow with semicolon
        call    outcon          ; print it
        pop     h               ; restore column
        mvi     h,0             ; hl = column
        call    nout
        mvi     e,'H'           ; terminate with 'move cursor' command
        jmp     outcon          ; output it and return
ENDIF;robin OR dmII 
;
;       csrpos for the HP-125 [MF]
;
IF hp125				;[MF]
csrpos:	dcr	b		;HP-125 uses zero-based addressing
	dcr	c		;...
 push    b               ; save coordinates
        lxi     d,curldn        ; get cursor leadin sequence
        call    prtstr          ; print it
        pop     h               ; peek at coordinates
        push    h               ;  then save away again
        mov     l,h             ; l = row
        mvi     h,0             ; hl = row
        call    nout            ; output in decimal
        mvi     e,'R'+20h	;Say it was a row
        call    outcon          ; print it
        pop     h               ; restore column
        mvi     h,0             ; hl = column
        call    nout
        mvi     e,'C'           ; terminate with 'move cursor' command
        jmp     outcon          ; output it and return
ENDIF;hp125 [MF]
;
;       csrpos for the Vector General.  It's weird.
;
IF vector
csrpos: dcr     b               ; vector uses zero-based addressing?
        dcr     c
        push    b               ; save coordinates
        mvi     e,esc           ; print an escape
        call    outcon
        pop     d               ; peek at coordinates
        push    d
        call    outcon          ; output column
        pop     d
        mov     e,d             ; get row
        jmp     outcon          ; output and return
ENDIF;vector

IF osi 				; systems without cursor positioning
csrpos: ret                     ; dummy routine referenced by linkage section
ENDIF;osi


;
; delchr - make delete look like a backspace.  Unless delete is a printing
;       character, we just need to print a backspace. (we'll output clrspc
;       afterwards)
;       For Kaypro and Vector General, delete puts a blotch on the screen.
;       For Apple and Osborne 1, delete moves but doesn't print.
delchr:

IF vector OR osbrn1 OR lobo
        lxi     d,delstr
        jmp     prtstr
ENDIF	;vector OR osbrn1 OR lobo

IF bbc OR rm380z      ;[22]
        ret
ENDIF;bbc OR rm380z

IF NOT (vector OR osbrn1 OR bbc OR rm380z);[22]
        mvi     e,bs            ;get a backspace
        jmp     outcon
ENDIF;NOT (vector OR osbrn1 OR bbc OR rm380z [22]

; erase the character at the current cursor position
clrspc: mvi     e,' '
        call    outcon
        mvi     e,bs            ;get a backspace
        jmp     outcon

; erase the current line
clrlin: lxi     d,eralin
        jmp     prtstr

; erase the whole screen, and go home. preserves b (but not c)
clrtop: lxi     d,erascr
        jmp     prtstr


IF robin
sysver:	db	'VT180 Robin$'
ENDIF;robin

IF dmII
sysver:	db	'DECmate II CP/M-80$'
ENDIF;dmII

IF delphi	; [7] new system
sysver:	db	'Digicomp Delphi 100$'
endif;delphi

IF access
sysver:	db	'Actrix CP/M$'
endif;

IF teletek
sysver:	db	'Teletek SYSTEMASTER CP/M-80$'
ENDIF	;teletek

IF cpt85xx
sysver:	db	'CPT-85xx under CompuPak CP/M$'
ENDIF;cpt85xx

IF mdI
sysver:	db	'Morrow Decision I$'
ENDIF;mdI  [Toad Hall]

IF mmdI
sysver:	db	'MicroDecision I$'
ENDIF;mmdI

IF osi
sysver:	db	'Ohio Scientific$'
ENDIF;osi

IF mmate	;[29]
sysver:	db	'PMC Micromate using port I/O$'
ENDIF;mmate [29]

IF disc		;[29]
sysver:	db	'Discovery using 83U board port B$'
ENDIF  ;disc [29]

IF s1008	;[29]
sysver:	db 'U. S. MicroSales using printer port$'
ENDIF ;s1008 [29]

IF cmemco	;[25]
sysver:	db	'Cromemco (TU-ART)$'
ENDIF;cmemco
;
IF robin OR dmII
; Note that we cannot support Graphics Mode or the H19 erase-screen command
; (<esc>E), because the sequences are more than three bytes.
defesc	EQU	'\'-100O        ;Still Control-\ (just ran out of room...)
vtval	EQU	0		; we probably don't want VT52 emulation
outlin:	db	esc,3CH,esc,'[H',esc,'[J',cr,lf,tab,tab,'$'
erascr:	db	esc,'[H',esc,'[J$'      ;Clear screen and go home.
eralin:	db	cr,esc,'[K$'            ;Clear line.
curldn:	db	esc,'[$'                ; Cursor leadin
ttab:
ta:	db	esc,'[A$'               ; Cursor up.
tb:	db	esc,'[B$'               ; Cursor down.
tc:	db	esc,'[C$'               ; Cursor right.
td:	db	esc,'[D$'               ; Cursor left
te:	db	'$',0,0,0               ; (can't) Clear display
tf:	db	'$',0,0,0               ; (don't) Enter Graphics Mode
tg:	db	'$',0,0,0               ; (don't) Exit Graphics mode
th:	db	esc,'[H$'               ; Cursor home.
ti:	db	esc,'M$',0              ; Reverse linefeed.
tj:	db	esc,'[J$'               ; Clear to end of screen.
tk:	db	esc,'[K$'               ; Clear to end of line.
ENDIF;robin OR dmII

IF mikko
sysver:	db	'MikroMikko$'
outlin:	db	subt,cr,lf,tab,'$'
erascr:	db	subt,'$'                ;Clear screen and go home.
eralin:	db	cr,1CH,'$'              ;Clear line.
curldn:	db	esc,'=$'                ;cursor leadin
ttab:					;Table start location.
ta:	db	0BH,'$',0,0             ;Cursor up.
tb:	db	0AH,'$',0,0             ;Cursor down.
tc:	db	0CH,'$',0,0             ;Cursor right.
td:	db	bs,'$',0,0              ;Cursor left
te:	db	subt,'$',0,0            ;Clear display
tf:	db	'$',0,0,0               ;(can't) Enter Graphics Mode
tg:	db	'$',0,0,0               ;(can't) Exit Graphics mode
th:	db	1EH,'$',0,0             ;Cursor home.
ti:	db	'$',0,0,0               ;(can't) Reverse linefeed.
tj:	db	1cH,'$',0,0             ;Clear to end of screen.
tk:	db	1cH,'$',0,0             ;Clear to end of line.
ENDIF;mikko
;
IF bbc		;[22]
sysver:	db	'BBC (Z80)$'
outlin:	db	0CH,esc,'=',21H,30H,'$'
erascr:	db	0CH,'$'                 ;Clear screen and go home.
eralin:	db	cr,esc,'@$'             ;Clear line.
curldn:	db	esc,'=$'                ;cursor leadin
ttab:					;Table start location.
ta:	db	0BH,'$',0,0             ;Cursor up.
tb:	db	0AH,'$',0,0             ;Cursor down.
tc:	db	tab,'$',0,0             ;Cursor right.
td:	db	bs,'$',0,0              ;Cursor left
te:	db	0CH,'$',0,0             ;Clear display
tf:	db	'$',0,0,0               ;(can't) Enter Graphics Mode
tg:	db	'$',0,0,0               ;(can't) Exit Graphics mode
th:	db	1EH,'$',0,0             ;Cursor home.
ti:	db	'$',0,0,0               ;(can't) Reverse linefeed.
tj:	db	esc,'?$',0,0            ;Clear to end of screen.
tk:	db	esc,'@$',0,0            ;Clear to end of line.
ENDIF;[22] bbc
;
IF rm380z	;[22]
sysver:	db	'Research Machines 380Z$'
outlin:	db	1FH,cr,tab,'$'
erascr:	db	1FH,'$'                 ;Clear screen and go home.
eralin:	db	0EH,19H,'$'             ;Clear line.
curldn:	db	16H,'$'                 ;cursor leadin
ttab:					;Table start location.
ta:	db	0BH,'$',0,0             ;Cursor up.
tb:	db	0AH,'$',0,0             ;Cursor down.
tc:	db	18H,'$',0,0             ;Cursor right.
td:	db	bs,'$',0,0              ;Cursor left
te:	db	1FH,'$',0,0             ;Clear display
tf:	db	'$',0,0,0               ;(can't) Enter Graphics Mode
tg:	db	'$',0,0,0               ;(can't) Exit Graphics mode
th:	db	1DH,'$',0,0             ;Cursor home.
ti:	db	'$',0,0,0               ;(can't) Reverse linefeed.
tj:	db	1EH,'$',0,0             ;Clear to end of screen.
tk:	db	19H,'$',0,0             ;Clear to end of line.
ENDIF;[22] rm380z

IF lobo	;[hh]
sysver:	db	'Lobo MAX-80$'
outlin:	db	esc,'*',cr,lf,tab,tab,'$'
erascr:	db	esc,'*$'                ;[hh] clear screen and home cursor
eralin:	db	cr,esc,'R$'             ;[hh] clear line
curldn:	db	esc,'=$'                ;[hh] cursor lead-in string
delstr:	db	bs,' ',bs,bs,'$'        ;[hh] ??adjust for echoing delete
ttab:					;[hh] table start location
ta:	db	0BH,'$',0,0             ;[hh] cursor up
tb:	db	0AH,'$',0,0             ;[hh] cursor down
tc:	db	0CH,'$',0,0             ;[hh] cursor right
td:	db	08H,'$',0,0             ;[hh] cursor left
te:	db	esc,'*$',0              ;[hh] clear display (homes cursor)
tf:	db	'$',0,0,0               ;[hh] (can't) enter graphics mode
tg:	db	'$',0,0,0               ;[hh] (can't) exit graphics mode
th:	db	01EH,'$',0,0            ;[hh] home cursor
ti:	db	esc,'E$',0              ;[hh] reverse linefeed (insert line)
tj:	db	esc,'Y$',0              ;[hh] clear to end of screen
tk:	db	esc,'T$',0              ;[hh] clear to end of line
ENDIF	;lobo

IF px8 ; [29]
sysver:	db	'Epson PX-8$'
outlin:	db	esc,'*$'
erascr:	db	esc,'*$'    ; clear screen and home
eralin:	db	cr,esc,'T$' ; clear line
curldn:	db	esc,'=$'    ; cursor lead in
ttab:			    ; table start location
ta:	db	30,'$',0,0  ; cursor up
tb:	db	31,'$',0,0  ; cursor down
tc:	db	28,'$',0,0  ; cursor right
td:	db	29,'$',0,0  ; cursor left
te:	db	esc,'*$',0  ; clear display
tf:	db	'$',0,0,0   ; can't enter graphics graphics mode
tg:	db	'$',0,0,0   ; can't exit graphics mode
th:	db	11,'$',0,0  ; home cursor
ti:	db	30,'$',0,0  ; reverse linefeed
tj:	db	esc,'Y$',0  ; erase to end of screen
tk:	db	esc,'T$',0  ; erase to end of line
ENDIF ; px8 [29]

;
IF osbrn1
sysver:	db	'Osborne 1$'
outlin:	db	1AH,cr,lf,tab,'$'       ;(Clear screen, home cursor)
erascr:	db	1AH,'$'                 ;Clear screen and go home.
eralin:	db	cr,esc,'T$'             ;Clear line.
delstr:	db	bs,bs,'$'               ; Adjust for delete
curldn:	db	esc,'=$'                ;Cursor lead-in
ttab:					;Table start location.
ta:	db	('K'-100O),'$',0,0      ;Cursor up.
tb:	db	12O,'$',0,0             ;Cursor down.
tc:	db	('L'-100O),'$',0,0      ;Cursor right.
td:	db	bs,'$',0,0              ;Cursor left.
te:	db	subt,'$',0,0            ;Clear screen.
tf:	db	'$',0,0,0               ;(can't) Enter graphics mode
tg:	db	'$',0,0,0               ;(can't) Exit graphics mode
th:	db	('^'-100O),'$',0,0      ;Cursor home.
ti:	db	('K'-100O),'$',0,0      ;Reverse linefeed.
tj:	db	esc,'T$',0              ;(can't) Clear to end of screen.
tk:	db	esc,'T$',0              ;Clear to end of line.
ENDIF;osbrn1
;
IF vector
sysver:	db	'Vector Graphics$'
outlin:	db	('D'-100O),cr,lf,tab,tab,'$'
erascr:	db	('D'-100O),'$'          ;Clear screen and go home.
eralin:	db	cr,('Q'-100O),'$'       ;Clear line.
delstr:	db	bs,' ',bs,bs,'$'        ; adjust for echoing delete character
ttab:					;Table start location.
ta:	db	('U'-100O),'$',0,0      ;Cursor up.
tb:	db	12O,'$',0,0             ;Cursor down.
tc:	db	('Z'-100O),'$',0,0      ;Cursor right.
td:	db	'$',0,0,0               ;(can't) Cursor left
te:	db	'$',0,0,0               ;(can't) Clear display
tf:	db	'$',0,0,0               ;(can't) Enter graphics mode
tg:	db	'$',0,0,0               ;(can't) Exit graphics mode
th:	db	('B'-100O),'$',0,0      ;Cursor home.
ti:	db	('U'-100O),'$',0,0      ;Reverse linefeed.
tj:	db	('P'-100O),'$',0,0      ;Clear to end of screen.
tk:	db	('Q'-100O),'$',0,0      ;Clear to end of line.
ENDIF;vector

IF trs80lb
sysver:	db	'TRS-80 II Lifeboat CP/M$'
outlin:	db	esc,':',cr,lf,tab,tab,'$'
erascr:	db	esc,':$'                ;Clear screen and go home.
eralin:	db	cr,esc,'T$'             ;Clear line.
curldn:	db	esc,'=$'                ;Cursor lead-in
ttab:					;Table start location.
ta:	db	0BH,'$',0,0             ;Cursor up.
tb:	db	0AH,'$',0,0             ;Cursor down.
tc:	db	0CH,'$',0,0             ;Cursor right.
td:	db	bs,'$',0,0              ;Cursor left
te:	db	esc,':$',0              ;Clear display
tf:	db	'$',0,0,0               ;(can't) Enter Graphics Mode
tg:	db	'$',0,0,0               ;(can't) Exit Graphics mode
th:	db	1EH,'$',0,0             ;Cursor home.
ti:	db	0BH,'$',0,0             ;Reverse linefeed.
tj:	db	esc,'Y$',0              ;Clear to end of screen.
tk:	db	esc,'T$',0              ;Clear to end of line.
ENDIF;trs80lb
;
IF trs80pt
sysver:	db	'TRS-80 II P+T CP/M$'
outlin:	db	0CH,cr,lf,tab,tab,'$'
erascr:	db	0CH,'$'                 ;Clear screen and go home.
eralin:	db	cr,01H,'$'              ;Clear line.
curldn:	db	esc,'Y$'                ;Cursor lead-in
ttab:	;Table start location           ;Must be 4 bytes each
ta:	db	1EH,'$',0,0             ;Cursor up.
tb:	db	1FH,'$',0,0             ;Cursor down.
tc:	db	1DH,'$',0,0             ;Cursor right.
td:	db	1CH,'$',0,0             ;Cursor left
te:	db	0CH,'$',0,0             ;Clear display
tf:	db	11H,'$',0,0             ;Enter Graphics Mode
tg:	db	14H,'$',0,0             ;Exit Graphics mode
th:	db	06H,'$',0,0             ;Cursor home.
ti:	db	1EH,'$',0,0             ;Reverse linefeed.
tj:	db	02H,'$',0,0             ;Clear to end of screen.
tk:	db	01H,'$',0,0             ;Clear to end of line.
ENDIF;trs80pt

IF osi
outlin:	db	cr,lf,'Starting ...$'
erascr	equ	crlf			;"Home & clear" (best we can do).
eralin:	db	'^U',cr,lf,'$'          ;Clear line.
prpack:	db	cr,lf,'RPack: $'
pspack:	db	cr,lf,'SPack: $'
ttab	equ	0			; no VT52 table
ENDIF;osi
;
IF hp125			;[MF]
defesc	EQU	'\'-100O        ;Still Control-\ (just ran out of room...)
vtval	EQU	0		; we probably don't want VT52 emulation
;
sysver:	db	'HP-125 Series 100$'
;
outlin:	db	esc,'H',esc,'J',cr,lf,tab,tab,'$'
erascr:	db	esc,'H',esc,'J$' 	;Clear screen and go home.
eralin:	db	cr,esc,'K$'		;Clear line.
curldn:	db	esc,'&a$'		;Cursor leadin
ttab:					;Table start location.
ta:	db	esc,'A$',0		;Cursor up.
tb:	db	esc,'B$',0		;Cursor down.
tc:	db	esc,'C$',0		;Cursor right.
td:	db	esc,'D$',0		;Cursor left
te:	db	esc,'J$',0		;Clear display
tf:	db	'$',0,0,0		;[hh] (can't) enter graphics mode
tg:	db	'$',0,0,0		;[hh] (can't) exit graphics mode
th:	db	esc,'H$',0		;Cursor home.
ti:	db	esc,'M$',0		;Reverse linefeed.
tj:	db	esc,'J$',0		;Clear to end of screen.
tk:	db	esc,'K$',0		;Clear to end of line.
;
;
; Escape sequences to map CP/M Reader/Punch to Data Comm input/output,
;	respectively and to turn off these mappings
;
mapon1:	db	esc,'&i10s18d9M'
	db	esc,'&i2s25d9M'
	db	esc,'&i10s16d2M'
	db	esc,'&i0s25d2M$';Esc. sequences to turn off DAtacomm2/turn
				;on Data Comm 1
mapon2:	db	esc,'&i10s16d9M'
	db	esc,'&i0s25d9M'
	db	esc,'&i10s18d2M'
	db	esc,'&i2s25d2M$';Esc. sequences to turn off Datacomm1/turn
				;on Datacomm 2
mapoff:	db	esc,'&i0s25d9M'
	db	esc,'&i10s16d9M'
	db	esc,'&i2s25d9M'
	db	esc,'&i10s18d9M$'
;
readin:	call	$-$		;Read character into b
	mov	a,b		;Get 8-bit character
	ret			;and return
;
jbuf:	db	7		;bios dispatch table vector argument block
	db	0		;to read RDR routine address
	db	0c3h		;...
	dw	0		;...
;
ENDIF;hp125 ;[MF]

IF lasm and termin	; if no terminal, no need to link
LINK CPXVDU.ASM
ENDIF	; lasm and termin

ovlend	EQU	$

IF lasm
	END	; If m80 then this ignored
ENDIF	; lasm