/****************************************************************
 * TrapIt                                                       *
 * by David M. Balean, 1993                                     *
 *								*
 * This program demonstrates a method of handling CPU           *
 * exceptions from a C program.                                 *
 ****************************************************************/

#include <exec/types.h>
#include <exec/tasks.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>			/* for getreg */
#include <clib/exec_protos.h>

extern char *_ProgramName;

char __stdiowin[] = "CON:0/0/620/240/";
char __stdiov37[] = "/CLOSE";

/* prototypes */

/* various bits of code to create CPU exceptions */
extern VOID address_exc(VOID), illegal_exc(VOID), div0_exc(VOID);
extern VOID chk_exc(VOID),trapv_exc(VOID),privelege_exc(VOID),trace_exc(VOID);
extern VOID A_Line_exc(VOID), F_Line_exc(VOID), trap1_exc(VOID);

VOID ExitInitTrap(VOID);	/* Clean-up function */
VOID (*func[])(VOID);		/* Array of function pointers */
VOID ClearUp(VOID);
VOID (*TrapFunc[])(...);
VOID ElseWhere(char *s);
VOID InLineFunction(VOID);

struct Task	*MyTask, *FindTask();


/*
reg_pc		the return address
reg_CCR		user status
reg_d0...d7	all the data registers
reg_a0...a7	all the address registers
fp0...fp7	all the floating point registers
res_num		the number of times it has been restored, max 0xffffffff
*/

struct TrapEnvironment
	{
	APTR	reg_pc;
	WORD	reg_CCR;
	LONG	reg_d0, reg_d1, reg_d2, reg_d3, reg_d4, reg_d5, reg_d6, reg_d7;
	LONG	reg_a0, reg_a1, reg_a2, reg_a3, reg_a4, reg_a5, reg_a6, reg_a7;
	LONG	fp0[3], fp1[3], fp2[3], fp3[3], fp4[3], fp5[3], fp6[3], fp7[3];
	ULONG	res_mum;
	};

/***
 NOTE:  The FPCP has more registers than this! Probably unimportant
	There are also:
		 FPCR (32 bit floating point control register)
		 FPSR (32 bit floating point status register)
		 FPIAR (32 bit floating point instruction address register)
***/


struct TrapIt
	{
	ULONG			trapnum;
	ULONG			ilnumber;
	ULONG			numcalls;
	APTR			oldtrap;
	APTR			ilfunc;

/* These are the available functions */
	UWORD			trapit[63];	/* should be hidden from user */
	UWORD			restore[2];
	UWORD			restore_a0[31];
	UWORD			save_env[13];
	UWORD			save_env_a0[39];
	UWORD			set_init_trap[10];
	UWORD			set_iltrap[34];
	UWORD			set_ilnumber[7];
	UWORD			clear_iltrap[13];
	UWORD			clear_init_trap[13];
	UWORD		 	free_trap[23];

/* The initial environment and the inline environment */
 	struct TrapEnvironment	initenv;
	struct TrapEnvironment	inlineenv;

	};

