.TITLE	KERMIT-65 CCS 7710 com card - interupt driven
.SBTTL	6502 version - Ted Medin
;	Thanks to Bill Rupp for the loan of his equipment and thus this driver

;	Version 1.0
;	Warning interupts must be allowed by card.

;	Based on the KERMIT Protocol.

;	$Header: appccs.m65,v 1.11 88/12/22 09:22:13 medin Locked $
.SBTTL	Define start address for assembly

       .=$1003			;[39] Start assembly here

debug	=	0		;[1] debug flag - when 0 will not add debug code
.SBTTL	Revision History

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

;$Log:	appccs.m65,v $
;Revision 1.11  88/12/22  09:22:13  medin
;Use time constant for the wait routine,
;enlarge the input buffer to $900.

;Revision 1.10  88/04/27  18:05:59  medin
; Dont allow interupts when you exit kermit.

;Revision 1.9  88/03/28  13:31:35  medin
; Attempt to make the interupt routine faster.

;Revision 1.8  88/01/15  08:42:30  medin
;New origin for 3.81

;Revision 1.7  87/06/29  10:55:05  medin
; Change wait rtn to use apple nom rtn, change org for 3.78.

;Revision 1.6  87/05/13  18:09:28  medin
; Change org to correspond with 3.76

;Revision 1.5  87/02/20  23:57:07  medin
; Put the version number in the hearld so we can keep track of the com
;drivers also. Thanks Rhoda.

; DONT FORGET TO UPDATE THE VERSION
;Revision 1.4  86/12/23  10:17:59  medin
; Protect ourselves from interupts during initialization and
;tattle that we cant set baud via software.

;Revision 1.3  86/12/09  22:14:52  medin
; Acknowledge Bill Rupp for the loan of his equipment.

;Revision 1.2  86/12/09  22:08:38  medin
; This is the interupt driven version of the ccs 7710 serial card.


;
;
;	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	;[57] flow flag for xon/xoff controll b7=1 yes
tl0end	.word	endcom	;[1.8] end of this routine
timect	.blkb	1	;[1.11] 1 ms delay via rom wait rtn
	.=sscdbd+29		;[54] future expansion
tlinit:	jmp	tl2int		;[54] initialize com card
tl0cmd:	jmp	tl2cmd		;[54] command in A reg
			;
			;[54] 0 - hang up 
			;[54] $0b - set baud
			;[54] $0c - set break on the line
			;[57] $91 - turn remote on (xon)
			;[57] $93 - turn remote off(xoff)
			;
			;[54] routine will return false(0) if unable
tl0cp:	jmp	tl2cp		;[54] check for input ch ready-0 false
tl0gpc:	jmp	tl2gpc		;[54] get input ch
tl0ppc:	jmp	tl2ppc		;[54] put output character
tl0exi:	jmp	tl2exi		;[54] reset card and restore initialized
	.=sscdbd+29+32		;[54] futures
;[1.7]wait:	.blkb	3	;[54] wait routine-a reg contains milliseconds
wait:	.blkb	3	;[1.7] wait routine-apple rom rtn 220=125ms,198=100ms,25=2ms
prstr:	.blkb	3	;[54] print string x=lsb,y=msb x&y->null terminated string
rdkey:	.blkb	3	;[54] read keyboard
prcrlf:	.blkb	3	;[54] print cr and lf
telcnc:	.blkb	3	;[54] check for keyboard character
telspa:	.blkb	3	;[57] set character parity
prbyte	=     $fdda		  ; Routine - Print A-reg as 2 hex nibbles

	.=$7f00	;[1.12][1.8][54] place to start com card assembly
