
#include "stdio.h"
#include <tamtypes.h>
#include <kernel.h>
#include "exception.h"
#include "system.h"
#include "pad.h"

////////////////////////////////////////////////////////////////////////
typedef union 
{
    unsigned int  uint128 __attribute__(( mode(TI) ));
    unsigned long uint64[2];
} eeReg __attribute((packed));

////////////////////////////////////////////////////////////////////////
// Prototypes
void TrapException(int cause, int badvaddr, int status, int epc, eeReg *regs);

extern void ExceptionHandler(void);

////////////////////////////////////////////////////////////////////////
static const unsigned char regName[32][5] =
{
    "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
    "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", 
    "t8", "t9", "s0", "s1", "s2", "s3", "s4", "s5", 
    "s6", "s7", "k0", "k1", "gp", "sp", "fp", "ra"
};

static char codeTxt[14][24] = 
{
    "Interrupt", "TLB modification", "TLB load/inst fetch", "TLB store",
    "Address load/inst fetch", "Address store", "Bus error (instr)", 
    "Bus error (data)", "Syscall", "Breakpoint", "Reserved instruction", 
    "Coprocessor unusable", "Arithmetic overflow", "Trap"
};

char _exceptionStack[8*1024] __attribute__((aligned(16)));
eeReg _savedRegs[32+4] __attribute__((aligned(16)));


////////////////////////////////////////////////////////////////////////
// The 'ee exception handler', only dumps registers to console or screen atm
void
TrapException(int cause, int badvaddr, int status, int epc, eeReg *regs)
{
	PadButtonStatus *p;
	int code,i;

	FlushCache(0);
	FlushCache(2);

	code = cause & 0x7c;

	pb_wait_for_vbl();
	pb_fill(0,0,640,450,0);
	while(pb_finished());
	pb_wait_for_vbl();
	pb_fill(0,0,640,450,0);
	while(pb_finished());
	pb_erase_text_screen();
	
    	debugPrint("Exception detected:\n%s\n", codeTxt[code>>2]);
	debugPrint(	"Cause    %08x\n"
			"BadVAddr %08x\n"
			"Status   %08x\n"
			"EPC      %08x (try 'addr2line -e prog.elf %x')\n",
			cause, badvaddr, status, epc, epc);

	debugPrint("Press X for next page\n");

	pb_draw_text_screen();
	while(pb_finished());
	pb_wait_for_vbl();
	pb_fill(0,0,640,450,0);
	
	while((PAD_Read(0,0,&p)&PAD_CROSS)); while((PAD_Read(0,0,&p)&PAD_CROSS)==0);
	debugPrint("\n");

	for(i = 0; i < 32; i++) 
	{
        	debugPrint("%4s: %016lX%016lX\n",
                   regName[i],    regs[i].uint64[1],    regs[i].uint64[0]);

		if (i%11==10)
		{
			debugPrint("Press X for next page\n");

			pb_draw_text_screen();
			while(pb_finished());
			pb_wait_for_vbl();
			pb_fill(0,0,640,450,0);
			
			while((PAD_Read(0,0,&p)&PAD_CROSS)); while((PAD_Read(0,0,&p)&PAD_CROSS)==0);
			debugPrint("\n");
		}
	}

	debugPrint("Press X for console reboot\n");
	
	pb_draw_text_screen();
	while(pb_finished());
	pb_wait_for_vbl();
	pb_fill(0,0,640,450,0);
	
	while((PAD_Read(0,0,&p)&PAD_CROSS)); while((PAD_Read(0,0,&p)&PAD_CROSS)==0);

	Exit(0);
}



////////////////////////////////////////////////////////////////////////
// Installs ee exception handlers for the 'usual' exceptions and iop
// exception callback
void
installExceptionHandlers(void)
{
	int i;
	
	// Skip exception #8 (syscall) & 9 (breakpoint)
	for (i = 1; i < 4; i++) {
        	SetVTLBRefillHandler(i, ExceptionHandler);
	}
	for (i = 4; i < 8; i++) {
		SetVCommonHandler(i, ExceptionHandler);
	}
	for (i = 10; i < 14; i++) {
		SetVCommonHandler(i, ExceptionHandler);
	}
}