static struct TrapIt MyTrap =
	{
	0,	/* errnum	ds.l 1	trap number goes here		*/
	0,	/* ilnumber	ds.l 1	for user use e.g. line number	*/
	0,	/* numcalls	ds.l 1	number of times inline called	*/
	NULL,	/* oldtrap	ds.l 1  old pointer, filled in later	*/
	NULL,	/* ilfunc	ds.l 1  pointer to user inline function	*/



	0x0C97, 0x0000, 0x0040,	/* trapit	cmp.l	#64,(a7)	*/
	0x6410,			/*		bcc.b	.NotTrapped	*/
	0x0C97, 0x0000, 0x0019,	/*		cmp.l	#25,(a7)	*/
	0x650E,			/*		bcs.b	.Trapped	*/
	0x0C97, 0x0000, 0x0020,	/*		cmp.l	#32,(a7)	*/
	0x6406,			/*		bcc.b	.Trapped	*/
	0x2F3A, 0xFFDE,		/* .NotTrapped	move.l oldtrap(pc),-(a7)*/
	0x4E75,			/*		rts			*/

	0x201F,			/* .Trapped	move.l	(a7)+,d0	*/
	0x41FA, 0xFFCA,		/*		lea.l	errnum(pc),a0	*/
	0x2080,			/* 		move.l	d0,(a0)		*/

	0x2078, 0x0004,		/*		movea.l	(4).w,a0	*/
	0x3228, 0x0128,		/*		move.w	$128(a0),d1	*/
	0x0281, 0x0000, 0x000F,	/*		and.l	#$0f,d1		*/
	0x660C,			/* 		bne.b   .NOT68000	*/

	0xB07C, 0x0004,		/* .MR68000	cmp.w   #4,d0		*/
	0x6402,			/*		bcc.b   .NOTaddress	*/
	0x504F,			/* 		addq.w  #8,a7		*/

	0x7206,			/* .NOTaddress	moveq.l	#6,d1		*/
	0x6012,			/*		bra.b	.donetrap	*/

	0x41FA, 0x006C,		/* .NOT68000	lea.l	Xtable(pc),a0	*/
	0x322F, 0x0006,		/*		move.w	$06(a7),d1	*/
	0x0241, 0xF000,		/*		andi.w	#$f000,d1	*/
	0xE959,			/*		rol.w	#4,d1		*/
	0xD0C1,			/*		add.w	d1,a0		*/
	0x1210,			/*		move.b	(a0),d1		*/
	
	0x3017,			/* .donetrap	move.w	(a7),d0		*/
	0xDEC1,			/*		add.w	d1,a7		*/

	0x0240, 0x5FFF,		/*		andi.w	#$5fff,d0	*/


	0x46C0,			/*		move.w	d0,SR		*/

	0x203A, 0xFF9C,		/*		move.l	ilfunc(pc),d0	*/
	0x6714,			/*		beq.b	.initenv	*/

	0x43FA, 0xFF8E,		/*		lea.l	numcalls(pc),a1	*/
	0x5291,			/*		addq.l	#1,(a1)		*/
	0x6602,			/*		bne.b	.calls_ok	*/

	0x5391,			/*		subq.l	#1,(a1)		*/

	0x2040,			/* .calls_ok	movea.l	d0,a0		*/
	0x4E90,			/*		jsr	(a0)		*/

	0x41FA, 0x0226,		/*		lea.l   inlineenv(pc),a0*/
	0x600A,			/*		bra.b	restore_a0	*/


	0x41FA, 0x0176,		/* .initenv	lea.l	initenv(pc),a0	*/
	0x6004,			/*		bra.b	restore_a0	*/

/* trapit = 63 WORDS */

	0x206F, 0x0004,		/* restore	movea.l	4(a7)+,a0	*/

/* resore = 2 WORDS */

	0x2278, 0x0004,		/* restore_a0	movea.l	(4).w,a1	*/

	0x0829, 0x0004, 0x0129,	/*		btst.b	#4,$129(a1)	*/
	0x6706,			/*		beq.b	.skip		*/

	0xF228, 0xD0FF, 0x0046,	/*	fmovem.x reg_fp0(a0),fp0-fp7	*/

	0x2268, 0x0042,		/* .skip	move.l	reg_a7(a0),a1	*/
	0x2290,			/*		move.l	(a0),(a1)	*/

	0x52A8,0x00A6,		/*		addq.l	#1,res_num(a0)	*/
	0x6604,			/*		bne.b	.res_num_ok	*/

	0x53A8,0x00A6,		/*		subq.l	#1,res_num(a0)	*/

	0x44E8, 0x0004,		/* .res_num_ok	move.w	reg_CCR(a0),CCR	*/
	0x4CE8, 0xFFFF, 0x0006,	/*       movem.l reg_d0(a0),d0-d7/a0-a7 */
	0x4E75,			/*		rts			*/

	0x0808,			/* Xtable	dc.b	8,8		*/
	0x0C00,			/*		dc.b	12,0		*/
	0x0000,			/*		dc.b	0,0		*/
	0x0000,			/*		dc.b	0,0		*/
	0x3A14,			/*		dc.b	58,20		*/
	0x205C,			/*		dc.b	32,92		*/
	0x0000,			/*		dc.b	0,0		*/
	0x0000,			/*		dc.b	0,0		*/

/* restore_a0 = 31 WORDS */

	0x48E7, 0x0080,		/* save_env	movem.l	a0,-(a7)	*/
	0x4CEF, 0x0100, 0x0008,	/*		movem.l	4+4(a7),a0	*/
	0x610E,			/*		bsr.b	save_env_a0	*/

	0x216F, 0x0004, 0x0000,	/*		move.l	4(a7),reg_pc(a0)*/
	0x44E8, 0x0004,		/*		move.w	reg_CCR(a0),CCR	*/
	0x205F,			/*		movea.l	(a7)+,a0	*/
	0x4E75,			/*		rts			*/

/* save_env = 13 WORDS */

	0x48E7, 0xC042,		/*save_env_a0 movem.l  d0-d1/a1/a6,-(a7)*/
	0x48E7, 0x0080,		/*		movem.l	a0,-(a7)	*/
	0x2C78, 0x0004,		/*		movea.l	(4).w,a6	*/
	0x4EAE, 0xFDF0,		/*		jsr	$fffffdf0(a6)	*/
	0x205F,			/*		movea.l	(a7)+,a0	*/

	0x3140, 0x0004,		/*		move.w	d0,reg_CCR(a0)	*/
	0x4CDF, 0x4203,		/*	movem.l	(a7)+,d0-d1/a1/a6	*/

	0x2097,			/*		move.l	(a7),(a0)	*/
	0x48E8, 0x00FF, 0x0006,	/*		movem.l	d0-d7,reg_d0(a0)*/
	0x216F, 0x0004, 0x0026,	/*		move.l	4(a7),reg_a0(a0)*/
	0x48E8, 0xFE00, 0x002A,	/*		movem.l	a1-a7,reg_a1(a0)*/

	0x50A8, 0x0042,		/*		addq.l	#8,reg_a7(a0)	*/

	0x2278, 0x0004,		/*		movea.l	(4).w,a1	*/
	0x0829, 0x0004, 0x0129,	/*		btst.b	#4,$129(a1)	*/
	0x6706,			/*		beq.b	.skip		*/

	0xF228, 0xF0FF, 0x0046,	/*        fmovem.x fp0-fp7,reg_fp0(a0)	*/

	0x44E8, 0x0004,		/* .skip	move.w	reg_CCR(a0),CCR	*/
	0x2268, 0x002A,		/*		movea.l	reg_a1(a0),a1	*/
	0x4E75,			/*		rts			*/

/* save_env_a0 = 39 WORDS */


	0x48E7, 0x0080,		/* set_init_trap movem.l a0,-(a7)	*/
	0x41FA, 0x00C2,		/*		lea.l	initenv(pc),a0	*/
	0x61A8,			/*		bsr.b	save_env_a0	*/

	0x20AF, 0x0008,		/*		move.l	4+4(a7),(a0)	*/
	0x6126,			/*		bsr.b	put_trap	*/
	0x205F,			/*		movea.l	(a7)+,a0	*/
	0x4E75,			/*		rts			*/



/* set_init_trap = 10 WORDS */

	0x48E7, 0x0080,		/* set_iltrap	movem.l	a0,-(a7)	*/
	0x41FA, 0x0158,		/*		lea.l	inlineenv(pc),a0*/
	0x6194,			/*		bsr.b	save_env_a0	*/

	0x20AF, 0x0004,		/*		move.l	4(a7),(a0)	*/
	0x41FA, 0xFEB0,		/*		lea.l	ilfunc(pc),a0	*/
	0x20AF, 0x0008,		/*		move.l	4+4(a7),(a0)	*/
	0x41FA, 0xFEA0,		/*		lea.l	numcalls(pc),a0	*/
	0x4290,			/*		clr.l	(a0)		*/
	0x6104,			/*		bsr.b	put_trap	*/
	0x205F,			/*		movea.l	(a7)+,a0	*/
	0x4E75,			/*		rts			*/

/* set_iltrap = 17 WORDS */

	0x2F09,			/* put_trap	move.l	a1,-(a7)	*/
	0x43FA, 0xFE96,		/*		lea.l	oldtrap(pc),a1	*/
	0x4A91,			/*		tst.l	(a1)		*/
	0x6614,			/*		bne.b	.trapped	*/

	0x2078, 0x0004,		/*		movea.l	(4).w,a0	*/
	0x2068, 0x0114,		/*		movea.l	$114(a0),a0	*/
	0x41E8, 0x0032,		/*		lea.l	$32(a0),a0	*/

	0x2290,			/*		move.l  (a0),(a1)	*/
	0x43FA, 0xFE88,		/*		lea.l	trapit(pc),a1	*/
	0x2089,			/*		move.l	a1,(a0)		*/

	0x225F,			/* .trapped	move.l	(a7)+,a1	*/
	0x4E75,			/*		rts			*/

/* put_trap = 17 WORDS */
/* set_iltrap + put_trap = 34 WORDS */


	0x2F08,			/* set_ilnumber	move.l	a0,-(a7)	*/
	0x41FA, 0xFE6C,		/*		lea.l	ilnumber(pc),a0	*/
	0x20AF, 0x0008,		/*		move.l  4+4(a7),(a0)	*/
	0x205F,			/* 		move.l	(a7)+,a0	*/
	0x4E75,			/*		rts			*/

/* set_ilnumber = 7 WORDS */

	0x2F08,			/* clear_iltrap	move.l	a0,-(a7)	*/
	0x41FA, 0x005E,		/*		lea.l	initenv(pc),a0	*/
	0x4A90,			/*		tst.l	(a0)		*/
	0x6606,			/*		bne.b	.il_only	*/

	0x6100, 0x0028,		/*		bsr.w	free_trap	*/
	0x6006,			/*		bra.b	.done		*/

	0x41FA, 0xFE5C,		/* il_only	lea.l	ilfunc(pc),a0	*/
	0x4290,			/*		clr.l	(a0)		*/

	0x205F,			/* .done	movea.l	(a7)+,a0	*/
	0x4E75,			/*		rts			*/

/* clear_iltrap = 13 WORDS */


	0x2F08,			/* clear_init_trap move.l a0,-(a7)	*/
	0x41FA, 0xFE50,		/*		lea.l	ilfunc(pc),a0	*/
	0x4A90,			/*		tst.l	(a0)		*/
	0x6606,			/*		bne.b	.init_only	*/

	0x6100, 0x000E,		/*		bsr.w	free_trap	*/
	0x6006,			/*		bra.b	.done		*/


	0x41FA, 0x0036,		/* .init_only	lea.l	initenv(pc),a0	*/
	0x4290,			/*		clr.l	(a0)		*/

	0x205F,			/* .done	move.l	(a7)+,a0	*/
	0x4E75,			/*		rts			*/

/* clear_init_trap = 13 WORDS */


	0x48E7, 0x00C0,		/* free_trap	movem.l	a0-a1,-(a7)	*/
	0x41FA, 0xFE34,		/*		lea.l	ilfunc(pc),a0	*/
	0x4290,			/*		clr.l	(a0)		*/

	0x41FA, 0x0022,		/*		lea.l	initenv(pc),a0	*/
	0x4290,			/*		clr.l	(a0)		*/

	0x2078, 0x0004,		/*		movea.l	(4).w,a0	*/
	0x2068, 0x0114,		/*		movea.l	$114(a0),a0	*/
	0x41E8, 0x0032,		/*		lea.l	50(a0),a0	*/
	0x43FA, 0xFE18,		/*		lea.l	oldtrap(pc),a1	*/

	0x4A91,			/*		tst.l	(a1)		*/
	0x6704,			/*		beq.b	.quit		*/

	0x2091,			/*		move.l	(a1),(a0)	*/
	0x4291,			/*		clr.l	(a1)		*/

	0x4CDF, 0x0300,		/* .quit	movem.l	(a7)+,a0-a1	*/
	0x4E75,			/*		rts			*/


/* free_trap = 23 WORDS */

/* The rest is not initialized, i.e. zero */

				/* initenv	ds.b	sizeof_env	*/
				/* inlineenv	ds.b	sizeof_env	*/

	};







