fix buncha things, can't be assed to list

This commit is contained in:
CocoSimone
2023-02-10 16:16:16 +01:00
parent 5d35fb229f
commit 30c6931f09
12 changed files with 332 additions and 374 deletions

View File

@@ -63,7 +63,7 @@ void Dynarec::Recompile(Mem& mem, u32 pc) {
while(!prevBranch) {
instrInBlock++;
prevBranch = branch;
u32 instr = mem.Read32<false>(regs, loopPC, loopPC);
u32 instr = mem.Read32(regs, loopPC);
emitBreakpoint();
code.mov(rdi, (uintptr_t)&regs);
@@ -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]) {

View File

@@ -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;

View File

@@ -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<true>(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr);
template bool MapVAddr<false>(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr);
template <bool tlb>
u8 Mem::Read8(n64::Registers &regs, u64 vaddr, s64 pc) {
u32 paddr = vaddr;
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false);
}
u8 Mem::Read8(n64::Registers &regs, 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 &regs, 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 &regs, u64 vaddr, s64 pc) {
}
}
template <bool tlb>
u16 Mem::Read16(n64::Registers &regs, u64 vaddr, s64 pc) {
u32 paddr = vaddr;
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false);
}
u16 Mem::Read16(n64::Registers &regs, 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 &regs, u64 vaddr, s64 pc) {
case 0x04500000 ... 0x048FFFFF:
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF:
paddr = (paddr + 2) & ~3;
return Util::ReadAccess<u16>(cart.data(), HALF_ADDRESS(paddr) & romMask);
case 0x1FC00000 ... 0x1FC007BF:
return Util::ReadAccess<u16>(pifBootrom, HALF_ADDRESS(paddr) - 0x1FC00000);
@@ -186,14 +183,7 @@ u16 Mem::Read16(n64::Registers &regs, u64 vaddr, s64 pc) {
}
}
template <bool tlb>
u32 Mem::Read32(n64::Registers &regs, u64 vaddr, s64 pc) {
u32 paddr = vaddr;
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false);
}
u32 Mem::Read32(n64::Registers &regs, 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 &regs, u64 vaddr, s64 pc) {
}
}
template <bool tlb>
u64 Mem::Read64(n64::Registers &regs, u64 vaddr, s64 pc) {
u32 paddr = vaddr;
if (!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, false);
}
u64 Mem::Read64(n64::Registers &regs, 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 &regs, u64 vaddr, s64 pc) {
}
}
template u8 Mem::Read8<false>(n64::Registers &regs, u64 vaddr, s64 pc);
template u8 Mem::Read8<true>(n64::Registers &regs, u64 vaddr, s64 pc);
template u16 Mem::Read16<false>(n64::Registers &regs, u64 vaddr, s64 pc);
template u16 Mem::Read16<true>(n64::Registers &regs, u64 vaddr, s64 pc);
template u32 Mem::Read32<false>(n64::Registers &regs, u64 vaddr, s64 pc);
template u32 Mem::Read32<true>(n64::Registers &regs, u64 vaddr, s64 pc);
template u64 Mem::Read64<false>(n64::Registers &regs, u64 vaddr, s64 pc);
template u64 Mem::Read64<true>(n64::Registers &regs, u64 vaddr, s64 pc);
template <bool tlb>
void Mem::Write8(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s64 pc) {
u32 paddr = vaddr;
if (!MapVAddr<tlb>(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<u32>(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 <bool tlb>
void Mem::Write16(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s64 pc) {
u32 paddr = vaddr;
if (!MapVAddr<tlb>(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<u16>((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<u16>(mmio.rdp.rdram.data(), HALF_ADDRESS(paddr), val);
break;
case 0x04000000 ... 0x0403FFFF:
val = val << (16 * !(paddr & 2));
paddr &= ~3;
if (paddr & 0x1000)
Util::WriteAccess<u32>(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 <bool tlb>
void Mem::Write32(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u32 val, s64 pc) {
u32 paddr = vaddr;
if(!MapVAddr<tlb>(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 <bool tlb>
void Mem::Write64(Registers& regs, n64::JIT::Dynarec& dyn, u64 vaddr, u64 val, s64 pc) {
u32 paddr = vaddr;
if(!MapVAddr<tlb>(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<u64>((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<u64>(mmio.rdp.rdram.data(), paddr, val);
break;
case 0x04000000 ... 0x0403FFFF:
val >>= 32;
if (paddr & 0x1000)
Util::WriteAccess<u32>(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<false>(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc);
template void Mem::Write8<true>(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc);
template void Mem::Write16<false>(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc);
template void Mem::Write16<true>(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc);
template void Mem::Write32<false>(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc);
template void Mem::Write32<true>(Registers& regs, JIT::Dynarec&, u64 vaddr, u32 val, s64 pc);
template void Mem::Write64<false>(Registers& regs, JIT::Dynarec&, u64 vaddr, u64 val, s64 pc);
template void Mem::Write64<true>(Registers& regs, JIT::Dynarec&, u64 vaddr, u64 val, s64 pc);
template <bool tlb>
void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) {
u32 paddr = vaddr;
if (!MapVAddr<tlb>(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<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else
@@ -579,12 +503,10 @@ void Mem::Write8(Registers& regs, u64 vaddr, u32 val, s64 pc) {
}
}
template <bool tlb>
void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc) {
u32 paddr = vaddr;
if (!MapVAddr<tlb>(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<u16>((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<u16>(mmio.rdp.rdram.data(), HALF_ADDRESS(paddr), val);
break;
case 0x04000000 ... 0x0403FFFF:
val = val << (16 * !(paddr & 2));
paddr &= ~3;
if (paddr & 0x1000)
Util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else
@@ -638,14 +553,7 @@ void Mem::Write16(Registers& regs, u64 vaddr, u32 val, s64 pc) {
}
}
template <bool tlb>
void Mem::Write32(Registers& regs, u64 vaddr, u32 val, s64 pc) {
u32 paddr = vaddr;
if(!MapVAddr<tlb>(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 <bool tlb>
void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc) {
u32 paddr = vaddr;
if(!MapVAddr<tlb>(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<u64>((u8*)pointer, offset, val);
} else {
switch (paddr) {
@@ -712,7 +614,6 @@ void Mem::Write64(Registers& regs, u64 vaddr, u64 val, s64 pc) {
Util::WriteAccess<u64>(mmio.rdp.rdram.data(), paddr, val);
break;
case 0x04000000 ... 0x0403FFFF:
val >>= 32;
if (paddr & 0x1000)
Util::WriteAccess<u32>(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<false>(Registers& regs, u64 vaddr, u32 val, s64 pc);
template void Mem::Write8<true>(Registers& regs, u64 vaddr, u32 val, s64 pc);
template void Mem::Write16<false>(Registers& regs, u64 vaddr, u32 val, s64 pc);
template void Mem::Write16<true>(Registers& regs, u64 vaddr, u32 val, s64 pc);
template void Mem::Write32<false>(Registers& regs, u64 vaddr, u32 val, s64 pc);
template void Mem::Write32<true>(Registers& regs, u64 vaddr, u32 val, s64 pc);
template void Mem::Write64<false>(Registers& regs, u64 vaddr, u64 val, s64 pc);
template void Mem::Write64<true>(Registers& regs, u64 vaddr, u64 val, s64 pc);
}

View File

@@ -28,30 +28,18 @@ struct Mem {
return mmio.rdp.rdram.data();
}
template <bool tlb = true>
u8 Read8(Registers&, u64, s64);
template <bool tlb = true>
u16 Read16(Registers&, u64, s64);
template <bool tlb = true>
u32 Read32(Registers&, u64, s64);
template <bool tlb = true>
u64 Read64(Registers&, u64, s64);
template <bool tlb = true>
void Write8(Registers&, JIT::Dynarec&, u64, u32, s64);
template <bool tlb = true>
void Write16(Registers&, JIT::Dynarec&, u64, u32, s64);
template <bool tlb = true>
void Write32(Registers&, JIT::Dynarec&, u64, u32, s64);
template <bool tlb = true>
void Write64(Registers&, JIT::Dynarec&, u64, u64, s64);
template <bool tlb = true>
void Write8(Registers&, u64, u32, s64);
template <bool tlb = true>
void Write16(Registers&, u64, u32, s64);
template <bool tlb = true>
void Write32(Registers&, u64, u32, s64);
template <bool tlb = true>
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]{};

View File

@@ -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<false>(regs, physical, regs.oldPC);
u32 data = mem.Read32(regs, physical);
regs.cop1.SetReg<u32>(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<false>(regs, physical, regs.cop1.GetReg<u32>(regs.cop0, FT(instr)), regs.oldPC);
mem.Write32(regs, physical, regs.cop1.GetReg<u32>(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<false>(regs, physical, regs.oldPC);
u64 data = mem.Read64(regs, physical);
regs.cop1.SetReg<u64>(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<false>(regs, physical, regs.cop1.GetReg<u64>(regs.cop0, FT(instr)), regs.oldPC);
mem.Write64(regs, physical, regs.cop1.GetReg<u64>(regs.cop0, FT(instr)));
}
}

View File

@@ -1,5 +1,4 @@
#include <dynarec/instructions.hpp>
#include <Registers.hpp>
#include <core/Dynarec.hpp>
#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<false>(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<false>(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<false>(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<false>(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<false>(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;
}
}
}
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<false>(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<false>(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.gpr[RT(instr)] = (u64)regs.cop0.llbit;
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;
}
}
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<false>(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<false>(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<false>(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<false>(regs, paddr & ~7, regs.oldPC);
u64 data = mem.Read64(regs, paddr & ~7);
u64 rt = regs.gpr[RT(instr)];
mem.Write64<false>(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<false>(regs, paddr & ~7, regs.oldPC);
u64 data = mem.Read64(regs, paddr & ~7);
u64 rt = regs.gpr[RT(instr)];
mem.Write64<false>(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<false>(regs, paddr & ~3, regs.oldPC);
u32 data = mem.Read32(regs, paddr & ~3);
u32 rt = regs.gpr[RT(instr)];
mem.Write32<false>(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<false>(regs, paddr & ~3, regs.oldPC);
u32 data = mem.Read32(regs, paddr & ~3);
u32 rt = regs.gpr[RT(instr)];
mem.Write32<false>(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) {
}
}

View File

@@ -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;

View File

@@ -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<false>(regs, physical, regs.oldPC);
u32 data = mem.Read32(regs, physical);
SetReg<u32>(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<false>(regs, physical, GetReg<u32>(regs.cop0, FT(instr)), regs.oldPC);
mem.Write32(regs, physical, GetReg<u32>(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<false>(regs, physical, regs.oldPC);
u64 data = mem.Read64(regs, physical);
SetReg<u64>(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<false>(regs, physical, GetReg<u64>(regs.cop0, FT(instr)), regs.oldPC);
mem.Write64(regs, physical, GetReg<u64>(regs.cop0, FT(instr)));
}
}

View File

@@ -1,7 +1,7 @@
#include <core/Interpreter.hpp>
#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<false>(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<false>(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<false>(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<false>(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);
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<false>(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;
}
}
}
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<false>(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<false>(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);
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);
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);
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.gpr[RT(instr)] = (u64)regs.cop0.llbit;
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;
}
}
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.gpr[RT(instr)] = (s64)((u64)regs.cop0.llbit);
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;
}
}
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<false>(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<false>(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<false>(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<false>(regs, paddr & ~7, regs.oldPC);
u64 data = mem.Read64(regs, paddr & ~7);
u64 rt = regs.gpr[RT(instr)];
mem.Write64<false>(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<false>(regs, paddr & ~7, regs.oldPC);
u64 data = mem.Read64(regs, paddr & ~7);
u64 rt = regs.gpr[RT(instr)];
mem.Write64<false>(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<false>(regs, paddr & ~3, regs.oldPC);
u32 data = mem.Read32(regs, paddr & ~3);
u32 rt = regs.gpr[RT(instr)];
mem.Write32<false>(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<false>(regs, paddr & ~3, regs.oldPC);
u32 data = mem.Read32(regs, paddr & ~3);
u32 rt = regs.gpr[RT(instr)];
mem.Write32<false>(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);
}
}

View File

@@ -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<false>(regs, 0x1FC007E4, cicSeeds[cicType], regs.pc);
mem.Write32(regs, 0x1FC007E4, cicSeeds[cicType]);
switch(cicType) {
case CIC_NUS_6101:
mem.Write32<false>(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<false>(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<false>(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<false>(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<false>(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<false>(regs, 0x04001000, 0x3C0DBFC0, regs.pc);
mem.Write32<false>(regs, 0x04001004, 0x8DA807FC, regs.pc);
mem.Write32<false>(regs, 0x04001008, 0x25AD07C0, regs.pc);
mem.Write32<false>(regs, 0x0400100C, 0x31080080, regs.pc);
mem.Write32<false>(regs, 0x04001000, 0x5500FFFC, regs.pc);
mem.Write32<false>(regs, 0x04001004, 0x3C0DBFC0, regs.pc);
mem.Write32<false>(regs, 0x04001008, 0x8DA80024, regs.pc);
mem.Write32<false>(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;

View File

@@ -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);

View File

@@ -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&);
};