implement write buffer

This commit is contained in:
Jaklyy 2024-12-08 00:19:43 -05:00
parent d14c5ea246
commit b40c6bc41d
4 changed files with 594 additions and 294 deletions

View File

@ -198,15 +198,12 @@ void ARM::Reset()
BreakReq = false; BreakReq = false;
#endif #endif
MainRAMTimestamp = 0;
memset(&MRTrack, 0, sizeof(MRTrack)); memset(&MRTrack, 0, sizeof(MRTrack));
FuncQueueFill = 0; FuncQueueFill = 0;
FuncQueueEnd = 0; FuncQueueEnd = 0;
FuncQueueProg = 0; FuncQueueProg = 0;
FuncQueueActive = false; FuncQueueActive = false;
ExecuteCycles = 0;
// zorp // zorp
JumpTo(ExceptionBase); JumpTo(ExceptionBase);
@ -748,6 +745,12 @@ void ARMv5::StartExec()
else else
AddCycles_C(); AddCycles_C();
} }
QueueFunction(&ARMv5::WBCheck_2);
}
void ARMv5::WBCheck_2()
{
WriteBufferCheck<false>();
} }
template <CPUExecuteMode mode> template <CPUExecuteMode mode>
@ -756,7 +759,7 @@ void ARMv5::Execute()
if constexpr (mode == CPUExecuteMode::InterpreterGDB) if constexpr (mode == CPUExecuteMode::InterpreterGDB)
GdbCheckB(); GdbCheckB();
if (Halted) if (!FuncQueueActive && Halted)
{ {
if (Halted == 2) if (Halted == 2)
{ {
@ -777,7 +780,6 @@ void ARMv5::Execute()
else else
{ {
NDS.ARM9Timestamp = NDS.ARM9Target; NDS.ARM9Timestamp = NDS.ARM9Target;
WriteBufferCheck<false>();
return; return;
} }
} }
@ -828,7 +830,7 @@ void ARMv5::Execute()
if constexpr (mode == CPUExecuteMode::InterpreterGDB) if constexpr (mode == CPUExecuteMode::InterpreterGDB)
GdbCheckC(); // gdb might throw a hissy fit about this change but idc GdbCheckC(); // gdb might throw a hissy fit about this change but idc
//printf("A:%i, F:%i, P:%i, E:%i, I:%08llX, P:%08X, 15:%08X\n", FuncQueueActive, FuncQueueFill, FuncQueueProg, FuncQueueEnd, CurInstr, PC, R[15]); //printf("A9: A:%i, F:%i, P:%i, E:%i, I:%08llX, P:%08X, 15:%08X\n", FuncQueueActive, FuncQueueFill, FuncQueueProg, FuncQueueEnd, CurInstr, PC, R[15]);
(this->*FuncQueue[FuncQueueProg])(); (this->*FuncQueue[FuncQueueProg])();
@ -882,7 +884,6 @@ void ARMv5::Execute()
//NDS.ARM9Timestamp += Cycles; //NDS.ARM9Timestamp += Cycles;
//Cycles = 0; //Cycles = 0;
} }
WriteBufferCheck<false>();
if (Halted == 2) if (Halted == 2)
Halted = 0; Halted = 0;
@ -938,7 +939,7 @@ void ARMv4::Execute()
if constexpr (mode == CPUExecuteMode::InterpreterGDB) if constexpr (mode == CPUExecuteMode::InterpreterGDB)
GdbCheckB(); GdbCheckB();
if (Halted) if (!FuncQueueActive && Halted)
{ {
if (Halted == 2) if (Halted == 2)
{ {
@ -1008,7 +1009,7 @@ void ARMv4::Execute()
if constexpr (mode == CPUExecuteMode::InterpreterGDB) if constexpr (mode == CPUExecuteMode::InterpreterGDB)
GdbCheckC(); GdbCheckC();
//printf("A:%i, F:%i, P:%i, E:%i, I:%08llX, 15:%08X\n", FuncQueueActive, FuncQueueFill, FuncQueueProg, FuncQueueEnd, CurInstr, R[15]); //printf("A7: A:%i, F:%i, P:%i, E:%i, I:%08llX, 15:%08X\n", FuncQueueActive, FuncQueueFill, FuncQueueProg, FuncQueueEnd, CurInstr, R[15]);
(this->*FuncQueue[FuncQueueProg])(); (this->*FuncQueue[FuncQueueProg])();

View File

@ -21,6 +21,7 @@
#include <algorithm> #include <algorithm>
#include <optional> #include <optional>
#include <cstring>
#include "types.h" #include "types.h"
#include "MemRegion.h" #include "MemRegion.h"
@ -54,12 +55,26 @@ enum class CPUExecuteMode : u32
#endif #endif
}; };
enum class WBMode
{
Check,
Force,
SingleBurst,
WaitEntry,
};
enum class MainRAMType : u8 enum class MainRAMType : u8
{ {
Null = 0, Null = 0,
Fetch, Fetch,
ICacheStream, ICacheStream,
DCacheStream, DCacheStream,
WriteBufferCmds, // all write buffer commands must be above this one; wb cmds not strictly used for main ram
WBDrain,
WBWrite,
WBCheck,
WBWaitRead,
WBWaitWrite,
}; };
// each one represents a bit in the field // each one represents a bit in the field
@ -214,7 +229,6 @@ public:
MemRegion CodeMem; MemRegion CodeMem;
u64 MainRAMTimestamp;
MainRAMTrackers MRTrack; MainRAMTrackers MRTrack;
u32 BranchAddr; u32 BranchAddr;
@ -493,7 +507,7 @@ public:
*/ */
void ICacheInvalidateAll(); void ICacheInvalidateAll();
template <int force> inline bool WriteBufferHandle(); template <WBMode mode> bool WriteBufferHandle();
template <int next> void WriteBufferCheck(); template <int next> void WriteBufferCheck();
void WriteBufferWrite(u32 val, u8 flag, u32 addr = 0); void WriteBufferWrite(u32 val, u8 flag, u32 addr = 0);
void WriteBufferDrain(); void WriteBufferDrain();
@ -724,18 +738,35 @@ public:
void JumpTo_3B(); void JumpTo_3B();
void JumpTo_3C(); void JumpTo_3C();
void JumpTo_4(); void JumpTo_4();
void CodeRead32_2();
void ICacheLookup_2();
void DAbortHandle(); void DAbortHandle();
void DCacheFin8(); void DCacheFin8();
void DRead8_2(); void DRead8_2();
void DRead8_3();
void DCacheFin16(); void DCacheFin16();
void DRead16_2(); void DRead16_2();
void DRead16_3();
void DCacheFin32(); void DCacheFin32();
void DRead32_2(); void DRead32_2();
void DRead32_3();
void DRead32S_2(); void DRead32S_2();
void DRead32S_3();
void DWrite8_2(); void DWrite8_2();
void DWrite8_3();
void DWrite16_2(); void DWrite16_2();
void DWrite16_3();
void DWrite32_2(); void DWrite32_2();
void DWrite32_3();
void DWrite32S_2(); void DWrite32S_2();
void DWrite32S_3();
void WBCheck_2();
void DCacheLookup_2();
void DCacheLookup_3();
void DCClearAddr_2();
void DCClearSetWay_2();
void DCClearInvalidateAddr_2();
void DCClearInvalidateSetWay_2();
void SetupInterlock_2(); void SetupInterlock_2();
void HandleInterlocksExecute_2(); void HandleInterlocksExecute_2();
void HandleInterlocksMemory_2(); void HandleInterlocksMemory_2();
@ -806,11 +837,14 @@ public:
u64 ITCMTimestamp; u64 ITCMTimestamp;
u64 TimestampMemory; u64 TimestampMemory;
void (ARMv5::*FuncQueue[31])(void); void (ARMv5::*FuncQueue[32])(void);
void (ARMv5::*DelayedQueue)(void);
u32 PC; u32 PC;
bool NullFetch; bool NullFetch;
bool Store; bool Store;
s8 ITCMDelay; s8 ITCMDelay;
u32 QueuedDCacheLine;
u32 CP15Queue;
u8 ILCurrReg; u8 ILCurrReg;
u8 ILPrevReg; u8 ILPrevReg;
@ -833,7 +867,9 @@ public:
u8 WBWriting; // whether the buffer is actively trying to perform a write u8 WBWriting; // whether the buffer is actively trying to perform a write
u32 WBCurAddr; // address the write buffer is currently writing to u32 WBCurAddr; // address the write buffer is currently writing to
u64 WBCurVal; // current value being written; 0-31: val | 61-63: flag; 0 = byte ns; 1 = halfword ns; 2 = word ns; 3 = word s; 4 = address (invalid in this variable) u64 WBCurVal; // current value being written; 0-31: val | 61-63: flag; 0 = byte ns; 1 = halfword ns; 2 = word ns; 3 = word s; 4 = address (invalid in this variable)
u32 WBAddrQueued[40];
u32 storeaddr[16]; // temp until i figure out why using the fifo address entries directly didn't work u32 storeaddr[16]; // temp until i figure out why using the fifo address entries directly didn't work
u64 WBValQueued[40];
u64 WriteBufferFifo[16]; // 0-31: val | 61-63: flag; 0 = byte ns; 1 = halfword ns; 2 = word ns; 3 = word s; 4 = address u64 WriteBufferFifo[16]; // 0-31: val | 61-63: flag; 0 = byte ns; 1 = halfword ns; 2 = word ns; 3 = word s; 4 = address
u64 WBTimestamp; // current timestamp u64 WBTimestamp; // current timestamp
//u64 WBMainRAMDelay; // timestamp used to emulate the delay before the next main ram write can begin //u64 WBMainRAMDelay; // timestamp used to emulate the delay before the next main ram write can begin
@ -870,8 +906,7 @@ public:
template <CPUExecuteMode mode> template <CPUExecuteMode mode>
void Execute(); void Execute();
Platform::FileHandle* filey; void (ARMv4::*FuncQueue[32])(void);
void (ARMv4::*FuncQueue[31])(void);
bool Nonseq; bool Nonseq;
void CodeRead16(u32 addr); void CodeRead16(u32 addr);

View File

@ -454,6 +454,18 @@ bool ARMv5::ICacheLookup(const u32 addr)
if (CP15BISTTestStateRegister & CP15_BIST_TR_DISABLE_ICACHE_LINEFILL) [[unlikely]] if (CP15BISTTestStateRegister & CP15_BIST_TR_DISABLE_ICACHE_LINEFILL) [[unlikely]]
return false; return false;
WriteBufferDrain();
FetchAddr[16] = addr;
QueueFunction(&ARMv5::ICacheLookup_2);
return true;
}
void ARMv5::ICacheLookup_2()
{
u32 addr = FetchAddr[16];
const u32 tag = (addr & ~(ICACHE_LINELENGTH - 1));
const u32 id = ((addr >> ICACHE_LINELENGTH_LOG2) & (ICACHE_LINESPERSET-1)) << ICACHE_SETS_LOG2;
u32 line; u32 line;
if (CP15Control & CP15_CACHE_CR_ROUNDROBIN) [[likely]] if (CP15Control & CP15_CACHE_CR_ROUNDROBIN) [[likely]]
@ -491,8 +503,6 @@ bool ARMv5::ICacheLookup(const u32 addr)
if (NDS.ARM9Timestamp < time) NDS.ARM9Timestamp = time; if (NDS.ARM9Timestamp < time) NDS.ARM9Timestamp = time;
} }
WriteBufferDrain();
ICacheTags[line] = tag | (line & (ICACHE_SETS-1)) | CACHE_FLAG_VALID; ICacheTags[line] = tag | (line & (ICACHE_SETS-1)) | CACHE_FLAG_VALID;
// timing logic // timing logic
@ -544,7 +554,6 @@ bool ARMv5::ICacheLookup(const u32 addr)
} }
Store = false; Store = false;
DataRegion = Mem9_Null; DataRegion = Mem9_Null;
return true;
} }
void ARMv5::ICacheInvalidateByAddr(const u32 addr) void ARMv5::ICacheInvalidateByAddr(const u32 addr)
@ -658,6 +667,7 @@ bool ARMv5::DCacheLookup(const u32 addr)
DataRegion = Mem9_DCache; DataRegion = Mem9_DCache;
//Log(LogLevel::Debug, "DCache hit at %08lx returned %08x from set %i, line %i\n", addr, cacheLine[(addr & (DCACHE_LINELENGTH -1)) >> 2], set, id>>2); //Log(LogLevel::Debug, "DCache hit at %08lx returned %08x from set %i, line %i\n", addr, cacheLine[(addr & (DCACHE_LINELENGTH -1)) >> 2], set, id>>2);
RetVal = cacheLine[(addr & (DCACHE_LINELENGTH -1)) >> 2]; RetVal = cacheLine[(addr & (DCACHE_LINELENGTH -1)) >> 2];
(this->*DelayedQueue)();
return true; return true;
} }
} }
@ -676,7 +686,18 @@ bool ARMv5::DCacheLookup(const u32 addr)
// BIST test State register (See arm946e-s Rev 1 technical manual, 2.3.15 "Register 15, test State Register") // 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) [[unlikely]] if (CP15BISTTestStateRegister & CP15_BIST_TR_DISABLE_DCACHE_LINEFILL) [[unlikely]]
return false; return false;
WriteBufferDrain(); // checkme?
FetchAddr[16] = addr;
QueueFunction(&ARMv5::DCacheLookup_2);
return true;
}
void ARMv5::DCacheLookup_2()
{
u32 addr = FetchAddr[16];
const u32 tag = (addr & ~(DCACHE_LINELENGTH - 1));
const u32 id = ((addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2;
u32 line; u32 line;
if (CP15Control & CP15_CACHE_CR_ROUNDROBIN) [[likely]] if (CP15Control & CP15_CACHE_CR_ROUNDROBIN) [[likely]]
@ -704,16 +725,23 @@ bool ARMv5::DCacheLookup(const u32 addr)
} }
line += id; line += id;
u32* ptr = (u32 *)&DCache[line << DCACHE_LINELENGTH_LOG2];
WriteBufferDrain(); // checkme?
#if !DISABLE_CACHEWRITEBACK #if !DISABLE_CACHEWRITEBACK
// Before we fill the cacheline, we need to write back dirty content // Before we fill the cacheline, we need to write back dirty content
// Datacycles will be incremented by the required cycles to do so // Datacycles will be incremented by the required cycles to do so
DCacheClearByASetAndWay(line & (DCACHE_SETS-1), line >> DCACHE_SETS_LOG2); DCacheClearByASetAndWay(line & (DCACHE_SETS-1), line >> DCACHE_SETS_LOG2);
#endif #endif
QueuedDCacheLine = line;
QueueFunction(&ARMv5::DCacheLookup_3);
}
void ARMv5::DCacheLookup_3()
{
u32 addr = FetchAddr[16];
const u32 tag = (addr & ~(DCACHE_LINELENGTH - 1));
const u32 id = ((addr >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET-1)) << DCACHE_SETS_LOG2;
u32 line = QueuedDCacheLine;
u32* ptr = (u32 *)&DCache[line << DCACHE_LINELENGTH_LOG2];
DCacheTags[line] = tag | (line & (DCACHE_SETS-1)) | CACHE_FLAG_VALID; DCacheTags[line] = tag | (line & (DCACHE_SETS-1)) | CACHE_FLAG_VALID;
// timing logic // timing logic
@ -722,10 +750,12 @@ bool ARMv5::DCacheLookup(const u32 addr)
{ {
MRTrack.Type = MainRAMType::DCacheStream; MRTrack.Type = MainRAMType::DCacheStream;
MRTrack.Var = line; MRTrack.Var = line;
FetchAddr[16] = addr;
if (CP15BISTTestStateRegister & CP15_BIST_TR_DISABLE_DCACHE_STREAMING) [[unlikely]] if (CP15BISTTestStateRegister & CP15_BIST_TR_DISABLE_DCACHE_STREAMING) [[unlikely]]
DCacheStreamPtr = 7; DCacheStreamPtr = 7;
else DCacheStreamPtr = (addr & 0x1F) / 4; else DCacheStreamPtr = (addr & 0x1F) / 4;
QueueFunction(DelayedQueue);
} }
else else
{ {
@ -773,8 +803,8 @@ bool ARMv5::DCacheLookup(const u32 addr)
} }
} }
RetVal = ptr[(addr & (DCACHE_LINELENGTH-1)) >> 2]; RetVal = ptr[(addr & (DCACHE_LINELENGTH-1)) >> 2];
(this->*DelayedQueue)();
} }
return true;
} }
bool ARMv5::DCacheWrite32(const u32 addr, const u32 val) bool ARMv5::DCacheWrite32(const u32 addr, const u32 val)
@ -1099,7 +1129,7 @@ void ARMv5::DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine)
WriteBufferWrite(ptr[1], 3, tag+0x04); WriteBufferWrite(ptr[1], 3, tag+0x04);
WriteBufferWrite(ptr[2], 3, tag+0x08); WriteBufferWrite(ptr[2], 3, tag+0x08);
WriteBufferWrite(ptr[3], 3, tag+0x0C); WriteBufferWrite(ptr[3], 3, tag+0x0C);
NDS.ARM9Timestamp += 4; //DataCycles += 5; CHECKME: does this function like a write does but with mcr? //NDS.ARM9Timestamp += 4; //DataCycles += 5; CHECKME: does this function like a write does but with mcr?
} }
if (DCacheTags[index] & CACHE_FLAG_DIRTY_UPPERHALF) // todo: check how this behaves when both fields need to be written if (DCacheTags[index] & CACHE_FLAG_DIRTY_UPPERHALF) // todo: check how this behaves when both fields need to be written
{ {
@ -1117,7 +1147,7 @@ void ARMv5::DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine)
WriteBufferWrite(ptr[5], 3, tag+0x14); WriteBufferWrite(ptr[5], 3, tag+0x14);
WriteBufferWrite(ptr[6], 3, tag+0x18); WriteBufferWrite(ptr[6], 3, tag+0x18);
WriteBufferWrite(ptr[7], 3, tag+0x1C); WriteBufferWrite(ptr[7], 3, tag+0x1C);
NDS.ARM9Timestamp += 4; //NDS.ARM9Timestamp += 4;
} }
DCacheTags[index] &= ~(CACHE_FLAG_DIRTY_LOWERHALF | CACHE_FLAG_DIRTY_UPPERHALF); DCacheTags[index] &= ~(CACHE_FLAG_DIRTY_LOWERHALF | CACHE_FLAG_DIRTY_UPPERHALF);
#endif #endif
@ -1128,12 +1158,21 @@ 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;
} }
template <int force> #define A9WENTLAST (!NDS.MainRAMLastAccess)
inline bool ARMv5::WriteBufferHandle() #define A7WENTLAST ( NDS.MainRAMLastAccess)
#define A9LAST false
#define A7LAST true
#define A9PRIORITY !(NDS.ExMemCnt[0] & 0x8000)
#define A7PRIORITY (NDS.ExMemCnt[0] & 0x8000)
template <WBMode mode>
bool ARMv5::WriteBufferHandle()
{ {
// handle write buffer writes while (true)
{
if (WBWriting) if (WBWriting)
{ {
if ((mode == WBMode::Check) && ((NDS.A9ContentionTS << NDS.ARM9ClockShift) > NDS.ARM9Timestamp)) return true;
// look up timings // look up timings
// TODO: handle interrupted bursts? // TODO: handle interrupted bursts?
u32 cycles; u32 cycles;
@ -1143,60 +1182,69 @@ inline bool ARMv5::WriteBufferHandle()
{ {
if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM)
{ {
cycles = (4 << NDS.ARM9ClockShift) - 1; if (NDS.A9ContentionTS < NDS.MainRAMTimestamp) { NDS.A9ContentionTS = NDS.MainRAMTimestamp; if (A7PRIORITY) return false; }
cycles = 4;
NDS.MainRAMTimestamp = NDS.A9ContentionTS + 9;
NDS.MainRAMLastAccess = A9LAST;
} }
else cycles = MemTimings[WBCurAddr>>14][0] - 6; // todo: twl timings else cycles = (MemTimings[WBCurAddr>>14][0] - 5) >> NDS.ARM9ClockShift; // todo: twl timings
break; break;
} }
case 1: case 1:
{ {
if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM)
{ {
cycles = (3 << NDS.ARM9ClockShift) - 1; if (NDS.A9ContentionTS < NDS.MainRAMTimestamp) { NDS.A9ContentionTS = NDS.MainRAMTimestamp; if (A7PRIORITY) return false; }
NDS.MainRAMTimestamp = NDS.A9ContentionTS + 8;
cycles = 3;
NDS.MainRAMLastAccess = A9LAST;
} }
else cycles = MemTimings[WBCurAddr>>14][0] - 6; // todo: twl timings else cycles = (MemTimings[WBCurAddr>>14][0] - 5) >> NDS.ARM9ClockShift; // todo: twl timings
break; break;
} }
case 3:
{
if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM)
{
if (A9WENTLAST)
{
NDS.MainRAMTimestamp += 2;
cycles = 2;
break;
}
}
else
{
cycles = MemTimings[WBCurAddr>>14][2] >> NDS.ARM9ClockShift;
break;
}
}
case 2: case 2:
{ {
if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM)
{ {
cycles = (4 << NDS.ARM9ClockShift) - 1; if (NDS.A9ContentionTS < NDS.MainRAMTimestamp) { NDS.A9ContentionTS = NDS.MainRAMTimestamp; if (A7PRIORITY) return false; }
NDS.MainRAMTimestamp = NDS.A9ContentionTS + 9;
cycles = 4;
NDS.MainRAMLastAccess = A9LAST;
} }
else cycles = MemTimings[WBCurAddr>>14][1] - 6; // todo: twl timings else cycles = (MemTimings[WBCurAddr>>14][1] - 5) >> NDS.ARM9ClockShift; // todo: twl timings
break;
}
case 3:
{
cycles = MemTimings[WBCurAddr>>14][2];
break; break;
} }
} }
if ((NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) && (((MainRAMTimestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1)) > WBTimestamp)) NDS.A9ContentionTS += cycles;
WBTimestamp = (MainRAMTimestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1); WBReleaseTS = (NDS.A9ContentionTS << NDS.ARM9ClockShift) - 1;
if (NDS.ARM9Regions[WBCurAddr>>14] != Mem9_MainRAM && ((WBCurVal >> 61) != 3))
// get the current timestamp
u64 ts = WBTimestamp + cycles;
if (!force && ts > NDS.ARM9Timestamp) return true;
if ( force && ts > NDS.ARM9Timestamp)
{ {
NDS.ARM9Timestamp = ts; NDS.A9ContentionTS += 1;
} WBTimestamp = WBReleaseTS + 2; // todo: twl timings
if ((WBCurVal >> 61) != 3)
{
WBReleaseTS = WBTimestamp = (ts + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1);
if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) MainRAMTimestamp = ts + ((((WBCurVal >> 61) == 0) ? 4 : 5) << NDS.ARM9ClockShift);
else WBTimestamp += 2; // todo: twl timings
} }
else else
{ {
WBTimestamp = ts; WBTimestamp = WBReleaseTS;
if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) MainRAMTimestamp += 2 << NDS.ARM9ClockShift;
} }
WBInitialTS = WBTimestamp; if (WBWritePointer != 16 && (WriteBufferFifo[WBWritePointer] >> 61) != 3) WBInitialTS = WBTimestamp;
switch (WBCurVal >> 61) switch (WBCurVal >> 61)
{ {
@ -1211,38 +1259,37 @@ inline bool ARMv5::WriteBufferHandle()
BusWrite32(WBCurAddr, WBCurVal); BusWrite32(WBCurAddr, WBCurVal);
break; break;
default: // invalid default: // invalid
Platform::Log(Platform::LogLevel::Warn, "WHY ARE WE TRYING TO WRITE AN ADDRESS VIA THE WRITE BUFFER! PANIC!!!\n", (u8)(WBCurVal >> 61)); Platform::Log(Platform::LogLevel::Warn, "WHY ARE WE TRYING TO WRITE NONSENSE VIA THE WRITE BUFFER! PANIC!!! Flag: %i\n", (u8)(WBCurVal >> 61));
break; break;
} }
WBLastRegion = NDS.ARM9Regions[WBCurAddr>>14]; WBLastRegion = NDS.ARM9Regions[WBCurAddr>>14];
WBWriting = false; WBWriting = false;
if ((force == 2) && ((WriteBufferFifo[WBWritePointer] >> 61) != 3)) return true; if ((mode == WBMode::SingleBurst) && ((WriteBufferFifo[WBWritePointer] >> 61) != 3)) return true;
} }
// check if write buffer is empty // check if write buffer is empty
if (WBWritePointer == 16) return true; if (WBWritePointer == 16) return true;
// attempt to drain write buffer // attempt to drain write buffer
if ((WriteBufferFifo[WBWritePointer] >> 61) != 4) // not an address if ((WriteBufferFifo[WBWritePointer] >> 61) != 4) // not an address
{ {
if (NDS.ARM9Regions[storeaddr[WBWritePointer]>>14] == Mem9_MainRAM) // main ram handling if (WBInitialTS > NDS.ARM9Timestamp)
{ {
if (!force && (WBTimestamp > NDS.ARM9Timestamp)) return true; if (mode == WBMode::Check) return true;
if ( force && (WBTimestamp > NDS.ARM9Timestamp)) else NDS.ARM9Timestamp = WBInitialTS;
NDS.ARM9Timestamp = WBTimestamp;
WBTimestamp = std::max(MainRAMTimestamp, WBTimestamp);
} }
WBTimestamp = (WBTimestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1); //if ((WriteBufferFifo[WBWritePointer] >> 61) == 3) WBCurAddr+=4; // TODO
//if (storeaddr[WBWritePointer] != WBCurAddr) printf("MISMATCH: %08X %08X\n", storeaddr[WBWritePointer], WBCurAddr);
WBCurVal = WriteBufferFifo[WBWritePointer];
WBCurAddr = storeaddr[WBWritePointer]; WBCurAddr = storeaddr[WBWritePointer];
WBCurVal = WriteBufferFifo[WBWritePointer];
WBWriting = true; WBWriting = true;
} }
else else
{ {
// todo: i want to set the address here instead //WBCurAddr = (u32)WriteBufferFifo[WBWritePointer]; // TODO
} }
WBWritePointer = (WBWritePointer + 1) & 0xF; WBWritePointer = (WBWritePointer + 1) & 0xF;
@ -1251,12 +1298,40 @@ inline bool ARMv5::WriteBufferHandle()
WBWritePointer = 16; WBWritePointer = 16;
WBFillPointer = 0; WBFillPointer = 0;
} }
return false; if ((mode == WBMode::WaitEntry) && (WBWritePointer != WBFillPointer)) return true;
}
} }
template bool ARMv5::WriteBufferHandle<WBMode::Check>();
template bool ARMv5::WriteBufferHandle<WBMode::Force>();
template bool ARMv5::WriteBufferHandle<WBMode::SingleBurst>();
template bool ARMv5::WriteBufferHandle<WBMode::WaitEntry>();
#undef A9WENTLAST
#undef A7WENTLAST
#undef A9LAST
#undef A7LAST
#undef A9PRIORITY
#undef A7PRIORITY
template <int next> template <int next>
void ARMv5::WriteBufferCheck() void ARMv5::WriteBufferCheck()
{ {
if ((WBWritePointer != 16) || WBWriting)
{
if constexpr (next == 0)
{
MRTrack.Type = MainRAMType::WBCheck;
}
else if constexpr (next == 2)
{
MRTrack.Type = MainRAMType::WBWaitWrite;
}
else
{
MRTrack.Type = MainRAMType::WBWaitRead;
}
}
/*
while (!WriteBufferHandle<0>()); // loop until we've cleared out all writeable entries while (!WriteBufferHandle<0>()); // loop until we've cleared out all writeable entries
if constexpr (next == 1 || next == 3) // check if the next write is occuring if constexpr (next == 1 || next == 3) // check if the next write is occuring
@ -1273,7 +1348,7 @@ void ARMv5::WriteBufferCheck()
{ {
//if (NDS.ARM9Timestamp >= WBInitialTS) //if (NDS.ARM9Timestamp >= WBInitialTS)
while(!WriteBufferHandle<2>()); while(!WriteBufferHandle<2>());
} }*/
} }
template void ARMv5::WriteBufferCheck<3>(); template void ARMv5::WriteBufferCheck<3>();
template void ARMv5::WriteBufferCheck<2>(); template void ARMv5::WriteBufferCheck<2>();
@ -1282,7 +1357,26 @@ template void ARMv5::WriteBufferCheck<0>();
void ARMv5::WriteBufferWrite(u32 val, u8 flag, u32 addr) void ARMv5::WriteBufferWrite(u32 val, u8 flag, u32 addr)
{ {
WriteBufferCheck<0>(); MRTrack.Type = MainRAMType::WBWrite;
WBAddrQueued[MRTrack.Var] = addr;
WBValQueued[MRTrack.Var++] = val | (u64)flag << 61;
/*switch (flag)
{
case 0: // byte
BusWrite8 (addr, val);
break;
case 1: // halfword
BusWrite16(addr, val);
break;
case 2: // word
case 3:
BusWrite32(addr, val);
break;
default: // invalid
//Platform::Log(Platform::LogLevel::Warn, "WHY ARE WE TRYING TO WRITE NONSENSE VIA THE WRITE BUFFER! PANIC!!! Flag: %i\n", (u8)(WBCurVal >> 61));
break;
}*/
/*WriteBufferCheck<0>();
if (WBFillPointer == WBWritePointer) // if the write buffer is full then we stall the cpu until room is made if (WBFillPointer == WBWritePointer) // if the write buffer is full then we stall the cpu until room is made
WriteBufferHandle<1>(); WriteBufferHandle<1>();
@ -1302,12 +1396,14 @@ void ARMv5::WriteBufferWrite(u32 val, u8 flag, u32 addr)
WriteBufferFifo[WBFillPointer] = val | (u64)flag << 61; WriteBufferFifo[WBFillPointer] = val | (u64)flag << 61;
storeaddr[WBFillPointer] = addr; storeaddr[WBFillPointer] = addr;
WBFillPointer = (WBFillPointer + 1) & 0xF; WBFillPointer = (WBFillPointer + 1) & 0xF;*/
} }
void ARMv5::WriteBufferDrain() void ARMv5::WriteBufferDrain()
{ {
while (!WriteBufferHandle<1>()); // loop until drained fully if ((WBWritePointer != 16) || WBWriting)
MRTrack.Type = MainRAMType::WBDrain;
//while (!WriteBufferHandle<1>()); // loop until drained fully
} }
void ARMv5::CP15Write(u32 id, u32 val) void ARMv5::CP15Write(u32 id, u32 val)
@ -1561,6 +1657,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
case 0x704: case 0x704:
case 0x782: case 0x782:
//WriteBufferDrain(); // checkme
Halt(1); Halt(1);
return; return;
@ -1578,7 +1675,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
ICacheInvalidateByAddr(val); ICacheInvalidateByAddr(val);
//Halt(255); //Halt(255);
return; return;
case 0x752: /*case 0x752:
// requires priv mode or causes UNKNOWN INSTRUCTION exception // requires priv mode or causes UNKNOWN INSTRUCTION exception
if (PU_Map != PU_PrivMap) if (PU_Map != PU_PrivMap)
{ {
@ -1592,7 +1689,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
} }
//Halt(255); //Halt(255);
return; return;
*/
case 0x760: case 0x760:
// requires priv mode or causes UNKNOWN INSTRUCTION exception // requires priv mode or causes UNKNOWN INSTRUCTION exception
@ -1612,7 +1709,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
DCacheInvalidateByAddr(val); DCacheInvalidateByAddr(val);
//printf("inval data cache SI\n"); //printf("inval data cache SI\n");
return; return;
case 0x762: /*case 0x762:
// requires priv mode or causes UNKNOWN INSTRUCTION exception // requires priv mode or causes UNKNOWN INSTRUCTION exception
if (PU_Map != PU_PrivMap) if (PU_Map != PU_PrivMap)
{ {
@ -1625,15 +1722,15 @@ void ARMv5::CP15Write(u32 id, u32 val)
DCacheInvalidateBySetAndWay(cacheSet, cacheLine); DCacheInvalidateBySetAndWay(cacheSet, cacheLine);
} }
return; return;
*/
case 0x770: /*case 0x770:
// invalidate both caches // invalidate both caches
// can be called from user and privileged // can be called from user and privileged
ICacheInvalidateAll(); ICacheInvalidateAll();
DCacheInvalidateAll(); DCacheInvalidateAll();
break; break;
*/
case 0x7A0: /*case 0x7A0:
// requires priv mode or causes UNKNOWN INSTRUCTION exception // requires priv mode or causes UNKNOWN INSTRUCTION exception
if (PU_Map != PU_PrivMap) if (PU_Map != PU_PrivMap)
{ {
@ -1641,15 +1738,16 @@ void ARMv5::CP15Write(u32 id, u32 val)
} }
//Log(LogLevel::Debug,"clean data cache\n"); //Log(LogLevel::Debug,"clean data cache\n");
DCacheClearAll(); DCacheClearAll();
return; return;*/
case 0x7A1: case 0x7A1:
// requires priv mode or causes UNKNOWN INSTRUCTION exception // requires priv mode or causes UNKNOWN INSTRUCTION exception
if (PU_Map != PU_PrivMap) if (PU_Map != PU_PrivMap)
{ {
return ARMInterpreter::A_UNK(this); return ARMInterpreter::A_UNK(this);
} }
//Log(LogLevel::Debug,"clean data cache MVA\n"); //Log(LogLevel::Debug,"clean data cache MVA\n");=
DCacheClearByAddr(val); CP15Queue = val;
QueueFunction(&ARMv5::DCClearAddr_2);
return; return;
case 0x7A2: case 0x7A2:
//Log(LogLevel::Debug,"clean data cache SET/WAY\n"); //Log(LogLevel::Debug,"clean data cache SET/WAY\n");
@ -1660,9 +1758,8 @@ void ARMv5::CP15Write(u32 id, u32 val)
} else } else
{ {
// Cache invalidat by line number and set number // Cache invalidat by line number and set number
u8 cacheSet = val >> (32 - DCACHE_SETS_LOG2) & (DCACHE_SETS -1); CP15Queue = val;
u8 cacheLine = (val >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET -1); QueueFunction(&ARMv5::DCClearSetWay_2);
DCacheClearByASetAndWay(cacheSet, cacheLine);
} }
return; return;
case 0x7A3: case 0x7A3:
@ -1678,7 +1775,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
case 0x7A4: case 0x7A4:
// Can be used in user and privileged mode // Can be used in user and privileged mode
// Drain Write Buffer: Stall until all write back completed // Drain Write Buffer: Stall until all write back completed
WriteBufferDrain(); QueueFunction(&ARMv5::WriteBufferDrain);
return; return;
case 0x7D1: case 0x7D1:
@ -1695,7 +1792,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
//ICacheLookup((val & ~0x03) | 0x1C); TODO: REIMPLEMENT WITH DEFERENCE //ICacheLookup((val & ~0x03) | 0x1C); TODO: REIMPLEMENT WITH DEFERENCE
return; return;
case 0x7E0: /*case 0x7E0:
//Log(LogLevel::Debug,"clean & invalidate data cache\n"); //Log(LogLevel::Debug,"clean & invalidate data cache\n");
// requires priv mode or causes UNKNOWN INSTRUCTION exception // requires priv mode or causes UNKNOWN INSTRUCTION exception
if (PU_Map != PU_PrivMap) if (PU_Map != PU_PrivMap)
@ -1704,7 +1801,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
} }
DCacheClearAll(); DCacheClearAll();
DCacheInvalidateAll(); DCacheInvalidateAll();
return; return;*/
case 0x7E1: case 0x7E1:
//Log(LogLevel::Debug,"clean & invalidate data cache MVA\n"); //Log(LogLevel::Debug,"clean & invalidate data cache MVA\n");
// requires priv mode or causes UNKNOWN INSTRUCTION exception // requires priv mode or causes UNKNOWN INSTRUCTION exception
@ -1712,8 +1809,8 @@ void ARMv5::CP15Write(u32 id, u32 val)
{ {
return ARMInterpreter::A_UNK(this); return ARMInterpreter::A_UNK(this);
} }
DCacheClearByAddr(val); CP15Queue = val;
DCacheInvalidateByAddr(val); QueueFunction(&ARMv5::DCClearInvalidateAddr_2);
return; return;
case 0x7E2: case 0x7E2:
//Log(LogLevel::Debug,"clean & invalidate data cache SET/WAY\n"); //Log(LogLevel::Debug,"clean & invalidate data cache SET/WAY\n");
@ -1724,10 +1821,8 @@ void ARMv5::CP15Write(u32 id, u32 val)
} else } else
{ {
// Cache invalidat by line number and set number // Cache invalidat by line number and set number
u8 cacheSet = val >> (32 - DCACHE_SETS_LOG2) & (DCACHE_SETS -1); CP15Queue = val;
u8 cacheLine = (val >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET -1); QueueFunction(&ARMv5::DCClearInvalidateSetWay_2);
DCacheClearByASetAndWay(cacheSet, cacheLine);
DCacheInvalidateBySetAndWay(cacheSet, cacheLine);
} }
return; return;
@ -2023,6 +2118,35 @@ u32 ARMv5::CP15Read(const u32 id) const
return 0; return 0;
} }
void ARMv5::DCClearAddr_2()
{
u32 val = CP15Queue;
DCacheClearByAddr(val);
}
void ARMv5::DCClearSetWay_2()
{
u32 val = CP15Queue;
u8 cacheSet = val >> (32 - DCACHE_SETS_LOG2) & (DCACHE_SETS -1);
u8 cacheLine = (val >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET -1);
DCacheClearByASetAndWay(cacheSet, cacheLine);
}
void ARMv5::DCClearInvalidateAddr_2()
{
u32 val = CP15Queue;
DCacheClearByAddr(val);
DCacheInvalidateByAddr(val);
}
void ARMv5::DCClearInvalidateSetWay_2()
{
u32 val = CP15Queue;
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);
}
// TCM are handled here. // TCM are handled here.
// TODO: later on, handle PU // TODO: later on, handle PU
@ -2071,15 +2195,23 @@ void ARMv5::CodeRead32(u32 addr)
if (NDS.ARM9Timestamp < time) NDS.ARM9Timestamp = time; if (NDS.ARM9Timestamp < time) NDS.ARM9Timestamp = time;
} }
u8 cycles = MemTimings[addr >> 14][1];
if (PU_Map[addr>>12] & 0x30) if (PU_Map[addr>>12] & 0x30)
WriteBufferDrain(); WriteBufferDrain();
else else
WriteBufferCheck<3>(); WriteBufferCheck<3>();
FetchAddr[16] = addr;
QueueFunction(&ARMv5::CodeRead32_2);
}
void ARMv5::CodeRead32_2()
{
u32 addr = FetchAddr[16];
NDS.ARM9Timestamp = NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1) & ~((1<<NDS.ARM9ClockShift)-1); NDS.ARM9Timestamp = NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1) & ~((1<<NDS.ARM9ClockShift)-1);
u8 cycles = MemTimings[addr >> 14][1];
if ((addr >> 24) == 0x02) if ((addr >> 24) == 0x02)
{ {
FetchAddr[16] = addr; FetchAddr[16] = addr;
@ -2180,11 +2312,8 @@ void ARMv5::DRead8_2()
{ {
if (IsAddressDCachable(addr)) if (IsAddressDCachable(addr))
{ {
if (DCacheLookup(addr)) DelayedQueue = &ARMv5::DCacheFin8;
{ if (DCacheLookup(addr)) return;
QueueFunction(&ARMv5::DCacheFin8);
return;
}
} }
} }
#endif #endif
@ -2202,6 +2331,15 @@ void ARMv5::DRead8_2()
else else
WriteBufferCheck<1>(); WriteBufferCheck<1>();
QueueFunction(&ARMv5::DRead8_3);
}
void ARMv5::DRead8_3()
{
u8 reg = __builtin_ctz(LDRRegs);
u32 addr = FetchAddr[reg];
u32 dummy; u32* val = (LDRFailedRegs & (1<<reg)) ? &dummy : &R[reg];
NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1); NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1);
if ((addr >> 24) == 0x02) if ((addr >> 24) == 0x02)
@ -2288,11 +2426,8 @@ void ARMv5::DRead16_2()
{ {
if (IsAddressDCachable(addr)) if (IsAddressDCachable(addr))
{ {
if (DCacheLookup(addr)) DelayedQueue = &ARMv5::DCacheFin16;
{ if (DCacheLookup(addr)) return;
QueueFunction(&ARMv5::DCacheFin16);
return;
}
} }
} }
#endif #endif
@ -2310,6 +2445,15 @@ void ARMv5::DRead16_2()
else else
WriteBufferCheck<1>(); WriteBufferCheck<1>();
QueueFunction(&ARMv5::DRead16_3);
}
void ARMv5::DRead16_3()
{
u8 reg = __builtin_ctz(LDRRegs);
u32 addr = FetchAddr[reg];
u32 dummy; u32* val = (LDRFailedRegs & (1<<reg)) ? &dummy : &R[reg];
NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1); NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1);
if ((addr >> 24) == 0x02) if ((addr >> 24) == 0x02)
@ -2397,11 +2541,8 @@ void ARMv5::DRead32_2()
{ {
if (IsAddressDCachable(addr)) if (IsAddressDCachable(addr))
{ {
if (DCacheLookup(addr)) DelayedQueue = &ARMv5::DCacheFin32;
{ if (DCacheLookup(addr)) return;
QueueFunction(&ARMv5::DCacheFin32);
return;
}
} }
} }
#endif #endif
@ -2419,6 +2560,15 @@ void ARMv5::DRead32_2()
else else
WriteBufferCheck<1>(); WriteBufferCheck<1>();
QueueFunction(&ARMv5::DRead32_3);
}
void ARMv5::DRead32_3()
{
u8 reg = __builtin_ctz(LDRRegs);
u32 addr = FetchAddr[reg];
u32 dummy; u32* val = (LDRFailedRegs & (1<<reg)) ? &dummy : &R[reg];
NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1); NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1);
if ((addr >> 24) == 0x02) if ((addr >> 24) == 0x02)
@ -2492,11 +2642,8 @@ void ARMv5::DRead32S_2()
{ {
if (IsAddressDCachable(addr)) if (IsAddressDCachable(addr))
{ {
if (DCacheLookup(addr)) DelayedQueue = &ARMv5::DCacheFin32;
{ if (DCacheLookup(addr)) return;
QueueFunction(&ARMv5::DCacheFin32);
return;
}
} }
} }
#endif #endif
@ -2514,6 +2661,15 @@ void ARMv5::DRead32S_2()
else else
WriteBufferCheck<1>(); WriteBufferCheck<1>();
QueueFunction(&ARMv5::DRead32S_3);
}
void ARMv5::DRead32S_3()
{
u8 reg = __builtin_ctz(LDRRegs);
u32 addr = FetchAddr[reg];
u32 dummy; u32* val = (LDRFailedRegs & (1<<reg)) ? &dummy : &R[reg];
// bursts cannot cross a 1kb boundary // bursts cannot cross a 1kb boundary
if (addr & 0x3FF) // s if (addr & 0x3FF) // s
{ {
@ -2636,6 +2792,22 @@ void ARMv5::DWrite8_2()
if (!(PU_Map[addr>>12] & (0x30))) if (!(PU_Map[addr>>12] & (0x30)))
{ {
WriteBufferCheck<2>(); WriteBufferCheck<2>();
QueueFunction(&ARMv5::DWrite8_3);
}
else
{
if (WBDelay > NDS.ARM9Timestamp) NDS.ARM9Timestamp = WBDelay;
WriteBufferWrite(addr, 4);
WriteBufferWrite(val, 0, addr);
}
}
void ARMv5::DWrite8_3()
{
u8 reg = __builtin_ctz(STRRegs);
u32 addr = FetchAddr[reg];
u8 val = STRVal[reg];
NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1); NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1);
@ -2655,17 +2827,6 @@ void ARMv5::DWrite8_2()
WBTimestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1); WBTimestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1);
BusWrite8(addr, val); BusWrite8(addr, val);
} }
}
else
{
if (WBDelay > NDS.ARM9Timestamp) NDS.ARM9Timestamp = WBDelay;
WriteBufferWrite(addr, 4);
WriteBufferWrite(val, 0, addr);
DataRegion = Mem9_Null;
NDS.ARM9Timestamp += DataCycles = 1;
WBDelay = NDS.ARM9Timestamp + 1;
}
} }
bool ARMv5::DataWrite16(u32 addr, u16 val, u8 reg) bool ARMv5::DataWrite16(u32 addr, u16 val, u8 reg)
@ -2744,6 +2905,22 @@ void ARMv5::DWrite16_2()
if (!(PU_Map[addr>>12] & 0x30)) if (!(PU_Map[addr>>12] & 0x30))
{ {
WriteBufferCheck<2>(); WriteBufferCheck<2>();
QueueFunction(&ARMv5::DWrite16_3);
}
else
{
if (WBDelay > NDS.ARM9Timestamp) NDS.ARM9Timestamp = WBDelay;
WriteBufferWrite(addr, 4);
WriteBufferWrite(val, 1, addr);
}
}
void ARMv5::DWrite16_3()
{
u8 reg = __builtin_ctz(STRRegs);
u32 addr = FetchAddr[reg];
u16 val = STRVal[reg];
NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1); NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1);
@ -2763,17 +2940,6 @@ void ARMv5::DWrite16_2()
WBTimestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1); WBTimestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1);
BusWrite16(addr, val); BusWrite16(addr, val);
} }
}
else
{
if (WBDelay > NDS.ARM9Timestamp) NDS.ARM9Timestamp = WBDelay;
WriteBufferWrite(addr, 4);
WriteBufferWrite(val, 1, addr);
DataRegion = Mem9_Null;
NDS.ARM9Timestamp += DataCycles = 1;
WBDelay = NDS.ARM9Timestamp + 1;
}
} }
bool ARMv5::DataWrite32(u32 addr, u32 val, u8 reg) bool ARMv5::DataWrite32(u32 addr, u32 val, u8 reg)
@ -2857,6 +3023,23 @@ void ARMv5::DWrite32_2()
if (!(PU_Map[addr>>12] & 0x30)) if (!(PU_Map[addr>>12] & 0x30))
{ {
WriteBufferCheck<2>(); WriteBufferCheck<2>();
QueueFunction(&ARMv5::DWrite32_3);
}
else
{
if (WBDelay > NDS.ARM9Timestamp) NDS.ARM9Timestamp = WBDelay;
WriteBufferWrite(addr, 4);
WriteBufferWrite(val, 2, addr);
STRRegs &= ~1<<reg;
}
}
void ARMv5::DWrite32_3()
{
u8 reg = __builtin_ctz(STRRegs);
u32 addr = FetchAddr[reg];
u32 val = STRVal[reg];
NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1); NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1);
@ -2876,17 +3059,6 @@ void ARMv5::DWrite32_2()
WBTimestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1); WBTimestamp = (NDS.ARM9Timestamp + ((1<<NDS.ARM9ClockShift)-1)) & ~((1<<NDS.ARM9ClockShift)-1);
BusWrite32(addr, val); BusWrite32(addr, val);
} }
}
else
{
if (WBDelay > NDS.ARM9Timestamp) NDS.ARM9Timestamp = WBDelay;
WriteBufferWrite(addr, 4);
WriteBufferWrite(val, 2, addr);
DataRegion = Mem9_Null;
NDS.ARM9Timestamp += DataCycles = 1;
WBDelay = NDS.ARM9Timestamp + 1;
}
STRRegs &= ~1<<reg; STRRegs &= ~1<<reg;
} }
@ -2964,6 +3136,20 @@ void ARMv5::DWrite32S_2()
if (!(PU_Map[addr>>12] & 0x30)) // non-bufferable if (!(PU_Map[addr>>12] & 0x30)) // non-bufferable
{ {
WriteBufferCheck<2>(); WriteBufferCheck<2>();
QueueFunction(&ARMv5::DWrite32S_3);
}
else
{
WriteBufferWrite(val, 3, addr);
STRRegs &= ~1<<reg;
}
}
void ARMv5::DWrite32S_3()
{
u8 reg = __builtin_ctz(STRRegs);
u32 addr = FetchAddr[reg];
u32 val = STRVal[reg];
// bursts cannot cross a 1kb boundary // bursts cannot cross a 1kb boundary
if (addr & 0x3FF) // s if (addr & 0x3FF) // s
@ -3005,14 +3191,6 @@ void ARMv5::DWrite32S_2()
BusWrite32(addr, val); BusWrite32(addr, val);
} }
} }
}
else
{
WriteBufferWrite(val, 3, addr);
DataRegion = Mem9_Null;
NDS.ARM9Timestamp += DataCycles = 1;
WBDelay = NDS.ARM9Timestamp + 1;
}
STRRegs &= ~1<<reg; STRRegs &= ~1<<reg;
} }

