2016-07-06 11:28:51 +02:00
|
|
|
//---
|
|
|
|
//
|
|
|
|
// gint core module: interrupt handler
|
|
|
|
//
|
|
|
|
// Central point of the library. Controls the interrupt handler and
|
|
|
|
// defines a few functions to configure callbacks for some interrupts.
|
|
|
|
//
|
|
|
|
//---
|
|
|
|
|
2016-07-25 09:04:22 +02:00
|
|
|
#include <internals/gint.h>
|
2016-05-05 11:49:05 +02:00
|
|
|
#include <gint.h>
|
|
|
|
#include <mpu.h>
|
2016-05-05 22:33:15 +02:00
|
|
|
#include <stddef.h>
|
2016-05-05 11:49:05 +02:00
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
new_vbr,
|
|
|
|
sys_vbr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
// Local functions.
|
|
|
|
//---
|
|
|
|
|
|
|
|
/*
|
|
|
|
gint_setup()
|
|
|
|
Configures interrupt priorities and some parameters to allow gint to
|
|
|
|
take control of the interrupt flow.
|
|
|
|
*/
|
|
|
|
static void gint_setup(void)
|
|
|
|
{
|
|
|
|
if(isSH3())
|
|
|
|
gint_setup_7705();
|
|
|
|
else
|
|
|
|
gint_setup_7305();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
gint_stop()
|
|
|
|
Un-configures the interrupt flow to give back the interrupt control to
|
|
|
|
the system.
|
|
|
|
*/
|
|
|
|
static void gint_stop(void)
|
|
|
|
{
|
|
|
|
if(isSH3())
|
|
|
|
gint_stop_7705();
|
|
|
|
else
|
|
|
|
gint_stop_7305();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
// Public API.
|
|
|
|
//---
|
|
|
|
|
|
|
|
/*
|
|
|
|
gint_systemVBR()
|
|
|
|
Returns the vbr address used by the system (saved when execution
|
|
|
|
starts).
|
|
|
|
*/
|
2016-07-06 11:28:51 +02:00
|
|
|
inline unsigned int gint_systemVBR(void)
|
2016-05-05 11:49:05 +02:00
|
|
|
{
|
|
|
|
return sys_vbr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
gint_init()
|
|
|
|
Initializes gint. Loads the interrupt handler into the memory and sets
|
|
|
|
the new vbr address.
|
|
|
|
*/
|
|
|
|
void gint_init(void)
|
|
|
|
{
|
|
|
|
// Linker script symbols -- gint.
|
|
|
|
extern unsigned int
|
|
|
|
gint_vbr,
|
|
|
|
gint_data,
|
|
|
|
bgint, egint;
|
|
|
|
|
|
|
|
unsigned int *ptr = &bgint;
|
|
|
|
unsigned int *src = &gint_data;
|
|
|
|
|
2016-07-14 21:10:51 +02:00
|
|
|
// This initialization routine is usually called before any
|
|
|
|
// constructor. We want to ensure that the MPU type is detected, but
|
|
|
|
// mpu_init() hasn't been called yet.
|
|
|
|
mpu_init();
|
|
|
|
|
2016-05-05 11:49:05 +02:00
|
|
|
// Loading the interrupt handler into the memory.
|
|
|
|
while(ptr < &egint) *ptr++ = *src++;
|
|
|
|
|
|
|
|
sys_vbr = gint_getVBR();
|
|
|
|
new_vbr = (unsigned int)&gint_vbr;
|
|
|
|
|
|
|
|
gint_setVBR(new_vbr, gint_setup);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
gint_quit()
|
|
|
|
Stops gint. Restores the system's configuration and vbr address.
|
|
|
|
*/
|
|
|
|
void gint_quit(void)
|
|
|
|
{
|
|
|
|
gint_setVBR(sys_vbr, gint_stop);
|
|
|
|
}
|
2016-07-25 09:04:22 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//---
|
|
|
|
// VBR space.
|
|
|
|
//---
|
|
|
|
|
|
|
|
#include <display.h>
|
|
|
|
#define print(str, x, y) dtext(str, 6 * (x) - 5, 8 * (y) - 7)
|
|
|
|
#define hexdigit(n) ((n) + '0' + 39 * ((n) > 9))
|
|
|
|
|
|
|
|
void hex(unsigned int x, int digits, char *str)
|
|
|
|
{
|
|
|
|
str[0] = '0';
|
|
|
|
str[1] = 'x';
|
|
|
|
str[digits + 2] = 0;
|
|
|
|
|
|
|
|
while(digits)
|
|
|
|
{
|
|
|
|
str[digits + 1] = hexdigit(x & 0xf);
|
|
|
|
x >>= 4;
|
|
|
|
digits--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
gint_exc()
|
|
|
|
Handles exceptions.
|
|
|
|
*/
|
|
|
|
void gint_exc(void)
|
|
|
|
{
|
|
|
|
volatile unsigned int *expevt = gint_reg(Register_EXPEVT);
|
|
|
|
volatile unsigned int *tea = gint_reg(Register_TEA);
|
|
|
|
unsigned int spc;
|
|
|
|
char str[11];
|
|
|
|
|
|
|
|
text_configure_default();
|
|
|
|
|
|
|
|
__asm__("\tstc spc, %0" : "=r"(spc));
|
|
|
|
|
|
|
|
dclear();
|
|
|
|
print("Exception raised!", 3, 1);
|
|
|
|
dreverse_area(0, 0, 127, 8);
|
|
|
|
print(gint_strerror(0), 2, 3);
|
|
|
|
|
|
|
|
print("expevt", 2, 4);
|
|
|
|
hex(*expevt, 3, str);
|
|
|
|
print(str, 16, 4);
|
|
|
|
|
|
|
|
print("pc", 2, 5);
|
|
|
|
hex(spc, 8, str);
|
|
|
|
print(str, 11, 5);
|
|
|
|
|
|
|
|
print("tea", 2, 6);
|
|
|
|
hex(*tea, 8, str);
|
|
|
|
print(str, 11, 6);
|
|
|
|
|
|
|
|
print("Please reset.", 2, 7);
|
|
|
|
dupdate();
|
|
|
|
while(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
gint_tlb()
|
|
|
|
Handles TLB misses.
|
|
|
|
*/
|
|
|
|
void gint_tlb(void)
|
|
|
|
{
|
|
|
|
volatile unsigned int *expevt = gint_reg(Register_EXPEVT);
|
|
|
|
volatile unsigned int *tea = gint_reg(Register_TEA);
|
|
|
|
unsigned int spc;
|
|
|
|
char str[11];
|
|
|
|
|
|
|
|
text_configure_default();
|
|
|
|
|
|
|
|
__asm__("\tstc spc, %0" : "=r"(spc));
|
|
|
|
|
|
|
|
dclear();
|
|
|
|
print("TLB error!", 6, 1);
|
|
|
|
dreverse_area(0, 0, 127, 8);
|
|
|
|
print(gint_strerror(1), 2, 3);
|
|
|
|
|
|
|
|
print("expevt", 2, 4);
|
|
|
|
hex(*expevt, 3, str);
|
|
|
|
print(str, 16, 4);
|
|
|
|
|
|
|
|
print("pc", 2, 5);
|
|
|
|
hex(spc, 8, str);
|
|
|
|
print(str, 11, 5);
|
|
|
|
|
|
|
|
print("tea", 2, 6);
|
|
|
|
hex(*tea, 8, str);
|
|
|
|
print(str, 11, 6);
|
|
|
|
|
|
|
|
print("Please reset.", 2, 7);
|
|
|
|
dupdate();
|
|
|
|
while(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
gint_int()
|
|
|
|
Handles interrupts.
|
|
|
|
*/
|
|
|
|
void gint_int(void)
|
|
|
|
{
|
|
|
|
if(isSH3())
|
|
|
|
gint_int_7705();
|
|
|
|
else
|
|
|
|
gint_int_7305();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
gint_reg()
|
|
|
|
Returns the address of a common register. All common registers exist
|
|
|
|
on both platforms but they may hold different values for the same
|
|
|
|
information (f.i. EXPEVT may not return the same value for a given
|
|
|
|
exception on both 7705 and 7305).
|
|
|
|
*/
|
|
|
|
inline volatile void *gint_reg(enum Register reg)
|
|
|
|
{
|
|
|
|
if(isSH3())
|
|
|
|
return gint_reg_7705(reg);
|
|
|
|
else
|
|
|
|
return gint_reg_7305(reg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
gint_strerror()
|
|
|
|
Returns a string that describe the error set in EXPEVT. This string is
|
|
|
|
not platform-dependent.
|
|
|
|
Some exception codes represent different errors when invoked inside the
|
|
|
|
general exception handler and the TLB error handler. Parameter 'is_tlb'
|
|
|
|
should be set to zero for general exception meanings, and anything non-
|
|
|
|
zero for TLB error meanings.
|
|
|
|
*/
|
|
|
|
const char *gint_strerror(int is_tlb)
|
|
|
|
{
|
|
|
|
if(isSH3())
|
|
|
|
return gint_strerror_7705(is_tlb);
|
|
|
|
else
|
|
|
|
return gint_strerror_7305(is_tlb);
|
|
|
|
}
|