4 ; KERMIT - (Celtic for "FREE")
6 ; This is the CP/M-80 implementation of the Columbia University
7 ; KERMIT file transfer protocol.
11 ; Copyright June 1981,1982,1983,1984,1985
14 ; Originally written by Bill Catchings of the Columbia University Center for
15 ; Computing Activities, 612 W. 115th St., New York, NY 10025.
17 ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,
18 ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many
25 ; edit 1, 1st September 1990
26 ; Original version by Russell Lang <rjl@monu1.cc.monash.edu.au>
27 ; The 'microbee' is designed and manufactured in Australia
28 ; by Microbee Systems Ltd (previously Applied Technology).
29 ; The microprocessor is a Z80 at 3.375MHz.
30 ; The video screen is memory mapped from 0F000h to 0F7FFh,
31 ; with Programmable Characters 80-FF from 0F800h to 0FFFFh.
32 ; The serial and parallel ports are implemented using a Z80 PIO.
33 ; The early model microbees were ROM-Basic computers with up
34 ; to 32k of battery backed RAM. Later models dropped the
35 ; ROM-Basic and added disk drives and CP/M. The disk systems
36 ; include the 56k (64k) APC (5.25" drives), 64k Computer-In-A-Book
37 ; (3.5"), 128k Dynamic (5.25" or 3.5"), 256TC (3.5").
39 ; This version of kermit was developed on a 56k APC.
40 ; It has been tested on 56k, 64k, 128k and 256k Microbees.
42 ; The serial port is implemented in software NOT hardware.
43 ; A special transmit routine allows simultaneous receiving
44 ; for all speeds except 75/1200, 1200/75, 4800, 9600.
45 ; The receive routine is interrupt driven with a 2 kbyte buffer.
46 ; The 9600 bit/s speed is marginal on receive - if the transmitter
47 ; is slightly fast (more than about 1%), the serial routine will
48 ; not have enough time to put the character in the buffer before
49 ; the next character arrives.
53 ; *** MAIN CODE START ***
56 ; Keep module name, edit number, and last revision date in memory.
58 sysedt: db 'CPXSYS.ASM (35) 01-Dec-86$'
59 family: db 'CPXBEE.ASM (1) 01-Sep-90$'
62 ; Assembly time message announcing which version we're building
64 .printx * Assembling Microbee Kermit-80 *
66 z80 EQU TRUE ; They all use Z80s
68 defesc EQU ']'-100O ;The default escape character for Microbee
70 vtval EQU 0 ; use default emulation which is adm3a superset
73 sysxin: ;continuation of system initialisation code
79 ; change the interrupt vector so that we intercept rs232 input
80 db 0EDh,57h ;ld a,i ;get old interrupt reg
84 ret ; return from system-dependent routine
88 ; sysexit - System-dependent termination processing
89 ; if we've changed anything, this is our last
90 ; chance to put it back.
93 lda oldint ;restore old interrupt reg
98 ; syscon - System-dependent processing for start
106 conmsg: ; Messages printed when entering transparent (CONNECT) mode:
109 ; syscls - system-dependent close routine
110 ; called when exiting transparent session.
115 ; sysinh - help for system-dependent special functions.
116 ; called in response to <escape>?, after listing
117 ; all the system-independent escape sequences.
120 lxi d,inhlps ; we got options...
121 call prtstr ; print them.
125 ; additional, system-dependent help for transparent mode
126 ; (two-character escape sequences)
128 db cr,lf,'B Transmit a BREAK (0.3s)'
129 db cr,lf,'L Transmit a LONG BREAK (1.8s)'
130 db cr,lf,'W Wipe screen clear'
133 ; sysint - system dependent special functions
134 ; called when transparent escape character has been typed;
135 ; the second character of the sequence is in A (and in B).
137 ; non-skip: sequence has been processed
138 ; skip : sequence was not recognized
140 sysint: ani 137O ; convert lower case to upper, for testing...
141 cpi 'B' ; send break ?
142 jz sendbr ; then jump to send break routine
143 cpi 'L' ; long break ?
144 jz longbr ; then jump to long break routine
145 cpi 'W' ; clear screen ?
146 jz clrtop ; then jump to clear screen routine
147 jmp rskp ; take skip return - command not recognized.
153 mvi e,180 ; time for long break is 1800 ms
157 mvi e,30 ; time for break is 300 ms
161 ani 0dfh ; mask with tx bit
164 ; Now, delay for duration of hangup or break
165 mov a,e ; delay count
168 ; Time's up. Put transmitter back in normal state and return.
170 ori 20h ; mask with tx bit
174 ; sysflt - system-dependent filter
175 ; called with character in E.
176 ; if this character should not be printed, return with A = zero.
177 ; preserves bc, de, hl.
178 ; note: <xon>,<xoff>,<del>, and <nul> are always discarded.
181 mov a,e ; get character for testing
185 ; sysbye - system-dependent processing for BYE command.
191 ; This is the system-dependent command to change the baud rate.
192 ; DE contains the two-byte value from the baud rate table; this
193 ; value is also stored in 'speed'.
201 ; (Note that speed tables MUST be in alphabetical order for later
202 ; lookup procedures, and must begin with a value showing the total
203 ; number of entries. The speed help tables are just for us poor
206 ; db string length,string,divisor (2 identical bytes or 1 word)
209 spdtbl: db 11 ;11 entries
233 sphtbl: db cr,lf,'75 75/1200 110 150 300 600 1200 1200/75'
234 db ' 2400 4800 9600$'
238 ; This is the system-dependent SET PORT command.
242 prttbl equ 0 ; SET PORT is not supported
247 ; selmdm - select modem port
248 ; selcon - select console port
249 ; selmdm is called before using inpmdm or outmdm;
250 ; selcon is called before using inpcon or outcon.
251 ; preserves BC, DE, HL.
257 ; Get character from console, or return zero.
258 ; result is returned in A. destroys bc, de, hl.
261 mvi c,dconio ;Direct console I/O BDOS call.
267 ; Output character in E to the console.
268 ; destroys bc, de, hl
272 mvi c,dconio ;Console output bdos call.
273 call bdos ;Output the char to the console.
280 ; outmdm - output a char from E to the modem.
281 ; the parity bit has been set as necessary.
282 ; returns nonskip; bc, de, hl preserved.
290 lxi h,outm2 ; return address
293 pchl ; send to rs232 port
302 ; get character from modem; return zero if none available.
303 ; bc, de, hl preserved.
305 call rsin ; get char if available
306 ret ; return with character in A
310 ; flsmdm - flush comm line.
312 ; Currently, just gets characters until none are available.
313 flsmdm: call inpmdm ; Try to get a character
315 jnz flsmdm ; If so, try for another
316 ret ; Receiver is drained. Return.
319 ; lptstat - get the printer status. Return a=0 if ok, or 0ffh if not.
325 ; outlpt - output character in E to printer
326 ; console is selected.
329 push d ; save DE in either case
330 ana a ; if A = 0 do nothing,
331 jz outlp1 ; [30] if a=0 do nothing
334 outlp1: pop d ; restore saved register pair
340 ; Screen manipulation routines
341 ; csrpos - move to row B, column C
343 ; csrpos for terminals that use a leadin sequence followed
344 ; by (row + 31.) and (column + 31.)
346 csrpos: push b ; save coordinates
347 lxi d,curldn ; get cursor leadin sequence
348 call prtstr ; print it
349 pop h ; restore coordinates
351 adi (' '-1) ; space is row one
354 call outcon ; output row
357 adi (' '-1) ; space is column one
359 jmp outcon ; output it and return
362 ; delchr - make delete look like a backspace. Unless delete is a
363 ; printing character, we just need to print a backspace
364 ; (we'll output clrsp afterwards)
370 ; erase the character at the current cursor position
373 mvi e,bs ;get a backspace
376 ; erase the current line
380 ; erase the whole screen, and go home
385 sysver: db 'Microbee$'
386 outlin: db 1AH,cr,lf,tab,'$' ;(Clear screen, home cursor)
387 erascr: db 1AH,'$' ;Clear screen and go home.
388 eralin: db cr,esc,'T$' ;Clear line.
389 delstr: db bs,'$' ; Adjust for delete
390 curldn: db esc,'=$' ;Cursor lead-in
391 ttab: ;Table start location.
392 ta: db ('K'-100O),'$',0,0 ;Cursor up.
393 tb: db 12O,'$',0,0 ;Cursor down.
394 tc: db ('L'-100O),'$',0,0 ;Cursor right.
395 td: db bs,'$',0,0 ;Cursor left.
396 te: db subt,'$',0,0 ;Clear screen.
397 tf: db '$',0,0,0 ;(can't) Enter graphics mode
398 tg: db '$',0,0,0 ;(can't) Exit graphics mode
399 th: db ('^'-100O),'$',0,0 ;Cursor home.
400 ti: db ('K'-100O),'$',0,0 ;Reverse linefeed.
401 tj: db esc,'Y$',0 ;Clear to end of screen.
402 tk: db esc,'T$',0 ;Clear to end of line.
405 ;Microbee software serial port routines
411 ; We change the Z80 Interrupt register to point to these vectors.
412 ; Instead of trying to identify a particular Microbee system,
413 ; we just put vectors here for all systems.
416 ; 48h : 56k (64k apc) - tested 19-Jun-1990
417 ; 48k : 64k - tested 01-Sep-1990
418 ; 50h : dreamdisk (3rd party disk for Microbee)
419 ; e0h : 128k - tested 19-Jun-1990
420 ; e0h : 256k - tested 01-Sep-1990
422 org ($ and 0ff00h) + 100h
423 int equ $/256 ; byte for interrupt register
425 dw inta ; printer vector
426 dw intb ; rs232 vector
555 ; tables for baud rates
556 t75: db 124,13 ; full delay
558 db 168,255 ; txrx delay
559 dw trout ; address of subroutine to transmit char
560 t7512: db 124,13 ; 75R/1200T
562 db 194,1 ; txout delay
584 t1275: db 195,1 ; 1200R/75T
602 ; copy table entries to locations used by serial routines
615 ;transmit character in E
617 txout: mvi b,ntotal ;total number of bits to send
619 in portb ;c = portb with tx bit zeroed
622 ora a ;carry=0 (start bit)
624 jnc txout4 ;10T skip if space
625 ori 20h ; 3T (average) set mark
626 txout4: out portb ;11T
631 jnz txout6 ; 14*L + 14*H + 3584*(H-1)
632 stc ; 4T carry=1 (stop bit)
633 mov a,e ; 4T shift next bit to carry
638 ;loop = 74T + (delay loop)
644 ;transmit character in E
645 ;simultaneous receive char if necessary
649 tro2: rrc ;shift tx char to hl
660 tro10: mvi b,tqfudge ;adjust char in hl to align with
671 mvi a,0ffh ;flag to say we are not receiving
673 mvi d,tqbit ;total number of qtr bits to send
674 in portb ;b = portb with tx bit zeroed
677 mvi e,0 ;we are not receiving yet
680 jz tro14 ;loop till Clear To Send
681 out 09h ;Color Wait OFF
684 lda trtemp ;are we receiving
686 jnz tro22 ;skip if not
687 in portb ;is last bit a mark?
689 jz tro18 ;skip if mark (don't wait for stop)
690 lhld fulldel ;delay to stop bit
695 tro18: lhld wptr ; check buffer
698 dcx d ; decrement queue pointer
701 jnz tro20 ; skip if no queue wrap around
702 lxi d,maxque-1 ; wrap around
703 tro20: mov a,l ; sub hl,de
709 ora l ; check for zero
710 jz tro22 ; skip if buffer full
712 shld wptr ; update queue
715 mov m,c ; put char in queue
720 ; routine for quarter bit timing
721 ; for transmit and simultaneous receive
722 ; total execution time is 223T + L*14T + H*34T
723 qbit: call txrx ;17T + 162T
735 mov a,d ; 4T Check if still sending or receiving
741 ;simultaneous transmit/receive
743 ; regs: b = portb with tx bit zeroed
744 ; c = character being received
745 ; d = number of qtr bits remaining to send
746 ; e = number of qtr bits remaining to receive (0 if not receiving)
747 ; hl = character being transmitted
748 ;this subroutine always executes in 162T (or 163T)
749 txrx: mov a,d ; 4T qtr bits remaining to send
751 jz txrx12 ;10T skip if no bits remaining (may be receiving)
752 ani 03h ; 7T a complete bit?
753 jnz txrx10 ;10T skip if not
754 dad h ;11T shift tx bit to bit 5 of h
756 ani 20h ; 7T extract tx bit
757 ora b ; 4T combine with portb
758 out portb ;11T send it
759 txrx2: dcr d ; 4T one less qtr bit to send
762 txrx4: mov a,e ; 4T qtr bits remaining to receive
764 jz txrx16 ;10T skip if not receiving
765 ani 3h ; 7T a complete bit?
766 jnz txrx14 ;10T skip if not
767 in portb ;11T get input
768 ani 10h ; 7T extract rx bit
769 sui 1 ; 7T bit to carry
770 mov a,c ; 4T bit to c
773 txrx6: dcr e ; 4T one less qtr bit to receive
777 ;come here if transmitting, but not a complete bit
778 ;delay to match up execution times
788 ;come here if not sending (but still receiving)
789 ;delay to match up execution times
804 ;come here if receiving (but not a complete bit)
805 ;delay to match up execution time
814 ;come here if not receiving
815 txrx16: in portb ;11T check if start bit
817 jz txrx18 ;10T skip if mark
818 mvi e,rqbit ; 7T get quarter bit count for receive
820 sta trtemp ;13T store flag to say we are receiving
821 ori a ; 7T delay (should be 6T)
834 ; RS232 input interrupt routine
835 ; stores received character in queue
836 ; ;semi delay starts here
837 intb: ;20T (approx.) for interrupt
843 ani 10h ; 7T test input for start bit
844 jz intb16 ;10T skip if no start bit.
846 lhld semidel ;16T half bit delay
848 jnz intb2 ;10T inner loop 14T*L
850 jnz intb2 ;10T outer loop (14*H + 256*14*(H-1))T
851 mvi e,8 ; 6T number of data bits
852 ;semi delay ends here (125T + delay loop)
853 ;full delay starts here
854 intb4: lhld fulldel ;16T full bit delay
858 jnz intb6 ; 14*L + 14*H + 3584*(H-1)
859 in portb ;11T test input
861 sui 1 ; 7T input bit to carry
864 mov c,a ; 4T and then to C
866 jnz intb4 ;10T loop till all data bits collected
867 ;full delay ends here (67T + delay loop)
870 jz intb12 ; skip if mark
871 lhld fulldel ; wait for stop bit
876 intb12: lhld wptr ; check buffer
879 dcx d ; decrement queue pointer
882 jnz intb14 ; skip if no queue wrap around
883 lxi d,maxque-1 ; wrap around
884 intb14: mov a,l ; sub hl,de
890 ora l ; check for zero
891 jz intb16 ; skip if buffer full
893 shld wptr ; update queue
896 mov m,c ; put char in queue
905 ; get char from serial port buffer.
906 ; exit: A=char or Z if no char
918 ora l ;check for zero
925 dcx d ; decrement queue pointer
928 jnz rsi6 ; skip if no queue wrap around
929 lxi d,maxque-1 ; wrap around
935 mov e,m ;get char from queue
951 par2: db 0CBh,46h ;bit 0,(hl)
960 oldint: db 0 ; storage for old i reg
962 ptemp: db 0 ;temp storage used by inta interrupt
963 pflag: db 0 ;0ffh if waiting for printer. 00h if ready
965 ;receive queue pointers
966 maxque equ 2048 ; receiver queue size
971 ndata equ 8 ; 8 data bits
972 nstrt equ 1 ; 1 start bit
973 nstop equ 1 ; 1 stop bit
974 ntotal equ nstrt+ndata+nstop
975 rqbit equ 4*(nstrt+ndata) ;number of quarter bits to receive
976 tqbit equ 4*(nstrt+ndata+nstop) ;number of quarter bits to transmit
977 tqfudge equ 13-nstrt-ndata
979 ;H=0 or L=0 behave as 256
981 fulldel: dw 0 ; 3584(H-1) + 14H + 14L + 67 cycles
982 semidel: dw 0 ; 3584(H-1) + 14H + 14L + 125 cycles
983 ;1/4 bit transmit and simultaneous tx/rx delay 34H + 14L + 223 cycles
984 ;or full bit delay 3584(H-1) + 14H + 14L + 74 cycles
986 txcall: dw trout ; address of subroutine to transmit char
992 ovlend equ $ ; End of overlay