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);