start	=	.		;need a label at begining
kr2pch	=	$c081		;data port
kr2pst	=	$c080		;status port
kr2pcr	=	$c080		;command port
kr2pcc	=	$c080		;control port
mncinb	=	$95	; Control port command(8 bit,no par,1-stop,in int,16xbaud)
mnminb	=	$3	; Master port reset
mssinb	=	$1	; status bit for input ready
mssoub	=	$2	;status bit for output busy
moutb	=	$60	; break command on output
moutnt	=	$b5	; command to start input & output with interupts
;	ACIA commands
;	xxxx xx00	clock 1x baud rate
;	xxxx xx01	clock 16x baud
;	xxxx xx10	clock 64x baud 
;	xxxx xx11	acia master reset
;	xxx0 00xx	7data + even parity + 2 stop bits
;	xxx0 01xx	7data + odd par     + 2 stop
;	xxx0 10xx	7data + even par    + 1 stop
;	xxx0 11xx	7data + odd par     + 1 stop
;	xxx1 00xx	8data + no par      + 2 stop
;	xxx1 01xx	8data + no par      + 1 stop
;	xxx1 10xx    	8data + even par    + 1 stop
;	xxx1 11xx	8data + odd par     + 1 stop
;	x00x xxxx	set   CTS, disable xmit interupts
;	x01x xxxx	set   CTS, enable xmit interupts
;	x10x xxxx	clear CTS, disable xmit interupts
;	x11x xxxx	set   CTS, disable xmit interups, xmit break on xmit data
;	0xxx xxxx	disable receive interrupts
;	1xxx xxxx	enable receive interrupts on rec full,rec overrun,DTR signal inactive
;	STATUS bits
;	.... ...x	receive data reg full when x=1
;	.... ..x.	xmit reg ready for data
;	.... .x..	DTR inactive - dont send
;	.... x...	RTS inactive - dont send
;	...x ....	rec data improper frame
;	..x. ....	rec data overrun
;	.x.. ....	parity error in rec data
;	x... ....	ACIA-generated xmit or rec interupt
inptr	.byte	0	;[51] input q pointer
pinptr	.byte	0	;[51] p "
outptr	.byte	0	;[51] output q pointer
poutpt	.byte	0	;[51] p "
hdirq	.word		;[51] hold area for dos IRQ
xon:	.byte	0	;[57] flow controll
xoff:	.byte	0	;[57] "
xofcnt	.byte	0	;count of times buffer overran
kwrk01	.byte	0	;[1.11]
	.ifne	debug	;[1] conditional assembly
cixon	.byte	0	;[1] count of input xon request
cixoff	.byte	0	;[1]         "      xoff  "
coxon	.byte	0	;[1] count of ouput xon requests
coxoff	.byte	0	;[1]         "      xoff   "
caixon	.byte	0	;[1] count of actual input xon sent
caixof	.byte	0	;[1]         "             xoff "
	.endc		;[1]
hxon	=	$91	;^Q with high bit on
hxoff	=	$93	;^S  "
ctrlq	=	$11	;xon ^Q
ctrls	=	$13	;xoff ^S
irqsva	=	$45	;place dos saves a reg
dirq	=	$3fe	;[51] interupt address
sscstp	=	$578	;[47] +slot,bit 7 on turns off commands to ssc
herld	nasc	<CCS 7710 V1.12> 1	;tell who we are
bad	nasc	<COM ROUTINES ASSEMBLED TOO LOW> 1
nbaud   nasc    <CCS 7710 UNABLE TO SET BAUD> 1
bcom    .byte   '<
        nasc    <-- IS UNKNOWN COM CARD COMMAND> 1

;
;	CCS 7710 Card I/O Device support - These routines support the
;		Apple CCS 7710 Card.
;

tl2rpt: 		;[51] a is already saved in irqsva
	txa		;[51] save x
	pha		;[51]
tl2rpe			;[67] enhanced // has all regs saved
;[1.9]	ldx	kersli	;[51]
;[1.9]	lda	kr2pst,x	;[51] get status
	lda	kr2pst	;[1.9] get status
	bpl	tl2nts	;[51] not our interupt
	and	#mssinb	;[51] look at input bit
	bne	tl2inp	;[51] this is input ready
	bit	flowfg	;[57] is flow controll on?
	bpl	tl2out	;[57] no
	bvs	tl2noo	;[59] yes, is output ctlr S on?, yes
	lda	xoff	;[57] have we given the ^S ?
	beq	tl2ou0	;[57] maybe
	lda	xon	;[57] yes
	bne	tl2out	;[57] is it time to give the xoff ?
	.ifne	debug	;[1]
	inc	caixof	;[1] bump count of actual input xoffs given
	.endc		;[1]
	lda	#ctrls	;[57] yes
	sta	xon	;[57] tatle
	jmp	tl2ou2	;[1][57] always jump
