.TITLE	KERMIT-65 Hayes micro modem
.SBTTL	6502 version - Ted Medin

;	Version 1.0

;	Based on the KERMIT Protocol.

;	$Header: apphmm.m65,v 1.8 90/10/15 14:23:32 medin Locked $
.SBTTL	Define start address for assembly

       .=$1003			;[39] Start assembly at hex 1003

.SBTTL	Revision History

;
; Edit #	Description
; ------	-----------
;

;$Log:	apphmm.m65,v $
Revision 1.8  90/10/15  14:23:32  medin
new org of $7f00 for 3.87
version 1.8

;Revision 1.7  88/12/22  09:26:51  medin
;use the time constant for the wait routine

;Revision 1.6  88/02/06  21:41:04  medin
; Correct bug in checking status for output ready. Happens only when
;host has asked us to stop flow.
;Change output routine to check for input ch ready before exiting.

;Revision 1.5  88/01/15  08:41:26  medin
;New origin for 3.81

;Revision 1.4  87/06/29  10:39:29  medin
; Change wait routine to use apple rom wait, change org to work with 3.78.

;Revision 1.3  87/05/13  18:11:36  medin
; Change org to correspond with 3.76

;Revision 1.2  87/02/21  00:01:58  medin
;Put the version in the hearld so we can keep track  of the com drivers
;also. Thanks Rhoda.

;DONT FORGET TO UPDATE THE VERSION
;Revision 1.1  86/10/28  10:32:10  medin
;Initial revision

;
;
;	Vector for com cards starts here 
;		location $1003 for data
;		location $1020 for routine jumps
;		location $1040 for main routines
;
sscdbd:	.blkb	1  ;[54]contains baud index(ala super serial card) used by init
			;		6 - 300 baud
			;		7 - 600 
			;		etc
	.blkb	1	;
crdnam:	.word	herld	;[54] null terminated string of who we are
kersli:	.blkb	1	;[54] com slot $n0
kerins:	.blkb	1	;[54] force initialization flag-when 0
endker:	.blkb	2	;[54] address of end of main kermit
flowfg:	.blkb	1	;flow control (xon xoff) flag true when hi bit set
tl0end	.word	endcom	;[1.5] end of this routine
timect	.blkb	1	;[1.7] 1 ms of delay via rom wait rtn
	.=sscdbd+29		;[54] future expansion
	jmp	tl2int		;[54] initialize com card
	jmp	tl2cmd		;[54] command for ACIA in A
			;
			; 0 - hang up 
			; $0b - set baud
			; $0c - set break on the line
			; $91 - xon
			; $93 - xoff
			;
			;[54] routine will return false(0) if unable
	jmp	tl2cp		;[54] check for input ch ready-0 false
	jmp	tl2gpc		;[54] get input ch
	jmp	tl2ppc		;[54] put output character
	jmp	tl2exi		;[54] reset card and restore initialized
	.=sscdbd+29+32		;[54] futures
;[1.4]wait:	.blkb	3	;[54] wait routine-a reg contains milliseconds
wait:	.blkb	3	;[1.4] apple rom wait rtn 220=125ms,206=108ms,25=2ms
prstr:	.blkb	3	;[54] print string-x=lsb,y=msb of null terminated string
urdkey:	.blkb	3	;[54] read keyboard
prcrlf:	.blkb	3	;[54] print cr and lf
telcnc	.blkb	3	;check for keyboard character
telspa	.blkb	3	;set character parity

;[1.4]	.=$7200	;[54] place to start com card assembly
	.=$7f00	;[1.8][1.5] place to start com card assembly
start	=	.		;need a label at begining
kr0pch	=	$c087		;[12] Base for port char location (DC Hayes)
kr0pst	=	$c086		;[12] Base for port strobe locations (DC Hayes)
kr0pcr	=	$c086		;[41] Base for prot control register (DC Hayes)
kr0pcc	=	$c085	;[48] Modem control port
kbd	=	$c000		; Keyboard character input location
cr	=	$d		; <cr>
apinc1	=	3	;[48] first init char for 6850 acia
apinc2	=	$11	;[48] second init (8-bits)
hctrlq	=	$91	;^Q with high bit set
hctrls	=	$93	;^S  "
hctrlz	=	$9a	;^Z  "
ctrlq	=	$11	;[59] ^Q
ctrls	=	$13	;[59] ^S
setio2	=	$fe93	; place for pr#0
cswl	=	$36
cswh	=	$37
rdkey	=	$fd0c	; read a ch from current input device
cout	=	$fded	; print a ch to current output device
kwrk01	.byte		;[1.7]
temp	.byte		;[48] work space for dial
pinptr	.byte		; input buffer pointer
inptr	.byte		; input buffer pointer for get
poutpt	.byte		;[59]  output buffer pointer
outptr	.byte		;[59]     "       "     "    for put
ksli	.byte		; com slot $0n
dch.cr	=	$7f8		;[41] Save area for Control register
herld	nasc	<HAYES MICRO MODEM V1.8> 1	;tell who we are
bad	nasc	<COM ROUTINES ASM TOO LOW IN MEMORY> 1
dialms:	nasc	<NUMBER TO DIAL:> 1	;[48]
dialm2:	nasc	<AWAITING CARRIER...ANY KEY ABORTS> 1	;[48]
dialm3:	nasc	<CONNECTED.> 1	;[48]
dialm4	nasc	<THERE WILL BE A 35 SEC DELAY> 1


