/
/ SCC interrupt handler for Atari ST
/
/ exported functions and variables
/
	.globl	sccvec_,sccnovec_
	.globl	scctvec_,sccotvec_,scctim_
/
/ variables from C
/
	.globl	sccvecloc_,sccmaxvec_,sccpolltab_,sccchan_
	.globl	sccisrloc_,sccisrbit_,sccgpiploc_,sccgpipbit_
/
	.shri
/
/ sccvec is the interrupt handler for SCC interrupts using INTACK
/
sccvec_:
	movem.l ${d0-d2,a0-a2},-(sp)	/ Save C working registers
/
/ Determine if an interrupt request is really coming in from SCC
/
	movea.l sccgpiploc_,a0		/ Location of GPIP register
	move.w	sccgpipbit_,d0		/ Bit number to test
	btst	d0,(a0)			/ Test bit in GPIP data register
	bne.s	clrisr			/ No interrupt, clear ISR & iret
/
/ Read SCC interrupt vector and check it
/
sccint: movea.l sccvecloc_,a0
	move.b	$0xff,(a0)		/ Generate INTACK
	bra	delay			/ Short delay
delay:
	move.b	(a0),d0			/ Read the vector
	cmp.b	sccmaxvec_,d0		/ Check for a legal vector
	bhs.s	panic			/ It should not be >= the maximum
/
/ Extract channel number and status from vector. Determine handler address.
/
	move.b	d0,d1			/ Save vector to retrieve status
	lsr.b	$1,d0			/ Discard least significant bit
	bcs.s	panic			/ It should not be a 1
	andi.w	$0x7c,d0		/ Isolate channel number (and make word)
	eori.w	$0x04,d0		/ Toggle A/B channel bit
	lea	sccchan_,a0		/ Address SCC channel table
	movea.l 0(a0,d0),a0		/ Read address of channel structure
	move.l	a0,d0			/ Make sure this is an attached channel
	beq.s	panic			/ No channel struct, problems...
	andi.w	$0x06,d1		/ Isolate status info from vector
	lsl.w	$1,d1			/ Make index in LONG array
	movea.l 0(a0,d1),a1		/ Read the interrupt handler address
/
/ Call the handler (defined in C), with sccchan struct as a parameter
/
	move.l	a0,-(sp)		/ Put channel struct as a parameter
	jsr	(a1)			/ Call the handler
	movea.l (sp)+,a0		/ Get channel struct back
					/ Assumes C routine does not change it
/
/ Reset highest priority interrupt
/
	movea.l 16(a0),a1		/ Get control register address
	move.b	$0x38,(a1)		/ "Reset Highest IUS" opcode to WR0
/
/ Clear the ISR bit in the MFP
/
clrisr: movea.l sccisrloc_,a0		/ Location of ISR
	move.w	sccisrbit_,d0		/ Bit number to clear
	bclr	d0,(a0)			/ Clear the bit
/
/ Determine if more interrupt requests are coming in from the SCCs
/
	movea.l sccgpiploc_,a0		/ Location of GPIP register
	move.w	sccgpipbit_,d0		/ Bit number to test
	btst	d0,(a0)			/ Test bit in GPIP data register
	beq.s	sccint			/ Is active, handle next SCC interrupt
/
/ Restore registers and return from interrupt handler
/
iret:	movem.l (sp)+,${d0-d2,a0-a2}	/ Restore registers
	rte
/
/ Branch to here when irrecoverable errors occur in the interrupt handler
/
panic:	illegal				/ This will cause a TRAP
	movea.l sccisrloc_,a0		/ On continuation, clear it and return
	move.w	sccisrbit_,d0		/ Bit number to clear
	bclr	d0,(a0)			/ Clear the bit
	bra	iret
/
/
/ sccnovec is the interrupt handler for SCC interrupts using polling
/
sccnovec_:
	movem.l ${d0-d2,a0-a2},-(sp)	/ Save C working registers
/
/ Determine if an interrupt request is really coming in from SCC
/
	movea.l sccgpiploc_,a0		/ Location of GPIP register
	move.w	sccgpipbit_,d0		/ Bit number to test
	btst	d0,(a0)			/ Test bit in GPIP data register
	bne.s	clrisrnv		/ No interrupt, clear ISR & iret
/
/ Find the SCC generating the interrupt by polling all attached SCCs
/ reading RR3A (the interrupt pending register)
/
sccintnv:
	movea.l $sccpolltab_,a0		/ Point to polling table
sccpoll:
	move.l	(a0)+,d0		/ Get chan A CTRL address
	beq.s	panic			/ End of table, we did not find it!
	movea.l d0,a1			/ Move it to an address register
	movea.l (a0)+,a2		/ Also read B CTRL address
	move.b	$3,(a1)			/ Select RR3A
	move.b	(a1),d0			/ Read it and test for 0
	beq.s	sccpoll			/ No interrupt here, try next chip
/
/ Read SCC interrupt vector from RR2B, it should always be correct
/ Extract channel number and status from vector. Determine handler address.
/
	move.b	$2,(a2)			/ Select RR2B
	move.b	(a2),d0			/ Read the vector
	move.b	d0,d1			/ Save vector to retrieve status
	lsr.b	$1,d0			/ Discard least significant bit
	andi.w	$0x7c,d0		/ Isolate channel number (and make word)
	eori.w	$0x04,d0		/ Toggle A/B channel bit
	lea	sccchan_,a0		/ Address SCC channel table
	movea.l 0(a0,d0),a0		/ Read address of channel structure
	move.l	a0,d0			/ Make sure this is an attached channel
	beq.s	panic			/ No channel struct, problems...
	andi.w	$0x06,d1		/ Isolate status info from vector
	lsl.w	$1,d1			/ Make index in LONG array
	movea.l 0(a0,d1),a1		/ Read the interrupt handler address
/
/ Call the handler (defined in C), with sccchan struct as a parameter
/
	move.l	a0,-(sp)		/ Put channel struct as a parameter
	jsr	(a1)			/ Call the handler
	addq.l	$4,sp			/ Remove parameter
/
/ Clear the ISR bit in the MFP
/
clrisrnv:
	movea.l sccisrloc_,a0		/ Location of ISR
	move.w	sccisrbit_,d0		/ Bit number to clear
	bclr	d0,(a0)			/ Clear the bit
/
/ Determine if more interrupt requests are coming in from the SCCs
/
	movea.l sccgpiploc_,a0		/ Location of GPIP register
	move.w	sccgpipbit_,d0		/ Bit number to test
	btst	d0,(a0)			/ Test bit in GPIP data register
	beq.s	sccintnv		/ Is active, handle next SCC interrupt
/
/ Restore registers and return from interrupt handler
/
	movem.l (sp)+,${d0-d2,a0-a2}	/ Restore registers
	rte
/
/
/ This routine will be inserted in the 200Hz timer interrupt handling
/ (vector 0x114) to call the SCC driver timing routine every 2nd
/ interrupt (= every 10 ms), and thereafter jump to the original handler
/
scctvec_:
	btst	$0,0x4bd		/ Test low bit of 200Hz counter
	beq.s	punt			/ Not our turn
	movem.l ${d0-d2,a0-a2},-(sp)	/ Save C working registers
	jsr	scctim_			/ Call C routine every 10 ms
	movem.l (sp)+,${d0-d2,a0-a2}	/ Restore registers
punt:	jmp	0xeeeeeeee		/ Jump to original handler
sccotvec_ =	.-4			/ Original hander address stored here