tl2ou0:	lda	xon	;[57] how about giving the xon ?
	beq	tl2out	;[57] no
	.ifne	debug	;[1]
	inc	caixon	;[1] bump count of actual input xons given
	.endc		;[1]
	lda	#0	;[57] turn off xoff
	sta	xon	;[57]
	lda	#ctrlq	;[57] now for the xon
tl2ou2:	jsr	telspa	;[57] set parity correctly

;[1.9]	sta	kr2pch,x	;[57] stop this flood
tl2oup	sta	kr2pch	;[1.9] stop this flood
	jmp	tl2com	;[1][57] always jump
tl2out:
	lda	outptr	;[51] see if any to output
	cmp	poutpt	;[51]
	beq	tl2noo	;[51] no more to output
	ldx	poutpt	;[51] pointer to next ch to output
	lda	outbuf,x	;[51] get next ch
;[1.9]	ldx	kersli	;[51] now for the port
;[1.9]	sta	kr2pch,x	;[51] give it to card
tl2rpp	sta	kr2pch	;[1.9] give it to card
	inc	poutpt	;[51] bump to next ch to output
	jmp	tl2com	;[51] common return
tl2nts:	pla		;[51] restore x
	tax		;[51]
	jmp	(hdirq)	;[51] and pass it on sans a reg
tl2noo:	lda	#mncinb	;[51] turn off the output interupt
;[1.9]	sta	kr2pcr,x	;[51]
tl2no3	sta	kr2pcr	;[1.9]
	jmp	tl2com	;[51] common return from interupt
;[1.9]tl2inp:	lda	kr2pch,x	;[51] we have an input character
tl2inp:	lda	kr2pch	;[1.9] we have an input character
	ldx	pinptr	;[51] pointer to next input character
store			;[1.11]
	sta	inbuf,x	;[51] save ch
;[1.11]	inc	pinptr	;[51] ready for next input
	bit	flowfg	;[57] are we flow controll
;[1.11]	bpl	tl2com	;[57] no we may overun the buffers
	bpl	tl2icm	;[1.11] no we may overun the buffers
;[1.11]	lda	inbuf,x	;[59] is host telling us stop ?
	and	#$7f	;[59] ignore parity
;	bvc	tl2in2	;[59] are we already stoped?, yes
	cmp	#ctrlq	;[59] do we have a continue
	bne	tl2in2	;[59] no
	lda	#$bf	;[59] yes, now turn on flow
	and	flowfg	;[59]
	sta 	flowfg	;[59]
	.ifne	debug	;[1]
	inc	coxon	;[1] bump count of output xons given
	.endc		;[1]
;[1.11]	dec	pinptr	;[59] and ignore this character
	jsr	tl2suo	;[59] start up output
	jmp	tl2com	;[59] and carry on
tl2in2	cmp	#ctrls	;[59] do we have a stop?
	bne	tl2in4	;[59] 
	.ifne	debug	;[1]
	inc	coxoff	;[1] bump count of output xoffs given
	.endc		;[1]
	lda	#$40	;[59] yes tell all
	ora	flowfg	;[59] would you believe the remote
	sta	flowfg	;[59] has asked us to stop!
;[1.11]	dec	pinptr	;[59] ignore this character
	jmp	tl2com	;[1] thats all
