Added write-back ability in addition to write-through for the data cache
This commit is contained in:
parent
97aabe0f4f
commit
129a3e0535
24
src/ARM.h
24
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
|
||||
|
|
205
src/CP15.cpp
205
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<DCACHE_SETS;set++)
|
||||
{
|
||||
if ((DCacheTags[id+set] & ~(CACHE_FLAG_DIRTY_MASK | CACHE_FLAG_SET_MASK)) == tag)
|
||||
{
|
||||
u32 *cacheLine = (u32 *)&DCache[(id+set) << DCACHE_LINELENGTH_LOG2];
|
||||
cacheLine[(addr & (ICACHE_LINELENGTH-1)) >> 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<DCACHE_SETS;set++)
|
||||
{
|
||||
if ((DCacheTags[id+set] & ~(CACHE_FLAG_DIRTY_MASK | CACHE_FLAG_SET_MASK)) == tag)
|
||||
{
|
||||
u16 *cacheLine = (u16 *)&DCache[(id+set) << DCACHE_LINELENGTH_LOG2];
|
||||
cacheLine[(addr & (ICACHE_LINELENGTH-1)) >> 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<DCACHE_SETS;set++)
|
||||
{
|
||||
if ((DCacheTags[id+set] & ~(CACHE_FLAG_DIRTY_MASK | CACHE_FLAG_SET_MASK)) == tag)
|
||||
{
|
||||
u8 *cacheLine = &DCache[(id+set) << DCACHE_LINELENGTH_LOG2];
|
||||
cacheLine[addr & (ICACHE_LINELENGTH-1)] = val;
|
||||
cacheLine[addr & (DCACHE_LINELENGTH-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 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_SETS;set++)
|
||||
for (int line = 0;line<=DCACHE_LINESPERSET;line++)
|
||||
DCacheClearByASetAndWay(set, line);
|
||||
}
|
||||
|
||||
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.
|
||||
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;set++)
|
||||
{
|
||||
if ((DCacheTags[id+set] & ~(CACHE_FLAG_DIRTY_MASK | CACHE_FLAG_SET_MASK)) == tag)
|
||||
{
|
||||
DCacheClearByASetAndWay(set, id >> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue