diff --git a/src/backend/core/Dynarec.cpp b/src/backend/core/Dynarec.cpp index 52d31636..c6364fd3 100644 --- a/src/backend/core/Dynarec.cpp +++ b/src/backend/core/Dynarec.cpp @@ -63,7 +63,7 @@ void Dynarec::Recompile(Mem& mem, u32 pc) { while(!prevBranch) { instrInBlock++; prevBranch = branch; - u32 instr = mem.Read32(regs, loopPC, loopPC); + u32 instr = mem.Read32(regs, loopPC); emitBreakpoint(); code.mov(rdi, (uintptr_t)®s); @@ -104,8 +104,11 @@ int Dynarec::Step(Mem &mem) { regs.delaySlot = false; u32 pc{}; + if(!MapVAddr(regs, LOAD, regs.pc, pc)) { - Util::panic("[RECOMPILER] Failed to translate PC to physical address (v: {:08X})\n", regs.pc); + HandleTLBException(regs, regs.pc); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false); + return 0; } if(blockCache[pc >> 20]) { diff --git a/src/backend/core/Interpreter.cpp b/src/backend/core/Interpreter.cpp index 0b9df763..99624e9e 100644 --- a/src/backend/core/Interpreter.cpp +++ b/src/backend/core/Interpreter.cpp @@ -29,13 +29,20 @@ void Interpreter::Step(Mem& mem) { regs.prevDelaySlot = regs.delaySlot; regs.delaySlot = false; + u32 paddr = 0; + if(!MapVAddr(regs, LOAD, regs.pc, paddr)) { + HandleTLBException(regs, regs.pc); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false); + return; + } + + u32 instruction = mem.Read32(regs, paddr); + if(ShouldServiceInterrupt(regs)) { FireException(regs, ExceptionCode::Interrupt, 0, false); return; } - u32 instruction = mem.Read32(regs, regs.pc, regs.pc); - regs.oldPC = regs.pc; regs.pc = regs.nextPC; regs.nextPC += 4; diff --git a/src/backend/core/Mem.cpp b/src/backend/core/Mem.cpp index 8a176825..0c7ec241 100644 --- a/src/backend/core/Mem.cpp +++ b/src/backend/core/Mem.cpp @@ -17,7 +17,8 @@ void Mem::Reset() { std::fill(readPages.begin(), readPages.end(), 0); std::fill(writePages.begin(), writePages.end(), 0); - for(int i = 0; i < 2048; i++) { + int i = 0; + for(i = 0; i < RDRAM_SIZE / PAGE_SIZE; i++) { const auto addr = (i * PAGE_SIZE) & RDRAM_DSIZE; const auto pointer = (uintptr_t) &mmio.rdp.rdram[addr]; readPages[i] = pointer; @@ -66,6 +67,12 @@ CartInfo Mem::LoadROM(const std::string& filename) { SetCICType(result.cicType, cicChecksum); result.isPAL = IsROMPAL(); + for(int i = 0; i < sizeAdjusted / PAGE_SIZE; i++) { + const auto addr = (i * PAGE_SIZE) & romMask; + const auto pointer = (uintptr_t) &cart[addr]; + readPages[0x10000 + i] = pointer; + } + return result; } @@ -89,13 +96,9 @@ bool MapVAddr(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) template bool MapVAddr(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr); template bool MapVAddr(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr); -template -u8 Mem::Read8(n64::Registers ®s, u64 vaddr, s64 pc) { - u32 paddr = vaddr; - if (!MapVAddr(regs, LOAD, vaddr, paddr)) { - HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false); - } +u8 Mem::Read8(n64::Registers ®s, u32 paddr) { + if(paddr >= 0x10000000 && paddr <= 0x1FBFFFFF) + paddr = (paddr + 2) & ~2; const auto page = paddr >> 12; const auto offset = paddr & 0xFFF; @@ -123,7 +126,6 @@ u8 Mem::Read8(n64::Registers ®s, u64 vaddr, s64 pc) { return (w >> (offs * 8)) & 0xff; } case 0x10000000 ... 0x1FBFFFFF: - paddr = (paddr + 2) & ~2; return cart[BYTE_ADDRESS(paddr) & romMask]; case 0x1FC00000 ... 0x1FC007BF: return pifBootrom[BYTE_ADDRESS(paddr) - 0x1FC00000]; @@ -140,13 +142,9 @@ u8 Mem::Read8(n64::Registers ®s, u64 vaddr, s64 pc) { } } -template -u16 Mem::Read16(n64::Registers ®s, u64 vaddr, s64 pc) { - u32 paddr = vaddr; - if (!MapVAddr(regs, LOAD, vaddr, paddr)) { - HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false); - } +u16 Mem::Read16(n64::Registers ®s, u32 paddr) { + if(paddr >= 0x10000000 && paddr <= 0x1FBFFFFF) + paddr = (paddr + 2) & ~3; const auto page = paddr >> 12; const auto offset = paddr & 0xFFF; @@ -169,7 +167,6 @@ u16 Mem::Read16(n64::Registers ®s, u64 vaddr, s64 pc) { case 0x04500000 ... 0x048FFFFF: return mmio.Read(paddr); case 0x10000000 ... 0x1FBFFFFF: - paddr = (paddr + 2) & ~3; return Util::ReadAccess(cart.data(), HALF_ADDRESS(paddr) & romMask); case 0x1FC00000 ... 0x1FC007BF: return Util::ReadAccess(pifBootrom, HALF_ADDRESS(paddr) - 0x1FC00000); @@ -186,14 +183,7 @@ u16 Mem::Read16(n64::Registers ®s, u64 vaddr, s64 pc) { } } -template -u32 Mem::Read32(n64::Registers ®s, u64 vaddr, s64 pc) { - u32 paddr = vaddr; - if (!MapVAddr(regs, LOAD, vaddr, paddr)) { - HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false); - } - +u32 Mem::Read32(n64::Registers ®s, u32 paddr) { const auto page = paddr >> 12; const auto offset = paddr & 0xFFF; const auto pointer = readPages[page]; @@ -226,14 +216,7 @@ u32 Mem::Read32(n64::Registers ®s, u64 vaddr, s64 pc) { } } -template -u64 Mem::Read64(n64::Registers ®s, u64 vaddr, s64 pc) { - u32 paddr = vaddr; - if (!MapVAddr(regs, LOAD, vaddr, paddr)) { - HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false); - } - +u64 Mem::Read64(n64::Registers ®s, u32 paddr) { const auto page = paddr >> 12; const auto offset = paddr & 0xFFF; const auto pointer = readPages[page]; @@ -271,35 +254,19 @@ u64 Mem::Read64(n64::Registers ®s, u64 vaddr, s64 pc) { } } -template u8 Mem::Read8(n64::Registers ®s, u64 vaddr, s64 pc); -template u8 Mem::Read8(n64::Registers ®s, u64 vaddr, s64 pc); -template u16 Mem::Read16(n64::Registers ®s, u64 vaddr, s64 pc); -template u16 Mem::Read16(n64::Registers ®s, u64 vaddr, s64 pc); -template u32 Mem::Read32(n64::Registers ®s, u64 vaddr, s64 pc); -template u32 Mem::Read32(n64::Registers ®s, u64 vaddr, s64 pc); -template u64 Mem::Read64(n64::Registers ®s, u64 vaddr, s64 pc); -template u64 Mem::Read64(n64::Registers ®s, u64 vaddr, s64 pc); - -template -void Mem::Write8(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s64 pc) { - u32 paddr = vaddr; - if (!MapVAddr(regs, LOAD, vaddr, paddr)) { - HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false); - } - +void Mem::Write8(Registers& regs, n64::JIT::Dynarec& dyn, u32 paddr, u32 val) { dyn.InvalidatePage(BYTE_ADDRESS(paddr)); + if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) { + val = val << (8 * (3 - (paddr & 3))); + paddr = (paddr & DMEM_DSIZE) & ~3; + } + const auto page = paddr >> 12; auto offset = paddr & 0xFFF; const auto pointer = readPages[page]; if(pointer) { - if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) { - val = val << (8 * (3 - (paddr & 3))); - offset = (offset & DMEM_DSIZE) & ~3; - } - ((u8*)pointer)[BYTE_ADDRESS(offset)] = val; } else { switch (paddr) { @@ -307,8 +274,6 @@ void Mem::Write8(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s6 mmio.rdp.rdram[BYTE_ADDRESS(paddr)] = val; break; case 0x04000000 ... 0x0403FFFF: - val = val << (8 * (3 - (paddr & 3))); - paddr = (paddr & DMEM_DSIZE) & ~3; if (paddr & 0x1000) Util::WriteAccess(mmio.rsp.imem, paddr & IMEM_DSIZE, val); else @@ -341,26 +306,19 @@ void Mem::Write8(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s6 } } -template -void Mem::Write16(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s64 pc) { - u32 paddr = vaddr; - if (!MapVAddr(regs, STORE, vaddr, paddr)) { - HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false); - } - +void Mem::Write16(Registers& regs, n64::JIT::Dynarec& dyn, u32 paddr, u32 val) { dyn.InvalidatePage(HALF_ADDRESS(paddr)); + if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) { + val = val << (16 * !(paddr & 2)); + paddr &= ~3; + } + const auto page = paddr >> 12; auto offset = paddr & 0xFFF; const auto pointer = readPages[page]; if(pointer) { - if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) { - val = val << (16 * !(paddr & 2)); - offset &= ~3; - } - Util::WriteAccess((u8*)pointer, HALF_ADDRESS(offset), val); } else { switch (paddr) { @@ -368,8 +326,6 @@ void Mem::Write16(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s Util::WriteAccess(mmio.rdp.rdram.data(), HALF_ADDRESS(paddr), val); break; case 0x04000000 ... 0x0403FFFF: - val = val << (16 * !(paddr & 2)); - paddr &= ~3; if (paddr & 0x1000) Util::WriteAccess(mmio.rsp.imem, paddr & IMEM_DSIZE, val); else @@ -402,14 +358,7 @@ void Mem::Write16(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s } } -template -void Mem::Write32(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s64 pc) { - u32 paddr = vaddr; - if(!MapVAddr(regs, STORE, vaddr, paddr)) { - HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false); - } - +void Mem::Write32(Registers& regs, n64::JIT::Dynarec& dyn, u32 paddr, u32 val) { dyn.InvalidatePage(paddr); const auto page = paddr >> 12; @@ -455,24 +404,18 @@ void Mem::Write32(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s } } -template -void Mem::Write64(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u64 val, s64 pc) { - u32 paddr = vaddr; - if(!MapVAddr(regs, STORE, vaddr, paddr)) { - HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false); - } - +void Mem::Write64(Registers& regs, n64::JIT::Dynarec& dyn, u32 paddr, u64 val) { dyn.InvalidatePage(paddr); + if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) { + val >>= 32; + } + const auto page = paddr >> 12; auto offset = paddr & 0xFFF; const auto pointer = readPages[page]; if(pointer) { - if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) { - val >>= 32; - } Util::WriteAccess((u8*)pointer, offset, val); } else { switch (paddr) { @@ -480,7 +423,6 @@ void Mem::Write64(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u64 val, s Util::WriteAccess(mmio.rdp.rdram.data(), paddr, val); break; case 0x04000000 ... 0x0403FFFF: - val >>= 32; if (paddr & 0x1000) Util::WriteAccess(mmio.rsp.imem, paddr & IMEM_DSIZE, val); else @@ -511,21 +453,10 @@ void Mem::Write64(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u64 val, s } } -template void Mem::Write8(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc); -template void Mem::Write8(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc); -template void Mem::Write16(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc); -template void Mem::Write16(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc); -template void Mem::Write32(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc); -template void Mem::Write32(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc); -template void Mem::Write64(Registers& regs, JIT::Dynarec&, u64 vaddr, u64 val, s64 pc); -template void Mem::Write64(Registers& regs, JIT::Dynarec&, u64 vaddr, u64 val, s64 pc); - -template -void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) { - u32 paddr = vaddr; - if (!MapVAddr(regs, LOAD, vaddr, paddr)) { - HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false); +void Mem::Write8(Registers& regs, u32 paddr, u32 val) { + if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) { + val = val << (8 * (3 - (paddr & 3))); + paddr = (paddr & DMEM_DSIZE) & ~3; } const auto page = paddr >> 12; @@ -533,11 +464,6 @@ void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) { const auto pointer = readPages[page]; if(pointer) { - if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) { - val = val << (8 * (3 - (paddr & 3))); - offset = (offset & DMEM_DSIZE) & ~3; - } - ((u8*)pointer)[BYTE_ADDRESS(offset)] = val; } else { switch (paddr) { @@ -545,8 +471,6 @@ void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) { mmio.rdp.rdram[BYTE_ADDRESS(paddr)] = val; break; case 0x04000000 ... 0x0403FFFF: - val = val << (8 * (3 - (paddr & 3))); - paddr = (paddr & DMEM_DSIZE) & ~3; if (paddr & 0x1000) Util::WriteAccess(mmio.rsp.imem, paddr & IMEM_DSIZE, val); else @@ -579,12 +503,10 @@ void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) { } } -template -void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc) { - u32 paddr = vaddr; - if (!MapVAddr(regs, STORE, vaddr, paddr)) { - HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false); +void Mem::Write16(Registers& regs, u32 paddr, u32 val) { + if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) { + val = val << (16 * !(paddr & 2)); + paddr &= ~3; } const auto page = paddr >> 12; @@ -592,11 +514,6 @@ void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc) { const auto pointer = readPages[page]; if(pointer) { - if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) { - val = val << (16 * !(paddr & 2)); - offset &= ~3; - } - Util::WriteAccess((u8*)pointer, HALF_ADDRESS(offset), val); } else { switch (paddr) { @@ -604,8 +521,6 @@ void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc) { Util::WriteAccess(mmio.rdp.rdram.data(), HALF_ADDRESS(paddr), val); break; case 0x04000000 ... 0x0403FFFF: - val = val << (16 * !(paddr & 2)); - paddr &= ~3; if (paddr & 0x1000) Util::WriteAccess(mmio.rsp.imem, paddr & IMEM_DSIZE, val); else @@ -638,14 +553,7 @@ void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc) { } } -template -void Mem::Write32(Registers& regs, u64 vaddr, u32 val, s64 pc) { - u32 paddr = vaddr; - if(!MapVAddr(regs, STORE, vaddr, paddr)) { - HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false); - } - +void Mem::Write32(Registers& regs, u32 paddr, u32 val) { const auto page = paddr >> 12; auto offset = paddr & 0xFFF; const auto pointer = readPages[page]; @@ -689,12 +597,9 @@ void Mem::Write32(Registers& regs, u64 vaddr, u32 val, s64 pc) { } } -template -void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc) { - u32 paddr = vaddr; - if(!MapVAddr(regs, STORE, vaddr, paddr)) { - HandleTLBException(regs, vaddr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, false); +void Mem::Write64(Registers& regs, u32 paddr, u64 val) { + if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) { + val >>= 32; } const auto page = paddr >> 12; @@ -702,9 +607,6 @@ void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc) { const auto pointer = readPages[page]; if(pointer) { - if(paddr >= 0x04000000 && paddr <= 0x0403FFFF) { - val >>= 32; - } Util::WriteAccess((u8*)pointer, offset, val); } else { switch (paddr) { @@ -712,7 +614,6 @@ void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc) { Util::WriteAccess(mmio.rdp.rdram.data(), paddr, val); break; case 0x04000000 ... 0x0403FFFF: - val >>= 32; if (paddr & 0x1000) Util::WriteAccess(mmio.rsp.imem, paddr & IMEM_DSIZE, val); else @@ -742,13 +643,4 @@ void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc) { } } } - -template void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc); -template void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc); -template void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc); -template void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc); -template void Mem::Write32(Registers& regs, u64 vaddr, u32 val, s64 pc); -template void Mem::Write32(Registers& regs, u64 vaddr, u32 val, s64 pc); -template void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc); -template void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc); } \ No newline at end of file diff --git a/src/backend/core/Mem.hpp b/src/backend/core/Mem.hpp index b12b9906..43fb272f 100644 --- a/src/backend/core/Mem.hpp +++ b/src/backend/core/Mem.hpp @@ -28,30 +28,18 @@ struct Mem { return mmio.rdp.rdram.data(); } - template - u8 Read8(Registers&, u64, s64); - template - u16 Read16(Registers&, u64, s64); - template - u32 Read32(Registers&, u64, s64); - template - u64 Read64(Registers&, u64, s64); - template - void Write8(Registers&, JIT::Dynarec&, u64, u32, s64); - template - void Write16(Registers&, JIT::Dynarec&, u64, u32, s64); - template - void Write32(Registers&, JIT::Dynarec&, u64, u32, s64); - template - void Write64(Registers&, JIT::Dynarec&, u64, u64, s64); - template - void Write8(Registers&, u64, u32, s64); - template - void Write16(Registers&, u64, u32, s64); - template - void Write32(Registers&, u64, u32, s64); - template - void Write64(Registers&, u64, u64, s64); + u8 Read8(Registers&, u32); + u16 Read16(Registers&, u32); + u32 Read32(Registers&, u32); + u64 Read64(Registers&, u32); + void Write8(Registers&, JIT::Dynarec&, u32, u32); + void Write16(Registers&, JIT::Dynarec&, u32, u32); + void Write32(Registers&, JIT::Dynarec&, u32, u32); + void Write64(Registers&, JIT::Dynarec&, u32, u64); + void Write8(Registers&, u32, u32); + void Write16(Registers&, u32, u32); + void Write32(Registers&, u32, u32); + void Write64(Registers&, u32, u64); MMIO mmio; u8 pifRam[PIF_RAM_SIZE]{}; diff --git a/src/backend/core/dynarec/cop/cop1instructions.cpp b/src/backend/core/dynarec/cop/cop1instructions.cpp index 5ee73242..5c27af92 100644 --- a/src/backend/core/dynarec/cop/cop1instructions.cpp +++ b/src/backend/core/dynarec/cop/cop1instructions.cpp @@ -448,16 +448,13 @@ void lwc1(n64::Registers& regs, Mem& mem, u32 instr) { } u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; - if(addr & 3) { - FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); - } u32 physical; if(!MapVAddr(regs, LOAD, addr, physical)) { HandleTLBException(regs, addr); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { - u32 data = mem.Read32(regs, physical, regs.oldPC); + u32 data = mem.Read32(regs, physical); regs.cop1.SetReg(regs.cop0, FT(instr), data); } } @@ -469,57 +466,48 @@ void swc1(n64::Registers& regs, Mem& mem, u32 instr) { } u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; - if(addr & 3) { - FireException(regs, ExceptionCode::AddressErrorStore, 0, true); - } u32 physical; if(!MapVAddr(regs, STORE, addr, physical)) { HandleTLBException(regs, addr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { - mem.Write32(regs, physical, regs.cop1.GetReg(regs.cop0, FT(instr)), regs.oldPC); + mem.Write32(regs, physical, regs.cop1.GetReg(regs.cop0, FT(instr))); } } void ldc1(n64::Registers& regs, Mem& mem, u32 instr) { if(!regs.cop0.status.cu1) { - FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); + FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); return; } u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; - if(addr & 7) { - FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); - } u32 physical; if(!MapVAddr(regs, LOAD, addr, physical)) { HandleTLBException(regs, addr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { - u64 data = mem.Read64(regs, physical, regs.oldPC); + u64 data = mem.Read64(regs, physical); regs.cop1.SetReg(regs.cop0, FT(instr), data); } } void sdc1(n64::Registers& regs, Mem& mem, u32 instr) { if(!regs.cop0.status.cu1) { - FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); + FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); return; } u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; - if(addr & 7) { - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); - } u32 physical; if(!MapVAddr(regs, STORE, addr, physical)) { HandleTLBException(regs, addr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { - mem.Write64(regs, physical, regs.cop1.GetReg(regs.cop0, FT(instr)), regs.oldPC); + mem.Write64(regs, physical, regs.cop1.GetReg(regs.cop0, FT(instr))); } } diff --git a/src/backend/core/dynarec/instructions.cpp b/src/backend/core/dynarec/instructions.cpp index 9e838c15..d9bd6526 100644 --- a/src/backend/core/dynarec/instructions.cpp +++ b/src/backend/core/dynarec/instructions.cpp @@ -1,5 +1,4 @@ -#include -#include +#include #define se_imm(x) ((s16)((x) & 0xFFFF)) #define check_address_error(mask, addr) (((!regs.cop0.is_64bit_addressing) && (s32)(addr) != (addr)) || (((addr) & (mask)) != 0)) @@ -41,7 +40,6 @@ void addiu(Registers& regs, u32 instr) { s16 imm = (s16)(instr); s32 result = rs + imm; regs.gpr[RT(instr)] = result; - Util::print("addiu {:08X}, {:04X} = {:08X} [reg: {:016X}]\n", (u32)rs, imm, (u32)result, (u64)regs.gpr[RT(instr)]); } void dadd(Registers& regs, u32 instr) { @@ -147,7 +145,6 @@ void ddivu(Registers& regs, u32 instr) { } void branch(Registers& regs, bool cond, s64 address) { - //Util::debug("\t\tJIT branch from {:08X} -> {:08X}\n", (u32)regs.oldPC, (u32)address); regs.delaySlot = true; if (cond) { regs.nextPC = address; @@ -157,10 +154,8 @@ void branch(Registers& regs, bool cond, s64 address) { void branch_likely(Registers& regs, bool cond, s64 address) { regs.delaySlot = true; if (cond) { - //Util::debug("\t\tJIT branch likely taken from {:08X} -> {:08X}\n", (u32)regs.oldPC, (u32)address); regs.nextPC = address; } else { - //Util::debug("\t\tJIT branch likely not taken from {:08X} -> {:08X}\n", (u32)regs.oldPC, (u32)address); regs.SetPC(regs.nextPC); } } @@ -199,18 +194,30 @@ void lui(Registers& regs, u32 instr) { void lb(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; - regs.gpr[RT(instr)] = (s8)mem.Read8(regs, address, regs.oldPC); + u32 paddr = 0; + if(!MapVAddr(regs, LOAD, address, paddr)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); + } else { + regs.gpr[RT(instr)] = (s8)mem.Read8(regs, paddr); + } } void lh(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; - if (check_address_error(address, 0b1)) { + if ((address & 0b1) > 0) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } - regs.gpr[RT(instr)] = (s16)mem.Read16(regs, address, regs.oldPC); + u32 paddr = 0; + if(!MapVAddr(regs, LOAD, address, paddr)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); + } else { + regs.gpr[RT(instr)] = (s16)mem.Read16(regs, address); + } } void lw(Registers& regs, Mem& mem, u32 instr) { @@ -222,23 +229,28 @@ void lw(Registers& regs, Mem& mem, u32 instr) { return; } - u32 physical; + u32 physical = 0; if (!MapVAddr(regs, LOAD, address, physical)) { HandleTLBException(regs, address); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { - regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical, regs.oldPC); + regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical); } } void ll(Registers& regs, Mem& mem, u32 instr) { - s64 address = regs.gpr[RS(instr)] + (s16)instr; + u64 address = regs.gpr[RS(instr)] + (s16)instr; u32 physical; if (!MapVAddr(regs, LOAD, address, physical)) { HandleTLBException(regs, address); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { - regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical, regs.oldPC); + if ((address & 0b11) > 0) { + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); + return; + } else { + regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical); + } } regs.cop0.llbit = true; @@ -254,7 +266,7 @@ void lwl(Registers& regs, Mem& mem, u32 instr) { } else { u32 shift = 8 * ((address ^ 0) & 3); u32 mask = 0xFFFFFFFF << shift; - u32 data = mem.Read32(regs, paddr & ~3, regs.oldPC); + u32 data = mem.Read32(regs, paddr & ~3); s32 result = s32((regs.gpr[RT(instr)] & ~mask) | (data << shift)); regs.gpr[RT(instr)] = result; } @@ -269,7 +281,7 @@ void lwr(Registers& regs, Mem& mem, u32 instr) { } else { u32 shift = 8 * ((address ^ 3) & 3); u32 mask = 0xFFFFFFFF >> shift; - u32 data = mem.Read32(regs, paddr & ~3, regs.oldPC); + u32 data = mem.Read32(regs, paddr & ~3); s32 result = s32((regs.gpr[RT(instr)] & ~mask) | (data >> shift)); regs.gpr[RT(instr)] = result; } @@ -283,22 +295,30 @@ void ld(Registers& regs, Mem& mem, u32 instr) { return; } - s64 value = mem.Read64(regs, address, regs.oldPC); + s64 value = mem.Read64(regs, address); regs.gpr[RT(instr)] = value; } void lld(Registers& regs, Mem& mem, u32 instr) { - s64 address = regs.gpr[RS(instr)] + (s16)instr; + if (!regs.cop0.is_64bit_addressing && !regs.cop0.kernel_mode) { + FireException(regs, ExceptionCode::ReservedInstruction, 0, true); + return; + } + + u64 address = regs.gpr[RS(instr)] + (s16)instr; u32 paddr; if (!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { - regs.gpr[RT(instr)] = mem.Read64(regs, paddr, regs.oldPC); + if ((address & 0b111) > 0) { + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); + } else { + regs.gpr[RT(instr)] = mem.Read64(regs, paddr); + regs.cop0.llbit = true; + regs.cop0.LLAddr = paddr >> 4; + } } - - regs.cop0.llbit = true; - regs.cop0.LLAddr = paddr >> 4; } void ldl(Registers& regs, Mem& mem, u32 instr) { @@ -310,7 +330,7 @@ void ldl(Registers& regs, Mem& mem, u32 instr) { } else { s32 shift = 8 * ((address ^ 0) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF << shift; - u64 data = mem.Read64(regs, paddr & ~7, regs.oldPC); + u64 data = mem.Read64(regs, paddr & ~7); s64 result = (s64) ((regs.gpr[RT(instr)] & ~mask) | (data << shift)); regs.gpr[RT(instr)] = result; } @@ -325,7 +345,7 @@ void ldr(Registers& regs, Mem& mem, u32 instr) { } else { s32 shift = 8 * ((address ^ 7) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; - u64 data = mem.Read64(regs, paddr & ~7, regs.oldPC); + u64 data = mem.Read64(regs, paddr & ~7); s64 result = (s64) ((regs.gpr[RT(instr)] & ~mask) | (data >> shift)); regs.gpr[RT(instr)] = result; } @@ -333,7 +353,7 @@ void ldr(Registers& regs, Mem& mem, u32 instr) { void lbu(Registers& regs, Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; - u8 value = mem.Read8(regs, address, regs.oldPC); + u8 value = mem.Read8(regs, address); regs.gpr[RT(instr)] = value; } @@ -345,7 +365,7 @@ void lhu(Registers& regs, Mem& mem, u32 instr) { return; } - u16 value = mem.Read16(regs, address, regs.oldPC); + u16 value = mem.Read16(regs, address); regs.gpr[RT(instr)] = value; } @@ -357,28 +377,36 @@ void lwu(Registers& regs, Mem& mem, u32 instr) { return; } - u32 value = mem.Read32(regs, address, regs.oldPC); + u32 value = mem.Read32(regs, address); regs.gpr[RT(instr)] = value; } void sb(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) { u32 address = regs.gpr[RS(instr)] + (s16)instr; - mem.Write8(regs, dyn, address, regs.gpr[RT(instr)], regs.oldPC); + mem.Write8(regs, dyn, address, regs.gpr[RT(instr)]); } void sc(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) { - s64 address = regs.gpr[RS(instr)] + (s16)instr; - if (check_address_error(address, 0b11)) { - HandleTLBException(regs, address); + u64 address = regs.gpr[RS(instr)] + (s16)instr; + + if ((address & 0b11) > 0) { FireException(regs, ExceptionCode::AddressErrorStore, 0, true); + return; } if(regs.cop0.llbit) { - mem.Write32(regs, dyn, address, regs.gpr[RT(instr)], regs.oldPC); + regs.cop0.llbit = false; + u32 paddr = 0; + if(!MapVAddr(regs, STORE, address, paddr)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); + } else { + mem.Write32(regs, dyn, paddr, regs.gpr[RT(instr)]); + regs.gpr[RT(instr)] = 1; + } + } else { + regs.gpr[RT(instr)] = 0; } - - regs.gpr[RT(instr)] = (u64)regs.cop0.llbit; - regs.cop0.llbit = false; } void scd(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) { @@ -390,7 +418,7 @@ void scd(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) { } if(regs.cop0.llbit) { - mem.Write64(regs, dyn, address, regs.gpr[RT(instr)], regs.oldPC); + mem.Write64(regs, dyn, address, regs.gpr[RT(instr)]); } regs.gpr[RT(instr)] = (s64)((u64)regs.cop0.llbit); @@ -410,7 +438,7 @@ void sh(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) { HandleTLBException(regs, address); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { - mem.Write16(regs, dyn, physical, regs.gpr[RT(instr)], regs.oldPC); + mem.Write16(regs, dyn, physical, regs.gpr[RT(instr)]); } } @@ -428,7 +456,7 @@ void sw(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) { HandleTLBException(regs, address); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { - mem.Write32(regs, dyn, physical, regs.gpr[RT(instr)], regs.oldPC); + mem.Write32(regs, dyn, physical, regs.gpr[RT(instr)]); } } @@ -445,7 +473,7 @@ void sd(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) { HandleTLBException(regs, address); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { - mem.Write64(regs, dyn, physical, regs.gpr[RT(instr)], regs.oldPC); + mem.Write64(regs, dyn, physical, regs.gpr[RT(instr)]); } } @@ -459,9 +487,9 @@ void sdl(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) { } else { s32 shift = 8 * ((address ^ 0) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; - u64 data = mem.Read64(regs, paddr & ~7, regs.oldPC); + u64 data = mem.Read64(regs, paddr & ~7); u64 rt = regs.gpr[RT(instr)]; - mem.Write64(regs, dyn, paddr & ~7, (data & ~mask) | (rt >> shift), regs.oldPC); + mem.Write64(regs, dyn, paddr & ~7, (data & ~mask) | (rt >> shift)); } } @@ -474,9 +502,9 @@ void sdr(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) { } else { s32 shift = 8 * ((address ^ 7) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF << shift; - u64 data = mem.Read64(regs, paddr & ~7, regs.oldPC); + u64 data = mem.Read64(regs, paddr & ~7); u64 rt = regs.gpr[RT(instr)]; - mem.Write64(regs, dyn, paddr & ~7, (data & ~mask) | (rt << shift), regs.oldPC); + mem.Write64(regs, dyn, paddr & ~7, (data & ~mask) | (rt << shift)); } } @@ -489,9 +517,9 @@ void swl(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) { } else { u32 shift = 8 * ((address ^ 0) & 3); u32 mask = 0xFFFFFFFF >> shift; - u32 data = mem.Read32(regs, paddr & ~3, regs.oldPC); + u32 data = mem.Read32(regs, paddr & ~3); u32 rt = regs.gpr[RT(instr)]; - mem.Write32(regs, dyn, paddr & ~3, (data & ~mask) | (rt >> shift), regs.oldPC); + mem.Write32(regs, dyn, paddr & ~3, (data & ~mask) | (rt >> shift)); } } @@ -504,9 +532,9 @@ void swr(Registers& regs, Mem& mem, Dynarec& dyn, u32 instr) { } else { u32 shift = 8 * ((address ^ 3) & 3); u32 mask = 0xFFFFFFFF << shift; - u32 data = mem.Read32(regs, paddr & ~3, regs.oldPC); + u32 data = mem.Read32(regs, paddr & ~3); u32 rt = regs.gpr[RT(instr)]; - mem.Write32(regs, dyn, paddr & ~3, (data & ~mask) | (rt << shift), regs.oldPC); + mem.Write32(regs, dyn, paddr & ~3, (data & ~mask) | (rt << shift)); } } @@ -525,12 +553,8 @@ void nor(Registers& regs, u32 instr) { } void j(Registers& regs, u32 instr) { - s32 target = (instr & 0x3ffffff) << 2; - s64 address = (regs.oldPC & ~0xfffffff) | target; - if (check_address_error(address, 0b11)) { - HandleTLBException(regs, address); - FireException(regs, ExceptionCode::DataBusError, 0, true); - } + u64 target = (instr & 0x3ffffff) << 2; + u64 address = ((regs.pc - 4) & ~0xfffffff) | target; branch(regs, true, address); } @@ -686,7 +710,7 @@ void jr(Registers& regs, u32 instr) { s64 address = regs.gpr[RS(instr)]; if (check_address_error(address, 0b11)) { HandleTLBException(regs, address); - FireException(regs, ExceptionCode::DataBusError, 0, regs.oldPC); + FireException(regs, ExceptionCode::DataBusError, 0, true); } branch(regs, true, address); @@ -697,7 +721,7 @@ void dsub(Registers& regs, u32 instr) { s64 rs = regs.gpr[RS(instr)]; s64 result = rs - rt; if(check_signed_underflow(rs, rt, result)) { - FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); + FireException(regs, ExceptionCode::Overflow, 0, true); } else { regs.gpr[RD(instr)] = result; } @@ -715,7 +739,7 @@ void sub(Registers& regs, u32 instr) { s32 rs = regs.gpr[RS(instr)]; s32 result = rs - rt; if(check_signed_underflow(rs, rt, result)) { - FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); + FireException(regs, ExceptionCode::Overflow, 0, true); } else { regs.gpr[RD(instr)] = result; } @@ -778,7 +802,7 @@ void mthi(Registers& regs, u32 instr) { void trap(Registers& regs, bool cond) { if(cond) { - FireException(regs, ExceptionCode::Trap, 0, regs.oldPC); + FireException(regs, ExceptionCode::Trap, 0, true); } } @@ -798,4 +822,13 @@ void dmtc2(Dynarec& dyn, Registers& regs, u32 instr) { void dmfc2(Dynarec& dyn, Registers& regs, u32 instr) { regs.gpr[RT(instr)] = dyn.cop2Latch; } + +void ctc2(u32) { + +} + +void cfc2(u32) { + +} + } \ No newline at end of file diff --git a/src/backend/core/interpreter/cop/cop0instructions.cpp b/src/backend/core/interpreter/cop/cop0instructions.cpp index b9fd947a..84c4586b 100644 --- a/src/backend/core/interpreter/cop/cop0instructions.cpp +++ b/src/backend/core/interpreter/cop/cop0instructions.cpp @@ -31,7 +31,7 @@ void Cop0::eret(Registers& regs) { } -void Cop0::tlbr(Registers& regs) { +void Cop0::tlbr() { u8 Index = index & 0b111111; if (Index >= 32) { Util::panic("TLBR with TLB index {}", index); @@ -48,7 +48,7 @@ void Cop0::tlbr(Registers& regs) { pageMask.raw = entry.pageMask.raw; } -void Cop0::tlbw(int index_, Registers& regs) { +void Cop0::tlbw(int index_) { PageMask page_mask{}; page_mask = pageMask; u32 top = page_mask.mask & 0xAAA; diff --git a/src/backend/core/interpreter/cop/cop1instructions.cpp b/src/backend/core/interpreter/cop/cop1instructions.cpp index 2b4936b0..787427f2 100644 --- a/src/backend/core/interpreter/cop/cop1instructions.cpp +++ b/src/backend/core/interpreter/cop/cop1instructions.cpp @@ -450,16 +450,13 @@ void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) { } u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; - if(addr & 3) { - FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); - } u32 physical; if(!MapVAddr(regs, LOAD, addr, physical)) { HandleTLBException(regs, addr); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { - u32 data = mem.Read32(regs, physical, regs.oldPC); + u32 data = mem.Read32(regs, physical); SetReg(regs.cop0, FT(instr), data); } } @@ -471,16 +468,13 @@ void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) { } u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; - if(addr & 3) { - FireException(regs, ExceptionCode::AddressErrorStore, 0, true); - } u32 physical; if(!MapVAddr(regs, STORE, addr, physical)) { HandleTLBException(regs, addr); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { - mem.Write32(regs, physical, GetReg(regs.cop0, FT(instr)), regs.oldPC); + mem.Write32(regs, physical, GetReg(regs.cop0, FT(instr))); } } @@ -491,37 +485,31 @@ void Cop1::ldc1(Registers& regs, Mem& mem, u32 instr) { } u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; - if(addr & 7) { - FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); - } u32 physical; if(!MapVAddr(regs, LOAD, addr, physical)) { HandleTLBException(regs, addr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { - u64 data = mem.Read64(regs, physical, regs.oldPC); + u64 data = mem.Read64(regs, physical); SetReg(regs.cop0, FT(instr), data); } } void Cop1::sdc1(Registers& regs, Mem& mem, u32 instr) { if(!regs.cop0.status.cu1) { - FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); + FireException(regs, ExceptionCode::CoprocessorUnusable, 1, true); return; } u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; - if(addr & 7) { - FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); - } u32 physical; if(!MapVAddr(regs, STORE, addr, physical)) { HandleTLBException(regs, addr); - FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { - mem.Write64(regs, physical, GetReg(regs.cop0, FT(instr)), regs.oldPC); + mem.Write64(regs, physical, GetReg(regs.cop0, FT(instr))); } } diff --git a/src/backend/core/interpreter/instructions.cpp b/src/backend/core/interpreter/instructions.cpp index cb24a4cf..89a10b83 100644 --- a/src/backend/core/interpreter/instructions.cpp +++ b/src/backend/core/interpreter/instructions.cpp @@ -1,7 +1,7 @@ #include #define se_imm(x) ((s16)((x) & 0xFFFF)) -#define check_address_error(mask, addr) (((!regs.cop0.is_64bit_addressing) && (s32)(addr) != (addr)) || (((addr) & (mask)) != 0)) +#define check_address_error(mask, vaddr) (((!regs.cop0.is_64bit_addressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0)) #define check_signed_overflow(op1, op2, res) (((~((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1) #define check_signed_underflow(op1, op2, res) (((((op1) ^ (op2)) & ((op1) ^ (res))) >> ((sizeof(res) * 8) - 1)) & 1) @@ -194,46 +194,63 @@ void Interpreter::lui(u32 instr) { void Interpreter::lb(Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; - regs.gpr[RT(instr)] = (s8)mem.Read8(regs, address, regs.oldPC); + u32 paddr = 0; + if(!MapVAddr(regs, LOAD, address, paddr)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); + } else { + regs.gpr[RT(instr)] = (s8)mem.Read8(regs, paddr); + } } void Interpreter::lh(Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; - if (check_address_error(address, 0b1)) { + if ((address & 0b1) > 0) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } - regs.gpr[RT(instr)] = (s16)mem.Read16(regs, address, regs.oldPC); + u32 paddr = 0; + if(!MapVAddr(regs, LOAD, address, paddr)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); + } else { + regs.gpr[RT(instr)] = (s16)mem.Read16(regs, paddr); + } } void Interpreter::lw(Mem& mem, u32 instr) { s16 offset = instr; u64 address = regs.gpr[RS(instr)] + offset; - if (check_address_error(address, 0b11)) { + if (check_address_error(0b11, address)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } - u32 physical; + u32 physical = 0; if (!MapVAddr(regs, LOAD, address, physical)) { HandleTLBException(regs, address); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { - regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical, regs.oldPC); + regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical); } } void Interpreter::ll(Mem& mem, u32 instr) { - s64 address = regs.gpr[RS(instr)] + (s16)instr; + u64 address = regs.gpr[RS(instr)] + (s16)instr; u32 physical; if (!MapVAddr(regs, LOAD, address, physical)) { HandleTLBException(regs, address); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { - regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical, regs.oldPC); + if ((address & 0b11) > 0) { + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); + return; + } else { + regs.gpr[RT(instr)] = (s32)mem.Read32(regs, physical); + } } regs.cop0.llbit = true; @@ -249,7 +266,7 @@ void Interpreter::lwl(Mem& mem, u32 instr) { } else { u32 shift = 8 * ((address ^ 0) & 3); u32 mask = 0xFFFFFFFF << shift; - u32 data = mem.Read32(regs, paddr & ~3, regs.oldPC); + u32 data = mem.Read32(regs, paddr & ~3); s32 result = s32((regs.gpr[RT(instr)] & ~mask) | (data << shift)); regs.gpr[RT(instr)] = result; } @@ -264,7 +281,7 @@ void Interpreter::lwr(Mem& mem, u32 instr) { } else { u32 shift = 8 * ((address ^ 3) & 3); u32 mask = 0xFFFFFFFF >> shift; - u32 data = mem.Read32(regs, paddr & ~3, regs.oldPC); + u32 data = mem.Read32(regs, paddr & ~3); s32 result = s32((regs.gpr[RT(instr)] & ~mask) | (data >> shift)); regs.gpr[RT(instr)] = result; } @@ -272,28 +289,42 @@ void Interpreter::lwr(Mem& mem, u32 instr) { void Interpreter::ld(Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; - if (check_address_error(address, 0b111)) { + if (check_address_error(0b111, address)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } - s64 value = mem.Read64(regs, address, regs.oldPC); - regs.gpr[RT(instr)] = value; + u32 paddr = 0; + if(!MapVAddr(regs, LOAD, address, paddr)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); + } else { + s64 value = mem.Read64(regs, paddr); + regs.gpr[RT(instr)] = value; + } } void Interpreter::lld(Mem& mem, u32 instr) { - s64 address = regs.gpr[RS(instr)] + (s16)instr; + if (!regs.cop0.is_64bit_addressing && !regs.cop0.kernel_mode) { + FireException(regs, ExceptionCode::ReservedInstruction, 0, true); + return; + } + + u64 address = regs.gpr[RS(instr)] + (s16)instr; u32 paddr; if (!MapVAddr(regs, LOAD, address, paddr)) { HandleTLBException(regs, address); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); } else { - regs.gpr[RT(instr)] = mem.Read64(regs, paddr, regs.oldPC); + if ((address & 0b111) > 0) { + FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); + } else { + regs.gpr[RT(instr)] = mem.Read64(regs, paddr); + regs.cop0.llbit = true; + regs.cop0.LLAddr = paddr >> 4; + } } - - regs.cop0.llbit = true; - regs.cop0.LLAddr = paddr >> 4; } void Interpreter::ldl(Mem& mem, u32 instr) { @@ -305,7 +336,7 @@ void Interpreter::ldl(Mem& mem, u32 instr) { } else { s32 shift = 8 * ((address ^ 0) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF << shift; - u64 data = mem.Read64(regs, paddr & ~7, regs.oldPC); + u64 data = mem.Read64(regs, paddr & ~7); s64 result = (s64) ((regs.gpr[RT(instr)] & ~mask) | (data << shift)); regs.gpr[RT(instr)] = result; } @@ -320,7 +351,7 @@ void Interpreter::ldr(Mem& mem, u32 instr) { } else { s32 shift = 8 * ((address ^ 7) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; - u64 data = mem.Read64(regs, paddr & ~7, regs.oldPC); + u64 data = mem.Read64(regs, paddr & ~7); s64 result = (s64) ((regs.gpr[RT(instr)] & ~mask) | (data >> shift)); regs.gpr[RT(instr)] = result; } @@ -328,91 +359,129 @@ void Interpreter::ldr(Mem& mem, u32 instr) { void Interpreter::lbu(Mem& mem, u32 instr) { u64 address = regs.gpr[RS(instr)] + (s16)instr; - u8 value = mem.Read8(regs, address, regs.oldPC); - regs.gpr[RT(instr)] = value; + u32 paddr; + if (!MapVAddr(regs, LOAD, address, paddr)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); + } else { + u8 value = mem.Read8(regs, paddr); + regs.gpr[RT(instr)] = value; + } } void Interpreter::lhu(Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; - if (check_address_error(address, 0b1)) { + if ((address & 0b1) > 0) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } - - u16 value = mem.Read16(regs, address, regs.oldPC); - regs.gpr[RT(instr)] = value; + u32 paddr; + if (!MapVAddr(regs, LOAD, address, paddr)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); + } else { + u16 value = mem.Read16(regs, paddr); + regs.gpr[RT(instr)] = value; + } } void Interpreter::lwu(Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; - if (check_address_error(address, 0b11)) { + if ((address & 0b11) > 0) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorLoad, 0, true); return; } - u32 value = mem.Read32(regs, address, regs.oldPC); - regs.gpr[RT(instr)] = value; + u32 paddr; + if (!MapVAddr(regs, LOAD, address, paddr)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, true); + } else { + u32 value = mem.Read32(regs, paddr); + regs.gpr[RT(instr)] = value; + } } void Interpreter::sb(Mem& mem, u32 instr) { - u32 address = regs.gpr[RS(instr)] + (s16)instr; - mem.Write8(regs, address, regs.gpr[RT(instr)], regs.oldPC); + u64 address = regs.gpr[RS(instr)] + (s16)instr; + u32 paddr; + if (!MapVAddr(regs, STORE, address, paddr)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); + } else { + mem.Write8(regs, paddr, regs.gpr[RT(instr)]); + } } void Interpreter::sc(Mem& mem, u32 instr) { - s64 address = regs.gpr[RS(instr)] + (s16)instr; - if (check_address_error(address, 0b11)) { - HandleTLBException(regs, address); + u64 address = regs.gpr[RS(instr)] + (s16)instr; + + if ((address & 0b11) > 0) { FireException(regs, ExceptionCode::AddressErrorStore, 0, true); + return; } if(regs.cop0.llbit) { - mem.Write32(regs, address, regs.gpr[RT(instr)], regs.oldPC); + regs.cop0.llbit = false; + u32 paddr = 0; + if(!MapVAddr(regs, STORE, address, paddr)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); + } else { + mem.Write32(regs, paddr, regs.gpr[RT(instr)]); + regs.gpr[RT(instr)] = 1; + } + } else { + regs.gpr[RT(instr)] = 0; } - - regs.gpr[RT(instr)] = (u64)regs.cop0.llbit; - regs.cop0.llbit = false; } void Interpreter::scd(Mem& mem, u32 instr) { + if (!regs.cop0.is_64bit_addressing && !regs.cop0.kernel_mode) { + FireException(regs, ExceptionCode::ReservedInstruction, 0, true); + return; + } + s64 address = regs.gpr[RS(instr)] + (s16)instr; - if (check_address_error(address, 0b111)) { + if ((address & 0b111) > 0) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorStore, 0, true); return; } if(regs.cop0.llbit) { - mem.Write64(regs, address, regs.gpr[RT(instr)], regs.oldPC); + regs.cop0.llbit = false; + u32 paddr = 0; + if(!MapVAddr(regs, STORE, address, paddr)) { + HandleTLBException(regs, address); + FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); + } else { + mem.Write32(regs, paddr, regs.gpr[RT(instr)]); + regs.gpr[RT(instr)] = 1; + } + } else { + regs.gpr[RT(instr)] = 0; } - - regs.gpr[RT(instr)] = (s64)((u64)regs.cop0.llbit); - regs.cop0.llbit = false; } void Interpreter::sh(Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; - if (check_address_error(address, 0b1)) { - HandleTLBException(regs, address); - FireException(regs, ExceptionCode::AddressErrorStore, 0, true); - return; - } u32 physical; if(!MapVAddr(regs, STORE, address, physical)) { HandleTLBException(regs, address); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { - mem.Write16(regs, physical, regs.gpr[RT(instr)], regs.oldPC); + mem.Write16(regs, physical, regs.gpr[RT(instr)]); } } void Interpreter::sw(Mem& mem, u32 instr) { s16 offset = instr; u64 address = regs.gpr[RS(instr)] + offset; - if (check_address_error(address, 0b11)) { + if (check_address_error(0b11, address)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorStore, 0, true); return; @@ -423,13 +492,13 @@ void Interpreter::sw(Mem& mem, u32 instr) { HandleTLBException(regs, address); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { - mem.Write32(regs, physical, regs.gpr[RT(instr)], regs.oldPC); + mem.Write32(regs, physical, regs.gpr[RT(instr)]); } } void Interpreter::sd(Mem& mem, u32 instr) { s64 address = regs.gpr[RS(instr)] + (s16)instr; - if (check_address_error(address, 0b11)) { + if (check_address_error(0b111, address)) { HandleTLBException(regs, address); FireException(regs, ExceptionCode::AddressErrorStore, 0, true); return; @@ -440,9 +509,8 @@ void Interpreter::sd(Mem& mem, u32 instr) { HandleTLBException(regs, address); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, true); } else { - mem.Write64(regs, physical, regs.gpr[RT(instr)], regs.oldPC); + mem.Write64(regs, physical, regs.gpr[RT(instr)]); } - } void Interpreter::sdl(Mem& mem, u32 instr) { @@ -454,9 +522,9 @@ void Interpreter::sdl(Mem& mem, u32 instr) { } else { s32 shift = 8 * ((address ^ 0) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; - u64 data = mem.Read64(regs, paddr & ~7, regs.oldPC); + u64 data = mem.Read64(regs, paddr & ~7); u64 rt = regs.gpr[RT(instr)]; - mem.Write64(regs, paddr & ~7, (data & ~mask) | (rt >> shift), regs.oldPC); + mem.Write64(regs, paddr & ~7, (data & ~mask) | (rt >> shift)); } } @@ -469,9 +537,9 @@ void Interpreter::sdr(Mem& mem, u32 instr) { } else { s32 shift = 8 * ((address ^ 7) & 7); u64 mask = 0xFFFFFFFFFFFFFFFF << shift; - u64 data = mem.Read64(regs, paddr & ~7, regs.oldPC); + u64 data = mem.Read64(regs, paddr & ~7); u64 rt = regs.gpr[RT(instr)]; - mem.Write64(regs, paddr & ~7, (data & ~mask) | (rt << shift), regs.oldPC); + mem.Write64(regs, paddr & ~7, (data & ~mask) | (rt << shift)); } } @@ -484,9 +552,9 @@ void Interpreter::swl(Mem& mem, u32 instr) { } else { u32 shift = 8 * ((address ^ 0) & 3); u32 mask = 0xFFFFFFFF >> shift; - u32 data = mem.Read32(regs, paddr & ~3, regs.oldPC); + u32 data = mem.Read32(regs, paddr & ~3); u32 rt = regs.gpr[RT(instr)]; - mem.Write32(regs, paddr & ~3, (data & ~mask) | (rt >> shift), regs.oldPC); + mem.Write32(regs, paddr & ~3, (data & ~mask) | (rt >> shift)); } } @@ -499,9 +567,9 @@ void Interpreter::swr(Mem& mem, u32 instr) { } else { u32 shift = 8 * ((address ^ 3) & 3); u32 mask = 0xFFFFFFFF << shift; - u32 data = mem.Read32(regs, paddr & ~3, regs.oldPC); + u32 data = mem.Read32(regs, paddr & ~3); u32 rt = regs.gpr[RT(instr)]; - mem.Write32(regs, paddr & ~3, (data & ~mask) | (rt << shift), regs.oldPC); + mem.Write32(regs, paddr & ~3, (data & ~mask) | (rt << shift)); } } @@ -522,10 +590,6 @@ void Interpreter::nor(u32 instr) { void Interpreter::j(u32 instr) { s32 target = (instr & 0x3ffffff) << 2; s64 address = (regs.oldPC & ~0xfffffff) | target; - if (check_address_error(address, 0b11)) { - HandleTLBException(regs, address); - FireException(regs, ExceptionCode::DataBusError, 0, true); - } branch(true, address); } @@ -679,11 +743,6 @@ void Interpreter::dsra32(u32 instr) { void Interpreter::jr(u32 instr) { s64 address = regs.gpr[RS(instr)]; - if (check_address_error(address, 0b11)) { - HandleTLBException(regs, address); - FireException(regs, ExceptionCode::DataBusError, 0, regs.oldPC); - } - branch(true, address); } @@ -692,7 +751,7 @@ void Interpreter::dsub(u32 instr) { s64 rs = regs.gpr[RS(instr)]; s64 result = rs - rt; if(check_signed_underflow(rs, rt, result)) { - FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); + FireException(regs, ExceptionCode::Overflow, 0, true); } else { regs.gpr[RD(instr)] = result; } @@ -710,7 +769,7 @@ void Interpreter::sub(u32 instr) { s32 rs = regs.gpr[RS(instr)]; s32 result = rs - rt; if(check_signed_underflow(rs, rt, result)) { - FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); + FireException(regs, ExceptionCode::Overflow, 0, true); } else { regs.gpr[RD(instr)] = result; } @@ -773,7 +832,7 @@ void Interpreter::mthi(u32 instr) { void Interpreter::trap(bool cond) { if(cond) { - FireException(regs, ExceptionCode::Trap, 0, regs.oldPC); + FireException(regs, ExceptionCode::Trap, 0, true); } } diff --git a/src/backend/core/mmio/PIF.cpp b/src/backend/core/mmio/PIF.cpp index c99e2044..2e4b1819 100644 --- a/src/backend/core/mmio/PIF.cpp +++ b/src/backend/core/mmio/PIF.cpp @@ -73,11 +73,11 @@ void ProcessPIFCommands(u8* pifRam, Controller& controller, Mem& mem) { void DoPIFHLE(Mem& mem, Registers& regs, CartInfo cartInfo) { u32 cicType = cartInfo.cicType; bool pal = cartInfo.isPAL; - mem.Write32(regs, 0x1FC007E4, cicSeeds[cicType], regs.pc); + mem.Write32(regs, 0x1FC007E4, cicSeeds[cicType]); switch(cicType) { case CIC_NUS_6101: - mem.Write32(regs, 0x318, RDRAM_SIZE, regs.pc); + mem.Write32(regs, 0x318, RDRAM_SIZE); regs.gpr[2] = (s64)0xFFFFFFFFDF6445CC; regs.gpr[3] = (s64)0xFFFFFFFFDF6445CC; regs.gpr[4] = 0x45CC; @@ -102,7 +102,7 @@ void DoPIFHLE(Mem& mem, Registers& regs, CartInfo cartInfo) { regs.hi = (s64)0xFFFFFFFF997EC317; break; case CIC_NUS_7102: - mem.Write32(regs, 0x318, RDRAM_SIZE, regs.pc); + mem.Write32(regs, 0x318, RDRAM_SIZE); regs.gpr[1] = 0x0000000000000001; regs.gpr[2] = 0x000000001E324416; regs.gpr[3] = 0x000000001E324416; @@ -127,7 +127,7 @@ void DoPIFHLE(Mem& mem, Registers& regs, CartInfo cartInfo) { regs.hi = 0x0000000010054A98; break; case CIC_NUS_6102_7101: - mem.Write32(regs, 0x318, RDRAM_SIZE, regs.pc); + mem.Write32(regs, 0x318, RDRAM_SIZE); regs.gpr[1] = 0x0000000000000001; regs.gpr[2] = 0x000000000EBDA536; regs.gpr[3] = 0x000000000EBDA536; @@ -157,7 +157,7 @@ void DoPIFHLE(Mem& mem, Registers& regs, CartInfo cartInfo) { } break; case CIC_NUS_6103_7103: - mem.Write32(regs, 0x318, RDRAM_SIZE, regs.pc); + mem.Write32(regs, 0x318, RDRAM_SIZE); regs.gpr[0] = 0x0000000000000000; regs.gpr[1] = 0x0000000000000001; regs.gpr[2] = 0x0000000049A5EE96; @@ -200,7 +200,7 @@ void DoPIFHLE(Mem& mem, Registers& regs, CartInfo cartInfo) { } break; case CIC_NUS_6105_7105: - mem.Write32(regs, 0x3F0, RDRAM_SIZE, regs.pc); + mem.Write32(regs, 0x3F0, RDRAM_SIZE); regs.gpr[2] = (s64)0xFFFFFFFFF58B0FBF; regs.gpr[3] = (s64)0xFFFFFFFFF58B0FBF; regs.gpr[4] = 0x0000000000000FBF; @@ -229,14 +229,14 @@ void DoPIFHLE(Mem& mem, Registers& regs, CartInfo cartInfo) { regs.gpr[31] = (s64)0xFFFFFFFFA4001554; } - mem.Write32(regs, 0x04001000, 0x3C0DBFC0, regs.pc); - mem.Write32(regs, 0x04001004, 0x8DA807FC, regs.pc); - mem.Write32(regs, 0x04001008, 0x25AD07C0, regs.pc); - mem.Write32(regs, 0x0400100C, 0x31080080, regs.pc); - mem.Write32(regs, 0x04001000, 0x5500FFFC, regs.pc); - mem.Write32(regs, 0x04001004, 0x3C0DBFC0, regs.pc); - mem.Write32(regs, 0x04001008, 0x8DA80024, regs.pc); - mem.Write32(regs, 0x0400100C, 0x3C0BB000, regs.pc); + mem.Write32(regs, 0x04001000, 0x3C0DBFC0); + mem.Write32(regs, 0x04001004, 0x8DA807FC); + mem.Write32(regs, 0x04001008, 0x25AD07C0); + mem.Write32(regs, 0x0400100C, 0x31080080); + mem.Write32(regs, 0x04001000, 0x5500FFFC); + mem.Write32(regs, 0x04001004, 0x3C0DBFC0); + mem.Write32(regs, 0x04001008, 0x8DA80024); + mem.Write32(regs, 0x0400100C, 0x3C0BB000); break; case CIC_NUS_6106_7106: regs.gpr[2] = (s64)0xFFFFFFFFA95930A4; diff --git a/src/backend/core/registers/Cop0.cpp b/src/backend/core/registers/Cop0.cpp index 71e174e5..737a9158 100644 --- a/src/backend/core/registers/Cop0.cpp +++ b/src/backend/core/registers/Cop0.cpp @@ -327,9 +327,9 @@ void Cop0::decode(Registers& regs, Mem& mem, u32 instr) { case 0x05: dmtc0(regs, instr); break; case 0x10 ... 0x1F: switch(mask_cop2) { - case 0x01: tlbr(regs); break; - case 0x02: tlbw(index & 0x3F, regs); break; - case 0x06: tlbw(GetRandom(), regs); break; + case 0x01: tlbr(); break; + case 0x02: tlbw(index & 0x3F); break; + case 0x06: tlbw(GetRandom()); break; case 0x08: tlbp(regs); break; case 0x18: eret(regs); break; default: Util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, regs.oldPC); diff --git a/src/backend/core/registers/Cop0.hpp b/src/backend/core/registers/Cop0.hpp index 5f737ca4..a86e463e 100644 --- a/src/backend/core/registers/Cop0.hpp +++ b/src/backend/core/registers/Cop0.hpp @@ -260,8 +260,8 @@ private: void dmfc0(n64::Registers&, u32); void eret(n64::Registers&); - void tlbr(n64::Registers&); - void tlbw(int, n64::Registers&); + void tlbr(); + void tlbw(int); void tlbp(n64::Registers&); };