tl2in4			;[59] place to hang ones hat
;[1.11]	lda	xoff	;[57] have we already asked for ^S ?
;[1.11]	bne	tl2com	;[57] yes no need for another
;	inx		;[57]
;	inx		;[57]
;	inx		;[57]
;	cpx	inptr	;[57] are we about to overrun ?
;[1.11]	txa		;[59] lets try stoping when half full
;[1.11]	clc		;[59]
;[1]	adc	#126	;[59]
;[1.11]	adc	#7	;[1]
;[1.11]	cmp	inptr	;[59] are we filling up ?
;[1.11]	bne	tl2com	;[57] no
;[1.11]	jsr	tl2suo	;[57] yes,start up output
;[1.11]	sta	xoff	;[57] turn on xon(non 0)
;[1.11]	.ifne	debug	;[1.11]
;[1.11]	inc	xofcnt	;just for debug 
;[1.11]	.endc		;[1.11]
tl2icm	
	inc	pinptr	;[1.11] now bump the ptr
	bne	tl2com	;[1.11] thats all
	ldx	store+2	;[1.11] now for the msb
	inx		;[1.11]
	cpx	#outbuf^	;[1.11] too far?
	bne	tl2ic0	;[1.11] no
	ldx	#inbuf^	;[1.11] yes
tl2ic0	stx	store+2	;[1.11] update the msb
tl2com:	pla		;[51] get x
	tax		;[51]
tl2eac	lda	irqsva	;[51] get a
tl2rti	rti		;[51] return from interupt

tl2suo:
;[1.9]	ldx	kersli		;[22] Get I/O location offset
	lda	#moutnt		;[51] turn on xmit and rec interupt
;[1.9]	sta	kr2pcr,x	;[51] tell card about it
tl2su3	sta	kr2pcr		;[1.9] tell card about it
tl2su0:	rts		;

tl2int:	sei		;lockout interupts just in case
;[1.11]	lda	hdirq	;see if we already saved
;[1.11]	bne	init0	;yes
	lda	hdirq+1	;maybe
	bne	init0	;sure thing
	lda	dirq	;[51] save dos IR for exit
	sta	hdirq	;[51]
	lda	dirq+1	;[51]
	sta	hdirq+1	;[51]
	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
;[1.11]	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:	lda	kerins		;[47] initialize slot
	beq	.+5		;hate to do this
	jmp	tl2prr		;[47] already initialized return

; 	apple machine id
;rom-->	$fbb3	$fbbf	$fbc0
; II	$38
; II+	$ea
; //e	$06		$ea
; //e+			$e0	enhanced
; //c	$06	$00	$00
;prodos-->	$bf98
; II,II+,//e	bit 3 = 0
; others	bit 3 = 1
; //c		bits 7,6 = 10

	lda	$fbc0		
	cmp	#$e0		; is this an enhanced 2e?
	beq	setenh		; yes
	cmp	#0		; no, how about a 2c?
	bne	init3		; no
	lda	$fbbf		; yes, how about an enhanced 2c?
	bne	init3		; no
setenh	lda	tl2rti		; yes
	sta	tl2com
	lda	#$ea		; a nop
	sta	tl2nts		; this keeps the stack straight
	sta	tl2nts+1	; incase there are mult interups
 	lda	#tl2rpe\	;[67][51]
	sta	dirq	;[67][51] setup inturpt address
	lda	#tl2rpe^	;[67][51]
	sta	dirq+1	;[67][51]
	ldx	#0		; now set up the ram banks for interupts
	bit	$c011
	bmi	.+4		;hate to do this
	ldx	#8
	bit	$c012
	bpl	.+4		;ssigh!
	inx
	inx
	bit	$c081
	bit	$c081
	phx			;save the current state for later
;	.byte	$da
	lda	$c016		;how about it
	asl	a
	ldy	#1
tl2ilp	lda	$fffe,y
	sta	$c009		;set alt card
	sta	$fffe,y
	sta	$c008		;now for main ram
	sta	$fffe,y
	dey
	bpl	tl2ilp
	bcc	.+5		;have we switch out the wrong one?
	sta	$c009		;yes
	plx
;	.byte	$fa
	bit	$c081,x
;	.byte	$3c,$81,$c0
	bit	$c081,x