;
;	D. C. Hayes I/O Device support - These routines support the
;		D. C. Hayes Micromodem.
;


tlini9:	lda	#1		;[59] give true return
	rts		;[48] only way to reach this

tl2int:	
	lda	#start^
	cmp	endker+1	;are we loaded above main
	beq	dontno		;cant tell yet
	bcc	trble		;yes we are in trouble
	bcs	setnm		;ok 
dontno	lda	#start\		;well lets check 16 bits
	cmp	endker
	beq	setnm		;whee just exactly right
	bcs	setnm		;ok
trble	ldx	#bad\		;got to tell someone
	ldy	#bad^
	jsr	prstr		;print the message
	jsr	prcrlf		;and terminate it properly
setnm:
init0:	

tlinit:			;[48]
	ldx	kersli	;[48] get device slot
	lda	kr0pch,x	;[48] access data
	lda	kr0pst,x	;[48] now for the status
	and	#4	;[48] do we have a carrier?
	beq 	tlini9	;[48] yes,carry on
	txa		; calculate $0n from $n0
	lsr	a
	lsr	a
	lsr	a
	lsr	a
	sta 	ksli	; now we have $0slot
	ldx	#dialm4\	; tell about the delay
	ldy	#dialm4^
	jsr	prstr
	jsr	prcrlf		;and make it look nice
	lda	cswl	; save output hooks
	pha
	lda	cswh
	pha
	lda	ksli	; now make it pr#slot
	jsr	setio2+2
	lda	#hctrlq	; ^q starts dialing
	jsr	cout
	lda	#cr+$80	; ^m end of dialing wait for carrier
	jsr	cout
	lda	#hctrlz	; ^z hang up
	jsr	cout
;[1.4]	lda	#10
	lda	#20	;[1.4]
	sta	temp	; wait for 2.5 sec, slow phone co
;[1.4]tlini0	lda	#250
;[1.4]	jsr	wait	; .250 sec at a time
;[1.7]tlini0	lda	#220	;[1.4] 125 ms
tlini0	lda	#125	;[1.7] 125 ms
	sta	kwrk01	;[1.7]
tlinii	lda	timect	;[1.7] 1 ms at a time
	jsr	wait	;[1.4]
	dec	kwrk01	;[1.7]
	bne	tlinii	;[1.7]
	dec	temp
	bne	tlini0
	pla		; we are now thru so restore output
	sta	cswh
	pla	
	sta	cswl
	lda	#$8d	;[48] go offhook to dial
	ldx	kersli	;[48] get slot again and again and again ...
	sta	kr0pcc,x	;[48]
	lda	#apinc1		;[48] init acia ch 1
	sta	kr0pch,x	;[48]
	lda	#apinc2		;[48] init acia ch 2
	sta	kr0pch,x	;[48]
;[1.4]	lda	#10	;[48] now to wait 2.5 sec
	lda	#20	;[1.4] now to wait 2.5 sec 125ms at a time
	sta	temp	;[48]
;[1.4]tlini2: lda	#250	;[48] 250 ms.
;[1.7]tlini2: lda	#220	;[1.4] 125 ms.
tlini2: lda	#125	;[1.7] 125 ms.
;[1.4]	jsr	wait	;[48] there goes x again
	sta	kwrk01	;[1.7] 1 ms at a time
tlinih	lda	timect	;[1.7]	
	jsr	wait	;[1.4]
	dec	kwrk01	;[1.7]
	bne	tlinih	;[1.7]
	dec	temp	;[48]
	bne	tlini2	;[48] all 2.5 sec? no
	ldx	#dialms\	;[48] now for the dial message
	ldy	#dialms^	;[48]
	jsr	prstr	;[48] print it
tlini5:	jsr	rdkey	;[48] get a ch from keyboard
	jsr	cout	; and print it
	and	#$7f	;[48] drop high bit
	cmp	#'0	;[48] you can never tell what one types
	bmi	notnum	;[48] its not in the number range fro ascii
	cmp	#$3a	;[48] well it may be a number
	bpl	notnum	;[48] no, its too big
	and	#$f	;[48] get the digits
	bne	tlini3	;[48] is it a zero
	lda	#10	;[48] yes, thats 10 pulses
