diff --git a/src/ARM.cpp b/src/ARM.cpp index f537fb49..a8ac0cc6 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -176,14 +176,14 @@ void ARMv5::JumpTo(u32 addr, bool restorecpsr) //if (addr == 0x0201764C) printf("capture test %d: R1=%08X\n", R[6], R[1]); //if (addr == 0x020175D8) printf("capture test %d: res=%08X\n", R[6], R[0]); // R0=DMA# R1=src R2=size + //if (addr==0x02019A88) printf("[%08X] [%03d] GX FIFO CMD %08X\n", R[15], NDS::ARM9Read16(0x04000006), R[0]); + //if (addr==0x02022A5C) printf("[%08X] [%03d|%04X] RENDE SHITO %08X\n", R[15], NDS::ARM9Read16(0x04000006), NDS::ARM9Read16(0x04000304), R[0]); u32 oldregion = R[15] >> 24; u32 newregion = addr >> 24; RegionCodeCycles = MemTimings[addr >> 12][0]; - s32 cycles; - if (addr & 0x1) { addr &= ~0x1; @@ -195,15 +195,16 @@ void ARMv5::JumpTo(u32 addr, bool restorecpsr) // doesn't matter if we put garbage in the MSbs there if (addr & 0x2) { - NextInstr[0] = CodeRead32(addr-2) >> 16; - NextInstr[1] = CodeRead32(addr+2); - cycles = CodeCycles * 2; + NextInstr[0] = CodeRead32(addr-2, true) >> 16; + Cycles += CodeCycles; + NextInstr[1] = CodeRead32(addr+2, false); + Cycles += CodeCycles; } else { - NextInstr[0] = CodeRead32(addr); + NextInstr[0] = CodeRead32(addr, true); NextInstr[1] = NextInstr[0] >> 16; - cycles = CodeCycles; + Cycles += CodeCycles; } CPSR |= 0x20; @@ -215,9 +216,10 @@ void ARMv5::JumpTo(u32 addr, bool restorecpsr) if (newregion != oldregion) SetupCodeMem(addr); - NextInstr[0] = CodeRead32(addr); - NextInstr[1] = CodeRead32(addr+4); - cycles = CodeCycles * 2; + NextInstr[0] = CodeRead32(addr, true); + Cycles += CodeCycles; + NextInstr[1] = CodeRead32(addr+4, false); + Cycles += CodeCycles; CPSR &= ~0x20; } @@ -231,8 +233,6 @@ void ARMv5::JumpTo(u32 addr, bool restorecpsr) PrefetchAbort(); return; }*/ - - Cycles += cycles; } void ARMv4::JumpTo(u32 addr, bool restorecpsr) @@ -487,7 +487,7 @@ s32 ARMv5::Execute() CurInstr = NextInstr[0]; NextInstr[0] = NextInstr[1]; if (R[15] & 0x2) { NextInstr[1] >>= 16; CodeCycles = 0; } - else NextInstr[1] = CodeRead32(R[15]); + else NextInstr[1] = CodeRead32(R[15], false); // actually execute u32 icode = (CurInstr >> 6) & 0x3FF; @@ -499,7 +499,7 @@ s32 ARMv5::Execute() R[15] += 4; CurInstr = NextInstr[0]; NextInstr[0] = NextInstr[1]; - NextInstr[1] = CodeRead32(R[15]); + NextInstr[1] = CodeRead32(R[15], false); // actually execute if (CheckCondition(CurInstr >> 28)) @@ -515,7 +515,7 @@ s32 ARMv5::Execute() AddCycles_C(); } - //s32 diff = Cycles - lastcycles;arm9timer+=(diff>>1); + //s32 diff = Cycles - lastcycles; //NDS::RunTightTimers(0, diff >> ClockShift); //lastcycles = Cycles - (diff & ClockDiffMask); @@ -543,7 +543,7 @@ s32 ARMv5::Execute() /*if (Cycles > lastcycles) { - //s32 diff = Cycles - lastcycles;arm9timer+=(diff>>1); + s32 diff = Cycles - lastcycles; //NDS::RunTightTimers(0, diff >> ClockShift); }*/ #ifdef DEBUG_CHECK_DESYNC @@ -613,7 +613,7 @@ s32 ARMv4::Execute() AddCycles_C(); } - //s32 diff = Cycles - lastcycles;arm7timer+=diff; + //s32 diff = Cycles - lastcycles; //NDS::RunTightTimers(1, diff); //lastcycles = Cycles; @@ -641,7 +641,7 @@ s32 ARMv4::Execute() /*if (Cycles > lastcycles) { - //s32 diff = Cycles - lastcycles;arm7timer+=(diff); + //s32 diff = Cycles - lastcycles; //NDS::RunTightTimers(1, diff); }*/ diff --git a/src/ARM.h b/src/ARM.h index 9a9b03c6..b37ab226 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -173,7 +173,7 @@ public: s32 Execute(); // all code accesses are forced nonseq 32bit - u32 CodeRead32(u32 addr); + u32 CodeRead32(u32 addr, bool branch); void DataRead8(u32 addr, u32* val); void DataRead16(u32 addr, u32* val); @@ -233,11 +233,19 @@ public: void UpdatePURegions(); + u32 RandomLineIndex(); + + void ICacheLookup(u32 addr); + void ICacheInvalidateByAddr(u32 addr); + void ICacheInvalidateAll(); + void CP15Write(u32 id, u32 val); u32 CP15Read(u32 id); u32 CP15Control; + u32 RNGSeed; + u32 DTCMSetting, ITCMSetting; u8 ITCM[0x8000]; @@ -245,6 +253,10 @@ public: u8 DTCM[0x4000]; u32 DTCMBase, DTCMSize; + u8 ICache[0x2000]; + u32 ICacheTags[64*4]; + u8 ICacheCount[64]; + u32 PU_CodeCacheable; u32 PU_DataCacheable; u32 PU_DataCacheWrite; @@ -265,6 +277,7 @@ public: u8 MemTimings[0x100000][4]; s32 RegionCodeCycles; + u8* CurICacheLine; }; class ARMv4 : public ARM diff --git a/src/CP15.cpp b/src/CP15.cpp index 8661364d..7da41e84 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -35,6 +35,8 @@ void ARMv5::CP15Reset() { CP15Control = 0x2078; // dunno + RNGSeed = 44203; + DTCMSetting = 0; ITCMSetting = 0; @@ -45,6 +47,10 @@ void ARMv5::CP15Reset() DTCMBase = 0xFFFFFFFF; DTCMSize = 0; + memset(ICache, 0, 0x2000); + ICacheInvalidateAll(); + memset(ICacheCount, 0, 64); + PU_CodeCacheable = 0; PU_DataCacheable = 0; PU_DataCacheWrite = 0; @@ -54,6 +60,8 @@ void ARMv5::CP15Reset() memset(PU_Region, 0, 8*sizeof(u32)); UpdatePURegions(); + + CurICacheLine = NULL; } void ARMv5::CP15DoSavestate(Savestate* file) @@ -276,6 +284,119 @@ void ARMv5::UpdateRegionTimings(u32 addrstart, u32 addrend) } +u32 ARMv5::RandomLineIndex() +{ + // lame RNG, but good enough for this purpose + u32 s = RNGSeed; + RNGSeed ^= (s*17); + RNGSeed ^= (s*7); + + return (RNGSeed >> 17) & 0x3; +} + +int zog=1; +void ARMv5::ICacheLookup(u32 addr) +{ + u32 tag = addr & 0xFFFFF800; + u32 id = (addr >> 5) & 0x3F; + + id <<= 2; + if (ICacheTags[id+0] == tag) + { + CodeCycles = 1;zog=1; + CurICacheLine = &ICache[(id+0) << 5]; + return; + } + if (ICacheTags[id+1] == tag) + { + CodeCycles = 1;zog=2; + CurICacheLine = &ICache[(id+1) << 5]; + return; + } + if (ICacheTags[id+2] == tag) + { + CodeCycles = 1;zog=3; + CurICacheLine = &ICache[(id+2) << 5]; + return; + } + if (ICacheTags[id+3] == tag) + { + CodeCycles = 1;zog=4; + CurICacheLine = &ICache[(id+3) << 5]; + return; + } + + // cache miss + + u32 line; + if (CP15Control & (1<<14)) + { + line = ICacheCount[id>>2]; + ICacheCount[id>>2] = (line+1) & 0x3; + } + else + { + line = RandomLineIndex(); + } + + line += id; + + addr &= ~0x1F; + u8* ptr = &ICache[line << 5]; + + if (CodeMem.Mem) + { + memcpy(ptr, &CodeMem.Mem[addr & CodeMem.Mask], 32); + } + else + { + for (int i = 0; i < 32; i+=4) + *(u32*)&ptr[i] = NDS::ARM9Read32(addr+i); + } + + ICacheTags[line] = tag; + + // ouch :/ + //printf("cache miss %08X: %d/%d\n", addr, NDS::ARM9MemTimings[addr >> 14][2], NDS::ARM9MemTimings[addr >> 14][3]); + CodeCycles = (NDS::ARM9MemTimings[addr >> 14][2] + (NDS::ARM9MemTimings[addr >> 14][3] * 7)) << ClockShift; + CurICacheLine = ptr; +} + +void ARMv5::ICacheInvalidateByAddr(u32 addr) +{ + u32 tag = addr & 0xFFFFF800; + u32 id = (addr >> 5) & 0x3F; + + id <<= 2; + if (ICacheTags[id+0] == tag) + { + ICacheTags[id+0] = 1; + return; + } + if (ICacheTags[id+1] == tag) + { + ICacheTags[id+1] = 1; + return; + } + if (ICacheTags[id+2] == tag) + { + ICacheTags[id+2] = 1; + return; + } + if (ICacheTags[id+3] == tag) + { + ICacheTags[id+3] = 1; + return; + } +} + +void ARMv5::ICacheInvalidateAll() +{ + for (int i = 0; i < 64*4; i++) + ICacheTags[i] = 1; +} + + void ARMv5::CP15Write(u32 id, u32 val) { //printf("CP15 write op %03X %08X %08X\n", id, val, NDS::ARM9->R[15]); @@ -391,6 +512,17 @@ void ARMv5::CP15Write(u32 id, u32 val) return; + case 0x750: + ICacheInvalidateAll(); + return; + case 0x751: + ICacheInvalidateByAddr(val); + return; + case 0x752: + printf("CP15: ICACHE INVALIDATE WEIRD. %08X\n", val); + return; + + case 0x761: //printf("inval data cache %08X\n", val); return; @@ -519,7 +651,7 @@ u32 ARMv5::CP15Read(u32 id) // TCM are handled here. // TODO: later on, handle PU, and maybe caches -u32 ARMv5::CodeRead32(u32 addr) +u32 ARMv5::CodeRead32(u32 addr, bool branch) { if (addr < ITCMSize) { @@ -528,11 +660,14 @@ u32 ARMv5::CodeRead32(u32 addr) } CodeCycles = RegionCodeCycles; - if (CodeCycles == 0xFF) + if (CodeCycles == 0xFF) // cached memory. hax { - // sort of code cache hit/miss average - if (!(addr & 0x1F)) CodeCycles = kCodeCacheTiming; - else CodeCycles = 1; + if (branch || !(addr & 0x1F)) + CodeCycles = kCodeCacheTiming;//ICacheLookup(addr); + else + CodeCycles = 1; + + //return *(u32*)&CurICacheLine[addr & 0x1C]; } if (CodeMem.Mem) return *(u32*)&CodeMem.Mem[addr & CodeMem.Mask];