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;