From a2f711c04852558bdd025de3367655ff5db4d045 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 18 Jan 2024 09:39:33 +0100 Subject: [PATCH 01/39] Added CP15 Data and Instruction Cache Lockdown Register --- src/ARM.h | 1 + src/CP15.cpp | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/ARM.h b/src/ARM.h index 1e0b71b8..c6711333 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -322,6 +322,7 @@ public: u32 RNGSeed; u32 DTCMSetting, ITCMSetting; + u32 DCacheLockDown, ICacheLockDown; // for aarch64 JIT they need to go up here // to be addressable by a 12-bit immediate diff --git a/src/CP15.cpp b/src/CP15.cpp index 58137fdd..ebebf975 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -55,6 +55,9 @@ void ARMv5::CP15Reset() DTCMBase = 0xFFFFFFFF; DTCMMask = 0; + ICacheLockDown = 0; + DCacheLockDown = 0; + memset(ICache, 0, 0x2000); ICacheInvalidateAll(); memset(ICacheCount, 0, 64); @@ -628,6 +631,22 @@ void ARMv5::CP15Write(u32 id, u32 val) //printf("flush data cache SI\n"); return; + case 0x900: + // Cache Lockdown - Format B + // Bit 31: Lock bit + // Bit 0..Way-1: locked ways + // The Cache is 4 way associative + // But all bits are r/w + DCacheLockDown = val ; + return; + case 0x901: + // Cache Lockdown - Format B + // Bit 31: Lock bit + // Bit 0..Way-1: locked ways + // The Cache is 4 way associative + // But all bits are r/w + ICacheLockDown = val; + return; case 0x910: DTCMSetting = val & 0xFFFFF03E; @@ -751,6 +770,10 @@ u32 ARMv5::CP15Read(u32 id) const case 0x671: return PU_Region[(id >> 4) & 0xF]; + case 0x900: + return DCacheLockDown; + case 0x901: + return ICacheLockDown; case 0x910: return DTCMSetting; From 716b4af81548614200cdfa560079c9c3b7a8e896 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 18 Jan 2024 14:35:03 +0100 Subject: [PATCH 02/39] Added ICacheLockDown and DCacheLockDown to CP15 savestate --- src/CP15.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/CP15.cpp b/src/CP15.cpp index ebebf975..b4bc5050 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -87,6 +87,9 @@ void ARMv5::CP15DoSavestate(Savestate* file) file->VarArray(ITCM, ITCMPhysicalSize); file->VarArray(DTCM, DTCMPhysicalSize); + file->Var32(&DCacheLockDown); + file->Var32(&ICacheLockDown); + file->Var32(&PU_CodeCacheable); file->Var32(&PU_DataCacheable); file->Var32(&PU_DataCacheWrite); From a4f8e6fe29ac24f15ecd1dc96382fb38244e45eb Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 18 Jan 2024 14:39:08 +0100 Subject: [PATCH 03/39] Updated savestate version --- src/Savestate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Savestate.h b/src/Savestate.h index 2e1400a0..52c7e294 100644 --- a/src/Savestate.h +++ b/src/Savestate.h @@ -24,7 +24,7 @@ #include #include "types.h" -#define SAVESTATE_MAJOR 12 +#define SAVESTATE_MAJOR 13 #define SAVESTATE_MINOR 1 namespace melonDS From 1019afee92778a718301b77b6c8af75123e6c8be Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Fri, 19 Jan 2024 08:30:38 +0100 Subject: [PATCH 04/39] Cleaned up magic numbers and simplified (not yet used) ICache functions Marked reading CP15 Cache Dirty Bit as not present --- src/CP15.cpp | 101 ++++++++++++++++++++------------------------- src/MemConstants.h | 14 +++++++ 2 files changed, 58 insertions(+), 57 deletions(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index b4bc5050..916f1631 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -58,9 +58,9 @@ void ARMv5::CP15Reset() ICacheLockDown = 0; DCacheLockDown = 0; - memset(ICache, 0, 0x2000); + memset(ICache, 0, ICACHE_SIZE); ICacheInvalidateAll(); - memset(ICacheCount, 0, 64); + memset(ICacheCount, 0, ICACHE_LINESPERSET); PU_CodeCacheable = 0; PU_DataCacheable = 0; @@ -340,42 +340,26 @@ u32 ARMv5::RandomLineIndex() void ARMv5::ICacheLookup(u32 addr) { - u32 tag = addr & 0xFFFFF800; - u32 id = (addr >> 5) & 0x3F; + u32 tag = addr & ~(ICACHE_LINESPERSET * ICACHE_LINELENGTH - 1); + u32 id = (addr >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1); - id <<= 2; - if (ICacheTags[id+0] == tag) + id <<= ICACHE_SETS_LOG2; + for (int set=0;set>2]; - ICacheCount[id>>2] = (line+1) & 0x3; + line = ICacheCount[id>>ICACHE_SETS_LOG2]; + ICacheCount[id>>ICACHE_SETS_LOG2] = (line+1) & (ICACHE_SETS-1); } else { @@ -384,16 +368,16 @@ void ARMv5::ICacheLookup(u32 addr) line += id; - addr &= ~0x1F; - u8* ptr = &ICache[line << 5]; + addr &= ~(ICACHE_LINELENGTH-1); + u8* ptr = &ICache[line << ICACHE_LINELENGTH_LOG2]; if (CodeMem.Mem) { - memcpy(ptr, &CodeMem.Mem[addr & CodeMem.Mask], 32); + memcpy(ptr, &CodeMem.Mem[addr & CodeMem.Mask], ICACHE_LINELENGTH); } else { - for (int i = 0; i < 32; i+=4) + for (int i = 0; i < ICACHE_LINELENGTH; i+=sizeof(u32)) *(u32*)&ptr[i] = NDS.ARM9Read32(addr+i); } @@ -407,35 +391,29 @@ void ARMv5::ICacheLookup(u32 addr) void ARMv5::ICacheInvalidateByAddr(u32 addr) { - u32 tag = addr & 0xFFFFF800; - u32 id = (addr >> 5) & 0x3F; + u32 tag = addr & ~(ICACHE_LINESPERSET * ICACHE_LINELENGTH - 1); + u32 id = (addr >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1); - id <<= 2; - if (ICacheTags[id+0] == tag) + id <<= ICACHE_SETS_LOG2; + for (int set=0;set> 4) & 0xF]; + case 0x7A6: + // read Cache Dirty Bit (optional) + // it is not present on the NDS/DSi + return 0; + case 0x900: return DCacheLockDown; case 0x901: diff --git a/src/MemConstants.h b/src/MemConstants.h index e9aa6b2b..ccd1ea00 100644 --- a/src/MemConstants.h +++ b/src/MemConstants.h @@ -34,6 +34,20 @@ constexpr u32 ITCMPhysicalSize = 0x8000; constexpr u32 DTCMPhysicalSize = 0x4000; constexpr u32 ARM7BIOSCRC32 = 0x1280f0d5; constexpr u32 ARM9BIOSCRC32 = 0x2ab23573; + +constexpr u32 ICACHE_SIZE_LOG2 = 13; +constexpr u32 ICACHE_SIZE = 1 << ICACHE_SIZE_LOG2; +constexpr u32 ICACHE_SETS_LOG2 = 2; +constexpr u32 ICACHE_SETS = 1 << ICACHE_SETS_LOG2; +constexpr u32 ICACHE_LINELENGTH_ENCODED = 2; +constexpr u32 ICACHE_LINELENGTH_LOG2 = ICACHE_LINELENGTH_ENCODED + 3; +constexpr u32 ICACHE_LINELENGTH = 8 * (1 << ICACHE_LINELENGTH_ENCODED); +constexpr u32 ICACHE_LINESPERSET = ICACHE_SIZE / (ICACHE_SETS * ICACHE_LINELENGTH); + +constexpr u32 CP15_CACHE_CR_ROUNDROBIN = (1 < 14); +constexpr u32 CP15_CACHE_CR_ICACHEENABLE = (1 < 12); +constexpr u32 CP15_CACHE_CR_DCACHEENABLE = (1 < 2); +constexpr u32 CP15_CACHE_CR_WRITEBUFFERENABLE = (1 < 3); } #endif // MELONDS_MEMCONSTANTS_H \ No newline at end of file From 434c234098dcefaeeebeefc7c699f0541b02d1fe Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Fri, 19 Jan 2024 10:00:02 +0100 Subject: [PATCH 05/39] Enable instruction cache routines. Fixed typos in constants. --- src/ARM.h | 1 + src/CP15.cpp | 18 +++++++++++++++++- src/MemConstants.h | 9 +++++---- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/ARM.h b/src/ARM.h index c6711333..64921654 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -313,6 +313,7 @@ public: void ICacheLookup(u32 addr); void ICacheInvalidateByAddr(u32 addr); void ICacheInvalidateAll(); + bool IsAddressICachable(u32 addr); void CP15Write(u32 id, u32 val); u32 CP15Read(u32 id) const; diff --git a/src/CP15.cpp b/src/CP15.cpp index 916f1631..0573f974 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -417,6 +417,11 @@ void ARMv5::ICacheInvalidateAll() ICacheTags[i] = 1; } +bool ARMv5::IsAddressICachable(u32 addr) +{ + return PU_Map[addr >> 12] & 0x40 ; +} + void ARMv5::CP15Write(u32 id, u32 val) { @@ -430,7 +435,7 @@ void ARMv5::CP15Write(u32 id, u32 val) val &= 0x000FF085; CP15Control &= ~0x000FF085; CP15Control |= val; - //printf("CP15Control = %08X (%08X->%08X)\n", CP15Control, old, val); + //Log(LogLevel::Debug, "CP15Control = %08X (%08X->%08X)\n", CP15Control, old, val); UpdateDTCMSetting(); UpdateITCMSetting(); if ((old & 0x1005) != (val & 0x1005)) @@ -800,6 +805,7 @@ u32 ARMv5::CodeRead32(u32 addr, bool branch) } CodeCycles = RegionCodeCycles; +#if 0 if (CodeCycles == 0xFF) // cached memory. hax { if (branch || !(addr & 0x1F)) @@ -809,6 +815,16 @@ u32 ARMv5::CodeRead32(u32 addr, bool branch) //return *(u32*)&CurICacheLine[addr & 0x1C]; } +#else + if (CP15Control & CP15_CACHE_CR_ICACHEENABLE) + { + if (IsAddressICachable(addr)) + { + ICacheLookup(addr); + return *(u32*)&CurICacheLine[addr & (ICACHE_LINELENGTH - 4)]; + } + } +#endif if (CodeMem.Mem) return *(u32*)&CodeMem.Mem[addr & CodeMem.Mask]; diff --git a/src/MemConstants.h b/src/MemConstants.h index ccd1ea00..fbb37523 100644 --- a/src/MemConstants.h +++ b/src/MemConstants.h @@ -44,10 +44,11 @@ constexpr u32 ICACHE_LINELENGTH_LOG2 = ICACHE_LINELENGTH_ENCODED + 3; constexpr u32 ICACHE_LINELENGTH = 8 * (1 << ICACHE_LINELENGTH_ENCODED); constexpr u32 ICACHE_LINESPERSET = ICACHE_SIZE / (ICACHE_SETS * ICACHE_LINELENGTH); -constexpr u32 CP15_CACHE_CR_ROUNDROBIN = (1 < 14); -constexpr u32 CP15_CACHE_CR_ICACHEENABLE = (1 < 12); -constexpr u32 CP15_CACHE_CR_DCACHEENABLE = (1 < 2); -constexpr u32 CP15_CACHE_CR_WRITEBUFFERENABLE = (1 < 3); +constexpr u32 CP15_CR_MPUENABLE = (1 << 0); +constexpr u32 CP15_CACHE_CR_ROUNDROBIN = (1 << 14); +constexpr u32 CP15_CACHE_CR_ICACHEENABLE = (1 << 12); +constexpr u32 CP15_CACHE_CR_DCACHEENABLE = (1 << 2); +constexpr u32 CP15_CACHE_CR_WRITEBUFFERENABLE = (1 << 3); } #endif // MELONDS_MEMCONSTANTS_H \ No newline at end of file From d9fcc2ec2c47ea91a1e5542f7fdcf30c3536e398 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Fri, 19 Jan 2024 10:24:02 +0100 Subject: [PATCH 06/39] Replaced more CP15 magic values with named constants --- src/CP15.cpp | 22 +++++++++++----------- src/MemConstants.h | 5 +++++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index 0573f974..781f1253 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -114,7 +114,7 @@ void ARMv5::UpdateDTCMSetting() u32 newDTCMMask; u32 newDTCMSize; - if (CP15Control & (1<<16)) + if (CP15Control & CP15_TCM_CR_DTCM_ENABLE) { newDTCMSize = 0x200 << ((DTCMSetting >> 1) & 0x1F); if (newDTCMSize < 0x1000) newDTCMSize = 0x1000; @@ -138,7 +138,7 @@ void ARMv5::UpdateDTCMSetting() void ARMv5::UpdateITCMSetting() { - if (CP15Control & (1<<18)) + if (CP15Control & CP15_TCM_CR_ITCM_ENABLE) { ITCMSize = 0x200 << ((ITCMSetting >> 1) & 0x1F); #ifdef JIT_ENABLED @@ -156,7 +156,7 @@ void ARMv5::UpdateITCMSetting() // (not to the region range/enabled status) void ARMv5::UpdatePURegion(u32 n) { - if (!(CP15Control & (1<<0))) + if (!(CP15Control & CP15_CR_MPUENABLE)) return; u32 coderw = (PU_CodeRW >> (4*n)) & 0xF; @@ -170,12 +170,12 @@ void ARMv5::UpdatePURegion(u32 n) // 1/0: goes to memory and cache // 1/1: goes to cache - if (CP15Control & (1<<12)) + if (CP15Control & CP15_CACHE_CR_ICACHEENABLE) codecache = (PU_CodeCacheable >> n) & 0x1; else codecache = 0; - if (CP15Control & (1<<2)) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { datacache = (PU_DataCacheable >> n) & 0x1; datawrite = (PU_DataCacheWrite >> n) & 0x1; @@ -263,13 +263,13 @@ void ARMv5::UpdatePURegion(u32 n) void ARMv5::UpdatePURegions(bool update_all) { - if (!(CP15Control & (1<<0))) + if (!(CP15Control & CP15_CR_MPUENABLE)) { // PU disabled u8 mask = 0x07; - if (CP15Control & (1<<2)) mask |= 0x30; - if (CP15Control & (1<<12)) mask |= 0x40; + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) mask |= 0x30; + if (CP15Control & CP15_CACHE_CR_ICACHEENABLE) mask |= 0x40; memset(PU_UserMap, mask, 0x100000); memset(PU_PrivMap, mask, 0x100000); @@ -442,9 +442,9 @@ void ARMv5::CP15Write(u32 id, u32 val) { UpdatePURegions((old & 0x1) != (val & 0x1)); } - if (val & (1<<7)) Log(LogLevel::Warn, "!!!! ARM9 BIG ENDIAN MODE. VERY BAD. SHIT GONNA ASPLODE NOW\n"); - if (val & (1<<13)) ExceptionBase = 0xFFFF0000; - else ExceptionBase = 0x00000000; + if (val & CP15_CR_BIGENDIAN) Log(LogLevel::Warn, "!!!! ARM9 BIG ENDIAN MODE. VERY BAD. SHIT GONNA ASPLODE NOW\n"); + if (val & CP15_CR_HIGHEXCEPTIONBASE) ExceptionBase = 0xFFFF0000; + else ExceptionBase = 0x00000000; } return; diff --git a/src/MemConstants.h b/src/MemConstants.h index fbb37523..f06edd96 100644 --- a/src/MemConstants.h +++ b/src/MemConstants.h @@ -45,10 +45,15 @@ constexpr u32 ICACHE_LINELENGTH = 8 * (1 << ICACHE_LINELENGTH_ENCODED); constexpr u32 ICACHE_LINESPERSET = ICACHE_SIZE / (ICACHE_SETS * ICACHE_LINELENGTH); constexpr u32 CP15_CR_MPUENABLE = (1 << 0); +constexpr u32 CP15_CR_BIGENDIAN = (1 << 7); +constexpr u32 CP15_CR_HIGHEXCEPTIONBASE = (1 << 13); constexpr u32 CP15_CACHE_CR_ROUNDROBIN = (1 << 14); constexpr u32 CP15_CACHE_CR_ICACHEENABLE = (1 << 12); constexpr u32 CP15_CACHE_CR_DCACHEENABLE = (1 << 2); constexpr u32 CP15_CACHE_CR_WRITEBUFFERENABLE = (1 << 3); +constexpr u32 CP15_TCM_CR_DTCM_ENABLE = (1 << 16); +constexpr u32 CP15_TCM_CR_ITCM_ENABLE = (1 << 18); + } #endif // MELONDS_MEMCONSTANTS_H \ No newline at end of file From b6b0197dd3e1da1df3a14e0446772885f271a8ff Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Fri, 19 Jan 2024 10:38:07 +0100 Subject: [PATCH 07/39] Implemented "weird" instruction cache invalidation by Set/Way --- src/ARM.h | 2 ++ src/CP15.cpp | 22 +++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/ARM.h b/src/ARM.h index 64921654..e9611b81 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -312,6 +312,8 @@ public: void ICacheLookup(u32 addr); void ICacheInvalidateByAddr(u32 addr); + void ICacheInvalidateBySetAndWay(u8 cacheSet, u8 cacheLine); + void ICacheInvalidateAll(); bool IsAddressICachable(u32 addr); diff --git a/src/CP15.cpp b/src/CP15.cpp index 781f1253..22285cf7 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -408,6 +408,21 @@ void ARMv5::ICacheInvalidateByAddr(u32 addr) } } +void ARMv5::ICacheInvalidateBySetAndWay(u8 cacheSet, u8 cacheLine) +{ + if (cacheSet >= ICACHE_SETS) + return; + if (cacheLine >= ICACHE_LINESPERSET) + return; + + u32 idx = (cacheLine << ICACHE_SETS_LOG2) + cacheSet; + // TODO: is this a valid magic number? + // it should indicate that no address is loaded here, instead + // a tag of 1 indicates that addr 0x00000800.. 0x0000FBF (depending on id) ist stored at this set. + ICacheTags[idx] = 1; +} + + void ARMv5::ICacheInvalidateAll() { // TODO: is this a valid magic number? @@ -598,7 +613,12 @@ void ARMv5::CP15Write(u32 id, u32 val) //Halt(255); return; case 0x752: - Log(LogLevel::Warn, "CP15: ICACHE INVALIDATE WEIRD. %08X\n", val); + { + // Cache invalidat by line number and set number + u8 cacheSet = val >> (32 - ICACHE_SETS_LOG2) & (ICACHE_SETS -1); + u8 cacheLine = (val >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET -1); + ICacheInvalidateBySetAndWay(cacheSet, cacheLine); + } //Halt(255); return; From 0a07661b5744587196009fd6a2515c66817fe53d Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Wed, 24 Jan 2024 09:51:56 +0100 Subject: [PATCH 08/39] Implemented DCache and several CP15 registers --- src/ARM.h | 30 +++- src/CP15.cpp | 355 +++++++++++++++++++++++++++++++++++++++++---- src/MemConstants.h | 13 ++ 3 files changed, 363 insertions(+), 35 deletions(-) diff --git a/src/ARM.h b/src/ARM.h index e9611b81..99ef4baf 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -311,11 +311,25 @@ public: u32 RandomLineIndex(); void ICacheLookup(u32 addr); + bool IsAddressICachable(u32 addr); + + void ICacheInvalidateAll(); void ICacheInvalidateByAddr(u32 addr); void ICacheInvalidateBySetAndWay(u8 cacheSet, u8 cacheLine); - void ICacheInvalidateAll(); - bool IsAddressICachable(u32 addr); + + void DCacheLookup(u32 addr); + bool IsAddressDCachable(u32 addr); + + void DCacheInvalidateAll(); + void DCacheInvalidateByAddr(u32 addr); + void DCacheInvalidateBySetAndWay(u8 cacheSet, u8 cacheLine); + + void DCacheClearAll(); + void DCacheClearByAddr(u32 addr); + void DCacheClearByASetAndWay(u8 cacheSet, u8 cacheLine); + + void CP15Write(u32 id, u32 val); u32 CP15Read(u32 id) const; @@ -326,6 +340,7 @@ public: u32 DTCMSetting, ITCMSetting; u32 DCacheLockDown, ICacheLockDown; + u32 CacheDebugRegisterIndex; // for aarch64 JIT they need to go up here // to be addressable by a 12-bit immediate @@ -336,9 +351,13 @@ public: u8 ITCM[ITCMPhysicalSize]; u8* DTCM; - u8 ICache[0x2000]; - u32 ICacheTags[64*4]; - u8 ICacheCount[64]; + u8 ICache[ICACHE_SIZE]; + u32 ICacheTags[ICACHE_LINESPERSET*ICACHE_SETS]; + u8 ICacheCount; + + u8 DCache[DCACHE_SIZE]; + u32 DCacheTags[DCACHE_LINESPERSET*DCACHE_SETS]; + u8 DCacheCount; u32 PU_CodeCacheable; u32 PU_DataCacheable; @@ -361,6 +380,7 @@ public: u8 MemTimings[0x100000][4]; u8* CurICacheLine; + u8* CurDCacheLine; bool (*GetMemRegion)(u32 addr, bool write, MemRegion* region); diff --git a/src/CP15.cpp b/src/CP15.cpp index 22285cf7..ea3acddf 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -57,10 +57,15 @@ void ARMv5::CP15Reset() ICacheLockDown = 0; DCacheLockDown = 0; + CacheDebugRegisterIndex = 0; memset(ICache, 0, ICACHE_SIZE); ICacheInvalidateAll(); - memset(ICacheCount, 0, ICACHE_LINESPERSET); + ICacheCount = 0; + + memset(DCache, 0, DCACHE_SIZE); + DCacheInvalidateAll(); + DCacheCount = 0; PU_CodeCacheable = 0; PU_DataCacheable = 0; @@ -87,8 +92,17 @@ void ARMv5::CP15DoSavestate(Savestate* file) file->VarArray(ITCM, ITCMPhysicalSize); file->VarArray(DTCM, DTCMPhysicalSize); + file->VarArray(ICache, sizeof(ICache)); + file->VarArray(ICacheTags, sizeof(ICacheTags)); + file->Var8(&ICacheCount); + + file->VarArray(DCache, sizeof(DCache)); + file->VarArray(DCacheTags, sizeof(DCacheTags)); + file->Var8(&DCacheCount); + file->Var32(&DCacheLockDown); file->Var32(&ICacheLockDown); + file->Var32(&CacheDebugRegisterIndex); file->Var32(&PU_CodeCacheable); file->Var32(&PU_DataCacheable); @@ -340,13 +354,13 @@ u32 ARMv5::RandomLineIndex() void ARMv5::ICacheLookup(u32 addr) { - u32 tag = addr & ~(ICACHE_LINESPERSET * ICACHE_LINELENGTH - 1); + u32 tag = (addr & ~(ICACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; u32 id = (addr >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1); id <<= ICACHE_SETS_LOG2; for (int set=0;set>ICACHE_SETS_LOG2]; - ICacheCount[id>>ICACHE_SETS_LOG2] = (line+1) & (ICACHE_SETS-1); + line = ICacheCount; + ICacheCount = (line+1) & (ICACHE_SETS-1); } else { @@ -381,7 +395,7 @@ void ARMv5::ICacheLookup(u32 addr) *(u32*)&ptr[i] = NDS.ARM9Read32(addr+i); } - ICacheTags[line] = tag; + ICacheTags[line] = addr | (line & (ICACHE_SETS-1)) | CACHE_FLAG_VALID; // ouch :/ //printf("cache miss %08X: %d/%d\n", addr, NDS::ARM9MemTimings[addr >> 14][2], NDS::ARM9MemTimings[addr >> 14][3]); @@ -391,18 +405,15 @@ void ARMv5::ICacheLookup(u32 addr) void ARMv5::ICacheInvalidateByAddr(u32 addr) { - u32 tag = addr & ~(ICACHE_LINESPERSET * ICACHE_LINELENGTH - 1); + u32 tag = (addr & ~(ICACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; u32 id = (addr >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1); id <<= ICACHE_SETS_LOG2; for (int set=0;set> 12] & 0x40 ; } +void ARMv5::DCacheLookup(u32 addr) +{ + //Log(LogLevel::Debug,"DCache load @ %08x\n", addr); + addr &= ~3; + u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; + u32 id = (addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); + + id <<= DCACHE_SETS_LOG2; + for (int set=0;set %08lx\n", addr, ((u32 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); + return; + } + } + + // cache miss + u32 line; + if (CP15Control & CP15_CACHE_CR_ROUNDROBIN) + { + line = DCacheCount; + DCacheCount = (line+1) & (DCACHE_SETS-1); + } + else + { + line = RandomLineIndex(); + } + + line += id; + + addr &= ~(DCACHE_LINELENGTH-1); + u8* ptr = &DCache[line << DCACHE_LINELENGTH_LOG2]; + + //Log(LogLevel::Debug,"DCache miss, load @ %08x\n", addr); + for (int i = 0; i < DCACHE_LINELENGTH; i+=sizeof(u32)) + { + //DataRead32S(addr+i, (u32*)&ptr[i]); + if (addr+i < ITCMSize) + { + *((u32*)&ptr[i]) = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)]; + } else + if (((addr+i) & DTCMMask) == DTCMBase) + { + *((u32*)&ptr[i]) = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)]; + } else + { + *((u32*)&ptr[i]) = BusRead32(addr+i); + + } + //Log(LogLevel::Debug,"DCache store @ %08x: %08x\n", addr+i, *(u32*)&ptr[i]); + } + + DCacheTags[line] = addr | (line & (DCACHE_SETS-1)) | CACHE_FLAG_VALID; + + // ouch :/ + //printf("cache miss %08X: %d/%d\n", addr, NDS::ARM9MemTimings[addr >> 14][2], NDS::ARM9MemTimings[addr >> 14][3]); + DataCycles = (NDS.ARM9MemTimings[addr >> 14][2] + (NDS.ARM9MemTimings[addr >> 14][3] * 7)) << NDS.ARM9ClockShift; + CurDCacheLine = ptr; +} + +void ARMv5::DCacheInvalidateByAddr(u32 addr) +{ + u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; + u32 id = (addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); + + id <<= DCACHE_SETS_LOG2; + for (int set=0;set= DCACHE_SETS) + return; + if (cacheLine >= DCACHE_LINESPERSET) + return; + + u32 idx = (cacheLine << DCACHE_SETS_LOG2) + cacheSet; + DCacheTags[idx] &= ~CACHE_FLAG_VALID; ; +} + + +void ARMv5::DCacheInvalidateAll() +{ + for (int i = 0; i < DCACHE_SIZE / DCACHE_LINELENGTH; i++) + DCacheTags[i] &= ~CACHE_FLAG_VALID; ; +} + +void ARMv5::DCacheClearAll() +{ + // TODO: right now any write to cached data goes straight to the + // underlying memory and invalidates the cache line. +} + +void ARMv5::DCacheClearByAddr(u32 addr) +{ + // TODO: right now any write to cached data goes straight to the + // underlying memory and invalidates the cache line. +} + +void ARMv5::DCacheClearByASetAndWay(u8 cacheSet, u8 cacheLine) +{ + // TODO: right now any write to cached data goes straight to the + // underlying memory and invalidates the cache line. +} + +bool ARMv5::IsAddressDCachable(u32 addr) +{ + return PU_Map[addr >> 12] & 0x10 ; +} void ARMv5::CP15Write(u32 id, u32 val) { @@ -623,23 +748,75 @@ void ARMv5::CP15Write(u32 id, u32 val) return; - case 0x761: + case 0x760: + DCacheInvalidateAll(); //printf("inval data cache %08X\n", val); return; - case 0x762: + case 0x761: + DCacheInvalidateByAddr(val); //printf("inval data cache SI\n"); return; + case 0x762: + { + // Cache invalidat by line number and set number + u8 cacheSet = val >> (32 - DCACHE_SETS_LOG2) & (DCACHE_SETS -1); + u8 cacheLine = (val >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET -1); + DCacheInvalidateBySetAndWay(cacheSet, cacheLine); + } + return; + case 0x770: + // invalidate both caches + ICacheInvalidateAll(); + DCacheInvalidateAll(); + break; + + case 0x7A0: + //Log(LogLevel::Debug,"clean data cache\n"); + DCacheClearAll(); + return; case 0x7A1: - //printf("flush data cache %08X\n", val); + //Log(LogLevel::Debug,"clean data cache MVA\n"); + DCacheClearByAddr(val); return; case 0x7A2: - //printf("flush data cache SI\n"); + //Log(LogLevel::Debug,"clean data cache SET/WAY\n"); + { + // Cache invalidat by line number and set number + u8 cacheSet = val >> (32 - DCACHE_SETS_LOG2) & (DCACHE_SETS -1); + u8 cacheLine = (val >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET -1); + DCacheClearByASetAndWay(cacheSet, cacheLine); + } return; case 0x7A3: // Test and clean (optional) // Is not present on the NDS/DSi - return; + return; + + case 0x7D1: + Log(LogLevel::Debug,"Prefetch instruction cache MVA\n"); + break; + + case 0x7E0: + //Log(LogLevel::Debug,"clean & invalidate data cache\n"); + DCacheClearAll(); + DCacheInvalidateAll(); + return; + case 0x7E1: + //Log(LogLevel::Debug,"clean & invalidate data cache MVA\n"); + DCacheClearByAddr(val); + DCacheInvalidateByAddr(val); + return; + case 0x7E2: + //Log(LogLevel::Debug,"clean & invalidate data cache SET/WAY\n"); + { + // Cache invalidat by line number and set number + u8 cacheSet = val >> (32 - DCACHE_SETS_LOG2) & (DCACHE_SETS -1); + u8 cacheLine = (val >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET -1); + DCacheClearByASetAndWay(cacheSet, cacheLine); + DCacheInvalidateBySetAndWay(cacheSet, cacheLine); + } + return; case 0x900: // Cache Lockdown - Format B @@ -648,6 +825,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // The Cache is 4 way associative // But all bits are r/w DCacheLockDown = val ; + Log(LogLevel::Debug,"ICacheLockDown\n"); return; case 0x901: // Cache Lockdown - Format B @@ -656,6 +834,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // The Cache is 4 way associative // But all bits are r/w ICacheLockDown = val; + Log(LogLevel::Debug,"ICacheLockDown\n"); return; case 0x910: @@ -669,16 +848,27 @@ void ARMv5::CP15Write(u32 id, u32 val) return; case 0xF00: - //printf("cache debug index register %08X\n", val); + CacheDebugRegisterIndex = val; return; case 0xF10: - //printf("cache debug instruction tag %08X\n", val); - return; + // instruction cache Tag register + { + uint8_t segment = (CacheDebugRegisterIndex >> (32-ICACHE_SETS_LOG2)) & (ICACHE_SETS-1); + uint8_t wordAddress = (CacheDebugRegisterIndex & (ICACHE_LINELENGTH-1)) >> 2; + uint8_t index = (CacheDebugRegisterIndex >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1); + ICacheTags[(index << ICACHE_SETS_LOG2) + segment] = val; + } case 0xF20: - //printf("cache debug data tag %08X\n", val); - return; + // data cache Tag register + { + uint8_t segment = (CacheDebugRegisterIndex >> (32-DCACHE_SETS_LOG2)) & (DCACHE_SETS-1); + uint8_t wordAddress = (CacheDebugRegisterIndex & (DCACHE_LINELENGTH-1)) >> 2; + uint8_t index = (CacheDebugRegisterIndex >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); + DCacheTags[(index << DCACHE_SETS_LOG2) + segment] = val; + } + case 0xF30: //printf("cache debug instruction cache %08X\n", val); @@ -794,6 +984,27 @@ u32 ARMv5::CP15Read(u32 id) const return DTCMSetting; case 0x911: return ITCMSetting; + + case 0xF00: + return CacheDebugRegisterIndex; + case 0xF10: + // instruction cache Tag register + { + uint8_t segment = (CacheDebugRegisterIndex >> (32-ICACHE_SETS_LOG2)) & (ICACHE_SETS-1); + uint8_t wordAddress = (CacheDebugRegisterIndex & (ICACHE_LINELENGTH-1)) >> 2; + uint8_t index = (CacheDebugRegisterIndex >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1); + Log(LogLevel::Debug, "Read ICache Tag %08lx -> %08lx\n", CacheDebugRegisterIndex, ICacheTags[(index << ICACHE_SETS_LOG2) + segment]); + return ICacheTags[(index << ICACHE_SETS_LOG2) + segment]; + } + case 0xF20: + // data cache Tag register + { + uint8_t segment = (CacheDebugRegisterIndex >> (32-DCACHE_SETS_LOG2)) & (DCACHE_SETS-1); + uint8_t wordAddress = (CacheDebugRegisterIndex & (DCACHE_LINELENGTH-1)) >> 2; + uint8_t index = (CacheDebugRegisterIndex >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); + Log(LogLevel::Debug, "Read DCache Tag %08lx (%u, %02x, %u) -> %08lx\n", CacheDebugRegisterIndex, segment, index, wordAddress, DCacheTags[(index << DCACHE_SETS_LOG2) + segment]); + return DCacheTags[(index << DCACHE_SETS_LOG2) + segment]; + } } if ((id & 0xF00) == 0xF00) // test/debug shit? @@ -860,6 +1071,19 @@ void ARMv5::DataRead8(u32 addr, u32* val) return; } +#if 1 + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + { + if (PU_Map[addr >> 12] & 0x10) + { + DCacheLookup(addr & ~3); + DataCycles = 1; + *val = CurDCacheLine[addr & (DCACHE_LINELENGTH - 1)]; + return; + } + } +#endif + DataRegion = addr; if (addr < ITCMSize) @@ -887,6 +1111,19 @@ void ARMv5::DataRead16(u32 addr, u32* val) return; } +#if 1 + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + { + if (PU_Map[addr >> 12] & 0x10) + { + DCacheLookup(addr & ~3); + DataCycles = 1; + *val = *(u16 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 2)]; + return; + } + } +#endif + DataRegion = addr; addr &= ~1; @@ -916,6 +1153,19 @@ void ARMv5::DataRead32(u32 addr, u32* val) return; } +#if 1 + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + { + if (PU_Map[addr >> 12] & 0x10) + { + DCacheLookup(addr & ~3); + DataCycles = 1; + *val = *(u32 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 4)]; + return; + } + } +#endif + DataRegion = addr; addr &= ~3; @@ -941,6 +1191,19 @@ void ARMv5::DataRead32S(u32 addr, u32* val) { addr &= ~3; +#if 1 + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + { + if (PU_Map[addr >> 12] & 0x10) + { + DCacheLookup(addr & ~3); + DataCycles = 1; + *val = *(u32 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 4)]; + return; + } + } +#endif + if (addr < ITCMSize) { DataCycles += 1; @@ -966,6 +1229,14 @@ void ARMv5::DataWrite8(u32 addr, u8 val) return; } + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + { + if (PU_Map[addr >> 12] & 0x10) + { + DCacheInvalidateByAddr(addr); + } + } + DataRegion = addr; if (addr < ITCMSize) @@ -994,6 +1265,14 @@ void ARMv5::DataWrite16(u32 addr, u16 val) return; } + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + { + if (PU_Map[addr >> 12] & 0x10) + { + DCacheInvalidateByAddr(addr); + } + } + DataRegion = addr; addr &= ~1; @@ -1024,6 +1303,14 @@ void ARMv5::DataWrite32(u32 addr, u32 val) return; } + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + { + if (PU_Map[addr >> 12] & 0x10) + { + DCacheInvalidateByAddr(addr); + } + } + DataRegion = addr; addr &= ~3; @@ -1050,6 +1337,14 @@ void ARMv5::DataWrite32S(u32 addr, u32 val) { addr &= ~3; + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + { + if (PU_Map[addr >> 12] & 0x10) + { + DCacheInvalidateByAddr(addr); + } + } + if (addr < ITCMSize) { DataCycles += 1; diff --git a/src/MemConstants.h b/src/MemConstants.h index f06edd96..6b378f7a 100644 --- a/src/MemConstants.h +++ b/src/MemConstants.h @@ -44,6 +44,19 @@ constexpr u32 ICACHE_LINELENGTH_LOG2 = ICACHE_LINELENGTH_ENCODED + 3; constexpr u32 ICACHE_LINELENGTH = 8 * (1 << ICACHE_LINELENGTH_ENCODED); constexpr u32 ICACHE_LINESPERSET = ICACHE_SIZE / (ICACHE_SETS * ICACHE_LINELENGTH); +constexpr u32 DCACHE_SIZE_LOG2 = 12; +constexpr u32 DCACHE_SIZE = 1 << DCACHE_SIZE_LOG2; +constexpr u32 DCACHE_SETS_LOG2 = 2; +constexpr u32 DCACHE_SETS = 1 << DCACHE_SETS_LOG2; +constexpr u32 DCACHE_LINELENGTH_ENCODED = 2; +constexpr u32 DCACHE_LINELENGTH_LOG2 = DCACHE_LINELENGTH_ENCODED + 3; +constexpr u32 DCACHE_LINELENGTH = 8 * (1 << DCACHE_LINELENGTH_ENCODED); +constexpr u32 DCACHE_LINESPERSET = DCACHE_SIZE / (DCACHE_SETS * DCACHE_LINELENGTH); + +constexpr u32 CACHE_FLAG_VALID = (1 << 4); +constexpr u32 CACHE_FLAG_DIRTY_LOWERHALF = (1 << 2); +constexpr u32 CACHE_FLAG_DIRTY_UPPERHALF = (1 << 3); + constexpr u32 CP15_CR_MPUENABLE = (1 << 0); constexpr u32 CP15_CR_BIGENDIAN = (1 << 7); constexpr u32 CP15_CR_HIGHEXCEPTIONBASE = (1 << 13); From a46f972c2179513060fc845faf2cbca418dc2133 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Wed, 24 Jan 2024 10:37:17 +0100 Subject: [PATCH 09/39] Added Cache Data Write and Read via CP15 --- src/CP15.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/CP15.cpp b/src/CP15.cpp index ea3acddf..3de89caa 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -872,10 +872,22 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0xF30: //printf("cache debug instruction cache %08X\n", val); + { + uint8_t segment = (CacheDebugRegisterIndex >> (32-ICACHE_SETS_LOG2)) & (ICACHE_SETS-1); + uint8_t wordAddress = (CacheDebugRegisterIndex & (ICACHE_LINELENGTH-1)) >> 2; + uint8_t index = (CacheDebugRegisterIndex >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1); + *(u32 *)&ICache[(((index << ICACHE_SETS_LOG2) + segment) << ICACHE_LINELENGTH_LOG2) + wordAddress*4] = val; + } return; case 0xF40: //printf("cache debug data cache %08X\n", val); + { + uint8_t segment = (CacheDebugRegisterIndex >> (32-DCACHE_SETS_LOG2)) & (DCACHE_SETS-1); + uint8_t wordAddress = (CacheDebugRegisterIndex & (DCACHE_LINELENGTH-1)) >> 2; + uint8_t index = (CacheDebugRegisterIndex >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); + *(u32 *)&DCache[((index << DCACHE_SETS_LOG2) + segment) << DCACHE_LINELENGTH_LOG2 + wordAddress*4] = val; + } return; } @@ -1005,6 +1017,20 @@ u32 ARMv5::CP15Read(u32 id) const Log(LogLevel::Debug, "Read DCache Tag %08lx (%u, %02x, %u) -> %08lx\n", CacheDebugRegisterIndex, segment, index, wordAddress, DCacheTags[(index << DCACHE_SETS_LOG2) + segment]); return DCacheTags[(index << DCACHE_SETS_LOG2) + segment]; } + case 0xF30: + { + uint8_t segment = (CacheDebugRegisterIndex >> (32-ICACHE_SETS_LOG2)) & (ICACHE_SETS-1); + uint8_t wordAddress = (CacheDebugRegisterIndex & (ICACHE_LINELENGTH-1)) >> 2; + uint8_t index = (CacheDebugRegisterIndex >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1); + return *(u32 *)&ICache[(((index << ICACHE_SETS_LOG2) + segment) << ICACHE_LINELENGTH_LOG2) + wordAddress*4]; + } + case 0xF40: + { + uint8_t segment = (CacheDebugRegisterIndex >> (32-DCACHE_SETS_LOG2)) & (DCACHE_SETS-1); + uint8_t wordAddress = (CacheDebugRegisterIndex & (DCACHE_LINELENGTH-1)) >> 2; + uint8_t index = (CacheDebugRegisterIndex >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); + return *(u32 *)&DCache[(((index << DCACHE_SETS_LOG2) + segment) << DCACHE_LINELENGTH_LOG2) + wordAddress*4]; + } } if ((id & 0xF00) == 0xF00) // test/debug shit? From f67e93918cf51972f40ca9a2614b33b95d38ff0f Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Wed, 24 Jan 2024 11:02:34 +0100 Subject: [PATCH 10/39] Fixed data cache using only 1 cycle on miss. --- src/CP15.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index 3de89caa..edd720cf 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -456,6 +456,8 @@ void ARMv5::DCacheLookup(u32 addr) { DataCycles = 1; CurDCacheLine = &DCache[(id+set) << DCACHE_LINELENGTH_LOG2]; + DataCycles = 1; + //Log(LogLevel::Debug,"DCache hit @ %08x -> %08lx\n", addr, ((u32 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); return; } @@ -492,7 +494,6 @@ void ARMv5::DCacheLookup(u32 addr) } else { *((u32*)&ptr[i]) = BusRead32(addr+i); - } //Log(LogLevel::Debug,"DCache store @ %08x: %08x\n", addr+i, *(u32*)&ptr[i]); } @@ -1103,7 +1104,6 @@ void ARMv5::DataRead8(u32 addr, u32* val) if (PU_Map[addr >> 12] & 0x10) { DCacheLookup(addr & ~3); - DataCycles = 1; *val = CurDCacheLine[addr & (DCACHE_LINELENGTH - 1)]; return; } @@ -1143,7 +1143,6 @@ void ARMv5::DataRead16(u32 addr, u32* val) if (PU_Map[addr >> 12] & 0x10) { DCacheLookup(addr & ~3); - DataCycles = 1; *val = *(u16 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 2)]; return; } @@ -1185,7 +1184,6 @@ void ARMv5::DataRead32(u32 addr, u32* val) if (PU_Map[addr >> 12] & 0x10) { DCacheLookup(addr & ~3); - DataCycles = 1; *val = *(u32 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 4)]; return; } @@ -1223,7 +1221,6 @@ void ARMv5::DataRead32S(u32 addr, u32* val) if (PU_Map[addr >> 12] & 0x10) { DCacheLookup(addr & ~3); - DataCycles = 1; *val = *(u32 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 4)]; return; } From b23cb819bbca8612bab0f764f73b9394e61af973 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Wed, 24 Jan 2024 11:57:57 +0100 Subject: [PATCH 11/39] Changed write to cached data from invalidating to updating the cached data to get nearer to hw timings --- src/ARM.h | 3 ++ src/CP15.cpp | 85 +++++++++++++++++++++++++++++++++++++++++------- wfcsettings.bin | Bin 0 -> 2304 bytes 3 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 wfcsettings.bin diff --git a/src/ARM.h b/src/ARM.h index 99ef4baf..f7a6b98b 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -319,6 +319,9 @@ public: void DCacheLookup(u32 addr); + void DCacheWrite32(u32 addr, u32 val); + void DCacheWrite16(u32 addr, u16 val); + void DCacheWrite8(u32 addr, u8 val); bool IsAddressDCachable(u32 addr); void DCacheInvalidateAll(); diff --git a/src/CP15.cpp b/src/CP15.cpp index edd720cf..b3afb00b 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -454,7 +454,6 @@ void ARMv5::DCacheLookup(u32 addr) { if ((DCacheTags[id+set] & ~0x0F) == tag) { - DataCycles = 1; CurDCacheLine = &DCache[(id+set) << DCACHE_LINELENGTH_LOG2]; DataCycles = 1; @@ -506,6 +505,66 @@ void ARMv5::DCacheLookup(u32 addr) CurDCacheLine = ptr; } +void ARMv5::DCacheWrite32(u32 addr, u32 val) +{ + u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; + u32 id = (addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); + + id <<= DCACHE_SETS_LOG2; + for (int set=0;set %08lx\n", addr, ((u32 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); + return; + } + } +} + +void ARMv5::DCacheWrite16(u32 addr, u16 val) +{ + u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; + u32 id = (addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); + + id <<= DCACHE_SETS_LOG2; + for (int set=0;set %08lx\n", addr, ((u32 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); + return; + } + } +} + +void ARMv5::DCacheWrite8(u32 addr, u8 val) +{ + u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; + u32 id = (addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); + + id <<= DCACHE_SETS_LOG2; + for (int set=0;set %08lx\n", addr, ((u32 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); + return; + } + } +} + void ARMv5::DCacheInvalidateByAddr(u32 addr) { u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; @@ -1098,6 +1157,8 @@ void ARMv5::DataRead8(u32 addr, u32* val) return; } + DataRegion = addr; + #if 1 if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { @@ -1110,8 +1171,6 @@ void ARMv5::DataRead8(u32 addr, u32* val) } #endif - DataRegion = addr; - if (addr < ITCMSize) { DataCycles = 1; @@ -1137,6 +1196,8 @@ void ARMv5::DataRead16(u32 addr, u32* val) return; } + DataRegion = addr; + #if 1 if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { @@ -1149,8 +1210,6 @@ void ARMv5::DataRead16(u32 addr, u32* val) } #endif - DataRegion = addr; - addr &= ~1; if (addr < ITCMSize) @@ -1178,6 +1237,8 @@ void ARMv5::DataRead32(u32 addr, u32* val) return; } + DataRegion = addr; + #if 1 if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { @@ -1190,8 +1251,6 @@ void ARMv5::DataRead32(u32 addr, u32* val) } #endif - DataRegion = addr; - addr &= ~3; if (addr < ITCMSize) @@ -1256,7 +1315,8 @@ void ARMv5::DataWrite8(u32 addr, u8 val) { if (PU_Map[addr >> 12] & 0x10) { - DCacheInvalidateByAddr(addr); + DCacheWrite8(addr, val); + //DCacheInvalidateByAddr(addr); } } @@ -1292,7 +1352,8 @@ void ARMv5::DataWrite16(u32 addr, u16 val) { if (PU_Map[addr >> 12] & 0x10) { - DCacheInvalidateByAddr(addr); + DCacheWrite16(addr, val); +// DCacheInvalidateByAddr(addr); } } @@ -1330,7 +1391,8 @@ void ARMv5::DataWrite32(u32 addr, u32 val) { if (PU_Map[addr >> 12] & 0x10) { - DCacheInvalidateByAddr(addr); + DCacheWrite32(addr, val); +// DCacheInvalidateByAddr(addr); } } @@ -1364,7 +1426,8 @@ void ARMv5::DataWrite32S(u32 addr, u32 val) { if (PU_Map[addr >> 12] & 0x10) { - DCacheInvalidateByAddr(addr); + DCacheWrite32(addr, val); +// DCacheInvalidateByAddr(addr); } } diff --git a/wfcsettings.bin b/wfcsettings.bin new file mode 100644 index 0000000000000000000000000000000000000000..af3146aeb6423c6cff0a4d369941eb72c52e62d7 GIT binary patch literal 2304 zcmezWe-w;{z-S1JhQMeDjKmONpb+Gy=H%x&22f}U-Lx};ZSpv2Zan{jrB=^(PP*AV buonG?T94-cg1ZCjEV|i_>VLSkr#}DyyOIjR literal 0 HcmV?d00001 From 71b5c829aa0b8f2b14796ce144dc2fc5cb348caf Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Wed, 24 Jan 2024 14:53:55 +0100 Subject: [PATCH 12/39] Fixed unaligned access to data cache --- src/CP15.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index b3afb00b..0f5c32df 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -507,6 +507,8 @@ void ARMv5::DCacheLookup(u32 addr) void ARMv5::DCacheWrite32(u32 addr, u32 val) { + addr &= ~3; + u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; u32 id = (addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); @@ -519,7 +521,7 @@ void ARMv5::DCacheWrite32(u32 addr, u32 val) *(u32 *)&CurDCacheLine[addr & (ICACHE_LINELENGTH-1)] = val; DataCycles = 1; - //Log(LogLevel::Debug,"DCache hit @ %08x -> %08lx\n", addr, ((u32 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); + //Log(LogLevel::Debug,"DCache write32 hit @ %08x -> %08lx\n", addr, ((u32 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); return; } } @@ -527,6 +529,8 @@ void ARMv5::DCacheWrite32(u32 addr, u32 val) void ARMv5::DCacheWrite16(u32 addr, u16 val) { + addr &= ~1; + u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; u32 id = (addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); @@ -539,7 +543,7 @@ void ARMv5::DCacheWrite16(u32 addr, u16 val) *(u16 *)&CurDCacheLine[addr & (ICACHE_LINELENGTH-1)] = val; DataCycles = 1; - //Log(LogLevel::Debug,"DCache hit @ %08x -> %08lx\n", addr, ((u32 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); + //Log(LogLevel::Debug,"DCache write16 hit @ %08x -> %04x\n", addr, ((u16 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); return; } } @@ -559,7 +563,7 @@ void ARMv5::DCacheWrite8(u32 addr, u8 val) *(u8 *)&CurDCacheLine[addr & (ICACHE_LINELENGTH-1)] = val; DataCycles = 1; - //Log(LogLevel::Debug,"DCache hit @ %08x -> %08lx\n", addr, ((u32 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); + //Log(LogLevel::Debug,"DCache write hit8 @ %08x -> %02x\n", addr, ((u8 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); return; } } @@ -1153,6 +1157,7 @@ void ARMv5::DataRead8(u32 addr, u32* val) { if (!(PU_Map[addr>>12] & 0x01)) { + Log(LogLevel::Debug, "data8 abort @ %08lx\n", addr); DataAbort(); return; } @@ -1192,6 +1197,7 @@ void ARMv5::DataRead16(u32 addr, u32* val) { if (!(PU_Map[addr>>12] & 0x01)) { + Log(LogLevel::Debug, "data16 abort @ %08lx\n", addr); DataAbort(); return; } @@ -1233,6 +1239,7 @@ void ARMv5::DataRead32(u32 addr, u32* val) { if (!(PU_Map[addr>>12] & 0x01)) { + Log(LogLevel::Debug, "data32 abort @ %08lx\n", addr); DataAbort(); return; } From 7b8327d3a484851628d412ecd55f79528df7d69e Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 25 Jan 2024 09:05:51 +0100 Subject: [PATCH 13/39] Disabled Caches, when JIT is enabled --- src/CP15.cpp | 159 +++++++++++++++++++++++++++++++-------------------- src/NDS.h | 4 ++ 2 files changed, 101 insertions(+), 62 deletions(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index 0f5c32df..ef7f6347 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -1106,7 +1106,7 @@ u32 ARMv5::CP15Read(u32 id) const // TCM are handled here. -// TODO: later on, handle PU, and maybe caches +// TODO: later on, handle PU u32 ARMv5::CodeRead32(u32 addr, bool branch) { @@ -1126,27 +1126,30 @@ u32 ARMv5::CodeRead32(u32 addr, bool branch) } CodeCycles = RegionCodeCycles; -#if 0 - if (CodeCycles == 0xFF) // cached memory. hax +#ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) +#endif { - if (branch || !(addr & 0x1F)) - CodeCycles = kCodeCacheTiming;//ICacheLookup(addr); - else - CodeCycles = 1; - - //return *(u32*)&CurICacheLine[addr & 0x1C]; - } -#else - if (CP15Control & CP15_CACHE_CR_ICACHEENABLE) - { - if (IsAddressICachable(addr)) + if (CP15Control & CP15_CACHE_CR_ICACHEENABLE) { - ICacheLookup(addr); - return *(u32*)&CurICacheLine[addr & (ICACHE_LINELENGTH - 4)]; + if (IsAddressICachable(addr)) + { + ICacheLookup(addr); + return *(u32*)&CurICacheLine[addr & (ICACHE_LINELENGTH - 4)]; + } + } + } else + { + if (CodeCycles == 0xFF) // cached memory. hax + { + if (branch || !(addr & 0x1F)) + CodeCycles = kCodeCacheTiming;//ICacheLookup(addr); + else + CodeCycles = 1; + + //return *(u32*)&CurICacheLine[addr & 0x1C]; } } -#endif - if (CodeMem.Mem) return *(u32*)&CodeMem.Mem[addr & CodeMem.Mask]; return BusRead32(addr); @@ -1164,17 +1167,20 @@ void ARMv5::DataRead8(u32 addr, u32* val) DataRegion = addr; -#if 1 - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) +#ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) +#endif { - if (PU_Map[addr >> 12] & 0x10) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - DCacheLookup(addr & ~3); - *val = CurDCacheLine[addr & (DCACHE_LINELENGTH - 1)]; - return; + if (PU_Map[addr >> 12] & 0x10) + { + DCacheLookup(addr & ~3); + *val = CurDCacheLine[addr & (DCACHE_LINELENGTH - 1)]; + return; + } } } -#endif if (addr < ITCMSize) { @@ -1204,17 +1210,20 @@ void ARMv5::DataRead16(u32 addr, u32* val) DataRegion = addr; -#if 1 - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) +#ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) +#endif { - if (PU_Map[addr >> 12] & 0x10) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - DCacheLookup(addr & ~3); - *val = *(u16 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 2)]; - return; + if (PU_Map[addr >> 12] & 0x10) + { + DCacheLookup(addr & ~3); + *val = *(u16 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 2)]; + return; + } } } -#endif addr &= ~1; @@ -1246,17 +1255,20 @@ void ARMv5::DataRead32(u32 addr, u32* val) DataRegion = addr; -#if 1 - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) +#ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) +#endif { - if (PU_Map[addr >> 12] & 0x10) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - DCacheLookup(addr & ~3); - *val = *(u32 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 4)]; - return; + if (PU_Map[addr >> 12] & 0x10) + { + DCacheLookup(addr & ~3); + *val = *(u32 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 4)]; + return; + } } } -#endif addr &= ~3; @@ -1281,17 +1293,20 @@ void ARMv5::DataRead32S(u32 addr, u32* val) { addr &= ~3; -#if 1 - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) +#ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) +#endif { - if (PU_Map[addr >> 12] & 0x10) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - DCacheLookup(addr & ~3); - *val = *(u32 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 4)]; - return; + if (PU_Map[addr >> 12] & 0x10) + { + DCacheLookup(addr & ~3); + *val = *(u32 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 4)]; + return; + } } } -#endif if (addr < ITCMSize) { @@ -1318,12 +1333,17 @@ void ARMv5::DataWrite8(u32 addr, u8 val) return; } - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) +#ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) +#endif { - if (PU_Map[addr >> 12] & 0x10) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - DCacheWrite8(addr, val); - //DCacheInvalidateByAddr(addr); + if (PU_Map[addr >> 12] & 0x10) + { + DCacheWrite8(addr, val); + //DCacheInvalidateByAddr(addr); + } } } @@ -1355,12 +1375,17 @@ void ARMv5::DataWrite16(u32 addr, u16 val) return; } - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) +#ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) +#endif { - if (PU_Map[addr >> 12] & 0x10) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - DCacheWrite16(addr, val); -// DCacheInvalidateByAddr(addr); + if (PU_Map[addr >> 12] & 0x10) + { + DCacheWrite16(addr, val); + // DCacheInvalidateByAddr(addr); + } } } @@ -1394,12 +1419,17 @@ void ARMv5::DataWrite32(u32 addr, u32 val) return; } - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) +#ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) +#endif { - if (PU_Map[addr >> 12] & 0x10) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - DCacheWrite32(addr, val); -// DCacheInvalidateByAddr(addr); + if (PU_Map[addr >> 12] & 0x10) + { + DCacheWrite32(addr, val); + // DCacheInvalidateByAddr(addr); + } } } @@ -1429,12 +1459,17 @@ void ARMv5::DataWrite32S(u32 addr, u32 val) { addr &= ~3; - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) +#ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) +#endif { - if (PU_Map[addr >> 12] & 0x10) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - DCacheWrite32(addr, val); -// DCacheInvalidateByAddr(addr); + if (PU_Map[addr >> 12] & 0x10) + { + DCacheWrite32(addr, val); + // DCacheInvalidateByAddr(addr); + } } } diff --git a/src/NDS.h b/src/NDS.h index f9df2d69..cfb8e3b5 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -302,6 +302,10 @@ public: // TODO: Encapsulate the rest of these members melonDS::GPU GPU; melonDS::AREngine AREngine; +#ifdef JIT_ENABLED + bool IsJITEnabled(){return EnableJIT;}; +#endif + const u32 ARM7WRAMSize = 0x10000; u8* ARM7WRAM; From 9d2e5159473b86670c790e2d8914197c4113d80f Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 25 Jan 2024 10:08:57 +0100 Subject: [PATCH 14/39] Implemented CacheLockDown --- src/CP15.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ src/MemConstants.h | 2 ++ 2 files changed, 42 insertions(+) diff --git a/src/CP15.cpp b/src/CP15.cpp index ef7f6347..fef3eac1 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -380,6 +380,24 @@ void ARMv5::ICacheLookup(u32 addr) line = RandomLineIndex(); } + if (ICacheLockDown) + { + if (ICacheLockDown & CACHE_LOCKUP_L) + { + // load into locked up cache + // into the selected set + line = ICacheLockDown & (ICACHE_SETS-1); + } else + { + u8 minSet = ICacheLockDown & (ICACHE_SETS-1); + if (minSet) + { + // part of the cache is locked up and only the cachelines + line = (line % (ICACHE_SETS - minSet)) + minSet; + } + } + } + line += id; addr &= ~(ICACHE_LINELENGTH-1); @@ -474,6 +492,24 @@ void ARMv5::DCacheLookup(u32 addr) line = RandomLineIndex(); } + if (DCacheLockDown) + { + if (DCacheLockDown & CACHE_LOCKUP_L) + { + // load into locked up cache + // into the selected set + line = DCacheLockDown & (DCACHE_SETS-1); + } else + { + u8 minSet = DCacheLockDown & (DCACHE_SETS-1); + if (minSet) + { + // part of the cache is locked up and only the cachelines + line = (line % (DCACHE_SETS - minSet)) + minSet; + } + } + } + line += id; addr &= ~(DCACHE_LINELENGTH-1); @@ -856,6 +892,10 @@ void ARMv5::CP15Write(u32 id, u32 val) // Test and clean (optional) // Is not present on the NDS/DSi return; + case 0x7A4: + // Drain Write Buffer: Stall until all write back completed + // TODO when write back was implemented instead of write through + return; case 0x7D1: Log(LogLevel::Debug,"Prefetch instruction cache MVA\n"); diff --git a/src/MemConstants.h b/src/MemConstants.h index 6b378f7a..af6f89f7 100644 --- a/src/MemConstants.h +++ b/src/MemConstants.h @@ -57,6 +57,8 @@ constexpr u32 CACHE_FLAG_VALID = (1 << 4); constexpr u32 CACHE_FLAG_DIRTY_LOWERHALF = (1 << 2); constexpr u32 CACHE_FLAG_DIRTY_UPPERHALF = (1 << 3); +constexpr u32 CACHE_LOCKUP_L = (1 << 31); + constexpr u32 CP15_CR_MPUENABLE = (1 << 0); constexpr u32 CP15_CR_BIGENDIAN = (1 << 7); constexpr u32 CP15_CR_HIGHEXCEPTIONBASE = (1 << 13); From bf0767b4f379809bdcca79d82ac90ced1158809b Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 25 Jan 2024 10:48:04 +0100 Subject: [PATCH 15/39] Added CP15 prefetch routine --- src/CP15.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/CP15.cpp b/src/CP15.cpp index fef3eac1..c2f8720c 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -899,6 +899,9 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0x7D1: Log(LogLevel::Debug,"Prefetch instruction cache MVA\n"); + // we force a fill by looking up the value from cache + // if it wasn't cached yet, it will be loaded into cache + ICacheLookup(val & ~0x03); break; case 0x7E0: From 3c94802704639c16e111ca0d66c8f39ed902fe26 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 25 Jan 2024 11:05:58 +0100 Subject: [PATCH 16/39] Removed magic number from Cache Fill timings. --- src/CP15.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index c2f8720c..8f3d7138 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -417,7 +417,8 @@ void ARMv5::ICacheLookup(u32 addr) // 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)) << NDS.ARM9ClockShift; + // first N32 remaining S32 + CodeCycles = (NDS.ARM9MemTimings[addr >> 14][2] + (NDS.ARM9MemTimings[addr >> 14][3] * ((DCACHE_LINELENGTH / 4) - 1))) << NDS.ARM9ClockShift; CurICacheLine = ptr; } @@ -537,7 +538,8 @@ void ARMv5::DCacheLookup(u32 addr) // ouch :/ //printf("cache miss %08X: %d/%d\n", addr, NDS::ARM9MemTimings[addr >> 14][2], NDS::ARM9MemTimings[addr >> 14][3]); - DataCycles = (NDS.ARM9MemTimings[addr >> 14][2] + (NDS.ARM9MemTimings[addr >> 14][3] * 7)) << NDS.ARM9ClockShift; + // first N32 remaining S32 + DataCycles = (NDS.ARM9MemTimings[addr >> 14][2] + (NDS.ARM9MemTimings[addr >> 14][3] * ((DCACHE_LINELENGTH / 4) - 1))) << NDS.ARM9ClockShift; CurDCacheLine = ptr; } From 8a0ad8ac3f99211e9d6f162856b2eece76137ad4 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 25 Jan 2024 11:44:26 +0100 Subject: [PATCH 17/39] Added permission checks to CP15 Cache register write operations --- src/CP15.cpp | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/src/CP15.cpp b/src/CP15.cpp index 8f3d7138..94494e62 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -832,14 +832,31 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0x750: + // Can be executed in user and priv mode ICacheInvalidateAll(); //Halt(255); return; case 0x751: + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } ICacheInvalidateByAddr(val); //Halt(255); return; case 0x752: + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } else { // Cache invalidat by line number and set number u8 cacheSet = val >> (32 - ICACHE_SETS_LOG2) & (ICACHE_SETS -1); @@ -851,14 +868,38 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0x760: + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } DCacheInvalidateAll(); //printf("inval data cache %08X\n", val); return; case 0x761: + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } DCacheInvalidateByAddr(val); //printf("inval data cache SI\n"); return; case 0x762: + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } else { // Cache invalidat by line number and set number u8 cacheSet = val >> (32 - DCACHE_SETS_LOG2) & (DCACHE_SETS -1); @@ -869,20 +910,45 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0x770: // invalidate both caches + // can be called from user and privileged ICacheInvalidateAll(); DCacheInvalidateAll(); break; case 0x7A0: + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } //Log(LogLevel::Debug,"clean data cache\n"); DCacheClearAll(); return; case 0x7A1: + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } //Log(LogLevel::Debug,"clean data cache MVA\n"); DCacheClearByAddr(val); return; case 0x7A2: //Log(LogLevel::Debug,"clean data cache SET/WAY\n"); + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } else { // Cache invalidat by line number and set number u8 cacheSet = val >> (32 - DCACHE_SETS_LOG2) & (DCACHE_SETS -1); @@ -891,16 +957,33 @@ void ARMv5::CP15Write(u32 id, u32 val) } return; case 0x7A3: + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } // Test and clean (optional) // Is not present on the NDS/DSi return; case 0x7A4: + // Can be used in user and privileged mode // Drain Write Buffer: Stall until all write back completed // TODO when write back was implemented instead of write through return; case 0x7D1: Log(LogLevel::Debug,"Prefetch instruction cache MVA\n"); + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } // we force a fill by looking up the value from cache // if it wasn't cached yet, it will be loaded into cache ICacheLookup(val & ~0x03); @@ -908,16 +991,40 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0x7E0: //Log(LogLevel::Debug,"clean & invalidate data cache\n"); + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } DCacheClearAll(); DCacheInvalidateAll(); return; case 0x7E1: //Log(LogLevel::Debug,"clean & invalidate data cache MVA\n"); + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } DCacheClearByAddr(val); DCacheInvalidateByAddr(val); return; case 0x7E2: //Log(LogLevel::Debug,"clean & invalidate data cache SET/WAY\n"); + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } else { // Cache invalidat by line number and set number u8 cacheSet = val >> (32 - DCACHE_SETS_LOG2) & (DCACHE_SETS -1); @@ -928,6 +1035,14 @@ void ARMv5::CP15Write(u32 id, u32 val) return; case 0x900: + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } // Cache Lockdown - Format B // Bit 31: Lock bit // Bit 0..Way-1: locked ways @@ -937,6 +1052,14 @@ void ARMv5::CP15Write(u32 id, u32 val) Log(LogLevel::Debug,"ICacheLockDown\n"); return; case 0x901: + // requires priv mode or causes UNKNOWN INSTRUCTION exception + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } // Cache Lockdown - Format B // Bit 31: Lock bit // Bit 0..Way-1: locked ways From 6959d6f2b0707e7ef6660c2f0fb22949875259ca Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 25 Jan 2024 11:52:37 +0100 Subject: [PATCH 18/39] Added privilege checks for reading & writing CP15 cache registers --- src/CP15.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index 94494e62..d6ddcad8 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -1080,11 +1080,25 @@ void ARMv5::CP15Write(u32 id, u32 val) return; case 0xF00: - CacheDebugRegisterIndex = val; + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } else + CacheDebugRegisterIndex = val; return; case 0xF10: // instruction cache Tag register + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } else { uint8_t segment = (CacheDebugRegisterIndex >> (32-ICACHE_SETS_LOG2)) & (ICACHE_SETS-1); uint8_t wordAddress = (CacheDebugRegisterIndex & (ICACHE_LINELENGTH-1)) >> 2; @@ -1094,6 +1108,13 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0xF20: // data cache Tag register + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } else { uint8_t segment = (CacheDebugRegisterIndex >> (32-DCACHE_SETS_LOG2)) & (DCACHE_SETS-1); uint8_t wordAddress = (CacheDebugRegisterIndex & (DCACHE_LINELENGTH-1)) >> 2; @@ -1104,6 +1125,13 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0xF30: //printf("cache debug instruction cache %08X\n", val); + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } else { uint8_t segment = (CacheDebugRegisterIndex >> (32-ICACHE_SETS_LOG2)) & (ICACHE_SETS-1); uint8_t wordAddress = (CacheDebugRegisterIndex & (ICACHE_LINELENGTH-1)) >> 2; @@ -1114,6 +1142,13 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0xF40: //printf("cache debug data cache %08X\n", val); + if (PU_Map != PU_PrivMap) + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } else { uint8_t segment = (CacheDebugRegisterIndex >> (32-DCACHE_SETS_LOG2)) & (DCACHE_SETS-1); uint8_t wordAddress = (CacheDebugRegisterIndex & (DCACHE_LINELENGTH-1)) >> 2; @@ -1220,9 +1255,17 @@ u32 ARMv5::CP15Read(u32 id) const return 0; case 0x900: - return DCacheLockDown; + if (PU_Map != PU_PrivMap) + { + return 0; + } else + return DCacheLockDown; case 0x901: - return ICacheLockDown; + if (PU_Map != PU_PrivMap) + { + return 0; + } else + return ICacheLockDown; case 0x910: return DTCMSetting; @@ -1230,9 +1273,17 @@ u32 ARMv5::CP15Read(u32 id) const return ITCMSetting; case 0xF00: - return CacheDebugRegisterIndex; + if (PU_Map != PU_PrivMap) + { + return 0; + } else + return CacheDebugRegisterIndex; case 0xF10: // instruction cache Tag register + if (PU_Map != PU_PrivMap) + { + return 0; + } else { uint8_t segment = (CacheDebugRegisterIndex >> (32-ICACHE_SETS_LOG2)) & (ICACHE_SETS-1); uint8_t wordAddress = (CacheDebugRegisterIndex & (ICACHE_LINELENGTH-1)) >> 2; @@ -1242,6 +1293,10 @@ u32 ARMv5::CP15Read(u32 id) const } case 0xF20: // data cache Tag register + if (PU_Map != PU_PrivMap) + { + return 0; + } else { uint8_t segment = (CacheDebugRegisterIndex >> (32-DCACHE_SETS_LOG2)) & (DCACHE_SETS-1); uint8_t wordAddress = (CacheDebugRegisterIndex & (DCACHE_LINELENGTH-1)) >> 2; @@ -1250,6 +1305,10 @@ u32 ARMv5::CP15Read(u32 id) const return DCacheTags[(index << DCACHE_SETS_LOG2) + segment]; } case 0xF30: + if (PU_Map != PU_PrivMap) + { + return 0; + } else { uint8_t segment = (CacheDebugRegisterIndex >> (32-ICACHE_SETS_LOG2)) & (ICACHE_SETS-1); uint8_t wordAddress = (CacheDebugRegisterIndex & (ICACHE_LINELENGTH-1)) >> 2; From cd60c13ea16ec60c5ba89a2a5d2b8ac412b78ddd Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 25 Jan 2024 12:09:17 +0100 Subject: [PATCH 19/39] Replaced Magic numbers in CP15 cache type register --- src/CP15.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index d6ddcad8..58105aa0 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -1181,7 +1181,9 @@ u32 ARMv5::CP15Read(u32 id) const return 0x41059461; case 0x001: // cache type - return 0x0F0D2112; + return CACHE_TR_LOCKUP_TYPE_B | CACHE_TR_NONUNIFIED + | (DCACHE_LINELENGTH_ENCODED << 12) | (DCACHE_SETS_LOG2 << 15) | ((DCACHE_SIZE_LOG2 - 9) << 18) + | (ICACHE_LINELENGTH_ENCODED << 0) | (ICACHE_SETS_LOG2 << 3) | ((ICACHE_SIZE_LOG2 - 9) << 6); case 0x002: // TCM size return (6 << 6) | (5 << 18); From a0f4eb691ba4a2308ca0545b4b8fa75b68ded92e Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 25 Jan 2024 12:12:31 +0100 Subject: [PATCH 20/39] Fixed Typo and missing file on the cache type constants --- src/CP15.cpp | 2 +- src/MemConstants.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index 58105aa0..2a3936d9 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -1181,7 +1181,7 @@ u32 ARMv5::CP15Read(u32 id) const return 0x41059461; case 0x001: // cache type - return CACHE_TR_LOCKUP_TYPE_B | CACHE_TR_NONUNIFIED + return CACHE_TR_LOCKDOWN_TYPE_B | CACHE_TR_NONUNIFIED | (DCACHE_LINELENGTH_ENCODED << 12) | (DCACHE_SETS_LOG2 << 15) | ((DCACHE_SIZE_LOG2 - 9) << 18) | (ICACHE_LINELENGTH_ENCODED << 0) | (ICACHE_SETS_LOG2 << 3) | ((ICACHE_SIZE_LOG2 - 9) << 6); diff --git a/src/MemConstants.h b/src/MemConstants.h index af6f89f7..332b9b18 100644 --- a/src/MemConstants.h +++ b/src/MemConstants.h @@ -57,6 +57,9 @@ constexpr u32 CACHE_FLAG_VALID = (1 << 4); constexpr u32 CACHE_FLAG_DIRTY_LOWERHALF = (1 << 2); constexpr u32 CACHE_FLAG_DIRTY_UPPERHALF = (1 << 3); +constexpr u32 CACHE_TR_LOCKDOWN_TYPE_B = (7 << 25); +constexpr u32 CACHE_TR_NONUNIFIED = (1 << 24); + constexpr u32 CACHE_LOCKUP_L = (1 << 31); constexpr u32 CP15_CR_MPUENABLE = (1 << 0); From caa90dd5acc26bcb074a15677cde388b86d9ccf7 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Fri, 26 Jan 2024 09:21:08 +0100 Subject: [PATCH 21/39] Changed DCache Random Cache-Line selection to a double Galoise LFSR --- src/ARM.h | 2 ++ src/CP15.cpp | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/ARM.h b/src/ARM.h index f7a6b98b..2eaf940d 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -318,6 +318,7 @@ public: void ICacheInvalidateBySetAndWay(u8 cacheSet, u8 cacheLine); + u8 DCacheRandom(); void DCacheLookup(u32 addr); void DCacheWrite32(u32 addr, u32 val); void DCacheWrite16(u32 addr, u16 val); @@ -361,6 +362,7 @@ public: u8 DCache[DCACHE_SIZE]; u32 DCacheTags[DCACHE_LINESPERSET*DCACHE_SETS]; u8 DCacheCount; + u32 DCacheLFSRStates; u32 PU_CodeCacheable; u32 PU_DataCacheable; diff --git a/src/CP15.cpp b/src/CP15.cpp index 2a3936d9..848859e9 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -67,6 +67,10 @@ void ARMv5::CP15Reset() DCacheInvalidateAll(); DCacheCount = 0; + // make sure that both half words are not the same otherwise the random of the DCache set selection only produces + // '00' and '11' + DCacheLFSRStates = 0xDEADBEEF; + PU_CodeCacheable = 0; PU_DataCacheable = 0; PU_DataCacheWrite = 0; @@ -99,6 +103,7 @@ void ARMv5::CP15DoSavestate(Savestate* file) file->VarArray(DCache, sizeof(DCache)); file->VarArray(DCacheTags, sizeof(DCacheTags)); file->Var8(&DCacheCount); + file->Var32(&DCacheLFSRStates); file->Var32(&DCacheLockDown); file->Var32(&ICacheLockDown); @@ -352,6 +357,17 @@ u32 ARMv5::RandomLineIndex() return (RNGSeed >> 17) & 0x3; } +u8 ARMv5::DCacheRandom() +{ + // The random value, which line to select is derived from two LFSR of the + // same polynomial with different initial states, so that they reproduce + // the same 2047 bit sequence but with a random different starting point + u32 lowLFSRBits = DCacheLFSRStates & 0x00010001; + DCacheLFSRStates = (DCacheLFSRStates & ~0x00010001) >> 1; + DCacheLFSRStates ^= lowLFSRBits * 0x5E5 ; + return (lowLFSRBits | (lowLFSRBits >> 15)) & 3; +} + void ARMv5::ICacheLookup(u32 addr) { u32 tag = (addr & ~(ICACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; @@ -490,7 +506,7 @@ void ARMv5::DCacheLookup(u32 addr) } else { - line = RandomLineIndex(); + line = DCacheRandom(); } if (DCacheLockDown) From 1dc15a0d075b455f9906f6b9e0bcf7b943964134 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Fri, 26 Jan 2024 10:09:10 +0100 Subject: [PATCH 22/39] Simplified set selection adjustment for the cache lock down --- src/CP15.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index 848859e9..a59af2ab 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -406,11 +406,7 @@ void ARMv5::ICacheLookup(u32 addr) } else { u8 minSet = ICacheLockDown & (ICACHE_SETS-1); - if (minSet) - { - // part of the cache is locked up and only the cachelines - line = (line % (ICACHE_SETS - minSet)) + minSet; - } + line = line | minSet; } } @@ -518,12 +514,8 @@ void ARMv5::DCacheLookup(u32 addr) line = DCacheLockDown & (DCACHE_SETS-1); } else { - u8 minSet = DCacheLockDown & (DCACHE_SETS-1); - if (minSet) - { - // part of the cache is locked up and only the cachelines - line = (line % (DCACHE_SETS - minSet)) + minSet; - } + u8 minSet = ICacheLockDown & (DCACHE_SETS-1); + line = line | minSet; } } From 06ea3f68ec483dfdc8ac81737373e2486bdb13d8 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Wed, 31 Jan 2024 12:20:41 +0100 Subject: [PATCH 23/39] Cleaned up and fastened up --- src/ARM.h | 27 ++++--- src/CP15.cpp | 203 ++++++++++++++++++++++++++------------------------- 2 files changed, 118 insertions(+), 112 deletions(-) diff --git a/src/ARM.h b/src/ARM.h index 2eaf940d..eedd997b 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -310,28 +310,27 @@ public: u32 RandomLineIndex(); - void ICacheLookup(u32 addr); - bool IsAddressICachable(u32 addr); + u32 ICacheLookup(const u32 addr); + inline bool IsAddressICachable(const u32 addr) const; void ICacheInvalidateAll(); - void ICacheInvalidateByAddr(u32 addr); - void ICacheInvalidateBySetAndWay(u8 cacheSet, u8 cacheLine); + void ICacheInvalidateByAddr(const u32 addr); + void ICacheInvalidateBySetAndWay(const u8 cacheSet, const u8 cacheLine); - u8 DCacheRandom(); - void DCacheLookup(u32 addr); - void DCacheWrite32(u32 addr, u32 val); - void DCacheWrite16(u32 addr, u16 val); - void DCacheWrite8(u32 addr, u8 val); - bool IsAddressDCachable(u32 addr); + u32 DCacheLookup(const u32 addr); + void DCacheWrite32(const u32 addr, const u32 val); + void DCacheWrite16(const u32 addr, const u16 val); + void DCacheWrite8(const u32 addr, const u8 val); + inline bool IsAddressDCachable(const u32 addr) const; void DCacheInvalidateAll(); - void DCacheInvalidateByAddr(u32 addr); - void DCacheInvalidateBySetAndWay(u8 cacheSet, u8 cacheLine); + void DCacheInvalidateByAddr(const u32 addr); + void DCacheInvalidateBySetAndWay(const u8 cacheSet, const u8 cacheLine); void DCacheClearAll(); - void DCacheClearByAddr(u32 addr); - void DCacheClearByASetAndWay(u8 cacheSet, u8 cacheLine); + void DCacheClearByAddr(const u32 addr); + void DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine); diff --git a/src/CP15.cpp b/src/CP15.cpp index a59af2ab..2dcce5c1 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -357,35 +357,33 @@ u32 ARMv5::RandomLineIndex() return (RNGSeed >> 17) & 0x3; } -u8 ARMv5::DCacheRandom() -{ - // The random value, which line to select is derived from two LFSR of the - // same polynomial with different initial states, so that they reproduce - // the same 2047 bit sequence but with a random different starting point - u32 lowLFSRBits = DCacheLFSRStates & 0x00010001; - DCacheLFSRStates = (DCacheLFSRStates & ~0x00010001) >> 1; - DCacheLFSRStates ^= lowLFSRBits * 0x5E5 ; - return (lowLFSRBits | (lowLFSRBits >> 15)) & 3; -} - -void ARMv5::ICacheLookup(u32 addr) +u32 ARMv5::ICacheLookup(const u32 addr) { - u32 tag = (addr & ~(ICACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; - u32 id = (addr >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1); + const u32 tag = (addr & ~(ICACHE_LINELENGTH - 1)); + const u32 id = ((addr >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1)) << ICACHE_SETS_LOG2; - id <<= ICACHE_SETS_LOG2; for (int set=0;set> 2]; } } // cache miss u32 line; +#if 0 + // caclulate in which cacheline the data is to be filled + // The code below is doing the same as the if-less below + // It increases performance by reducing banches. + // The code is kept here for readability. + // + // NOTE: If you need to update either part, you need + // to update the other too to keep them in sync! + // + if (CP15Control & CP15_CACHE_CR_ROUNDROBIN) { line = ICacheCount; @@ -410,36 +408,44 @@ void ARMv5::ICacheLookup(u32 addr) } } - line += id; +#else + // Do the same as above but instead of using if-else + // utilize the && and || operators to skip parts of the operations + // With the order of comparison we can put the most likely path + // checked first - addr &= ~(ICACHE_LINELENGTH-1); - u8* ptr = &ICache[line << ICACHE_LINELENGTH_LOG2]; + bool doLockDown = (ICacheLockDown & CACHE_LOCKUP_L); + bool roundRobin = CP15Control & CP15_CACHE_CR_ROUNDROBIN; + (!roundRobin && (line = RandomLineIndex())) || (roundRobin && (ICacheCount = line = ((ICacheCount+1) & (ICACHE_SETS-1)))) ; + (!doLockDown && (line = (line | ICacheLockDown & (ICACHE_SETS-1))+id)) || (doLockDown && (line = (ICacheLockDown & (ICACHE_SETS-1))+id)); +#endif + + u32* ptr = (u32 *)&ICache[line << ICACHE_LINELENGTH_LOG2]; if (CodeMem.Mem) { - memcpy(ptr, &CodeMem.Mem[addr & CodeMem.Mask], ICACHE_LINELENGTH); + memcpy(ptr, &CodeMem.Mem[tag & CodeMem.Mask], ICACHE_LINELENGTH); } else { for (int i = 0; i < ICACHE_LINELENGTH; i+=sizeof(u32)) - *(u32*)&ptr[i] = NDS.ARM9Read32(addr+i); + ptr[i >> 2] = NDS.ARM9Read32(tag+i); } - ICacheTags[line] = addr | (line & (ICACHE_SETS-1)) | CACHE_FLAG_VALID; + ICacheTags[line] = tag | (line & (ICACHE_SETS-1)) | CACHE_FLAG_VALID; // ouch :/ //printf("cache miss %08X: %d/%d\n", addr, NDS::ARM9MemTimings[addr >> 14][2], NDS::ARM9MemTimings[addr >> 14][3]); // first N32 remaining S32 - CodeCycles = (NDS.ARM9MemTimings[addr >> 14][2] + (NDS.ARM9MemTimings[addr >> 14][3] * ((DCACHE_LINELENGTH / 4) - 1))) << NDS.ARM9ClockShift; - CurICacheLine = ptr; + CodeCycles = (NDS.ARM9MemTimings[tag >> 14][2] + (NDS.ARM9MemTimings[tag >> 14][3] * ((DCACHE_LINELENGTH / 4) - 1))) << NDS.ARM9ClockShift; + return ptr[(addr & (ICACHE_LINELENGTH-1)) >> 2]; } -void ARMv5::ICacheInvalidateByAddr(u32 addr) +void ARMv5::ICacheInvalidateByAddr(const u32 addr) { - u32 tag = (addr & ~(ICACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; - u32 id = (addr >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1); + const u32 tag = (addr & ~(ICACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; + const u32 id = ((addr >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1)) << ICACHE_SETS_LOG2; - id <<= ICACHE_SETS_LOG2; for (int set=0;set= ICACHE_SETS) return; @@ -468,33 +474,39 @@ void ARMv5::ICacheInvalidateAll() ICacheTags[i] &= ~CACHE_FLAG_VALID; ; } -bool ARMv5::IsAddressICachable(u32 addr) +bool ARMv5::IsAddressICachable(const u32 addr) const { return PU_Map[addr >> 12] & 0x40 ; } -void ARMv5::DCacheLookup(u32 addr) +u32 ARMv5::DCacheLookup(const u32 addr) { //Log(LogLevel::Debug,"DCache load @ %08x\n", addr); - addr &= ~3; - u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; - u32 id = (addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); + const u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) ; + const u32 id = ((addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; - id <<= DCACHE_SETS_LOG2; for (int set=0;set %08lx\n", addr, ((u32 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); - return; + u32 *cacheLine = (u32 *)&DCache[(id+set) << DCACHE_LINELENGTH_LOG2]; + return cacheLine[(addr & (ICACHE_LINELENGTH -1)) >> 2]; } } // cache miss u32 line; +#if 0 + // caclulate in which cacheline the data is to be filled + // The code below is doing the same as the if-less below + // It increases performance by reducing banches. + // The code is kept here for readability. + // + // NOTE: If you need to update either part, you need + // to update the other too to keep them in sync! + // + if (CP15Control & CP15_CACHE_CR_ROUNDROBIN) { line = DCacheCount; @@ -505,66 +517,71 @@ void ARMv5::DCacheLookup(u32 addr) line = DCacheRandom(); } + // Update the selected set depending on the DCache LockDown register if (DCacheLockDown) { if (DCacheLockDown & CACHE_LOCKUP_L) { // load into locked up cache // into the selected set - line = DCacheLockDown & (DCACHE_SETS-1); + line = (DCacheLockDown & (DCACHE_SETS-1)) + id; } else { u8 minSet = ICacheLockDown & (DCACHE_SETS-1); - line = line | minSet; + line = (line | minSet) + id; } } +#else + // Do the same as above but instead of using if-else + // utilize the && and || operators to skip parts of the operations + // With the order of comparison we can put the most likely path + // checked first - line += id; + bool doLockDown = (DCacheLockDown & CACHE_LOCKUP_L); + bool roundRobin = CP15Control & CP15_CACHE_CR_ROUNDROBIN; + (!roundRobin && (line = RandomLineIndex())) || (roundRobin && (DCacheCount = line = ((DCacheCount+1) & (DCACHE_SETS-1)))); + (!doLockDown && (line = (line | DCacheLockDown & (DCACHE_SETS-1))+id)) || (doLockDown && (line = (DCacheLockDown & (DCACHE_SETS-1))+id)); +#endif - addr &= ~(DCACHE_LINELENGTH-1); - u8* ptr = &DCache[line << DCACHE_LINELENGTH_LOG2]; + u32* ptr = (u32 *)&DCache[line << DCACHE_LINELENGTH_LOG2]; - //Log(LogLevel::Debug,"DCache miss, load @ %08x\n", addr); + //Log(LogLevel::Debug,"DCache miss, load @ %08x\n", tag); for (int i = 0; i < DCACHE_LINELENGTH; i+=sizeof(u32)) { - //DataRead32S(addr+i, (u32*)&ptr[i]); - if (addr+i < ITCMSize) + if (tag+i < ITCMSize) { - *((u32*)&ptr[i]) = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)]; + ptr[i >> 2] = *(u32*)&ITCM[(tag+i) & (ITCMPhysicalSize - 1)]; } else - if (((addr+i) & DTCMMask) == DTCMBase) + if (((tag+i) & DTCMMask) == DTCMBase) { - *((u32*)&ptr[i]) = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)]; + ptr[i >> 2] = *(u32*)&DTCM[(tag+i) & (DTCMPhysicalSize - 1)]; } else { - *((u32*)&ptr[i]) = BusRead32(addr+i); + ptr[i >> 2] = BusRead32(tag+i); } - //Log(LogLevel::Debug,"DCache store @ %08x: %08x\n", addr+i, *(u32*)&ptr[i]); + //Log(LogLevel::Debug,"DCache store @ %08x: %08x\n", tag+i, *(u32*)&ptr[i]); } - DCacheTags[line] = addr | (line & (DCACHE_SETS-1)) | CACHE_FLAG_VALID; + DCacheTags[line] = tag | (line & (DCACHE_SETS-1)) | CACHE_FLAG_VALID; // ouch :/ //printf("cache miss %08X: %d/%d\n", addr, NDS::ARM9MemTimings[addr >> 14][2], NDS::ARM9MemTimings[addr >> 14][3]); // first N32 remaining S32 - DataCycles = (NDS.ARM9MemTimings[addr >> 14][2] + (NDS.ARM9MemTimings[addr >> 14][3] * ((DCACHE_LINELENGTH / 4) - 1))) << NDS.ARM9ClockShift; - CurDCacheLine = ptr; + DataCycles = (NDS.ARM9MemTimings[tag >> 14][2] + (NDS.ARM9MemTimings[tag >> 14][3] * ((DCACHE_LINELENGTH / 4) - 1))) << NDS.ARM9ClockShift; + return ptr[(addr & (DCACHE_LINELENGTH-1)) >> 2]; } -void ARMv5::DCacheWrite32(u32 addr, u32 val) +void ARMv5::DCacheWrite32(const u32 addr, const u32 val) { - addr &= ~3; + const u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; + const u32 id = ((addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; - u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; - u32 id = (addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); - - id <<= DCACHE_SETS_LOG2; for (int set=0;set> 2] = val; DataCycles = 1; //Log(LogLevel::Debug,"DCache write32 hit @ %08x -> %08lx\n", addr, ((u32 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); @@ -573,20 +590,17 @@ void ARMv5::DCacheWrite32(u32 addr, u32 val) } } -void ARMv5::DCacheWrite16(u32 addr, u16 val) +void ARMv5::DCacheWrite16(const u32 addr, const u16 val) { - addr &= ~1; + const u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; + const u32 id = ((addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; - u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; - u32 id = (addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); - - id <<= DCACHE_SETS_LOG2; for (int set=0;set> 1] = val; DataCycles = 1; //Log(LogLevel::Debug,"DCache write16 hit @ %08x -> %04x\n", addr, ((u16 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); @@ -595,18 +609,17 @@ void ARMv5::DCacheWrite16(u32 addr, u16 val) } } -void ARMv5::DCacheWrite8(u32 addr, u8 val) +void ARMv5::DCacheWrite8(const u32 addr, const u8 val) { - u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; - u32 id = (addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); + const u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; + const u32 id = ((addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2;; - id <<= DCACHE_SETS_LOG2; for (int set=0;set %02x\n", addr, ((u8 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); @@ -615,12 +628,11 @@ void ARMv5::DCacheWrite8(u32 addr, u8 val) } } -void ARMv5::DCacheInvalidateByAddr(u32 addr) +void ARMv5::DCacheInvalidateByAddr(const u32 addr) { - u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; - u32 id = (addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); + const u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; + const u32 id = ((addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; - id <<= DCACHE_SETS_LOG2; for (int set=0;set= DCACHE_SETS) return; @@ -656,19 +668,19 @@ void ARMv5::DCacheClearAll() // underlying memory and invalidates the cache line. } -void ARMv5::DCacheClearByAddr(u32 addr) +void ARMv5::DCacheClearByAddr(const u32 addr) { // TODO: right now any write to cached data goes straight to the // underlying memory and invalidates the cache line. } -void ARMv5::DCacheClearByASetAndWay(u8 cacheSet, u8 cacheLine) +void ARMv5::DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine) { // TODO: right now any write to cached data goes straight to the // underlying memory and invalidates the cache line. } -bool ARMv5::IsAddressDCachable(u32 addr) +bool ARMv5::IsAddressDCachable(const u32 addr) const { return PU_Map[addr >> 12] & 0x10 ; } @@ -1371,8 +1383,7 @@ u32 ARMv5::CodeRead32(u32 addr, bool branch) { if (IsAddressICachable(addr)) { - ICacheLookup(addr); - return *(u32*)&CurICacheLine[addr & (ICACHE_LINELENGTH - 4)]; + return ICacheLookup(addr); } } } else @@ -1412,8 +1423,7 @@ void ARMv5::DataRead8(u32 addr, u32* val) { if (PU_Map[addr >> 12] & 0x10) { - DCacheLookup(addr & ~3); - *val = CurDCacheLine[addr & (DCACHE_LINELENGTH - 1)]; + *val = (DCacheLookup(addr) >> (8* (addr & 3))) & 0xff; return; } } @@ -1455,8 +1465,7 @@ void ARMv5::DataRead16(u32 addr, u32* val) { if (PU_Map[addr >> 12] & 0x10) { - DCacheLookup(addr & ~3); - *val = *(u16 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 2)]; + *val = (DCacheLookup(addr) >> (8* (addr & 2))) & 0xffff; return; } } @@ -1500,8 +1509,7 @@ void ARMv5::DataRead32(u32 addr, u32* val) { if (PU_Map[addr >> 12] & 0x10) { - DCacheLookup(addr & ~3); - *val = *(u32 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 4)]; + *val = DCacheLookup(addr); return; } } @@ -1538,8 +1546,7 @@ void ARMv5::DataRead32S(u32 addr, u32* val) { if (PU_Map[addr >> 12] & 0x10) { - DCacheLookup(addr & ~3); - *val = *(u32 *)&CurDCacheLine[addr & (DCACHE_LINELENGTH - 4)]; + *val = DCacheLookup(addr); return; } } From c8204a8c63c261937fbf39e9faf3af335bb5f5a0 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 1 Feb 2024 08:36:52 +0100 Subject: [PATCH 24/39] Further clean up, removal of magic numbers from CP15.cpp Split the cp15 constants into CP15_Constants.h instead from MemConstants. --- src/ARM.cpp | 40 ++---- src/ARM.h | 60 ++++---- src/CP15.cpp | 328 ++++++++++++++++++------------------------- src/CP15_Constants.h | 131 +++++++++++++++++ src/MemConstants.h | 38 ----- 5 files changed, 311 insertions(+), 286 deletions(-) create mode 100644 src/CP15_Constants.h diff --git a/src/ARM.cpp b/src/ARM.cpp index c2f6a6c2..b8961a8f 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -1152,69 +1152,57 @@ u32 ARMv5::ReadMem(u32 addr, int size) } #endif -void ARMv4::DataRead8(u32 addr, u32* val) +void ARMv4::DataRead8(const u32 addr, u32* val) { *val = BusRead8(addr); DataRegion = addr; DataCycles = NDS.ARM7MemTimings[addr >> 15][0]; } -void ARMv4::DataRead16(u32 addr, u32* val) +void ARMv4::DataRead16(const u32 addr, u32* val) { - addr &= ~1; - - *val = BusRead16(addr); + *val = BusRead16(addr & ~1); DataRegion = addr; DataCycles = NDS.ARM7MemTimings[addr >> 15][0]; } -void ARMv4::DataRead32(u32 addr, u32* val) +void ARMv4::DataRead32(const u32 addr, u32* val) { - addr &= ~3; - - *val = BusRead32(addr); + *val = BusRead32(addr & ~3); DataRegion = addr; DataCycles = NDS.ARM7MemTimings[addr >> 15][2]; } -void ARMv4::DataRead32S(u32 addr, u32* val) +void ARMv4::DataRead32S(const u32 addr, u32* val) { - addr &= ~3; - - *val = BusRead32(addr); + *val = BusRead32(addr & ~3); DataCycles += NDS.ARM7MemTimings[addr >> 15][3]; } -void ARMv4::DataWrite8(u32 addr, u8 val) +void ARMv4::DataWrite8(const u32 addr, const u8 val) { BusWrite8(addr, val); DataRegion = addr; DataCycles = NDS.ARM7MemTimings[addr >> 15][0]; } -void ARMv4::DataWrite16(u32 addr, u16 val) +void ARMv4::DataWrite16(const u32 addr, const u16 val) { - addr &= ~1; - - BusWrite16(addr, val); + BusWrite16(addr & ~1, val); DataRegion = addr; DataCycles = NDS.ARM7MemTimings[addr >> 15][0]; } -void ARMv4::DataWrite32(u32 addr, u32 val) +void ARMv4::DataWrite32(const u32 addr, const u32 val) { - addr &= ~3; - - BusWrite32(addr, val); + BusWrite32(addr & ~3, val); DataRegion = addr; DataCycles = NDS.ARM7MemTimings[addr >> 15][2]; } -void ARMv4::DataWrite32S(u32 addr, u32 val) +void ARMv4::DataWrite32S(const u32 addr, const u32 val) { - addr &= ~3; - - BusWrite32(addr, val); + BusWrite32(addr & ~3, val); DataCycles += NDS.ARM7MemTimings[addr >> 15][3]; } diff --git a/src/ARM.h b/src/ARM.h index eedd997b..df06e84e 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -25,6 +25,7 @@ #include "types.h" #include "MemRegion.h" #include "MemConstants.h" +#include "CP15_Constants.h" #ifdef GDBSTUB_ENABLED #include "debug/GdbStub.h" @@ -128,14 +129,14 @@ public: void SetupCodeMem(u32 addr); - virtual void DataRead8(u32 addr, u32* val) = 0; - virtual void DataRead16(u32 addr, u32* val) = 0; - virtual void DataRead32(u32 addr, u32* val) = 0; - virtual void DataRead32S(u32 addr, u32* val) = 0; - virtual void DataWrite8(u32 addr, u8 val) = 0; - virtual void DataWrite16(u32 addr, u16 val) = 0; - virtual void DataWrite32(u32 addr, u32 val) = 0; - virtual void DataWrite32S(u32 addr, u32 val) = 0; + virtual void DataRead8(const u32 addr, u32* val) = 0; + virtual void DataRead16(const u32 addr, u32* val) = 0; + virtual void DataRead32(const u32 addr, u32* val) = 0; + virtual void DataRead32S(const u32 addr, u32* val) = 0; + virtual void DataWrite8(const u32 addr, const u8 val) = 0; + virtual void DataWrite16(const u32 addr, const u16 val) = 0; + virtual void DataWrite32(const u32 addr, const u32 val) = 0; + virtual void DataWrite32S(const u32 addr, const u32 val) = 0; virtual void AddCycles_C() = 0; virtual void AddCycles_CI(s32 numI) = 0; @@ -247,16 +248,16 @@ public: #endif // all code accesses are forced nonseq 32bit - u32 CodeRead32(u32 addr, bool branch); + u32 CodeRead32(const u32 addr, const bool branch); - void DataRead8(u32 addr, u32* val) override; - void DataRead16(u32 addr, u32* val) override; - void DataRead32(u32 addr, u32* val) override; - void DataRead32S(u32 addr, u32* val) override; - void DataWrite8(u32 addr, u8 val) override; - void DataWrite16(u32 addr, u16 val) override; - void DataWrite32(u32 addr, u32 val) override; - void DataWrite32S(u32 addr, u32 val) override; + void DataRead8(const u32 addr, u32* val) override; + void DataRead16(const u32 addr, u32* val) override; + void DataRead32(const u32 addr, u32* val) override; + void DataRead32S(const u32 addr, u32* val) override; + void DataWrite8(const u32 addr, const u8 val) override; + void DataWrite16(const u32 addr, const u16 val) override; + void DataWrite32(const u32 addr, const u32 val) override; + void DataWrite32S(const u32 addr, const u32 val) override; void AddCycles_C() override { @@ -317,7 +318,6 @@ public: void ICacheInvalidateByAddr(const u32 addr); void ICacheInvalidateBySetAndWay(const u8 cacheSet, const u8 cacheLine); - u32 DCacheLookup(const u32 addr); void DCacheWrite32(const u32 addr, const u32 val); void DCacheWrite16(const u32 addr, const u16 val); @@ -361,7 +361,6 @@ public: u8 DCache[DCACHE_SIZE]; u32 DCacheTags[DCACHE_LINESPERSET*DCACHE_SETS]; u8 DCacheCount; - u32 DCacheLFSRStates; u32 PU_CodeCacheable; u32 PU_DataCacheable; @@ -383,9 +382,6 @@ public: // code/16N/32N/32S u8 MemTimings[0x100000][4]; - u8* CurICacheLine; - u8* CurDCacheLine; - bool (*GetMemRegion)(u32 addr, bool write, MemRegion* region); #ifdef GDBSTUB_ENABLED @@ -416,24 +412,24 @@ public: void ExecuteJIT() override; #endif - u16 CodeRead16(u32 addr) + u16 CodeRead16(const u32 addr) { return BusRead16(addr); } - u32 CodeRead32(u32 addr) + u32 CodeRead32(const u32 addr) { return BusRead32(addr); } - void DataRead8(u32 addr, u32* val) override; - void DataRead16(u32 addr, u32* val) override; - void DataRead32(u32 addr, u32* val) override; - void DataRead32S(u32 addr, u32* val) override; - void DataWrite8(u32 addr, u8 val) override; - void DataWrite16(u32 addr, u16 val) override; - void DataWrite32(u32 addr, u32 val) override; - void DataWrite32S(u32 addr, u32 val) override; + void DataRead8(const u32 addr, u32* val) override; + void DataRead16(const u32 addr, u32* val) override; + void DataRead32(const u32 addr, u32* val) override; + void DataRead32S(const u32 addr, u32* val) override; + void DataWrite8(const u32 addr, const u8 val) override; + void DataWrite16(const u32 addr, const u16 val) override; + void DataWrite32(const u32 addr, const u32 val) override; + void DataWrite32S(const u32 addr, const u32 val) override; void AddCycles_C() override; void AddCycles_CI(s32 num) override; void AddCycles_CDI() override; diff --git a/src/CP15.cpp b/src/CP15.cpp index 2dcce5c1..714e591d 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -24,6 +24,7 @@ #include "Platform.h" #include "ARMJIT_Memory.h" #include "ARMJIT.h" +#include "CP15_Constants.h" namespace melonDS { @@ -67,10 +68,6 @@ void ARMv5::CP15Reset() DCacheInvalidateAll(); DCacheCount = 0; - // make sure that both half words are not the same otherwise the random of the DCache set selection only produces - // '00' and '11' - DCacheLFSRStates = 0xDEADBEEF; - PU_CodeCacheable = 0; PU_DataCacheable = 0; PU_DataCacheWrite = 0; @@ -78,10 +75,9 @@ void ARMv5::CP15Reset() PU_CodeRW = 0; PU_DataRW = 0; - memset(PU_Region, 0, 8*sizeof(u32)); + memset(PU_Region, 0, CP15_REGION_COUNT*sizeof(u32)); UpdatePURegions(true); - CurICacheLine = NULL; } void ARMv5::CP15DoSavestate(Savestate* file) @@ -103,7 +99,6 @@ void ARMv5::CP15DoSavestate(Savestate* file) file->VarArray(DCache, sizeof(DCache)); file->VarArray(DCacheTags, sizeof(DCacheTags)); file->Var8(&DCacheCount); - file->Var32(&DCacheLFSRStates); file->Var32(&DCacheLockDown); file->Var32(&ICacheLockDown); @@ -116,7 +111,7 @@ void ARMv5::CP15DoSavestate(Savestate* file) file->Var32(&PU_CodeRW); file->Var32(&PU_DataRW); - file->VarArray(PU_Region, 8*sizeof(u32)); + file->VarArray(PU_Region, CP15_REGION_COUNT*sizeof(u32)); if (!file->Saving) { @@ -178,8 +173,11 @@ void ARMv5::UpdatePURegion(u32 n) if (!(CP15Control & CP15_CR_MPUENABLE)) return; - u32 coderw = (PU_CodeRW >> (4*n)) & 0xF; - u32 datarw = (PU_DataRW >> (4*n)) & 0xF; + if (n >= CP15_REGION_COUNT) + return; + + u32 coderw = (PU_CodeRW >> (CP15_REGIONACCESS_BITS_PER_REGION * n)) & CP15_REGIONACCESS_REGIONMASK; + u32 datarw = (PU_DataRW >> (CP15_REGIONACCESS_BITS_PER_REGION * n)) & CP15_REGIONACCESS_REGIONMASK; u32 codecache, datacache, datawrite; @@ -211,60 +209,60 @@ void ARMv5::UpdatePURegion(u32 n) return; } - u32 start = rgn >> 12; - u32 sz = 2 << ((rgn >> 1) & 0x1F); - u32 end = start + (sz >> 12); + u32 start = (rgn & CP15_REGION_BASE_MASK) >> CP15_MAP_ENTRYSIZE_LOG2; + u32 sz = 2 << ((rgn & CP15_REGION_SIZE_MASK) >> 1); + u32 end = start + (sz >> CP15_MAP_ENTRYSIZE_LOG2); // TODO: check alignment of start - u8 usermask = 0; - u8 privmask = 0; + u8 usermask = CP15_MAP_NOACCESS; + u8 privmask = CP15_MAP_NOACCESS; switch (datarw) { case 0: break; - case 1: privmask |= 0x03; break; - case 2: privmask |= 0x03; usermask |= 0x01; break; - case 3: privmask |= 0x03; usermask |= 0x03; break; - case 5: privmask |= 0x01; break; - case 6: privmask |= 0x01; usermask |= 0x01; break; + case 1: privmask |= CP15_MAP_READABLE | CP15_MAP_WRITEABLE; break; + case 2: privmask |= CP15_MAP_READABLE | CP15_MAP_WRITEABLE; usermask |= CP15_MAP_READABLE; break; + case 3: privmask |= CP15_MAP_READABLE | CP15_MAP_WRITEABLE; usermask |= CP15_MAP_READABLE | CP15_MAP_WRITEABLE; break; + case 5: privmask |= CP15_MAP_READABLE; break; + case 6: privmask |= CP15_MAP_READABLE; usermask |= CP15_MAP_READABLE; break; default: Log(LogLevel::Warn, "!! BAD DATARW VALUE %d\n", datarw&0xF); } switch (coderw) { case 0: break; - case 1: privmask |= 0x04; break; - case 2: privmask |= 0x04; usermask |= 0x04; break; - case 3: privmask |= 0x04; usermask |= 0x04; break; - case 5: privmask |= 0x04; break; - case 6: privmask |= 0x04; usermask |= 0x04; break; + case 1: privmask |= CP15_MAP_EXECUTABLE; break; + case 2: privmask |= CP15_MAP_EXECUTABLE; usermask |= CP15_MAP_EXECUTABLE; break; + case 3: privmask |= CP15_MAP_EXECUTABLE; usermask |= CP15_MAP_EXECUTABLE; break; + case 5: privmask |= CP15_MAP_EXECUTABLE; break; + case 6: privmask |= CP15_MAP_EXECUTABLE; usermask |= CP15_MAP_EXECUTABLE; break; default: Log(LogLevel::Warn, "!! BAD CODERW VALUE %d\n", datarw&0xF); } if (datacache & 0x1) { - privmask |= 0x10; - usermask |= 0x10; + privmask |= CP15_MAP_DCACHEABLE; + usermask |= CP15_MAP_DCACHEABLE; if (datawrite & 0x1) { - privmask |= 0x20; - usermask |= 0x20; + privmask |= CP15_MAP_DCACHEWRITEBACK; + usermask |= CP15_MAP_DCACHEWRITEBACK; } } if (codecache & 0x1) { - privmask |= 0x40; - usermask |= 0x40; + privmask |= CP15_MAP_ICACHEABLE; + usermask |= CP15_MAP_ICACHEABLE; } Log( LogLevel::Debug, "PU region %d: %08X-%08X, user=%02X priv=%02X, %08X/%08X\n", n, - start << 12, - end << 12, + start << CP15_MAP_ENTRYSIZE_LOG2, + end << CP15_MAP_ENTRYSIZE_LOG2, usermask, privmask, PU_DataRW, @@ -286,9 +284,9 @@ void ARMv5::UpdatePURegions(bool update_all) { // PU disabled - u8 mask = 0x07; - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) mask |= 0x30; - if (CP15Control & CP15_CACHE_CR_ICACHEENABLE) mask |= 0x40; + u8 mask = CP15_MAP_READABLE | CP15_MAP_WRITEABLE | CP15_MAP_EXECUTABLE; + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) mask |= CP15_MAP_DCACHEABLE | CP15_MAP_DCACHEWRITEBACK ; + if (CP15Control & CP15_CACHE_CR_ICACHEENABLE) mask |= CP15_MAP_ICACHEABLE; memset(PU_UserMap, mask, 0x100000); memset(PU_PrivMap, mask, 0x100000); @@ -299,11 +297,11 @@ void ARMv5::UpdatePURegions(bool update_all) if (update_all) { - memset(PU_UserMap, 0, 0x100000); - memset(PU_PrivMap, 0, 0x100000); + memset(PU_UserMap, CP15_MAP_NOACCESS, 0x100000); + memset(PU_PrivMap, CP15_MAP_NOACCESS, 0x100000); } - for (int n = 0; n < 8; n++) + for (int n = 0; n < CP15_REGION_COUNT; n++) { UpdatePURegion(n); } @@ -322,7 +320,7 @@ void ARMv5::UpdateRegionTimings(u32 addrstart, u32 addrend) u8 pu = PU_Map[i]; u8* bustimings = NDS.ARM9MemTimings[i >> 2]; - if (pu & 0x40) + if (pu & CP15_MAP_ICACHEABLE) { MemTimings[i][0] = 0xFF;//kCodeCacheTiming; } @@ -331,7 +329,7 @@ void ARMv5::UpdateRegionTimings(u32 addrstart, u32 addrend) MemTimings[i][0] = bustimings[2] << NDS.ARM9ClockShift; } - if (pu & 0x10) + if (pu & CP15_MAP_DCACHEABLE) { MemTimings[i][1] = kDataCacheTiming; MemTimings[i][2] = kDataCacheTiming; @@ -364,7 +362,7 @@ u32 ARMv5::ICacheLookup(const u32 addr) for (int set=0;set> 12] & 0x40 ; + return PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_ICACHEABLE ; } u32 ARMv5::DCacheLookup(const u32 addr) @@ -487,7 +485,7 @@ u32 ARMv5::DCacheLookup(const u32 addr) for (int set=0;set> 2] = val; DataCycles = 1; - - //Log(LogLevel::Debug,"DCache write32 hit @ %08x -> %08lx\n", addr, ((u32 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); return; } } @@ -597,13 +593,11 @@ void ARMv5::DCacheWrite16(const u32 addr, const u16 val) for (int set=0;set> 1] = val; DataCycles = 1; - - //Log(LogLevel::Debug,"DCache write16 hit @ %08x -> %04x\n", addr, ((u16 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); return; } } @@ -616,13 +610,11 @@ void ARMv5::DCacheWrite8(const u32 addr, const u8 val) for (int set=0;set %02x\n", addr, ((u8 *)CurDCacheLine)[(addr & (DCACHE_LINELENGTH-1)) >> 2]); return; } } @@ -635,7 +627,7 @@ void ARMv5::DCacheInvalidateByAddr(const u32 addr) for (int set=0;set> 12] & 0x10 ; + return PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEABLE ; } void ARMv5::CP15Write(u32 id, u32 val) @@ -700,13 +692,14 @@ void ARMv5::CP15Write(u32 id, u32 val) //Log(LogLevel::Debug, "CP15Control = %08X (%08X->%08X)\n", CP15Control, old, val); UpdateDTCMSetting(); UpdateITCMSetting(); - if ((old & 0x1005) != (val & 0x1005)) + u32 changedBits = old^val; + if (changedBits & (CP15_CR_MPUENABLE | CP15_CACHE_CR_ICACHEENABLE| CP15_CACHE_CR_DCACHEENABLE)) { - UpdatePURegions((old & 0x1) != (val & 0x1)); + UpdatePURegions(changedBits & CP15_CR_MPUENABLE); } if (val & CP15_CR_BIGENDIAN) Log(LogLevel::Warn, "!!!! ARM9 BIG ENDIAN MODE. VERY BAD. SHIT GONNA ASPLODE NOW\n"); - if (val & CP15_CR_HIGHEXCEPTIONBASE) ExceptionBase = 0xFFFF0000; - else ExceptionBase = 0x00000000; + if (val & CP15_CR_HIGHEXCEPTIONBASE) ExceptionBase = CP15_EXCEPTIONBASE_HIGH; + else ExceptionBase = CP15_EXCEPTIONBASE_LOW; } return; @@ -715,7 +708,7 @@ void ARMv5::CP15Write(u32 id, u32 val) { u32 diff = PU_DataCacheable ^ val; PU_DataCacheable = val; - for (u32 i = 0; i < 8; i++) + for (u32 i = 0; i < CP15_REGION_COUNT; i++) { if (diff & (1<> 4) & 0xF] = val; + PU_Region[(id >> CP15_REGIONACCESS_BITS_PER_REGION) & CP15_REGIONACCESS_REGIONMASK] = val; - std::snprintf(log_output, - sizeof(log_output), + Log(LogLevel::Debug, "PU: region %d = %08X : %s, %08X-%08X\n", - (id >> 4) & 0xF, + (id >> CP15_REGIONACCESS_BITS_PER_REGION) & CP15_REGIONACCESS_REGIONMASK, val, val & 1 ? "enabled" : "disabled", - val & 0xFFFFF000, - (val & 0xFFFFF000) + (2 << ((val & 0x3E) >> 1)) + val & CP15_REGION_BASE_MASK, + (val & CP15_REGION_BASE_MASK) + (2 << ((val & CP15_REGION_SIZE_MASK) >> 1)) ); - Log(LogLevel::Debug, "%s", log_output); - // Some implementations of Log imply a newline, so we build up the line before printing it - // TODO: smarter region update for this? UpdatePURegions(true); return; @@ -854,7 +842,6 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0x750: // Can be executed in user and priv mode ICacheInvalidateAll(); - //Halt(255); return; case 0x751: // requires priv mode or causes UNKNOWN INSTRUCTION exception @@ -1179,11 +1166,7 @@ void ARMv5::CP15Write(u32 id, u32 val) } - if ((id & 0xF00) == 0xF00) // test/debug shit? - return; - - if ((id & 0xF00) != 0x700) - Log(LogLevel::Debug, "unknown CP15 write op %03X %08X\n", id, val); + Log(LogLevel::Debug, "unknown CP15 write op %03X %08X\n", id, val); } u32 ARMv5::CP15Read(u32 id) const @@ -1198,7 +1181,7 @@ u32 ARMv5::CP15Read(u32 id) const case 0x005: case 0x006: case 0x007: - return 0x41059461; + return CP15_MAINID_IMPLEMENTOR_ARM | CP15_MAINID_VARIANT_0 | CP15_MAINID_ARCH_v5TE | CP15_MAINID_IMPLEMENTATION_946 | CP15_MAINID_REVISION_1; case 0x001: // cache type return CACHE_TR_LOCKDOWN_TYPE_B | CACHE_TR_NONUNIFIED @@ -1269,7 +1252,7 @@ u32 ARMv5::CP15Read(u32 id) const case 0x661: case 0x670: case 0x671: - return PU_Region[(id >> 4) & 0xF]; + return PU_Region[(id >> CP15_REGIONACCESS_BITS_PER_REGION) & 0xF]; case 0x7A6: // read Cache Dirty Bit (optional) @@ -1346,9 +1329,6 @@ u32 ARMv5::CP15Read(u32 id) const } } - if ((id & 0xF00) == 0xF00) // test/debug shit? - return 0; - Log(LogLevel::Debug, "unknown CP15 read op %03X\n", id); return 0; } @@ -1357,24 +1337,9 @@ u32 ARMv5::CP15Read(u32 id) const // TCM are handled here. // TODO: later on, handle PU -u32 ARMv5::CodeRead32(u32 addr, bool branch) +u32 ARMv5::CodeRead32(const u32 addr, bool const branch) { - /*if (branch || (!(addr & 0xFFF))) - { - if (!(PU_Map[addr>>12] & 0x04)) - { - PrefetchAbort(); - return 0; - } - }*/ - if (addr < ITCMSize) - { - CodeCycles = 1; - return *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)]; - } - - CodeCycles = RegionCodeCycles; #ifdef JIT_ENABLED if (!NDS.IsJITEnabled()) #endif @@ -1386,27 +1351,33 @@ u32 ARMv5::CodeRead32(u32 addr, bool branch) return ICacheLookup(addr); } } - } else - { - if (CodeCycles == 0xFF) // cached memory. hax - { - if (branch || !(addr & 0x1F)) - CodeCycles = kCodeCacheTiming;//ICacheLookup(addr); - else - CodeCycles = 1; + } - //return *(u32*)&CurICacheLine[addr & 0x1C]; - } + if (addr < ITCMSize) + { + CodeCycles = 1; + return *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)]; } + + CodeCycles = RegionCodeCycles; + + if (CodeCycles == 0xFF) // cached memory. hax + { + if (branch || !(addr & (ICACHE_LINELENGTH-1))) + CodeCycles = kCodeCacheTiming;//ICacheLookup(addr); + else + CodeCycles = 1; + } + if (CodeMem.Mem) return *(u32*)&CodeMem.Mem[addr & CodeMem.Mask]; return BusRead32(addr); } -void ARMv5::DataRead8(u32 addr, u32* val) +void ARMv5::DataRead8(const u32 addr, u32* val) { - if (!(PU_Map[addr>>12] & 0x01)) + if (!(PU_Map[addr>>CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_READABLE)) { Log(LogLevel::Debug, "data8 abort @ %08lx\n", addr); DataAbort(); @@ -1421,9 +1392,9 @@ void ARMv5::DataRead8(u32 addr, u32* val) { if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - if (PU_Map[addr >> 12] & 0x10) + if (IsAddressDCachable(addr)) { - *val = (DCacheLookup(addr) >> (8* (addr & 3))) & 0xff; + *val = (DCacheLookup(addr) >> (8 * (addr & 3))) & 0xff; return; } } @@ -1443,12 +1414,12 @@ void ARMv5::DataRead8(u32 addr, u32* val) } *val = BusRead8(addr); - DataCycles = MemTimings[addr >> 12][1]; + DataCycles = MemTimings[addr >> BUSCYCLES_MAP_GRANULARITY_LOG2][BUSCYCLES_S16]; } -void ARMv5::DataRead16(u32 addr, u32* val) +void ARMv5::DataRead16(const u32 addr, u32* val) { - if (!(PU_Map[addr>>12] & 0x01)) + if (!(PU_Map[addr>>CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_READABLE)) { Log(LogLevel::Debug, "data16 abort @ %08lx\n", addr); DataAbort(); @@ -1463,7 +1434,7 @@ void ARMv5::DataRead16(u32 addr, u32* val) { if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - if (PU_Map[addr >> 12] & 0x10) + if (IsAddressDCachable(addr)) { *val = (DCacheLookup(addr) >> (8* (addr & 2))) & 0xffff; return; @@ -1471,28 +1442,26 @@ void ARMv5::DataRead16(u32 addr, u32* val) } } - addr &= ~1; - if (addr < ITCMSize) { DataCycles = 1; - *val = *(u16*)&ITCM[addr & (ITCMPhysicalSize - 1)]; + *val = *(u16*)&ITCM[addr & (ITCMPhysicalSize - 2)]; return; } if ((addr & DTCMMask) == DTCMBase) { DataCycles = 1; - *val = *(u16*)&DTCM[addr & (DTCMPhysicalSize - 1)]; + *val = *(u16*)&DTCM[addr & (DTCMPhysicalSize - 2)]; return; } - *val = BusRead16(addr); - DataCycles = MemTimings[addr >> 12][1]; + *val = BusRead16(addr & ~1); + DataCycles = MemTimings[addr >> BUSCYCLES_MAP_GRANULARITY_LOG2][BUSCYCLES_S16]; } -void ARMv5::DataRead32(u32 addr, u32* val) +void ARMv5::DataRead32(const u32 addr, u32* val) { - if (!(PU_Map[addr>>12] & 0x01)) + if (!(PU_Map[addr>>CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_READABLE)) { Log(LogLevel::Debug, "data32 abort @ %08lx\n", addr); DataAbort(); @@ -1507,7 +1476,7 @@ void ARMv5::DataRead32(u32 addr, u32* val) { if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - if (PU_Map[addr >> 12] & 0x10) + if (IsAddressDCachable(addr)) { *val = DCacheLookup(addr); return; @@ -1515,36 +1484,32 @@ void ARMv5::DataRead32(u32 addr, u32* val) } } - addr &= ~3; - if (addr < ITCMSize) { DataCycles = 1; - *val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)]; + *val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 3)]; return; } if ((addr & DTCMMask) == DTCMBase) { DataCycles = 1; - *val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)]; + *val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 3)]; return; } - *val = BusRead32(addr); - DataCycles = MemTimings[addr >> 12][2]; + *val = BusRead32(addr & ~0x03); + DataCycles = MemTimings[addr >> BUSCYCLES_MAP_GRANULARITY_LOG2][BUSCYCLES_N32]; } -void ARMv5::DataRead32S(u32 addr, u32* val) +void ARMv5::DataRead32S(const u32 addr, u32* val) { - addr &= ~3; - #ifdef JIT_ENABLED if (!NDS.IsJITEnabled()) #endif { if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - if (PU_Map[addr >> 12] & 0x10) + if (IsAddressDCachable(addr)) { *val = DCacheLookup(addr); return; @@ -1555,23 +1520,23 @@ void ARMv5::DataRead32S(u32 addr, u32* val) if (addr < ITCMSize) { DataCycles += 1; - *val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)]; + *val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 3)]; return; } if ((addr & DTCMMask) == DTCMBase) { DataCycles += 1; - *val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)]; + *val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 3)]; return; } - *val = BusRead32(addr); - DataCycles += MemTimings[addr >> 12][3]; + *val = BusRead32(addr & ~0x03); + DataCycles += MemTimings[addr >> BUSCYCLES_MAP_GRANULARITY_LOG2][BUSCYCLES_S32]; } -void ARMv5::DataWrite8(u32 addr, u8 val) +void ARMv5::DataWrite8(const u32 addr, const u8 val) { - if (!(PU_Map[addr>>12] & 0x02)) + if (!(PU_Map[addr>>CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_WRITEABLE)) { DataAbort(); return; @@ -1583,10 +1548,9 @@ void ARMv5::DataWrite8(u32 addr, u8 val) { if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - if (PU_Map[addr >> 12] & 0x10) + if (IsAddressDCachable(addr)) { DCacheWrite8(addr, val); - //DCacheInvalidateByAddr(addr); } } } @@ -1608,12 +1572,12 @@ void ARMv5::DataWrite8(u32 addr, u8 val) } BusWrite8(addr, val); - DataCycles = MemTimings[addr >> 12][1]; + DataCycles = MemTimings[addr >> BUSCYCLES_MAP_GRANULARITY_LOG2][BUSCYCLES_S16]; } -void ARMv5::DataWrite16(u32 addr, u16 val) +void ARMv5::DataWrite16(const u32 addr, const u16 val) { - if (!(PU_Map[addr>>12] & 0x02)) + if (!(PU_Map[addr>>CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_WRITEABLE)) { DataAbort(); return; @@ -1625,39 +1589,36 @@ void ARMv5::DataWrite16(u32 addr, u16 val) { if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - if (PU_Map[addr >> 12] & 0x10) + if (IsAddressDCachable(addr)) { DCacheWrite16(addr, val); - // DCacheInvalidateByAddr(addr); } } } DataRegion = addr; - addr &= ~1; - if (addr < ITCMSize) { DataCycles = 1; - *(u16*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val; + *(u16*)&ITCM[addr & (ITCMPhysicalSize - 2)] = val; NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); return; } if ((addr & DTCMMask) == DTCMBase) { DataCycles = 1; - *(u16*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; + *(u16*)&DTCM[addr & (DTCMPhysicalSize - 2)] = val; return; } - BusWrite16(addr, val); - DataCycles = MemTimings[addr >> 12][1]; + BusWrite16(addr & ~1, val); + DataCycles = MemTimings[addr >> BUSCYCLES_MAP_GRANULARITY_LOG2][BUSCYCLES_S16]; } -void ARMv5::DataWrite32(u32 addr, u32 val) +void ARMv5::DataWrite32(const u32 addr, const u32 val) { - if (!(PU_Map[addr>>12] & 0x02)) + if (!(PU_Map[addr>>CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_WRITEABLE)) { DataAbort(); return; @@ -1669,50 +1630,44 @@ void ARMv5::DataWrite32(u32 addr, u32 val) { if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - if (PU_Map[addr >> 12] & 0x10) + if (IsAddressDCachable(addr)) { DCacheWrite32(addr, val); - // DCacheInvalidateByAddr(addr); } } } DataRegion = addr; - addr &= ~3; - if (addr < ITCMSize) { DataCycles = 1; - *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val; + *(u32*)&ITCM[addr & (ITCMPhysicalSize - 3)] = val; NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); return; } if ((addr & DTCMMask) == DTCMBase) { DataCycles = 1; - *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; + *(u32*)&DTCM[addr & (DTCMPhysicalSize - 3)] = val; return; } - BusWrite32(addr, val); - DataCycles = MemTimings[addr >> 12][2]; + BusWrite32(addr & ~3, val); + DataCycles = MemTimings[addr >> BUSCYCLES_MAP_GRANULARITY_LOG2][BUSCYCLES_N32]; } -void ARMv5::DataWrite32S(u32 addr, u32 val) +void ARMv5::DataWrite32S(const u32 addr, const u32 val) { - addr &= ~3; - #ifdef JIT_ENABLED if (!NDS.IsJITEnabled()) #endif { if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - if (PU_Map[addr >> 12] & 0x10) + if (IsAddressDCachable(addr)) { DCacheWrite32(addr, val); - // DCacheInvalidateByAddr(addr); } } } @@ -1720,7 +1675,7 @@ void ARMv5::DataWrite32S(u32 addr, u32 val) if (addr < ITCMSize) { DataCycles += 1; - *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val; + *(u32*)&ITCM[addr & (ITCMPhysicalSize - 3)] = val; #ifdef JIT_ENABLED NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); #endif @@ -1729,23 +1684,16 @@ void ARMv5::DataWrite32S(u32 addr, u32 val) if ((addr & DTCMMask) == DTCMBase) { DataCycles += 1; - *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; + *(u32*)&DTCM[addr & (DTCMPhysicalSize - 3)] = val; return; } - BusWrite32(addr, val); - DataCycles += MemTimings[addr >> 12][3]; + BusWrite32(addr & ~3, val); + DataCycles += MemTimings[addr >> BUSCYCLES_MAP_GRANULARITY_LOG2][BUSCYCLES_S32]; } void ARMv5::GetCodeMemRegion(u32 addr, MemRegion* region) { - /*if (addr < ITCMSize) - { - region->Mem = ITCM; - region->Mask = 0x7FFF; - return; - }*/ - NDS.ARM9GetMemRegion(addr, false, &CodeMem); } diff --git a/src/CP15_Constants.h b/src/CP15_Constants.h new file mode 100644 index 00000000..80fadf31 --- /dev/null +++ b/src/CP15_Constants.h @@ -0,0 +1,131 @@ +/* + Copyright 2016-2023 melonDS team + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef MELONDS_CP15CONSTANTS_H +#define MELONDS_CP15CONSTANTS_H + +#include "types.h" + +namespace melonDS +{ + +/* ICACHE Layout constants */ +constexpr u32 ICACHE_SIZE_LOG2 = 13; +constexpr u32 ICACHE_SIZE = 1 << ICACHE_SIZE_LOG2; +constexpr u32 ICACHE_SETS_LOG2 = 2; +constexpr u32 ICACHE_SETS = 1 << ICACHE_SETS_LOG2; +constexpr u32 ICACHE_LINELENGTH_ENCODED = 2; +constexpr u32 ICACHE_LINELENGTH_LOG2 = ICACHE_LINELENGTH_ENCODED + 3; +constexpr u32 ICACHE_LINELENGTH = 8 * (1 << ICACHE_LINELENGTH_ENCODED); +constexpr u32 ICACHE_LINESPERSET = ICACHE_SIZE / (ICACHE_SETS * ICACHE_LINELENGTH); + +/* DCACHE Layout constants */ +constexpr u32 DCACHE_SIZE_LOG2 = 12; +constexpr u32 DCACHE_SIZE = 1 << DCACHE_SIZE_LOG2; +constexpr u32 DCACHE_SETS_LOG2 = 2; +constexpr u32 DCACHE_SETS = 1 << DCACHE_SETS_LOG2; +constexpr u32 DCACHE_LINELENGTH_ENCODED = 2; +constexpr u32 DCACHE_LINELENGTH_LOG2 = DCACHE_LINELENGTH_ENCODED + 3; +constexpr u32 DCACHE_LINELENGTH = 8 * (1 << DCACHE_LINELENGTH_ENCODED); +constexpr u32 DCACHE_LINESPERSET = DCACHE_SIZE / (DCACHE_SETS * DCACHE_LINELENGTH); + +/* CP15 Cache Data TAGs */ +constexpr u32 CACHE_FLAG_VALID = (1 << 4); +constexpr u32 CACHE_FLAG_DIRTY_LOWERHALF = (1 << 2); +constexpr u32 CACHE_FLAG_DIRTY_UPPERHALF = (1 << 3); +constexpr u32 CACHE_FLAG_DIRTY_MASK = (3 << 2); +constexpr u32 CACHE_FLAG_SET_MASK = (3 << 0); + +/* CP15 Cache Type Register */ +constexpr u32 CACHE_TR_LOCKDOWN_TYPE_B = (7 << 25); +constexpr u32 CACHE_TR_NONUNIFIED = (1 << 24); + +/* CP15 I/DCache LockDown registers */ +constexpr u32 CACHE_LOCKUP_L = (1 << 31); + +/* CP15 Main ID register */ +constexpr u32 CP15_MAINID_IMPLEMENTOR_ARM = (0x41 << 24); +constexpr u32 CP15_MAINID_IMPLEMENTOR_DEC = (0x44 << 24); +constexpr u32 CP15_MAINID_IMPLEMENTOR_MOTOROLA = (0x4D << 24); +constexpr u32 CP15_MAINID_IMPLEMENTOR_MARVELL = (0x56 << 24); +constexpr u32 CP15_MAINID_IMPLEMENTOR_INTEL = (0x69 << 24); +constexpr u32 CP15_MAINID_VARIANT_0 = (0 << 20); +constexpr u32 CP15_MAINID_ARCH_v4 = (1 << 16); +constexpr u32 CP15_MAINID_ARCH_v4T = (2 << 16); +constexpr u32 CP15_MAINID_ARCH_v5 = (3 << 16); +constexpr u32 CP15_MAINID_ARCH_v5T = (4 << 16); +constexpr u32 CP15_MAINID_ARCH_v5TE = (5 << 16); +constexpr u32 CP15_MAINID_ARCH_v5TEJ = (6 << 16); +constexpr u32 CP15_MAINID_ARCH_v6 = (7 << 16); +constexpr u32 CP15_MAINID_IMPLEMENTATION_946 = (0x946 << 4); +constexpr u32 CP15_MAINID_REVISION_0 = (0 << 0); +constexpr u32 CP15_MAINID_REVISION_1 = (1 << 0); + +/* CP15 Control Register */ +constexpr u32 CP15_CR_MPUENABLE = (1 << 0); +constexpr u32 CP15_CR_BIGENDIAN = (1 << 7); +constexpr u32 CP15_CR_HIGHEXCEPTIONBASE = (1 << 13); + +/* CP15 Internal Exception base value */ +constexpr u32 CP15_EXCEPTIONBASE_HIGH = 0xFFFF0000; +constexpr u32 CP15_EXCEPTIONBASE_LOW = 0x00000000; + +/* CP15 Cache and Write Buffer Conrol Register */ +constexpr u32 CP15_CACHE_CR_ROUNDROBIN = (1 << 14); +constexpr u32 CP15_CACHE_CR_ICACHEENABLE = (1 << 12); +constexpr u32 CP15_CACHE_CR_DCACHEENABLE = (1 << 2); +constexpr u32 CP15_CACHE_CR_WRITEBUFFERENABLE = (1 << 3); + +/* CP15 TCM Control Register */ +constexpr u32 CP15_TCM_CR_DTCM_ENABLE = (1 << 16); +constexpr u32 CP15_TCM_CR_ITCM_ENABLE = (1 << 18); + +/* CP15 Region Base and Size Register */ +constexpr u32 CP15_REGION_COUNT = 8; +constexpr u32 CP15_REGION_ENABLE = (1 << 0); +constexpr u32 CP15_REGION_SIZE_MASK = (0x1F << 1); +constexpr u32 CP15_REGION_BASE_GRANULARITY_LOG2 = 12; +constexpr u32 CP15_REGION_BASE_GRANULARITY = (1 << CP15_REGION_BASE_GRANULARITY_LOG2); +constexpr u32 CP15_REGION_BASE_MASK = ~(CP15_REGION_BASE_GRANULARITY_LOG2-1); + +/* CP15 Region access mask registers */ +constexpr u32 CP15_REGIONACCESS_BITS_PER_REGION = 4; +constexpr u32 CP15_REGIONACCESS_REGIONMASK = (1 << CP15_REGIONACCESS_BITS_PER_REGION) - 1; + +/* Flags in the melonDS internal PU_PrivMap and PU_UserMap */ +constexpr u32 CP15_MAP_NOACCESS = 0x00; +constexpr u32 CP15_MAP_READABLE = 0x01; +constexpr u32 CP15_MAP_WRITEABLE = 0x02; +constexpr u32 CP15_MAP_EXECUTABLE = 0x04; +constexpr u32 CP15_MAP_DCACHEABLE = 0x10; +constexpr u32 CP15_MAP_DCACHEWRITEBACK = 0x20; +constexpr u32 CP15_MAP_ICACHEABLE = 0x40; + +constexpr u32 CP15_MAP_ENTRYSIZE_LOG2 = CP15_REGION_BASE_GRANULARITY_LOG2; +constexpr u32 CP15_MAP_ENTRYSIZE = (1 << CP15_MAP_ENTRYSIZE_LOG2); + +/* Internal Timing Constants */ +constexpr u32 BUSCYCLES_N16 = 0; +constexpr u32 BUSCYCLES_S16 = 1; +constexpr u32 BUSCYCLES_N32 = 2; +constexpr u32 BUSCYCLES_S32 = 3; + +constexpr u32 BUSCYCLES_MAP_GRANULARITY_LOG2 = CP15_REGION_BASE_GRANULARITY_LOG2; +} + +#endif // MELONDS_CP15CONSTANTS_H \ No newline at end of file diff --git a/src/MemConstants.h b/src/MemConstants.h index 332b9b18..e9aa6b2b 100644 --- a/src/MemConstants.h +++ b/src/MemConstants.h @@ -34,44 +34,6 @@ constexpr u32 ITCMPhysicalSize = 0x8000; constexpr u32 DTCMPhysicalSize = 0x4000; constexpr u32 ARM7BIOSCRC32 = 0x1280f0d5; constexpr u32 ARM9BIOSCRC32 = 0x2ab23573; - -constexpr u32 ICACHE_SIZE_LOG2 = 13; -constexpr u32 ICACHE_SIZE = 1 << ICACHE_SIZE_LOG2; -constexpr u32 ICACHE_SETS_LOG2 = 2; -constexpr u32 ICACHE_SETS = 1 << ICACHE_SETS_LOG2; -constexpr u32 ICACHE_LINELENGTH_ENCODED = 2; -constexpr u32 ICACHE_LINELENGTH_LOG2 = ICACHE_LINELENGTH_ENCODED + 3; -constexpr u32 ICACHE_LINELENGTH = 8 * (1 << ICACHE_LINELENGTH_ENCODED); -constexpr u32 ICACHE_LINESPERSET = ICACHE_SIZE / (ICACHE_SETS * ICACHE_LINELENGTH); - -constexpr u32 DCACHE_SIZE_LOG2 = 12; -constexpr u32 DCACHE_SIZE = 1 << DCACHE_SIZE_LOG2; -constexpr u32 DCACHE_SETS_LOG2 = 2; -constexpr u32 DCACHE_SETS = 1 << DCACHE_SETS_LOG2; -constexpr u32 DCACHE_LINELENGTH_ENCODED = 2; -constexpr u32 DCACHE_LINELENGTH_LOG2 = DCACHE_LINELENGTH_ENCODED + 3; -constexpr u32 DCACHE_LINELENGTH = 8 * (1 << DCACHE_LINELENGTH_ENCODED); -constexpr u32 DCACHE_LINESPERSET = DCACHE_SIZE / (DCACHE_SETS * DCACHE_LINELENGTH); - -constexpr u32 CACHE_FLAG_VALID = (1 << 4); -constexpr u32 CACHE_FLAG_DIRTY_LOWERHALF = (1 << 2); -constexpr u32 CACHE_FLAG_DIRTY_UPPERHALF = (1 << 3); - -constexpr u32 CACHE_TR_LOCKDOWN_TYPE_B = (7 << 25); -constexpr u32 CACHE_TR_NONUNIFIED = (1 << 24); - -constexpr u32 CACHE_LOCKUP_L = (1 << 31); - -constexpr u32 CP15_CR_MPUENABLE = (1 << 0); -constexpr u32 CP15_CR_BIGENDIAN = (1 << 7); -constexpr u32 CP15_CR_HIGHEXCEPTIONBASE = (1 << 13); -constexpr u32 CP15_CACHE_CR_ROUNDROBIN = (1 << 14); -constexpr u32 CP15_CACHE_CR_ICACHEENABLE = (1 << 12); -constexpr u32 CP15_CACHE_CR_DCACHEENABLE = (1 << 2); -constexpr u32 CP15_CACHE_CR_WRITEBUFFERENABLE = (1 << 3); -constexpr u32 CP15_TCM_CR_DTCM_ENABLE = (1 << 16); -constexpr u32 CP15_TCM_CR_ITCM_ENABLE = (1 << 18); - } #endif // MELONDS_MEMCONSTANTS_H \ No newline at end of file From 1a9179b8d03ba46287b92460de77a756b5a16a71 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 1 Feb 2024 08:49:04 +0100 Subject: [PATCH 25/39] Removed unneccessary wfcsettings file --- wfcsettings.bin | Bin 2304 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 wfcsettings.bin diff --git a/wfcsettings.bin b/wfcsettings.bin deleted file mode 100644 index af3146aeb6423c6cff0a4d369941eb72c52e62d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2304 zcmezWe-w;{z-S1JhQMeDjKmONpb+Gy=H%x&22f}U-Lx};ZSpv2Zan{jrB=^(PP*AV buonG?T94-cg1ZCjEV|i_>VLSkr#}DyyOIjR From 81c943411654d49b0ab9220a7f03a18d88f9ccb5 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 1 Feb 2024 12:01:16 +0100 Subject: [PATCH 26/39] Added CP15 Trace Process ID --- src/ARM.h | 3 +-- src/CP15.cpp | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/ARM.h b/src/ARM.h index df06e84e..e56534ad 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -332,8 +332,6 @@ public: void DCacheClearByAddr(const u32 addr); void DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine); - - void CP15Write(u32 id, u32 val); u32 CP15Read(u32 id) const; @@ -344,6 +342,7 @@ public: u32 DTCMSetting, ITCMSetting; u32 DCacheLockDown, ICacheLockDown; u32 CacheDebugRegisterIndex; + u32 CP15TraceProcessId; // for aarch64 JIT they need to go up here // to be addressable by a 12-bit immediate diff --git a/src/CP15.cpp b/src/CP15.cpp index 714e591d..caa8de34 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -40,6 +40,16 @@ const int kDataCacheTiming = 3;//2; const int kCodeCacheTiming = 3;//5; +/* CP15 Reset sets the default values within each registers and + memories of the CP15. + This includes the Settings for + DTCM + ITCM + Caches + Regions + Process Trace +*/ + void ARMv5::CP15Reset() { CP15Control = 0x2078; // dunno @@ -68,6 +78,8 @@ void ARMv5::CP15Reset() DCacheInvalidateAll(); DCacheCount = 0; + CP15TraceProcessId = 0; + PU_CodeCacheable = 0; PU_DataCacheable = 0; PU_DataCacheWrite = 0; @@ -103,6 +115,7 @@ void ARMv5::CP15DoSavestate(Savestate* file) file->Var32(&DCacheLockDown); file->Var32(&ICacheLockDown); file->Var32(&CacheDebugRegisterIndex); + file->Var32(&CP15TraceProcessId); file->Var32(&PU_CodeCacheable); file->Var32(&PU_DataCacheable); @@ -1086,6 +1099,11 @@ void ARMv5::CP15Write(u32 id, u32 val) UpdateITCMSetting(); return; + case 0xD01: + case 0xD11: + CP15TraceProcessId = val; + return; + case 0xF00: if (PU_Map != PU_PrivMap) { @@ -1277,6 +1295,10 @@ u32 ARMv5::CP15Read(u32 id) const case 0x911: return ITCMSetting; + case 0xD01: // See arm946E-S Rev 1 technical Reference Manual, Chapter 2.3.13 */ + case 0xD11: // backwards compatible read/write of the same register + return CP15TraceProcessId; + case 0xF00: if (PU_Map != PU_PrivMap) { From 9fa814b68e20bedb667f8938f9cbfce12285be26 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 1 Feb 2024 13:15:03 +0100 Subject: [PATCH 27/39] Added check of op1 in MCR/MRC Fixed Cache Debug registers were accessible, when op1 != 3 in MCR/MRC instructions Added BIST Test Status register and its cache linefill disable bits --- src/ARM.h | 1 + src/ARMInterpreter.cpp | 12 ++++---- src/CP15.cpp | 66 ++++++++++++++++++++++++++++++++++++++---- src/CP15_Constants.h | 4 +++ 4 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/ARM.h b/src/ARM.h index e56534ad..abb0e686 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -343,6 +343,7 @@ public: u32 DCacheLockDown, ICacheLockDown; u32 CacheDebugRegisterIndex; u32 CP15TraceProcessId; + u32 CP15BISTTestStateRegister; // for aarch64 JIT they need to go up here // to be addressable by a 12-bit immediate diff --git a/src/ARMInterpreter.cpp b/src/ARMInterpreter.cpp index ff73e230..316db0a2 100644 --- a/src/ARMInterpreter.cpp +++ b/src/ARMInterpreter.cpp @@ -212,14 +212,14 @@ void A_MCR(ARM* cpu) return A_UNK(cpu); u32 cp = (cpu->CurInstr >> 8) & 0xF; - //u32 op = (cpu->CurInstr >> 21) & 0x7; + u32 op = (cpu->CurInstr >> 21) & 0x7; u32 cn = (cpu->CurInstr >> 16) & 0xF; u32 cm = cpu->CurInstr & 0xF; u32 cpinfo = (cpu->CurInstr >> 5) & 0x7; if (cpu->Num==0 && cp==15) { - ((ARMv5*)cpu)->CP15Write((cn<<8)|(cm<<4)|cpinfo, cpu->R[(cpu->CurInstr>>12)&0xF]); + ((ARMv5*)cpu)->CP15Write((cn<<8)|(cm<<4)|cpinfo|(op<<12), cpu->R[(cpu->CurInstr>>12)&0xF]); } else if (cpu->Num==1 && cp==14) { @@ -227,7 +227,7 @@ void A_MCR(ARM* cpu) } else { - Log(LogLevel::Warn, "bad MCR opcode p%d,%d,%d,%d on ARM%d\n", cp, cn, cm, cpinfo, cpu->Num?7:9); + Log(LogLevel::Warn, "bad MCR opcode p%d, %d, reg, c%d, c%d, %d on ARM%d\n", cp, op, cn, cm, cpinfo, cpu->Num?7:9); return A_UNK(cpu); // TODO: check what kind of exception it really is } @@ -240,14 +240,14 @@ void A_MRC(ARM* cpu) return A_UNK(cpu); u32 cp = (cpu->CurInstr >> 8) & 0xF; - //u32 op = (cpu->CurInstr >> 21) & 0x7; + u32 op = (cpu->CurInstr >> 21) & 0x7; u32 cn = (cpu->CurInstr >> 16) & 0xF; u32 cm = cpu->CurInstr & 0xF; u32 cpinfo = (cpu->CurInstr >> 5) & 0x7; if (cpu->Num==0 && cp==15) { - cpu->R[(cpu->CurInstr>>12)&0xF] = ((ARMv5*)cpu)->CP15Read((cn<<8)|(cm<<4)|cpinfo); + cpu->R[(cpu->CurInstr>>12)&0xF] = ((ARMv5*)cpu)->CP15Read((cn<<8)|(cm<<4)|cpinfo|(op<<12)); } else if (cpu->Num==1 && cp==14) { @@ -255,7 +255,7 @@ void A_MRC(ARM* cpu) } else { - Log(LogLevel::Warn, "bad MRC opcode p%d,%d,%d,%d on ARM%d\n", cp, cn, cm, cpinfo, cpu->Num?7:9); + Log(LogLevel::Warn, "bad MRC opcode p%d, %d, reg, c%d, c%d, %d on ARM%d\n", cp, op, cn, cm, cpinfo, cpu->Num?7:9); return A_UNK(cpu); // TODO: check what kind of exception it really is } diff --git a/src/CP15.cpp b/src/CP15.cpp index caa8de34..f6f11a7a 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -69,6 +69,7 @@ void ARMv5::CP15Reset() ICacheLockDown = 0; DCacheLockDown = 0; CacheDebugRegisterIndex = 0; + CP15BISTTestStateRegister = 0; memset(ICache, 0, ICACHE_SIZE); ICacheInvalidateAll(); @@ -116,6 +117,7 @@ void ARMv5::CP15DoSavestate(Savestate* file) file->Var32(&ICacheLockDown); file->Var32(&CacheDebugRegisterIndex); file->Var32(&CP15TraceProcessId); + file->Var32(&CP15BISTTestStateRegister); file->Var32(&PU_CodeCacheable); file->Var32(&PU_DataCacheable); @@ -384,6 +386,21 @@ u32 ARMv5::ICacheLookup(const u32 addr) } // cache miss + + // We do not fill the cacheline if it is disabled in the + // BIST test State register (See arm946e-s Rev 1 technical manual, 2.3.15 "Register 15, test State Register") + if (CP15BISTTestStateRegister & CP15_BIST_TR_DISABLE_ICACHE_LINEFILL) + { + CodeCycles = NDS.ARM9MemTimings[tag >> 14][2]; + if (CodeMem.Mem) + { + return *(u32*)&CodeMem.Mem[(addr & CodeMem.Mask) & ~3]; + } else + { + return NDS.ARM9Read32(addr & ~3); + } + } + u32 line; #if 0 // caclulate in which cacheline the data is to be filled @@ -507,6 +524,25 @@ u32 ARMv5::DCacheLookup(const u32 addr) } // cache miss + + // We do not fill the cacheline if it is disabled in the + // BIST test State register (See arm946e-s Rev 1 technical manual, 2.3.15 "Register 15, test State Register") + if (CP15BISTTestStateRegister & CP15_BIST_TR_DISABLE_DCACHE_LINEFILL) + { + DataCycles = NDS.ARM9MemTimings[tag >> 14][2]; + if (addr < ITCMSize) + { + return *(u32*)&ITCM[addr & (ITCMPhysicalSize - 3)]; + } else + if ((addr & DTCMMask) == DTCMBase) + { + return *(u32*)&DTCM[addr & (DTCMPhysicalSize - 3)]; + } else + { + return BusRead32(addr & ~3); + } + } + u32 line; #if 0 // caclulate in which cacheline the data is to be filled @@ -694,7 +730,7 @@ void ARMv5::CP15Write(u32 id, u32 val) { //if(id!=0x704)printf("CP15 write op %03X %08X %08X\n", id, val, R[15]); - switch (id) + switch (id & 0xFFF) { case 0x100: { @@ -1112,7 +1148,20 @@ void ARMv5::CP15Write(u32 id, u32 val) else return ARMInterpreter::A_UNK(this); } else - CacheDebugRegisterIndex = val; + { + if (((id >> 12) & 0x0f) == 0x03) + CacheDebugRegisterIndex = val; + else if (((id >> 12) & 0x0f) == 0x00) + CP15BISTTestStateRegister = val; + else + { + if (CPSR & 0x20) // THUMB + return ARMInterpreter::T_UNK(this); + else + return ARMInterpreter::A_UNK(this); + } + + } return; case 0xF10: @@ -1184,14 +1233,14 @@ void ARMv5::CP15Write(u32 id, u32 val) } - Log(LogLevel::Debug, "unknown CP15 write op %03X %08X\n", id, val); + Log(LogLevel::Debug, "unknown CP15 write op %04X %08X\n", id, val); } u32 ARMv5::CP15Read(u32 id) const { //printf("CP15 read op %03X %08X\n", id, NDS::ARM9->R[15]); - switch (id) + switch (id & 0xFFF) { case 0x000: // CPU ID case 0x003: @@ -1304,7 +1353,12 @@ u32 ARMv5::CP15Read(u32 id) const { return 0; } else - return CacheDebugRegisterIndex; + { + if (((id >> 12) & 0x0f) == 0x03) + return CacheDebugRegisterIndex; + if (((id >> 12) & 0x0f) == 0x00) + return CP15BISTTestStateRegister; + } case 0xF10: // instruction cache Tag register if (PU_Map != PU_PrivMap) @@ -1351,7 +1405,7 @@ u32 ARMv5::CP15Read(u32 id) const } } - Log(LogLevel::Debug, "unknown CP15 read op %03X\n", id); + Log(LogLevel::Debug, "unknown CP15 read op %04X\n", id); return 0; } diff --git a/src/CP15_Constants.h b/src/CP15_Constants.h index 80fadf31..0d786afa 100644 --- a/src/CP15_Constants.h +++ b/src/CP15_Constants.h @@ -91,6 +91,10 @@ constexpr u32 CP15_CACHE_CR_ICACHEENABLE = (1 << 12); constexpr u32 CP15_CACHE_CR_DCACHEENABLE = (1 << 2); constexpr u32 CP15_CACHE_CR_WRITEBUFFERENABLE = (1 << 3); +/* CP15 BIST Test State register */ +constexpr u32 CP15_BIST_TR_DISABLE_ICACHE_LINEFILL = (1 << 9); +constexpr u32 CP15_BIST_TR_DISABLE_DCACHE_LINEFILL = (1 << 10); + /* CP15 TCM Control Register */ constexpr u32 CP15_TCM_CR_DTCM_ENABLE = (1 << 16); constexpr u32 CP15_TCM_CR_ITCM_ENABLE = (1 << 18); From c0075404fd32429820cce7f7c0e73b4936a2e13d Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Thu, 1 Feb 2024 13:25:07 +0100 Subject: [PATCH 28/39] Included the I/DCache Streaming disable bits in cache lookup --- src/CP15.cpp | 32 ++++++++++++++++++++++++++++++++ src/CP15_Constants.h | 2 ++ 2 files changed, 34 insertions(+) diff --git a/src/CP15.cpp b/src/CP15.cpp index f6f11a7a..5861f15f 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -381,6 +381,20 @@ u32 ARMv5::ICacheLookup(const u32 addr) { CodeCycles = 1; u32 *cacheLine = (u32 *)&ICache[(id+set) << ICACHE_LINELENGTH_LOG2]; + if (CP15BISTTestStateRegister & CP15_BIST_TR_DISABLE_ICACHE_STREAMING) + { + // Disabled ICACHE Streaming: + // retreive the data from memory, even if the data was cached + // See arm946e-s Rev 1 technical manual, 2.3.15 "Register 15, test State Register") + CodeCycles = NDS.ARM9MemTimings[tag >> 14][2]; + if (CodeMem.Mem) + { + return *(u32*)&CodeMem.Mem[(addr & CodeMem.Mask) & ~3]; + } else + { + return NDS.ARM9Read32(addr & ~3); + } + } return cacheLine[(addr & (ICACHE_LINELENGTH -1)) >> 2]; } } @@ -519,6 +533,24 @@ u32 ARMv5::DCacheLookup(const u32 addr) { DataCycles = 1; u32 *cacheLine = (u32 *)&DCache[(id+set) << DCACHE_LINELENGTH_LOG2]; + if (CP15BISTTestStateRegister & CP15_BIST_TR_DISABLE_DCACHE_STREAMING) + { + // Disabled DCACHE Streaming: + // retreive the data from memory, even if the data was cached + // See arm946e-s Rev 1 technical manual, 2.3.15 "Register 15, test State Register") + DataCycles = NDS.ARM9MemTimings[tag >> 14][2]; + if (addr < ITCMSize) + { + return *(u32*)&ITCM[addr & (ITCMPhysicalSize - 3)]; + } else + if ((addr & DTCMMask) == DTCMBase) + { + return *(u32*)&DTCM[addr & (DTCMPhysicalSize - 3)]; + } else + { + return BusRead32(addr & ~3); + } + } return cacheLine[(addr & (ICACHE_LINELENGTH -1)) >> 2]; } } diff --git a/src/CP15_Constants.h b/src/CP15_Constants.h index 0d786afa..b148372d 100644 --- a/src/CP15_Constants.h +++ b/src/CP15_Constants.h @@ -92,6 +92,8 @@ constexpr u32 CP15_CACHE_CR_DCACHEENABLE = (1 << 2); constexpr u32 CP15_CACHE_CR_WRITEBUFFERENABLE = (1 << 3); /* CP15 BIST Test State register */ +constexpr u32 CP15_BIST_TR_DISABLE_ICACHE_STREAMING = (1 << 11); +constexpr u32 CP15_BIST_TR_DISABLE_DCACHE_STREAMING = (1 << 12); constexpr u32 CP15_BIST_TR_DISABLE_ICACHE_LINEFILL = (1 << 9); constexpr u32 CP15_BIST_TR_DISABLE_DCACHE_LINEFILL = (1 << 10); From 02d6fbacf6d75757ae32fba86e51a3d464487d35 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Fri, 2 Feb 2024 14:43:23 +0100 Subject: [PATCH 29/39] Added several doxygen-style comments for documentation --- src/ARM.h | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 206 insertions(+), 13 deletions(-) diff --git a/src/ARM.h b/src/ARM.h index abb0e686..2f9f4507 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -311,39 +311,232 @@ public: u32 RandomLineIndex(); + /** + * @brief Perform an instruction cache lookup handle + * @details + * A cache lookup is performed, if not disabled in + * @ref CP15BISTTestStateRegister, a hit will returned the + * cached data, otherwise it returns the result of an memory + * access instead. + * If the cache lookup results in a cachemiss and linefill is + * not disabled in @ref CP15BISTTestStateRegister, will fill + * fetch all data to fill the entire cacheline directly + * from the ITCM or bus + * @param [in] addr Address of the memory to be retreived from + * cache. The address is internally aligned to an word boundary + * @return Value of the word at addr + */ u32 ICacheLookup(const u32 addr); + + /** + * @brief Check if an address is within a instruction cachable + * region + * @details + * Checks the address by looking up the PU_map flags for + * the address and returns the status of the instruction + * cache enable flag + * + * @param [in] addr Address. May be unaligned. + * @retval true If the address points to a region, that is + * enabled for instruction fetches to be cached. + */ inline bool IsAddressICachable(const u32 addr) const; + /** + * @brief Invalidates all instruction cache lines + * @details + * Clears the @ref CACHE_FLAG_VALID of each cache line in the + * instruction cache. All other flags and values are kept. + * @par Returns + * Nothing + */ void ICacheInvalidateAll(); + + /** + * @brief Invalidates the instruction cacheline containing + * the data of an address. + * @details + * Searches the cacheline containing the data of an address, and + * if found clears the @ref CACHE_FLAG_VALID of this cache line. + * Nothing is done if the address is not present in the cache. + * @param [in] addr Memory address of the data in the cache line + * @par Returns + * Nothing + */ void ICacheInvalidateByAddr(const u32 addr); + + /** + * @brief Invalidates an instruction cache line + * @details + * Clears the @ref CACHE_FLAG_VALID of the cacheline given by + * set and index within the set. Nothing is done if the cache + * line does not exist. + * @param [in] cacheSet index of the internal cache set from + * 0 to @ref ICACHE_SETS - 1 + * @param [in] cacheLine index of the line within the cache set + * from 0 to @ref ICACHE_LINESPERSET - 1 + * @par Returns + * Nothing + */ void ICacheInvalidateBySetAndWay(const u8 cacheSet, const u8 cacheLine); + /** + * @brief Perform an data cache lookup handle + * @details + * A cache lookup is performed, if not disabled in + * @ref CP15BISTTestStateRegister, a hit will returned the + * cached data, otherwise it returns the result of an memory + * access instead. + * If the cache lookup results in a cachemiss and linefill is + * not disabled in @ref CP15BISTTestStateRegister, will fill + * fetch all data to fill the entire cacheline directly + * from the ITCM, DTCM or bus + * @param [in] addr Address of the memory to be retreived from + * cache. The address is internally aligned to an word boundary + * @return Value of the word at addr + */ u32 DCacheLookup(const u32 addr); + + /** + * @brief Updates a word in the data cache if present + * @param [in] addr Memory address which is written + * @param [in] val Word value to be written + * @par Returns + * Nothing + */ void DCacheWrite32(const u32 addr, const u32 val); + + /** + * @brief Updates a word in the data cache if present + * @param [in] addr Memory address which is written + * @param [in] val Half-Word value to be written + * @par Returns + * Nothing + */ void DCacheWrite16(const u32 addr, const u16 val); + + /** + * @brief Updates a word in the data cache if present + * @param [in] addr Memory address which is written + * @param [in] val Byte value to be written + * @par Returns + * Nothing + */ void DCacheWrite8(const u32 addr, const u8 val); + + /** + * @brief Check if an address is within a data cachable region + * @details + * Checks the address by looking up the PU_map flags for + * the address and returns the status of the data cache enable + * flag + * + * @param [in] addr Address. May be unaligned. + * @retval true If the address points to a region, that is + * enabled for instruction fetches to be cached. + */ inline bool IsAddressDCachable(const u32 addr) const; + /** + * @brief Invalidates the data cacheline containing the data of + * an address. + * @details + * Searches the cacheline containing the data of an address, and + * if found clears the @ref CACHE_FLAG_VALID of this cache line. + * Nothing is done if the address is not present in the cache. + * @par Returns + * Nothing + */ void DCacheInvalidateAll(); + + /** + * @brief Invalidates the data cacheline containing the data of + * an address. + * @details + * Searches the cacheline containing the data of an address, and + * if found clears the @ref CACHE_FLAG_VALID of this cache line. + * Nothing is done if the address is not present in the cache. + * @par Returns + * Nothing + */ void DCacheInvalidateByAddr(const u32 addr); + + /** + * @brief Invalidates an data cache line + * @details + * Clears the @ref CACHE_FLAG_VALID of the cacheline given by + * set and index within the set. Nothing is done if the cache + * line does not exist. + * @param [in] cacheSet index of the internal cache set from + * 0 to @ref DCACHE_SETS - 1 + * @param [in] cacheLine index of the line within the cache set + * from 0 to @ref DCACHE_LINESPERSET - 1 + * @par Returns + * Nothing + */ void DCacheInvalidateBySetAndWay(const u8 cacheSet, const u8 cacheLine); + /** + * @brief Cleans the entire data cache + * @details + * In melonDS, the data cache is instantly cleaned on writes, the + * @ref CACHE_FLAG_DIRTY_LOWERHALF and @ref CACHE_FLAG_DIRTY_UPPERHALF are + * not set. + * If they are implemented at a later time, the cache content has to be + * written to memory, the dirty bit cleared. The call should require + * as much cycles as needed for this write operation. + * @par Returns + * Nothing + */ void DCacheClearAll(); + + /** + * @brief Cleans a data cache line + * @details + * In melonDS, the data cache is instantly cleaned on writes, the + * @ref CACHE_FLAG_DIRTY_LOWERHALF and @ref CACHE_FLAG_DIRTY_UPPERHALF are + * not set. + * If they are implemented at a later time, the cache content has to be + * written to memory, the dirty bit cleared. The call should require + * as much cycles as needed for this write operation. + * @param [in] addr Memory address of the data in the cache line + * @par Returns + * Nothing + */ void DCacheClearByAddr(const u32 addr); + + /** + * @brief Cleans a data cache line + * @details + * In melonDS, the data cache is instantly cleaned on writes, the + * @ref CACHE_FLAG_DIRTY_LOWERHALF and @ref CACHE_FLAG_DIRTY_UPPERHALF are + * not set. + * If they are implemented at a later time, the cache content has to be + * written to memory, the dirty bit cleared. The call should require + * as much cycles as needed for this write operation. + * @param [in] cacheSet index of the internal cache set from + * 0 to @ref DCACHE_SETS - 1 + * @param [in] cacheLine index of the line within the cache set + * from 0 to @ref DCACHE_LINESPERSET - 1 + * @par Returns + * Nothing + */ void DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine); void CP15Write(u32 id, u32 val); u32 CP15Read(u32 id) const; - u32 CP15Control; + u32 CP15Control; //! CP15 Register 1: Control Register - u32 RNGSeed; + u32 RNGSeed; //! Global cache line fill seed. Used for pseudo random replacement strategy with the instruction and data cache - u32 DTCMSetting, ITCMSetting; - u32 DCacheLockDown, ICacheLockDown; - u32 CacheDebugRegisterIndex; - u32 CP15TraceProcessId; - u32 CP15BISTTestStateRegister; + u32 DTCMSetting; + u32 ITCMSetting; + u32 DCacheLockDown; //! CP15: Data Cache Lockdown Register + u32 ICacheLockDown; //! CP15: Instruction Cache Lockdown Register + u32 CacheDebugRegisterIndex; //! CP15: Cache Debug Index Register + u32 CP15TraceProcessId; //! CP15: Trace Process Id Register + u32 CP15BISTTestStateRegister; //! CP15: BIST Test State Register // for aarch64 JIT they need to go up here // to be addressable by a 12-bit immediate @@ -354,13 +547,13 @@ public: u8 ITCM[ITCMPhysicalSize]; u8* DTCM; - u8 ICache[ICACHE_SIZE]; - u32 ICacheTags[ICACHE_LINESPERSET*ICACHE_SETS]; - u8 ICacheCount; + u8 ICache[ICACHE_SIZE]; //! Instruction Cache Content organized in @ref ICACHE_LINESPERSET times @ref ICACHE_SETS times @ref ICACHE_LINELENGTH bytes + u32 ICacheTags[ICACHE_LINESPERSET*ICACHE_SETS]; //! Instruction Cache Tags organized in @ref ICACHE_LINESPERSET times @ref ICACHE_SETS Tags + u8 ICacheCount; //! Global instruction line fill counter. Used for round-robin replacement strategy with the instruction cache - u8 DCache[DCACHE_SIZE]; - u32 DCacheTags[DCACHE_LINESPERSET*DCACHE_SETS]; - u8 DCacheCount; + u8 DCache[DCACHE_SIZE]; //! Data Cache Content organized in @ref DCACHE_LINESPERSET times @ref DCACHE_SETS times @ref DCACHE_LINELENGTH bytes + u32 DCacheTags[DCACHE_LINESPERSET*DCACHE_SETS]; //! Data Cache Tags organized in @ref DCACHE_LINESPERSET times @ref DCACHE_SETS Tags + u8 DCacheCount; //! Global data line fill counter. Used for round-robin replacement strategy with the instruction cache u32 PU_CodeCacheable; u32 PU_DataCacheable; From f9a831e446b377b2a059dfa105904922272f60a6 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Sat, 3 Feb 2024 16:20:40 +0100 Subject: [PATCH 30/39] Removed Thumb Check on CP15 Access restriction as MCR/MRC are not present in thumb --- src/CP15.cpp | 105 +++++++++++---------------------------------------- 1 file changed, 21 insertions(+), 84 deletions(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index 5861f15f..5f84543b 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -928,10 +928,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } ICacheInvalidateByAddr(val); //Halt(255); @@ -940,10 +937,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } else { // Cache invalidat by line number and set number @@ -959,10 +953,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } DCacheInvalidateAll(); //printf("inval data cache %08X\n", val); @@ -971,10 +962,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } DCacheInvalidateByAddr(val); //printf("inval data cache SI\n"); @@ -983,10 +971,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } else { // Cache invalidat by line number and set number @@ -1007,10 +992,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } //Log(LogLevel::Debug,"clean data cache\n"); DCacheClearAll(); @@ -1019,10 +1001,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } //Log(LogLevel::Debug,"clean data cache MVA\n"); DCacheClearByAddr(val); @@ -1032,10 +1011,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } else { // Cache invalidat by line number and set number @@ -1048,10 +1024,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } // Test and clean (optional) // Is not present on the NDS/DSi @@ -1067,10 +1040,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } // we force a fill by looking up the value from cache // if it wasn't cached yet, it will be loaded into cache @@ -1082,10 +1052,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } DCacheClearAll(); DCacheInvalidateAll(); @@ -1095,10 +1062,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } DCacheClearByAddr(val); DCacheInvalidateByAddr(val); @@ -1108,10 +1072,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } else { // Cache invalidat by line number and set number @@ -1126,10 +1087,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } // Cache Lockdown - Format B // Bit 31: Lock bit @@ -1143,10 +1101,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } // Cache Lockdown - Format B // Bit 31: Lock bit @@ -1175,10 +1130,7 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0xF00: if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } else { if (((id >> 12) & 0x0f) == 0x03) @@ -1187,10 +1139,7 @@ void ARMv5::CP15Write(u32 id, u32 val) CP15BISTTestStateRegister = val; else { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } } @@ -1200,10 +1149,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // instruction cache Tag register if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } else { uint8_t segment = (CacheDebugRegisterIndex >> (32-ICACHE_SETS_LOG2)) & (ICACHE_SETS-1); @@ -1216,10 +1162,7 @@ void ARMv5::CP15Write(u32 id, u32 val) // data cache Tag register if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } else { uint8_t segment = (CacheDebugRegisterIndex >> (32-DCACHE_SETS_LOG2)) & (DCACHE_SETS-1); @@ -1233,10 +1176,7 @@ void ARMv5::CP15Write(u32 id, u32 val) //printf("cache debug instruction cache %08X\n", val); if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } else { uint8_t segment = (CacheDebugRegisterIndex >> (32-ICACHE_SETS_LOG2)) & (ICACHE_SETS-1); @@ -1250,10 +1190,7 @@ void ARMv5::CP15Write(u32 id, u32 val) //printf("cache debug data cache %08X\n", val); if (PU_Map != PU_PrivMap) { - if (CPSR & 0x20) // THUMB - return ARMInterpreter::T_UNK(this); - else - return ARMInterpreter::A_UNK(this); + return ARMInterpreter::A_UNK(this); } else { uint8_t segment = (CacheDebugRegisterIndex >> (32-DCACHE_SETS_LOG2)) & (DCACHE_SETS-1); From 2a385b52773a6a19f309f02760731ff2fa50ee18 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Sun, 4 Feb 2024 12:31:57 +0100 Subject: [PATCH 31/39] Cleaned up some more magic numbers Fixed a bug causing overlapping protection regions priority not taken into account, when access permission or cachability bits were changed only on the least priority overlap --- src/ARM.h | 12 +-- src/CP15.cpp | 223 ++++++++++++++++++++++++++++++------------- src/CP15_Constants.h | 34 ++++--- 3 files changed, 184 insertions(+), 85 deletions(-) diff --git a/src/ARM.h b/src/ARM.h index 2f9f4507..61a087fd 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -555,14 +555,14 @@ public: u32 DCacheTags[DCACHE_LINESPERSET*DCACHE_SETS]; //! Data Cache Tags organized in @ref DCACHE_LINESPERSET times @ref DCACHE_SETS Tags u8 DCacheCount; //! Global data line fill counter. Used for round-robin replacement strategy with the instruction cache - u32 PU_CodeCacheable; - u32 PU_DataCacheable; - u32 PU_DataCacheWrite; + u32 PU_CodeCacheable; //! CP15 Register 2 Opcode 1: Code Cachable Bits + u32 PU_DataCacheable; //! CP15 Register 2 Opcode 0: Data Cachable Bits + u32 PU_DataCacheWrite; //! CP15 Register 3 Opcode 0: WriteBuffer Control Register - u32 PU_CodeRW; - u32 PU_DataRW; + u32 PU_CodeRW; //! CP15 Register 5 Opcode 3: Code Access Permission register + u32 PU_DataRW; //! CP15 Register 5 Opcode 2: Data Access Permission register - u32 PU_Region[8]; + u32 PU_Region[8]; //! CP15 Register 6 Opcode 0..7: Protection Region Base and Size Register // 0=dataR 1=dataW 2=codeR 4=datacache 5=datawrite 6=codecache u8 PU_PrivMap[0x100000]; diff --git a/src/CP15.cpp b/src/CP15.cpp index 5f84543b..fa0a426d 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -512,6 +512,7 @@ void ARMv5::ICacheInvalidateBySetAndWay(const u8 cacheSet, const u8 cacheLine) void ARMv5::ICacheInvalidateAll() { + #pragma GCC ivdep for (int i = 0; i < ICACHE_SIZE / ICACHE_LINELENGTH; i++) ICacheTags[i] &= ~CACHE_FLAG_VALID; ; } @@ -731,6 +732,7 @@ void ARMv5::DCacheInvalidateBySetAndWay(const u8 cacheSet, const u8 cacheLine) void ARMv5::DCacheInvalidateAll() { + #pragma GCC ivdep for (int i = 0; i < DCACHE_SIZE / DCACHE_LINELENGTH; i++) DCacheTags[i] &= ~CACHE_FLAG_VALID; ; } @@ -767,13 +769,11 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0x100: { u32 old = CP15Control; - val &= 0x000FF085; - CP15Control &= ~0x000FF085; - CP15Control |= val; + CP15Control = (CP15Control & ~CP15_CR_CHANGEABLE_MASK) | (val & CP15_CR_CHANGEABLE_MASK); //Log(LogLevel::Debug, "CP15Control = %08X (%08X->%08X)\n", CP15Control, old, val); UpdateDTCMSetting(); UpdateITCMSetting(); - u32 changedBits = old^val; + u32 changedBits = old ^ CP15Control; if (changedBits & (CP15_CR_MPUENABLE | CP15_CACHE_CR_ICACHEENABLE| CP15_CACHE_CR_DCACHEENABLE)) { UpdatePURegions(changedBits & CP15_CR_MPUENABLE); @@ -789,10 +789,25 @@ void ARMv5::CP15Write(u32 id, u32 val) { u32 diff = PU_DataCacheable ^ val; PU_DataCacheable = val; - for (u32 i = 0; i < CP15_REGION_COUNT; i++) - { - if (diff & (1<> (i * 2) & 3) << (i * CP15_REGIONACCESS_BITS_PER_REGION); + + #if 0 + // This code just updates the PU_Map entries of the given region + // this works fine, if the regions do not overlap + // If overlapping and the least priority region access permission + // would change, this results in wrong map entries. On HW the changed + // access permissions would not be applied because of a higher priority + // region overwriting them. + // + // Writing to the data permission bits is sparse, so we + // should just take the long but correct update via all regions + // so the permission priority is correct + + u32 diff = old ^ PU_DataRW; + for (u32 i = 0; i < CP15_REGION_COUNT; i++) + { + if (diff & (CP15_REGIONACCESS_REGIONMASK<<(i*CP15_REGIONACCESS_BITS_PER_REGION))) UpdatePURegion(i); + } + #else + UpdatePURegions(true); + #endif } return; @@ -844,19 +901,30 @@ void ARMv5::CP15Write(u32 id, u32 val) { u32 old = PU_CodeRW; PU_CodeRW = 0; - PU_CodeRW |= (val & 0x0003); - PU_CodeRW |= ((val & 0x000C) << 2); - PU_CodeRW |= ((val & 0x0030) << 4); - PU_CodeRW |= ((val & 0x00C0) << 6); - PU_CodeRW |= ((val & 0x0300) << 8); - PU_CodeRW |= ((val & 0x0C00) << 10); - PU_CodeRW |= ((val & 0x3000) << 12); - PU_CodeRW |= ((val & 0xC000) << 14); - u32 diff = old ^ PU_CodeRW; - for (u32 i = 0; i < CP15_REGION_COUNT; i++) - { - if (diff & (CP15_REGIONACCESS_REGIONMASK<<(i*CP15_REGIONACCESS_BITS_PER_REGION))) UpdatePURegion(i); - } + #pragma GCC ivdep + #pragma GCC unroll 8 + for (int i=0;i> (i * 2) & 3) << (i * CP15_REGIONACCESS_BITS_PER_REGION); + + #if 0 + // This code just updates the PU_Map entries of the given region + // this works fine, if the regions do not overlap + // If overlapping and the least priority region access permission + // would change, this results in wrong map entries, because it + // would on HW be overridden by the higher priority region + // + // Writing to the data permission bits is sparse, so we + // should just take the long but correct update via all regions + // so the permission priority is correct + + u32 diff = old ^ PU_CodeRW; + for (u32 i = 0; i < CP15_REGION_COUNT; i++) + { + if (diff & (CP15_REGIONACCESS_REGIONMASK<<(i*CP15_REGIONACCESS_BITS_PER_REGION))) UpdatePURegion(i); + } + #else + UpdatePURegions(true); + #endif } return; @@ -864,10 +932,23 @@ void ARMv5::CP15Write(u32 id, u32 val) { u32 diff = PU_DataRW ^ val; PU_DataRW = val; - for (u32 i = 0; i < CP15_REGION_COUNT; i++) - { - if (diff & (CP15_REGIONACCESS_REGIONMASK<<(i*CP15_REGIONACCESS_BITS_PER_REGION))) UpdatePURegion(i); - } + #if 0 + // This code just updates the PU_Map entries of the given region + // this works fine, if the regions do not overlap + // If overlapping and the least priority region access permission + // would change, this results in wrong map entries, because it + // would on HW be overridden by the higher priority region + // + // Writing to the data permission bits is sparse, so we + // should just take the long but correct update via all regions + // so the permission priority is correct + for (u32 i = 0; i < CP15_REGION_COUNT; i++) + { + if (diff & (CP15_REGIONACCESS_REGIONMASK<<(i*CP15_REGIONACCESS_BITS_PER_REGION))) UpdatePURegion(i); + } + #else + UpdatePURegions(true); + #endif } return; @@ -875,10 +956,23 @@ void ARMv5::CP15Write(u32 id, u32 val) { u32 diff = PU_CodeRW ^ val; PU_CodeRW = val; - for (u32 i = 0; i < CP15_REGION_COUNT; i++) - { - if (diff & (CP15_REGIONACCESS_REGIONMASK<<(i*CP15_REGIONACCESS_BITS_PER_REGION))) UpdatePURegion(i); - } + #if 0 + // This code just updates the PU_Map entries of the given region + // this works fine, if the regions do not overlap + // If overlapping and the least priority region access permission + // would change, this results in wrong map entries, because it + // would on HW be overridden by the higher priority region + // + // Writing to the data permission bits is sparse, so we + // should just take the long but correct update via all regions + // so the permission priority is correct + for (u32 i = 0; i < CP15_REGION_COUNT; i++) + { + if (diff & (CP15_REGIONACCESS_REGIONMASK<<(i*CP15_REGIONACCESS_BITS_PER_REGION))) UpdatePURegion(i); + } + #else + UpdatePURegions(true); + #endif } return; @@ -1242,28 +1336,25 @@ u32 ARMv5::CP15Read(u32 id) const case 0x500: { + // this format has 2 bits per region, but we store 4 per region + // so we reduce and consoldate the bits + // 0x502 returns all 4 bits per region u32 ret = 0; - ret |= (PU_DataRW & 0x00000003); - ret |= ((PU_DataRW & 0x00000030) >> 2); - ret |= ((PU_DataRW & 0x00000300) >> 4); - ret |= ((PU_DataRW & 0x00003000) >> 6); - ret |= ((PU_DataRW & 0x00030000) >> 8); - ret |= ((PU_DataRW & 0x00300000) >> 10); - ret |= ((PU_DataRW & 0x03000000) >> 12); - ret |= ((PU_DataRW & 0x30000000) >> 14); + #pragma GCC ivdep + #pragma GCC unroll 8 + for (int i=0;i> (i * CP15_REGIONACCESS_BITS_PER_REGION) & CP15_REGIONACCESS_REGIONMASK) << (i*2); return ret; } case 0x501: { + // this format has 2 bits per region, but we store 4 per region + // so we reduce and consoldate the bits + // 0x503 returns all 4 bits per region u32 ret = 0; - ret |= (PU_CodeRW & 0x00000003); - ret |= ((PU_CodeRW & 0x00000030) >> 2); - ret |= ((PU_CodeRW & 0x00000300) >> 4); - ret |= ((PU_CodeRW & 0x00003000) >> 6); - ret |= ((PU_CodeRW & 0x00030000) >> 8); - ret |= ((PU_CodeRW & 0x00300000) >> 10); - ret |= ((PU_CodeRW & 0x03000000) >> 12); - ret |= ((PU_CodeRW & 0x30000000) >> 14); + #pragma GCC unroll 8 + for (int i=0;i> (i * CP15_REGIONACCESS_BITS_PER_REGION) & CP15_REGIONACCESS_REGIONMASK) << (i*2); return ret; } case 0x502: diff --git a/src/CP15_Constants.h b/src/CP15_Constants.h index b148372d..98ddf84d 100644 --- a/src/CP15_Constants.h +++ b/src/CP15_Constants.h @@ -76,31 +76,39 @@ constexpr u32 CP15_MAINID_IMPLEMENTATION_946 = (0x946 << 4); constexpr u32 CP15_MAINID_REVISION_0 = (0 << 0); constexpr u32 CP15_MAINID_REVISION_1 = (1 << 0); -/* CP15 Control Register */ -constexpr u32 CP15_CR_MPUENABLE = (1 << 0); -constexpr u32 CP15_CR_BIGENDIAN = (1 << 7); -constexpr u32 CP15_CR_HIGHEXCEPTIONBASE = (1 << 13); - -/* CP15 Internal Exception base value */ -constexpr u32 CP15_EXCEPTIONBASE_HIGH = 0xFFFF0000; -constexpr u32 CP15_EXCEPTIONBASE_LOW = 0x00000000; - /* CP15 Cache and Write Buffer Conrol Register */ constexpr u32 CP15_CACHE_CR_ROUNDROBIN = (1 << 14); constexpr u32 CP15_CACHE_CR_ICACHEENABLE = (1 << 12); constexpr u32 CP15_CACHE_CR_DCACHEENABLE = (1 << 2); constexpr u32 CP15_CACHE_CR_WRITEBUFFERENABLE = (1 << 3); +/* CP15 TCM Control Register */ +constexpr u32 CP15_TCM_CR_DTCM_ENABLE = (1 << 16); +constexpr u32 CP15_TCM_CR_ITCM_ENABLE = (1 << 18); +constexpr u32 CP15_TCM_CR_DTCM_LOADMODE = (1 << 17); +constexpr u32 CP15_TCM_CR_ITCM_LOADMODE = (1 << 19); + +/* CP15 Control Register */ +constexpr u32 CP15_CR_MPUENABLE = (1 << 0); +constexpr u32 CP15_CR_BIGENDIAN = (1 << 7); +constexpr u32 CP15_CR_HIGHEXCEPTIONBASE = (1 << 13); +constexpr u32 CP15_CR_DISABLE_THUMBBIT = (1 << 15); +constexpr u32 CP15_CR_CHANGEABLE_MASK = CP15_CR_MPUENABLE | CP15_CR_BIGENDIAN | CP15_CACHE_CR_DCACHEENABLE + | CP15_CACHE_CR_ICACHEENABLE | CP15_CR_HIGHEXCEPTIONBASE + | CP15_TCM_CR_DTCM_ENABLE | CP15_TCM_CR_ITCM_ENABLE + | CP15_TCM_CR_DTCM_LOADMODE | CP15_TCM_CR_ITCM_LOADMODE + | CP15_CACHE_CR_ROUNDROBIN | CP15_CR_DISABLE_THUMBBIT; + +/* CP15 Internal Exception base value */ +constexpr u32 CP15_EXCEPTIONBASE_HIGH = 0xFFFF0000; +constexpr u32 CP15_EXCEPTIONBASE_LOW = 0x00000000; + /* CP15 BIST Test State register */ constexpr u32 CP15_BIST_TR_DISABLE_ICACHE_STREAMING = (1 << 11); constexpr u32 CP15_BIST_TR_DISABLE_DCACHE_STREAMING = (1 << 12); constexpr u32 CP15_BIST_TR_DISABLE_ICACHE_LINEFILL = (1 << 9); constexpr u32 CP15_BIST_TR_DISABLE_DCACHE_LINEFILL = (1 << 10); -/* CP15 TCM Control Register */ -constexpr u32 CP15_TCM_CR_DTCM_ENABLE = (1 << 16); -constexpr u32 CP15_TCM_CR_ITCM_ENABLE = (1 << 18); - /* CP15 Region Base and Size Register */ constexpr u32 CP15_REGION_COUNT = 8; constexpr u32 CP15_REGION_ENABLE = (1 << 0); From b1637e25a46fb77d75f061332cd35fb7fd0387e5 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Sun, 4 Feb 2024 12:48:06 +0100 Subject: [PATCH 32/39] Added more function documenting comments Added const properties to the CP15Write/Read functions --- src/ARM.h | 32 ++++++++++++++++++++++++++++++-- src/CP15.cpp | 4 ++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/ARM.h b/src/ARM.h index 61a087fd..3207628e 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -523,8 +523,36 @@ public: */ void DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine); - void CP15Write(u32 id, u32 val); - u32 CP15Read(u32 id) const; + /** + * @brief Handles MCR operations writing to cp15 registers + * @details + * This function updates the internal state of the emulator when + * a cp15 register is written, or triggers the corresponding action + * like flushing caches. + * + * @param [in] id the operation id to be performed, consisting of + * (from lower to higher nibble) opcode2, intermediate register, + * register and opcode1. Most write operations just take the first 3 + * into account. + * param [in] val value to be written to the cp15 register + * @par Returns + * Nothing + */ + void CP15Write(const u32 id, const u32 val); + + /** + * @brief handles MRC operations reading from cp15 registers + * @details + * This function accumulates the regsiter states from the internal + * emulator state. It does not modify the internal state of the + * emulator or cp15. + * @param [in] id the operation id to be performed, consisting of + * (from lower to higher nibble) opcode2, intermediate register, + * register and opcode1. Most read operations just take the first 3 + * into account. + * @return Value of the cp15 register + */ + u32 CP15Read(const u32 id) const; u32 CP15Control; //! CP15 Register 1: Control Register diff --git a/src/CP15.cpp b/src/CP15.cpp index fa0a426d..78cb8992 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -760,7 +760,7 @@ bool ARMv5::IsAddressDCachable(const u32 addr) const return PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEABLE ; } -void ARMv5::CP15Write(u32 id, u32 val) +void ARMv5::CP15Write(const u32 id, const u32 val) { //if(id!=0x704)printf("CP15 write op %03X %08X %08X\n", id, val, R[15]); @@ -1299,7 +1299,7 @@ void ARMv5::CP15Write(u32 id, u32 val) Log(LogLevel::Debug, "unknown CP15 write op %04X %08X\n", id, val); } -u32 ARMv5::CP15Read(u32 id) const +u32 ARMv5::CP15Read(const u32 id) const { //printf("CP15 read op %03X %08X\n", id, NDS::ARM9->R[15]); From d5a351aefec6a013f8f235b8aa45849a42f14e55 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Sun, 4 Feb 2024 13:56:03 +0100 Subject: [PATCH 33/39] Added more documenting comments --- src/ARM.h | 60 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/src/ARM.h b/src/ARM.h index 3207628e..2e900851 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -303,7 +303,18 @@ public: void CP15Reset(); void CP15DoSavestate(Savestate* file); + /** + * @brief Caclulates the internal state from @ref DTCMSettings + * @par Returns + * Nothing + */ void UpdateDTCMSetting(); + + /** + * @brief Caclulates the internal state from @ref ITCMSettings + * @par Returns + * Nothing + */ void UpdateITCMSetting(); void UpdatePURegion(u32 n); @@ -558,22 +569,23 @@ public: u32 RNGSeed; //! Global cache line fill seed. Used for pseudo random replacement strategy with the instruction and data cache - u32 DTCMSetting; - u32 ITCMSetting; - u32 DCacheLockDown; //! CP15: Data Cache Lockdown Register - u32 ICacheLockDown; //! CP15: Instruction Cache Lockdown Register + u32 DTCMSetting; //! CP15 Register 9 Intermediate 1 Opcode2 0: Data Tightly-Coupled Memory register + u32 ITCMSetting; //! CP15 Register 9 Intermediate 1 Opcode2 1: Instruction Tightly-Coupled Memory register + u32 DCacheLockDown; //! CP15 Register 9 Intermediate 0 Opcode2 0: Data Cache Lockdown Register + u32 ICacheLockDown; //! CP15 Register 9 Intermediate 0 Opcode2 1: Instruction Cache Lockdown Register u32 CacheDebugRegisterIndex; //! CP15: Cache Debug Index Register u32 CP15TraceProcessId; //! CP15: Trace Process Id Register u32 CP15BISTTestStateRegister; //! CP15: BIST Test State Register // for aarch64 JIT they need to go up here // to be addressable by a 12-bit immediate - u32 ITCMSize; - u32 DTCMBase, DTCMMask; - s32 RegionCodeCycles; + u32 ITCMSize; //! Internal: Size of the memory ITCM is mapped to. @ref ITCM data repeats every @ref ITCMPhysicalSize withhin + u32 DTCMBase; //! Internal: DTCMBase Address. The DTCM can be accessed if the address & ~ @ref DTCMMask is equal to thhis base address + u32 DTCMMask; //! Internal: DTCM Address Mask used in conjunction with @ref DTCMBase to check for DTCM access + s32 RegionCodeCycles; //! Internal: Cached amount of cycles to fetch instruction from the current code region. - u8 ITCM[ITCMPhysicalSize]; - u8* DTCM; + u8 ITCM[ITCMPhysicalSize]; //! Content of the ITCM + u8* DTCM; //! Content of the DTCM u8 ICache[ICACHE_SIZE]; //! Instruction Cache Content organized in @ref ICACHE_LINESPERSET times @ref ICACHE_SETS times @ref ICACHE_LINELENGTH bytes u32 ICacheTags[ICACHE_LINESPERSET*ICACHE_SETS]; //! Instruction Cache Tags organized in @ref ICACHE_LINESPERSET times @ref ICACHE_SETS Tags @@ -583,22 +595,28 @@ public: u32 DCacheTags[DCACHE_LINESPERSET*DCACHE_SETS]; //! Data Cache Tags organized in @ref DCACHE_LINESPERSET times @ref DCACHE_SETS Tags u8 DCacheCount; //! Global data line fill counter. Used for round-robin replacement strategy with the instruction cache - u32 PU_CodeCacheable; //! CP15 Register 2 Opcode 1: Code Cachable Bits - u32 PU_DataCacheable; //! CP15 Register 2 Opcode 0: Data Cachable Bits - u32 PU_DataCacheWrite; //! CP15 Register 3 Opcode 0: WriteBuffer Control Register + u32 PU_CodeCacheable; //! CP15 Register 2 Opcode2 1: Code Cachable Bits + u32 PU_DataCacheable; //! CP15 Register 2 Opcode2 0: Data Cachable Bits + u32 PU_DataCacheWrite; //! CP15 Register 3 Opcode2 0: WriteBuffer Control Register - u32 PU_CodeRW; //! CP15 Register 5 Opcode 3: Code Access Permission register - u32 PU_DataRW; //! CP15 Register 5 Opcode 2: Data Access Permission register + u32 PU_CodeRW; //! CP15 Register 5 Opcode2 3: Code Access Permission register + u32 PU_DataRW; //! CP15 Register 5 Opcode2 2: Data Access Permission register - u32 PU_Region[8]; //! CP15 Register 6 Opcode 0..7: Protection Region Base and Size Register + u32 PU_Region[8]; //! CP15 Register 6 Opcode2 0..7: Protection Region Base and Size Register // 0=dataR 1=dataW 2=codeR 4=datacache 5=datawrite 6=codecache - u8 PU_PrivMap[0x100000]; - u8 PU_UserMap[0x100000]; - - // games operate under system mode, generally - //#define PU_Map PU_PrivMap - u8* PU_Map; + u8 PU_PrivMap[0x100000]; /** + * Memory mapping flags for Privileged Modes + * Bits: + * 0 - CP15_MAP_READABLE + * 1 - CP15_MAP_WRITEABLE + * 2 - CP15_MAP_EXECUTABLE + * 4 - CP15_MAP_DCACHEABLE + * 5 - CP15_MAP_DCACHEWRITEBACK + * 6 - CP15_MAP_ICACHEABLE + */ + u8 PU_UserMap[0x100000]; //! Memory mapping flags for User Mode + u8* PU_Map; //! Current valid Region Mapping (is either @ref PU_PrivMap or PU_UserMap) // code/16N/32N/32S u8 MemTimings[0x100000][4]; From 4b20c1bc0f3d333dae0c19cd3c2335c552f96d66 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Mon, 5 Feb 2024 12:30:39 +0100 Subject: [PATCH 34/39] Added more documenting comments Replaced mogic values with named constants Added const specifier to some argument and subsequent calls --- src/ARM.h | 55 ++++++++++++++++++++----- src/CP15.cpp | 96 +++++++++++++++++++++----------------------- src/CP15_Constants.h | 25 +++++++++++- src/DSi.cpp | 2 +- src/DSi.h | 2 +- src/NDS.cpp | 2 +- src/NDS.h | 2 +- 7 files changed, 119 insertions(+), 65 deletions(-) diff --git a/src/ARM.h b/src/ARM.h index 2e900851..6b32983d 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -298,27 +298,64 @@ public: // Cycles += numC + numD; } - void GetCodeMemRegion(u32 addr, MemRegion* region); + void GetCodeMemRegion(const u32 addr, MemRegion* region); + /** + * @brief Resets the state of all CP15 registers and variables + * to power up state. + * @par Returns + * Nothing + */ void CP15Reset(); + + /** + * @brief handles read and write operations to a save-state + * file. + * @param [in] file Savestate file + * @par Returns + * Nothing + */ void CP15DoSavestate(Savestate* file); /** - * @brief Caclulates the internal state from @ref DTCMSettings + * @brief Calculates the internal state from @ref DTCMSettings * @par Returns * Nothing */ void UpdateDTCMSetting(); /** - * @brief Caclulates the internal state from @ref ITCMSettings + * @brief Calculates the internal state from @ref ITCMSettings * @par Returns * Nothing */ void UpdateITCMSetting(); - void UpdatePURegion(u32 n); - void UpdatePURegions(bool update_all); + /** + * @brief Calculates the internal state from the + * region protection bits of a specific region number + * @details + * This function updates the PU_####Map array in all + * parts that are occupied by this region. Updating a single + * region does not take into account the priority of the + * regions. + * @param [in] n index of the region from 0 to @ref CP15_REGION_COUNT - 1 + * @par Returns + * Nothing + */ + void UpdatePURegion(const u32 n); + + /** + * @brief Calculates the internal state from all region + * protection bits. + * @details + * This function updates the internal state in order from the + * least to the most priotized regions, so that the + * priority of the regions match the internal state + * @par Returns + * Nothing + */ + void UpdatePURegions(const bool update_all); u32 RandomLineIndex(); @@ -602,10 +639,10 @@ public: u32 PU_CodeRW; //! CP15 Register 5 Opcode2 3: Code Access Permission register u32 PU_DataRW; //! CP15 Register 5 Opcode2 2: Data Access Permission register - u32 PU_Region[8]; //! CP15 Register 6 Opcode2 0..7: Protection Region Base and Size Register + u32 PU_Region[CP15_REGION_COUNT]; //! CP15 Register 6 Opcode2 0..7: Protection Region Base and Size Register // 0=dataR 1=dataW 2=codeR 4=datacache 5=datawrite 6=codecache - u8 PU_PrivMap[0x100000]; /** + u8 PU_PrivMap[CP15_MAP_ENTRYCOUNT]; /** * Memory mapping flags for Privileged Modes * Bits: * 0 - CP15_MAP_READABLE @@ -615,11 +652,11 @@ public: * 5 - CP15_MAP_DCACHEWRITEBACK * 6 - CP15_MAP_ICACHEABLE */ - u8 PU_UserMap[0x100000]; //! Memory mapping flags for User Mode + u8 PU_UserMap[CP15_MAP_ENTRYCOUNT]; //! Memory mapping flags for User Mode u8* PU_Map; //! Current valid Region Mapping (is either @ref PU_PrivMap or PU_UserMap) // code/16N/32N/32S - u8 MemTimings[0x100000][4]; + u8 MemTimings[CP15_MAP_ENTRYCOUNT][4]; bool (*GetMemRegion)(u32 addr, bool write, MemRegion* region); diff --git a/src/CP15.cpp b/src/CP15.cpp index 78cb8992..576f9f8d 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -40,36 +40,32 @@ const int kDataCacheTiming = 3;//2; const int kCodeCacheTiming = 3;//5; -/* CP15 Reset sets the default values within each registers and - memories of the CP15. - This includes the Settings for - DTCM - ITCM - Caches - Regions - Process Trace -*/ - void ARMv5::CP15Reset() { CP15Control = 0x2078; // dunno RNGSeed = 44203; + // Memory Regions Protection + PU_CodeRW = 0; + PU_DataRW = 0; + + memset(PU_Region, 0, CP15_REGION_COUNT*sizeof(*PU_Region)); + + // TCM-Settings DTCMSetting = 0; ITCMSetting = 0; memset(ITCM, 0, ITCMPhysicalSize); memset(DTCM, 0, DTCMPhysicalSize); - ITCMSize = 0; - DTCMBase = 0xFFFFFFFF; - DTCMMask = 0; + // Cache Settings + PU_CodeCacheable = 0; + PU_DataCacheable = 0; + PU_DataCacheWrite = 0; ICacheLockDown = 0; DCacheLockDown = 0; - CacheDebugRegisterIndex = 0; - CP15BISTTestStateRegister = 0; memset(ICache, 0, ICACHE_SIZE); ICacheInvalidateAll(); @@ -79,18 +75,15 @@ void ARMv5::CP15Reset() DCacheInvalidateAll(); DCacheCount = 0; + // Debug / Misc Registers + CacheDebugRegisterIndex = 0; + CP15BISTTestStateRegister = 0; CP15TraceProcessId = 0; - PU_CodeCacheable = 0; - PU_DataCacheable = 0; - PU_DataCacheWrite = 0; - - PU_CodeRW = 0; - PU_DataRW = 0; - - memset(PU_Region, 0, CP15_REGION_COUNT*sizeof(u32)); + // And now Update the internal state + UpdateDTCMSetting(); + UpdateITCMSetting(); UpdatePURegions(true); - } void ARMv5::CP15DoSavestate(Savestate* file) @@ -145,13 +138,16 @@ void ARMv5::UpdateDTCMSetting() if (CP15Control & CP15_TCM_CR_DTCM_ENABLE) { - newDTCMSize = 0x200 << ((DTCMSetting >> 1) & 0x1F); - if (newDTCMSize < 0x1000) newDTCMSize = 0x1000; - newDTCMMask = 0xFFFFF000 & ~(newDTCMSize-1); + newDTCMSize = CP15_DTCM_SIZE_BASE << ((DTCMSetting & CP15_DTCM_SIZE_MASK) >> CP15_DTCM_SIZE_POS); + if (newDTCMSize < (CP15_DTCM_SIZE_BASE << CP15_DTCM_SIZE_MIN)) + newDTCMSize = CP15_DTCM_SIZE_BASE << CP15_DTCM_SIZE_MIN; + + newDTCMMask = CP15_DTCM_BASE_MASK & ~(newDTCMSize-1); newDTCMBase = DTCMSetting & newDTCMMask; } else { + // DTCM Disabled newDTCMSize = 0; newDTCMBase = 0xFFFFFFFF; newDTCMMask = 0; @@ -169,7 +165,7 @@ void ARMv5::UpdateITCMSetting() { if (CP15Control & CP15_TCM_CR_ITCM_ENABLE) { - ITCMSize = 0x200 << ((ITCMSetting >> 1) & 0x1F); + ITCMSize = CP15_ITCM_SIZE_BASE << ((ITCMSetting & CP15_ITCM_SIZE_MASK) >> CP15_ITCM_SIZE_POS); #ifdef JIT_ENABLED FastBlockLookupSize = 0; #endif @@ -183,7 +179,7 @@ void ARMv5::UpdateITCMSetting() // covers updates to a specific PU region's cache/etc settings // (not to the region range/enabled status) -void ARMv5::UpdatePURegion(u32 n) +void ARMv5::UpdatePURegion(const u32 n) { if (!(CP15Control & CP15_CR_MPUENABLE)) return; @@ -194,7 +190,7 @@ void ARMv5::UpdatePURegion(u32 n) u32 coderw = (PU_CodeRW >> (CP15_REGIONACCESS_BITS_PER_REGION * n)) & CP15_REGIONACCESS_REGIONMASK; u32 datarw = (PU_DataRW >> (CP15_REGIONACCESS_BITS_PER_REGION * n)) & CP15_REGIONACCESS_REGIONMASK; - u32 codecache, datacache, datawrite; + bool codecache, datacache, datawrite; // datacache/datawrite // 0/0: goes to memory @@ -205,7 +201,7 @@ void ARMv5::UpdatePURegion(u32 n) if (CP15Control & CP15_CACHE_CR_ICACHEENABLE) codecache = (PU_CodeCacheable >> n) & 0x1; else - codecache = 0; + codecache = false; if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { @@ -214,12 +210,12 @@ void ARMv5::UpdatePURegion(u32 n) } else { - datacache = 0; - datawrite = 0; + datacache = false; + datawrite = false; } u32 rgn = PU_Region[n]; - if (!(rgn & (1<<0))) + if (!(rgn & CP15_REGION_ENABLE)) { return; } @@ -240,7 +236,7 @@ void ARMv5::UpdatePURegion(u32 n) case 3: privmask |= CP15_MAP_READABLE | CP15_MAP_WRITEABLE; usermask |= CP15_MAP_READABLE | CP15_MAP_WRITEABLE; break; case 5: privmask |= CP15_MAP_READABLE; break; case 6: privmask |= CP15_MAP_READABLE; usermask |= CP15_MAP_READABLE; break; - default: Log(LogLevel::Warn, "!! BAD DATARW VALUE %d\n", datarw&0xF); + default: Log(LogLevel::Warn, "!! BAD DATARW VALUE %d\n", datarw & ((1 << CP15_REGIONACCESS_BITS_PER_REGION)-1)); } switch (coderw) @@ -251,22 +247,22 @@ void ARMv5::UpdatePURegion(u32 n) case 3: privmask |= CP15_MAP_EXECUTABLE; usermask |= CP15_MAP_EXECUTABLE; break; case 5: privmask |= CP15_MAP_EXECUTABLE; break; case 6: privmask |= CP15_MAP_EXECUTABLE; usermask |= CP15_MAP_EXECUTABLE; break; - default: Log(LogLevel::Warn, "!! BAD CODERW VALUE %d\n", datarw&0xF); + default: Log(LogLevel::Warn, "!! BAD CODERW VALUE %d\n", datarw & ((1 << CP15_REGIONACCESS_BITS_PER_REGION)-1)); } - if (datacache & 0x1) + if (datacache) { privmask |= CP15_MAP_DCACHEABLE; usermask |= CP15_MAP_DCACHEABLE; - if (datawrite & 0x1) + if (datawrite) { privmask |= CP15_MAP_DCACHEWRITEBACK; usermask |= CP15_MAP_DCACHEWRITEBACK; } } - if (codecache & 0x1) + if (codecache) { privmask |= CP15_MAP_ICACHEABLE; usermask |= CP15_MAP_ICACHEABLE; @@ -293,7 +289,7 @@ void ARMv5::UpdatePURegion(u32 n) UpdateRegionTimings(start, end); } -void ARMv5::UpdatePURegions(bool update_all) +void ARMv5::UpdatePURegions(const bool update_all) { if (!(CP15Control & CP15_CR_MPUENABLE)) { @@ -303,17 +299,17 @@ void ARMv5::UpdatePURegions(bool update_all) if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) mask |= CP15_MAP_DCACHEABLE | CP15_MAP_DCACHEWRITEBACK ; if (CP15Control & CP15_CACHE_CR_ICACHEENABLE) mask |= CP15_MAP_ICACHEABLE; - memset(PU_UserMap, mask, 0x100000); - memset(PU_PrivMap, mask, 0x100000); + memset(PU_UserMap, mask, CP15_MAP_ENTRYCOUNT); + memset(PU_PrivMap, mask, CP15_MAP_ENTRYCOUNT); - UpdateRegionTimings(0x00000, 0x100000); + UpdateRegionTimings(0x00000, CP15_MAP_ENTRYCOUNT); return; } if (update_all) { - memset(PU_UserMap, CP15_MAP_NOACCESS, 0x100000); - memset(PU_PrivMap, CP15_MAP_NOACCESS, 0x100000); + memset(PU_UserMap, CP15_MAP_NOACCESS, CP15_MAP_ENTRYCOUNT); + memset(PU_PrivMap, CP15_MAP_NOACCESS, CP15_MAP_ENTRYCOUNT); } for (int n = 0; n < CP15_REGION_COUNT; n++) @@ -323,7 +319,7 @@ void ARMv5::UpdatePURegions(bool update_all) // TODO: this is way unoptimized // should be okay unless the game keeps changing shit, tho - if (update_all) UpdateRegionTimings(0x00000, 0x100000); + if (update_all) UpdateRegionTimings(0x00000, CP15_MAP_ENTRYCOUNT); // TODO: throw exception if the region we're running in has become non-executable, I guess } @@ -1207,12 +1203,12 @@ void ARMv5::CP15Write(const u32 id, const u32 val) return; case 0x910: - DTCMSetting = val & 0xFFFFF03E; + DTCMSetting = val & (CP15_DTCM_BASE_MASK | CP15_DTCM_SIZE_MASK); UpdateDTCMSetting(); return; case 0x911: - ITCMSetting = val & 0x0000003E; + ITCMSetting = val & (CP15_ITCM_BASE_MASK | CP15_ITCM_SIZE_MASK); UpdateITCMSetting(); return; @@ -1319,7 +1315,7 @@ u32 ARMv5::CP15Read(const u32 id) const | (ICACHE_LINELENGTH_ENCODED << 0) | (ICACHE_SETS_LOG2 << 3) | ((ICACHE_SIZE_LOG2 - 9) << 6); case 0x002: // TCM size - return (6 << 6) | (5 << 18); + return CP15_TCMSIZE_ITCM_32KB | CP15_TCMSIZE_DTCM_16KB; case 0x100: // control reg @@ -1828,7 +1824,7 @@ void ARMv5::DataWrite32S(const u32 addr, const u32 val) DataCycles += MemTimings[addr >> BUSCYCLES_MAP_GRANULARITY_LOG2][BUSCYCLES_S32]; } -void ARMv5::GetCodeMemRegion(u32 addr, MemRegion* region) +void ARMv5::GetCodeMemRegion(const u32 addr, MemRegion* region) { NDS.ARM9GetMemRegion(addr, false, &CodeMem); } diff --git a/src/CP15_Constants.h b/src/CP15_Constants.h index 98ddf84d..3b3cbf9a 100644 --- a/src/CP15_Constants.h +++ b/src/CP15_Constants.h @@ -76,6 +76,10 @@ constexpr u32 CP15_MAINID_IMPLEMENTATION_946 = (0x946 << 4); constexpr u32 CP15_MAINID_REVISION_0 = (0 << 0); constexpr u32 CP15_MAINID_REVISION_1 = (1 << 0); +/* CP15 TCM Size Register */ +constexpr u32 CP15_TCMSIZE_DTCM_16KB = (5 << 18); +constexpr u32 CP15_TCMSIZE_ITCM_32KB = (6 << 6); + /* CP15 Cache and Write Buffer Conrol Register */ constexpr u32 CP15_CACHE_CR_ROUNDROBIN = (1 << 14); constexpr u32 CP15_CACHE_CR_ICACHEENABLE = (1 << 12); @@ -85,8 +89,24 @@ constexpr u32 CP15_CACHE_CR_WRITEBUFFERENABLE = (1 << 3); /* CP15 TCM Control Register */ constexpr u32 CP15_TCM_CR_DTCM_ENABLE = (1 << 16); constexpr u32 CP15_TCM_CR_ITCM_ENABLE = (1 << 18); -constexpr u32 CP15_TCM_CR_DTCM_LOADMODE = (1 << 17); -constexpr u32 CP15_TCM_CR_ITCM_LOADMODE = (1 << 19); +constexpr u32 CP15_TCM_CR_DTCM_LOADMODE = (1 << 17); // TODO +constexpr u32 CP15_TCM_CR_ITCM_LOADMODE = (1 << 19); // TODO + +/* CP15 DTCM Settings Register */ +constexpr u32 CP15_DTCM_SIZE_BASE = 0x200; +constexpr u32 CP15_DTCM_SIZE_MASK = 0x3E; +constexpr u32 CP15_DTCM_SIZE_POS = 1; +constexpr u32 CP15_DTCM_SIZE_MIN = 0b00011; +constexpr u32 CP15_DTCM_SIZE_MAX = 0b10111; +constexpr u32 CP15_DTCM_BASE_MASK = 0xFFFFF000; + +/* CP15 ITCM Settings Register */ +constexpr u32 CP15_ITCM_SIZE_BASE = 0x200; +constexpr u32 CP15_ITCM_SIZE_MASK = 0x3E; +constexpr u32 CP15_ITCM_SIZE_POS = 1; +constexpr u32 CP15_ITCM_SIZE_MIN = 0b00011; +constexpr u32 CP15_ITCM_SIZE_MAX = 0b10111; +constexpr u32 CP15_ITCM_BASE_MASK = 0x00000000; /* CP15 Control Register */ constexpr u32 CP15_CR_MPUENABLE = (1 << 0); @@ -132,6 +152,7 @@ constexpr u32 CP15_MAP_ICACHEABLE = 0x40; constexpr u32 CP15_MAP_ENTRYSIZE_LOG2 = CP15_REGION_BASE_GRANULARITY_LOG2; constexpr u32 CP15_MAP_ENTRYSIZE = (1 << CP15_MAP_ENTRYSIZE_LOG2); +constexpr u32 CP15_MAP_ENTRYCOUNT = 1 << (32 - CP15_MAP_ENTRYSIZE_LOG2); /* Internal Timing Constants */ constexpr u32 BUSCYCLES_N16 = 0; diff --git a/src/DSi.cpp b/src/DSi.cpp index c929c6d2..fbc72ed3 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -1705,7 +1705,7 @@ void DSi::ARM9Write32(u32 addr, u32 val) return NDS::ARM9Write32(addr, val); } -bool DSi::ARM9GetMemRegion(u32 addr, bool write, MemRegion* region) +bool DSi::ARM9GetMemRegion(const u32 addr, const bool write, MemRegion* region) { assert(ConsoleType == 1); switch (addr & 0xFF000000) diff --git a/src/DSi.h b/src/DSi.h index 1d010e0f..0da0596c 100644 --- a/src/DSi.h +++ b/src/DSi.h @@ -104,7 +104,7 @@ public: void ARM9Write16(u32 addr, u16 val) override; void ARM9Write32(u32 addr, u32 val) override; - bool ARM9GetMemRegion(u32 addr, bool write, MemRegion* region) override; + bool ARM9GetMemRegion(const u32 addr, const bool write, MemRegion* region) override; u8 ARM7Read8(u32 addr) override; u16 ARM7Read16(u32 addr) override; diff --git a/src/NDS.cpp b/src/NDS.cpp index 1f9597ce..b5cf7b4f 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -2227,7 +2227,7 @@ void NDS::ARM9Write32(u32 addr, u32 val) //Log(LogLevel::Warn, "unknown arm9 write32 %08X %08X | %08X\n", addr, val, ARM9.R[15]); } -bool NDS::ARM9GetMemRegion(u32 addr, bool write, MemRegion* region) +bool NDS::ARM9GetMemRegion(const u32 addr, const bool write, MemRegion* region) { switch (addr & 0xFF000000) { diff --git a/src/NDS.h b/src/NDS.h index cfb8e3b5..65dc2764 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -442,7 +442,7 @@ public: // TODO: Encapsulate the rest of these members virtual void ARM9Write16(u32 addr, u16 val); virtual void ARM9Write32(u32 addr, u32 val); - virtual bool ARM9GetMemRegion(u32 addr, bool write, MemRegion* region); + virtual bool ARM9GetMemRegion(const u32 addr, const bool write, MemRegion* region); virtual u8 ARM7Read8(u32 addr); virtual u16 ARM7Read16(u32 addr); From 129a3e0535bee095ed8ff660613b69aec4d05ed7 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Tue, 6 Feb 2024 08:19:05 +0100 Subject: [PATCH 35/39] Added write-back ability in addition to write-through for the data cache --- src/ARM.h | 24 +++-- src/CP15.cpp | 205 +++++++++++++++++++++++++++++++++++++------ src/CP15_Constants.h | 4 + 3 files changed, 195 insertions(+), 38 deletions(-) diff --git a/src/ARM.h b/src/ARM.h index 6b32983d..9f0cbf64 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -449,28 +449,34 @@ public: * @brief Updates a word in the data cache if present * @param [in] addr Memory address which is written * @param [in] val Word value to be written - * @par Returns - * Nothing + * @retval true, if the data was written into the cache and + * does not need to be updated until cache is + * cleaned + * false, to write through */ - void DCacheWrite32(const u32 addr, const u32 val); + bool DCacheWrite32(const u32 addr, const u32 val); /** * @brief Updates a word in the data cache if present * @param [in] addr Memory address which is written * @param [in] val Half-Word value to be written - * @par Returns - * Nothing + * @retval true, if the data was written into the cache and + * does not need to be updated until cache is + * cleaned + * false, to write through */ - void DCacheWrite16(const u32 addr, const u16 val); + bool DCacheWrite16(const u32 addr, const u16 val); /** * @brief Updates a word in the data cache if present * @param [in] addr Memory address which is written * @param [in] val Byte value to be written - * @par Returns - * Nothing + * @retval true, if the data was written into the cache and + * does not need to be updated until cache is + * cleaned + * false, to write through */ - void DCacheWrite8(const u32 addr, const u8 val); + bool DCacheWrite8(const u32 addr, const u8 val); /** * @brief Check if an address is within a data cachable region diff --git a/src/CP15.cpp b/src/CP15.cpp index 576f9f8d..22be6a52 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -548,6 +548,7 @@ u32 ARMv5::DCacheLookup(const u32 addr) return BusRead32(addr & ~3); } } + //Log(LogLevel::Debug, "DCache hit at %08lx returned %08x from set %i, line %i\n", addr, cacheLine[(addr & (ICACHE_LINELENGTH -1)) >> 2], set, id>>2); return cacheLine[(addr & (ICACHE_LINELENGTH -1)) >> 2]; } } @@ -621,6 +622,11 @@ u32 ARMv5::DCacheLookup(const u32 addr) u32* ptr = (u32 *)&DCache[line << DCACHE_LINELENGTH_LOG2]; + DataCycles = 0; + // Before we fill the cacheline, we need to write back dirty content + // Datacycles will be incremented by the required cycles to do so + DCacheClearByASetAndWay(line & (DCACHE_SETS-1), line >> DCACHE_SETS_LOG2); + //Log(LogLevel::Debug,"DCache miss, load @ %08x\n", tag); for (int i = 0; i < DCACHE_LINELENGTH; i+=sizeof(u32)) { @@ -635,7 +641,13 @@ u32 ARMv5::DCacheLookup(const u32 addr) { ptr[i >> 2] = BusRead32(tag+i); } - //Log(LogLevel::Debug,"DCache store @ %08x: %08x\n", tag+i, *(u32*)&ptr[i]); + //Log(LogLevel::Debug,"DCache store @ %08x: %08x in set %i, line %i\n", tag+i, *(u32*)&ptr[i >> 2], line & 3, line >> 2); + if ((addr == 0x02007ea0) && ((*(u32*)&ptr[i]) == 0x1239 )) + { + // Halt(1); + // exit(1); + } + } DCacheTags[line] = tag | (line & (DCACHE_SETS-1)) | CACHE_FLAG_VALID; @@ -643,59 +655,107 @@ u32 ARMv5::DCacheLookup(const u32 addr) // ouch :/ //printf("cache miss %08X: %d/%d\n", addr, NDS::ARM9MemTimings[addr >> 14][2], NDS::ARM9MemTimings[addr >> 14][3]); // first N32 remaining S32 - DataCycles = (NDS.ARM9MemTimings[tag >> 14][2] + (NDS.ARM9MemTimings[tag >> 14][3] * ((DCACHE_LINELENGTH / 4) - 1))) << NDS.ARM9ClockShift; + DataCycles += (NDS.ARM9MemTimings[tag >> 14][2] + (NDS.ARM9MemTimings[tag >> 14][3] * ((DCACHE_LINELENGTH / 4) - 1))) << NDS.ARM9ClockShift; return ptr[(addr & (DCACHE_LINELENGTH-1)) >> 2]; } -void ARMv5::DCacheWrite32(const u32 addr, const u32 val) +bool ARMv5::DCacheWrite32(const u32 addr, const u32 val) { const u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; const u32 id = ((addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; + //Log(LogLevel::Debug, "Cache write 32: %08lx <= %08lx\n", addr, val); + for (int set=0;set> 2] = val; + cacheLine[(addr & (DCACHE_LINELENGTH-1)) >> 2] = val; DataCycles = 1; - return; + //if (PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEWRITEBACK) + { + if (addr & (DCACHE_LINELENGTH / 2)) + { + DCacheTags[id+set] |= CACHE_FLAG_DIRTY_UPPERHALF ; + } + else + { + DCacheTags[id+set] |= CACHE_FLAG_DIRTY_LOWERHALF ; + } + // just mark dirty and abort the data write through the bus + return true; + } + return false; } } + return false; } -void ARMv5::DCacheWrite16(const u32 addr, const u16 val) +bool ARMv5::DCacheWrite16(const u32 addr, const u16 val) { const u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; const u32 id = ((addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; + //Log(LogLevel::Debug, "Cache write 16: %08lx <= %04x\n", addr, val); for (int set=0;set> 1] = val; + cacheLine[(addr & (DCACHE_LINELENGTH-1)) >> 1] = val; DataCycles = 1; - return; + //if (PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEWRITEBACK) + { + if (addr & (DCACHE_LINELENGTH / 2)) + { + DCacheTags[id+set] |= CACHE_FLAG_DIRTY_UPPERHALF ; + } + else + { + DCacheTags[id+set] |= CACHE_FLAG_DIRTY_LOWERHALF ; + } + // just mark dirtyand abort the data write through the bus + return true; + } + return false; } } + return false; } -void ARMv5::DCacheWrite8(const u32 addr, const u8 val) +bool ARMv5::DCacheWrite8(const u32 addr, const u8 val) { const u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; const u32 id = ((addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2;; + //Log(LogLevel::Debug, "Cache write 8: %08lx <= %02x\n", addr, val); + for (int set=0;set> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEWRITEBACK) + { + if (addr & (DCACHE_LINELENGTH / 2)) + { + DCacheTags[id+set] |= CACHE_FLAG_DIRTY_UPPERHALF ; + } + else + { + DCacheTags[id+set] |= CACHE_FLAG_DIRTY_LOWERHALF ; + } + + // just mark dirty and abort the data write through the bus + return true; + } + return false; } - } + } + return false; } void ARMv5::DCacheInvalidateByAddr(const u32 addr) @@ -735,20 +795,84 @@ void ARMv5::DCacheInvalidateAll() void ARMv5::DCacheClearAll() { - // TODO: right now any write to cached data goes straight to the - // underlying memory and invalidates the cache line. + for (int set = 0;set> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; + + for (int set=0;set> DCACHE_SETS_LOG2); + return; + } + } } void ARMv5::DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine) { - // TODO: right now any write to cached data goes straight to the - // underlying memory and invalidates the cache line. + const u32 index = cacheSet | (cacheLine << DCACHE_SETS_LOG2); + + // Only write back if valid + if (!(DCacheTags[index] & CACHE_FLAG_VALID)) + return ; + + const u32 tag = DCacheTags[index] & ~CACHE_FLAG_MASK; + u32* ptr = (u32 *)&DCache[index << DCACHE_LINELENGTH_LOG2]; + + if (DCacheTags[index] & CACHE_FLAG_DIRTY_LOWERHALF) + { + //Log(LogLevel::Debug, "Writing back %i / %i, lower half -> %08lx\n", cacheSet, cacheLine, tag); +#if 1 + for (int i = 0; i < DCACHE_LINELENGTH / 2; i+=sizeof(u32)) + { + //Log(LogLevel::Debug, " WB Value %08x\n", ptr[i >> 2]); + if (tag+i < ITCMSize) + { + *(u32*)&ITCM[(tag+i) & (ITCMPhysicalSize - 1)] = ptr[i >> 2] ; + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(tag+i); + } else + if (((tag+i) & DTCMMask) == DTCMBase) + { + *(u32*)&DTCM[(tag+i) & (DTCMPhysicalSize - 1)] = ptr[i >> 2]; + } else + { + BusWrite32(tag+i, ptr[i >> 2]); + } + } +#endif + DataCycles += (NDS.ARM9MemTimings[tag >> 14][2] + (NDS.ARM9MemTimings[tag >> 14][3] * ((DCACHE_LINELENGTH / 8) - 1))) << NDS.ARM9ClockShift; + } + if (DCacheTags[index] & CACHE_FLAG_DIRTY_UPPERHALF) + { + //Log(LogLevel::Debug, "Writing back %i / %i, upper half-> %08lx\n", cacheSet, cacheLine, tag); +#if 1 + for (int i = DCACHE_LINELENGTH / 2; i < DCACHE_LINELENGTH; i+=sizeof(u32)) + { + //Log(LogLevel::Debug, " WB Value %08x\n", ptr[i >> 2]); + if (tag+i < ITCMSize) + { + *(u32*)&ITCM[(tag+i) & (ITCMPhysicalSize - 1)] = ptr[i >> 2] ; + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(tag+i); + } else + if (((tag+i) & DTCMMask) == DTCMBase) + { + *(u32*)&DTCM[(tag+i) & (DTCMPhysicalSize - 1)] = ptr[i >> 2]; + } else + { + BusWrite32(tag+i, ptr[i >> 2]); + } + } +#endif + DataCycles += (NDS.ARM9MemTimings[tag >> 14][2] + (NDS.ARM9MemTimings[tag >> 14][3] * ((DCACHE_LINELENGTH / 8) - 1))) << NDS.ARM9ClockShift; + } + DCacheTags[index] &= ~(CACHE_FLAG_DIRTY_LOWERHALF | CACHE_FLAG_DIRTY_UPPERHALF); } bool ARMv5::IsAddressDCachable(const u32 addr) const @@ -780,7 +904,6 @@ void ARMv5::CP15Write(const u32 id, const u32 val) } return; - case 0x200: // data cacheable { u32 diff = PU_DataCacheable ^ val; @@ -1674,6 +1797,8 @@ void ARMv5::DataWrite8(const u32 addr, const u8 val) return; } + DataRegion = addr; + #ifdef JIT_ENABLED if (!NDS.IsJITEnabled()) #endif @@ -1682,13 +1807,17 @@ void ARMv5::DataWrite8(const u32 addr, const u8 val) { if (IsAddressDCachable(addr)) { - DCacheWrite8(addr, val); + if (DCacheWrite8(addr, val)) + return; +// DCacheInvalidateByAddr(addr); +// DCacheLookup(addr); +// DCacheWrite8(addr, val); +// DCacheClearByAddr(addr); +// return; } } } - DataRegion = addr; - if (addr < ITCMSize) { DataCycles = 1; @@ -1715,6 +1844,8 @@ void ARMv5::DataWrite16(const u32 addr, const u16 val) return; } + DataRegion = addr; + #ifdef JIT_ENABLED if (!NDS.IsJITEnabled()) #endif @@ -1723,13 +1854,17 @@ void ARMv5::DataWrite16(const u32 addr, const u16 val) { if (IsAddressDCachable(addr)) { - DCacheWrite16(addr, val); + if (DCacheWrite16(addr, val)) + return; +// DCacheInvalidateByAddr(addr); +// DCacheLookup(addr); +// DCacheWrite16(addr, val); +// DCacheClearByAddr(addr); +// return; } } } - DataRegion = addr; - if (addr < ITCMSize) { DataCycles = 1; @@ -1756,6 +1891,8 @@ void ARMv5::DataWrite32(const u32 addr, const u32 val) return; } + DataRegion = addr; + #ifdef JIT_ENABLED if (!NDS.IsJITEnabled()) #endif @@ -1764,13 +1901,17 @@ void ARMv5::DataWrite32(const u32 addr, const u32 val) { if (IsAddressDCachable(addr)) { - DCacheWrite32(addr, val); + if (DCacheWrite32(addr, val)) + return; +// DCacheInvalidateByAddr(addr); +// DCacheLookup(addr); +// DCacheWrite32(addr, val); +// DCacheClearByAddr(addr); +// return; } } } - DataRegion = addr; - if (addr < ITCMSize) { DataCycles = 1; @@ -1799,7 +1940,13 @@ void ARMv5::DataWrite32S(const u32 addr, const u32 val) { if (IsAddressDCachable(addr)) { - DCacheWrite32(addr, val); + if (DCacheWrite32(addr, val)) + return; +// DCacheInvalidateByAddr(addr); +// DCacheLookup(addr); +// DCacheWrite32(addr, val); +// DCacheClearByAddr(addr); +// return; } } } diff --git a/src/CP15_Constants.h b/src/CP15_Constants.h index 3b3cbf9a..de8a71f4 100644 --- a/src/CP15_Constants.h +++ b/src/CP15_Constants.h @@ -50,6 +50,7 @@ constexpr u32 CACHE_FLAG_DIRTY_LOWERHALF = (1 << 2); constexpr u32 CACHE_FLAG_DIRTY_UPPERHALF = (1 << 3); constexpr u32 CACHE_FLAG_DIRTY_MASK = (3 << 2); constexpr u32 CACHE_FLAG_SET_MASK = (3 << 0); +constexpr u32 CACHE_FLAG_MASK = 0x1F; /* CP15 Cache Type Register */ constexpr u32 CACHE_TR_LOCKDOWN_TYPE_B = (7 << 25); @@ -118,6 +119,9 @@ constexpr u32 CP15_CR_CHANGEABLE_MASK = CP15_CR_MPUENABLE | CP15_CR_BIGENDIAN | | CP15_TCM_CR_DTCM_ENABLE | CP15_TCM_CR_ITCM_ENABLE | CP15_TCM_CR_DTCM_LOADMODE | CP15_TCM_CR_ITCM_LOADMODE | CP15_CACHE_CR_ROUNDROBIN | CP15_CR_DISABLE_THUMBBIT; + /* Note: ARM946E-S Technical reference manual, Chapter 6.5.2 "You cannot directly enable or disable the write buffer" + CP15_CACHE_CR_WRITEBUFFERENABLE is always set on the cp15 + */ /* CP15 Internal Exception base value */ constexpr u32 CP15_EXCEPTIONBASE_HIGH = 0xFFFF0000; From a8306f2aa002506acfd97c9b6ed891d239a04f91 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Tue, 6 Feb 2024 08:29:01 +0100 Subject: [PATCH 36/39] Removed some debug remains Updated documenting comments for the DCacheClear* methods --- src/ARM.h | 36 ++++++++++++++++++------------------ src/CP15.cpp | 32 +------------------------------- 2 files changed, 19 insertions(+), 49 deletions(-) diff --git a/src/ARM.h b/src/ARM.h index 9f0cbf64..b1ba3c29 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -533,12 +533,12 @@ public: /** * @brief Cleans the entire data cache * @details - * In melonDS, the data cache is instantly cleaned on writes, the - * @ref CACHE_FLAG_DIRTY_LOWERHALF and @ref CACHE_FLAG_DIRTY_UPPERHALF are - * not set. - * If they are implemented at a later time, the cache content has to be - * written to memory, the dirty bit cleared. The call should require - * as much cycles as needed for this write operation. + * If write-back is enabled in conjunction with the data cache + * the dirty flags in tags are set if the corresponding cache + * line is written to. + * A clean will write the parts of the cache line back + * that is marked dirty and adds the required cycles to the + * @ref DataCyces member. * @par Returns * Nothing */ @@ -547,12 +547,12 @@ public: /** * @brief Cleans a data cache line * @details - * In melonDS, the data cache is instantly cleaned on writes, the - * @ref CACHE_FLAG_DIRTY_LOWERHALF and @ref CACHE_FLAG_DIRTY_UPPERHALF are - * not set. - * If they are implemented at a later time, the cache content has to be - * written to memory, the dirty bit cleared. The call should require - * as much cycles as needed for this write operation. + * If write-back is enabled in conjunction with the data cache + * the dirty flags in tags are set if the corresponding cache + * line is written to. + * A clean will write the parts of the cache line back + * that is marked dirty and adds the required cycles to the + * @ref DataCyces member. * @param [in] addr Memory address of the data in the cache line * @par Returns * Nothing @@ -562,12 +562,12 @@ public: /** * @brief Cleans a data cache line * @details - * In melonDS, the data cache is instantly cleaned on writes, the - * @ref CACHE_FLAG_DIRTY_LOWERHALF and @ref CACHE_FLAG_DIRTY_UPPERHALF are - * not set. - * If they are implemented at a later time, the cache content has to be - * written to memory, the dirty bit cleared. The call should require - * as much cycles as needed for this write operation. + * If write-back is enabled in conjunction with the data cache + * the dirty flags in tags are set if the corresponding cache + * line is written to. + * A clean will write the parts of the cache line back + * that is marked dirty and adds the required cycles to the + * @ref DataCyces member. * @param [in] cacheSet index of the internal cache set from * 0 to @ref DCACHE_SETS - 1 * @param [in] cacheLine index of the line within the cache set diff --git a/src/CP15.cpp b/src/CP15.cpp index 22be6a52..66d26b03 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -641,13 +641,7 @@ u32 ARMv5::DCacheLookup(const u32 addr) { ptr[i >> 2] = BusRead32(tag+i); } - //Log(LogLevel::Debug,"DCache store @ %08x: %08x in set %i, line %i\n", tag+i, *(u32*)&ptr[i >> 2], line & 3, line >> 2); - if ((addr == 0x02007ea0) && ((*(u32*)&ptr[i]) == 0x1239 )) - { - // Halt(1); - // exit(1); - } - + //Log(LogLevel::Debug,"DCache store @ %08x: %08x in set %i, line %i\n", tag+i, *(u32*)&ptr[i >> 2], line & 3, line >> 2); } DCacheTags[line] = tag | (line & (DCACHE_SETS-1)) | CACHE_FLAG_VALID; @@ -829,7 +823,6 @@ void ARMv5::DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine) if (DCacheTags[index] & CACHE_FLAG_DIRTY_LOWERHALF) { //Log(LogLevel::Debug, "Writing back %i / %i, lower half -> %08lx\n", cacheSet, cacheLine, tag); -#if 1 for (int i = 0; i < DCACHE_LINELENGTH / 2; i+=sizeof(u32)) { //Log(LogLevel::Debug, " WB Value %08x\n", ptr[i >> 2]); @@ -846,13 +839,11 @@ void ARMv5::DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine) BusWrite32(tag+i, ptr[i >> 2]); } } -#endif DataCycles += (NDS.ARM9MemTimings[tag >> 14][2] + (NDS.ARM9MemTimings[tag >> 14][3] * ((DCACHE_LINELENGTH / 8) - 1))) << NDS.ARM9ClockShift; } if (DCacheTags[index] & CACHE_FLAG_DIRTY_UPPERHALF) { //Log(LogLevel::Debug, "Writing back %i / %i, upper half-> %08lx\n", cacheSet, cacheLine, tag); -#if 1 for (int i = DCACHE_LINELENGTH / 2; i < DCACHE_LINELENGTH; i+=sizeof(u32)) { //Log(LogLevel::Debug, " WB Value %08x\n", ptr[i >> 2]); @@ -869,7 +860,6 @@ void ARMv5::DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine) BusWrite32(tag+i, ptr[i >> 2]); } } -#endif DataCycles += (NDS.ARM9MemTimings[tag >> 14][2] + (NDS.ARM9MemTimings[tag >> 14][3] * ((DCACHE_LINELENGTH / 8) - 1))) << NDS.ARM9ClockShift; } DCacheTags[index] &= ~(CACHE_FLAG_DIRTY_LOWERHALF | CACHE_FLAG_DIRTY_UPPERHALF); @@ -1809,11 +1799,6 @@ void ARMv5::DataWrite8(const u32 addr, const u8 val) { if (DCacheWrite8(addr, val)) return; -// DCacheInvalidateByAddr(addr); -// DCacheLookup(addr); -// DCacheWrite8(addr, val); -// DCacheClearByAddr(addr); -// return; } } } @@ -1856,11 +1841,6 @@ void ARMv5::DataWrite16(const u32 addr, const u16 val) { if (DCacheWrite16(addr, val)) return; -// DCacheInvalidateByAddr(addr); -// DCacheLookup(addr); -// DCacheWrite16(addr, val); -// DCacheClearByAddr(addr); -// return; } } } @@ -1903,11 +1883,6 @@ void ARMv5::DataWrite32(const u32 addr, const u32 val) { if (DCacheWrite32(addr, val)) return; -// DCacheInvalidateByAddr(addr); -// DCacheLookup(addr); -// DCacheWrite32(addr, val); -// DCacheClearByAddr(addr); -// return; } } } @@ -1942,11 +1917,6 @@ void ARMv5::DataWrite32S(const u32 addr, const u32 val) { if (DCacheWrite32(addr, val)) return; -// DCacheInvalidateByAddr(addr); -// DCacheLookup(addr); -// DCacheWrite32(addr, val); -// DCacheClearByAddr(addr); -// return; } } } From 4164687bd29acbc0baed7adaa8c1dcfa81842bfa Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Tue, 6 Feb 2024 10:18:53 +0100 Subject: [PATCH 37/39] Fixed an issue with caclulating DTCM/ITCM masks after addr was declared constant Encapsuled the cache features in #if to disable the features via compile flags --- src/CP15.cpp | 405 +++++++++++++++++++++++++++------------------------ 1 file changed, 218 insertions(+), 187 deletions(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index 66d26b03..c25470bf 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -623,10 +623,11 @@ u32 ARMv5::DCacheLookup(const u32 addr) u32* ptr = (u32 *)&DCache[line << DCACHE_LINELENGTH_LOG2]; DataCycles = 0; - // Before we fill the cacheline, we need to write back dirty content - // Datacycles will be incremented by the required cycles to do so - DCacheClearByASetAndWay(line & (DCACHE_SETS-1), line >> DCACHE_SETS_LOG2); - + #if !DISABLE_CACHEWRITEBACK + // Before we fill the cacheline, we need to write back dirty content + // Datacycles will be incremented by the required cycles to do so + DCacheClearByASetAndWay(line & (DCACHE_SETS-1), line >> DCACHE_SETS_LOG2); + #endif //Log(LogLevel::Debug,"DCache miss, load @ %08x\n", tag); for (int i = 0; i < DCACHE_LINELENGTH; i+=sizeof(u32)) { @@ -667,19 +668,21 @@ bool ARMv5::DCacheWrite32(const u32 addr, const u32 val) u32 *cacheLine = (u32 *)&DCache[(id+set) << DCACHE_LINELENGTH_LOG2]; cacheLine[(addr & (DCACHE_LINELENGTH-1)) >> 2] = val; DataCycles = 1; - //if (PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEWRITEBACK) - { - if (addr & (DCACHE_LINELENGTH / 2)) + #if !DISABLE_CACHEWRITEBACK + if (PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEWRITEBACK) { - DCacheTags[id+set] |= CACHE_FLAG_DIRTY_UPPERHALF ; + if (addr & (DCACHE_LINELENGTH / 2)) + { + DCacheTags[id+set] |= CACHE_FLAG_DIRTY_UPPERHALF ; + } + else + { + DCacheTags[id+set] |= CACHE_FLAG_DIRTY_LOWERHALF ; + } + // just mark dirty and abort the data write through the bus + return true; } - else - { - DCacheTags[id+set] |= CACHE_FLAG_DIRTY_LOWERHALF ; - } - // just mark dirty and abort the data write through the bus - return true; - } + #endif return false; } } @@ -699,19 +702,21 @@ bool ARMv5::DCacheWrite16(const u32 addr, const u16 val) u16 *cacheLine = (u16 *)&DCache[(id+set) << DCACHE_LINELENGTH_LOG2]; cacheLine[(addr & (DCACHE_LINELENGTH-1)) >> 1] = val; DataCycles = 1; - //if (PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEWRITEBACK) - { - if (addr & (DCACHE_LINELENGTH / 2)) + #if !DISABLE_CACHEWRITEBACK + if (PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEWRITEBACK) { - DCacheTags[id+set] |= CACHE_FLAG_DIRTY_UPPERHALF ; + if (addr & (DCACHE_LINELENGTH / 2)) + { + DCacheTags[id+set] |= CACHE_FLAG_DIRTY_UPPERHALF ; + } + else + { + DCacheTags[id+set] |= CACHE_FLAG_DIRTY_LOWERHALF ; + } + // just mark dirtyand abort the data write through the bus + return true; } - else - { - DCacheTags[id+set] |= CACHE_FLAG_DIRTY_LOWERHALF ; - } - // just mark dirtyand abort the data write through the bus - return true; - } + #endif return false; } } @@ -732,20 +737,22 @@ bool ARMv5::DCacheWrite8(const u32 addr, const u8 val) u8 *cacheLine = &DCache[(id+set) << DCACHE_LINELENGTH_LOG2]; cacheLine[addr & (DCACHE_LINELENGTH-1)] = val; DataCycles = 1; - //if (PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEWRITEBACK) - { - if (addr & (DCACHE_LINELENGTH / 2)) + #if !DISABLE_CACHEWRITEBACK + if (PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEWRITEBACK) { - DCacheTags[id+set] |= CACHE_FLAG_DIRTY_UPPERHALF ; + if (addr & (DCACHE_LINELENGTH / 2)) + { + DCacheTags[id+set] |= CACHE_FLAG_DIRTY_UPPERHALF ; + } + else + { + DCacheTags[id+set] |= CACHE_FLAG_DIRTY_LOWERHALF ; + } + + // just mark dirty and abort the data write through the bus + return true; } - else - { - DCacheTags[id+set] |= CACHE_FLAG_DIRTY_LOWERHALF ; - } - - // just mark dirty and abort the data write through the bus - return true; - } + #endif return false; } } @@ -789,80 +796,86 @@ void ARMv5::DCacheInvalidateAll() void ARMv5::DCacheClearAll() { - for (int set = 0;set> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; + #if !DISABLE_CACHEWRITEBACK + const u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; + const u32 id = ((addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; - for (int set=0;set> DCACHE_SETS_LOG2); - return; + if ((DCacheTags[id+set] & ~(CACHE_FLAG_DIRTY_MASK | CACHE_FLAG_SET_MASK)) == tag) + { + DCacheClearByASetAndWay(set, id >> DCACHE_SETS_LOG2); + return; + } } - } + #endif } void ARMv5::DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine) { - const u32 index = cacheSet | (cacheLine << DCACHE_SETS_LOG2); + #if !DISABLE_CACHEWRITEBACK + const u32 index = cacheSet | (cacheLine << DCACHE_SETS_LOG2); - // Only write back if valid - if (!(DCacheTags[index] & CACHE_FLAG_VALID)) - return ; + // Only write back if valid + if (!(DCacheTags[index] & CACHE_FLAG_VALID)) + return ; - const u32 tag = DCacheTags[index] & ~CACHE_FLAG_MASK; - u32* ptr = (u32 *)&DCache[index << DCACHE_LINELENGTH_LOG2]; + const u32 tag = DCacheTags[index] & ~CACHE_FLAG_MASK; + u32* ptr = (u32 *)&DCache[index << DCACHE_LINELENGTH_LOG2]; - if (DCacheTags[index] & CACHE_FLAG_DIRTY_LOWERHALF) - { - //Log(LogLevel::Debug, "Writing back %i / %i, lower half -> %08lx\n", cacheSet, cacheLine, tag); - for (int i = 0; i < DCACHE_LINELENGTH / 2; i+=sizeof(u32)) + if (DCacheTags[index] & CACHE_FLAG_DIRTY_LOWERHALF) { - //Log(LogLevel::Debug, " WB Value %08x\n", ptr[i >> 2]); - if (tag+i < ITCMSize) + //Log(LogLevel::Debug, "Writing back %i / %i, lower half -> %08lx\n", cacheSet, cacheLine, tag); + for (int i = 0; i < DCACHE_LINELENGTH / 2; i+=sizeof(u32)) { - *(u32*)&ITCM[(tag+i) & (ITCMPhysicalSize - 1)] = ptr[i >> 2] ; - NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(tag+i); - } else - if (((tag+i) & DTCMMask) == DTCMBase) - { - *(u32*)&DTCM[(tag+i) & (DTCMPhysicalSize - 1)] = ptr[i >> 2]; - } else - { - BusWrite32(tag+i, ptr[i >> 2]); + //Log(LogLevel::Debug, " WB Value %08x\n", ptr[i >> 2]); + if (tag+i < ITCMSize) + { + *(u32*)&ITCM[(tag+i) & (ITCMPhysicalSize - 1)] = ptr[i >> 2] ; + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(tag+i); + } else + if (((tag+i) & DTCMMask) == DTCMBase) + { + *(u32*)&DTCM[(tag+i) & (DTCMPhysicalSize - 1)] = ptr[i >> 2]; + } else + { + BusWrite32(tag+i, ptr[i >> 2]); + } } + DataCycles += (NDS.ARM9MemTimings[tag >> 14][2] + (NDS.ARM9MemTimings[tag >> 14][3] * ((DCACHE_LINELENGTH / 8) - 1))) << NDS.ARM9ClockShift; } - DataCycles += (NDS.ARM9MemTimings[tag >> 14][2] + (NDS.ARM9MemTimings[tag >> 14][3] * ((DCACHE_LINELENGTH / 8) - 1))) << NDS.ARM9ClockShift; - } - if (DCacheTags[index] & CACHE_FLAG_DIRTY_UPPERHALF) - { - //Log(LogLevel::Debug, "Writing back %i / %i, upper half-> %08lx\n", cacheSet, cacheLine, tag); - for (int i = DCACHE_LINELENGTH / 2; i < DCACHE_LINELENGTH; i+=sizeof(u32)) + if (DCacheTags[index] & CACHE_FLAG_DIRTY_UPPERHALF) { - //Log(LogLevel::Debug, " WB Value %08x\n", ptr[i >> 2]); - if (tag+i < ITCMSize) + //Log(LogLevel::Debug, "Writing back %i / %i, upper half-> %08lx\n", cacheSet, cacheLine, tag); + for (int i = DCACHE_LINELENGTH / 2; i < DCACHE_LINELENGTH; i+=sizeof(u32)) { - *(u32*)&ITCM[(tag+i) & (ITCMPhysicalSize - 1)] = ptr[i >> 2] ; - NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(tag+i); - } else - if (((tag+i) & DTCMMask) == DTCMBase) - { - *(u32*)&DTCM[(tag+i) & (DTCMPhysicalSize - 1)] = ptr[i >> 2]; - } else - { - BusWrite32(tag+i, ptr[i >> 2]); + //Log(LogLevel::Debug, " WB Value %08x\n", ptr[i >> 2]); + if (tag+i < ITCMSize) + { + *(u32*)&ITCM[(tag+i) & (ITCMPhysicalSize - 1)] = ptr[i >> 2] ; + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(tag+i); + } else + if (((tag+i) & DTCMMask) == DTCMBase) + { + *(u32*)&DTCM[(tag+i) & (DTCMPhysicalSize - 1)] = ptr[i >> 2]; + } else + { + BusWrite32(tag+i, ptr[i >> 2]); + } } + DataCycles += (NDS.ARM9MemTimings[tag >> 14][2] + (NDS.ARM9MemTimings[tag >> 14][3] * ((DCACHE_LINELENGTH / 8) - 1))) << NDS.ARM9ClockShift; } - DataCycles += (NDS.ARM9MemTimings[tag >> 14][2] + (NDS.ARM9MemTimings[tag >> 14][3] * ((DCACHE_LINELENGTH / 8) - 1))) << NDS.ARM9ClockShift; - } - DCacheTags[index] &= ~(CACHE_FLAG_DIRTY_LOWERHALF | CACHE_FLAG_DIRTY_UPPERHALF); + DCacheTags[index] &= ~(CACHE_FLAG_DIRTY_LOWERHALF | CACHE_FLAG_DIRTY_UPPERHALF); + #endif } bool ARMv5::IsAddressDCachable(const u32 addr) const @@ -898,7 +911,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) { u32 diff = PU_DataCacheable ^ val; PU_DataCacheable = val; - #if 0 + #if 1 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region cachable bit @@ -924,7 +937,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) { u32 diff = PU_CodeCacheable ^ val; PU_CodeCacheable = val; - #if 0 + #if 1 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region cachable bit @@ -951,7 +964,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) { u32 diff = PU_DataCacheWrite ^ val; PU_DataCacheWrite = val; - #if 0 + #if 1 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region write buffer @@ -983,7 +996,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) for (int i=0;i> (i * 2) & 3) << (i * CP15_REGIONACCESS_BITS_PER_REGION); - #if 0 + #if 1 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region access permission @@ -1015,7 +1028,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) for (int i=0;i> (i * 2) & 3) << (i * CP15_REGIONACCESS_BITS_PER_REGION); - #if 0 + #if 1 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region access permission @@ -1041,7 +1054,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) { u32 diff = PU_DataRW ^ val; PU_DataRW = val; - #if 0 + #if 1 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region access permission @@ -1065,7 +1078,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) { u32 diff = PU_CodeRW ^ val; PU_CodeRW = val; - #if 0 + #if 1 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region access permission @@ -1399,7 +1412,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) uint8_t segment = (CacheDebugRegisterIndex >> (32-DCACHE_SETS_LOG2)) & (DCACHE_SETS-1); uint8_t wordAddress = (CacheDebugRegisterIndex & (DCACHE_LINELENGTH-1)) >> 2; uint8_t index = (CacheDebugRegisterIndex >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1); - *(u32 *)&DCache[((index << DCACHE_SETS_LOG2) + segment) << DCACHE_LINELENGTH_LOG2 + wordAddress*4] = val; + *(u32 *)&DCache[(((index << DCACHE_SETS_LOG2) + segment) << DCACHE_LINELENGTH_LOG2) + wordAddress*4] = val; } return; @@ -1488,7 +1501,7 @@ u32 ARMv5::CP15Read(const u32 id) const case 0x661: case 0x670: case 0x671: - return PU_Region[(id >> CP15_REGIONACCESS_BITS_PER_REGION) & 0xF]; + return PU_Region[(id >> 4) & 0xF]; case 0x7A6: // read Cache Dirty Bit (optional) @@ -1585,18 +1598,20 @@ u32 ARMv5::CP15Read(const u32 id) const u32 ARMv5::CodeRead32(const u32 addr, bool const branch) { -#ifdef JIT_ENABLED - if (!NDS.IsJITEnabled()) -#endif - { - if (CP15Control & CP15_CACHE_CR_ICACHEENABLE) + #if !DISABLE_ICACHE + #ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) + #endif { - if (IsAddressICachable(addr)) + if (CP15Control & CP15_CACHE_CR_ICACHEENABLE) { - return ICacheLookup(addr); + if (IsAddressICachable(addr)) + { + return ICacheLookup(addr); + } } } - } + #endif if (addr < ITCMSize) { @@ -1631,19 +1646,21 @@ void ARMv5::DataRead8(const u32 addr, u32* val) DataRegion = addr; -#ifdef JIT_ENABLED - if (!NDS.IsJITEnabled()) -#endif - { - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + #if !DISABLE_DCACHE + #ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) + #endif { - if (IsAddressDCachable(addr)) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - *val = (DCacheLookup(addr) >> (8 * (addr & 3))) & 0xff; - return; + if (IsAddressDCachable(addr)) + { + *val = (DCacheLookup(addr) >> (8 * (addr & 3))) & 0xff; + return; + } } } - } + #endif if (addr < ITCMSize) { @@ -1673,19 +1690,21 @@ void ARMv5::DataRead16(const u32 addr, u32* val) DataRegion = addr; -#ifdef JIT_ENABLED - if (!NDS.IsJITEnabled()) -#endif - { - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + #if !DISABLE_DCACHE + #ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) + #endif { - if (IsAddressDCachable(addr)) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - *val = (DCacheLookup(addr) >> (8* (addr & 2))) & 0xffff; - return; + if (IsAddressDCachable(addr)) + { + *val = (DCacheLookup(addr) >> (8* (addr & 2))) & 0xffff; + return; + } } } - } + #endif if (addr < ITCMSize) { @@ -1715,30 +1734,32 @@ void ARMv5::DataRead32(const u32 addr, u32* val) DataRegion = addr; -#ifdef JIT_ENABLED - if (!NDS.IsJITEnabled()) -#endif - { - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + #if !DISABLE_DCACHE + #ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) + #endif { - if (IsAddressDCachable(addr)) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - *val = DCacheLookup(addr); - return; + if (IsAddressDCachable(addr)) + { + *val = DCacheLookup(addr); + return; + } } } - } + #endif if (addr < ITCMSize) { DataCycles = 1; - *val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 3)]; + *val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 4)]; return; } if ((addr & DTCMMask) == DTCMBase) { DataCycles = 1; - *val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 3)]; + *val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 4)]; return; } @@ -1748,30 +1769,32 @@ void ARMv5::DataRead32(const u32 addr, u32* val) void ARMv5::DataRead32S(const u32 addr, u32* val) { -#ifdef JIT_ENABLED - if (!NDS.IsJITEnabled()) -#endif - { - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + #if !DISABLE_DCACHE + #ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) + #endif { - if (IsAddressDCachable(addr)) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - *val = DCacheLookup(addr); - return; + if (IsAddressDCachable(addr)) + { + *val = DCacheLookup(addr); + return; + } } } - } + #endif if (addr < ITCMSize) { DataCycles += 1; - *val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 3)]; + *val = *(u32*)&ITCM[addr & (ITCMPhysicalSize - 4)]; return; } if ((addr & DTCMMask) == DTCMBase) { DataCycles += 1; - *val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 3)]; + *val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 4)]; return; } @@ -1789,19 +1812,21 @@ void ARMv5::DataWrite8(const u32 addr, const u8 val) DataRegion = addr; -#ifdef JIT_ENABLED - if (!NDS.IsJITEnabled()) -#endif - { - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + #if !DISABLE_DCACHE + #ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) + #endif { - if (IsAddressDCachable(addr)) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - if (DCacheWrite8(addr, val)) - return; + if (IsAddressDCachable(addr)) + { + if (DCacheWrite8(addr, val)) + return; + } } } - } + #endif if (addr < ITCMSize) { @@ -1831,19 +1856,21 @@ void ARMv5::DataWrite16(const u32 addr, const u16 val) DataRegion = addr; -#ifdef JIT_ENABLED - if (!NDS.IsJITEnabled()) -#endif - { - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + #if !DISABLE_DCACHE + #ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) + #endif { - if (IsAddressDCachable(addr)) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - if (DCacheWrite16(addr, val)) - return; + if (IsAddressDCachable(addr)) + { + if (DCacheWrite16(addr, val)) + return; + } } } - } + #endif if (addr < ITCMSize) { @@ -1873,31 +1900,33 @@ void ARMv5::DataWrite32(const u32 addr, const u32 val) DataRegion = addr; -#ifdef JIT_ENABLED - if (!NDS.IsJITEnabled()) -#endif - { - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + #if !DISABLE_DCACHE + #ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) + #endif { - if (IsAddressDCachable(addr)) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - if (DCacheWrite32(addr, val)) - return; + if (IsAddressDCachable(addr)) + { + if (DCacheWrite32(addr, val)) + return; + } } } - } + #endif if (addr < ITCMSize) { DataCycles = 1; - *(u32*)&ITCM[addr & (ITCMPhysicalSize - 3)] = val; + *(u32*)&ITCM[addr & (ITCMPhysicalSize - 4)] = val; NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); return; } if ((addr & DTCMMask) == DTCMBase) { DataCycles = 1; - *(u32*)&DTCM[addr & (DTCMPhysicalSize - 3)] = val; + *(u32*)&DTCM[addr & (DTCMPhysicalSize - 4)] = val; return; } @@ -1907,24 +1936,26 @@ void ARMv5::DataWrite32(const u32 addr, const u32 val) void ARMv5::DataWrite32S(const u32 addr, const u32 val) { -#ifdef JIT_ENABLED - if (!NDS.IsJITEnabled()) -#endif - { - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) + #if !DISABLE_DCACHE + #ifdef JIT_ENABLED + if (!NDS.IsJITEnabled()) + #endif { - if (IsAddressDCachable(addr)) + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { - if (DCacheWrite32(addr, val)) - return; + if (IsAddressDCachable(addr)) + { + if (DCacheWrite32(addr, val)) + return; + } } } - } + #endif if (addr < ITCMSize) { DataCycles += 1; - *(u32*)&ITCM[addr & (ITCMPhysicalSize - 3)] = val; + *(u32*)&ITCM[addr & (ITCMPhysicalSize - 4)] = val; #ifdef JIT_ENABLED NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); #endif @@ -1933,7 +1964,7 @@ void ARMv5::DataWrite32S(const u32 addr, const u32 val) if ((addr & DTCMMask) == DTCMBase) { DataCycles += 1; - *(u32*)&DTCM[addr & (DTCMPhysicalSize - 3)] = val; + *(u32*)&DTCM[addr & (DTCMPhysicalSize - 4)] = val; return; } From 01bb5f1fe2796a73d1aa3e5995a53d22d997a4c5 Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Tue, 6 Feb 2024 11:17:23 +0100 Subject: [PATCH 38/39] Enabled Overlapping region fix again --- src/CP15.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index c25470bf..f2fb9b75 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -911,7 +911,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) { u32 diff = PU_DataCacheable ^ val; PU_DataCacheable = val; - #if 1 + #if 0 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region cachable bit @@ -937,7 +937,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) { u32 diff = PU_CodeCacheable ^ val; PU_CodeCacheable = val; - #if 1 + #if 0 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region cachable bit @@ -964,7 +964,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) { u32 diff = PU_DataCacheWrite ^ val; PU_DataCacheWrite = val; - #if 1 + #if 0 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region write buffer @@ -996,7 +996,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) for (int i=0;i> (i * 2) & 3) << (i * CP15_REGIONACCESS_BITS_PER_REGION); - #if 1 + #if 0 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region access permission @@ -1028,7 +1028,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) for (int i=0;i> (i * 2) & 3) << (i * CP15_REGIONACCESS_BITS_PER_REGION); - #if 1 + #if 0 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region access permission @@ -1054,7 +1054,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) { u32 diff = PU_DataRW ^ val; PU_DataRW = val; - #if 1 + #if 0 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region access permission @@ -1078,7 +1078,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) { u32 diff = PU_CodeRW ^ val; PU_CodeRW = val; - #if 1 + #if 0 // This code just updates the PU_Map entries of the given region // this works fine, if the regions do not overlap // If overlapping and the least priority region access permission From b2d196cd64bcec42ed10836f587fa2d7c4bca7cc Mon Sep 17 00:00:00 2001 From: DesperateProgrammer Date: Wed, 7 Feb 2024 08:10:27 +0100 Subject: [PATCH 39/39] Formatting corrections Removed premature optimization and replaced them with [[(un)likely]] --- src/CP15.cpp | 139 ++++++++++++++++++--------------------------------- 1 file changed, 50 insertions(+), 89 deletions(-) diff --git a/src/CP15.cpp b/src/CP15.cpp index f2fb9b75..be0c0839 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -296,7 +296,7 @@ void ARMv5::UpdatePURegions(const bool update_all) // PU disabled u8 mask = CP15_MAP_READABLE | CP15_MAP_WRITEABLE | CP15_MAP_EXECUTABLE; - if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) mask |= CP15_MAP_DCACHEABLE | CP15_MAP_DCACHEWRITEBACK ; + if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) mask |= CP15_MAP_DCACHEABLE | CP15_MAP_DCACHEWRITEBACK; if (CP15Control & CP15_CACHE_CR_ICACHEENABLE) mask |= CP15_MAP_ICACHEABLE; memset(PU_UserMap, mask, CP15_MAP_ENTRYCOUNT); @@ -371,13 +371,13 @@ u32 ARMv5::ICacheLookup(const u32 addr) const u32 tag = (addr & ~(ICACHE_LINELENGTH - 1)); const u32 id = ((addr >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1)) << ICACHE_SETS_LOG2; - for (int set=0;set> 14][2]; if (CodeMem.Mem) @@ -412,17 +412,8 @@ u32 ARMv5::ICacheLookup(const u32 addr) } u32 line; -#if 0 - // caclulate in which cacheline the data is to be filled - // The code below is doing the same as the if-less below - // It increases performance by reducing banches. - // The code is kept here for readability. - // - // NOTE: If you need to update either part, you need - // to update the other too to keep them in sync! - // - if (CP15Control & CP15_CACHE_CR_ROUNDROBIN) + if (CP15Control & CP15_CACHE_CR_ROUNDROBIN) [[likely]] { line = ICacheCount; ICacheCount = (line+1) & (ICACHE_SETS-1); @@ -434,7 +425,7 @@ u32 ARMv5::ICacheLookup(const u32 addr) if (ICacheLockDown) { - if (ICacheLockDown & CACHE_LOCKUP_L) + if (ICacheLockDown & CACHE_LOCKUP_L) [[unlikely]] { // load into locked up cache // into the selected set @@ -446,17 +437,7 @@ u32 ARMv5::ICacheLookup(const u32 addr) } } -#else - // Do the same as above but instead of using if-else - // utilize the && and || operators to skip parts of the operations - // With the order of comparison we can put the most likely path - // checked first - - bool doLockDown = (ICacheLockDown & CACHE_LOCKUP_L); - bool roundRobin = CP15Control & CP15_CACHE_CR_ROUNDROBIN; - (!roundRobin && (line = RandomLineIndex())) || (roundRobin && (ICacheCount = line = ((ICacheCount+1) & (ICACHE_SETS-1)))) ; - (!doLockDown && (line = (line | ICacheLockDown & (ICACHE_SETS-1))+id)) || (doLockDown && (line = (ICacheLockDown & (ICACHE_SETS-1))+id)); -#endif + line += id; u32* ptr = (u32 *)&ICache[line << ICACHE_LINELENGTH_LOG2]; @@ -484,11 +465,11 @@ void ARMv5::ICacheInvalidateByAddr(const u32 addr) const u32 tag = (addr & ~(ICACHE_LINELENGTH - 1)) | CACHE_FLAG_VALID; const u32 id = ((addr >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1)) << ICACHE_SETS_LOG2; - for (int set=0;set> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_ICACHEABLE ; + return PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_ICACHEABLE; } u32 ARMv5::DCacheLookup(const u32 addr) { //Log(LogLevel::Debug,"DCache load @ %08x\n", addr); - const u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)) ; + const u32 tag = (addr & ~(DCACHE_LINELENGTH - 1)); const u32 id = ((addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; - for (int set=0;set> 14][2]; if (addr < ITCMSize) @@ -574,51 +555,31 @@ u32 ARMv5::DCacheLookup(const u32 addr) } u32 line; -#if 0 - // caclulate in which cacheline the data is to be filled - // The code below is doing the same as the if-less below - // It increases performance by reducing banches. - // The code is kept here for readability. - // - // NOTE: If you need to update either part, you need - // to update the other too to keep them in sync! - // - if (CP15Control & CP15_CACHE_CR_ROUNDROBIN) + if (CP15Control & CP15_CACHE_CR_ROUNDROBIN) [[likely]] { line = DCacheCount; DCacheCount = (line+1) & (DCACHE_SETS-1); } else { - line = DCacheRandom(); + line = RandomLineIndex(); } - // Update the selected set depending on the DCache LockDown register if (DCacheLockDown) { - if (DCacheLockDown & CACHE_LOCKUP_L) + if (DCacheLockDown & CACHE_LOCKUP_L) [[unlikely]] { // load into locked up cache // into the selected set - line = (DCacheLockDown & (DCACHE_SETS-1)) + id; + line = DCacheLockDown & (DCACHE_SETS-1); } else { - u8 minSet = ICacheLockDown & (DCACHE_SETS-1); - line = (line | minSet) + id; + u8 minSet = DCacheLockDown & (DCACHE_SETS-1); + line = line | minSet; } - } -#else - // Do the same as above but instead of using if-else - // utilize the && and || operators to skip parts of the operations - // With the order of comparison we can put the most likely path - // checked first - - bool doLockDown = (DCacheLockDown & CACHE_LOCKUP_L); - bool roundRobin = CP15Control & CP15_CACHE_CR_ROUNDROBIN; - (!roundRobin && (line = RandomLineIndex())) || (roundRobin && (DCacheCount = line = ((DCacheCount+1) & (DCACHE_SETS-1)))); - (!doLockDown && (line = (line | DCacheLockDown & (DCACHE_SETS-1))+id)) || (doLockDown && (line = (DCacheLockDown & (DCACHE_SETS-1))+id)); -#endif + } + line += id; u32* ptr = (u32 *)&DCache[line << DCACHE_LINELENGTH_LOG2]; @@ -661,7 +622,7 @@ bool ARMv5::DCacheWrite32(const u32 addr, const u32 val) //Log(LogLevel::Debug, "Cache write 32: %08lx <= %08lx\n", addr, val); - for (int set=0;set> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; //Log(LogLevel::Debug, "Cache write 16: %08lx <= %04x\n", addr, val); - for (int set=0;set> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2;; + const u32 id = ((addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; //Log(LogLevel::Debug, "Cache write 8: %08lx <= %02x\n", addr, val); - for (int set=0;set> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; - for (int set=0;set> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2; - for (int set=0;set> 2]); if (tag+i < ITCMSize) { - *(u32*)&ITCM[(tag+i) & (ITCMPhysicalSize - 1)] = ptr[i >> 2] ; + *(u32*)&ITCM[(tag+i) & (ITCMPhysicalSize - 1)] = ptr[i >> 2]; NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(tag+i); } else if (((tag+i) & DTCMMask) == DTCMBase) @@ -861,7 +822,7 @@ void ARMv5::DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine) //Log(LogLevel::Debug, " WB Value %08x\n", ptr[i >> 2]); if (tag+i < ITCMSize) { - *(u32*)&ITCM[(tag+i) & (ITCMPhysicalSize - 1)] = ptr[i >> 2] ; + *(u32*)&ITCM[(tag+i) & (ITCMPhysicalSize - 1)] = ptr[i >> 2]; NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(tag+i); } else if (((tag+i) & DTCMMask) == DTCMBase) @@ -880,7 +841,7 @@ void ARMv5::DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine) bool ARMv5::IsAddressDCachable(const u32 addr) const { - return PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEABLE ; + return PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEABLE; } void ARMv5::CP15Write(const u32 id, const u32 val) @@ -993,7 +954,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) PU_DataRW = 0; #pragma GCC ivdep #pragma GCC unroll 8 - for (int i=0;i> (i * 2) & 3) << (i * CP15_REGIONACCESS_BITS_PER_REGION); #if 0 @@ -1025,7 +986,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) PU_CodeRW = 0; #pragma GCC ivdep #pragma GCC unroll 8 - for (int i=0;i> (i * 2) & 3) << (i * CP15_REGIONACCESS_BITS_PER_REGION); #if 0 @@ -1310,7 +1271,7 @@ void ARMv5::CP15Write(const u32 id, const u32 val) // Bit 0..Way-1: locked ways // The Cache is 4 way associative // But all bits are r/w - DCacheLockDown = val ; + DCacheLockDown = val; Log(LogLevel::Debug,"ICacheLockDown\n"); return; case 0x901: @@ -1464,7 +1425,7 @@ u32 ARMv5::CP15Read(const u32 id) const u32 ret = 0; #pragma GCC ivdep #pragma GCC unroll 8 - for (int i=0;i> (i * CP15_REGIONACCESS_BITS_PER_REGION) & CP15_REGIONACCESS_REGIONMASK) << (i*2); return ret; } @@ -1475,7 +1436,7 @@ u32 ARMv5::CP15Read(const u32 id) const // 0x503 returns all 4 bits per region u32 ret = 0; #pragma GCC unroll 8 - for (int i=0;i> (i * CP15_REGIONACCESS_BITS_PER_REGION) & CP15_REGIONACCESS_REGIONMASK) << (i*2); return ret; }