VOID NoError(VOID)
{
printf("\nNo Error...\n");
}

VOID BusError(VOID)
{
printf("\nSorry, can't create exception 2.\n");
}


#define NUMFUNCS 13


VOID (*func[NUMFUNCS])(VOID) =
	{
	(VOID (*)())NoError,
	(VOID (*)())NoError,
	(VOID (*)())BusError,
	(VOID (*)())&address_exc,
	(VOID (*)())&illegal_exc,
	(VOID (*)())&div0_exc,
	(VOID (*)())&chk_exc,
	(VOID (*)())&trapv_exc,
	(VOID (*)())&privelege_exc,
	(VOID (*)())&trace_exc,
	(VOID (*)())&A_Line_exc,
	(VOID (*)())&F_Line_exc,
	(VOID (*)())&trap1_exc,
	};





/* Trapit functions */

#define NUMTRAPFUNCS 9

VOID (*TrapFunc[NUMTRAPFUNCS])(...) =
	{
	(VOID (*)(struct TrapEnvironment *))MyTrap.restore,  /* restore env */

	(VOID (*)(struct TrapEnvironment))MyTrap.save_env,	/* save env */

	(VOID (*)(APTR))MyTrap.set_init_trap,	/* set initial trap	*/

	(VOID (*)(APTR))MyTrap.set_iltrap,	/* set inline trap	*/

	(VOID (*)(ULONG))MyTrap.set_ilnumber,	/* set user trap number	*/

	(VOID (*)(VOID))MyTrap.clear_iltrap,	/* clear inline trap	*/

	(VOID (*)(VOID))MyTrap.clear_init_trap,	/* clear initial trap	*/

	(VOID (*)(VOID))MyTrap.free_trap	/* free the whole trap	*/
	};

