-IF NOT lasm
-.printx * CPXBEE.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.09
-;
-; 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.
-;
-;
-;
-; revision history:
-;
-; edit 1, 1st September 1990
-; Original version by Russell Lang <rjl@monu1.cc.monash.edu.au>
-; The 'microbee' is designed and manufactured in Australia
-; by Microbee Systems Ltd (previously Applied Technology).
-; The microprocessor is a Z80 at 3.375MHz.
-; The video screen is memory mapped from 0F000h to 0F7FFh,
-; with Programmable Characters 80-FF from 0F800h to 0FFFFh.
-; The serial and parallel ports are implemented using a Z80 PIO.
-; The early model microbees were ROM-Basic computers with up
-; to 32k of battery backed RAM. Later models dropped the
-; ROM-Basic and added disk drives and CP/M. The disk systems
-; include the 56k (64k) APC (5.25" drives), 64k Computer-In-A-Book
-; (3.5"), 128k Dynamic (5.25" or 3.5"), 256TC (3.5").
-;
-; This version of kermit was developed on a 56k APC.
-; It has been tested on 56k, 64k, 128k and 256k Microbees.
-;
-; The serial port is implemented in software NOT hardware.
-; A special transmit routine allows simultaneous receiving
-; for all speeds except 75/1200, 1200/75, 4800, 9600.
-; The receive routine is interrupt driven with a 2 kbyte buffer.
-; The 9600 bit/s speed is marginal on receive - if the transmitter
-; is slightly fast (more than about 1%), the serial routine will
-; not have enough time to put the character in the buffer before
-; the next character arrives.
-
-
-;
-; *** MAIN CODE START ***
-;
-;
-; Keep module name, edit number, and last revision date in memory.
-
-sysedt: db 'CPXSYS.ASM (35) 01-Dec-86$'
-family: db 'CPXBEE.ASM (1) 01-Sep-90$'
-
-
-; Assembly time message announcing which version we're building
-
-.printx * Assembling Microbee Kermit-80 *
-
-z80 EQU TRUE ; They all use Z80s
-
-defesc EQU ']'-100O ;The default escape character for Microbee
-
-vtval EQU 0 ; use default emulation which is adm3a superset
-
-;
-sysxin: ;continuation of system initialisation code
- ; set up baud rate
- lxi h,t300
- shld speed
- xchg
- call setbaud
- ; change the interrupt vector so that we intercept rs232 input
- db 0EDh,57h ;ld a,i ;get old interrupt reg
- sta oldint
- mvi a,int ;new value
- db 0EDh,47h ;ld i,a
- ret ; return from system-dependent routine
-
-
-;
-; sysexit - System-dependent termination processing
-; if we've changed anything, this is our last
-; chance to put it back.
-;
-sysexit:
- lda oldint ;restore old interrupt reg
- db 0EDh,47h ;ld i,a
- ret
-
-;
-; syscon - System-dependent processing for start
-; of CONNECT command.
-;
-syscon:
- lxi d,conmsg
- call prtstr
- ret
-
-conmsg: ; Messages printed when entering transparent (CONNECT) mode:
- 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 (0.3s)'
- db cr,lf,'L Transmit a LONG BREAK (1.8s)'
- db cr,lf,'W Wipe screen clear'
- db '$'
-
-; 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 ; then jump to send break routine
- cpi 'L' ; long break ?
- jz longbr ; then jump to long break routine
- cpi 'W' ; clear screen ?
- jz clrtop ; then jump to clear screen routine
- jmp rskp ; take skip return - command not recognized.
-
-;
-; Break routines
-;
-longbr:
- mvi e,180 ; time for long break is 1800 ms
- jmp setbit
-
-sendbr:
- mvi e,30 ; time for break is 300 ms
-
-setbit:
- in portb
- ani 0dfh ; mask with tx bit
- out portb
-;
-; 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.
- in portb
- ori 20h ; mask with tx bit
- out portb
- 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
-
-;
-; sysbye - 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:
- call setbaud
- 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)
-; [Toad Hall]
-
-spdtbl: db 11 ;11 entries
- db 03h,'110$'
- dw t110
- db 04h,'1200$'
- dw t1200
- db 07h,'1200/75$'
- dw t1275
- db 03h,'150$'
- dw t150
- db 04h,'2400$'
- dw t2400
- db 03h,'300$'
- dw t300
- db 04h,'4800$'
- dw t4800
- db 03h,'600$'
- dw t600
- db 02h,'75$'
- dw t75
- db 07h,'75/1200$'
- dw t7512
- db 04h,'9600$'
- dw t9600
-
-sphtbl: db cr,lf,'75 75/1200 110 150 300 600 1200 1200/75'
- db ' 2400 4800 9600$'
-
-
-;
-; This is the system-dependent SET PORT command.
-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:
- mvi c,dconio ;Direct console I/O BDOS call.
- mvi e,0FFH ;Input.
- call BDOS
- ret
-;
-;
-; Output character in E to the console.
-; destroys bc, de, hl
-;
-outcon:
-
- mvi c,dconio ;Console output bdos call.
- call bdos ;Output the char to the console.
- 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:
-;
- push psw
- push b
- push d
- push h
- mov a,e
- lxi h,outm2 ; return address
- push h
- lhld txcall
- pchl ; send to rs232 port
-outm2: pop h
- pop d
- pop b
- pop psw
- ret
-
-
-;
-; get character from modem; return zero if none available.
-; bc, de, hl preserved.
-inpmdm:
- call rsin ; get char if available
- 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=0 if ok, or 0ffh if not.
-lptstat:
- lda pflag
- ret
-
-;
-; outlpt - output character in E to printer
-; console is selected.
-; preserves de.
-outlpt:
- push d ; save DE in either case
- ana a ; if A = 0 do nothing,
- jz outlp1 ; [30] if a=0 do nothing
- mov a,e
- call parout
-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.)
-;
-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 clrsp afterwards)
-delchr:
- lxi d,delstr
- jmp prtstr
-
-
-; 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
-clrtop: lxi d,erascr
- jmp prtstr
-
-
-sysver: db 'Microbee$'
-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,'$' ; 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,'Y$',0 ;Clear to end of screen.
-tk: db esc,'T$',0 ;Clear to end of line.
-
-
-;Microbee software serial port routines
-porta equ 0
-portb equ 2
-
-
-; interrupt vectors
-; We change the Z80 Interrupt register to point to these vectors.
-; Instead of trying to identify a particular Microbee system,
-; we just put vectors here for all systems.
-;
-; known vectors are:
-; 48h : 56k (64k apc) - tested 19-Jun-1990
-; 48k : 64k - tested 01-Sep-1990
-; 50h : dreamdisk (3rd party disk for Microbee)
-; e0h : 128k - tested 19-Jun-1990
-; e0h : 256k - tested 01-Sep-1990
-
- org ($ and 0ff00h) + 100h
-int equ $/256 ; byte for interrupt register
-
- dw inta ; printer vector
- dw intb ; rs232 vector
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
- dw inta
- dw intb
-
-
-; tables for baud rates
-t75: db 124,13 ; full delay
- db 55,7 ; semi delay
- db 168,255 ; txrx delay
- dw trout ; address of subroutine to transmit char
-t7512: db 124,13 ; 75R/1200T
- db 55,7
- db 194,1 ; txout delay
- dw txout
-t110: db 129,9
- db 55,5
- db 5,217
- dw trout
-t150: db 59,7
- db 23,4
- db 2,158
- dw trout
-t300: db 26,4
- db 134,2
- db 3,75
- dw trout
-t600: db 139,2
- db 191,1
- db 2,34
- dw trout
-t1200: db 195,1
- db 90,1
- db 3,13
- dw trout
-t1275: db 195,1 ; 1200R/75T
- db 90,1
- db 124,13
- dw txout
-t2400: db 94,1
- db 40,1
- db 2,3
- dw trout
-t4800: db 44,1
- db 15,1
- db 44,1
- dw txout
-t9600: db 19,1
- db 1,1
- db 19,1
- dw txout
-
-
-; copy table entries to locations used by serial routines
-setbaud:
- lxi h,fulldel
- mvi b,8
-setb2: ldax d
- mov m,a
- inx h
- inx d
- dcr b
- jnz setb2
- ret
-
-
-;transmit character in E
-; destroys all regs
-txout: mvi b,ntotal ;total number of bits to send
- di
- in portb ;c = portb with tx bit zeroed
- ani 0dfh
- mov c,a
- ora a ;carry=0 (start bit)
-txout2: mov a,c ; 4T
- jnc txout4 ;10T skip if space
- ori 20h ; 3T (average) set mark
-txout4: out portb ;11T
- lhld txrxdel ;16T
-txout6: dcr l ;delay
- jnz txout6
- dcr h
- jnz txout6 ; 14*L + 14*H + 3584*(H-1)
- stc ; 4T carry=1 (stop bit)
- mov a,e ; 4T shift next bit to carry
- rar ; 4T
- mov e,a ; 4T
- dcr b ; 4T
- jnz txout2 ;10T
- ;loop = 74T + (delay loop)
- ei
- ret
-
-
-;
-;transmit character in E
-;simultaneous receive char if necessary
-trout: mov a,e
- mvi b,ndata
- lxi h,0
-tro2: rrc ;shift tx char to hl
- mov c,a
- mov a,l
- ral
- mov l,a
- mov a,h
- ral
- mov h,a
- mov a,c ;recover
- dcr b
- jnz tro2
-tro10: mvi b,tqfudge ;adjust char in hl to align with
- ;tx bit of portb
-tro12: stc ; pad out
- mov a,l
- ral
- mov l,a
- mov a,h
- ral
- mov h,a
- dcr b
- jnz tro12
- mvi a,0ffh ;flag to say we are not receiving
- sta trtemp ;save it
- mvi d,tqbit ;total number of qtr bits to send
- in portb ;b = portb with tx bit zeroed
- ani 0dfh
- mov b,a
- mvi e,0 ;we are not receiving yet
-tro14: in portb
- ori 8h ;test CTS
- jz tro14 ;loop till Clear To Send
- out 09h ;Color Wait OFF
- di
- call qbit
- lda trtemp ;are we receiving
- ora a
- jnz tro22 ;skip if not
- in portb ;is last bit a mark?
- ori 10h
- jz tro18 ;skip if mark (don't wait for stop)
- lhld fulldel ;delay to stop bit
-tro16: dcr l
- jnz tro16
- dcr h
- jnz tro16
-tro18: lhld wptr ; check buffer
- xchg
- lhld rptr
- dcx d ; decrement queue pointer
- mov a,d
- ora e
- jnz tro20 ; skip if no queue wrap around
- lxi d,maxque-1 ; wrap around
-tro20: mov a,l ; sub hl,de
- sub e
- mov l,a
- mov a,h
- sbb d
- mov h,a
- ora l ; check for zero
- jz tro22 ; skip if buffer full
- xchg
- shld wptr ; update queue
- lxi d,rqueue
- dad d
- mov m,c ; put char in queue
-tro22: ei
- ret ;ret
-
-
-; routine for quarter bit timing
-; for transmit and simultaneous receive
-; total execution time is 223T + L*14T + H*34T
-qbit: call txrx ;17T + 162T
- lda txrxdel ;13T
-qbit2: dcr a ; 4T
- jnz qbit2 ;10T
- lda txrxdel+1 ;13T
-qbit4: dcr a ; 4T
- nop ; 4T
- nop ; 4T
- nop ; 4T
- nop ; 4T
- nop ; 4T
- jnz qbit4 ;10T
- mov a,d ; 4T Check if still sending or receiving
- ora e ; 4T
- jnz qbit ;10T
- ret
-
-
-;simultaneous transmit/receive
-;do next quarter bit
-; regs: b = portb with tx bit zeroed
-; c = character being received
-; d = number of qtr bits remaining to send
-; e = number of qtr bits remaining to receive (0 if not receiving)
-; hl = character being transmitted
-;this subroutine always executes in 162T (or 163T)
-txrx: mov a,d ; 4T qtr bits remaining to send
- ora a ; 4T
- jz txrx12 ;10T skip if no bits remaining (may be receiving)
- ani 03h ; 7T a complete bit?
- jnz txrx10 ;10T skip if not
- dad h ;11T shift tx bit to bit 5 of h
- mov a,h ; 4T
- ani 20h ; 7T extract tx bit
- ora b ; 4T combine with portb
- out portb ;11T send it
-txrx2: dcr d ; 4T one less qtr bit to send
- ;76T total
-;now receive part
-txrx4: mov a,e ; 4T qtr bits remaining to receive
- ora a ; 4T
- jz txrx16 ;10T skip if not receiving
- ani 3h ; 7T a complete bit?
- jnz txrx14 ;10T skip if not
- in portb ;11T get input
- ani 10h ; 7T extract rx bit
- sui 1 ; 7T bit to carry
- mov a,c ; 4T bit to c
- rar ; 4T
- mov c,a ; 4T
-txrx6: dcr e ; 4T one less qtr bit to receive
-txrx8: ret ;10T
- ;86T total
-
-;come here if transmitting, but not a complete bit
-;delay to match up execution times
-txrx10:
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ori 00h ; 7T
- jmp txrx2 ;10T
-
-;come here if not sending (but still receiving)
-;delay to match up execution times
-txrx12: ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- jmp txrx4 ;10T
-
-;come here if receiving (but not a complete bit)
-;delay to match up execution time
-txrx14: ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ori 00h ; 7T
- jmp txrx6 ;10T
-
-;come here if not receiving
-txrx16: in portb ;11T check if start bit
- ani 10h ; 7T
- jz txrx18 ;10T skip if mark
- mvi e,rqbit ; 7T get quarter bit count for receive
- xra a ; 4T
- sta trtemp ;13T store flag to say we are receiving
- ori a ; 7T delay (should be 6T)
- ret ;10T
-
-txrx18: ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- ora a ; 4T
- jmp txrx8 ;10T
-
-
-
-
-; RS232 input interrupt routine
-; stores received character in queue
-; ;semi delay starts here
-intb: ;20T (approx.) for interrupt
- push psw ;11T
- push b ;11T
- push d ;11T
- push h ;11T
- in portb ;11T
- ani 10h ; 7T test input for start bit
- jz intb16 ;10T skip if no start bit.
- out 09h ;11T
- lhld semidel ;16T half bit delay
-intb2: dcr l ; 4T
- jnz intb2 ;10T inner loop 14T*L
- dcr h ; 4T
- jnz intb2 ;10T outer loop (14*H + 256*14*(H-1))T
- mvi e,8 ; 6T number of data bits
- ;semi delay ends here (125T + delay loop)
- ;full delay starts here
-intb4: lhld fulldel ;16T full bit delay
-intb6: dcr l
- jnz intb6
- dcr h
- jnz intb6 ; 14*L + 14*H + 3584*(H-1)
- in portb ;11T test input
- ani 10h ; 7T
- sui 1 ; 7T input bit to carry
- mov a,c ; 4T
- rar ; 4T
- mov c,a ; 4T and then to C
- dcr e ; 4T bit count
- jnz intb4 ;10T loop till all data bits collected
- ;full delay ends here (67T + delay loop)
- in portb
- ani 10h
- jz intb12 ; skip if mark
- lhld fulldel ; wait for stop bit
-intb10: dcr l
- jnz intb10
- dcr h
- jnz intb10
-intb12: lhld wptr ; check buffer
- xchg
- lhld rptr
- dcx d ; decrement queue pointer
- mov a,d
- ora e
- jnz intb14 ; skip if no queue wrap around
- lxi d,maxque-1 ; wrap around
-intb14: mov a,l ; sub hl,de
- sub e
- mov l,a
- mov a,h
- sbb d
- mov h,a
- ora l ; check for zero
- jz intb16 ; skip if buffer full
- xchg
- shld wptr ; update queue
- lxi d,rqueue
- dad d
- mov m,c ; put char in queue
-intb16: pop h
- pop d
- pop b
- pop psw
- ei
- db 0EDh,4Dh ;reti
-
-;
-; get char from serial port buffer.
-; exit: A=char or Z if no char
-rsin: push d
- push h
- lhld rptr
- xchg
- lhld wptr
- mov a,l ;sub hl,de
- sub e
- mov l,a
- mov a,h
- sbb d
- mov h,a
- ora l ;check for zero
- jnz rsi4 ;get char
-rsi2: pop h
- pop d
- ret
-
-rsi4: push psw
- dcx d ; decrement queue pointer
- mov a,d
- ora e
- jnz rsi6 ; skip if no queue wrap around
- lxi d,maxque-1 ; wrap around
-rsi6: pop psw
- xchg
- shld rptr
- lxi d,rqueue
- dad d
- mov e,m ;get char from queue
- ori 0ffh ;set NZ
- mov a,e
- jmp rsi2
-
-; printer routines
-
-inta: sta ptemp
- mvi a,0
- sta pflag
- lda ptemp
- ei
- db 0EDh,4Dh ;reti
-
-parout: push h
- lxi h,pflag
-par2: db 0CBh,46h ;bit 0,(hl)
- jnz par2
- mvi m,0ffh
- out porta
- pop h
- ret
-
-; data storage
-
-oldint: db 0 ; storage for old i reg
-trtemp: db 0
-ptemp: db 0 ;temp storage used by inta interrupt
-pflag: db 0 ;0ffh if waiting for printer. 00h if ready
-
-;receive queue pointers
-maxque equ 2048 ; receiver queue size
-rptr: dw maxque-1
-wptr: dw maxque-1
-
-;transmit
-ndata equ 8 ; 8 data bits
-nstrt equ 1 ; 1 start bit
-nstop equ 1 ; 1 stop bit
-ntotal equ nstrt+ndata+nstop
-rqbit equ 4*(nstrt+ndata) ;number of quarter bits to receive
-tqbit equ 4*(nstrt+ndata+nstop) ;number of quarter bits to transmit
-tqfudge equ 13-nstrt-ndata
-
-;H=0 or L=0 behave as 256
-;receive delays.
-fulldel: dw 0 ; 3584(H-1) + 14H + 14L + 67 cycles
-semidel: dw 0 ; 3584(H-1) + 14H + 14L + 125 cycles
-;1/4 bit transmit and simultaneous tx/rx delay 34H + 14L + 223 cycles
-;or full bit delay 3584(H-1) + 14H + 14L + 74 cycles
-txrxdel: dw 0 ;
-txcall: dw trout ; address of subroutine to transmit char
-
-; receiver queue
-rqueue: ds maxque
-
-
-ovlend equ $ ; End of overlay
-
-IF lasm
- END
-ENDIF
+IF NOT lasm\r
+.printx * CPXBEE.ASM *\r
+ENDIF ;NOT lasm\r
+; KERMIT - (Celtic for "FREE")\r
+;\r
+; This is the CP/M-80 implementation of the Columbia University\r
+; KERMIT file transfer protocol.\r
+;\r
+; Version 4.09\r
+;\r
+; Copyright June 1981,1982,1983,1984,1985\r
+; Columbia University\r
+;\r
+; Originally written by Bill Catchings of the Columbia University Center for\r
+; Computing Activities, 612 W. 115th St., New York, NY 10025.\r
+;\r
+; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,\r
+; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many\r
+; others.\r
+;\r
+;\r
+;\r
+; revision history:\r
+;\r
+; edit 1, 1st September 1990 \r
+; Original version by Russell Lang <rjl@monu1.cc.monash.edu.au>\r
+; The 'microbee' is designed and manufactured in Australia\r
+; by Microbee Systems Ltd (previously Applied Technology).\r
+; The microprocessor is a Z80 at 3.375MHz.\r
+; The video screen is memory mapped from 0F000h to 0F7FFh, \r
+; with Programmable Characters 80-FF from 0F800h to 0FFFFh. \r
+; The serial and parallel ports are implemented using a Z80 PIO.\r
+; The early model microbees were ROM-Basic computers with up\r
+; to 32k of battery backed RAM. Later models dropped the\r
+; ROM-Basic and added disk drives and CP/M. The disk systems\r
+; include the 56k (64k) APC (5.25" drives), 64k Computer-In-A-Book \r
+; (3.5"), 128k Dynamic (5.25" or 3.5"), 256TC (3.5").\r
+; \r
+; This version of kermit was developed on a 56k APC.\r
+; It has been tested on 56k, 64k, 128k and 256k Microbees.\r
+;\r
+; The serial port is implemented in software NOT hardware.\r
+; A special transmit routine allows simultaneous receiving\r
+; for all speeds except 75/1200, 1200/75, 4800, 9600.\r
+; The receive routine is interrupt driven with a 2 kbyte buffer.\r
+; The 9600 bit/s speed is marginal on receive - if the transmitter\r
+; is slightly fast (more than about 1%), the serial routine will \r
+; not have enough time to put the character in the buffer before \r
+; the next character arrives.\r
+\r
+\r
+;\r
+; *** MAIN CODE START ***\r
+;\r
+;\r
+; Keep module name, edit number, and last revision date in memory.\r
+\r
+sysedt: db 'CPXSYS.ASM (35) 01-Dec-86$'\r
+family: db 'CPXBEE.ASM (1) 01-Sep-90$'\r
+\r
+\r
+; Assembly time message announcing which version we're building\r
+\r
+.printx * Assembling Microbee Kermit-80 *\r
+\r
+z80 EQU TRUE ; They all use Z80s\r
+\r
+defesc EQU ']'-100O ;The default escape character for Microbee\r
+\r
+vtval EQU 0 ; use default emulation which is adm3a superset\r
+\r
+;\r
+sysxin: ;continuation of system initialisation code\r
+ ; set up baud rate\r
+ lxi h,t300\r
+ shld speed\r
+ xchg\r
+ call setbaud\r
+ ; change the interrupt vector so that we intercept rs232 input\r
+ db 0EDh,57h ;ld a,i ;get old interrupt reg\r
+ sta oldint\r
+ mvi a,int ;new value\r
+ db 0EDh,47h ;ld i,a\r
+ ret ; return from system-dependent routine\r
+\r
+\r
+;\r
+; sysexit - System-dependent termination processing\r
+; if we've changed anything, this is our last\r
+; chance to put it back.\r
+;\r
+sysexit:\r
+ lda oldint ;restore old interrupt reg\r
+ db 0EDh,47h ;ld i,a\r
+ ret\r
+\r
+;\r
+; syscon - System-dependent processing for start\r
+; of CONNECT command.\r
+;\r
+syscon:\r
+ lxi d,conmsg\r
+ call prtstr\r
+ ret\r
+\r
+conmsg: ; Messages printed when entering transparent (CONNECT) mode:\r
+ db cr,lf,'$'\r
+;\r
+; syscls - system-dependent close routine\r
+; called when exiting transparent session.\r
+;\r
+syscls:\r
+ ret\r
+;\r
+; sysinh - help for system-dependent special functions.\r
+; called in response to <escape>?, after listing\r
+; all the system-independent escape sequences.\r
+;\r
+sysinh:\r
+ lxi d,inhlps ; we got options...\r
+ call prtstr ; print them.\r
+ ret\r
+\r
+\r
+; additional, system-dependent help for transparent mode\r
+; (two-character escape sequences)\r
+inhlps:\r
+ db cr,lf,'B Transmit a BREAK (0.3s)'\r
+ db cr,lf,'L Transmit a LONG BREAK (1.8s)'\r
+ db cr,lf,'W Wipe screen clear'\r
+ db '$'\r
+\r
+; sysint - system dependent special functions\r
+; called when transparent escape character has been typed;\r
+; the second character of the sequence is in A (and in B).\r
+; returns:-\r
+; non-skip: sequence has been processed\r
+; skip : sequence was not recognized\r
+;\r
+sysint: ani 137O ; convert lower case to upper, for testing...\r
+ cpi 'B' ; send break ?\r
+ jz sendbr ; then jump to send break routine\r
+ cpi 'L' ; long break ?\r
+ jz longbr ; then jump to long break routine\r
+ cpi 'W' ; clear screen ?\r
+ jz clrtop ; then jump to clear screen routine\r
+ jmp rskp ; take skip return - command not recognized.\r
+\r
+;\r
+; Break routines\r
+;\r
+longbr:\r
+ mvi e,180 ; time for long break is 1800 ms\r
+ jmp setbit\r
+\r
+sendbr:\r
+ mvi e,30 ; time for break is 300 ms\r
+\r
+setbit: \r
+ in portb\r
+ ani 0dfh ; mask with tx bit\r
+ out portb\r
+;\r
+; Now, delay for duration of hangup or break\r
+ mov a,e ; delay count\r
+ call delay\r
+;\r
+; Time's up. Put transmitter back in normal state and return.\r
+ in portb\r
+ ori 20h ; mask with tx bit\r
+ out portb\r
+ ret ; done.\r
+\r
+; sysflt - system-dependent filter\r
+; called with character in E.\r
+; if this character should not be printed, return with A = zero.\r
+; preserves bc, de, hl.\r
+; note: <xon>,<xoff>,<del>, and <nul> are always discarded.\r
+;\r
+sysflt:\r
+ mov a,e ; get character for testing\r
+ ret\r
+\r
+;\r
+; sysbye - system-dependent processing for BYE command.\r
+;\r
+sysbye:\r
+ ret\r
+\r
+;\r
+; This is the system-dependent command to change the baud rate.\r
+; DE contains the two-byte value from the baud rate table; this\r
+; value is also stored in 'speed'.\r
+;\r
+sysspd:\r
+ call setbaud\r
+ ret\r
+\r
+;\r
+; Speed tables\r
+; (Note that speed tables MUST be in alphabetical order for later\r
+; lookup procedures, and must begin with a value showing the total\r
+; number of entries. The speed help tables are just for us poor\r
+; humans.\r
+\r
+; db string length,string,divisor (2 identical bytes or 1 word)\r
+; [Toad Hall]\r
+\r
+spdtbl: db 11 ;11 entries\r
+ db 03h,'110$'\r
+ dw t110\r
+ db 04h,'1200$'\r
+ dw t1200\r
+ db 07h,'1200/75$'\r
+ dw t1275\r
+ db 03h,'150$'\r
+ dw t150\r
+ db 04h,'2400$'\r
+ dw t2400\r
+ db 03h,'300$'\r
+ dw t300\r
+ db 04h,'4800$'\r
+ dw t4800\r
+ db 03h,'600$'\r
+ dw t600\r
+ db 02h,'75$'\r
+ dw t75\r
+ db 07h,'75/1200$'\r
+ dw t7512\r
+ db 04h,'9600$'\r
+ dw t9600\r
+\r
+sphtbl: db cr,lf,'75 75/1200 110 150 300 600 1200 1200/75'\r
+ db ' 2400 4800 9600$'\r
+\r
+\r
+;\r
+; This is the system-dependent SET PORT command.\r
+sysprt:\r
+ ret\r
+\r
+prttbl equ 0 ; SET PORT is not supported\r
+prhtbl equ 0\r
+\r
+\r
+;\r
+; selmdm - select modem port\r
+; selcon - select console port\r
+; selmdm is called before using inpmdm or outmdm;\r
+; selcon is called before using inpcon or outcon.\r
+; preserves BC, DE, HL.\r
+;\r
+selmdm:\r
+selcon:\r
+ ret\r
+;\r
+; Get character from console, or return zero.\r
+; result is returned in A. destroys bc, de, hl.\r
+;\r
+inpcon:\r
+ mvi c,dconio ;Direct console I/O BDOS call.\r
+ mvi e,0FFH ;Input.\r
+ call BDOS\r
+ ret\r
+;\r
+;\r
+; Output character in E to the console.\r
+; destroys bc, de, hl\r
+;\r
+outcon:\r
+\r
+ mvi c,dconio ;Console output bdos call.\r
+ call bdos ;Output the char to the console.\r
+ ret\r
+\r
+\r
+\r
+;\r
+;\r
+; outmdm - output a char from E to the modem.\r
+; the parity bit has been set as necessary.\r
+; returns nonskip; bc, de, hl preserved.\r
+outmdm:\r
+;\r
+ push psw\r
+ push b\r
+ push d\r
+ push h\r
+ mov a,e\r
+ lxi h,outm2 ; return address\r
+ push h\r
+ lhld txcall\r
+ pchl ; send to rs232 port\r
+outm2: pop h\r
+ pop d\r
+ pop b\r
+ pop psw\r
+ ret\r
+\r
+\r
+;\r
+; get character from modem; return zero if none available.\r
+; bc, de, hl preserved.\r
+inpmdm:\r
+ call rsin ; get char if available\r
+ ret ; return with character in A\r
+\r
+\r
+;\r
+; flsmdm - flush comm line.\r
+; Modem is selected.\r
+; Currently, just gets characters until none are available.\r
+flsmdm: call inpmdm ; Try to get a character\r
+ ora a ; Got one?\r
+ jnz flsmdm ; If so, try for another\r
+ ret ; Receiver is drained. Return.\r
+\r
+;\r
+; lptstat - get the printer status. Return a=0 if ok, or 0ffh if not.\r
+lptstat:\r
+ lda pflag\r
+ ret\r
+\r
+;\r
+; outlpt - output character in E to printer\r
+; console is selected.\r
+; preserves de.\r
+outlpt:\r
+ push d ; save DE in either case\r
+ ana a ; if A = 0 do nothing,\r
+ jz outlp1 ; [30] if a=0 do nothing\r
+ mov a,e\r
+ call parout\r
+outlp1: pop d ; restore saved register pair\r
+ ret\r
+\r
+\r
+;\r
+;\r
+; Screen manipulation routines\r
+; csrpos - move to row B, column C\r
+;\r
+; csrpos for terminals that use a leadin sequence followed\r
+; by (row + 31.) and (column + 31.)\r
+;\r
+csrpos: push b ; save coordinates\r
+ lxi d,curldn ; get cursor leadin sequence\r
+ call prtstr ; print it\r
+ pop h ; restore coordinates\r
+ mov a,h ; get row\r
+ adi (' '-1) ; space is row one\r
+ mov e,a\r
+ push h\r
+ call outcon ; output row\r
+ pop h\r
+ mov a,l ; get column\r
+ adi (' '-1) ; space is column one\r
+ mov e,a\r
+ jmp outcon ; output it and return\r
+\r
+;\r
+; delchr - make delete look like a backspace. Unless delete is a\r
+; printing character, we just need to print a backspace\r
+; (we'll output clrsp afterwards)\r
+delchr:\r
+ lxi d,delstr\r
+ jmp prtstr\r
+\r
+\r
+; erase the character at the current cursor position\r
+clrspc: mvi e,' '\r
+ call outcon\r
+ mvi e,bs ;get a backspace\r
+ jmp outcon\r
+\r
+; erase the current line\r
+clrlin: lxi d,eralin\r
+ jmp prtstr\r
+\r
+; erase the whole screen, and go home\r
+clrtop: lxi d,erascr\r
+ jmp prtstr\r
+\r
+\r
+sysver: db 'Microbee$'\r
+outlin: db 1AH,cr,lf,tab,'$' ;(Clear screen, home cursor)\r
+erascr: db 1AH,'$' ;Clear screen and go home.\r
+eralin: db cr,esc,'T$' ;Clear line.\r
+delstr: db bs,'$' ; Adjust for delete\r
+curldn: db esc,'=$' ;Cursor lead-in\r
+ttab: ;Table start location.\r
+ta: db ('K'-100O),'$',0,0 ;Cursor up.\r
+tb: db 12O,'$',0,0 ;Cursor down.\r
+tc: db ('L'-100O),'$',0,0 ;Cursor right.\r
+td: db bs,'$',0,0 ;Cursor left.\r
+te: db subt,'$',0,0 ;Clear screen.\r
+tf: db '$',0,0,0 ;(can't) Enter graphics mode\r
+tg: db '$',0,0,0 ;(can't) Exit graphics mode\r
+th: db ('^'-100O),'$',0,0 ;Cursor home.\r
+ti: db ('K'-100O),'$',0,0 ;Reverse linefeed.\r
+tj: db esc,'Y$',0 ;Clear to end of screen.\r
+tk: db esc,'T$',0 ;Clear to end of line.\r
+\r
+\r
+;Microbee software serial port routines\r
+porta equ 0\r
+portb equ 2\r
+\r
+\r
+; interrupt vectors\r
+; We change the Z80 Interrupt register to point to these vectors.\r
+; Instead of trying to identify a particular Microbee system, \r
+; we just put vectors here for all systems.\r
+;\r
+; known vectors are:\r
+; 48h : 56k (64k apc) - tested 19-Jun-1990\r
+; 48k : 64k - tested 01-Sep-1990\r
+; 50h : dreamdisk (3rd party disk for Microbee)\r
+; e0h : 128k - tested 19-Jun-1990\r
+; e0h : 256k - tested 01-Sep-1990\r
+\r
+ org ($ and 0ff00h) + 100h\r
+int equ $/256 ; byte for interrupt register\r
+\r
+ dw inta ; printer vector\r
+ dw intb ; rs232 vector\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ dw inta\r
+ dw intb\r
+ \r
+\r
+; tables for baud rates\r
+t75: db 124,13 ; full delay\r
+ db 55,7 ; semi delay\r
+ db 168,255 ; txrx delay\r
+ dw trout ; address of subroutine to transmit char\r
+t7512: db 124,13 ; 75R/1200T\r
+ db 55,7\r
+ db 194,1 ; txout delay\r
+ dw txout\r
+t110: db 129,9\r
+ db 55,5\r
+ db 5,217 \r
+ dw trout\r
+t150: db 59,7\r
+ db 23,4\r
+ db 2,158\r
+ dw trout\r
+t300: db 26,4\r
+ db 134,2\r
+ db 3,75\r
+ dw trout\r
+t600: db 139,2\r
+ db 191,1\r
+ db 2,34\r
+ dw trout\r
+t1200: db 195,1\r
+ db 90,1\r
+ db 3,13\r
+ dw trout\r
+t1275: db 195,1 ; 1200R/75T\r
+ db 90,1\r
+ db 124,13\r
+ dw txout\r
+t2400: db 94,1\r
+ db 40,1\r
+ db 2,3\r
+ dw trout\r
+t4800: db 44,1\r
+ db 15,1\r
+ db 44,1\r
+ dw txout\r
+t9600: db 19,1\r
+ db 1,1\r
+ db 19,1\r
+ dw txout\r
+\r
+\r
+; copy table entries to locations used by serial routines\r
+setbaud:\r
+ lxi h,fulldel\r
+ mvi b,8\r
+setb2: ldax d\r
+ mov m,a\r
+ inx h\r
+ inx d\r
+ dcr b\r
+ jnz setb2\r
+ ret\r
+\r
+\r
+;transmit character in E\r
+; destroys all regs\r
+txout: mvi b,ntotal ;total number of bits to send\r
+ di\r
+ in portb ;c = portb with tx bit zeroed\r
+ ani 0dfh\r
+ mov c,a\r
+ ora a ;carry=0 (start bit)\r
+txout2: mov a,c ; 4T\r
+ jnc txout4 ;10T skip if space\r
+ ori 20h ; 3T (average) set mark\r
+txout4: out portb ;11T\r
+ lhld txrxdel ;16T\r
+txout6: dcr l ;delay\r
+ jnz txout6\r
+ dcr h\r
+ jnz txout6 ; 14*L + 14*H + 3584*(H-1)\r
+ stc ; 4T carry=1 (stop bit)\r
+ mov a,e ; 4T shift next bit to carry\r
+ rar ; 4T\r
+ mov e,a ; 4T\r
+ dcr b ; 4T\r
+ jnz txout2 ;10T\r
+ ;loop = 74T + (delay loop)\r
+ ei\r
+ ret\r
+\r
+ \r
+;\r
+;transmit character in E\r
+;simultaneous receive char if necessary\r
+trout: mov a,e\r
+ mvi b,ndata\r
+ lxi h,0\r
+tro2: rrc ;shift tx char to hl\r
+ mov c,a\r
+ mov a,l\r
+ ral\r
+ mov l,a\r
+ mov a,h\r
+ ral\r
+ mov h,a\r
+ mov a,c ;recover\r
+ dcr b\r
+ jnz tro2\r
+tro10: mvi b,tqfudge ;adjust char in hl to align with\r
+ ;tx bit of portb\r
+tro12: stc ; pad out\r
+ mov a,l\r
+ ral\r
+ mov l,a\r
+ mov a,h\r
+ ral\r
+ mov h,a\r
+ dcr b\r
+ jnz tro12\r
+ mvi a,0ffh ;flag to say we are not receiving\r
+ sta trtemp ;save it\r
+ mvi d,tqbit ;total number of qtr bits to send\r
+ in portb ;b = portb with tx bit zeroed\r
+ ani 0dfh\r
+ mov b,a\r
+ mvi e,0 ;we are not receiving yet\r
+tro14: in portb\r
+ ori 8h ;test CTS\r
+ jz tro14 ;loop till Clear To Send\r
+ out 09h ;Color Wait OFF\r
+ di\r
+ call qbit\r
+ lda trtemp ;are we receiving\r
+ ora a\r
+ jnz tro22 ;skip if not\r
+ in portb ;is last bit a mark?\r
+ ori 10h\r
+ jz tro18 ;skip if mark (don't wait for stop)\r
+ lhld fulldel ;delay to stop bit\r
+tro16: dcr l\r
+ jnz tro16\r
+ dcr h\r
+ jnz tro16\r
+tro18: lhld wptr ; check buffer\r
+ xchg\r
+ lhld rptr\r
+ dcx d ; decrement queue pointer\r
+ mov a,d\r
+ ora e\r
+ jnz tro20 ; skip if no queue wrap around\r
+ lxi d,maxque-1 ; wrap around\r
+tro20: mov a,l ; sub hl,de\r
+ sub e\r
+ mov l,a\r
+ mov a,h\r
+ sbb d\r
+ mov h,a\r
+ ora l ; check for zero\r
+ jz tro22 ; skip if buffer full\r
+ xchg\r
+ shld wptr ; update queue\r
+ lxi d,rqueue\r
+ dad d\r
+ mov m,c ; put char in queue\r
+tro22: ei\r
+ ret ;ret\r
+\r
+\r
+; routine for quarter bit timing\r
+; for transmit and simultaneous receive\r
+; total execution time is 223T + L*14T + H*34T\r
+qbit: call txrx ;17T + 162T\r
+ lda txrxdel ;13T\r
+qbit2: dcr a ; 4T\r
+ jnz qbit2 ;10T\r
+ lda txrxdel+1 ;13T\r
+qbit4: dcr a ; 4T\r
+ nop ; 4T\r
+ nop ; 4T\r
+ nop ; 4T\r
+ nop ; 4T\r
+ nop ; 4T\r
+ jnz qbit4 ;10T\r
+ mov a,d ; 4T Check if still sending or receiving\r
+ ora e ; 4T\r
+ jnz qbit ;10T\r
+ ret\r
+\r
+\r
+;simultaneous transmit/receive\r
+;do next quarter bit\r
+; regs: b = portb with tx bit zeroed\r
+; c = character being received\r
+; d = number of qtr bits remaining to send\r
+; e = number of qtr bits remaining to receive (0 if not receiving)\r
+; hl = character being transmitted\r
+;this subroutine always executes in 162T (or 163T)\r
+txrx: mov a,d ; 4T qtr bits remaining to send\r
+ ora a ; 4T\r
+ jz txrx12 ;10T skip if no bits remaining (may be receiving)\r
+ ani 03h ; 7T a complete bit?\r
+ jnz txrx10 ;10T skip if not\r
+ dad h ;11T shift tx bit to bit 5 of h\r
+ mov a,h ; 4T\r
+ ani 20h ; 7T extract tx bit\r
+ ora b ; 4T combine with portb\r
+ out portb ;11T send it\r
+txrx2: dcr d ; 4T one less qtr bit to send\r
+ ;76T total\r
+;now receive part\r
+txrx4: mov a,e ; 4T qtr bits remaining to receive\r
+ ora a ; 4T\r
+ jz txrx16 ;10T skip if not receiving\r
+ ani 3h ; 7T a complete bit?\r
+ jnz txrx14 ;10T skip if not\r
+ in portb ;11T get input\r
+ ani 10h ; 7T extract rx bit\r
+ sui 1 ; 7T bit to carry\r
+ mov a,c ; 4T bit to c\r
+ rar ; 4T\r
+ mov c,a ; 4T\r
+txrx6: dcr e ; 4T one less qtr bit to receive\r
+txrx8: ret ;10T\r
+ ;86T total\r
+\r
+;come here if transmitting, but not a complete bit\r
+;delay to match up execution times\r
+txrx10:\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ori 00h ; 7T\r
+ jmp txrx2 ;10T\r
+\r
+;come here if not sending (but still receiving)\r
+;delay to match up execution times\r
+txrx12: ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ jmp txrx4 ;10T\r
+\r
+;come here if receiving (but not a complete bit)\r
+;delay to match up execution time\r
+txrx14: ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ori 00h ; 7T\r
+ jmp txrx6 ;10T\r
+\r
+;come here if not receiving\r
+txrx16: in portb ;11T check if start bit\r
+ ani 10h ; 7T\r
+ jz txrx18 ;10T skip if mark\r
+ mvi e,rqbit ; 7T get quarter bit count for receive\r
+ xra a ; 4T\r
+ sta trtemp ;13T store flag to say we are receiving\r
+ ori a ; 7T delay (should be 6T)\r
+ ret ;10T\r
+ \r
+txrx18: ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ ora a ; 4T\r
+ jmp txrx8 ;10T\r
+\r
+\r
+\r
+\r
+; RS232 input interrupt routine\r
+; stores received character in queue\r
+; ;semi delay starts here\r
+intb: ;20T (approx.) for interrupt\r
+ push psw ;11T\r
+ push b ;11T\r
+ push d ;11T\r
+ push h ;11T\r
+ in portb ;11T\r
+ ani 10h ; 7T test input for start bit\r
+ jz intb16 ;10T skip if no start bit.\r
+ out 09h ;11T\r
+ lhld semidel ;16T half bit delay\r
+intb2: dcr l ; 4T\r
+ jnz intb2 ;10T inner loop 14T*L\r
+ dcr h ; 4T\r
+ jnz intb2 ;10T outer loop (14*H + 256*14*(H-1))T\r
+ mvi e,8 ; 6T number of data bits\r
+ ;semi delay ends here (125T + delay loop)\r
+ ;full delay starts here\r
+intb4: lhld fulldel ;16T full bit delay\r
+intb6: dcr l\r
+ jnz intb6\r
+ dcr h\r
+ jnz intb6 ; 14*L + 14*H + 3584*(H-1)\r
+ in portb ;11T test input\r
+ ani 10h ; 7T\r
+ sui 1 ; 7T input bit to carry\r
+ mov a,c ; 4T\r
+ rar ; 4T\r
+ mov c,a ; 4T and then to C\r
+ dcr e ; 4T bit count\r
+ jnz intb4 ;10T loop till all data bits collected\r
+ ;full delay ends here (67T + delay loop)\r
+ in portb\r
+ ani 10h\r
+ jz intb12 ; skip if mark\r
+ lhld fulldel ; wait for stop bit\r
+intb10: dcr l\r
+ jnz intb10\r
+ dcr h\r
+ jnz intb10\r
+intb12: lhld wptr ; check buffer\r
+ xchg\r
+ lhld rptr\r
+ dcx d ; decrement queue pointer\r
+ mov a,d\r
+ ora e\r
+ jnz intb14 ; skip if no queue wrap around\r
+ lxi d,maxque-1 ; wrap around\r
+intb14: mov a,l ; sub hl,de\r
+ sub e\r
+ mov l,a\r
+ mov a,h\r
+ sbb d\r
+ mov h,a\r
+ ora l ; check for zero\r
+ jz intb16 ; skip if buffer full\r
+ xchg\r
+ shld wptr ; update queue\r
+ lxi d,rqueue\r
+ dad d\r
+ mov m,c ; put char in queue\r
+intb16: pop h\r
+ pop d\r
+ pop b\r
+ pop psw\r
+ ei\r
+ db 0EDh,4Dh ;reti\r
+\r
+;\r
+; get char from serial port buffer.\r
+; exit: A=char or Z if no char\r
+rsin: push d\r
+ push h\r
+ lhld rptr\r
+ xchg\r
+ lhld wptr\r
+ mov a,l ;sub hl,de\r
+ sub e\r
+ mov l,a\r
+ mov a,h\r
+ sbb d\r
+ mov h,a\r
+ ora l ;check for zero\r
+ jnz rsi4 ;get char\r
+rsi2: pop h\r
+ pop d\r
+ ret\r
+\r
+rsi4: push psw\r
+ dcx d ; decrement queue pointer\r
+ mov a,d\r
+ ora e\r
+ jnz rsi6 ; skip if no queue wrap around\r
+ lxi d,maxque-1 ; wrap around\r
+rsi6: pop psw\r
+ xchg\r
+ shld rptr\r
+ lxi d,rqueue\r
+ dad d\r
+ mov e,m ;get char from queue\r
+ ori 0ffh ;set NZ\r
+ mov a,e\r
+ jmp rsi2\r
+\r
+; printer routines\r
+\r
+inta: sta ptemp\r
+ mvi a,0\r
+ sta pflag\r
+ lda ptemp\r
+ ei\r
+ db 0EDh,4Dh ;reti\r
+\r
+parout: push h\r
+ lxi h,pflag\r
+par2: db 0CBh,46h ;bit 0,(hl)\r
+ jnz par2\r
+ mvi m,0ffh\r
+ out porta\r
+ pop h\r
+ ret\r
+\r
+; data storage\r
+\r
+oldint: db 0 ; storage for old i reg\r
+trtemp: db 0\r
+ptemp: db 0 ;temp storage used by inta interrupt\r
+pflag: db 0 ;0ffh if waiting for printer. 00h if ready\r
+\r
+;receive queue pointers\r
+maxque equ 2048 ; receiver queue size\r
+rptr: dw maxque-1\r
+wptr: dw maxque-1\r
+\r
+;transmit\r
+ndata equ 8 ; 8 data bits\r
+nstrt equ 1 ; 1 start bit\r
+nstop equ 1 ; 1 stop bit\r
+ntotal equ nstrt+ndata+nstop\r
+rqbit equ 4*(nstrt+ndata) ;number of quarter bits to receive\r
+tqbit equ 4*(nstrt+ndata+nstop) ;number of quarter bits to transmit\r
+tqfudge equ 13-nstrt-ndata\r
+\r
+;H=0 or L=0 behave as 256\r
+;receive delays.\r
+fulldel: dw 0 ; 3584(H-1) + 14H + 14L + 67 cycles\r
+semidel: dw 0 ; 3584(H-1) + 14H + 14L + 125 cycles\r
+;1/4 bit transmit and simultaneous tx/rx delay 34H + 14L + 223 cycles\r
+;or full bit delay 3584(H-1) + 14H + 14L + 74 cycles\r
+txrxdel: dw 0 ;\r
+txcall: dw trout ; address of subroutine to transmit char\r
+\r
+; receiver queue\r
+rqueue: ds maxque\r
+\r
+\r
+ovlend equ $ ; End of overlay\r
+\r
+IF lasm\r
+ END\r
+ENDIF\r