tlini3:	sta	temp	;[48] thats the count of pulses
tlini4:	lda	#$d	;[48] go on hook
	ldx	kersli	;[48] the slot again
	sta	kr0pcc,x	;[48] tell the chip
;[1.4]	lda	#61	;[48] this is a 61 ms delay
;[1.7]	lda	#154	;[1.4] this is a 61 ms delay
	lda	#61	;[1.7] this is a 61 ms delay
	sta	kwrk01	;[1.7]
tlinib	lda	timect	;[1.7] 1 ms at a time
	jsr 	wait	;[48]
	dec	kwrk01	;[1.7]
	bne	tlinib	;[1.7]
	lda	#$8d	;[48] off hook
	ldx	kersli	;[48] you know what this is by now
	sta	kr0pcc,x	;[48] tell
;[1.4]	lda	#39	;[48] now for a 39 ms delay
;[1.7]	lda	#123	;[1.4] now for a 39 ms delay
	lda	#39	;[1.7] now for a 39 ms delay
	sta	kwrk01	;[1.7]
tlinif	lda	timect	;[1.7] 1 ms at a time
	jsr	wait	;[48]
	dec	kwrk01	;[1.7]
	bne	tlinif	;[1.7]
	dec	temp	;[48] all the pulses ?
	bne	tlini4	;[48] no, keep on
;[1.4]	lda	#3	;[48] wait for 600 ms
	lda	#6	;[1.4] wait for 600 ms
	sta	temp	;[48]
;[1.4]tlini6:	lda	#200	;[48]
;[1.7]tlini6:	lda	#198	;[48] 100ms
tlini6:	lda	#100	;[1.7] 100ms
	sta	kwrk01	;[1.7]
tlinig	lda	timect	;[1.7] 1 ms at a tiime
	jsr	wait	;[48]
	dec	kwrk01	;[1.7]
	bne	tlinig	;[1.7]
	dec	temp	;[48]
	bne	tlini6	;[48]
	jmp	tlini5	;[48] get the next number
notnum:	cmp	#cr	;[48] is this the end
	bne	tlini5	;[48] nope try for a number
	jsr	prcrlf	;[48] make the screen look nice
	ldx	#dialm2\	;[48] now for the waiting msg
	ldy	#dialm2^	;[48]
	jsr	prstr	;[48] print it
	ldx	kersli	;[48] the slot again
tlini8:	bit	kbd	;[48] do we have a ch from the keyboard
	bpl	tlini7	;[48] no, try for carrier
	jsr	rdkey	; lets do this right
	lda	#0	;[48]
	ldx	kersli	;[48] the slot again
	sta	kr0pcc,x	;[48] hang up and give up
	lda	#0	; give a false return (0)
	rts		;[48]give a false return (0)
tlini7:	lda	kr0pch,x	;[48] the data
	lda	kr0pst,x	;[48] and now the status
	and	#4	;[48] carrier?
	bne	tlini8	;[48] not yet try again
	lda	#$8f	;[48] originate mode+ap300+apoffh
	sta	kr0pcc,x	;[48] tell
	jsr	prcrlf	;[48]
	ldx	#dialm3\	;[48] tell we got carrier
	ldy	#dialm3^	;[48]
	jsr	prstr	;[48]
	jsr	prcrlf	;[48]
	lda	#0	;start the buffer at 0
	sta	pinptr	
	sta	inptr	
	sta	poutpt	;[59]    "
	sta	outptr	;[59]    "
	lda	#1	; give a true return (non 0)
	rts		;[48] finally

tl2cp:
	ldx	kersli		;[12] Offset into I/O locations
tl0cp1:	lda	kr0pst,x	;[12] Try for a character
	and	#$01		;[12] Check for receive register full
	beq	tl0cp7
	lda	kr0pch,x	; get ch
	ldy	pinptr		; get place to store
	sta	inbuf,y		; in buf
	inc	pinptr		; ready for next
	bit	flowfg		;[59] how about flow control
	bpl	tl0cp7		;[59] no
	lda	inbuf,y		;[59] get input ch
	and	#$7f		;[59] drop parity etc
;	bvc	tl2cp4		;[59] yes,how about ^S received?, no
	cmp	#ctrlq		;[59] is this continue(start up outputing)
	bne	tl2cp4		;[59] no, check for ^S
	lda	flowfg		;[59] tattle about the continue
	and	#$bf		;[59]
	sta	flowfg		;[59]
	dec	pinptr		;[59] forget about this character
