2013-12-19 17:10:14 +00:00
|
|
|
/*
|
2013-12-24 00:56:44 +00:00
|
|
|
Interrupt list caching and handling
|
2013-12-19 17:10:14 +00:00
|
|
|
|
2013-12-24 00:56:44 +00:00
|
|
|
SH4 has a very flexible interrupt controller. In order to handle it efficiently, a sorted
|
2013-12-19 17:10:14 +00:00
|
|
|
interrupt bitfield is build from the set interrupt priorities. Higher priorities get allocated
|
|
|
|
into higher bits, and a simple mask is kept. In order to check for pending interrupts a simple
|
2013-12-24 00:56:44 +00:00
|
|
|
!=0 test works, and to identify the pending interrupt bsr(pend) will give the sorted id. As
|
2013-12-19 17:10:14 +00:00
|
|
|
this is a single cycle operation on most platforms, the interrupt checking/identification
|
|
|
|
is very fast !
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "types.h"
|
|
|
|
#include "sh4_interrupts.h"
|
|
|
|
#include "sh4_core.h"
|
|
|
|
#include "sh4_mmr.h"
|
|
|
|
#include "oslib/oslib.h"
|
2021-03-23 13:49:19 +00:00
|
|
|
#include "debug/gdb_server.h"
|
2023-01-11 19:42:33 +00:00
|
|
|
#include <cassert>
|
2013-12-19 17:10:14 +00:00
|
|
|
|
|
|
|
//these are fixed
|
2019-07-12 15:20:43 +00:00
|
|
|
const u16 IRLPriority = 0x0246;
|
2013-12-19 17:10:14 +00:00
|
|
|
#define IRLP9 &IRLPriority,0
|
|
|
|
#define IRLP11 &IRLPriority,4
|
|
|
|
#define IRLP13 &IRLPriority,8
|
|
|
|
|
|
|
|
#define GIPA(p) &INTC_IPRA.reg_data,4*p
|
|
|
|
#define GIPB(p) &INTC_IPRB.reg_data,4*p
|
|
|
|
#define GIPC(p) &INTC_IPRC.reg_data,4*p
|
|
|
|
|
|
|
|
struct InterptSourceList_Entry
|
|
|
|
{
|
2019-07-10 15:25:11 +00:00
|
|
|
const u16* PrioReg;
|
2013-12-19 17:10:14 +00:00
|
|
|
u32 Shift;
|
2023-01-11 19:42:33 +00:00
|
|
|
Sh4ExceptionCode IntEvnCode;
|
2013-12-19 17:10:14 +00:00
|
|
|
|
2023-01-11 19:42:33 +00:00
|
|
|
int GetPrLvl() const { return (*PrioReg >> Shift) & 0xF; }
|
2013-12-19 17:10:14 +00:00
|
|
|
};
|
|
|
|
|
2023-01-11 19:42:33 +00:00
|
|
|
static const InterptSourceList_Entry InterruptSourceList[sh4_INT_ID_COUNT] =
|
2020-11-24 20:29:04 +00:00
|
|
|
{
|
|
|
|
//IRL
|
2023-01-11 19:42:33 +00:00
|
|
|
{ IRLP9, Sh4Ex_ExtInterrupt9 }, //sh4_IRL_9
|
|
|
|
{ IRLP11, Sh4Ex_ExtInterruptB }, //sh4_IRL_11
|
|
|
|
{ IRLP13, Sh4Ex_ExtInterruptD }, //sh4_IRL_13
|
2020-11-24 20:29:04 +00:00
|
|
|
|
|
|
|
//HUDI
|
2023-01-11 19:42:33 +00:00
|
|
|
{ GIPC(0), Sh4Ex_HUDI }, //sh4_HUDI_HUDI
|
2020-11-24 20:29:04 +00:00
|
|
|
|
|
|
|
//GPIO (missing on dc ?)
|
2023-01-11 19:42:33 +00:00
|
|
|
{ GIPC(3), Sh4Ex_GPIO }, //sh4_GPIO_GPIOI
|
2020-11-24 20:29:04 +00:00
|
|
|
|
|
|
|
//DMAC
|
2023-01-11 19:42:33 +00:00
|
|
|
{ GIPC(2), Sh4Ex_DMAC_DTME0 }, //sh4_DMAC_DMTE0
|
|
|
|
{ GIPC(2), Sh4Ex_DMAC_DTME1 }, //sh4_DMAC_DMTE1
|
|
|
|
{ GIPC(2), Sh4Ex_DMAC_DTME2 }, //sh4_DMAC_DMTE2
|
|
|
|
{ GIPC(2), Sh4Ex_DMAC_DTME3 }, //sh4_DMAC_DMTE3
|
|
|
|
{ GIPC(2), Sh4Ex_DMAC_DMAE }, //sh4_DMAC_DMAE
|
2020-11-24 20:29:04 +00:00
|
|
|
|
|
|
|
//TMU
|
2023-01-11 19:42:33 +00:00
|
|
|
{ GIPA(3), Sh4Ex_TMU0 }, //sh4_TMU0_TUNI0
|
|
|
|
{ GIPA(2), Sh4Ex_TMU1 }, //sh4_TMU1_TUNI1
|
|
|
|
{ GIPA(1), Sh4Ex_TMU2 }, //sh4_TMU2_TUNI2
|
|
|
|
{ GIPA(1), Sh4Ex_TMU2_TICPI2 }, //sh4_TMU2_TICPI2
|
2020-11-24 20:29:04 +00:00
|
|
|
|
|
|
|
//RTC
|
2023-01-11 19:42:33 +00:00
|
|
|
{ GIPA(0), Sh4Ex_RTC_ATI }, //sh4_RTC_ATI
|
|
|
|
{ GIPA(0), Sh4Ex_RTC_PRI }, //sh4_RTC_PRI
|
|
|
|
{ GIPA(0), Sh4Ex_RTC_CUI }, //sh4_RTC_CUI
|
2020-11-24 20:29:04 +00:00
|
|
|
|
|
|
|
//SCI
|
2023-01-11 19:42:33 +00:00
|
|
|
{ GIPB(1), Sh4Ex_SCI_ERI }, //sh4_SCI1_ERI
|
|
|
|
{ GIPB(1), Sh4Ex_SCI_RXI }, //sh4_SCI1_RXI
|
|
|
|
{ GIPB(1), Sh4Ex_SCI_TXI }, //sh4_SCI1_TXI
|
|
|
|
{ GIPB(1), Sh4Ex_SCI_TEI }, //sh4_SCI1_TEI
|
2020-11-24 20:29:04 +00:00
|
|
|
|
|
|
|
//SCIF
|
2023-01-11 19:42:33 +00:00
|
|
|
{ GIPC(1), Sh4Ex_SCIF_ERI }, //sh4_SCIF_ERI
|
|
|
|
{ GIPC(1), Sh4Ex_SCIF_RXI }, //sh4_SCIF_RXI
|
|
|
|
{ GIPC(1), Sh4Ex_SCIF_BRI }, //sh4_SCIF_BRI
|
|
|
|
{ GIPC(1), Sh4Ex_SCIF_TXI }, //sh4_SCIF_TXI
|
2020-11-24 20:29:04 +00:00
|
|
|
|
|
|
|
//WDT
|
2023-01-11 19:42:33 +00:00
|
|
|
{ GIPB(3), Sh4Ex_WDT }, //sh4_WDT_ITI
|
2020-11-24 20:29:04 +00:00
|
|
|
|
|
|
|
//REF
|
2023-01-11 19:42:33 +00:00
|
|
|
{ GIPB(2), Sh4Ex_REF_RCMI }, //sh4_REF_RCMI
|
|
|
|
{ GIPA(2), Sh4Ex_REF_ROVI }, //sh4_REF_ROVI
|
2020-11-24 20:29:04 +00:00
|
|
|
};
|
|
|
|
|
2013-12-19 17:10:14 +00:00
|
|
|
//Maps siid -> EventID
|
2023-01-11 22:01:37 +00:00
|
|
|
alignas(64) Sh4ExceptionCode InterruptEnvId[32];
|
2013-12-19 17:10:14 +00:00
|
|
|
//Maps piid -> 1<<siid
|
2023-01-11 22:01:37 +00:00
|
|
|
alignas(64) u32 InterruptBit[32];
|
2013-12-24 00:56:44 +00:00
|
|
|
//Maps sh4 interrupt level to inclusive bitfield
|
2023-01-11 19:42:33 +00:00
|
|
|
alignas(64) u32 InterruptLevelBit[16];
|
2013-12-19 17:10:14 +00:00
|
|
|
|
2023-01-11 19:42:33 +00:00
|
|
|
static bool Do_Interrupt(Sh4ExceptionCode intEvn);
|
2013-12-19 17:10:14 +00:00
|
|
|
|
2013-12-24 00:56:44 +00:00
|
|
|
u32 interrupt_vpend; // Vector of pending interrupts
|
|
|
|
u32 interrupt_vmask; // Vector of masked interrupts (-1 inhibits all interrupts)
|
|
|
|
u32 decoded_srimask; // Vector of interrupts allowed by SR.IMSK (-1 inhibits all interrupts)
|
2013-12-19 17:10:14 +00:00
|
|
|
|
|
|
|
//bit 0 ~ 27 : interrupt source 27:0. 0 = lowest level, 27 = highest level.
|
2019-08-30 21:35:10 +00:00
|
|
|
static void recalc_pending_itrs()
|
2013-12-19 17:10:14 +00:00
|
|
|
{
|
2023-01-11 19:42:33 +00:00
|
|
|
Sh4cntx.interrupt_pend = interrupt_vpend & interrupt_vmask & decoded_srimask;
|
2013-12-19 17:10:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Rebuild sorted interrupt id table (priorities were updated)
|
|
|
|
void SIIDRebuild()
|
|
|
|
{
|
2023-01-11 19:42:33 +00:00
|
|
|
int cnt = 0;
|
|
|
|
u32 vpend = interrupt_vpend;
|
|
|
|
u32 vmask = interrupt_vmask;
|
|
|
|
interrupt_vpend = 0;
|
|
|
|
interrupt_vmask = 0;
|
2013-12-19 17:10:14 +00:00
|
|
|
//rebuild interrupt table
|
2023-01-11 19:42:33 +00:00
|
|
|
for (int ilevel = 0; ilevel < 16; ilevel++)
|
2013-12-19 17:10:14 +00:00
|
|
|
{
|
2023-01-11 19:42:33 +00:00
|
|
|
for (int isrc = 0; isrc < sh4_INT_ID_COUNT; isrc++)
|
2013-12-19 17:10:14 +00:00
|
|
|
{
|
2023-01-11 19:42:33 +00:00
|
|
|
if (InterruptSourceList[isrc].GetPrLvl() == ilevel)
|
2013-12-19 17:10:14 +00:00
|
|
|
{
|
2023-01-11 19:42:33 +00:00
|
|
|
InterruptEnvId[cnt] = InterruptSourceList[isrc].IntEvnCode;
|
|
|
|
u32 p = InterruptBit[isrc] & vpend;
|
|
|
|
u32 m = InterruptBit[isrc] & vmask;
|
|
|
|
InterruptBit[isrc] = 1 << cnt;
|
2013-12-19 17:10:14 +00:00
|
|
|
if (p)
|
2023-01-11 19:42:33 +00:00
|
|
|
interrupt_vpend |= InterruptBit[isrc];
|
2013-12-19 17:10:14 +00:00
|
|
|
if (m)
|
2023-01-11 19:42:33 +00:00
|
|
|
interrupt_vmask |= InterruptBit[isrc];
|
2013-12-19 17:10:14 +00:00
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
}
|
2023-01-11 19:42:33 +00:00
|
|
|
InterruptLevelBit[ilevel] = (1 << cnt) - 1;
|
2013-12-19 17:10:14 +00:00
|
|
|
}
|
|
|
|
SRdecode();
|
|
|
|
}
|
|
|
|
|
|
|
|
//Decode SR.IMSK into a interrupt mask, update and return the interrupt state
|
|
|
|
bool SRdecode()
|
|
|
|
{
|
|
|
|
if (sr.BL)
|
|
|
|
decoded_srimask=~0xFFFFFFFF;
|
|
|
|
else
|
|
|
|
decoded_srimask=~InterruptLevelBit[sr.IMASK];
|
|
|
|
|
|
|
|
recalc_pending_itrs();
|
|
|
|
return Sh4cntx.interrupt_pend;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int UpdateINTC()
|
|
|
|
{
|
|
|
|
if (!Sh4cntx.interrupt_pend)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return Do_Interrupt(InterruptEnvId[bitscanrev(Sh4cntx.interrupt_pend)]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetInterruptPend(InterruptID intr)
|
|
|
|
{
|
2023-01-11 19:42:33 +00:00
|
|
|
interrupt_vpend |= InterruptBit[intr];
|
2013-12-19 17:10:14 +00:00
|
|
|
recalc_pending_itrs();
|
|
|
|
}
|
|
|
|
void ResetInterruptPend(InterruptID intr)
|
|
|
|
{
|
2023-01-11 19:42:33 +00:00
|
|
|
interrupt_vpend &= ~InterruptBit[intr];
|
2013-12-19 17:10:14 +00:00
|
|
|
recalc_pending_itrs();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetInterruptMask(InterruptID intr)
|
|
|
|
{
|
2023-01-11 19:42:33 +00:00
|
|
|
interrupt_vmask |= InterruptBit[intr];
|
2013-12-19 17:10:14 +00:00
|
|
|
recalc_pending_itrs();
|
|
|
|
}
|
|
|
|
void ResetInterruptMask(InterruptID intr)
|
|
|
|
{
|
2023-01-11 19:42:33 +00:00
|
|
|
interrupt_vmask &= ~InterruptBit[intr];
|
2013-12-19 17:10:14 +00:00
|
|
|
recalc_pending_itrs();
|
|
|
|
}
|
|
|
|
|
2023-01-11 19:42:33 +00:00
|
|
|
static bool Do_Interrupt(Sh4ExceptionCode intEvn)
|
2013-12-19 17:10:14 +00:00
|
|
|
{
|
|
|
|
CCN_INTEVT = intEvn;
|
|
|
|
|
2018-09-02 13:49:23 +00:00
|
|
|
ssr = sh4_sr_GetFull();
|
2013-12-19 17:10:14 +00:00
|
|
|
spc = next_pc;
|
|
|
|
sgr = r[15];
|
|
|
|
sr.BL = 1;
|
|
|
|
sr.MD = 1;
|
|
|
|
sr.RB = 1;
|
|
|
|
UpdateSR();
|
|
|
|
next_pc = vbr + 0x600;
|
2021-03-23 13:49:19 +00:00
|
|
|
debugger::subroutineCall();
|
2013-12-19 17:10:14 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-01-11 19:42:33 +00:00
|
|
|
bool Do_Exception(u32 epc, Sh4ExceptionCode expEvn)
|
2013-12-19 17:10:14 +00:00
|
|
|
{
|
2023-01-11 19:42:33 +00:00
|
|
|
assert((expEvn >= Sh4Ex_TlbMissRead && expEvn <= Sh4Ex_SlotIllegalInstr)
|
|
|
|
|| expEvn == Sh4Ex_FpuDisabled || expEvn == Sh4Ex_SlotFpuDisabled || expEvn == Sh4Ex_UserBreak);
|
2021-08-03 07:47:13 +00:00
|
|
|
if (sr.BL != 0)
|
|
|
|
throw FlycastException("Fatal: SH4 exception when blocked");
|
2013-12-19 17:10:14 +00:00
|
|
|
CCN_EXPEVT = expEvn;
|
|
|
|
|
2018-09-02 13:49:23 +00:00
|
|
|
ssr = sh4_sr_GetFull();
|
2013-12-19 17:10:14 +00:00
|
|
|
spc = epc;
|
|
|
|
sgr = r[15];
|
|
|
|
sr.BL = 1;
|
|
|
|
sr.MD = 1;
|
|
|
|
sr.RB = 1;
|
|
|
|
UpdateSR();
|
|
|
|
|
2023-01-11 19:42:33 +00:00
|
|
|
next_pc = vbr + (expEvn == Sh4Ex_TlbMissRead || expEvn == Sh4Ex_TlbMissWrite ? 0x400 : 0x100);
|
2021-03-23 13:49:19 +00:00
|
|
|
debugger::subroutineCall();
|
2013-12-19 17:10:14 +00:00
|
|
|
|
2023-01-11 19:42:33 +00:00
|
|
|
//printf("RaiseException: from pc %08x to %08x, event %x\n", epc, next_pc, expEvn);
|
2013-12-19 17:10:14 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//Init/Res/Term
|
|
|
|
void interrupts_init()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void interrupts_reset()
|
|
|
|
{
|
|
|
|
//reset interrupts cache
|
2023-01-11 19:42:33 +00:00
|
|
|
interrupt_vpend = 0;
|
|
|
|
interrupt_vmask = 0xFFFFFFFF;
|
|
|
|
decoded_srimask = 0;
|
2013-12-19 17:10:14 +00:00
|
|
|
|
2023-01-11 19:42:33 +00:00
|
|
|
for (u32 i = 0; i < sh4_INT_ID_COUNT; i++)
|
|
|
|
InterruptBit[i] = 1 << i;
|
2013-12-19 17:10:14 +00:00
|
|
|
|
|
|
|
//rebuild the interrupts table
|
|
|
|
SIIDRebuild();
|
|
|
|
}
|
|
|
|
|
|
|
|
void interrupts_term()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|