implement write buffer
This commit is contained in:
parent
d14c5ea246
commit
b40c6bc41d
19
src/ARM.cpp
19
src/ARM.cpp
|
@ -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])();
|
||||||
|
|
||||||
|
|
45
src/ARM.h
45
src/ARM.h
|
@ -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);
|
||||||
|
|
468
src/CP15.cpp
468
src/CP15.cpp
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
100
src/NDS.cpp
100
src/NDS.cpp
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue