home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oakland CPM Archive
/
oakcpm.iso
/
cpm
/
kermit
/
cp411src.ark
/
cpxapp.asm
< prev
next >
Wrap
Assembly Source File
|
1991-04-23
|
20KB
|
750 lines
IF NOT lasm
.printx * CPXAPP.ASM *
ENDIF ;NOT lasm
; KERMIT - (Celtic for "FREE")
;
; This is the CP/M-80 implementation of the Columbia University
; KERMIT file transfer protocol.
;
; Version 4.0
;
; Copyright June 1981,1982,1983,1984,1985
; Columbia University
;
; Originally written by Bill Catchings of the Columbia University Center for
; Computing Activities, 612 W. 115th St., New York, NY 10025.
;
; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,
; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many
; others.
;
; This file contains the system-dependent code and data for KERMIT.
; It will be probably be broken into independent files to generate
; overlays for the various systems, one or more overlay possible
; from each file. For now, we will leave it in one piece.
;
; revision history:
; edit 2, 22 July, 1987 by OBSchou. Massaged code to work with CPXCOM.ASM
;
; edit 1, 2nd June, 1987 by OBSchou. Extracted all Apple related code.
;
;
; Family is the string used in VERSION to say which of several
; smaller overlay files are used. These are (will be) derived from
; the juge CPXSYS.ASM file, in which case we will never get here.
; Just a Dollar, but put a sting in for a family of machines.
;
family: db 'CPXAPP.ASM (2) 22-jul-87$' ; Used for family versions....
;
IF apple
.printx * Assembling KERMIT-80 for the Apple ][ *
ENDIF;apple
IF apmmdm
.printx * with Z80 Softcard & Micromodem II *
ENDIF;apmmdm
IF ap6551
.printx * with Z80 Softcard & 6551 ACIA *
ENDIF;ap6551
IF ap6850;[32]
.printx * with Z80 Softcard & 6850 ACIA *
ENDIF;ap6850 [32]
IF apcps;[22]
.printx * with Softcard & CPS Multifunction card *
ENDIF;apcps
;
IF ap6551 OR ap6850 OR apcps;[9] [14]
;jb eg. Apple SSC, Videx PSIO, Basis 108
apslot EQU 2 ;jb set equal to slot containing serial card
;jb set to 1 for Basis built-in port
ENDIF;jb ap6551 [9] apcps ap6850 [14]
IF ap6850 ;[14] offset in slot I/O space for ACIA registers
;e.g. PACT=00,01: AIO-I=05,04: AIO-II=0D,0C: Aristocard=0B,0A
apdat EQU 0DH ;data reg.=0E080h+apslot*10h*apdat
apstat EQU 0CH ;comm/stat reg.=0E080h+apslot*10h+apstat
ENDIF;ap6850
IF apmmdm
;APPLE Slot 2 contains Micromodem II.
MNPORT EQU 0E0A7H ;Communications Port.
mnprts EQU 0E0A6H ;Communications Port Status.
mnmodm EQU 0E0A5H ;Modem Control Port.
orgmod EQU 8EH ;Modem Originate Mode.
OUTPUT EQU 02H ;Output Buffer Empty.
INPUT EQU 01H ;Input Register Full.
apinc1 EQU 03H ;First Init Character for 6850 ACIA (Reset)
apinc2 EQU 11H ;Second Init Character for ACIA (8-bits)
apoffh EQU 80H ;Set if OFFHOOK
AP300 EQU 1 ;300 Baud
z80 EQU TRUE ;Z80 Softcard
ENDIF;apmmdm
IF ap6551 ;jb
mnport EQU 0E088H+(10H*apslot) ;jb Communications Port.
mnprts EQU 0E089H+(10H*apslot) ;jb Communications Port Status.
mnprtc EQU 0E08BH+(10H*apslot) ;jb Communications Control
mnprtm EQU 0E08AH+(10H*apslot) ;jb Communications Master (command)
output EQU 10H ;jb Output Buffer Empty.
input EQU 08H ;jb Input Register Full.
mncinb EQU 18H ;jb Control Port Initialization Byte
;jb (8-bit, no parity, 1-stop, 1200 baud)
mnminb EQU 0BH ;jb Master Port Initialization Byte
;jb (DTR, RTS, no interrupts)
z80 EQU TRUE ;Z80 Softcard
ENDIF;ap6551
IF ap6850 ;[32]
mnport EQU 0E080H+(10H*apslot)+apdat ;Communications Port.
mnprts EQU 0E080H+(10H*apslot)+apstat ;Communications Port Status.
OUTPUT EQU 02H ;Output Buffer Empty.
INPUT EQU 01H ;Input Register Full.
apinc1 EQU 03H ;First Init Character for 6850 ACIA (Reset)
apinc2 EQU 15H ;Second Init Character for ACIA (8 data, 1 stop bit)
z80 EQU TRUE ;Z80 Softcard
ENDIF;[32] ap6850
IF apcps ;[22]
mnport EQU 0E0FAH+(100H*apslot) ; Communications Port.
mnprts EQU 0E0FBH+(100H*apslot) ; Communications Port Status.
mnprtc EQU 0E0FEH+(100H*apslot) ; Communications Control
output EQU 1 ; Output Buffer Empty.
input EQU 2 ; Input Register Full.
TxEmpty EQU 04h ; Transmitter empty flag
apmod1 EQU 4EH ; Mode Byte 1 (1 stop, no parity,8-bit, 16x)
; Mode Byte 2 is speed control byte
apcmd EQU 37H ; Command Byte (RTS,Error reset,RxE,DTR,TxE)
z80 EQU TRUE ;Z80 Softcard
ENDIF;[22] apcps
IF apple
defesc EQU ']'-100O ;The default escape character.
ENDIF;apple
; default to VT52-EMULATION ON.
vtval EQU 1
sysxin: ; continuation of systemm dependent initialisation code
IF ap6551
lda mnprtc ; read control port
ani 0fH ; extract low order nybble
sta speed ; store as comm line speed
sta speed+1 ; (16 bits, to match speed table entries)
mvi a,mnminb ;jb initialization routine
sta mnprts ;jb
sta mnprtm ;jb initialize master (command) port
mvi a,mncinb ;jb
sta mnprtc ;jb initialize control port
ENDIF;ap6551
IF ap6850 ;[32]
mvi a,apinc1 ;Init ACIA
sta mnprts
mvi a,apinc2 ;Set ACIA bits per character
sta mnprts
ENDIF;[32] ap6850
IF apcps ;[22]
lxi h,3737h ;Default 1200 baud
shld speed ;Store as port speed
xchg
call sysspd ;Initialise the port
ENDIF;[22] apcps
ret ; return from system-dependent routine
;
;
; system-dependent termination processing
; If we've changed anything, this is our last chance to put it back.
sysexit:
ret
;
; system-dependent processing for start of CONNECT command
;
syscon:
IF apmmdm
call ckdial ;See if dialing is required.
jmp kermit ;Go to command loop if aborted.
ENDIF;apmmdm
ret
conmsg: ; Messages printed when entering transparent (CONNECT) mode:
;
IF apmmdm
;This code was mostly taken from
; APMODEM.ASM V2.1
; Based on MODEM.ASM by Ward Christensen
; Modified for the Apple ][ by Gordon Banks 1-Jan-81
; Micromodem ][ dialer option by Dav Holle 2-Feb-81
; Code modified for KERMIT by Scott Robinson 14-Oct-82
;
;Come here to see if we need to dial a number.
;
ckdial: lda mnport ;access the data port
lda mnprts ;check status
ani 4 ;do we already have carrier?
jz rskp ;Yes, just continue
xra a ;Hangup Phone for starters
sta mnmodm
lxi b,1000 ;Delay for a second
call delay
mvi a,8FH ;orgmod+ap300+apoffh
sta holdd ;storing mode for after dialing
mvi A,8DH ;Go Offhook to start dialing sequence
sta mnmodm
mvi a,apinc1 ;Init ACIA
sta mnport
mvi a,apinc2 ;Set ACIA bits per character
sta mnport
lxi b,2500 ;wait 2.5 seconds for dial tone
call delay
lxi d,dialms ;Ask the user for the number
call prtstr
;
gtdial: mvi c,conin ;Get a character
call bdos
push psw ;save it
cpi 30H ;is it big enough to dial?
jc dialed ;no
cpi 3AH ;is it too big to dial?
jnc dialed ;yes
ani 0FH ;ok, it's a digit, get its value
jnz dialnz ;dial nonzero digits as-is
mvi A,10 ;dial zero as ten
;
dialnz: mov e,a ;count pulses in E-reg
dopuls: mvi a,0DH ;put it on-hook
sta mnmodm
lxi b,61 ;61-millisec pulse
call delay
mvi a,8DH ;take it off-hook again...
sta mnmodm
lxi b,39 ;39-millisec delay between pulses
call delay
dcr e ;any more pulses to do?
jnz dopuls ;yep, do 'em
lxi b,600 ;delay 600 msecs between digits
call delay
;
dialed: pop psw ;get back the char
cpi cr ;do we have a CR (done dialing)?
jnz gtdial ;no, keep on dialin'
lxi d,dialm2
call prtstr
tictoc: mvi c,dconio ;Direct console input.
mvi e,0FFH
call bdos
ora a ;Have a charcter?
jnz nodial ;If so we abort
lda mnport ;access the data port
lda mnprts ;get modem status
ani 4 ;carrier?
jnz tictoc ;No
;
lda holdd ;get the old modem control byte
sta mnmodm ;turn our carrier on
lxi d,dialm3
call prtstr
jmp rskp
nodial: xra a ;Hangup the modem.
sta mnmodm
ret ;Return to abort the command.
;
holdd: db 0 ;Modem setup code
dialms: DB 'Number to Dial: $'
dialm2: DB CR,LF,'Awaiting Carrier....(any key aborts)$'
dialm3: DB cr,lf,'Connected.',CR,LF,'$'
;
;DELAY wait for the number of millisecs in B,C
;
delay: push b ;save B,C
push d ;save D,E
inr b ;bump B for later DCR
;
delay1: mvi e,126 ;delay count for 1 millisec (Apple Z80
;clock=2.041MHz)
;
delay2: dcr e ;count
jnz delay2 ;down
;
dcr c ;more millisecs?
jnz delay1 ;yes
dcr b ;no - more in hi byte?
jnz delay1 ;yes
pop d ;no, restore D,E
pop b ; restore B,C
ret
ENDIF;apmmdm
;
;
; 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:
IF apmmdm OR apcps OR ap6850 ;
lxi d,inhlps ; we got options...
call prtstr ; print them.
ENDIF ;apmmdm OR apcps OR ap6850
ret
;additional, system-dependent help for transparent mode
; (two-character escape sequences)
inhlps:
IF apcps OR ap6850
db cr,lf,'B Transmit a BREAK'
ENDIF;apcps OR ap6850
IF apmmdm
db cr,lf,'D Drop the line'
ENDIF;apmmdm
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...
IF apmmdm
cpi 'D' ;Disconnect Modem?
jnz intc00 ;No.
xra a ;Yes, hangup the modem
sta mnmodm
ret ; command has been executed
intc00:
ENDIF;apmmdm
IF ap6850 OR apcps ; [22] [25] ... some more
cpi 'B' ; send break?
jz sendbr ; yes, go do it. return nonskip when through.
ENDIF;[22] ap6850 OR apcps
jmp rskp ; take skip return - command not recognized.
;
IF ap6850 ;[32]
sendbr:
;
; Ensure that the transmitter has finished sending buffered chars
sndbr1: lda mnprts ; get UART status
ani output ; everything sent?
jz sndbr1 ; no, wait a bit more
;
; Begin sending a break
mvi a,apinc2
ori 60h ;transmit break level, CTS high
sta mnprts
;
; Wait for 250 milliseconds (using hundredths second delay routine)
mvi a,25
call delay
;
; Resume normal operation
mvi a,apinc2
sta mnprts
;
ret ;done
ENDIF;[32] ap6850
IF apcps ;[22]
sendbr:
;
; Ensure that the transmitter has finished sending buffered chars
sndbr1: lda mnprts ; get UART status
ani TxEmpty ; everything sent?
jz sndbr1 ; no, wait a bit more
;
; Unmask command register
mvi a,80h
sta mnprtc
;
; Begin sending a break by setting bit in UART command register
mvi a,3Fh ; Set TxEna, DTR, RxEna, SBreak, ErrRst, RTS
sta mnprts
;
; Wait for 250 milliseconds (using hundredths second delay routine)
mvi a,25
call delay
;
; Resume normal operation by clearing the SendBreak command bit
mvi a,37h ;Set TxEna, DTR, RxEna, ErrRst, RTS
sta mnprts
;
; Remask command register
mvi a,0
sta mnprtc
;
ret ;done
ENDIF;[22] apcps
;
;
; 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
; mdmflt - modem filter [30]
; called with character to be sent to printer in E
; with parity set as appropriate.
; return with accumulator = 0 do do nothing,
; <> 0 to send char in E.
mdmflt:
mov a,e ;[30] get character to test
ret
; prtflt - printer filter [30]
; called with character to be sent to printer in E
; returns with a = 0 to do nothing
; a <> 0 to print it.
;
; this routine for those printer that automatically insert
; a lf on cr, or cr for lf. Should this be shifted to
; the system indep. stuff, in say 4.06?
prtflt:
mov a,e ; [30] get character to test
ret
;
;
; system-dependent processing for BYE command.
; for apmmdm, heath, and lobo, hang up the phone.
sysbye:
IF apmmdm
xra a ;Hangup our end, too.
sta mnmodm
ENDIF;apmmdm
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:
; Set the speed for Apple with 6551 ACIA
IF ap6551
lda mnprtc ;jb read control port
ani 0F0H ;jb zap low order nybble
ora e ;jb put rate in low order nybble
sta mnprtc ;jb send to control port
ret
ENDIF;ap6551
; Set the speed for Apple with CPS Multifunction card
IF apcps ;[22]
mvi a,80h
sta mnprtc
lda mnprts ;read command register to reset 2651
mvi a,apmod1 ;first mode byte
sta mnport
mvi a,4 ;waste some time before sending second byte
spdwt: dcr a ; 4 T-states
jnz spdwt ; 10 T-states
mov a,e ;second mode byte is speed byte
sta mnport
mvi a,apcmd ;command byte
sta mnprts
xra a
sta mnprtc
ret
ENDIF;[22] apcps
IF ap6551 ;jb
spdtbl: db 0DH ;jb 13 entries
db 03H,'110$', 03H,03H ;jb
db 04H,'1200$', 08H,08H ;jb
db 05H,'134.5$', 04H,04H ;jb
db 03H,'150$', 05H,05H ;jb
db 04H,'1800$', 09H,09H ;jb
db 05H,'19200$', 0FH,0FH ;jb
db 04H,'2400$', 0AH,0AH ;jb
db 03H,'300$', 06H,06H ;jb
db 04H,'3600$', 0BH,0BH ;jb
db 04H,'4800$', 0CH,0CH ;jb
db 03H,'600$', 07H,07H ;jb
db 04H,'7200$', 0DH,0DH ;jb
db 04H,'9600$', 0EH,0EH ;jb
sphtbl: db cr,lf,' 110 134.5 150 300 600 1200 1800'
db cr,lf,' 2400 3600 4800 7200 9600 19200$'
ENDIF;ap6551
IF apcps ;[22]
spdtbl: db 10H ; 16 entries
db 03H,'110$', 32h,32h
db 04H,'1200$', 37h,37h
db 05H,'134.5$', 33h,33h
db 03H,'150$', 34h,34h
db 04H,'1800$', 38h,38h
db 05H,'19200$', 3fh,3fh
db 04H,'2000$', 39h,39h
db 04H,'2400$', 3ah,3ah
db 03H,'300$', 35h,35h
db 04H,'3600$', 3bh,3bh
db 04H,'4800$', 3ch,3ch
db 02H,'50$', 30h,30h
db 03H,'600$', 36h,36h
db 04H,'7200$', 3dh,3dh
db 02H,'75$', 31h,31h
db 04H,'9600$', 3eh,3eh
sphtbl: db cr,lf,' 50 75 110 134.5 150 300 600 1200'
db cr,lf,' 1800 2000 2400 3600 4800 7200 9600 19200$'
ENDIF;[22] apcps
; The following conditionals were once a huge if not statement. There
; wasn't enough room to add the lobo to the list, so it had to be broken
; into 2, which you can't do with an if not. I redid it as two ifs and
; applied them to those that wouldn't set baud. [Hal Hostetler]
IF apmmdm OR ap6850 ;[32]
spdtbl equ 0 ; SET BAUD not supported.
sphtbl equ 0
ENDIF;appmdm OR ap6850 [32]
;
;
; no ports available for Apple
prttbl EQU 0 ;SET PORT not supported
prhtbl EQU 0
;
;
; This is the system-dependent SET PORT command.
; HL contains the argument from the command table.
sysprt:
ret
;
;
; selmdm - select modem port
; selcon - select console port
; selmdm is called before using inpmdm or outmdm;
; selcon is called before using inpcon or outcon.
; For iobyt systems, diddle the I/O byte to select console or comm port;
; For Decision I, switches Multi I/O board to console or modem serial
; port. [Toad Hall]
; For the rest, does nothing.
; preserves bc, de, hl.
selmdm:
ret
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:
IF apple
push h
outmd1: lxi h,mnprts ;address of the port status register
outmd2: mov a,m ; get port status in A
ani output ;Loop till ready.
jz outmd2
outmd3: lxi h,mnport ;address of port data register
mov m,e ; write the character
pop h
ret
ENDIF;apple
;
;
; get character from modem; return zero if none available.
; for IOBYT systems, the modem port has already been selected.
; destroys bc, de, hl.
inpmdm:
IF apple
inpmd1: lda mnprts ;Get the port status into A.
ani input ;See if the input ready bit is on.
rz ;If not then return.
inpmd2: lda mnport ;If so, get the char.
ENDIF;apple
ret ; return with character in A
;
; flsmdm - flush comm line.
; Modem is selected.
; Currently, just gets characters until none are available.
flsmdm: call inpmdm ; Try to get a character
ora a ; Got one?
jnz flsmdm ; If so, try for another
ret ; Receiver is drained. Return.
;
;
; lptstat - get the printer status. Return a=0ffh if ok, or 0 if not.
lptstat:
xra a
ret
;
; outlpt - output character in E to printer
; console is selected.
; preserves de.
outlpt:
push d ; save DE in either case
call prtflt ; go through printer filter [30]
ana a ; if A = 0 do nothing,
jz outlp1 ; [30] if a=0 do nothing
mvi c,lstout
call bdos ;Char to printer
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 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:
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. preserves b (but not c)
clrtop: lxi d,erascr
jmp prtstr
IF apple
sysver: db 'Apple II CP/M$'
outlin: db ('^'-100O),esc,'Y',cr,lf,' $'
erascr: db ('^'-100O),esc,'Y$' ;Clear screen and go home.
eralin: db cr,esc,'T$' ;Clear line.
delstr: db bs,bs,'$' ; Adjust for delete
curldn: db esc,'=$' ;Cursor lead-in
ttab: ;Table start location.
ta: db ('K'-100O),'$',0,0 ;Cursor up.
tb: db 12O,'$',0,0 ;Cursor down.
tc: db ('F'-100O),'$',0,0 ;Cursor right.
td: db '$',0,0,0 ;(can't) Cursor left
te: db '$',0,0,0 ;(can't) Clear display
tf: db '$',0,0,0 ;(can't) Enter graphics mode
tg: db '$',0,0,0 ;(can't) Exit graphics mode
th: db ('^'-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.
ENDIF;apple
ovlend equ $ ; End of overlay
END