*************************************************
*						*
*	CP/M-68k Basic Disk Operating System 	*
*		Exception Handling Module	*
*						*
*	Version 0.0 -- July    21, 1982		*
*	Version 0.1 -- July    25, 1982		*
*	Version 0.2 -- October  6, 1982		*
*	Version 0.3 -- December 21, 1982	*
*						*
*	Modified 2/15/84 sw for 68010 support	*
*						*
*************************************************


	.globl	_initexc
	.globl	_tpa_lp
	.globl	_tpa_hp
	.globl	gouser				*sw RTE routine

bgetseg = 18
bsetexc	= 22
buserr	= 2
spurious = 24
trap0	= 32
trap2	= 34
trap3	= 35
endvec	= 48

_initexc:
* Initialize Exception Vector Handlers
* It has 1 passed parameter: the address of the exception vector array
	move	#bsetexc,d0
	moveq	#2,d1
	move.l	#exchndl,d2
init1:
	movem.l	d0-d2,-(sp)
	trap	#3		* BIOS call to set exception vector
	movem.l	(sp)+,d0-d2
init2:	addq	#1,d1
	add.l	#4,d2
	cmpi	#spurious,d1
	bne	init3
	move	#trap0,d1
init3:	cmpi	#trap2,d1
	beq	init2		* don't init trap 2 or trap 3
	cmpi	#trap3,d1
	beq	init2
	cmpi	#endvec,d1
	blt	init1
*				initialize the exception vector array

	moveq	#bgetseg,d0
	trap	#3		* get the original TPA limits
	movea.l	d0,a0
	tst.w	(a0)+
	move.l	(a0)+,d1	* d1 = original low TPA limit
	move.l	d1,d2
	add.l	(a0),d2		* d2 = original high TPA limit
	move.l	_tpa_lp,d3	* d3 = new low TPA limit
	move.l	_tpa_hp,d4	* d4 = new high TPA limit
	move	#17,d0
	movea.l	4(sp),a0
	move.l	a0,evec_adr	* save exception vector address
init4:
	cmp.l	(a0),d1
	bhi	do_init		* if old exception outside orig TPA, clear it
	cmp.l	(a0),d2
	bls	do_init
* current exception array entry is in original TPA
	cmp.l	(a0),d3
	bhi	dontinit	* if old exception in old TPA but outside new
	cmp.l	(a0),d4		*	TPA, don't clear it
	bls	dontinit
do_init:
	clr.l	(a0)
dontinit:
	tst.l	(a0)+
	dbf	d0,init4
	rts

	.page
exchndl:.equ	*

#ifndef	M68010
	bsr.w	except		*  2	Buserr
excrtn0:
	bsr.w	except		*  3	Addressing error
	bsr.w	except		*  4	Illegal Instruction
#else
	.globl	m68010		*	Note case difference!
m68010:				*	For build process
	bsr.w	berr		*  2	Buserr
excrtn0:
	bsr.w	berr		*  3	Addressing error
	bsr.w	except		*  4	Illegal Instruction
#endif
	bsr.w	except		*  5
	bsr.w	except		*  6
	bsr.w	except		*  7
#ifndef	M68010
	bsr.w	except		*  8
#else				* Privilege violation
	bsr.w	privviol	*  8
#endif
	bsr.w	except		*  9
	bsr.w	except		* 10
	bsr.w	except		* 11
	bsr.w	except		* 12
	bsr.w	except		* 13
	bsr.w	except		* 14
	bsr.w	except		* 15
	bsr.w	except		* 16
	bsr.w	except		* 17
	bsr.w	except		* 18
	bsr.w	except		* 19
	bsr.w	except		* 20
	bsr.w	except		* 21
	bsr.w	except		* 22
	bsr.w	except		* 23
	bsr.w	except		* 24
	bsr.w	except		* 25
	bsr.w	except		* 26
	bsr.w	except		* 27
	bsr.w	except		* 28
	bsr.w	except		* 29
	bsr.w	except		* 30
	bsr.w	except		* 31
	bsr.w	except		* 32
	bsr.w	except		* 33
	bsr.w	except		* 34
	bsr.w	except		* 35
	bsr.w	except		* 36
	bsr.w	except		* 37
	bsr.w	except		* 38
	bsr.w	except		* 39
	.page
