diff --git a/ares/n64/cpu/cpu.cpp b/ares/n64/cpu/cpu.cpp index dd6745d2d4..8f92cc3513 100644 --- a/ares/n64/cpu/cpu.cpp +++ b/ares/n64/cpu/cpu.cpp @@ -91,6 +91,9 @@ auto CPU::instruction() -> void { step(1 * 2); return exception.nmi(); } + if (scc.sysadFrozen) { + return; + } if constexpr(Accuracy::CPU::Recompiler) { // Fast path: attempt to lookup previously compiled blocks with devirtualizeFast diff --git a/ares/n64/cpu/cpu.hpp b/ares/n64/cpu/cpu.hpp index c55664afcd..f2cb421120 100644 --- a/ares/n64/cpu/cpu.hpp +++ b/ares/n64/cpu/cpu.hpp @@ -147,26 +147,12 @@ struct CPU : Thread { cpu.step(48 * 2); valid = 1; tag = address & ~0x0000'0fff; - words[0] = cpu.busRead(tag | index | 0x00); - words[1] = cpu.busRead(tag | index | 0x04); - words[2] = cpu.busRead(tag | index | 0x08); - words[3] = cpu.busRead(tag | index | 0x0c); - words[4] = cpu.busRead(tag | index | 0x10); - words[5] = cpu.busRead(tag | index | 0x14); - words[6] = cpu.busRead(tag | index | 0x18); - words[7] = cpu.busRead(tag | index | 0x1c); + cpu.busReadBurst(tag | index, words); } auto writeBack(CPU& cpu) -> void { cpu.step(48 * 2); - cpu.busWrite(tag | index | 0x00, words[0]); - cpu.busWrite(tag | index | 0x04, words[1]); - cpu.busWrite(tag | index | 0x08, words[2]); - cpu.busWrite(tag | index | 0x0c, words[3]); - cpu.busWrite(tag | index | 0x10, words[4]); - cpu.busWrite(tag | index | 0x14, words[5]); - cpu.busWrite(tag | index | 0x18, words[6]); - cpu.busWrite(tag | index | 0x1c, words[7]); + cpu.busWriteBurst(tag | index, words); } auto read(u32 address) const -> u32 { return words[address >> 2 & 7]; } @@ -191,7 +177,6 @@ struct CPU : Thread { //8KB struct Line { auto hit(u32 address) const -> bool; - template auto fill(u32 address, u64 data) -> void; auto fill(u32 address) -> void; auto writeBack() -> void; template auto read(u32 address) const -> u64; @@ -300,6 +285,8 @@ struct CPU : Thread { auto fetch(u64 vaddr) -> maybe; template auto busWrite(u32 address, u64 data) -> void; template auto busRead(u32 address) -> u64; + template auto busWriteBurst(u32 address, u32 *data) -> void; + template auto busReadBurst(u32 address, u32 *data) -> void; template auto read(u64 vaddr) -> maybe; template auto write(u64 vaddr, u64 data, bool alignedError=true) -> bool; template auto vaddrAlignedError(u64 vaddr, bool write) -> bool; @@ -637,6 +624,7 @@ struct CPU : Thread { //other n64 latch; n1 nmiPending; + n1 sysadFrozen; } scc; //interpreter-scc.cpp diff --git a/ares/n64/cpu/dcache.cpp b/ares/n64/cpu/dcache.cpp index 479181dd00..dd81312f62 100644 --- a/ares/n64/cpu/dcache.cpp +++ b/ares/n64/cpu/dcache.cpp @@ -2,63 +2,18 @@ auto CPU::DataCache::Line::hit(u32 address) const -> bool { return valid && tag == (address & ~0x0000'0fff); } -template auto CPU::DataCache::Line::fill(u32 address, u64 data) -> void { - cpu.step(40 * 2); - valid = 1; - dirty = 1; - tag = address & ~0x0000'0fff; - //read words according to critical doubleword first scheme - switch(address & 8) { - case 0: - if constexpr(Size != Dual) { - words[0] = cpu.busRead(tag | index | 0x0); - words[1] = cpu.busRead(tag | index | 0x4); - } - write(address, data); - words[2] = cpu.busRead(tag | index | 0x8); - words[3] = cpu.busRead(tag | index | 0xc); - break; - case 8: - if constexpr(Size != Dual) { - words[2] = cpu.busRead(tag | index | 0x8); - words[3] = cpu.busRead(tag | index | 0xc); - } - write(address, data); - words[0] = cpu.busRead(tag | index | 0x0); - words[1] = cpu.busRead(tag | index | 0x4); - break; - } -} - auto CPU::DataCache::Line::fill(u32 address) -> void { cpu.step(40 * 2); valid = 1; dirty = 0; tag = address & ~0x0000'0fff; - //read words according to critical doubleword first scheme - switch(address & 8) { - case 0: - words[0] = cpu.busRead(tag | index | 0x0); - words[1] = cpu.busRead(tag | index | 0x4); - words[2] = cpu.busRead(tag | index | 0x8); - words[3] = cpu.busRead(tag | index | 0xc); - break; - case 8: - words[2] = cpu.busRead(tag | index | 0x8); - words[3] = cpu.busRead(tag | index | 0xc); - words[0] = cpu.busRead(tag | index | 0x0); - words[1] = cpu.busRead(tag | index | 0x4); - break; - } + cpu.busReadBurst(tag | index, words); } auto CPU::DataCache::Line::writeBack() -> void { cpu.step(40 * 2); dirty = 0; - cpu.busWrite(tag | index | 0x0, words[0]); - cpu.busWrite(tag | index | 0x4, words[1]); - cpu.busWrite(tag | index | 0x8, words[2]); - cpu.busWrite(tag | index | 0xc, words[3]); + cpu.busWriteBurst(tag | index, words); } auto CPU::DataCache::line(u32 vaddr) -> Line& { @@ -115,7 +70,7 @@ auto CPU::DataCache::write(u32 vaddr, u32 address, u64 data) -> void { auto& line = this->line(vaddr); if(!line.hit(address)) { if(line.valid && line.dirty) line.writeBack(); - return line.fill(address, data); + line.fill(address); } else { cpu.step(1 * 2); } diff --git a/ares/n64/cpu/memory.cpp b/ares/n64/cpu/memory.cpp index 1ca871621d..d548d2be78 100644 --- a/ares/n64/cpu/memory.cpp +++ b/ares/n64/cpu/memory.cpp @@ -149,11 +149,21 @@ inline auto CPU::busWrite(u32 address, u64 data) -> void { bus.write(address, data, *this); } +template +inline auto CPU::busWriteBurst(u32 address, u32 *data) -> void { + bus.writeBurst(address, data, *this); +} + template inline auto CPU::busRead(u32 address) -> u64 { return bus.read(address, *this); } +template +inline auto CPU::busReadBurst(u32 address, u32 *data) -> void { + return bus.readBurst(address, data, *this); +} + auto CPU::fetch(u64 vaddr) -> maybe { if(vaddrAlignedError(vaddr, false)) return nothing; switch(segment(vaddr)) { diff --git a/ares/n64/cpu/serialization.cpp b/ares/n64/cpu/serialization.cpp index 48f9d03cfd..fc6880f582 100644 --- a/ares/n64/cpu/serialization.cpp +++ b/ares/n64/cpu/serialization.cpp @@ -117,6 +117,7 @@ auto CPU::serialize(serializer& s) -> void { s(scc.epcError); s(scc.latch); s(scc.nmiPending); + s(scc.sysadFrozen); for(auto& r : fpu.r) s(r.u64); s(fpu.csr.roundMode); diff --git a/ares/n64/memory/bus.hpp b/ares/n64/memory/bus.hpp index bff5a4e093..b72ae9b016 100644 --- a/ares/n64/memory/bus.hpp +++ b/ares/n64/memory/bus.hpp @@ -1,7 +1,7 @@ template inline auto Bus::read(u32 address, Thread& thread) -> u64 { static constexpr u64 unmapped = 0; - address &= 0x1fff'ffff - (Size - 1); + static_assert(Size == Byte || Size == Half || Size == Word || Size == Dual); if(address <= 0x007f'ffff) return rdram.ram.read(address); if(address <= 0x03ef'ffff) return unmapped; @@ -23,9 +23,31 @@ inline auto Bus::read(u32 address, Thread& thread) -> u64 { return unmapped; } +template +inline auto Bus::readBurst(u32 address, u32 *data, Thread& thread) -> void { + static_assert(Size == DCache || Size == ICache); + + if(address <= 0x03ff'ffff) { + data[0] = read(address | 0x0, thread); + data[1] = read(address | 0x4, thread); + data[2] = read(address | 0x8, thread); + data[3] = read(address | 0xc, thread); + if constexpr(Size == ICache) { + data[4] = read(address | 0x10, thread); + data[5] = read(address | 0x14, thread); + data[6] = read(address | 0x18, thread); + data[7] = read(address | 0x1c, thread); + } + return; + } + + debug(unusual, "[Bus::readBurst] CPU frozen because of cached read to non-RDRAM area: 0x", hex(address, 8L)); + cpu.scc.sysadFrozen = true; +} + template inline auto Bus::write(u32 address, u64 data, Thread& thread) -> void { - address &= 0x1fff'ffff - (Size - 1); + static_assert(Size == Byte || Size == Half || Size == Word || Size == Dual); if constexpr(Accuracy::CPU::Recompiler) { cpu.recompiler.invalidate(address + 0); if constexpr(Size == Dual) cpu.recompiler.invalidate(address + 4); @@ -50,3 +72,25 @@ inline auto Bus::write(u32 address, u64 data, Thread& thread) -> void { if(address <= 0x7fff'ffff) return pi.write(address, data, thread); return; } + +template +inline auto Bus::writeBurst(u32 address, u32 *data, Thread& thread) -> void { + static_assert(Size == DCache || Size == ICache); + + if(address <= 0x03ff'ffff) { + write(address | 0x0, data[0], thread); + write(address | 0x4, data[1], thread); + write(address | 0x8, data[2], thread); + write(address | 0xc, data[3], thread); + if constexpr(Size == ICache) { + write(address | 0x10, data[4], thread); + write(address | 0x14, data[5], thread); + write(address | 0x18, data[6], thread); + write(address | 0x1c, data[7], thread); + } + return; + } + + debug(unusual, "[Bus::readBurst] CPU frozen because of cached write to non-RDRAM area: 0x", hex(address, 8L)); + cpu.scc.sysadFrozen = true; +} diff --git a/ares/n64/memory/memory.hpp b/ares/n64/memory/memory.hpp index f1ce23dcba..0e7478c513 100644 --- a/ares/n64/memory/memory.hpp +++ b/ares/n64/memory/memory.hpp @@ -33,6 +33,9 @@ struct Bus { //bus.hpp template auto read(u32 address, Thread& thread) -> u64; template auto write(u32 address, u64 data, Thread& thread) -> void; + + template auto readBurst(u32 address, u32* data, Thread& thread) -> void; + template auto writeBurst(u32 address, u32* data, Thread& thread) -> void; }; extern Bus bus; diff --git a/ares/n64/n64.hpp b/ares/n64/n64.hpp index 6810ad0578..d386deb96f 100644 --- a/ares/n64/n64.hpp +++ b/ares/n64/n64.hpp @@ -34,7 +34,7 @@ namespace ares::Nintendo64 { auto option(string name, string value) -> bool; enum : u32 { Read, Write }; - enum : u32 { Byte = 1, Half = 2, Word = 4, Dual = 8 }; + enum : u32 { Byte = 1, Half = 2, Word = 4, Dual = 8, DCache = 16, ICache = 32 }; struct Region { static inline auto NTSC() -> bool;