make REG_IF a generated value instead of a cached value; rewrite IPC FIFO IF handling and IPC FIFO clearing
This commit is contained in:
parent
9cf546bef3
commit
4d201d86d2
|
@ -75,7 +75,7 @@ void IPC_FIFOsend(u8 proc, u32 val)
|
|||
T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, cnt_l);
|
||||
T1WriteWord(MMU.MMU_MEM[proc_remote][0x40], 0x184, cnt_r);
|
||||
|
||||
setIF(proc_remote, ((cnt_r & 0x0400)<<8)); // IRQ18: recv not empty
|
||||
NDS_Reschedule();
|
||||
}
|
||||
|
||||
u32 IPC_FIFOrecv(u8 proc)
|
||||
|
@ -116,38 +116,56 @@ u32 IPC_FIFOrecv(u8 proc)
|
|||
T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, cnt_l);
|
||||
T1WriteWord(MMU.MMU_MEM[proc_remote][0x40], 0x184, cnt_r);
|
||||
|
||||
setIF(proc_remote, ((cnt_r & 0x0004)<<15)); // IRQ17: send empty
|
||||
NDS_Reschedule();
|
||||
|
||||
return (val);
|
||||
}
|
||||
|
||||
#define IPCFIFOCNT_SENDEMPTY 0x0001
|
||||
#define IPCFIFOCNT_SENDFULL 0x0002
|
||||
#define IPCFIFOCNT_SENDIRQEN 0x0004
|
||||
#define IPCFIFOCNT_SENDCLEAR 0x0008
|
||||
#define IPCFIFOCNT_RECVEMPTY 0x0100
|
||||
#define IPCFIFOCNT_RECVFULL 0x0200
|
||||
#define IPCFIFOCNT_RECVIRQEN 0x0400
|
||||
#define IPCFIFOCNT_FIFOERROR 0x4000
|
||||
#define IPCFIFOCNT_FIFOENABLE 0x8000
|
||||
#define IPCFIFOCNT_WRITEABLE (IPCFIFOCNT_SENDIRQEN | IPCFIFOCNT_RECVIRQEN | IPCFIFOCNT_FIFOENABLE)
|
||||
|
||||
void IPC_FIFOcnt(u8 proc, u16 val)
|
||||
{
|
||||
u16 cnt_l = T1ReadWord(MMU.MMU_MEM[proc][0x40], 0x184);
|
||||
u16 cnt_r = T1ReadWord(MMU.MMU_MEM[proc^1][0x40], 0x184);
|
||||
|
||||
//LOG("IPC%s FIFO context 0x%X (local 0x%04X, remote 0x%04X)\n", proc?"7":"9", val, cnt_l, cnt_r);
|
||||
if (val & 0x4008)
|
||||
if (val & IPCFIFOCNT_FIFOERROR)
|
||||
{
|
||||
ipc_fifo[proc].head = 0; ipc_fifo[proc].tail = 0; ipc_fifo[proc].size = 0;
|
||||
T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, (cnt_l & 0x0301) | (val & 0x8404) | 1);
|
||||
T1WriteWord(MMU.MMU_MEM[proc^1][0x40], 0x184, (cnt_r & 0x8407) | 0x100);
|
||||
//MMU.reg_IF[proc^1] |= ((val & 0x0004) << 15);
|
||||
setIF(proc^1, ((cnt_r & 0x0004)<<15));
|
||||
return;
|
||||
//at least SPP uses this, maybe every retail game
|
||||
cnt_l &= ~IPCFIFOCNT_FIFOERROR;
|
||||
}
|
||||
|
||||
T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, val);
|
||||
if (val & IPCFIFOCNT_SENDCLEAR)
|
||||
{
|
||||
ipc_fifo[proc].head = 0; ipc_fifo[proc].tail = 0; ipc_fifo[proc].size = 0;
|
||||
|
||||
cnt_l |= IPCFIFOCNT_SENDEMPTY;
|
||||
cnt_l &= ~IPCFIFOCNT_SENDFULL;
|
||||
cnt_r |= IPCFIFOCNT_RECVEMPTY;
|
||||
cnt_r &= ~IPCFIFOCNT_RECVFULL;
|
||||
}
|
||||
|
||||
cnt_l &= ~IPCFIFOCNT_WRITEABLE;
|
||||
cnt_l |= val & IPCFIFOCNT_WRITEABLE;
|
||||
|
||||
T1WriteWord(MMU.MMU_MEM[proc][0x40], 0x184, cnt_l);
|
||||
T1WriteWord(MMU.MMU_MEM[proc^1][0x40], 0x184, cnt_r);
|
||||
|
||||
NDS_Reschedule();
|
||||
}
|
||||
|
||||
// ========================================================= GFX FIFO
|
||||
GFX_PIPE gxPIPE;
|
||||
GFX_FIFO gxFIFO;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void GFX_PIPEclear()
|
||||
{
|
||||
gxPIPE.head = 0;
|
||||
|
|
|
@ -919,7 +919,7 @@ void MMU_Reset()
|
|||
|
||||
memset(MMU.reg_IME, 0, sizeof(u32) * 2);
|
||||
memset(MMU.reg_IE, 0, sizeof(u32) * 2);
|
||||
memset(MMU.reg_IF, 0, sizeof(u32) * 2);
|
||||
memset(MMU.reg_IF_bits, 0, sizeof(u32) * 2);
|
||||
|
||||
memset(MMU.dscard, 0, sizeof(nds_dscard) * 2);
|
||||
|
||||
|
@ -1220,17 +1220,96 @@ u32 MMU_readFromGC()
|
|||
//does some validation on the game's choice of IF value, correcting it if necessary
|
||||
static void validateIF_arm9()
|
||||
{
|
||||
//according to gbatek, these flags are forced on until the condition is removed.
|
||||
//no proof of this though...
|
||||
if(MMU_new.gxstat.gxfifo_irq == 1)
|
||||
if(gxFIFO.size <= 127)
|
||||
MMU.reg_IF[ARMCPU_ARM9] |= (1<<21);
|
||||
else MMU.reg_IF[ARMCPU_ARM9] &= ~(1<<21);
|
||||
else if(MMU_new.gxstat.gxfifo_irq == 2)
|
||||
if(gxFIFO.size == 0)
|
||||
MMU.reg_IF[ARMCPU_ARM9] |= (1<<21);
|
||||
else MMU.reg_IF[ARMCPU_ARM9] &= ~(1<<21);
|
||||
else if(MMU_new.gxstat.gxfifo_irq == 0) MMU.reg_IF[ARMCPU_ARM9] &= ~(1<<21);
|
||||
}
|
||||
|
||||
template<int PROCNUM> static void REG_IF_WriteByte(u32 addr, u8 val)
|
||||
{
|
||||
//the following bits are generated from logic and should not be affected here
|
||||
//Bit 17 IPC Send FIFO Empty
|
||||
//Bit 18 IPC Recv FIFO Not Empty
|
||||
//Bit 21 NDS9 only: Geometry Command FIFO
|
||||
//arm9: IF &= ~0x00260000;
|
||||
//arm7: IF &= ~0x00060000;
|
||||
if(addr==2)
|
||||
if(PROCNUM==ARMCPU_ARM9)
|
||||
val &= ~0x26;
|
||||
else
|
||||
val &= ~0x06;
|
||||
|
||||
MMU.reg_IF_bits[PROCNUM] &= (~(((u32)val)<<(addr<<3)));
|
||||
NDS_Reschedule();
|
||||
}
|
||||
|
||||
template<int PROCNUM> static void REG_IF_WriteWord(u32 addr,u16 val)
|
||||
{
|
||||
REG_IF_WriteByte<PROCNUM>(addr,val&0xFF);
|
||||
REG_IF_WriteByte<PROCNUM>(addr+1,(val>>8)&0xFF);
|
||||
}
|
||||
|
||||
template<int PROCNUM> static void REG_IF_WriteLong(u32 val)
|
||||
{
|
||||
REG_IF_WriteByte<PROCNUM>(0,val&0xFF);
|
||||
REG_IF_WriteByte<PROCNUM>(1,(val>>8)&0xFF);
|
||||
REG_IF_WriteByte<PROCNUM>(2,(val>>16)&0xFF);
|
||||
REG_IF_WriteByte<PROCNUM>(3,(val>>24)&0xFF);
|
||||
}
|
||||
|
||||
template<int PROCNUM>
|
||||
u32 MMU_struct::gen_IF()
|
||||
{
|
||||
//TODO - analyze setIF behaviour in GXF_FIFO_handleEvents
|
||||
|
||||
u32 IF = reg_IF_bits[PROCNUM];
|
||||
|
||||
if(PROCNUM==ARMCPU_ARM9)
|
||||
{
|
||||
//according to gbatek, these flags are forced on until the condition is removed.
|
||||
//no proof of this though...
|
||||
switch(MMU_new.gxstat.gxfifo_irq)
|
||||
{
|
||||
case 0: //never
|
||||
break;
|
||||
case 1: //less than half full
|
||||
if(gxFIFO.size <= 127)
|
||||
IF |= (1<<21);
|
||||
break;
|
||||
case 2: //empty
|
||||
if(gxFIFO.size == 0)
|
||||
IF |= (1<<21);
|
||||
break;
|
||||
case 3: //reserved/unknown
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//generate IPC IF states from the ipc registers
|
||||
u16 ipc = T1ReadWord(MMU.MMU_MEM[PROCNUM][0x40], 0x184);
|
||||
if(ipc&0x8000)
|
||||
{
|
||||
if(ipc&0x0004) if(ipc&0x0001)
|
||||
IF |= (1<<17); //IPC Send FIFO Empty
|
||||
if(ipc&0x0400) if(!(ipc&0x0100))
|
||||
IF |= (1<<18); //IPC Recv FIFO Not Empty
|
||||
}
|
||||
|
||||
//4000184h - NDS9/NDS7 - IPCFIFOCNT - IPC Fifo Control Register (R/W)
|
||||
//
|
||||
// Bit Dir Expl.
|
||||
// 0 R Send Fifo Empty Status (0=Not Empty, 1=Empty)
|
||||
// 1 R Send Fifo Full Status (0=Not Full, 1=Full)
|
||||
// 2 R/W Send Fifo Empty IRQ (0=Disable, 1=Enable)
|
||||
// 3 W Send Fifo Clear (0=Nothing, 1=Flush Send Fifo)
|
||||
// 4-7 - Not used
|
||||
// 8 R Receive Fifo Empty (0=Not Empty, 1=Empty)
|
||||
// 9 R Receive Fifo Full (0=Not Full, 1=Full)
|
||||
// 10 R/W Receive Fifo Not Empty IRQ (0=Disable, 1=Enable)
|
||||
// 11-13 - Not used
|
||||
// 14 R/W Error, Read Empty/Send Full (0=No Error, 1=Error/Acknowledge)
|
||||
// 15 R/W Enable Send/Receive Fifo (0=Disable, 1=Enable)
|
||||
// 16-31 - Not used
|
||||
|
||||
|
||||
return IF;
|
||||
}
|
||||
|
||||
static u32 readreg_POWCNT1(const int size, const u32 adr) {
|
||||
|
@ -2549,14 +2628,10 @@ void FASTCALL _MMU_ARM9_write16(u32 adr, u16 val)
|
|||
MMU.reg_IE[ARMCPU_ARM9] = (MMU.reg_IE[ARMCPU_ARM9]&0xFFFF) | (((u32)val)<<16);
|
||||
return;
|
||||
case REG_IF :
|
||||
NDS_Reschedule();
|
||||
MMU.reg_IF[ARMCPU_ARM9] &= (~((u32)val));
|
||||
validateIF_arm9();
|
||||
REG_IF_WriteWord<ARMCPU_ARM9>(0,val);
|
||||
return;
|
||||
case REG_IF + 2 :
|
||||
NDS_Reschedule();
|
||||
MMU.reg_IF[ARMCPU_ARM9] &= (~(((u32)val)<<16));
|
||||
validateIF_arm9();
|
||||
REG_IF_WriteWord<ARMCPU_ARM9>(2,val);
|
||||
return;
|
||||
|
||||
case REG_IPCSYNC :
|
||||
|
@ -2968,9 +3043,7 @@ void FASTCALL _MMU_ARM9_write32(u32 adr, u32 val)
|
|||
return;
|
||||
|
||||
case REG_IF :
|
||||
NDS_Reschedule();
|
||||
MMU.reg_IF[ARMCPU_ARM9] &= (~val);
|
||||
validateIF_arm9();
|
||||
REG_IF_WriteLong<ARMCPU_ARM9>(val);
|
||||
return;
|
||||
|
||||
case REG_TM0CNTL:
|
||||
|
@ -3101,6 +3174,11 @@ u8 FASTCALL _MMU_ARM9_read08(u32 adr)
|
|||
|
||||
switch(adr)
|
||||
{
|
||||
case REG_IF: return MMU.gen_IF<ARMCPU_ARM9>();
|
||||
case REG_IF+1: return (MMU.gen_IF<ARMCPU_ARM9>()>>8);
|
||||
case REG_IF+2: return (MMU.gen_IF<ARMCPU_ARM9>()>>16);
|
||||
case REG_IF+3: return (MMU.gen_IF<ARMCPU_ARM9>()>>24);
|
||||
|
||||
case REG_DISPA_DISPSTAT:
|
||||
break;
|
||||
case REG_DISPA_DISPSTAT+1:
|
||||
|
@ -3210,10 +3288,8 @@ u16 FASTCALL _MMU_ARM9_read16(u32 adr)
|
|||
case REG_IE + 2 :
|
||||
return (u16)(MMU.reg_IE[ARMCPU_ARM9]>>16);
|
||||
|
||||
case REG_IF :
|
||||
return (u16)MMU.reg_IF[ARMCPU_ARM9];
|
||||
case REG_IF + 2 :
|
||||
return (u16)(MMU.reg_IF[ARMCPU_ARM9]>>16);
|
||||
case REG_IF: return MMU.gen_IF<ARMCPU_ARM9>();
|
||||
case REG_IF+2: return MMU.gen_IF<ARMCPU_ARM9>()>>16;
|
||||
|
||||
case REG_TM0CNTL :
|
||||
case REG_TM1CNTL :
|
||||
|
@ -3342,8 +3418,9 @@ u32 FASTCALL _MMU_ARM9_read32(u32 adr)
|
|||
return MMU.reg_IME[ARMCPU_ARM9];
|
||||
case REG_IE :
|
||||
return MMU.reg_IE[ARMCPU_ARM9];
|
||||
case REG_IF :
|
||||
return MMU.reg_IF[ARMCPU_ARM9];
|
||||
|
||||
case REG_IF: return MMU.gen_IF<ARMCPU_ARM9>();
|
||||
|
||||
case REG_IPCFIFORECV :
|
||||
return IPC_FIFOrecv(ARMCPU_ARM9);
|
||||
case REG_TM0CNTL :
|
||||
|
@ -3714,23 +3791,20 @@ void FASTCALL _MMU_ARM7_write16(u32 adr, u16 val)
|
|||
MMU.reg_IE[ARMCPU_ARM7] = (MMU.reg_IE[ARMCPU_ARM7]&0xFFFF) | (((u32)val)<<16);
|
||||
return;
|
||||
|
||||
case REG_IF :
|
||||
NDS_Reschedule();
|
||||
//emu_halt();
|
||||
MMU.reg_IF[ARMCPU_ARM7] &= (~((u32)val));
|
||||
case REG_IF:
|
||||
REG_IF_WriteWord<ARMCPU_ARM7>(0,val);
|
||||
return;
|
||||
case REG_IF + 2 :
|
||||
NDS_Reschedule();
|
||||
//emu_halt();
|
||||
MMU.reg_IF[ARMCPU_ARM7] &= (~(((u32)val)<<16));
|
||||
|
||||
case REG_IF+2:
|
||||
REG_IF_WriteWord<ARMCPU_ARM7>(2,val);
|
||||
return;
|
||||
|
||||
case REG_IPCSYNC :
|
||||
MMU_IPCSync(ARMCPU_ARM7, val);
|
||||
MMU_IPCSync(ARMCPU_ARM7, val);
|
||||
return;
|
||||
|
||||
case REG_IPCFIFOCNT :
|
||||
IPC_FIFOcnt(ARMCPU_ARM7, val);
|
||||
IPC_FIFOcnt(ARMCPU_ARM7, val);
|
||||
return;
|
||||
case REG_TM0CNTL :
|
||||
case REG_TM1CNTL :
|
||||
|
@ -3812,8 +3886,7 @@ void FASTCALL _MMU_ARM7_write32(u32 adr, u32 val)
|
|||
return;
|
||||
|
||||
case REG_IF :
|
||||
NDS_Reschedule();
|
||||
MMU.reg_IF[ARMCPU_ARM7] &= (~val);
|
||||
REG_IF_WriteLong<ARMCPU_ARM7>(val);
|
||||
return;
|
||||
|
||||
case REG_TM0CNTL:
|
||||
|
@ -3962,10 +4035,8 @@ u16 FASTCALL _MMU_ARM7_read16(u32 adr)
|
|||
case REG_IE + 2 :
|
||||
return (u16)(MMU.reg_IE[ARMCPU_ARM7]>>16);
|
||||
|
||||
case REG_IF :
|
||||
return (u16)MMU.reg_IF[ARMCPU_ARM7];
|
||||
case REG_IF + 2 :
|
||||
return (u16)(MMU.reg_IF[ARMCPU_ARM7]>>16);
|
||||
case REG_IF: return MMU.gen_IF<ARMCPU_ARM7>();
|
||||
case REG_IF+2: return MMU.gen_IF<ARMCPU_ARM7>()>>16;
|
||||
|
||||
case REG_TM0CNTL :
|
||||
case REG_TM1CNTL :
|
||||
|
@ -4043,8 +4114,7 @@ u32 FASTCALL _MMU_ARM7_read32(u32 adr)
|
|||
return MMU.reg_IME[ARMCPU_ARM7];
|
||||
case REG_IE :
|
||||
return MMU.reg_IE[ARMCPU_ARM7];
|
||||
case REG_IF :
|
||||
return MMU.reg_IF[ARMCPU_ARM7];
|
||||
case REG_IF: return MMU.gen_IF<ARMCPU_ARM7>();
|
||||
case REG_IPCFIFORECV :
|
||||
return IPC_FIFOrecv(ARMCPU_ARM7);
|
||||
case REG_TM0CNTL :
|
||||
|
|
|
@ -384,7 +384,11 @@ struct MMU_struct
|
|||
|
||||
u32 reg_IME[2];
|
||||
u32 reg_IE[2];
|
||||
u32 reg_IF[2];
|
||||
|
||||
//these are the user-controlled IF bits. some IF bits are generated as necessary from hardware conditions
|
||||
u32 reg_IF_bits[2];
|
||||
|
||||
template<int PROCNUM> u32 gen_IF();
|
||||
|
||||
BOOL divRunning;
|
||||
s64 divResult;
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
//#define LOG_ARM9
|
||||
//#define LOG_ARM7
|
||||
//bool dolog = true;
|
||||
//bool dolog = false;
|
||||
//#define LOG_TO_FILE
|
||||
//#define LOG_TO_FILE_REGS
|
||||
|
||||
|
@ -1769,6 +1769,7 @@ bool nds_loadstate(EMUFILE* is, int size)
|
|||
|
||||
FORCEINLINE void arm9log()
|
||||
{
|
||||
//if(currFrameCounter>19) dolog=true;
|
||||
#ifdef LOG_ARM9
|
||||
if(dolog)
|
||||
{
|
||||
|
@ -1951,7 +1952,7 @@ void NDS_exec(s32 nb)
|
|||
//speculative code: if ANY irq happens, wake up the arm7.
|
||||
//I think the arm7 program analyzes the system and may decide not to wake up
|
||||
//if it is dissatisfied with the conditions
|
||||
if((MMU.reg_IE[1] & MMU.reg_IF[1]))
|
||||
if((MMU.reg_IE[1] & MMU.gen_IF<1>()))
|
||||
{
|
||||
nds.sleeping = FALSE;
|
||||
}
|
||||
|
@ -2062,7 +2063,7 @@ void NDS_exec(s32 nb)
|
|||
|
||||
void execHardware_interrupts()
|
||||
{
|
||||
if((MMU.reg_IF[0]&MMU.reg_IE[0]) && (MMU.reg_IME[0]))
|
||||
if((MMU.reg_IME[0]) && (MMU.gen_IF<0>()&MMU.reg_IE[0]))
|
||||
{
|
||||
//TODO - remove GDB specific code
|
||||
//#ifdef GDB_STUB
|
||||
|
@ -2076,7 +2077,7 @@ void execHardware_interrupts()
|
|||
}
|
||||
}
|
||||
//TODO - remove GDB specific code
|
||||
if((MMU.reg_IF[1]&MMU.reg_IE[1]) && (MMU.reg_IME[1]))
|
||||
if((MMU.reg_IME[1]) && (MMU.gen_IF<1>()&MMU.reg_IE[1]))
|
||||
{
|
||||
//#ifdef GDB_STUB
|
||||
// if ( armcpu_flagIrq( &NDS_ARM7))
|
||||
|
|
|
@ -261,19 +261,23 @@ extern armcpu_t NDS_ARM9;
|
|||
|
||||
static INLINE void setIF(int PROCNUM, u32 flag)
|
||||
{
|
||||
MMU.reg_IF[PROCNUM] |= flag;
|
||||
//don't set generated bits!!!
|
||||
assert(!(flag&0x00260000));
|
||||
|
||||
MMU.reg_IF_bits[PROCNUM] |= flag;
|
||||
|
||||
extern void NDS_Reschedule();
|
||||
NDS_Reschedule();
|
||||
|
||||
//TODO SEP - was this necessary???
|
||||
//generate the interrupt if enabled
|
||||
if ((MMU.reg_IE[PROCNUM] & (flag)) && MMU.reg_IME[PROCNUM])
|
||||
{
|
||||
if(PROCNUM==0)
|
||||
NDS_ARM9.waitIRQ = FALSE;
|
||||
else
|
||||
NDS_ARM7.waitIRQ = FALSE;
|
||||
}
|
||||
//if ((MMU.reg_IE[PROCNUM] & (flag)) && MMU.reg_IME[PROCNUM])
|
||||
//{
|
||||
// if(PROCNUM==0)
|
||||
// NDS_ARM9.waitIRQ = FALSE;
|
||||
// else
|
||||
// NDS_ARM7.waitIRQ = FALSE;
|
||||
//}
|
||||
}
|
||||
|
||||
static INLINE void NDS_makeARM9Int(u32 num)
|
||||
|
|
|
@ -202,7 +202,7 @@ SFORMAT SF_MMU[]={
|
|||
{ "MTRL", 2, 8, MMU.timerReload},
|
||||
{ "MIME", 4, 2, MMU.reg_IME},
|
||||
{ "MIE_", 4, 2, MMU.reg_IE},
|
||||
{ "MIF_", 4, 2, MMU.reg_IF},
|
||||
{ "MIF_", 4, 2, MMU.reg_IF_bits},
|
||||
|
||||
{ "MGXC", 8, 1, &MMU.gfx3dCycles},
|
||||
|
||||
|
@ -449,6 +449,10 @@ static bool mmu_loadstate(EMUFILE* is, int size)
|
|||
ok &= MMU_new.sqrt.loadstate(is,version);
|
||||
ok &= MMU_new.div.loadstate(is,version);
|
||||
|
||||
//to prevent old savestates from confusing IF bits, mask out ones which had been stored but should have been generated
|
||||
MMU.reg_IF_bits[0] &= ~0x00260000;
|
||||
MMU.reg_IF_bits[1] &= ~0x00060000;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue