diff --git a/src/ARM.cpp b/src/ARM.cpp index a7f19414..b2b10c63 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -198,15 +198,12 @@ void ARM::Reset() BreakReq = false; #endif - MainRAMTimestamp = 0; - memset(&MRTrack, 0, sizeof(MRTrack)); FuncQueueFill = 0; FuncQueueEnd = 0; FuncQueueProg = 0; FuncQueueActive = false; - ExecuteCycles = 0; // zorp JumpTo(ExceptionBase); @@ -748,6 +745,12 @@ void ARMv5::StartExec() else AddCycles_C(); } + QueueFunction(&ARMv5::WBCheck_2); +} + +void ARMv5::WBCheck_2() +{ + WriteBufferCheck(); } template @@ -756,7 +759,7 @@ void ARMv5::Execute() if constexpr (mode == CPUExecuteMode::InterpreterGDB) GdbCheckB(); - if (Halted) + if (!FuncQueueActive && Halted) { if (Halted == 2) { @@ -777,7 +780,6 @@ void ARMv5::Execute() else { NDS.ARM9Timestamp = NDS.ARM9Target; - WriteBufferCheck(); return; } } @@ -828,7 +830,7 @@ void ARMv5::Execute() if constexpr (mode == CPUExecuteMode::InterpreterGDB) 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])(); @@ -882,7 +884,6 @@ void ARMv5::Execute() //NDS.ARM9Timestamp += Cycles; //Cycles = 0; } - WriteBufferCheck(); if (Halted == 2) Halted = 0; @@ -938,7 +939,7 @@ void ARMv4::Execute() if constexpr (mode == CPUExecuteMode::InterpreterGDB) GdbCheckB(); - if (Halted) + if (!FuncQueueActive && Halted) { if (Halted == 2) { @@ -1008,8 +1009,8 @@ void ARMv4::Execute() if constexpr (mode == CPUExecuteMode::InterpreterGDB) 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])(); if (FuncQueueActive) diff --git a/src/ARM.h b/src/ARM.h index 737b196f..7eb8e842 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -21,6 +21,7 @@ #include #include +#include #include "types.h" #include "MemRegion.h" @@ -54,12 +55,26 @@ enum class CPUExecuteMode : u32 #endif }; +enum class WBMode +{ + Check, + Force, + SingleBurst, + WaitEntry, +}; + enum class MainRAMType : u8 { Null = 0, Fetch, ICacheStream, 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 @@ -214,7 +229,6 @@ public: MemRegion CodeMem; - u64 MainRAMTimestamp; MainRAMTrackers MRTrack; u32 BranchAddr; @@ -493,7 +507,7 @@ public: */ void ICacheInvalidateAll(); - template inline bool WriteBufferHandle(); + template bool WriteBufferHandle(); template void WriteBufferCheck(); void WriteBufferWrite(u32 val, u8 flag, u32 addr = 0); void WriteBufferDrain(); @@ -724,18 +738,35 @@ public: void JumpTo_3B(); void JumpTo_3C(); void JumpTo_4(); + void CodeRead32_2(); + void ICacheLookup_2(); void DAbortHandle(); void DCacheFin8(); void DRead8_2(); + void DRead8_3(); void DCacheFin16(); void DRead16_2(); + void DRead16_3(); void DCacheFin32(); void DRead32_2(); + void DRead32_3(); void DRead32S_2(); + void DRead32S_3(); void DWrite8_2(); + void DWrite8_3(); void DWrite16_2(); + void DWrite16_3(); void DWrite32_2(); + void DWrite32_3(); 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 HandleInterlocksExecute_2(); void HandleInterlocksMemory_2(); @@ -806,11 +837,14 @@ public: u64 ITCMTimestamp; u64 TimestampMemory; - void (ARMv5::*FuncQueue[31])(void); + void (ARMv5::*FuncQueue[32])(void); + void (ARMv5::*DelayedQueue)(void); u32 PC; bool NullFetch; bool Store; s8 ITCMDelay; + u32 QueuedDCacheLine; + u32 CP15Queue; u8 ILCurrReg; u8 ILPrevReg; @@ -833,7 +867,9 @@ public: u8 WBWriting; // whether the buffer is actively trying to perform a write 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) + u32 WBAddrQueued[40]; 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 WBTimestamp; // current timestamp //u64 WBMainRAMDelay; // timestamp used to emulate the delay before the next main ram write can begin @@ -870,8 +906,7 @@ public: template void Execute(); - Platform::FileHandle* filey; - void (ARMv4::*FuncQueue[31])(void); + void (ARMv4::*FuncQueue[32])(void); bool Nonseq; void CodeRead16(u32 addr); diff --git a/src/CP15.cpp b/src/CP15.cpp index e15fb41b..979cbb38 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -454,6 +454,18 @@ bool ARMv5::ICacheLookup(const u32 addr) if (CP15BISTTestStateRegister & CP15_BIST_TR_DISABLE_ICACHE_LINEFILL) [[unlikely]] 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; if (CP15Control & CP15_CACHE_CR_ROUNDROBIN) [[likely]] @@ -491,8 +503,6 @@ bool ARMv5::ICacheLookup(const u32 addr) if (NDS.ARM9Timestamp < time) NDS.ARM9Timestamp = time; } - WriteBufferDrain(); - ICacheTags[line] = tag | (line & (ICACHE_SETS-1)) | CACHE_FLAG_VALID; // timing logic @@ -544,7 +554,6 @@ bool ARMv5::ICacheLookup(const u32 addr) } Store = false; DataRegion = Mem9_Null; - return true; } void ARMv5::ICacheInvalidateByAddr(const u32 addr) @@ -658,6 +667,7 @@ bool ARMv5::DCacheLookup(const u32 addr) 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); RetVal = cacheLine[(addr & (DCACHE_LINELENGTH -1)) >> 2]; + (this->*DelayedQueue)(); 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") if (CP15BISTTestStateRegister & CP15_BIST_TR_DISABLE_DCACHE_LINEFILL) [[unlikely]] 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; if (CP15Control & CP15_CACHE_CR_ROUNDROBIN) [[likely]] @@ -701,19 +722,26 @@ bool ARMv5::DCacheLookup(const u32 addr) u8 minSet = DCacheLockDown & (DCACHE_SETS-1); line = line | minSet; } - } + } line += id; - u32* ptr = (u32 *)&DCache[line << DCACHE_LINELENGTH_LOG2]; - - WriteBufferDrain(); // checkme? - #if !DISABLE_CACHEWRITEBACK // Before we fill the cacheline, we need to write back dirty content // Datacycles will be incremented by the required cycles to do so DCacheClearByASetAndWay(line & (DCACHE_SETS-1), line >> DCACHE_SETS_LOG2); #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; // timing logic @@ -722,10 +750,12 @@ bool ARMv5::DCacheLookup(const u32 addr) { MRTrack.Type = MainRAMType::DCacheStream; MRTrack.Var = line; - FetchAddr[16] = addr; + if (CP15BISTTestStateRegister & CP15_BIST_TR_DISABLE_DCACHE_STREAMING) [[unlikely]] DCacheStreamPtr = 7; else DCacheStreamPtr = (addr & 0x1F) / 4; + + QueueFunction(DelayedQueue); } else { @@ -773,8 +803,8 @@ bool ARMv5::DCacheLookup(const u32 addr) } } RetVal = ptr[(addr & (DCACHE_LINELENGTH-1)) >> 2]; + (this->*DelayedQueue)(); } - return true; } 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[2], 3, tag+0x08); 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 { @@ -1117,7 +1147,7 @@ void ARMv5::DCacheClearByASetAndWay(const u8 cacheSet, const u8 cacheLine) WriteBufferWrite(ptr[5], 3, tag+0x14); WriteBufferWrite(ptr[6], 3, tag+0x18); WriteBufferWrite(ptr[7], 3, tag+0x1C); - NDS.ARM9Timestamp += 4; + //NDS.ARM9Timestamp += 4; } DCacheTags[index] &= ~(CACHE_FLAG_DIRTY_LOWERHALF | CACHE_FLAG_DIRTY_UPPERHALF); #endif @@ -1128,135 +1158,180 @@ bool ARMv5::IsAddressDCachable(const u32 addr) const return PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEABLE; } -template -inline bool ARMv5::WriteBufferHandle() +#define A9WENTLAST (!NDS.MainRAMLastAccess) +#define A7WENTLAST ( NDS.MainRAMLastAccess) +#define A9LAST false +#define A7LAST true +#define A9PRIORITY !(NDS.ExMemCnt[0] & 0x8000) +#define A7PRIORITY (NDS.ExMemCnt[0] & 0x8000) + +template +bool ARMv5::WriteBufferHandle() { - // handle write buffer writes - if (WBWriting) + while (true) { - // look up timings - // TODO: handle interrupted bursts? - u32 cycles; - switch (WBCurVal >> 61) + if (WBWriting) { - case 0: + if ((mode == WBMode::Check) && ((NDS.A9ContentionTS << NDS.ARM9ClockShift) > NDS.ARM9Timestamp)) return true; + // look up timings + // TODO: handle interrupted bursts? + u32 cycles; + switch (WBCurVal >> 61) { - if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) + case 0: { - cycles = (4 << NDS.ARM9ClockShift) - 1; + if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) + { + 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] - 5) >> NDS.ARM9ClockShift; // todo: twl timings + break; } - else cycles = MemTimings[WBCurAddr>>14][0] - 6; // todo: twl timings - break; - } - case 1: - { - if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) + case 1: { - cycles = (3 << NDS.ARM9ClockShift) - 1; + if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) + { + 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] - 5) >> NDS.ARM9ClockShift; // todo: twl timings + break; } - else cycles = MemTimings[WBCurAddr>>14][0] - 6; // todo: twl timings - break; - } - case 2: - { - if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) + case 3: { - cycles = (4 << NDS.ARM9ClockShift) - 1; + 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: + { + if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) + { + 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] - 5) >> NDS.ARM9ClockShift; // todo: twl timings + break; } - else cycles = MemTimings[WBCurAddr>>14][1] - 6; // todo: twl timings - break; } - case 3: + + NDS.A9ContentionTS += cycles; + WBReleaseTS = (NDS.A9ContentionTS << NDS.ARM9ClockShift) - 1; + if (NDS.ARM9Regions[WBCurAddr>>14] != Mem9_MainRAM && ((WBCurVal >> 61) != 3)) { - cycles = MemTimings[WBCurAddr>>14][2]; - break; + NDS.A9ContentionTS += 1; + WBTimestamp = WBReleaseTS + 2; // todo: twl timings } + else + { + WBTimestamp = WBReleaseTS; + } + if (WBWritePointer != 16 && (WriteBufferFifo[WBWritePointer] >> 61) != 3) WBInitialTS = WBTimestamp; + + switch (WBCurVal >> 61) + { + case 0: // byte + BusWrite8 (WBCurAddr, WBCurVal); + break; + case 1: // halfword + BusWrite16(WBCurAddr, WBCurVal); + break; + case 2: // word + case 3: + BusWrite32(WBCurAddr, WBCurVal); + 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; + } + + WBLastRegion = NDS.ARM9Regions[WBCurAddr>>14]; + WBWriting = false; + if ((mode == WBMode::SingleBurst) && ((WriteBufferFifo[WBWritePointer] >> 61) != 3)) return true; } - if ((NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) && (((MainRAMTimestamp + ((1< WBTimestamp)) - WBTimestamp = (MainRAMTimestamp + ((1< NDS.ARM9Timestamp) return true; - if ( force && ts > NDS.ARM9Timestamp) + // attempt to drain write buffer + if ((WriteBufferFifo[WBWritePointer] >> 61) != 4) // not an address { - NDS.ARM9Timestamp = ts; - } + if (WBInitialTS > NDS.ARM9Timestamp) + { + if (mode == WBMode::Check) return true; + else NDS.ARM9Timestamp = WBInitialTS; + } - if ((WBCurVal >> 61) != 3) - { - WBReleaseTS = WBTimestamp = (ts + ((1<>14] == Mem9_MainRAM) MainRAMTimestamp = ts + ((((WBCurVal >> 61) == 0) ? 4 : 5) << NDS.ARM9ClockShift); - else WBTimestamp += 2; // todo: twl timings + //if ((WriteBufferFifo[WBWritePointer] >> 61) == 3) WBCurAddr+=4; // TODO + //if (storeaddr[WBWritePointer] != WBCurAddr) printf("MISMATCH: %08X %08X\n", storeaddr[WBWritePointer], WBCurAddr); + + WBCurAddr = storeaddr[WBWritePointer]; + WBCurVal = WriteBufferFifo[WBWritePointer]; + WBWriting = true; } else { - WBTimestamp = ts; - if (NDS.ARM9Regions[WBCurAddr>>14] == Mem9_MainRAM) MainRAMTimestamp += 2 << NDS.ARM9ClockShift; + //WBCurAddr = (u32)WriteBufferFifo[WBWritePointer]; // TODO } - WBInitialTS = WBTimestamp; - - switch (WBCurVal >> 61) + + WBWritePointer = (WBWritePointer + 1) & 0xF; + if (WBWritePointer == WBFillPointer) { - case 0: // byte - BusWrite8 (WBCurAddr, WBCurVal); - break; - case 1: // halfword - BusWrite16(WBCurAddr, WBCurVal); - break; - case 2: // word - case 3: - BusWrite32(WBCurAddr, WBCurVal); - break; - default: // invalid - Platform::Log(Platform::LogLevel::Warn, "WHY ARE WE TRYING TO WRITE AN ADDRESS VIA THE WRITE BUFFER! PANIC!!!\n", (u8)(WBCurVal >> 61)); - break; + WBWritePointer = 16; + WBFillPointer = 0; } - - WBLastRegion = NDS.ARM9Regions[WBCurAddr>>14]; - WBWriting = false; - if ((force == 2) && ((WriteBufferFifo[WBWritePointer] >> 61) != 3)) return true; + if ((mode == WBMode::WaitEntry) && (WBWritePointer != WBFillPointer)) return true; } - - // check if write buffer is empty - if (WBWritePointer == 16) return true; - // attempt to drain write buffer - if ((WriteBufferFifo[WBWritePointer] >> 61) != 4) // not an address - { - if (NDS.ARM9Regions[storeaddr[WBWritePointer]>>14] == Mem9_MainRAM) // main ram handling - { - if (!force && (WBTimestamp > NDS.ARM9Timestamp)) return true; - if ( force && (WBTimestamp > NDS.ARM9Timestamp)) - NDS.ARM9Timestamp = WBTimestamp; - - WBTimestamp = std::max(MainRAMTimestamp, WBTimestamp); - } - - WBTimestamp = (WBTimestamp + ((1<(); +template bool ARMv5::WriteBufferHandle(); +template bool ARMv5::WriteBufferHandle(); +template bool ARMv5::WriteBufferHandle(); + +#undef A9WENTLAST +#undef A7WENTLAST +#undef A9LAST +#undef A7LAST +#undef A9PRIORITY +#undef A7PRIORITY template 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 if constexpr (next == 1 || next == 3) // check if the next write is occuring @@ -1273,7 +1348,7 @@ void ARMv5::WriteBufferCheck() { //if (NDS.ARM9Timestamp >= WBInitialTS) while(!WriteBufferHandle<2>()); - } + }*/ } template void ARMv5::WriteBufferCheck<3>(); template void ARMv5::WriteBufferCheck<2>(); @@ -1282,7 +1357,26 @@ template void ARMv5::WriteBufferCheck<0>(); 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 WriteBufferHandle<1>(); @@ -1302,12 +1396,14 @@ void ARMv5::WriteBufferWrite(u32 val, u8 flag, u32 addr) WriteBufferFifo[WBFillPointer] = val | (u64)flag << 61; storeaddr[WBFillPointer] = addr; - WBFillPointer = (WBFillPointer + 1) & 0xF; + WBFillPointer = (WBFillPointer + 1) & 0xF;*/ } 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) @@ -1561,6 +1657,7 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0x704: case 0x782: + //WriteBufferDrain(); // checkme Halt(1); return; @@ -1578,7 +1675,7 @@ void ARMv5::CP15Write(u32 id, u32 val) ICacheInvalidateByAddr(val); //Halt(255); return; - case 0x752: + /*case 0x752: // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { @@ -1592,7 +1689,7 @@ void ARMv5::CP15Write(u32 id, u32 val) } //Halt(255); return; - + */ case 0x760: // requires priv mode or causes UNKNOWN INSTRUCTION exception @@ -1612,7 +1709,7 @@ void ARMv5::CP15Write(u32 id, u32 val) DCacheInvalidateByAddr(val); //printf("inval data cache SI\n"); return; - case 0x762: + /*case 0x762: // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { @@ -1625,15 +1722,15 @@ void ARMv5::CP15Write(u32 id, u32 val) DCacheInvalidateBySetAndWay(cacheSet, cacheLine); } return; - - case 0x770: + */ + /*case 0x770: // invalidate both caches // can be called from user and privileged ICacheInvalidateAll(); DCacheInvalidateAll(); break; - - case 0x7A0: + */ + /*case 0x7A0: // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { @@ -1641,15 +1738,16 @@ void ARMv5::CP15Write(u32 id, u32 val) } //Log(LogLevel::Debug,"clean data cache\n"); DCacheClearAll(); - return; + return;*/ case 0x7A1: // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) { return ARMInterpreter::A_UNK(this); } - //Log(LogLevel::Debug,"clean data cache MVA\n"); - DCacheClearByAddr(val); + //Log(LogLevel::Debug,"clean data cache MVA\n");= + CP15Queue = val; + QueueFunction(&ARMv5::DCClearAddr_2); return; case 0x7A2: //Log(LogLevel::Debug,"clean data cache SET/WAY\n"); @@ -1660,9 +1758,8 @@ void ARMv5::CP15Write(u32 id, u32 val) } else { // Cache invalidat by line number and set number - u8 cacheSet = val >> (32 - DCACHE_SETS_LOG2) & (DCACHE_SETS -1); - u8 cacheLine = (val >> DCACHE_LINELENGTH_LOG2) & (DCACHE_LINESPERSET -1); - DCacheClearByASetAndWay(cacheSet, cacheLine); + CP15Queue = val; + QueueFunction(&ARMv5::DCClearSetWay_2); } return; case 0x7A3: @@ -1678,7 +1775,7 @@ void ARMv5::CP15Write(u32 id, u32 val) case 0x7A4: // Can be used in user and privileged mode // Drain Write Buffer: Stall until all write back completed - WriteBufferDrain(); + QueueFunction(&ARMv5::WriteBufferDrain); return; case 0x7D1: @@ -1695,7 +1792,7 @@ void ARMv5::CP15Write(u32 id, u32 val) //ICacheLookup((val & ~0x03) | 0x1C); TODO: REIMPLEMENT WITH DEFERENCE return; - case 0x7E0: + /*case 0x7E0: //Log(LogLevel::Debug,"clean & invalidate data cache\n"); // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) @@ -1704,7 +1801,7 @@ void ARMv5::CP15Write(u32 id, u32 val) } DCacheClearAll(); DCacheInvalidateAll(); - return; + return;*/ case 0x7E1: //Log(LogLevel::Debug,"clean & invalidate data cache MVA\n"); // requires priv mode or causes UNKNOWN INSTRUCTION exception @@ -1712,8 +1809,8 @@ void ARMv5::CP15Write(u32 id, u32 val) { return ARMInterpreter::A_UNK(this); } - DCacheClearByAddr(val); - DCacheInvalidateByAddr(val); + CP15Queue = val; + QueueFunction(&ARMv5::DCClearInvalidateAddr_2); return; case 0x7E2: //Log(LogLevel::Debug,"clean & invalidate data cache SET/WAY\n"); @@ -1724,13 +1821,11 @@ void ARMv5::CP15Write(u32 id, u32 val) } else { // Cache invalidat by line number and set number - 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); + CP15Queue = val; + QueueFunction(&ARMv5::DCClearInvalidateSetWay_2); } return; - + case 0x900: // requires priv mode or causes UNKNOWN INSTRUCTION exception if (PU_Map != PU_PrivMap) @@ -2023,6 +2118,35 @@ u32 ARMv5::CP15Read(const u32 id) const 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. // TODO: later on, handle PU @@ -2070,16 +2194,24 @@ void ARMv5::CodeRead32(u32 addr) u64 time = DCacheStreamTimes[6] - 6; // checkme: minus 6? if (NDS.ARM9Timestamp < time) NDS.ARM9Timestamp = time; } - - u8 cycles = MemTimings[addr >> 14][1]; if (PU_Map[addr>>12] & 0x30) WriteBufferDrain(); else WriteBufferCheck<3>(); + FetchAddr[16] = addr; + QueueFunction(&ARMv5::CodeRead32_2); +} + +void ARMv5::CodeRead32_2() +{ + u32 addr = FetchAddr[16]; + NDS.ARM9Timestamp = NDS.ARM9Timestamp + ((1<> 14][1]; + if ((addr >> 24) == 0x02) { FetchAddr[16] = addr; @@ -2180,11 +2312,8 @@ void ARMv5::DRead8_2() { if (IsAddressDCachable(addr)) { - if (DCacheLookup(addr)) - { - QueueFunction(&ARMv5::DCacheFin8); - return; - } + DelayedQueue = &ARMv5::DCacheFin8; + if (DCacheLookup(addr)) return; } } #endif @@ -2202,6 +2331,15 @@ void ARMv5::DRead8_2() else 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<> 24) == 0x02) @@ -2288,11 +2426,8 @@ void ARMv5::DRead16_2() { if (IsAddressDCachable(addr)) { - if (DCacheLookup(addr)) - { - QueueFunction(&ARMv5::DCacheFin16); - return; - } + DelayedQueue = &ARMv5::DCacheFin16; + if (DCacheLookup(addr)) return; } } #endif @@ -2310,6 +2445,15 @@ void ARMv5::DRead16_2() else 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<> 24) == 0x02) @@ -2397,11 +2541,8 @@ void ARMv5::DRead32_2() { if (IsAddressDCachable(addr)) { - if (DCacheLookup(addr)) - { - QueueFunction(&ARMv5::DCacheFin32); - return; - } + DelayedQueue = &ARMv5::DCacheFin32; + if (DCacheLookup(addr)) return; } } #endif @@ -2419,6 +2560,15 @@ void ARMv5::DRead32_2() else 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<> 24) == 0x02) @@ -2492,11 +2642,8 @@ void ARMv5::DRead32S_2() { if (IsAddressDCachable(addr)) { - if (DCacheLookup(addr)) - { - QueueFunction(&ARMv5::DCacheFin32); - return; - } + DelayedQueue = &ARMv5::DCacheFin32; + if (DCacheLookup(addr)) return; } } #endif @@ -2514,6 +2661,15 @@ void ARMv5::DRead32S_2() else 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<>12] & (0x30))) { WriteBufferCheck<2>(); - - NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<> 24) == 0x02) - { - MRTrack.Type = MainRAMType::Fetch; - MRTrack.Var = MRWrite | MR8; - MRTrack.Progress = reg; - } - else - { - NDS.ARM9Timestamp += MemTimings[addr >> 14][0]; - DataCycles = 3<>14]; - - if (WBTimestamp < ((NDS.ARM9Timestamp + ((1<> 24) == 0x02) + { + MRTrack.Type = MainRAMType::Fetch; + MRTrack.Var = MRWrite | MR8; + MRTrack.Progress = reg; + } + else + { + NDS.ARM9Timestamp += MemTimings[addr >> 14][0]; + DataCycles = 3<>14]; + + if (WBTimestamp < ((NDS.ARM9Timestamp + ((1<>12] & 0x30)) { WriteBufferCheck<2>(); - - NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<> 24) == 0x02) - { - MRTrack.Type = MainRAMType::Fetch; - MRTrack.Var = MRWrite | MR16; - MRTrack.Progress = reg; - } - else - { - NDS.ARM9Timestamp += MemTimings[addr >> 14][0]; - DataCycles = NDS.ARM9ClockShift; - DataRegion = NDS.ARM9Regions[addr>>14]; - - if (WBTimestamp < ((NDS.ARM9Timestamp + ((1<> 24) == 0x02) + { + MRTrack.Type = MainRAMType::Fetch; + MRTrack.Var = MRWrite | MR16; + MRTrack.Progress = reg; + } + else + { + NDS.ARM9Timestamp += MemTimings[addr >> 14][0]; + DataCycles = NDS.ARM9ClockShift; + DataRegion = NDS.ARM9Regions[addr>>14]; + + if (WBTimestamp < ((NDS.ARM9Timestamp + ((1<>12] & 0x30)) { WriteBufferCheck<2>(); - - NDS.ARM9Timestamp = (NDS.ARM9Timestamp + ((1<> 24) == 0x02) - { - MRTrack.Type = MainRAMType::Fetch; - MRTrack.Var = MRWrite | MR32; - MRTrack.Progress = reg; - } - else - { - NDS.ARM9Timestamp += MemTimings[addr >> 14][1]; - DataCycles = 3<>14]; - - if (WBTimestamp < ((NDS.ARM9Timestamp + ((1<> 24) == 0x02) + { + MRTrack.Type = MainRAMType::Fetch; + MRTrack.Var = MRWrite | MR32; + MRTrack.Progress = reg; + } + else + { + NDS.ARM9Timestamp += MemTimings[addr >> 14][1]; + DataCycles = 3<>14]; + + if (WBTimestamp < ((NDS.ARM9Timestamp + ((1<>12] & 0x30)) // non-bufferable { WriteBufferCheck<2>(); - - // bursts cannot cross a 1kb boundary - if (addr & 0x3FF) // s - { - if ((addr >> 24) == 0x02) - { - MRTrack.Type = MainRAMType::Fetch; - MRTrack.Var = MRWrite | MR32 | MRSequential; - MRTrack.Progress = reg; - } - else - { - NDS.ARM9Timestamp += DataCycles = MemTimings[addr>>14][2]; - DataRegion = NDS.ARM9Regions[addr>>14]; - - if (WBTimestamp < ((NDS.ARM9Timestamp + ((1<> 24) == 0x02) - { - MRTrack.Type = MainRAMType::Fetch; - MRTrack.Var = MRWrite | MR32; - MRTrack.Progress = reg; - } - else - { - NDS.ARM9Timestamp += MemTimings[addr>>14][1]; - DataCycles = 3 << NDS.ARM9ClockShift; - DataRegion = NDS.ARM9Regions[addr>>14]; - - if (WBTimestamp < ((NDS.ARM9Timestamp + ((1<> 24) == 0x02) + { + MRTrack.Type = MainRAMType::Fetch; + MRTrack.Var = MRWrite | MR32 | MRSequential; + MRTrack.Progress = reg; + } + else + { + NDS.ARM9Timestamp += DataCycles = MemTimings[addr>>14][2]; + DataRegion = NDS.ARM9Regions[addr>>14]; + + if (WBTimestamp < ((NDS.ARM9Timestamp + ((1<> 24) == 0x02) + { + MRTrack.Type = MainRAMType::Fetch; + MRTrack.Var = MRWrite | MR32; + MRTrack.Progress = reg; + } + else + { + NDS.ARM9Timestamp += MemTimings[addr>>14][1]; + DataCycles = 3 << NDS.ARM9ClockShift; + DataRegion = NDS.ARM9Regions[addr>>14]; + + if (WBTimestamp < ((NDS.ARM9Timestamp + ((1<()) return; + + if ((ARM9.WBWritePointer == 16) && !ARM9.WBWriting) + { + memset(&ARM9.MRTrack, 0, sizeof(ARM9.MRTrack)); + ConTSLock = false; + } + break; + } + + case MainRAMType::WBWrite: + { + if (!ARM9.WriteBufferHandle()) return; + + if (ARM9.WBWritePointer == ARM9.WBFillPointer) + { + if (!ARM9.WriteBufferHandle()) return; + } + else if (ARM9.WBWritePointer == 16) + { + ARM9.WBWritePointer = 0; + if (!ARM9.WBWriting) + { + u64 ts = (ARM9Timestamp + 1 + ((1<> 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()) return; + + memset(&ARM9.MRTrack, 0, sizeof(ARM9.MRTrack)); + ConTSLock = false; + break; + } + + case MainRAMType::WBWaitRead: + { + if (!ARM9.WriteBufferHandle()) return; + + if (ARM9Timestamp >= ARM9.WBInitialTS) + { + if (!ARM9.WriteBufferHandle()) return; + if (ARM9Timestamp < ARM9.WBReleaseTS) ARM9Timestamp = ARM9.WBReleaseTS; + } + + memset(&ARM9.MRTrack, 0, sizeof(ARM9.MRTrack)); + ConTSLock = false; + break; + } + + case MainRAMType::WBWaitWrite: + { + if (!ARM9.WriteBufferHandle()) return; + + if (!ARM9.WriteBufferHandle()) 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) { - A9ContentionTS = (ARM9Timestamp + ((1<> ARM9ClockShift; - if (ARM9.MRTrack.Type != MainRAMType::Null) - { - ConTSLock = true; - if (A9ContentionTS < MainRAMTimestamp) A9ContentionTS = MainRAMTimestamp; - } + if (ARM9.MRTrack.Type != MainRAMType::Null) ConTSLock = true; + + if (ARM9.MRTrack.Type > MainRAMType::WriteBufferCmds) + A9ContentionTS = (ARM9.WBTimestamp + ((1<> ARM9ClockShift; + else + A9ContentionTS = (ARM9Timestamp + ((1<> ARM9ClockShift; } if (A7PRIORITY) @@ -1261,14 +1346,14 @@ u32 NDS::RunFrame() } else if (ARM9.MRTrack.Type == MainRAMType::Null) { - if (ARM9.abt) ARM9Timestamp = ARM9Target; + //if (ARM9.abt) ARM9Timestamp = ARM9Target; ARM9.Execute(); } - //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(); - + RunTimers(0); GPU.GPU3D.Run(); @@ -1326,6 +1411,7 @@ u32 NDS::RunFrame() SPU.TransferOutput(); 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, // so it needs to be tracked even if NDS is powered off.