From 026719acef269f17e0f44d3efd2da71453001740 Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Mon, 14 Oct 2024 20:05:06 -0400 Subject: [PATCH] improve timing model --- src/ARM.cpp | 1 + src/ARM.h | 21 ++-- src/CP15.cpp | 263 +++++++++++++++++++++++---------------------------- 3 files changed, 135 insertions(+), 150 deletions(-) diff --git a/src/ARM.cpp b/src/ARM.cpp index 9e768047..b783431c 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -211,6 +211,7 @@ void ARMv5::Reset() WBWritePointer = 16; WBFillPointer = 0; WBDelay = 0; + WBWriting = false; ARM::Reset(); } diff --git a/src/ARM.h b/src/ARM.h index 16f4b72a..31044108 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -317,6 +317,7 @@ public: void ICacheInvalidateByAddr(u32 addr); void ICacheInvalidateAll(); + template inline bool WriteBufferHandle(); void WriteBufferCheck(); void WriteBufferWrite(u32 val, u8 flag, u8 cycles, u32 addr = 0); void WriteBufferDrain(); @@ -375,13 +376,19 @@ public: bool Store; u16 InterlockMask; - u8 WBWritePointer; - u8 WBFillPointer; - u64 WBDelay; - 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 + + u8 WBWritePointer; // which entry to attempt to write next; should always be ANDed with 0xF after incrementing + u8 WBFillPointer; // where the next entry should be added; should always be ANDed with 0xF after incrementing + bool WBWriting; // whether the buffer is actively trying to perform a write + u8 WBCurCycles; // how long the current write will take; bit 7 is a flag used to indicate main ram + u64 WBCurVal; // current value being written; 0-31: val | 62-32: flag; 0 = byte; 1 = halfword; 2 = word; 3 = address (invalid in this variable) + u32 WBCurAddr; // address the write buffer is currently writing to + u32 storeaddr[16]; // temp until i figure out why using the fifo address entries directly didn't work + u8 WBCycles[16]; // num cycles for each write; bit 7 is a flag used to indicate main ram + u64 WriteBufferFifo[16]; // 0-31: val | 62-32: flag; 0 = byte; 1 = halfword; 2 = word; 3 = address + u64 WBTimestamp; // current timestamp in bus cycles + u64 WBMainRAMDelay; // timestamp in bus cycles used to emulate the delay before the next main ram write can begin + u64 WBDelay; // timestamp in bus cycles use for the delay before next write to the write buffer can occur (seems to be a 1 cycle delay after a write to it) #ifdef GDBSTUB_ENABLED u32 ReadMem(u32 addr, int size) override; diff --git a/src/CP15.cpp b/src/CP15.cpp index 9ac9d568..14b87c73 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -438,159 +438,109 @@ void ARMv5::ICacheInvalidateAll() ICacheTags[i] = 1; } +template +inline bool ARMv5::WriteBufferHandle() +{ + // handle write buffer writes + if (WBWriting) + { + bool mainram = (WBCurCycles >= 0x80); + + u64 ts; + if (mainram) ts = std::max(WBTimestamp, WBMainRAMDelay) + (WBCurCycles & 0x7F); + else ts = WBTimestamp + (WBCurCycles & 0x7F); + + if (!force && ts > ((NDS.ARM9Timestamp + DataCycles) >> NDS.ARM9ClockShift)) return true; + if ( force && ts > ((NDS.ARM9Timestamp + DataCycles) >> NDS.ARM9ClockShift)) + { + NDS.ARM9Timestamp = ((ts - 1) << NDS.ARM9ClockShift) + 1; + DataCycles = 0; // checkme + } + + WBTimestamp = ts; + if (mainram) WBMainRAMDelay = WBTimestamp + 2; + + switch (WBCurVal >> 62) + { + case 0: // byte + BusWrite8 (WBCurAddr, WBCurVal); + break; + case 1: // halfword + BusWrite16(WBCurAddr, WBCurVal); + break; + case 2: // word + BusWrite32(WBCurAddr, WBCurVal); + break; + default: // address ie. invalid + Platform::Log(Platform::LogLevel::Warn, "WHY ARE WE TRYING TO WRITE AN ADDRESS VIA THE WRITE BUFFER! PANIC!!!\n", (u8)(WBCurVal >> 62)); + break; + } + + //printf("writing: adr: %i, val: %lli, cyl: %i", WBCurAddr, WBCurVal, WBCurCycles); + WBWriting = false; + } + + // check if write buffer is empty + if (WBWritePointer == 16) return true; + // attempt to drain write buffer + if ((WriteBufferFifo[WBWritePointer] >> 62) != 3) // not an address + { + if (WBCycles[WBWritePointer] >= 0x80) // main ram handling + { + u64 ts = ((NDS.ARM9Timestamp + DataCycles) >> NDS.ARM9ClockShift); + if (!force && (WBMainRAMDelay > ts)) return true; + if ( force && (WBMainRAMDelay > ts)) + { + NDS.ARM9Timestamp = ((WBMainRAMDelay - 1) << NDS.ARM9ClockShift) + 1; + DataCycles = 0; + } + } + + WBCurVal = WriteBufferFifo[WBWritePointer]; + WBCurCycles = WBCycles[WBWritePointer]; + WBCurAddr = storeaddr[WBWritePointer]; + WBWriting = true; + } + else + { + // todo: i want to set the address here instead + } + + WBWritePointer = (WBWritePointer + 1) & 0xF; + if (WBWritePointer == WBFillPointer) + { + WBWritePointer = 16; + WBFillPointer = 0; + } + return false; +} + 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; - BusWrite8(storeaddr[WBWritePointer], val); - break; - } - case 1: // halfword - { - u16 val = WriteBufferFifo[WBWritePointer] & 0xFFFF; - BusWrite16(storeaddr[WBWritePointer], val); - break; - } - case 2: // word - { - u32 val = WriteBufferFifo[WBWritePointer] & 0xFFFFFFFF; - 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; - } - } + while (!WriteBufferHandle()); // loop until we've cleared out all writeable entries } void ARMv5::WriteBufferWrite(u32 val, u8 flag, u8 cycles, u32 addr) { WriteBufferCheck(); - if (WBFillPointer == WBWritePointer) + if (WBFillPointer == WBWritePointer) // if the write buffer is full then we stall the cpu until room is made + WriteBufferHandle(); + else if (WBWritePointer == 16) // indicates empty write buffer { - //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; - BusWrite8(storeaddr[WBWritePointer], val); - break; - } - case 1: // halfword - { - u16 val = WriteBufferFifo[WBWritePointer] & 0xFFFF; - BusWrite16(storeaddr[WBWritePointer], val); - break; - } - case 2: // word - { - u32 val = WriteBufferFifo[WBWritePointer] & 0xFFFFFFFF; - 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; + WBTimestamp = (((NDS.ARM9Timestamp + DataCycles) + ((1<> NDS.ARM9ClockShift; } - else - { - WBCycles[WBFillPointer] = WBCycles[(WBFillPointer-1) & 0xF] + cycles; - } + WriteBufferFifo[WBFillPointer] = val | (u64)flag << 62; + WBCycles[WBFillPointer] = cycles; 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; - BusWrite8(storeaddr[WBWritePointer], val); - break; - } - case 1: // halfword - { - u16 val = WriteBufferFifo[WBWritePointer] & 0xFFFF; - BusWrite16(storeaddr[WBWritePointer], val); - break; - } - case 2: // word - { - u32 val = WriteBufferFifo[WBWritePointer] & 0xFFFFFFFF; - 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"); + while (!WriteBufferHandle()); // loop until drained fully } void ARMv5::CP15Write(u32 id, u32 val) @@ -1224,9 +1174,16 @@ bool ARMv5::DataWrite8(u32 addr, u8 val) else { if (WBDelay > NDS.ARM9Timestamp) NDS.ARM9Timestamp = WBDelay; + + u8 cycles = NDS.ARM9MemTimings[addr>>14][0]; + if ((addr >> 24) == 0x02) + { + cycles = (cycles - 2) & 0x80; + } + + WriteBufferWrite(addr, 3, 0); + WriteBufferWrite(val, 0, cycles, addr); DataCycles = 1; - WriteBufferWrite(addr, 3, 1); - WriteBufferWrite(val, 0, MemTimings[addr >> 12][1], addr); WBDelay = NDS.ARM9Timestamp + 2; } return true; @@ -1284,9 +1241,16 @@ bool ARMv5::DataWrite16(u32 addr, u16 val) else { if (WBDelay > NDS.ARM9Timestamp) NDS.ARM9Timestamp = WBDelay; + + u8 cycles = NDS.ARM9MemTimings[addr>>14][0]; + if ((addr >> 24) == 0x02) + { + cycles = (cycles - 2) & 0x80; + } + + WriteBufferWrite(addr, 3, 0); + WriteBufferWrite(val, 1, cycles, addr); DataCycles = 1; - WriteBufferWrite(addr, 3, 1); - WriteBufferWrite(val, 1, MemTimings[addr >> 12][1], addr); WBDelay = NDS.ARM9Timestamp + 2; } return true; @@ -1344,9 +1308,16 @@ bool ARMv5::DataWrite32(u32 addr, u32 val) else { if (WBDelay > NDS.ARM9Timestamp) NDS.ARM9Timestamp = WBDelay; + + u8 cycles = NDS.ARM9MemTimings[addr>>14][2]; + if ((addr >> 24) == 0x02) + { + cycles = (cycles - 2) & 0x80; + } + + WriteBufferWrite(addr, 3, 0); + WriteBufferWrite(val, 2, cycles, addr); DataCycles = 1; - WriteBufferWrite(addr, 3, 1); - WriteBufferWrite(val, 2, MemTimings[addr >> 12][2], addr); WBDelay = NDS.ARM9Timestamp + 2; } return true; @@ -1385,7 +1356,7 @@ bool ARMv5::DataWrite32S(u32 addr, u32 val) if (!(PU_Map[addr>>12] & 0x30)) { - DataCycles += (((NDS.ARM9Timestamp + DataCycles) + ((1<>14][3]; + if ((addr >> 24) == 0x02) + { + cycles = (cycles - 2) & 0x80; + } + + WriteBufferWrite(val, 2, cycles, addr); DataCycles += 1; - WriteBufferWrite(val, 2, MemTimings[addr >> 12][3], addr); WBDelay = NDS.ARM9Timestamp + DataCycles + 1; } return true;