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
21 ; This file contains the system-dependent code and data for KERMIT.
22 ; It will be probably be broken into independent files to generate
23 ; overlays for the various systems, one or more overlay possible
24 ; from each file. For now, we will leave it in one piece.
27 ; edit 2, 22 July, 1987 by OBSchou. Massaged code to work with CPXCOM.ASM
29 ; edit 1, 2nd June, 1987 by OBSchou. Extracted all Apple related code.
32 ; Family is the string used in VERSION to say which of several
33 ; smaller overlay files are used. These are (will be) derived from
34 ; the juge CPXSYS.ASM file, in which case we will never get here.
35 ; Just a Dollar, but put a sting in for a family of machines.
37 family: db 'CPXAPP.ASM (2) 22-jul-87$' ; Used for family versions....
41 .printx * Assembling KERMIT-80 for the Apple ][ *
44 .printx * with Z80 Softcard & Micromodem II *
47 .printx * with Z80 Softcard & 6551 ACIA *
50 .printx * with Z80 Softcard & 6850 ACIA *
53 .printx * with Softcard & CPS Multifunction card *
58 IF ap6551 OR ap6850 OR apcps;[9] [14]
59 ;jb eg. Apple SSC, Videx PSIO, Basis 108
60 apslot EQU 2 ;jb set equal to slot containing serial card
61 ;jb set to 1 for Basis built-in port
62 ENDIF;jb ap6551 [9] apcps ap6850 [14]
63 IF ap6850 ;[14] offset in slot I/O space for ACIA registers
64 ;e.g. PACT=00,01: AIO-I=05,04: AIO-II=0D,0C: Aristocard=0B,0A
65 apdat EQU 0DH ;data reg.=0E080h+apslot*10h*apdat
66 apstat EQU 0CH ;comm/stat reg.=0E080h+apslot*10h+apstat
71 ;APPLE Slot 2 contains Micromodem II.
72 MNPORT EQU 0E0A7H ;Communications Port.
73 mnprts EQU 0E0A6H ;Communications Port Status.
74 mnmodm EQU 0E0A5H ;Modem Control Port.
75 orgmod EQU 8EH ;Modem Originate Mode.
76 OUTPUT EQU 02H ;Output Buffer Empty.
77 INPUT EQU 01H ;Input Register Full.
78 apinc1 EQU 03H ;First Init Character for 6850 ACIA (Reset)
79 apinc2 EQU 11H ;Second Init Character for ACIA (8-bits)
80 apoffh EQU 80H ;Set if OFFHOOK
82 z80 EQU TRUE ;Z80 Softcard
86 mnport EQU 0E088H+(10H*apslot) ;jb Communications Port.
87 mnprts EQU 0E089H+(10H*apslot) ;jb Communications Port Status.
88 mnprtc EQU 0E08BH+(10H*apslot) ;jb Communications Control
89 mnprtm EQU 0E08AH+(10H*apslot) ;jb Communications Master (command)
90 output EQU 10H ;jb Output Buffer Empty.
91 input EQU 08H ;jb Input Register Full.
92 mncinb EQU 18H ;jb Control Port Initialization Byte
93 ;jb (8-bit, no parity, 1-stop, 1200 baud)
94 mnminb EQU 0BH ;jb Master Port Initialization Byte
95 ;jb (DTR, RTS, no interrupts)
96 z80 EQU TRUE ;Z80 Softcard
100 mnport EQU 0E080H+(10H*apslot)+apdat ;Communications Port.
101 mnprts EQU 0E080H+(10H*apslot)+apstat ;Communications Port Status.
102 OUTPUT EQU 02H ;Output Buffer Empty.
103 INPUT EQU 01H ;Input Register Full.
104 apinc1 EQU 03H ;First Init Character for 6850 ACIA (Reset)
105 apinc2 EQU 15H ;Second Init Character for ACIA (8 data, 1 stop bit)
106 z80 EQU TRUE ;Z80 Softcard
110 mnport EQU 0E0FAH+(100H*apslot) ; Communications Port.
111 mnprts EQU 0E0FBH+(100H*apslot) ; Communications Port Status.
112 mnprtc EQU 0E0FEH+(100H*apslot) ; Communications Control
113 output EQU 1 ; Output Buffer Empty.
114 input EQU 2 ; Input Register Full.
115 TxEmpty EQU 04h ; Transmitter empty flag
116 apmod1 EQU 4EH ; Mode Byte 1 (1 stop, no parity,8-bit, 16x)
117 ; Mode Byte 2 is speed control byte
118 apcmd EQU 37H ; Command Byte (RTS,Error reset,RxE,DTR,TxE)
119 z80 EQU TRUE ;Z80 Softcard
123 defesc EQU ']'-100O ;The default escape character.
127 ; default to VT52-EMULATION ON.
133 sysxin: ; continuation of systemm dependent initialisation code
136 lda mnprtc ; read control port
137 ani 0fH ; extract low order nybble
138 sta speed ; store as comm line speed
139 sta speed+1 ; (16 bits, to match speed table entries)
140 mvi a,mnminb ;jb initialization routine
142 sta mnprtm ;jb initialize master (command) port
144 sta mnprtc ;jb initialize control port
148 mvi a,apinc1 ;Init ACIA
150 mvi a,apinc2 ;Set ACIA bits per character
155 lxi h,3737h ;Default 1200 baud
156 shld speed ;Store as port speed
158 call sysspd ;Initialise the port
161 ret ; return from system-dependent routine
166 ; system-dependent termination processing
167 ; If we've changed anything, this is our last chance to put it back.
173 ; system-dependent processing for start of CONNECT command
177 call ckdial ;See if dialing is required.
178 jmp kermit ;Go to command loop if aborted.
183 conmsg: ; Messages printed when entering transparent (CONNECT) mode:
187 ;This code was mostly taken from
189 ; Based on MODEM.ASM by Ward Christensen
190 ; Modified for the Apple ][ by Gordon Banks 1-Jan-81
191 ; Micromodem ][ dialer option by Dav Holle 2-Feb-81
192 ; Code modified for KERMIT by Scott Robinson 14-Oct-82
194 ;Come here to see if we need to dial a number.
196 ckdial: lda mnport ;access the data port
197 lda mnprts ;check status
198 ani 4 ;do we already have carrier?
199 jz rskp ;Yes, just continue
200 xra a ;Hangup Phone for starters
202 lxi b,1000 ;Delay for a second
204 mvi a,8FH ;orgmod+ap300+apoffh
205 sta holdd ;storing mode for after dialing
206 mvi A,8DH ;Go Offhook to start dialing sequence
208 mvi a,apinc1 ;Init ACIA
210 mvi a,apinc2 ;Set ACIA bits per character
213 lxi b,2500 ;wait 2.5 seconds for dial tone
215 lxi d,dialms ;Ask the user for the number
218 gtdial: mvi c,conin ;Get a character
221 cpi 30H ;is it big enough to dial?
223 cpi 3AH ;is it too big to dial?
225 ani 0FH ;ok, it's a digit, get its value
226 jnz dialnz ;dial nonzero digits as-is
227 mvi A,10 ;dial zero as ten
229 dialnz: mov e,a ;count pulses in E-reg
230 dopuls: mvi a,0DH ;put it on-hook
232 lxi b,61 ;61-millisec pulse
234 mvi a,8DH ;take it off-hook again...
236 lxi b,39 ;39-millisec delay between pulses
238 dcr e ;any more pulses to do?
239 jnz dopuls ;yep, do 'em
240 lxi b,600 ;delay 600 msecs between digits
243 dialed: pop psw ;get back the char
244 cpi cr ;do we have a CR (done dialing)?
245 jnz gtdial ;no, keep on dialin'
249 tictoc: mvi c,dconio ;Direct console input.
252 ora a ;Have a charcter?
253 jnz nodial ;If so we abort
254 lda mnport ;access the data port
255 lda mnprts ;get modem status
259 lda holdd ;get the old modem control byte
260 sta mnmodm ;turn our carrier on
265 nodial: xra a ;Hangup the modem.
267 ret ;Return to abort the command.
269 holdd: db 0 ;Modem setup code
270 dialms: DB 'Number to Dial: $'
271 dialm2: DB CR,LF,'Awaiting Carrier....(any key aborts)$'
272 dialm3: DB cr,lf,'Connected.',CR,LF,'$'
274 ;DELAY wait for the number of millisecs in B,C
276 delay: push b ;save B,C
278 inr b ;bump B for later DCR
280 delay1: mvi e,126 ;delay count for 1 millisec (Apple Z80
286 dcr c ;more millisecs?
288 dcr b ;no - more in hi byte?
290 pop d ;no, restore D,E
297 ; syscls - system-dependent close routine
298 ; called when exiting transparent session.
305 ; sysinh - help for system-dependent special functions.
306 ; called in response to <escape>?, after listing all the
307 ; system-independent escape sequences.
310 IF apmmdm OR apcps OR ap6850 ;
311 lxi d,inhlps ; we got options...
312 call prtstr ; print them.
313 ENDIF ;apmmdm OR apcps OR ap6850
318 ;additional, system-dependent help for transparent mode
319 ; (two-character escape sequences)
323 db cr,lf,'B Transmit a BREAK'
324 ENDIF;apcps OR ap6850
327 db cr,lf,'D Drop the line'
330 db '$' ;[hh] table terminator
333 ; sysint - system dependent special functions
334 ; called when transparent escape character has been typed;
335 ; the second character of the sequence is in A (and in B).
337 ; non-skip: sequence has been processed
338 ; skip: sequence was not recognized
339 sysint: ani 137O ; convert lower case to upper, for testing...
341 cpi 'D' ;Disconnect Modem?
343 xra a ;Yes, hangup the modem
345 ret ; command has been executed
349 IF ap6850 OR apcps ; [22] [25] ... some more
350 cpi 'B' ; send break?
351 jz sendbr ; yes, go do it. return nonskip when through.
352 ENDIF;[22] ap6850 OR apcps
354 jmp rskp ; take skip return - command not recognized.
362 ; Ensure that the transmitter has finished sending buffered chars
363 sndbr1: lda mnprts ; get UART status
364 ani output ; everything sent?
365 jz sndbr1 ; no, wait a bit more
367 ; Begin sending a break
369 ori 60h ;transmit break level, CTS high
372 ; Wait for 250 milliseconds (using hundredths second delay routine)
376 ; Resume normal operation
386 ; Ensure that the transmitter has finished sending buffered chars
387 sndbr1: lda mnprts ; get UART status
388 ani TxEmpty ; everything sent?
389 jz sndbr1 ; no, wait a bit more
391 ; Unmask command register
395 ; Begin sending a break by setting bit in UART command register
396 mvi a,3Fh ; Set TxEna, DTR, RxEna, SBreak, ErrRst, RTS
399 ; Wait for 250 milliseconds (using hundredths second delay routine)
403 ; Resume normal operation by clearing the SendBreak command bit
404 mvi a,37h ;Set TxEna, DTR, RxEna, ErrRst, RTS
407 ; Remask command register
417 ; sysflt - system-dependent filter
418 ; called with character in E.
419 ; if this character should not be printed, return with A = zero.
420 ; preserves bc, de, hl.
421 ; note: <xon>,<xoff>,<del>, and <nul> are always discarded.
423 mov a,e ; get character for testing
427 ; mdmflt - modem filter [30]
428 ; called with character to be sent to printer in E
429 ; with parity set as appropriate.
430 ; return with accumulator = 0 do do nothing,
431 ; <> 0 to send char in E.
433 mov a,e ;[30] get character to test
438 ; prtflt - printer filter [30]
439 ; called with character to be sent to printer in E
440 ; returns with a = 0 to do nothing
441 ; a <> 0 to print it.
443 ; this routine for those printer that automatically insert
444 ; a lf on cr, or cr for lf. Should this be shifted to
445 ; the system indep. stuff, in say 4.06?
447 mov a,e ; [30] get character to test
455 ; system-dependent processing for BYE command.
456 ; for apmmdm, heath, and lobo, hang up the phone.
459 xra a ;Hangup our end, too.
466 ; This is the system-dependent command to change the baud rate.
467 ; DE contains the two-byte value from the baud rate table; this
468 ; value is also stored in 'speed'.
471 ; Set the speed for Apple with 6551 ACIA
473 lda mnprtc ;jb read control port
474 ani 0F0H ;jb zap low order nybble
475 ora e ;jb put rate in low order nybble
476 sta mnprtc ;jb send to control port
480 ; Set the speed for Apple with CPS Multifunction card
484 lda mnprts ;read command register to reset 2651
485 mvi a,apmod1 ;first mode byte
487 mvi a,4 ;waste some time before sending second byte
488 spdwt: dcr a ; 4 T-states
489 jnz spdwt ; 10 T-states
490 mov a,e ;second mode byte is speed byte
492 mvi a,apcmd ;command byte
501 spdtbl: db 0DH ;jb 13 entries
502 db 03H,'110$', 03H,03H ;jb
503 db 04H,'1200$', 08H,08H ;jb
504 db 05H,'134.5$', 04H,04H ;jb
505 db 03H,'150$', 05H,05H ;jb
506 db 04H,'1800$', 09H,09H ;jb
507 db 05H,'19200$', 0FH,0FH ;jb
508 db 04H,'2400$', 0AH,0AH ;jb
509 db 03H,'300$', 06H,06H ;jb
510 db 04H,'3600$', 0BH,0BH ;jb
511 db 04H,'4800$', 0CH,0CH ;jb
512 db 03H,'600$', 07H,07H ;jb
513 db 04H,'7200$', 0DH,0DH ;jb
514 db 04H,'9600$', 0EH,0EH ;jb
516 sphtbl: db cr,lf,' 110 134.5 150 300 600 1200 1800'
517 db cr,lf,' 2400 3600 4800 7200 9600 19200$'
521 spdtbl: db 10H ; 16 entries
522 db 03H,'110$', 32h,32h
523 db 04H,'1200$', 37h,37h
524 db 05H,'134.5$', 33h,33h
525 db 03H,'150$', 34h,34h
526 db 04H,'1800$', 38h,38h
527 db 05H,'19200$', 3fh,3fh
528 db 04H,'2000$', 39h,39h
529 db 04H,'2400$', 3ah,3ah
530 db 03H,'300$', 35h,35h
531 db 04H,'3600$', 3bh,3bh
532 db 04H,'4800$', 3ch,3ch
533 db 02H,'50$', 30h,30h
534 db 03H,'600$', 36h,36h
535 db 04H,'7200$', 3dh,3dh
536 db 02H,'75$', 31h,31h
537 db 04H,'9600$', 3eh,3eh
539 sphtbl: db cr,lf,' 50 75 110 134.5 150 300 600 1200'
540 db cr,lf,' 1800 2000 2400 3600 4800 7200 9600 19200$'
545 ; The following conditionals were once a huge if not statement. There
546 ; wasn't enough room to add the lobo to the list, so it had to be broken
547 ; into 2, which you can't do with an if not. I redid it as two ifs and
548 ; applied them to those that wouldn't set baud. [Hal Hostetler]
549 IF apmmdm OR ap6850 ;[32]
550 spdtbl equ 0 ; SET BAUD not supported.
552 ENDIF;appmdm OR ap6850 [32]
555 ; no ports available for Apple
556 prttbl EQU 0 ;SET PORT not supported
562 ; This is the system-dependent SET PORT command.
563 ; HL contains the argument from the command table.
570 ; selmdm - select modem port
571 ; selcon - select console port
572 ; selmdm is called before using inpmdm or outmdm;
573 ; selcon is called before using inpcon or outcon.
574 ; For iobyt systems, diddle the I/O byte to select console or comm port;
575 ; For Decision I, switches Multi I/O board to console or modem serial
577 ; For the rest, does nothing.
578 ; preserves bc, de, hl.
586 ; Get character from console, or return zero.
587 ; result is returned in A. destroys bc, de, hl.
590 mvi c,dconio ;Direct console I/O BDOS call.
597 ; Output character in E to the console.
598 ; destroys bc, de, hl
602 mvi c,dconio ;Console output bdos call.
603 call bdos ;Output the char to the console.
608 ; outmdm - output a char from E to the modem.
609 ; the parity bit has been set as necessary.
610 ; returns nonskip; bc, de, hl preserved.
614 outmd1: lxi h,mnprts ;address of the port status register
615 outmd2: mov a,m ; get port status in A
616 ani output ;Loop till ready.
618 outmd3: lxi h,mnport ;address of port data register
619 mov m,e ; write the character
630 ; get character from modem; return zero if none available.
631 ; for IOBYT systems, the modem port has already been selected.
632 ; destroys bc, de, hl.
635 inpmd1: lda mnprts ;Get the port status into A.
636 ani input ;See if the input ready bit is on.
637 rz ;If not then return.
638 inpmd2: lda mnport ;If so, get the char.
642 ret ; return with character in A
646 ; flsmdm - flush comm line.
648 ; Currently, just gets characters until none are available.
650 flsmdm: call inpmdm ; Try to get a character
652 jnz flsmdm ; If so, try for another
653 ret ; Receiver is drained. Return.
657 ; lptstat - get the printer status. Return a=0ffh if ok, or 0 if not.
663 ; outlpt - output character in E to printer
664 ; console is selected.
667 push d ; save DE in either case
668 call prtflt ; go through printer filter [30]
669 ana a ; if A = 0 do nothing,
670 jz outlp1 ; [30] if a=0 do nothing
673 call bdos ;Char to printer
675 outlp1: pop d ; restore saved register pair
680 ; Screen manipulation routines
681 ; csrpos - move to row B, column C
683 ; csrpos for terminals that use a leadin sequence followed
684 ; by (row + 31.) and (column + 31.)
686 csrpos: push b ; save coordinates
687 lxi d,curldn ; get cursor leadin sequence
688 call prtstr ; print it
689 pop h ; restore coordinates
691 adi (' '-1) ; space is row one
694 call outcon ; output row
697 adi (' '-1) ; space is column one
699 jmp outcon ; output it and return
702 ; delchr - make delete look like a backspace. Unless delete is a printing
703 ; character, we just need to print a backspace. (we'll output clrspc
705 ; For Kaypro and Vector General, delete puts a blotch on the screen.
706 ; For Apple and Osborne 1, delete moves but doesn't print.
712 ; erase the character at the current cursor position
715 mvi e,bs ;get a backspace
718 ; erase the current line
722 ; erase the whole screen, and go home. preserves b (but not c)
727 sysver: db 'Apple II CP/M$'
728 outlin: db ('^'-100O),esc,'Y',cr,lf,' $'
729 erascr: db ('^'-100O),esc,'Y$' ;Clear screen and go home.
730 eralin: db cr,esc,'T$' ;Clear line.
731 delstr: db bs,bs,'$' ; Adjust for delete
732 curldn: db esc,'=$' ;Cursor lead-in
733 ttab: ;Table start location.
734 ta: db ('K'-100O),'$',0,0 ;Cursor up.
735 tb: db 12O,'$',0,0 ;Cursor down.
736 tc: db ('F'-100O),'$',0,0 ;Cursor right.
737 td: db '$',0,0,0 ;(can't) Cursor left
738 te: db '$',0,0,0 ;(can't) Clear display
739 tf: db '$',0,0,0 ;(can't) Enter graphics mode
740 tg: db '$',0,0,0 ;(can't) Exit graphics mode
741 th: db ('^'-100O),'$',0,0 ;Cursor home.
742 ti: db ('K'-100O),'$',0,0 ;Reverse linefeed.
743 tj: db esc,'Y$',0 ;Clear to end of screen.
744 tk: db esc,'T$',0 ;Clear to end of line.
747 ovlend equ $ ; End of overlay