mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2025-01-06 08:53:36 +01:00
1c7b1350b4
* Removed .pretext sections since the TLB is now entirely dynamic; left only .text.entry for the start symbol. * Reworked the main files of src/core to move the INTC to its own driver and let the kernel handle only VBR space and CPU (now: VBR & CPUOPM). * Moved src/core/gint.c to src/core/kernel.c and centralized all driver loops that save or restore context for more robustness. This leaves the callbacks of cpu_setVBR() (formerly gint_setvbr()) pretty short. * Coalesced gint_switch_out() and gint_switch_in() into a single function callback for cpu_setVBR(). * Added an abstraction of interrupt signals as an enumerated value so that drivers no longer hardcode the IPR and IMR numbers and bits, sometimes even with isSH3() due to differences in the SH7705. * Changed the interrupt blocking method in cpu_setVBR() from SR.BL=1 to SR.IMASK=15 so that TLB misses are still handled. This removes the need for callback functions to be GMAPPED. * Moved gint_osmenu() and its utilities to a new file src/core/osmenu.c.
180 lines
3.9 KiB
C
180 lines
3.9 KiB
C
#include <gint/drivers.h>
|
|
#include <gint/hardware.h>
|
|
#include <gint/mpu/intc.h>
|
|
|
|
/* Interrupt controllers */
|
|
|
|
GDATA3 sh7705_intc_t SH7705_INTC = {
|
|
.IPR = {
|
|
(void *)0xfffffee2, (void *)0xfffffee4,
|
|
(void *)0xa4000016, (void *)0xa4000018, (void *)0xa400001a,
|
|
(void *)0xa4080000, (void *)0xa4080002, (void *)0xa4080004,
|
|
},
|
|
.ICR1 = (void *)0xa4000010,
|
|
};
|
|
|
|
GDATA sh7305_intc_t SH7305_INTC = {
|
|
.IPR = (void *)0xa4080000,
|
|
.MSK = (void *)0xa4080080,
|
|
.MSKCLR = (void *)0xa40800c0,
|
|
.USERIMASK = (void *)0xa4700000,
|
|
};
|
|
|
|
/* Interrupt IPR and IMR positions. The order of entries is as in the named
|
|
list of interrupt signals in <gint/intc.h>. */
|
|
|
|
/* Friendly names for IPR and IMR register numbers */
|
|
enum{ IPRA, IPRB, IPRC, IPRD, IPRE, IPRF, IPRG, IPRH, IPRI, IPRJ, IPRK, IPRL };
|
|
enum{ IMR0, IMR1, IMR2, IMR3, IMR4, IMR5, IMR6, IMR7, IMR8, IMR9, IMR10 };
|
|
#define _ 0,0
|
|
|
|
struct info {
|
|
uint16_t IPR4, IPR4bits, IMR, IMRbits;
|
|
/* Only set if different than IPR4 with IPR4bits */
|
|
uint16_t IPR3, IPR3bits;
|
|
} info[] = {
|
|
/* Standard TMU */
|
|
{ IPRA, 0xf000, IMR4, 0x10, _ },
|
|
{ IPRA, 0x0f00, IMR4, 0x20, _ },
|
|
{ IPRA, 0x00f0, IMR4, 0x40, _ },
|
|
/* ETMU */
|
|
{ IPRJ, 0xf000, IMR6, 0x08, IPRF, 0x000f },
|
|
{ IPRG, 0x0f00, IMR5, 0x02, _ },
|
|
{ IPRG, 0x00f0, IMR5, 0x04, _ },
|
|
{ IPRE, 0x00f0, IMR2, 0x01, _ },
|
|
{ IPRI, 0xf000, IMR6, 0x10, _ },
|
|
{ IPRL, 0xf000, IMR8, 0x02, _ },
|
|
/* DMA */
|
|
{ IPRE, 0xf000, IMR1, 0x01, _ /* Not supported on SH3! */ },
|
|
{ IPRE, 0xf000, IMR1, 0x02, _ },
|
|
{ IPRE, 0xf000, IMR1, 0x04, _ },
|
|
{ IPRE, 0xf000, IMR1, 0x08, _ },
|
|
{ IPRF, 0x0f00, IMR5, 0x10, _ },
|
|
{ IPRF, 0x0f00, IMR5, 0x20, _ },
|
|
{ IPRF, 0x0f00, IMR5, 0x40, _ },
|
|
/* RTC */
|
|
{ IPRK, 0xf000, IMR10, 0x04, IPRA, 0x000f },
|
|
{ IPRK, 0xf000, IMR10, 0x02, IPRA, 0x000f },
|
|
{ IPRK, 0xf000, IMR10, 0x01, IPRA, 0x000f },
|
|
};
|
|
|
|
|
|
//---
|
|
// Interrupt controller functions
|
|
//---
|
|
|
|
/* intc_priority(): Configure the level of interrupts */
|
|
int intc_priority(int intname, int level)
|
|
{
|
|
struct info *i = &info[intname];
|
|
int IPRn = i->IPR4, IPRbits = i->IPR4bits;
|
|
|
|
if(isSH3() && i->IPR3bits != 0)
|
|
{
|
|
IPRn = i->IPR3;
|
|
IPRbits = i->IPR3bits;
|
|
}
|
|
|
|
/* Bit-shift for the mask */
|
|
int shift = 0;
|
|
while(IPRbits >>= 4) shift += 4;
|
|
|
|
uint16_t volatile *IPR;
|
|
IPR = isSH3() ? SH7705_INTC.IPR[IPRn] : &SH7305_INTC.IPR[2*IPRn];
|
|
|
|
int oldlevel = (*IPR >> shift) & 0xf;
|
|
*IPR = (*IPR & ~(0xf << shift)) | (level << shift);
|
|
|
|
if(isSH4() && level > 0 && i->IMRbits)
|
|
{
|
|
uint8_t volatile *MSKCLR = &SH7305_INTC.MSKCLR->IMR0;
|
|
MSKCLR[4*i->IMR] = i->IMRbits;
|
|
}
|
|
|
|
return oldlevel;
|
|
}
|
|
|
|
//---
|
|
// Initialization
|
|
//---
|
|
|
|
static void init(void)
|
|
{
|
|
/* Just disable everything, drivers will enable what they support */
|
|
if(isSH3()) for(int i = 0; i < 8; i++)
|
|
*(SH7705_INTC.IPR[i]) = 0x0000;
|
|
else for(int i = 0; i < 12; i++)
|
|
SH7305_INTC.IPR[2 * i] = 0x0000;
|
|
}
|
|
|
|
//---
|
|
// Driver context
|
|
//---
|
|
|
|
typedef struct
|
|
{
|
|
uint16_t IPR[12];
|
|
uint8_t MSK[13];
|
|
} ctx_t;
|
|
|
|
GBSS static ctx_t sys_ctx, gint_ctx;
|
|
|
|
static void ctx_save(void *buf)
|
|
{
|
|
ctx_t *ctx = buf;
|
|
|
|
if(isSH3())
|
|
{
|
|
for(int i = 0; i < 8; i++)
|
|
ctx->IPR[i] = *(SH7705_INTC.IPR[i]);
|
|
}
|
|
else
|
|
{
|
|
for(int i = 0; i < 12; i++)
|
|
ctx->IPR[i] = SH7305_INTC.IPR[2 * i];
|
|
|
|
uint8_t *IMR = (void *)SH7305_INTC.MSK;
|
|
for(int i = 0; i < 13; i++, IMR += 4)
|
|
ctx->MSK[i] = *IMR;
|
|
}
|
|
}
|
|
|
|
static void ctx_restore(void *buf)
|
|
{
|
|
ctx_t *ctx = buf;
|
|
|
|
if(isSH3())
|
|
{
|
|
for(int i = 0; i < 8; i++)
|
|
*(SH7705_INTC.IPR[i]) = ctx->IPR[i];
|
|
}
|
|
else
|
|
{
|
|
for(int i = 0; i < 12; i++)
|
|
SH7305_INTC.IPR[2 * i] = ctx->IPR[i];
|
|
|
|
/* Setting masks it a bit more involved than reading them */
|
|
uint8_t *IMCR = (void *)SH7305_INTC.MSKCLR;
|
|
uint8_t *IMR = (void *)SH7305_INTC.MSK;
|
|
for(int i = 0; i < 13; i++, IMR += 4, IMCR += 4)
|
|
{
|
|
*IMCR = 0xff;
|
|
*IMR = ctx->MSK[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
//---
|
|
// Driver structure definition
|
|
//---
|
|
|
|
gint_driver_t drv_intc = {
|
|
.name = "INTC",
|
|
.init = init,
|
|
.sys_ctx = &sys_ctx,
|
|
.gint_ctx = &gint_ctx,
|
|
.ctx_save = ctx_save,
|
|
.ctx_restore = ctx_restore,
|
|
};
|
|
|
|
GINT_DECLARE_DRIVER(0, drv_intc);
|