aboutsummaryrefslogtreecommitdiff
path: root/src/cpxpcw.asm
diff options
context:
space:
mode:
authorJeff Armstrong <jeff@approximatrix.com>2026-10-25 17:42:06 -0400
committerJeff Armstrong <jeff@approximatrix.com>2026-10-25 17:42:06 -0400
commitebb2ff2af569d5822b70ee555a32d27cf7494816 (patch)
tree7ac5e7b3fa73f7a8d996129086932ecce66374ad /src/cpxpcw.asm
downloadkermit-80-ebb2ff2af569d5822b70ee555a32d27cf7494816.tar.gz
kermit-80-ebb2ff2af569d5822b70ee555a32d27cf7494816.zip
Initial import of 4.11HEADmain
Diffstat (limited to 'src/cpxpcw.asm')
-rw-r--r--src/cpxpcw.asm912
1 files changed, 912 insertions, 0 deletions
diff --git a/src/cpxpcw.asm b/src/cpxpcw.asm
new file mode 100644
index 0000000..554fd61
--- /dev/null
+++ b/src/cpxpcw.asm
@@ -0,0 +1,912 @@
+IF NOT lasm
+.printx * CPXPCW.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.08
+;
+; 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.
+;
+; This file contains the system-dependent code and data for KERMIT
+; on the Amstrad range of personal computers.
+;
+;
+; Revision history:
+;
+;edit 9, 22-Jan-1991 by MF. Added "sysinit" code at "init04" from Kermit
+; version 4.08 which had been left out of version 4.09 to reserve
+; space for the Amstrad's I/O buffers. Amstrad Kermit now stores
+; files correctly (version 4.09 had garbled files). Again,
+; this fix comes from Mr. D. P. Arnot of the Scottish Agricultural
+; College in the UK.
+;edit 8, 16-Jan-1991 by MF. Added a "bs" left out of "delstr" per
+; instruction from David P. Arnot of Scottish Agricultural
+; College, Auchincruive, Ayr, UK.
+; E-mail: <D.P.Arnot@edinburgh.ac.uk>
+; edit 7, 22 July 1987 by OBSchou to massage code to fit with CPXCOM.ASM
+; Had to rename bcnout to bcnot as the former label clashed with
+; one of the same name in CPXCOM.ASM. Sorry, folks.
+;
+; edit 6, 14th July, 1987 by OBSchou for Phillip Wade, Hull University
+; Computer Centre. Change to delchr routine for PCW machines,
+; as character 127 decimal is a printing character on
+; the Amstrad PCW. The routine has been replaced
+; by a bs,space,bs,bs string. (OBS Comment - why a total of THREE bs?)
+;
+; edit 5 9 May 1987 by C.J.MILES@UK.AC.UMRCC
+; Hangup phone and clear screen options added to
+; terminal mode.
+;
+; edit 4 23 March 1987 by C.J.MILES@UK.AC.UMRCC
+; Use direct input drom SIO for CPC machines instead
+; of using BDOS. Improvement reduces time for file
+; transfer to 65% of time used by BDOS method.
+; Add reverse Prestel baud rate.
+;
+; edit 3 20 March 1987 by Chris Miles (C.J.MILES@UK.AC.UMRCC)
+; (Greater Manchester Archaeological Unit, Manchester Univ.).
+; Added support for Amstrad CPC CP/M Plus machines,
+; Added 31250 baud rate option,
+; Bug fixed in sending BREAK,
+; Bug fixed in 1200/75 baud setup
+; Machine and CP/M version checks added.
+;
+; edit 2 11 Febuary, 1987 by OBSchou for Ian Young.
+; Changes to the send break routine to change two lines of code from
+; ori 018h ; send break, Tx enable
+; and ori 0008h ; Tx enable
+;
+; to ori 01ah ; send break, Tx enable, RTS
+; and ori 00ah ; Tx enable, RTS
+;
+; This is a bug fix to hopefully keep RTS actve during breaks.
+;
+; [Ed. (OBSchou) 21/1/87.
+; This file linked FROM cpxsys.asm, so do NOT rename this
+; file. The diffculty of needing a HUGE CPXSYS.ASM file on your floppy
+; only to act as a switcher remains, but hopefully will be better in
+; the future. If you ARE stuck, then rename this CPXSYS.ASM but add the
+; label SYSEDT: to the FAMILY label. A bit messy.]
+;
+;
+; The "author" of this system-dependent file is:
+;
+; Ian A. Young
+; Lattice Logic Ltd
+; 9 Wemyss Place
+; Edinburgh
+;
+; Some other addresses:
+;
+; ian@latlog.uucp
+; ...seismo!mcvax!ukc!latlog!ian
+; or c/o OBSchou@uk.ac.lut.multics
+;
+; ... although much of the code concerned was written by others.
+;
+
+
+; Keep module name, edit number, and last revision date in memory.
+
+;sysedt: db 'CPXSYS.ASM (36) 20-Mar-87$'
+family: db 'CPXPCW.ASM (9) 22-Jan-1991$'
+
+
+;
+; Assembly-time message announcing which version we are building
+;
+
+IF pcw
+.printx * Assembling Amstrad PCW Kermit-80 *
+ENDIF
+
+IF cpc
+.printx * Assembling Amstrad CPC Kermit-80 *
+ENDIF
+
+;
+; Miscellany of parameter settings
+;
+z80 EQU TRUE ; all Amstrads have a Z80.
+defesc EQU '\'-100O ; The default escape character.
+vtval EQU 0 ; we don't need VT52 emulation
+
+;
+; Amstrad CPC machines use 16 bit I/O address decoding and therefore
+; the Z80 instructions OUT (C),A and IN A,(C) must be defined.
+;
+outc EQU 79edh ; IN A,(C)
+inpc EQU 78edh ; OUT (C),A
+
+;
+; hardware information
+;
+; There is a Z80-DART (Mostek/SGS 8470) at I/O addresses E0..E3 (PCW)
+; and FADC..FADD (CPC), and a 8253 programmable divider running it at
+; E4..E7 (PCW) and FBDC..FBDF (CPC)
+;
+
+input EQU 01h ; input data available
+output EQU 04h ; output buffer ready
+
+IF pcw
+mnport EQU 0E0h ; data register for SIO
+mnprts EQU 0E1h ; control register for SIO
+ctc0 EQU 0E4h ; 8253 load counter 0
+ctc1 EQU 0E5h ; 8253 load counter 1
+ctcmod EQU 0E7h ; 8253 write mode word
+ENDIF
+
+IF cpc
+mnport EQU 0FADCh ; data register for SIO
+mnprts EQU 0FADDh ; control register for SIO
+ctc0 EQU 0FBDCh ; 8253 load counter 0
+ctc1 EQU 0FBDDh ; 8253 load counter 1
+ctcmod EQU 0FBDFh ; 8253 write mode word
+ENDIF
+
+;
+; SIO input buffering
+;
+siosz EQU 4096 ; size of SIO input buffer
+siomsk EQU 4095 ; mask for wrapping buffer round
+
+;
+; Extended BIOS jump-block addresses; reached through USERF
+;
+sainit EQU 00B6h ; initialise SIO
+sabaud EQU 00B9h ; set baud rate
+saparm EQU 00BCh ; fetch SIO parameters
+teask EQU 00BFh ; find out cursor position
+cdvers EQU 00E3h ; get version numbers
+cdinfo EQU 00E6h ; get BIOS system information
+
+;
+; System-dependent initialization
+; Called once at program start.
+sysxin: ; continuation of system initialzation
+;
+; check for correct CP/M version
+;
+ mvi c,12 ; get CP/M version BDOS call
+ call bdos
+ mov a,l ; check if CP/M Plus
+ cpi 31h
+ jz init08
+ lxi d,wrong2 ; point to error message
+ call prtstr
+ mvi c,0 ; warm boot
+ call bdos
+;
+init08: ;[OBS] Moved the Cinfigured for message out as
+ ;[OBS] it is in CPXCOM.ASM
+;
+; get addresses of BIOS routines
+;
+; BIOS USERF is used to get to extended BIOS routines
+;
+ lhld 1 ; warm boot vector
+ lxi d,87 ; offset to USERF vector
+ dad d ; DE now has USERF vector address
+ shld userf+1 ; ready for jumping to...
+;
+; BIOS routines for fast character I/O
+;
+ lhld 1 ; warm boot vector (#1)
+ lxi d,3
+ dad d ; next is #2, CONST
+ shld bcnst+1
+ dad d ; next is #3, CONIN
+ shld bcnin+1
+ dad d ; next is #4, CONOUT
+ shld bcnot+1 ;[obs] Was bcnout, but this conflicts
+ ;[obs] with a label in CPXCOM.ASM
+ dad d ; next is #5, LIST
+ shld blist+1
+ dad d ; next is #6, AUXOUT
+ dad d ; next is #7, AUXIN
+ shld baxin+1
+ lhld 1 ; warm boot vector again
+ lxi d,002Ah ; offset to LISTST (#15)
+ dad d
+ shld lptstat+1
+ lhld 1 ; warm boot vector again
+ lxi d,0033h ; offset to AUXIST (#18)
+ dad d
+ shld baxist+1
+;
+; check if running on correct Amstrad
+;
+ call userf
+ dw cdvers
+IF pcw
+ cpi 0
+ENDIF
+IF cpc
+ cpi 1
+ENDIF
+ jnz init06
+ lxi d,wrong1 ; point to error message
+ call prtstr
+ mvi c,0
+ call bdos
+;
+; verify presence of SIO board by asking the BIOS.
+;
+init06: call userf ; C gets 00 if not fitted
+ dw cdinfo
+ xra a ; a <- 0
+ ora c ; zero => no serial port
+ jnz init03 ; non-zero => OK
+ lxi d,nosio ; snooty message...
+ call prtstr
+ mvi c,0 ; warm boot out of here
+ call bdos
+init03:
+;
+; find initial baud rate and other information
+;
+ call userf ; gives B=rx baud, C=tx baud, D=stop bits,
+ ; E=parity, H=rx bits, L=tx bits.
+ dw saparm ; get SIO parameters
+ push h ; save bit settings
+ mov a,b ; if TX and RX speeds same, they are OK
+ cmp c
+ jz init01
+ cpi 8 ; rx=1200?
+ jnz init02 ; no, can't be Prestel
+ mov a,c
+ cpi 2 ; tx=75?
+ jnz init02 ; no, can't be Prestel
+ lxi b,0 ; otherwise 1200/75 comes out as 0s.
+init01: push b ; assign value to SPEED
+ pop h
+ shld speed
+init02: ; here if we leave it as is
+ pop h ; get bit settings
+ mov a,l ; no of TX data bits set
+ sui 5 ; make into 00, 01, 10, 11.
+ rrc
+ rrc
+ rrc
+ sta txbits ; we may need it later
+;
+; set handshake mode: there are two parts to this, interrupts and
+; hardware handshake. The MODE byte used by the firmware expresses
+; this combination as -(int*2 + hand*1). Thus, both options on would
+; be (-3) or 0FDh.
+;
+; Here, we set the interrupt part of the mode on; it helps the BIOS cope.
+; Unfortunately, >sigh<, according to Soft971, this will only work
+; if you have BIOS V1.4 or higher. I have no idea what would happen
+; if we tried random hanshake mode flags with lower versions, so we
+; just skip over if it would be dangerous...
+;
+ call userf ; fetch all parameters
+ dw saparm
+ sta orgmode ; remember original mode for later
+
+ call userf ; get BIOS version to B,C
+ dw cdvers
+ mov a,b ; BIOS major version number (eg 1)
+ ora a ; if zero, too low...
+ jz init04
+ cpi 1 ; if not 1, definitely OK
+ jnz init05
+ mov a,c ; otherwise, its 1.X; want >= 4
+ cpi 4
+ jm init04 ; <4 => too low
+
+init05: call userf ; get the original flags back
+ dw saparm
+ xri 0FFh ; make mode into bit mask
+ inr a
+ ori 2 ; set interrupt mode
+ xri 0FFh ; turn back into mode value
+ inr a
+ call userf ; feed change back to BIOS
+ dw sainit
+init04: ; come here if not setting mode
+
+; Locate large buffers for multi-sector I/O and SIO input buffering.
+; Space above ovlend is available for buffers; we have pretty well the machine
+; to ourselves in an Amstrad PCW because they all gave 61K TPAs. We don't even
+; bother to perform any checking.
+; We don't want to use more than maxsec for disk buffers because
+; if we use too many, the remote end could time out while we're
+; writing to disk. maxsec is system-dependent, but for now we'll just
+; use 8Kbytes. If you get retransmissions and other protocol errors after
+; transferring the first maxsec sectors, lower maxsec.
+;
+maxsec EQU (8*1024)/bufsiz ; 8K / number of bytes per sector
+
+ lxi h,ovlend+siosz ; get start of buffer
+ shld bufadr ; store in linkage section
+ mvi a,maxsec ; get size of buffer, in sectors
+ sta bufsec ; store that, too.
+
+
+ ret ; return from system-dependent routine
+
+;
+; message complaining about wrong Amstrad machine
+;
+wrong1: db 'Error - This Kermit will only run on the Amstrad '
+IF pcw
+ db 'PCW 8256/8512'
+ENDIF
+IF cpc
+ db 'CPC 464/664/6128'
+ENDIF
+ db cr,lf,'$'
+;
+; message complaining about version of CP/M being used
+;
+wrong2: db 'Error - Incorrect CP/M version, needs CP/M 3.x'
+ db cr,lf,'$'
+;
+; message complaining of no SIO board
+;
+nosio: db 'Error - No SIO option fitted to this machine'
+ db cr, lf, '$'
+
+;
+; jumps to BIOS character I/O routines.
+; Addresses filled in by initialisation code above.
+;
+bcnst: jmp $-$ ; console status
+bcnin: jmp $-$ ; console input
+bcnot: jmp $-$ ; console output [obs - was bcnout]
+blist: jmp $-$ ; printer output
+baxin: jmp $-$ ; aux port input
+baxist: jmp $-$ ; aux port status
+lptstat:jmp $-$ ; printer status
+
+;
+; Other BIOS routines
+;
+userf: jmp $-$ ; call extended BIOS function
+
+;
+; saved value of some original parameters
+;
+orgmode:ds 1
+txbits: ds 1
+
+;
+; system-dependent termination processing
+; If we've changed anything, this is our last chance to put it back.
+sysexit:
+ call userf ; fetch firmware parameters
+ dw saparm
+ lda orgmode ; replace with original mode
+ call userf ; inform BIOS
+ dw sainit
+ ret
+
+;
+; system-dependent processing for start of CONNECT command
+;
+syscon:
+ lxi d,conmsg ; how to get escape char message
+ call prtstr
+ ret
+
+conmsg: ; Messages printed when entering transparent (CONNECT) mode:
+IF pcw
+ db '(Use boxed minus key next to space bar to generate a Control-\)'
+ENDIF
+ db cr,lf,'$'
+
+;
+; syscls - system-dependent close routine
+; called when exiting transparent session.
+;
+syscls:
+ ret
+
+;
+; sysinh - help for system-dependent special functions.
+; called in response to <escape>?, after listing all the
+; system-independent escape sequences.
+;
+sysinh:
+ lxi d,inhlps ; we got options...
+ call prtstr ; print them.
+ ret
+
+;
+; additional, system-dependent help for transparent mode
+; (two-character escape sequences)
+;
+inhlps:
+ db cr,lf,'B Transmit a BREAK'
+ db cr,lf,'H Hangup using DTR'
+ db cr,lf,'W Wipe screen clear'
+ db '$' ;[hh] table terminator
+
+;
+; sysint - system dependent special functions
+; called when transparent escape character has been typed;
+; the second character of the sequence is in A (and in B).
+; returns:
+; non-skip: sequence has been processed
+; skip : sequence was not recognized
+;
+sysint: ani 137O ; convert lower case to upper, for testing...
+ cpi 'B' ; send break ?
+ jz sendbr ; yes, go do it. return nonskip when through.
+ cpi 'H' ; hang up ?
+ jz hangup
+ cpi 'W' ; clear screen ?
+ jz clrtop
+ jmp rskp ; take skip return - command not recognized.
+
+;
+; Hangup (drop DTR) and Break send routine
+;
+
+hangup:
+ mvi d,0ah ; set up hangup bit mask
+ mvi e,255 ; time for hangup is 2 1/2 secs
+ jmp setbit ; skip Tx empty test
+
+sendbr:
+ mvi d,9ah ; set up break bit mask
+ mvi e,30 ; time for break is 300 ms
+
+sndbr1: mvi a,1 ; select Read Register 1
+
+IF pcw ; allow 8 bit I/O instructions
+ out mnprts
+ in mnprts ; read the contents
+ENDIF
+
+IF cpc ; use 16 bit I/O instructions
+ lxi b,mnprts
+ dw outc ; OUT (C),A
+ dw inpc ; IN A,(C)
+ENDIF
+
+ ani 1 ; test "all done" flag
+ jz sndbr1 ; loop until it's nonzero.
+;
+; Next, set the break or hangup bit on the SIO.
+;
+setbit:
+ mvi a,5 ; select Write Register 5
+IF pcw
+ out mnprts
+ENDIF
+IF cpc
+ dw outc ; OUT (C),A
+ENDIF
+ lda txbits ; get txbits (already in correct bit positions)
+ ora d ; send break, Tx Enable, RTS
+IF pcw
+ out mnprts
+ENDIF
+IF cpc
+ dw outc ; OUT (C),A
+ENDIF
+
+;
+; Now, delay for duration of hangup or break
+;
+ mov a,e ; delay count
+ call delay
+;
+; Time's up. Put transmitter back in normal state and return.
+;
+ mvi a,5 ; select Write Register 5
+IF pcw
+ out mnprts
+ENDIF
+IF cpc
+ lxi b,mnprts
+ dw outc ; OUT (C),A
+ENDIF
+ lda txbits ; get txbits again
+ ori 8ah ; Reset break, Tx Enable, RTS
+IF pcw
+ out mnprts
+ENDIF
+IF cpc
+ dw outc ; OUT (C),A
+ENDIF
+ ret ; done.
+
+;
+; sysflt - system-dependent filter
+; called with character in E.
+; if this character should not be printed, return with A = zero.
+; preserves bc, de, hl.
+; note: <xon>,<xoff>,<del>, and <nul> are always discarded.
+;
+sysflt:
+ mov a,e ; get character for testing
+ ret
+;
+; system-dependent processing for BYE command.
+;
+sysbye:
+ ret
+
+;
+; 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:
+ push d ; move to HL for firmware
+ pop h
+ mov a,h ; if h=0 then Prestel rates
+ ora a
+ jnz spd01 ; if not 1200/75 then skip
+ lxi h,0802H ; else set 1200/75 into HL
+ jmp spd03 ; jump to normal setup
+
+spd01: cpi 11h ; if h=11h then reverse Prestel
+ jnz spd02 ; if not 75/1200 then skip
+ lxi h,0208h ; else set 75/1200 into HL
+ jmp spd03 ; jump to normal setup
+
+spd02: cpi 10h ; if h=10h then 31250 baud
+ jnz spd03 ; if not 31250 then skip to normal setup
+ mvi a,36h ; set 8253 for mode 2 binary count
+ lxi b,ctcmod ; output to CTC mode register
+ dw outc
+ lxi b,ctc0 ; select transmit clock
+ mov a,4 ; timer value for 31250 (04h)
+ dw outc
+ mov a,0 ; timer value for 31250 (04h)
+ dw outc
+ lxi b,ctc0 ; select receive clock
+ mov a,4 ; timer value for 31250 (04h)
+ dw outc
+ mov a,0 ; timer value for 31250 (04h)
+ dw outc
+ ret
+
+spd03: call userf ; set whatever we have now...
+ dw sabaud ; using BIOS routine
+ ret
+
+;
+; 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)
+;
+spdtbl: db 12h ;18 entries
+ db 03h,'110$', 03h,03h
+ db 04h,'1200$', 08h,08h
+ db 07h,'1200/75$', 00h,00h ; real values faked up when required
+ db 05h,'134.5$', 04h,04h
+ db 03h,'150$', 05h,05h
+ db 04h,'1800$', 09h,09h
+ db 05h,'19200$', 0fh,0fh
+ db 04h,'2400$', 0ah,0ah
+ db 03h,'300$', 06h,06h
+ db 05h,'31250$',10h,10h ; flag to direct setup routine
+ db 04h,'3600$', 0bh,0bh
+ db 04h,'4800$', 0ch,0ch
+ db 02h,'50$', 01h,01h
+ db 03h,'600$', 07h,07h
+ db 04h,'7200$', 0dh,0dh
+ db 02h,'75$', 02h,02h
+ db 07h,'75/1200$',11h,11h ; real values faked up when required
+ db 04h,'9600$', 0eh,0eh
+
+sphtbl: db cr,lf,lf
+ db 'Normal rates: 50 75 110 134.5 150 300 600'
+ db cr,lf
+ db ' 1200 1800 2400 3600 4800 7200 9600 19200'
+ db cr,lf,lf
+ db 'High speed : 31250 (only between Amstrads)'
+ db cr,lf,lf
+ db 'Split rates : 1200/75 (Rx=1200, Tx= 75)'
+ db cr,lf
+ db ' 75/1200 (Rx= 75, Tx=1200)'
+ db cr,lf,'$'
+
+;
+; This is the system-dependent SET PORT command.
+; HL contains the argument from the command table.
+;
+sysprt:
+ ret
+
+prttbl equ 0 ; SET PORT is not supported
+prhtbl equ 0
+
+;
+; selmdm - select modem port
+; selcon - select console port
+; selmdm is called before using inpmdm or outmdm;
+; selcon is called before using inpcon or outcon.
+; preserves bc, de, hl.
+;
+selmdm:
+selcon:
+ ret
+
+;
+; Get character from console, or return zero.
+; result is returned in A. destroys bc, de, hl.
+;
+inpcon:
+ call bcnst ; get console status
+ ora a ; anything there?
+ rz ; no, forget it
+ jmp bcnin ; yes, get the character
+
+;
+; Output character in E to the console.
+; destroys bc, de, hl
+;
+outcon:
+ mov a,e ; TAB?
+ cpi tab
+ jz out001
+ mov c,e ; set correct arg register
+ jmp bcnot ; output to console via BIOS [obs was bcnout]
+
+;
+; perform tab expansion ourselves
+;
+out001: call userf ; get column in L
+ dw teask
+ mov a,l ; a <- column 0..n
+ ani 7 ; column 0..7
+ xri 0FFh ; not(col 0..7)
+ adi 9 ; a is 8-(colf7)
+out002: ora a ; any left?
+ rz ; return if not
+ dcr a ; one less now, anyhow
+ push psw ; save over BIOS call (just in case)
+ mvi c,' ' ; print one space
+ call bcnot ;[obs was bcnout]
+ call suck ; in case any stuff coming in
+ pop psw ; fetch count back
+ jmp out002 ; and go round again
+
+;
+; 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 cpc
+ push b ; save BC for CPC 16 bit I/O
+ENDIF
+outmd1:
+ call xsuck ; keep checking for incoming characters
+IF pcw
+ in mnprts ; get the output done flag.
+ENDIF
+IF cpc
+ lxi b,mnprts
+ dw inpc ; IN A,(C)
+ENDIF
+ ani output ; is it set?
+ jz outmd1 ; if not, loop until it is.
+ mov a,e
+IF pcw
+ out mnport ; output it.
+ENDIF
+IF cpc
+ lxi b,mnport
+ dw outc ; OUT (C),A
+ pop b ; restore BC
+ENDIF
+ ret
+
+;
+; get character from modem; return zero if none available.
+; destroys bc, de, hl.
+;
+inpmdm:
+ call suck ; get any characters pending
+ lhld sioct ; count of chars in buffer
+ mov a,h ; or together to get result
+ ora l
+ rz ; not got any, return now
+
+ dcx h ; down count
+ shld sioct
+
+ lhld siord ; read pointer
+ mov c,m ; fetch character ** NB TO C FOR NOW **
+
+ lxi d,1-ovlend ; bump pointer, subtract base
+ dad d
+ mov a,h ; mask high byte of offset
+ ani siomsk/256
+ mov h,a
+ lxi d,ovlend ; add in base again
+ dad d
+ shld siord
+
+ mov a,c ; get to proper register
+ ret
+
+;
+; 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.
+
+;
+; SIO input buffer handling. The buffer pointers are held as pointers into
+; the buffer. The read pointer
+; is to the next unused character, the write pointer to the next unused space.
+;
+siord: dw ovlend ; next char to read
+siowr: dw ovlend ; next char to write
+sioct: dw 0 ; number in buffer
+
+xsuck: push d ; save regs version of suck
+ push b
+ push h
+ call suck
+ pop h
+ pop b
+ pop d
+ ret
+
+;
+; suck
+;
+; this routine is called whenever it would be possible that some
+; characters might be available in the SIO device; they are all
+; transferred (there may be up to 4 pending) to the buffer.
+;
+; all registers are destroyed
+;
+suck:
+IF pcw
+ call baxist ; check input status via BDOS
+ ora a ; check if zero
+ENDIF
+IF cpc
+ lxi b,mnprts ; get input status directly
+ dw inpc ; IN A,(C)
+ ani input ; mask for Rx ready
+ENDIF
+ rz ; return if no
+
+IF pcw
+ call baxin ; fetch character via BDOS
+ENDIF
+IF cpc
+ lxi b,mnport ; fetch character directly from SIO
+ dw inpc ; IN A,(C)
+ENDIF
+
+ lhld siowr ; write pointer
+ mov m,a ; put character
+
+ lxi d,1-ovlend ; take off base, bump pointer
+ dad d
+ mov a,h ; top byte of offset
+ ani siomsk/256 ; masked off
+ mov h,a
+ lxi d,ovlend ; add on base again
+ dad d
+ shld siowr ; replace pointer
+
+ lhld sioct ; bump count in buffer
+ inx h
+ shld sioct
+
+ jmp suck ; go round in case any more
+
+;
+; outlpt - output character in E to printer
+; console is selected.
+; preserves de.
+outlpt:
+ push d ; save DE in either case
+ mov c,e ; correct arg register
+ call blist
+ 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.)
+; or (row) and (column)
+;
+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
+
+;
+; 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 pcw ;[6] OBS for Phillip Wade
+ lxi d,delstr ;[5] send a string rather than a single character
+ call prtstr
+
+delstr: db bs,' ',bs,'$' ;[OBS] Was bs,space,bs,bs
+ENDIF ;pcw
+
+ mvi e,bs ;get a backspace
+ jmp outcon
+
+; 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 pcw
+sysver: db 'Amstrad PCW with SIO option$'
+ENDIF
+IF cpc
+sysver: db 'Amstrad CPC with CP/M Plus$'
+ENDIF
+
+outlin: db esc,'H',esc,'J',cr,lf,' $'
+
+erascr: db esc,'H',esc,'J$' ;Clear screen and go home.
+eralin: db cr,esc,'K$' ;Clear line.
+curldn: db esc,'Y$' ;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,'E$',0 ;Clear display
+tf: db '$',0,0,0 ;Enter Graphics Mode
+tg: db '$',0,0,0 ;Exit Graphics mode
+th: db esc,'H$',0 ;Cursor home.
+ti: db esc,'I$',0 ;Reverse linefeed.
+tj: db esc,'J$',0 ;Clear to end of screen.
+tk: db esc,'K$',0 ;Clear to end of line.
+
+ovlend equ $ ; End of overlay
+
+ END