#ifdef	M68010
*
*	Here if the exception in question was a buserr/addressing error.
*	We reformat the stack to look like a 68000.
*
*	Entered with a standard 68010 exception stack frame with a return
*	address on top (at 0(sp)).
*
berr:
	move.l	$0(sp),$2a(sp)			*	Move return address
	move.w	$0c(sp),$2e(sp)			*	Move Status word
	andi.w	#7,$2e(sp)			*	Clear all but FC0-2
	move.l	$0e(sp),$30(sp)			*	Copy Fault address
	move.w	$1c(sp),$34(sp)			*	Move IR
	move.w	$4(sp),$36(sp)			*	Move SR
	move.l	$6(sp),$38(sp)			*	Move PC
	move.w	$0a(sp),$3c(sp)			*	Move format word
	adda.l	#$2a,sp				*	Make sp -> new frame
	bra	except				*	Merge
******************************************************************************
*	Here we make up for a faux pas in the C compiler.  Change all        *
*	move from SR instructions ($40CX) to move from CCR ($42CX).          *
*	Precludes executing 68000 programs in ROM on a 68010.                *
*                                                                            *
*	Relies on the fact that the exception PC (Stack offset 0E below)     *
*	points to the instruction on an illegal instruction exception.       *
******************************************************************************
privviol:
	movem.l	d0/a0,-(sp)			*	Save some regs
	move.l	$0e(sp),a0			*	A0 -> Instruction
	move.w	(a0),d0				*	d0 =  Instruction
	andi.w	#$FFC0,d0			*	Mask off <EA> field
	cmpi.w	#$40C0,d0			*	Move from SR?
	bne	notsr				*	No, handle normally
	ori.w	#$0200,(a0)			*	Change to move from CCR
	movem.l	(sp)+,d0/a0			*	Restore regs
	tst.l	(sp)+				*	Pop return address
	rte					*	Try it again
notsr:	movem.l	(sp)+,d0/a0			*	Abandon hope, all ye ..
	.page
#endif
except:
	clr.w	-(sp)
	movem.l	a0/d0,-(sp)	* 10 (11) words now on stack in following order
*				 _______________________________
*				|____________D0.L_______________|
*				|____________A0.L_______________|
*				|____0000______|________________
*				|_______Handler Return__________|
*				If bus error, extra 2 longs are here
*				 ______________
*				|__Status Reg__|________________
*				|_____Exception Return__________|
*				|_(format word)|
	move.l	10(sp),d0	* get return address from above array
	sub.l	#excrtn0,d0	* d0 now has 4 * (encoded excptn nmbr), where
*				  encoded excptn nmbr is in [0..21,22..37]
*					      representing  [2..23,32..47]
	cmpi	#36,d0		* if d0/4 is in [0..9,22..29] then
	ble	chkredir	*     the exception may be redirected
	cmpi	#88,d0
	blt	dfltexc
	cmpi	#116,d0
	bgt	dfltexc
*				in range of redirected exceptions
	subi	#48,d0		* subtract 4*12 to normalize [0..9,22..29]
*							into [0..9,10..17]
chkredir:
	movea.l	evec_adr,a0
	adda	d0,a0		* index into exception vector array
	tst.l	(a0)		* if 00000000, then not redirected
	bne	usrexc
*				not redirected, do default handler
supexc:				* Here for supervisor state
	cmpi	#40,d0
	blt	dfltexc
	addi	#48,d0		* add 4*12 that was sub'd above
dfltexc:
	adda	#14,sp		* throw away 7 words that we added to stack
	asr	#2,d0		* divide d0 by 4
*				now d0 is in [0..21,22..37]
*				to represent [2..23,32..47]
	cmpi	#2,d0		* bus or address error?
	bge	nobusexc
	movem.l	(sp)+,a0-a1	* if yes, throw away 4 words from stack
nobusexc:
	tst.w	(sp)+		* throw away stacked SR
	addi	#2,d0
	cmpi	#23,d0		* get back real excptn nmbr in [2..23,32..47]
	ble	lowexc
	addi	#8,d0