;	.byte	$3c,$81,$c0
	jmp	init4		;[67]
init3
 	lda	#tl2rpt\	;[67][51]
	sta	dirq	;[67][51] setup inturpt address
	lda	#tl2rpt^	;[67][51]
	sta	dirq+1	;[67][51]
init4			;[67]
	lda	#0	;[51] clear pointers etc
	sta	inptr	;[51]
	sta	pinptr	;[51]
	sta	outptr	;[51]
	sta	poutpt	;[51]
	lda	#inbuf^	;[1.11] and the msb also
	sta	store+2	;[1.11]
	sta	get+2	;[1.11]
;[67] 	lda	#tl2rpt\	;[51]
;[67]	sta	dirq	;[51] setup inturpt address
;[67]	lda	#tl2rpt^	;[51]
;[67]	sta	dirq+1	;[51]
	ldx	kersli	;[47] get slot number
	stx	kerins	;[67] tell weve been here
	clc
	lda	#kr2pst\	;[1.9] status address
	adc	kersli	;[1.9] calculate proper address for status
	sta	tl2rpe+1	;[1.9] and set interupt rtn
	sta	tl2su3+1	;[1.9]
	sta	tl2no3+1
	clc
	lda	#kr2pch\	;[1.9] data port address
	adc	kersli	;[1.9] calulate proper address for ld & st
	sta	tl2rpp+1	;[1.9] and set interupt rtn
	sta	tl2inp+1
	sta	tl2oup+1
	lda	#mnminb	;[47] Master port init
	sta	kr2pcr,x	;[47] Com master port
	lda	#mncinb	;[47] Control port init
	sta	kr2pcc,x	;[47]
tl2prr:	cli		;[51] allow the interurpts to happen
	rts			;[22] Return


tl2cp:	sei		;[51] lockout inturpts
	lda	inptr	;[51] check input for chs
	cmp	pinptr	;[51]
	bne	tl2cp3	;[1.11] how about msb, no
	lda	store+2	;[1.11] yes check that also
	cmp	get+2	;[1.11]
tl2cp3			;[1.11]
	cli		;[51] allow interupts
	rts			;[22]		...

tl2gpc:	sei		;[51] lockout interupts
	ldx	inptr	;[51] get input character
get			;[1.11]
	lda	inbuf,x	;[51]
	inc	inptr	;[51] bump in pointer
	bne	tl2gp0	;[1.11]
	ldy	get+2	;[1.11] bump msb also
	iny		;[1.11]
	cpy	#outbuf^	;[1.11] too far?
	bne	tl2gp7	;[1.11] no
	ldy	#inbuf^	;[1.11] yes, circle those wagons
tl2gp7	sty	get+2	;[1.11] msb
;[1.11]	ldy	xon	;[57] are we flow controlling ?
;[1.11]	beq	tl2gp0	;[57] no
;[1.11]	inx		;[57]
;[1.11]	inx		;[57]
;[1.11]	inx		;[57]
;[1.11]	cpx	pinptr	;[57] have we about caught up ?
;[1.11]	bne	tl2gp0	;[57] no
;[1.11]	pha		;[57] save ch
;[1.11]	lda	#0	;[57] turn off xon
;[1.11]	sta	xoff	;[57]
;[1.11]	jsr	tl2suo	;[57] now start up output with a ^Q
;[1.11]	pla		;[57] restore ch
tl2gp0:
	cli		;[51] allow interupts
;	ldx	parity		;[22] Check parity
;	cpx	#nparit		;[22] No parity
;	beq	tl2rtc		;[22] Go return the character
;	and	#$7f		;[22] There is parity, so strip it off
tl2rtc:	rts			;[22]	and return

tl2ppc:	pha			;[22] Hold the byte to send
	sei		;[51] lockout interupts
	jsr	tl2suo	;[57] start up output
	pla			;[22] Fetch the data byte off the stack
;	jsr	telspa		;[22] Go set the parity appropriately
	ldx	outptr	;[51] get output pointer
	sta	outbuf,x	;[51] save in buffer for interupt
	inc	outptr	;[51] ready for next output
	cli		;[51] allow interupts
	rts			;[22]	and return

