 /*
 |  First port of call in C for interrupts
*/

#include <sys/types.h>
#include <sys/hardware.h>
#include <sys/unix.h>
#include <sys/extern.h>

/* Level 1 is serial TX or disk block done */
void int_handle1( level )
int	level;
{
	uint16	reqs = *INTREQR;
	uint16	clear = 0x0000;

	if( reqs & INT_TBE )
		clear |= INT_TBE;

	if( reqs & INT_DSKBLK )
	{
		clear |= INT_DSKBLK;
		fdd_blockdone();
	}

	if( reqs & INT_SOFT )
		clear |= INT_SOFT;

	*INTREQ = clear;
	return;
}

/* Level 2 is CIA-A or expansion port */
void int_handle2( level )
int	level;
{
	uint16	reqs = *INTREQR;
	uint16	clear = 0x0000;

	if( reqs & INT_PORTS )
	{
		clear |= INT_PORTS;
		termKeyInt();
	}

	*INTREQ = clear;
	return;
}

/* Level 3 is copper, vertical blank or blitter */
void int_handle3( level )
int	level;
{
	uint16	reqs = *INTREQR;
	uint16	clear = 0x0000;

	if( reqs & INT_COPER )
		clear |= INT_COPER;

	if( reqs & INT_VERTB )
	{
		/* Calling clk_int is a special case because we're
		   possibly going to call swapout() and therefore must
		   be stoppable and restartable purely from usp */
		*INTREQ = clear | INT_VERTB;
		call_clock();
		/* We won't be back here */
		panic("clock: returned to isr");
	}
	
	*INTREQ = clear;
	return;
}

/* Level 4 is the audio hardware */
void int_handle4( level )
int	level;
{
	uint16	reqs = *INTREQR;
	uint16	clear = 0x0000;

	if( reqs & INT_AUD0 )
		clear |= INT_AUD0;
	if( reqs & INT_AUD1 )
		clear |= INT_AUD1;
	if( reqs & INT_AUD2 )
		clear |= INT_AUD2;
	if( reqs & INT_AUD3 )
		clear |= INT_AUD3;

	*INTREQ = clear;
	return;
}

/* Level 5 is serial RX and disk sync */
void int_handle5( level )
int	level;
{
	uint16	reqs = *INTREQR;
	uint16	clear = 0x0000;

	if( reqs & INT_RBF )
		clear |= INT_RBF;

	if( reqs & INT_DSKSYN )
		clear |= INT_DSKSYN;

	*INTREQ = clear;
	return;
}

/* Level 6 is CIA-B, expansion port or internal(?) */
void int_handle6( level )
int	level;
{
	uint16	reqs = *INTREQR;
	uint16	clear = 0x0000;

	if( reqs & INT_EXTER )
		clear |= INT_EXTER;

	if( reqs & INT_INTEN )
		clear |= INT_INTEN;

	*INTREQ = clear;
	return;
}

/* Level 7 is, presumably some additional hardware */
void int_handle7( level )
int	level;
{
	uint16	reqs = *INTREQR;
	uint16	clear = 0x0000;

	*INTREQ = clear;
	return;
}

char *retaddr;

/* First port of exception call */
void except( context )
char	*context;
{
	uint16	form = *(uint16*)(((int)context)+70);
	int	num = (form&1020)>>2;
	int	signum = 0;
	void	dumpexcept();

	/*kprintf("-=Exception %i (%i) lc:%i pc:%x ra:%x=-\n",num,udata.u_ptab->p_pid,udata.u_callno,*(char**)(((int)context)+66),retaddr);*/

	if( udata.u_insys != 0 )
		dumpexcept( num, context );

	/* Will be zeroed on exit, or cause dump on repeated exception */
	udata.u_insys = 2;

	switch( num )
	{
		case X_BUSERR:
			signum = SIGBUS;
			break;
		case X_ADDERR:
			signum = SIGADD;
			break;
		case X_ILLI:
		case X_CHK:
		case X_TRAPV:
		case X_PRIV:
		case X_ALINE:
			signum = SIGILL;
			break;
		case X_DIV0:
			signum = SIGINTE;
			break;
		case X_TRACE:
			signum = SIGTRAP;
			break;
		case X_FLINE:
			signum = SIGFPE;
			break;
	}

	if( signum )
		sendsig( udata.u_ptab, signum );
	else
		dumpexcept( num, context );

	/* Won't return if signal causes exit */
	chksigs();

	/* Won't return if signal is handled */
	calltrap( context, 0 );

	/* Comes here only when signal is ignored (A Bad Thing) */
	leave_kernel( context, 0 );
}

extern char	*SStack;

/* Process exception handler; prints some possibly useful info */
void dumpexcept( num, context )
int	num;
char	*context;
{
	char	*name="        ";
	int	i;
	int	*p;
	uint16	form = *(uint16*)(((int)context)+70),
		sr   = *(uint16*)(((int)context)+64);
	char	*pc  = *(char**)(((int)context)+66);
	
	di();
	kprintf("\n----====Exception %i====----\n",num);
	kprintf("pc:%x  sr:%x  format:%x\n",pc,(int)sr,(int)form);
	bcopy( udata.u_name, name, 8 );
	kprintf("Process:%i (%s)\n",((int)udata.u_ptab-(int)ptab)/sizeof(p_tab),name);
	kprintf("Insys:%i ",udata.u_insys);
	kprintf("Callno:%i  Errno:%i  Retval:%i\n",udata.u_callno,udata.u_error,udata.u_retval);
	kprintf("Arg0:%i, Arg1:%i, Arg2:%i, Arg3:%i\n",udata.u_argn,udata.u_argn1,udata.u_argn2,udata.u_argn3);
	kprintf("Swaptype:%i  Context:%x  ISP:%xi \n",udata.u_swaptype,udata.u_sp,udata.u_ptab->p_isp);
	kprintf("isp:%x, msp:%x, SStack:%x\n",get_isp(),get_msp(),&SStack);	
	p = (int*)udata.u_sp;
	kprintf("context:%x  ucp:%x\n",p,*p);
	p++;
	for(i=0;i<8;i++)
		kprintf("d%i:%x\t",i,*p++);
	kprintf("\n");
	for(i=0;i<7;i++)
		kprintf("a%i:%x\t",i,*p++);
	kprintf("\nsr:%x\tpc:%x\tform:%x\n",*(uint16*)(((char*)udata.u_sp)+64),*(char**)(((char*)udata.u_sp)+66),*(uint16*)(((char*)udata.u_sp)+70) );

	kprintf("retaddr:%x\n",retaddr);

	kprintf("pid:%i, stat:%i, uid:%i\n",udata.u_ptab->p_pid,udata.u_ptab->p_status,udata.u_ptab->p_uid );

	kprintf("Ticks: run:%i, max:%i\n",runticks,MAXTICKS);
	
	kprintf("---Halting----");

	i=0;
	while(++i);
		i--;
}
