diff --git a/src/ARM.cpp b/src/ARM.cpp index d547174e..7072978d 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -208,6 +208,9 @@ void ARMv5::Reset() Store = false; InterlockMask = 0; + WBWritePointer = 16; + WBFillPointer = 0; + ARM::Reset(); } @@ -609,6 +612,7 @@ void ARMv5::Execute() else { NDS.ARM9Timestamp = NDS.ARM9Target; + WriteBufferCheck(); return; } } @@ -742,6 +746,7 @@ void ARMv5::Execute() //NDS.ARM9Timestamp += Cycles; //Cycles = 0; } + WriteBufferCheck(); if (Halted == 2) Halted = 0; @@ -757,7 +762,7 @@ void ARMv4::Execute() { if constexpr (mode == CPUExecuteMode::InterpreterGDB) GdbCheckB(); - + if (Halted) { if (Halted == 2) diff --git a/src/ARM.h b/src/ARM.h index a31ead4e..76d356fb 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -292,11 +292,13 @@ public: void AddCycles_CDI() override { AddCycles_MW(DataCycles); + DataCycles = 0; } void AddCycles_CD() override { AddCycles_MW(DataCycles); + DataCycles = 0; } void GetCodeMemRegion(const u32 addr, MemRegion* region); @@ -400,6 +402,10 @@ public: * Nothing */ void ICacheInvalidateAll(); + + void WriteBufferCheck(); + void WriteBufferWrite(u32 val, u8 flag, u8 cycles, u32 addr = 0); + void WriteBufferDrain(); /** * @brief Invalidates the instruction cacheline containing @@ -675,6 +681,13 @@ public: bool Store; u16 InterlockMask; + u8 WBWritePointer; + u8 WBFillPointer; + u32 WBAddr; // current working address for the write buffer + u32 storeaddr[16]; // debugging + u64 WBCycles[16]; // timestamp each write will complete + u64 WriteBufferFifo[16]; // 0-31: value | 62-63: 0 byte, 1 half, 2 word, 3 addr + #ifdef GDBSTUB_ENABLED u32 ReadMem(u32 addr, int size) override; void WriteMem(u32 addr, int size, u32 v) override; diff --git a/src/CP15.cpp b/src/CP15.cpp index 2cc502a8..e213e112 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -206,13 +206,13 @@ void ARMv5::UpdatePURegion(const u32 n) if (CP15Control & CP15_CACHE_CR_DCACHEENABLE) { datacache = (PU_DataCacheable >> n) & 0x1; - datawrite = (PU_DataCacheWrite >> n) & 0x1; } else { datacache = false; - datawrite = false; } + + datawrite = (PU_DataCacheWrite >> n) & 0x1; u32 rgn = PU_Region[n]; if (!(rgn & CP15_REGION_ENABLE)) @@ -256,14 +256,14 @@ void ARMv5::UpdatePURegion(const u32 n) if (datacache) { - privmask |= CP15_MAP_DCACHEABLE; - usermask |= CP15_MAP_DCACHEABLE; - - if (datawrite) - { - privmask |= CP15_MAP_DCACHEWRITEBACK; - usermask |= CP15_MAP_DCACHEWRITEBACK; - } + privmask |= 0x10; + usermask |= 0x10; + } + + if (datawrite & 0x1) + { + privmask |= 0x20; + usermask |= 0x20; } if (codecache) @@ -880,7 +880,234 @@ bool ARMv5::IsAddressDCachable(const u32 addr) const return PU_Map[addr >> CP15_MAP_ENTRYSIZE_LOG2] & CP15_MAP_DCACHEABLE; } -void ARMv5::CP15Write(const u32 id, const u32 val) +void ARMv5::WriteBufferCheck() +{ + if (WBWritePointer == 16) return; + + while (WBCycles[WBWritePointer] <= (NDS.ARM9Timestamp + DataCycles)) + { + //printf("drainingwb %lli, %i %08X %i\n", WBCycles[WBWritePointer], WBWritePointer, WBAddr, WriteBufferFifo[WBWritePointer] >> 62); + switch ((u64)WriteBufferFifo[WBWritePointer] >> 62) + { + case 0: // byte + { + u8 val = WriteBufferFifo[WBWritePointer] & 0xFF; + if (WBAddr < ITCMSize) + { + *(u8*)&ITCM[WBAddr & (ITCMPhysicalSize - 1)] = val; +#ifdef JIT_ENABLED + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(WBAddr); +#endif + } + else if ((WBAddr & DTCMMask) == DTCMBase) *(u8*)&DTCM[WBAddr & (DTCMPhysicalSize - 1)] = val; + else BusWrite8(storeaddr[WBWritePointer], val); + break; + } + case 1: // halfword + { + u16 val = WriteBufferFifo[WBWritePointer] & 0xFFFF; + if (WBAddr < ITCMSize) + { + *(u16*)&ITCM[WBAddr & (ITCMPhysicalSize - 2)] = val; +#ifdef JIT_ENABLED + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(WBAddr); +#endif + } + else if ((WBAddr & DTCMMask) == DTCMBase) *(u16*)&DTCM[WBAddr & (DTCMPhysicalSize - 2)] = val; + else BusWrite16(storeaddr[WBWritePointer], val); + break; + } + case 2: // word + { + u32 val = WriteBufferFifo[WBWritePointer] & 0xFFFFFFFF; + if (WBAddr < ITCMSize) + { + *(u32*)&ITCM[WBAddr & (ITCMPhysicalSize - 4)] = val; +#ifdef JIT_ENABLED + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(WBAddr); +#endif + } + else if ((WBAddr & DTCMMask) == DTCMBase) *(u32*)&DTCM[WBAddr & (DTCMPhysicalSize - 4)] = val; + else BusWrite32(storeaddr[WBWritePointer], val); + WBAddr += 4; + break; + } + case 3: // address update + WBAddr = WriteBufferFifo[WBWritePointer] & 0xFFFFFFFF; + break; + } + + WBWritePointer = (WBWritePointer + 1) & 0xF; + if (WBWritePointer == WBFillPointer) + { + WBWritePointer = 16; + WBFillPointer = 0; + break; + } + } +} + +void ARMv5::WriteBufferWrite(u32 val, u8 flag, u8 cycles, u32 addr) +{ + WriteBufferCheck(); + + if (WBFillPointer == WBWritePointer) + { + //printf("forcedrainingwb %lli, %i %08X %i\n", WBCycles[WBWritePointer], WBWritePointer, WBAddr, WriteBufferFifo[WBWritePointer] >> 62); + if (NDS.ARM9Timestamp < WBCycles[WBWritePointer]) + { + NDS.ARM9Timestamp = WBCycles[WBWritePointer]; + DataCycles = 0; // checkme + } + + switch ((u64)WriteBufferFifo[WBWritePointer] >> 62) + { + case 0: // byte + { + u8 val = WriteBufferFifo[WBWritePointer] & 0xFF; + if (WBAddr < ITCMSize) + { + *(u8*)&ITCM[WBAddr & (ITCMPhysicalSize - 1)] = val; +#ifdef JIT_ENABLED + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(WBAddr); +#endif + } + else if ((WBAddr & DTCMMask) == DTCMBase) *(u8*)&DTCM[WBAddr & (DTCMPhysicalSize - 1)] = val; + else BusWrite8(storeaddr[WBWritePointer], val); + break; + } + case 1: // halfword + { + u16 val = WriteBufferFifo[WBWritePointer] & 0xFFFF; + if (WBAddr < ITCMSize) + { + *(u16*)&ITCM[WBAddr & (ITCMPhysicalSize - 2)] = val; +#ifdef JIT_ENABLED + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(WBAddr); +#endif + } + else if ((WBAddr & DTCMMask) == DTCMBase) *(u16*)&DTCM[WBAddr & (DTCMPhysicalSize - 2)] = val; + else BusWrite16(storeaddr[WBWritePointer], val); + break; + } + case 2: // word + { + u32 val = WriteBufferFifo[WBWritePointer] & 0xFFFFFFFF; + if (WBAddr < ITCMSize) + { + *(u32*)&ITCM[WBAddr & (ITCMPhysicalSize - 4)] = val; +#ifdef JIT_ENABLED + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(WBAddr); +#endif + } + else if ((WBAddr & DTCMMask) == DTCMBase) *(u32*)&DTCM[WBAddr & (DTCMPhysicalSize - 4)] = val; + else BusWrite32(storeaddr[WBWritePointer], val); + WBAddr += 4; + break; + } + case 3: // address update + WBAddr = WriteBufferFifo[WBWritePointer] & 0xFFFFFFFF; + break; + } + + WBWritePointer = (WBWritePointer + 1) & 0xF; + if (WBWritePointer == WBFillPointer) + { + WBWritePointer = 16; + WBFillPointer = 0; + } + } + + //printf("fillingwb %lli %i %i %08X %i\n", NDS.ARM9Timestamp, WBWritePointer, WBFillPointer, val, flag); + if (WBWritePointer == 16) + { + WBCycles[WBFillPointer] = NDS.ARM9Timestamp + DataCycles + cycles; + WBWritePointer = 0; + } + else + { + WBCycles[WBFillPointer] = WBCycles[(WBFillPointer-1) & 0xF] + cycles; + } + WriteBufferFifo[WBFillPointer] = val | (u64)flag << 62; + storeaddr[WBFillPointer] = addr; + WBFillPointer = (WBFillPointer + 1) & 0xF; +} + +void ARMv5::WriteBufferDrain() +{ + if (WBWritePointer == 16) return; + + while (true) + { + //printf("fullydrainingwb %lli, %i %08X %i\n", WBCycles[WBWritePointer], WBWritePointer, WBAddr, WriteBufferFifo[WBWritePointer] >> 62); + if (NDS.ARM9Timestamp < WBCycles[WBWritePointer]) + { + NDS.ARM9Timestamp = WBCycles[WBWritePointer]; + DataCycles = 0; // checkme + } + + switch (WriteBufferFifo[WBWritePointer] >> 62) + { + case 0: // byte + { + u8 val = WriteBufferFifo[WBWritePointer] & 0xFF; + if (WBAddr < ITCMSize) + { + *(u8*)&ITCM[WBAddr & (ITCMPhysicalSize - 1)] = val; +#ifdef JIT_ENABLED + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(WBAddr); +#endif + } + else if ((WBAddr & DTCMMask) == DTCMBase) *(u8*)&DTCM[WBAddr & (DTCMPhysicalSize - 1)] = val; + else BusWrite8(storeaddr[WBWritePointer], val); + break; + } + case 1: // halfword + { + u16 val = WriteBufferFifo[WBWritePointer] & 0xFFFF; + if (WBAddr < ITCMSize) + { + *(u16*)&ITCM[WBAddr & (ITCMPhysicalSize - 2)] = val; +#ifdef JIT_ENABLED + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(WBAddr); +#endif + } + else if ((WBAddr & DTCMMask) == DTCMBase) *(u16*)&DTCM[WBAddr & (DTCMPhysicalSize - 2)] = val; + else BusWrite16(storeaddr[WBWritePointer], val); + break; + } + case 2: // word + { + u32 val = WriteBufferFifo[WBWritePointer] & 0xFFFFFFFF; + if (WBAddr < ITCMSize) + { + *(u32*)&ITCM[WBAddr & (ITCMPhysicalSize - 4)] = val; +#ifdef JIT_ENABLED + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(WBAddr); +#endif + } + else if ((WBAddr & DTCMMask) == DTCMBase) *(u32*)&DTCM[WBAddr & (DTCMPhysicalSize - 4)] = val; + else BusWrite32(storeaddr[WBWritePointer], val); + WBAddr += 4; + break; + } + case 3: // address update + WBAddr = WriteBufferFifo[WBWritePointer] & 0xFFFFFFFF; + break; + } + + WBWritePointer = (WBWritePointer + 1) & 0xF; + if (WBWritePointer == WBFillPointer) + { + WBWritePointer = 16; + WBFillPointer = 0; + break; + } + } + //printf("wbdrained\n"); +} + +void ARMv5::CP15Write(u32 id, u32 val) { //if(id!=0x704)printf("CP15 write op %03X %08X %08X\n", id, val, R[15]); @@ -1623,6 +1850,9 @@ u32 ARMv5::CodeRead32(u32 addr, bool branch) } #endif + if ((PU_Map[addr>>12] & 0x30)) + WriteBufferDrain(); + if (addr < ITCMSize) { CodeCycles = 1; @@ -1688,6 +1918,9 @@ bool ARMv5::DataRead8(u32 addr, u32* val) } #endif + if ((PU_Map[addr>>12] & 0x30)) + WriteBufferDrain(); + if (addr < ITCMSize) { DataCycles = 1; @@ -1748,6 +1981,8 @@ bool ARMv5::DataRead16(u32 addr, u32* val) } #endif addr &= ~1; + if ((PU_Map[addr>>12] & 0x30)) + WriteBufferDrain(); if (addr < ITCMSize) { @@ -1811,6 +2046,9 @@ bool ARMv5::DataRead32(u32 addr, u32* val) } #endif + if ((PU_Map[addr>>12] & 0x30)) + WriteBufferDrain(); + if (addr < ITCMSize) { DataCycles = 1; @@ -1871,6 +2109,9 @@ bool ARMv5::DataRead32S(u32 addr, u32* val) } #endif + if ((PU_Map[addr>>12] & 0x30)) + WriteBufferDrain(); + if (addr < ITCMSize) { DataCycles += 1; @@ -1886,8 +2127,11 @@ bool ARMv5::DataRead32S(u32 addr, u32* val) *val = *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)]; return true; } - + NDS.ARM9Timestamp += DataCycles; + + if (!(addr & 0x3FF)) return DataRead32(addr, val); // bursts cannot cross a 1kb boundary + DataCycles = MemTimings[addr >> 12][3]; NDS.ARM9Timestamp = NDS.ARM9Timestamp + ((1<(addr); - return true; - } - if ((addr & DTCMMask) == DTCMBase) - { - DataCycles = 1; - DataRegion = Mem9_DTCM; - *(u8*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; - return true; - } - NDS.ARM9Timestamp = NDS.ARM9Timestamp + ((1<>12] & (0x30))) + { + if (addr < ITCMSize) + { + DataCycles = 1; + ITCMTimestamp = NDS.ARM9Timestamp + DataCycles; + DataRegion = Mem9_ITCM; + *(u8*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val; +#ifdef JIT_ENABLED + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); +#endif + return true; + } + if ((addr & DTCMMask) == DTCMBase) + { + DataCycles = 1; + DataRegion = Mem9_DTCM; + *(u8*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; + return true; + } - DataCycles = MemTimings[addr >> 12][1]; + NDS.ARM9Timestamp = NDS.ARM9Timestamp + ((1<> 12][1]; - if ((addr >> 24) == 0x02) - { - if (NDS.ARM9Timestamp < MainRAMTimestamp) NDS.ARM9Timestamp = MainRAMTimestamp; - DataRegion = Mem9_MainRAM; - MainRAMTimestamp = NDS.ARM9Timestamp + DataCycles; - DataCycles -= (2<> 24) == 0x02) + { + if (NDS.ARM9Timestamp < MainRAMTimestamp) NDS.ARM9Timestamp = MainRAMTimestamp; + DataRegion = Mem9_MainRAM; + MainRAMTimestamp = NDS.ARM9Timestamp + DataCycles; + DataCycles -= (2<>14]; + + BusWrite8(addr, val); + } + else + { + DataCycles = 1; + WriteBufferWrite(addr, 3, 1); + WriteBufferWrite(val, 0, MemTimings[addr >> 12][1], addr); } - else DataRegion = NDS.ARM9Regions[addr>>14]; - - BusWrite8(addr, val); return true; } @@ -1993,37 +2249,48 @@ bool ARMv5::DataWrite16(u32 addr, u16 val) } #endif - if (addr < ITCMSize) + if (!(PU_Map[addr>>12] & 0x30)) { - DataCycles = 1; - ITCMTimestamp = NDS.ARM9Timestamp + DataCycles; - DataRegion = Mem9_ITCM; - *(u16*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val; - NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); - return true; - } - if ((addr & DTCMMask) == DTCMBase) - { - DataCycles = 1; - DataRegion = Mem9_DTCM; - *(u16*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; - return true; - } - - NDS.ARM9Timestamp = NDS.ARM9Timestamp + ((1<(addr); +#endif + return true; + } + if ((addr & DTCMMask) == DTCMBase) + { + DataCycles = 1; + DataRegion = Mem9_DTCM; + *(u16*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; + return true; + } - DataCycles = MemTimings[addr >> 12][1]; + NDS.ARM9Timestamp = NDS.ARM9Timestamp + ((1<> 12][1]; - if ((addr >> 24) == 0x02) - { - if (NDS.ARM9Timestamp < MainRAMTimestamp) NDS.ARM9Timestamp = MainRAMTimestamp; - DataRegion = Mem9_MainRAM; - MainRAMTimestamp = NDS.ARM9Timestamp + DataCycles; - DataCycles -= (2<> 24) == 0x02) + { + if (NDS.ARM9Timestamp < MainRAMTimestamp) NDS.ARM9Timestamp = MainRAMTimestamp; + DataRegion = Mem9_MainRAM; + MainRAMTimestamp = NDS.ARM9Timestamp + DataCycles; + DataCycles -= (2<>14]; + + BusWrite16(addr, val); + } + else + { + DataCycles = 1; + WriteBufferWrite(addr, 3, 1); + WriteBufferWrite(val, 1, MemTimings[addr >> 12][1], addr); } - else DataRegion = NDS.ARM9Regions[addr>>14]; - - BusWrite16(addr, val); return true; } @@ -2057,37 +2324,48 @@ bool ARMv5::DataWrite32(u32 addr, u32 val) } #endif - if (addr < ITCMSize) + if (!(PU_Map[addr>>12] & 0x30)) { - DataCycles = 1; - ITCMTimestamp = NDS.ARM9Timestamp + DataCycles; - DataRegion = Mem9_ITCM; - *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val; - NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); - return true; - } - if ((addr & DTCMMask) == DTCMBase) - { - DataCycles = 1; - DataRegion = Mem9_DTCM; - *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; - return true; - } - - NDS.ARM9Timestamp = NDS.ARM9Timestamp + ((1<(addr); +#endif + return true; + } + if ((addr & DTCMMask) == DTCMBase) + { + DataCycles = 1; + DataRegion = Mem9_DTCM; + *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; + return true; + } - DataCycles = MemTimings[addr >> 12][2]; + NDS.ARM9Timestamp = NDS.ARM9Timestamp + ((1<> 12][2]; - if ((addr >> 24) == 0x02) - { - if (NDS.ARM9Timestamp < MainRAMTimestamp) NDS.ARM9Timestamp = MainRAMTimestamp; - DataRegion = Mem9_MainRAM; - MainRAMTimestamp = NDS.ARM9Timestamp + DataCycles; - DataCycles -= (2<> 24) == 0x02) + { + if (NDS.ARM9Timestamp < MainRAMTimestamp) NDS.ARM9Timestamp = MainRAMTimestamp; + DataRegion = Mem9_MainRAM; + MainRAMTimestamp = NDS.ARM9Timestamp + DataCycles; + DataCycles -= (2<>14]; + + BusWrite32(addr, val); + } + else + { + DataCycles = 1; + WriteBufferWrite(addr, 3, 1); + WriteBufferWrite(val, 2, MemTimings[addr >> 12][2], addr); } - else DataRegion = NDS.ARM9Regions[addr>>14]; - - BusWrite32(addr, val); return true; } @@ -2119,38 +2397,47 @@ bool ARMv5::DataWrite32S(u32 addr, u32 val) } #endif - if (addr < ITCMSize) + if (!(PU_Map[addr>>12] & 0x30)) { - DataCycles += 1; - ITCMTimestamp = NDS.ARM9Timestamp + DataCycles; - DataRegion = Mem9_ITCM; - *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val; + if (addr < ITCMSize) + { + DataCycles += 1; + ITCMTimestamp = NDS.ARM9Timestamp + DataCycles; + DataRegion = Mem9_ITCM; + *(u32*)&ITCM[addr & (ITCMPhysicalSize - 1)] = val; #ifdef JIT_ENABLED - NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); + NDS.JIT.CheckAndInvalidate<0, ARMJIT_Memory::memregion_ITCM>(addr); #endif - return true; + return true; + } + if ((addr & DTCMMask) == DTCMBase) + { + DataCycles += 1; + DataRegion = Mem9_DTCM; + *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; + return true; + } + + DataCycles += ((NDS.ARM9Timestamp + ((1<> 24) == 0x02) + { + if ((DataRegion != Mem9_MainRAM) && ((NDS.ARM9Timestamp + DataCycles) < MainRAMTimestamp)) NDS.ARM9Timestamp = MainRAMTimestamp - DataCycles; + MainRAMTimestamp = NDS.ARM9Timestamp + DataCycles; + DataRegion = Mem9_MainRAM; + } + else DataRegion = NDS.ARM9Regions[addr>>14]; + + BusWrite32(addr, val); + DataCycles += MemTimings[addr >> 12][3]; } - if ((addr & DTCMMask) == DTCMBase) + else { DataCycles += 1; - DataRegion = Mem9_DTCM; - *(u32*)&DTCM[addr & (DTCMPhysicalSize - 1)] = val; - return true; + WriteBufferWrite(val, 2, MemTimings[addr >> 12][3], addr); } - - NDS.ARM9Timestamp = NDS.ARM9Timestamp + ((1<> 24) == 0x02) - { - if ((DataRegion != Mem9_MainRAM) && ((NDS.ARM9Timestamp + DataCycles) < MainRAMTimestamp)) NDS.ARM9Timestamp = MainRAMTimestamp - DataCycles; - MainRAMTimestamp = NDS.ARM9Timestamp + DataCycles; - DataRegion = Mem9_MainRAM; - } - else DataRegion = NDS.ARM9Regions[addr>>14]; - - BusWrite32(addr, val); - DataCycles += MemTimings[addr >> 12][3]; return true; }