#define RESTORE_ENV(x)		(*TrapFunc[0])(x)

#define SAVE_ENV(x)		(*TrapFunc[1])(x)

#define SET_INIT_TRAP(x)	(*TrapFunc[2])(x) 

#define SET_ILTRAP(x)		(*TrapFunc[3])(x);\
if(MyTrap.numcalls==0){

#define ILTRAP			}else{

#define END_ILTRAP		}

#define SET_TRAPNUM(x)		(*TrapFunc[4])(x)

#define RESET_ILTRAP(x)		}SET_ILTRAP(x)

#define CLEAR_ILTRAP()		(*TrapFunc[5])()

#define CLEAR_INIT_TRAP()	(*TrapFunc[6])()

#define FREE_TRAP()		(*TrapFunc[7])()






static struct TrapEnvironment TestEnv;


VOID main(VOID)
{
int n;

SET_INIT_TRAP(&ExitInitTrap);

printf("WARNING: I have got A-Line Exception working on standard 68000 only.\n");
printf("     It gurus on my Derringer accelerated A2000HD (68030/68881).\n\n");

printf("Testing ILTRAP\n");

SET_ILTRAP(&InLineFunction);


SAVE_ENV(&TestEnv);


printf(" 0    No Error...          0\n");
printf(" 1    No Error...          1\n");
printf(" 2    Bus error            2   Can't create this one!\n");
printf(" 3    Address error        3\n");
printf(" 4    Illegal instruction  4\n");
printf(" 5    Divide by zero error 5\n");
printf(" 6    chk exception        6\n");
printf(" 7    trapv exception      7\n");
printf(" 8    Privelege violation  8\n");
printf(" 9    trace exception      9\n");
printf(" 10   1010 (A) emulation  10   (WARNING: possible Guru exception #3\n");
printf(" 11   1111 (F) emulation  11\n");
printf(" 33   Trap #1  ( = $21)   33\n");
printf(" 100  Restore Environment to before this...\n");
printf(" 101  Restore Environment from elsewhere...\n");
printf("\n                 WHICH: ");

scanf("%ld",&n);

if (n == 100)
/* You can do this as many times as you like */
	RESTORE_ENV(&TestEnv);

if (n == 101)
		ElseWhere("We got here");

if (n==33) n = 12;
else if (n==12) n = 33;

SET_TRAPNUM(n<<2);

if ((n>=0) && (n<NUMFUNCS))
		(*func[n])();
ILTRAP

printf("<< Passed over the error! >>\n");

END_ILTRAP

printf("Now testing INIT_TRAP\n");

CLEAR_ILTRAP();

RESTORE_ENV(&TestEnv);

printf("---- ALL DONE ---- (don't know how you got here!)\n");

ClearUp();
}


/* Function called by SET_ILTRAP if a CPU exception occurs */

VOID InLineFunction(VOID)
{
printf("INLINE TRAP:\n");
printf("Clever me! I have trapped exception number %ld\n",MyTrap.trapnum);
printf("The user number was %ld\n\n",MyTrap.ilnumber);
}


/* To test a restore from way off! */

VOID ElseWhere(char *s)
{
printf("ElseWhere: %s!\n",s);
RESTORE_ENV(&TestEnv);
}




/* Free memory, close up everything and exit... */

VOID ClearUp(VOID)
{
FREE_TRAP();
printf("Press a key or WINDOWCLOSE gadget to quit");
fseek(stdin, 0, SEEK_END);
getch();
exit(0);				/* exit(0) will fix stack */
}


/* Our Exception Code Exits To Here (Init_Trap) */

VOID ExitInitTrap(VOID)
{
printf("INITIAL TRAP\n");
printf("Clever me! I have trapped exception number %ld\n\n",MyTrap.trapnum);
ClearUp();
}



/* << END OF FILE >> */