View File

@ -1054,6 +1054,91 @@ void NDS::MainRAMHandleARM9()
} }
break; break;
} }
case MainRAMType::WBDrain:
{
if (!ARM9.WriteBufferHandle<WBMode::Force>()) return;
if ((ARM9.WBWritePointer == 16) && !ARM9.WBWriting)
{
memset(&ARM9.MRTrack, 0, sizeof(ARM9.MRTrack));
ConTSLock = false;
}
break;
}
case MainRAMType::WBWrite:
{
if (!ARM9.WriteBufferHandle<WBMode::Check>()) return;
if (ARM9.WBWritePointer == ARM9.WBFillPointer)
{
if (!ARM9.WriteBufferHandle<WBMode::WaitEntry>()) return;
}
else if (ARM9.WBWritePointer == 16)
{
ARM9.WBWritePointer = 0;
if (!ARM9.WBWriting)
{
u64 ts = (ARM9Timestamp + 1 + ((1<<ARM9ClockShift)-1)) & ~((1<<ARM9ClockShift)-1);
if (ARM9.WBTimestamp < ts) ARM9.WBTimestamp = ts;
}
}
ARM9.WriteBufferFifo[ARM9.WBFillPointer] = ARM9.WBValQueued[ARM9.MRTrack.Progress];
ARM9.storeaddr[ARM9.WBFillPointer] = ARM9.WBAddrQueued[ARM9.MRTrack.Progress];
ARM9.WBFillPointer = (ARM9.WBFillPointer + 1) & 0xF;
if ((ARM9.WBValQueued[ARM9.MRTrack.Progress] >> 61) != 4)
{
ARM9Timestamp += ARM9.DataCycles = 1;
ARM9.WBDelay = ARM9Timestamp + 1;
}
ARM9.MRTrack.Progress++;
if (ARM9.MRTrack.Progress >= ARM9.MRTrack.Var)
{
memset(&ARM9.MRTrack, 0, sizeof(ARM9.MRTrack));
ConTSLock = false;
}
break;
}
case MainRAMType::WBCheck:
{
if (!ARM9.WriteBufferHandle<WBMode::Check>()) return;
memset(&ARM9.MRTrack, 0, sizeof(ARM9.MRTrack));
ConTSLock = false;
break;
}
case MainRAMType::WBWaitRead:
{
if (!ARM9.WriteBufferHandle<WBMode::Check>()) return;
if (ARM9Timestamp >= ARM9.WBInitialTS)
{
if (!ARM9.WriteBufferHandle<WBMode::SingleBurst>()) return;
if (ARM9Timestamp < ARM9.WBReleaseTS) ARM9Timestamp = ARM9.WBReleaseTS;
}
memset(&ARM9.MRTrack, 0, sizeof(ARM9.MRTrack));
ConTSLock = false;
break;
}
case MainRAMType::WBWaitWrite:
{
if (!ARM9.WriteBufferHandle<WBMode::Check>()) return;
if (!ARM9.WriteBufferHandle<WBMode::SingleBurst>()) return;
if (ARM9Timestamp < ARM9.WBReleaseTS) ARM9Timestamp = ARM9.WBReleaseTS;
memset(&ARM9.MRTrack, 0, sizeof(ARM9.MRTrack));
ConTSLock = false;
break;
}
} }
} }
@ -1121,12 +1206,12 @@ void NDS::MainRAMHandle()
{ {
if (!ConTSLock) if (!ConTSLock)
{ {
if (ARM9.MRTrack.Type != MainRAMType::Null) ConTSLock = true;
if (ARM9.MRTrack.Type > MainRAMType::WriteBufferCmds)
A9ContentionTS = (ARM9.WBTimestamp + ((1<<ARM9ClockShift)-1)) >> ARM9ClockShift;
else
A9ContentionTS = (ARM9Timestamp + ((1<<ARM9ClockShift)-1)) >> ARM9ClockShift; A9ContentionTS = (ARM9Timestamp + ((1<<ARM9ClockShift)-1)) >> ARM9ClockShift;
if (ARM9.MRTrack.Type != MainRAMType::Null)
{
ConTSLock = true;
if (A9ContentionTS < MainRAMTimestamp) A9ContentionTS = MainRAMTimestamp;
}
} }
if (A7PRIORITY) if (A7PRIORITY)
@ -1261,11 +1346,11 @@ u32 NDS::RunFrame()
} }
else if (ARM9.MRTrack.Type == MainRAMType::Null) else if (ARM9.MRTrack.Type == MainRAMType::Null)
{ {
if (ARM9.abt) ARM9Timestamp = ARM9Target; //if (ARM9.abt) ARM9Timestamp = ARM9Target;
ARM9.Execute<cpuMode>(); ARM9.Execute<cpuMode>();
} }
//printf("MAIN LOOP: 9 %lli %08X %08llX 7 %lli %08X %08llX %i %08X\n", ARM9Timestamp>>ARM9ClockShift, ARM9.PC, ARM9.CurInstr, ARM7Timestamp, ARM7.R[15], ARM7.CurInstr, IME[1], IE[1]); //printf("MAIN LOOP: 9 %lli %08X %08llX %i 7 %lli %08X %08llX %i %i %08X\n", ARM9Timestamp>>ARM9ClockShift, ARM9.PC, ARM9.CurInstr, (u8)ARM9.MRTrack.Type, ARM7Timestamp, ARM7.R[15], ARM7.CurInstr, (u8)ARM7.MRTrack.Type, IME[1], IE[1]);
MainRAMHandle(); MainRAMHandle();
@ -1326,6 +1411,7 @@ u32 NDS::RunFrame()
SPU.TransferOutput(); SPU.TransferOutput();
break; break;
} }
//printf("MAIN LOOP: 9 %lli %08X %08llX %i 7 %lli %08X %08llX %i %i %08X\n", ARM9Timestamp>>ARM9ClockShift, ARM9.PC, ARM9.CurInstr, (u8)ARM9.MRTrack.Type, ARM7Timestamp, ARM7.R[15], ARM7.CurInstr, (u8)ARM7.MRTrack.Type, IME[1], IE[1]);
// In the context of TASes, frame count is traditionally the primary measure of emulated time, // In the context of TASes, frame count is traditionally the primary measure of emulated time,
// so it needs to be tracked even if NDS is powered off. // so it needs to be tracked even if NDS is powered off.