tl2exi:	sei		;lockout interupts
;[1.11]	lda	hdirq	;have we alredy done this?
;[1.11]	bne	exit0	;nope
	lda	hdirq+1	;maybe
	beq	exit9	;definitly
exit0:	lda	hdirq	;[51] restore dos IRQ address
	sta	dirq	;[51]
	lda	hdirq+1	;[51]
	sta	dirq+1	;[51]
	lda	#0	;tell we did this
;[1.11]	sta 	hdirq
	sta	hdirq+1
	ldx	kersli	;[47] get slot number
	sta	kr2pcr,x	;shut it down
;[1.10exit9:	cli		;now allow them
exit9:	;[1.10]cli		;now allow them
	rts
tl2cmd:			;find out what command
	beq	tl2rts	;its drop line and we cant
	cmp	#$0c
	beq	break	;its a break command
	cmp	#$0b
	beq	baud   	;its a set baud command
	cmp	#hxon	
	beq	txon	;its a turn xon
	cmp	#hxoff
	beq	txoff	;its a turn xoff
	jsr	prbyte	;print command
	ldx	#bcom\	;and tell all
	ldy	#bcom^
tl2prn	jsr	prstr
	jsr	prcrlf
tl2fls:			;a false return
tl2rts:			;tell that we cant
	lda	#0	;unknown command
	rts		
baud			; sorry we cant
	ldx	#nbaud\	;tell that we cant
	ldy	#nbaud^	;drop the line
	jmp	tl2prn	;and tell kermit we cant
txon:	;[1.9]bit	flowfg	;do we have flow control
;[1.9]	bpl	tl2fls	;no can do
	sei		;protect ourselves from interupts
	jsr	tl2suo	;[57] now start up output 
	lda	#0	
	sta	xoff	;tell interupt to start up 
	.ifne	debug	;[1]
	inc	cixon	;[1] bump count of xon requests
	.endc		;[1]
	cli
ltxon	lda	xon	;[1] got to wait for ch to be sent
	bne	ltxon	;[1] its called true syncronization
	lda	#1	;give a true return
	rts
txoff:	;[1.9]bit	flowfg	;do we have flow control ?
;[1.9]	bpl	tl2fls	;no 
	sei
	jsr	tl2suo	;[57] now start up output 
	.ifne	debug	;[1]
	inc	cixoff	;[1] bump count of xoff requests
	.endc		;[1]
	lda	#1	;we need xoff
	sta	xoff	;this also gives a true return
	cli
ltxoff	lda	xon	;[1] wait for it to be sent
	beq	ltxoff	;[1] are we syncronized? no
	rts
break:
	sei		;lock out interupts
	ldy	kersli		; ss card routine is not on
	lda	#moutb		;
	sta	kr2pcr,y	; start the break
	sta	kr2pch,y	; start xmit
	cli		; allow others to go
;[1.7]	lda	#233		; for 233 millseconds
;[1.7]	jsr	wait		; the y reg is not clobered
;[1.11]	lda	#220		;[1.7] for 125 millseconds
	lda	#233		;[1.11] for 233 millseconds
	sta	kwrk01		;[1.11]
break3	lda	timect		;[1.11] 1 ms at a time
	jsr	wait		;[1.7]
	dec	kwrk01		;[1.11]
	bne	break3		;[1.11]
;[1.11]	lda	#206		;[1.7] for 108 millseconds
;[1.11]	jsr	wait		;[1.7] which is a grand total of 223ms
	lda	#moutnt		; restore the commands
	sei		; see how nice one can be
	sta	kr2pcr,y	;
	cli		;allow interupts
	lda	#1	;return true
	rts
;[1.11]inbuf	.blkb	256	;input buffer
inbuf	.blkb	$900	;[1.11]input buffer ***** inbuf & outbuf no separations
outbuf	.blkb	256	;output buffer
endcom			;[1.8]