lowexc:	move	d0,-(sp)	* save excptn nmbr
	lea	excmsg1,a0
	bsr	print		* print default exception message
	move	(sp)+,d0
	bsr	prtbyte
	lea	excmsg2, a0
	bsr	print
	move.l	(sp)+,d0
	bsr	prtlong
	lea	excmsg3, a0
	bsr	print
	clr.l	d0
	trap	#2		* warm boot
	rte

usrexc:
* Call user exception handler
* make sure exception information is on his stack
	cmpi	#8,d0		* address or bus error?
	blt	addrexc		* if yes, skip
	btst	#13,14(sp)	* exception occured in user state?
	bne	supexc		*sw if no, go to supervisor handler
	move.l	(a0),10(sp)	* put user handler address on our stack
	move.l	usp,a0		* user stack pointer to a0
	move.l	16(sp),-(a0)	* put exception return on user stack
	move.w	14(sp),-(a0)	* put SR on user stack
	move.l	a0,usp		* update user stack pointer
	movem.l	(sp)+,a0/d0	* restore regs
	move.l	2(sp),8(sp)	* move address of user handler to excptn rtn
#ifdef	M68010
	clr.w	12(sp)		*sw Clear out the format word
#endif
	addq	#6,sp		* clear junk from stack
	andi	#$7fff,(sp)	* clear trace bit
	rte			* go to user handler
addrexc:
	btst	#13,22(sp)	* exception occured in user state?
	bne	supexc		*sw if no, go to supervisor handler
	move.l	(a0),10(sp)	* put user handler address on our stack
	move.l	usp,a0		* user stack pointer to a0
	move.l	24(sp),-(a0)	* put exception return on user stack
	move.w	22(sp),-(a0)	* put SR on user stack
	move.l	18(sp),-(a0)	* put extra 2 longs on user stack
	move.l	14(sp),-(a0)
	move.l	a0,usp		* update user stack pointer
	movem.l	(sp)+,a0/d0	* restore regs
	move.l	2(sp),16(sp)	* move address of user handler to excptn rtn
#ifdef	M68010
	clr.w	20(sp)		*sw Clear format word
#endif
	adda	#14,sp		* clear junk from stack
	andi	#$7fff,(sp)	* clear trace bit
	rte			* go to user handler

	.page
*******************************************************************************
*
*	gouser routine.  This routine performs an RTE to go to the user program
*			 User EPA is passed in A0.L.
*
*******************************************************************************
gouser:
#ifdef	M68010
	clr.w	-(sp)			*	Push format word
#endif
	move.l	a0,-(sp)		*	Push epa
	clr.w	-(sp)			*		  and SR
	rte				*	Do it.  Into user program.
.page
*
*  Subroutines
*

print:
	clr.l	d1
	move.b	(a0)+, d1
	beq	prtdone
	move	#2, d0
	trap	#2
	bra	print
prtdone:
	rts

prtlong:
*  Print d0.l in hex format
	move	d0,-(sp)
	swap	d0
	bsr	prtword
	move	(sp)+,d0

prtword:
*  Print d0.w in hex format
	move	d0,-(sp)
	lsr	#8,d0
	bsr	prtbyte
	move	(sp)+,d0

prtbyte:
*  Print d0.b in hex format
	move	d0,-(sp)
	lsr	#4,d0
	bsr	prtnib
	move	(sp)+,d0

prtnib:
	andi	#$f,d0
	cmpi	#10,d0
	blt	lt10
	addi.b	#'A'-'9'-1,d0
lt10:
	addi.b	#'0',d0
	move	d0,d1
	move	#2,d0
	trap	#2
	rts


	.data

excmsg1:
	.dc.b	13,10,10,'Exception $',0

excmsg2:
	.dc.b	' at user address $',0

excmsg3:
	.dc.b	'.  Aborted.',0


	.bss

evec_adr:
	.ds.l	1

	.end
0

excmsg2:
	.dc.b	' at user address $',0

excmsg3:
	.dc.b	'.  Aborted.',0


	.bss

evec_adr:
	.ds.l	1

	.end