tl2cp2	ldy	outptr		;[59] see if any to output
	cpy	poutpt		;[59] well?
	beq	tl0cp7		;[59] no more we have put all
tl2cp3	lda	kr0pst,x	;[59] check status for output
;[1.6]	and	#$10		;[59] ready?
	and	#2		;[1.6] ready?
	beq	tl2cp3		;[59] no, spin
	lda	outbuf,y	;[59] output ch
	sta	kr0pch,x	;[59] bye
	inc	outptr		;[59] ready for next
	jmp	tl2cp2		;[59] 
tl2cp4	cmp	#ctrls		;[59] is this stop?
	bne	tl0cp7		;[59] no
	lda	#$40		;[59] yes, tattle
	ora	flowfg		;[59]
	sta	flowfg		;[59] now everyone knows
	dec	pinptr		;[59] forget about the ^S character
tl0cp7:
	lda	pinptr
	cmp	inptr
				;[12] No character, return false(zero)
				;[12] Successful return, return true(non 0)
	rts			;[12]		...

tl2gpc:
	ldx	inptr		;get where the ch is
	lda	inbuf,x		;get ch
	inc	inptr
tl0rtc:	rts			;[12]	and return

tl2ppc:
	pha			;[12] Hold the byte to send
	ldx	kersli		;[12] Get I/O location offset
tl0pp1:	lda	kr0pst,x	;[12] Get the status byte
	and	#$02		;[12] Isolate the flag we want (TRE)
	beq	tl0pp2		;[12] Transmit register is NOT empty, try again
	bit	flowfg		;[59] flow control?
	bpl	tl2pp0		;[59] no
	bvc	tl2pp0		;[59] should we stop outputing?,no
	ldy	poutpt		;[59] yes, save this ch in buffer
	pla			;[59]
	sta	outbuf,y	;[59]
	inc	poutpt		;[59] tell how many
;[1.6]	rts			;[59] thats all
	jmp	tl0cp1		;[1.6] check for input and return
tl2pp0				;[59]
	pla			;[12] Fetch the data byte off the stack
	sta	kr0pch,x	;[12] Stuff it at the proper loc to send it
;[1.6]	rts			;[59] thats all
	jmp	tl0cp1		;[1.6] check for input and return

tl0pp2:	jsr	tl0cp1		;go check for an input ch
	jmp	tl0pp1		;try output again

tl2exi:
	lda	#0	;tell we did this
	ldx	kersli	;[47] get slot number
	sta	kr0pcc,x	;shut it down
exit9:	rts

tl2cmd:			;find out what command
	beq	tl0drp	;its drop line 
	cmp	#$0c
	beq	break	;its a break command
	cmp	#$0b
	beq	tl2rts 	;its a set baud command and we cant
	cmp	#hctrlq
	beq	tl2sac	;its a xon command
	cmp	#hctrls
	beq	tl2sac	;its a xoff command
tl2fls:	lda	#0	;unknown command
tl2rts:	rts		;que passo ? return false(0)
tl2sac:	ldx	flowfg	;do we have flow control
	bpl	tl2fls	;no return false
	and	#$7f	;drop high bit
	jsr	telspa	;set parity
	jsr	tl2ppc	;output the ch
	lda	#1	;return a true
	rts
tl0drp:
	ldx	kersli	;[47] get slot number
	sta	kr0pcc,x	;shut it down
	lda	#1	;[54] true return
	rts
break:
	ldy	kersli		;[41] Get slot index,form = $n0
	ldx 	ksli		; and $0n where n = slot
	lda	dch.cr,x	;[41] Get saved Control Register
	ora	#$60		;[41] Set appropriate flags for break
	sta	kr0pcr,y	;[41] Start break signal
;[1.4]	lda	#233		;[41] Wait for 233 ms.
;[1.4]	jsr	wait		;[41] Do it, say goodby to x
;[1.7]	lda	#220		;[1.4] Wait for 125 ms.
	lda	#233		;[1.7] Wait for 233 ms.
	sta	kwrk01		;[1.7]
break3	lda	timect		;[1.7] 1 ms at a time
	jsr	wait		;[1.4]
	dec	kwrk01		;[1.7]
	bne	break3		;[1.7]
;[1.7]	lda	#206		;[1.4] Wait for 108 ms a total of 233ms.
;[1.7]	jsr	wait		;[1.4]
;[1.7]	ldx	ksli		; restore x
	lda	dch.cr,x	;[41] Get saved Control reg
	and	#$9f		;[41] Reset flags
;[1.7]	ldy	kersli		;[41] Get slot index
	sta	kr0pcr,y	;[41] Stop break signal
	rts			;[41]  and return
inbuf	.blkb	256	;input buffer 
outbuf	.blkb	256		;[59] output  "
endcom			;[1.5]
