Fix various memory things

This commit is contained in:
CocoSimone
2022-09-20 23:01:18 +02:00
parent f88fcf657e
commit 82578cd914
6 changed files with 291 additions and 138 deletions

View File

@@ -94,7 +94,7 @@ void Cpu::Step(Mem& mem) {
CheckCompareInterrupt(mem.mmio.mi, regs); CheckCompareInterrupt(mem.mmio.mi, regs);
HandleInterrupt(regs); HandleInterrupt(regs);
u32 instruction = mem.Read<u32>(regs, regs.pc, regs.pc); u32 instruction = mem.Read32(regs, regs.pc, regs.pc);
regs.oldPC = regs.pc; regs.oldPC = regs.pc;
regs.pc = regs.nextPC; regs.pc = regs.nextPC;

View File

@@ -63,8 +63,8 @@ bool MapVAddr(Registers& regs, TLBAccessType accessType, u32 vaddr, u32& paddr)
template bool MapVAddr<true>(Registers& regs, TLBAccessType accessType, u32 vaddr, u32& paddr); template bool MapVAddr<true>(Registers& regs, TLBAccessType accessType, u32 vaddr, u32& paddr);
template bool MapVAddr<false>(Registers& regs, TLBAccessType accessType, u32 vaddr, u32& paddr); template bool MapVAddr<false>(Registers& regs, TLBAccessType accessType, u32 vaddr, u32& paddr);
template <class T, bool tlb> template <bool tlb>
T Mem::Read(Registers& regs, u32 vaddr, s64 pc) { u8 Mem::Read8(n64::Registers &regs, u32 vaddr, s64 pc) {
u32 paddr = vaddr; u32 paddr = vaddr;
if(!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) { if(!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr); HandleTLBException(regs, vaddr);
@@ -73,76 +73,135 @@ T Mem::Read(Registers& regs, u32 vaddr, s64 pc) {
switch(paddr) { switch(paddr) {
case 0x00000000 ... 0x007FFFFF: case 0x00000000 ... 0x007FFFFF:
if constexpr (sizeof(T) == 1) { return mmio.rdp.dram[BYTE_ADDRESS(paddr) & RDRAM_DSIZE];
return util::ReadAccess<T>(mmio.rdp.dram.data(), BYTE_ADDRESS(paddr) & RDRAM_DSIZE);
} else if constexpr (sizeof(T) == 2) {
return util::ReadAccess<T>(mmio.rdp.dram.data(), HALF_ADDRESS(paddr) & RDRAM_DSIZE);
} else {
return util::ReadAccess<T>(mmio.rdp.dram.data(), paddr & RDRAM_DSIZE);
}
case 0x04000000 ... 0x0403FFFF: case 0x04000000 ... 0x0403FFFF:
if constexpr (sizeof(T) == 1) { if(paddr & 0x1000)
return mmio.rsp.ReadByte(paddr, paddr & 0x1000); return mmio.rsp.imem[BYTE_ADDRESS(paddr) & IMEM_DSIZE];
} else if constexpr (sizeof(T) == 2) { else
return mmio.rsp.ReadHalf(paddr, paddr & 0x1000); return mmio.rsp.dmem[BYTE_ADDRESS(paddr) & DMEM_DSIZE];
} else if constexpr (sizeof(T) == 4) {
return mmio.rsp.ReadWord(paddr, paddr & 0x1000);
} else {
return mmio.rsp.ReadDword(paddr, paddr & 0x1000);
}
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF: case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: return mmio.Read(paddr); case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF:
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF: case 0x10000000 ... 0x1FBFFFFF:
if constexpr (sizeof(T) == 1) { return cart[BYTE_ADDRESS(paddr) & romMask];
return util::ReadAccess<T>(cart.data(), BYTE_ADDRESS(paddr) & romMask);
} else if constexpr (sizeof(T) == 2) {
return util::ReadAccess<T>(cart.data(), HALF_ADDRESS(paddr) & romMask);
} else {
return util::ReadAccess<T>(cart.data(), paddr & romMask);
}
case 0x1FC00000 ... 0x1FC007BF: case 0x1FC00000 ... 0x1FC007BF:
if constexpr (sizeof(T) == 1) { return pifBootrom[BYTE_ADDRESS(paddr) & PIF_BOOTROM_DSIZE];
return util::ReadAccess<T>(pifBootrom, BYTE_ADDRESS(paddr) & PIF_BOOTROM_DSIZE);
} else if constexpr (sizeof(T) == 2) {
return util::ReadAccess<T>(pifBootrom, HALF_ADDRESS(paddr) & PIF_BOOTROM_DSIZE);
} else {
return util::ReadAccess<T>(pifBootrom, paddr & PIF_BOOTROM_DSIZE);
}
case 0x1FC007C0 ... 0x1FC007FF: case 0x1FC007C0 ... 0x1FC007FF:
if constexpr (sizeof(T) == 1) { return pifRam[paddr & PIF_RAM_DSIZE];
return util::ReadAccess<T>(pifRam, BYTE_ADDRESS(paddr) & PIF_RAM_DSIZE);
} else if constexpr (sizeof(T) == 2) {
return util::ReadAccess<T>(pifRam, HALF_ADDRESS(paddr) & PIF_RAM_DSIZE);
} else {
return util::ReadAccess<T>(pifRam, paddr & PIF_RAM_DSIZE);
}
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x07FFFFFF: case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF: case 0x08000000 ... 0x0FFFFFFF:
case 0x80000000 ... 0xFFFFFFFF: case 0x1FC00800 ... 0x7FFFFFFF: return 0; case 0x80000000 ... 0xFFFFFFFF: case 0x1FC00800 ... 0x7FFFFFFF: return 0;
default: util::panic("Unimplemented {}-bit read at address {:08X} (PC = {:016X})\n", sizeof(T) * 8, paddr, (u64)regs.pc); default: util::panic("Unimplemented 8-bit read at address {:08X} (PC = {:016X})\n", paddr, (u64)regs.pc);
} }
return 0;
} }
template u8 Mem::Read<u8>(Registers& regs, u32 vaddr, s64 pc); template <bool tlb>
template u16 Mem::Read<u16>(Registers& regs, u32 vaddr, s64 pc); u16 Mem::Read16(n64::Registers &regs, u32 vaddr, s64 pc) {
template u32 Mem::Read<u32>(Registers& regs, u32 vaddr, s64 pc); u32 paddr = vaddr;
template u64 Mem::Read<u64>(Registers& regs, u32 vaddr, s64 pc); if(!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
template u8 Mem::Read<u8, false>(Registers& regs, u32 vaddr, s64 pc); HandleTLBException(regs, vaddr);
template u16 Mem::Read<u16, false>(Registers& regs, u32 vaddr, s64 pc); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc);
template u32 Mem::Read<u32, false>(Registers& regs, u32 vaddr, s64 pc); }
template u64 Mem::Read<u64, false>(Registers& regs, u32 vaddr, s64 pc);
template s8 Mem::Read<s8>(Registers& regs, u32 vaddr, s64 pc);
template s16 Mem::Read<s16>(Registers& regs, u32 vaddr, s64 pc);
template s32 Mem::Read<s32>(Registers& regs, u32 vaddr, s64 pc);
template s64 Mem::Read<s64>(Registers& regs, u32 vaddr, s64 pc);
template s8 Mem::Read<s8, false>(Registers& regs, u32 vaddr, s64 pc);
template s16 Mem::Read<s16, false>(Registers& regs, u32 vaddr, s64 pc);
template s32 Mem::Read<s32, false>(Registers& regs, u32 vaddr, s64 pc);
template s64 Mem::Read<s64, false>(Registers& regs, u32 vaddr, s64 pc);
template <class T, bool tlb> switch(paddr) {
void Mem::Write(Registers& regs, u32 vaddr, T val, s64 pc) { case 0x00000000 ... 0x007FFFFF:
return util::ReadAccess<u16>(mmio.rdp.dram.data(), HALF_ADDRESS(paddr) & RDRAM_DSIZE);
case 0x04000000 ... 0x0403FFFF:
if(paddr & 0x1000)
return util::ReadAccess<u16>(mmio.rsp.imem, HALF_ADDRESS(paddr) & IMEM_DSIZE);
else
return util::ReadAccess<u16>(mmio.rsp.dmem, HALF_ADDRESS(paddr) & DMEM_DSIZE);
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF:
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF:
return util::ReadAccess<u16>(cart.data(), HALF_ADDRESS(paddr) & romMask);
case 0x1FC00000 ... 0x1FC007BF:
return util::ReadAccess<u16>(pifBootrom, HALF_ADDRESS(paddr) & PIF_BOOTROM_DSIZE);
case 0x1FC007C0 ... 0x1FC007FF:
return be16toh(util::ReadAccess<u16>(pifRam, paddr & PIF_RAM_DSIZE));
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x07FFFFFF: case 0x08000000 ... 0x0FFFFFFF:
case 0x80000000 ... 0xFFFFFFFF: case 0x1FC00800 ... 0x7FFFFFFF: return 0;
default: util::panic("Unimplemented 16-bit read at address {:08X} (PC = {:016X})\n", paddr, (u64)regs.pc);
}
}
template <bool tlb>
u32 Mem::Read32(n64::Registers &regs, u32 vaddr, s64 pc) {
u32 paddr = vaddr;
if(!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc);
}
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
return util::ReadAccess<u32>(mmio.rdp.dram.data(), paddr & RDRAM_DSIZE);
case 0x04000000 ... 0x0403FFFF:
if(paddr & 0x1000)
return util::ReadAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE);
else
return util::ReadAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE);
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF:
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF:
return util::ReadAccess<u32>(cart.data(), paddr & romMask);
case 0x1FC00000 ... 0x1FC007BF:
return util::ReadAccess<u32>(pifBootrom, paddr & PIF_BOOTROM_DSIZE);
case 0x1FC007C0 ... 0x1FC007FF:
return be32toh(util::ReadAccess<u32>(pifRam, paddr & PIF_RAM_DSIZE));
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x07FFFFFF: case 0x08000000 ... 0x0FFFFFFF:
case 0x80000000 ... 0xFFFFFFFF: case 0x1FC00800 ... 0x7FFFFFFF: return 0;
default: util::panic("Unimplemented 32-bit read at address {:08X} (PC = {:016X})\n", paddr, (u64)regs.pc);
}
}
template <bool tlb>
u64 Mem::Read64(n64::Registers &regs, u32 vaddr, s64 pc) {
u32 paddr = vaddr;
if(!MapVAddr<tlb>(regs, LOAD, vaddr, paddr)) {
HandleTLBException(regs, vaddr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, pc);
}
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
return util::ReadAccess<u64>(mmio.rdp.dram.data(), paddr & RDRAM_DSIZE);
case 0x04000000 ... 0x0403FFFF:
if(paddr & 0x1000)
return util::ReadAccess<u64>(mmio.rsp.imem, paddr & IMEM_DSIZE);
else
return util::ReadAccess<u64>(mmio.rsp.dmem, paddr & DMEM_DSIZE);
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF:
return mmio.Read(paddr);
case 0x10000000 ... 0x1FBFFFFF:
return util::ReadAccess<u64>(cart.data(), paddr & romMask);
case 0x1FC00000 ... 0x1FC007BF:
return util::ReadAccess<u64>(pifBootrom, paddr & PIF_BOOTROM_DSIZE);
case 0x1FC007C0 ... 0x1FC007FF:
return be64toh(util::ReadAccess<u64>(pifRam, paddr & PIF_RAM_DSIZE));
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x04900000 ... 0x07FFFFFF: case 0x08000000 ... 0x0FFFFFFF:
case 0x80000000 ... 0xFFFFFFFF: case 0x1FC00800 ... 0x7FFFFFFF: return 0;
default: util::panic("Unimplemented 32-bit read at address {:08X} (PC = {:016X})\n", paddr, (u64)regs.pc);
}
}
template u8 Mem::Read8<false>(n64::Registers &regs, u32 vaddr, s64 pc);
template u8 Mem::Read8<true>(n64::Registers &regs, u32 vaddr, s64 pc);
template u16 Mem::Read16<false>(n64::Registers &regs, u32 vaddr, s64 pc);
template u16 Mem::Read16<true>(n64::Registers &regs, u32 vaddr, s64 pc);
template u32 Mem::Read32<false>(n64::Registers &regs, u32 vaddr, s64 pc);
template u32 Mem::Read32<true>(n64::Registers &regs, u32 vaddr, s64 pc);
template u64 Mem::Read64<false>(n64::Registers &regs, u32 vaddr, s64 pc);
template u64 Mem::Read64<true>(n64::Registers &regs, u32 vaddr, s64 pc);
template <bool tlb>
void Mem::Write8(Registers& regs, u32 vaddr, u32 val, s64 pc) {
u32 paddr = vaddr; u32 paddr = vaddr;
if(!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) { if(!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
HandleTLBException(regs, vaddr); HandleTLBException(regs, vaddr);
@@ -151,24 +210,85 @@ void Mem::Write(Registers& regs, u32 vaddr, T val, s64 pc) {
switch(paddr) { switch(paddr) {
case 0x00000000 ... 0x007FFFFF: case 0x00000000 ... 0x007FFFFF:
if constexpr (sizeof(T) == 1) { mmio.rdp.dram[BYTE_ADDRESS(paddr) & RDRAM_DSIZE] = val;
util::WriteAccess<T>(mmio.rdp.dram.data(), BYTE_ADDRESS(paddr) & RDRAM_DSIZE, val);
} else if constexpr (sizeof(T) == 2) {
util::WriteAccess<T>(mmio.rdp.dram.data(), HALF_ADDRESS(paddr) & RDRAM_DSIZE, val);
} else {
util::WriteAccess<T>(mmio.rdp.dram.data(), paddr & RDRAM_DSIZE, val);
}
break; break;
case 0x04000000 ... 0x0403FFFF: case 0x04000000 ... 0x0403FFFF:
if constexpr (sizeof(T) == 1) { val = val << (8 * (3 - (paddr & 3)));
mmio.rsp.WriteByte(paddr, val, paddr & 0x1000); paddr = (paddr & DMEM_DSIZE) & ~3;
} else if constexpr (sizeof(T) == 2) { if(paddr & 0x1000)
mmio.rsp.WriteHalf(paddr, val, paddr & 0x1000); util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
} else if constexpr (sizeof(T) == 4) { else
mmio.rsp.WriteWord(paddr, val, paddr & 0x1000); util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
} else { break;
mmio.rsp.WriteDword(paddr, val, paddr & 0x1000); case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(*this, regs, paddr, val); break;
case 0x10000000 ... 0x13FFFFFF: break;
case 0x1FC007C0 ... 0x1FC007FF:
val = val << (8 * (3 - (paddr & 3)));
paddr = (paddr & PIF_RAM_DSIZE) & ~3;
util::WriteAccess<u32>(pifRam, paddr & PIF_RAM_DSIZE, htobe32(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00800 ... 0x7FFFFFFF: case 0x80000000 ... 0xFFFFFFFF: break;
default: util::panic("Unimplemented 8-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val, (u64)regs.pc);
} }
}
template <bool tlb>
void Mem::Write16(Registers& regs, u32 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, pc);
}
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
util::WriteAccess<u16>(mmio.rdp.dram.data(), HALF_ADDRESS(paddr) & RDRAM_DSIZE, 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
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(*this, regs, paddr, val); break;
case 0x10000000 ... 0x13FFFFFF: break;
case 0x1FC007C0 ... 0x1FC007FF:
val = val << (16 * !(paddr & 2));
paddr &= ~3;
util::WriteAccess<u32>(pifRam, paddr & PIF_RAM_DSIZE, htobe32(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00800 ... 0x7FFFFFFF: case 0x80000000 ... 0xFFFFFFFF: break;
default: util::panic("Unimplemented 16-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val, (u64)regs.pc);
}
}
template <bool tlb>
void Mem::Write32(Registers& regs, u32 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, pc);
}
switch(paddr) {
case 0x00000000 ... 0x007FFFFF:
util::WriteAccess<u32>(mmio.rdp.dram.data(), paddr & RDRAM_DSIZE, val);
break;
case 0x04000000 ... 0x0403FFFF:
if(paddr & 0x1000)
util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break; break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF: case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(*this, regs, paddr, val); break; case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(*this, regs, paddr, val); break;
@@ -182,39 +302,58 @@ void Mem::Write(Registers& regs, u32 vaddr, T val, s64 pc) {
} }
} break; } break;
case 0x13FF0020 ... 0x13FFFFFF: case 0x13FF0020 ... 0x13FFFFFF:
util::WriteAccess<T>(isviewer, paddr & ISVIEWER_DSIZE, be32toh(val)); util::WriteAccess<u32>(isviewer, paddr & ISVIEWER_DSIZE, htobe32(val));
break; break;
case 0x1FC007C0 ... 0x1FC007FF: case 0x1FC007C0 ... 0x1FC007FF:
if constexpr (sizeof(T) == 1) { util::WriteAccess<u32>(pifRam, paddr & PIF_RAM_DSIZE, htobe32(val));
util::WriteAccess<T>(pifRam, BYTE_ADDRESS(paddr) & PIF_RAM_DSIZE, val);
} else if constexpr (sizeof(T) == 2) {
util::WriteAccess<T>(pifRam, HALF_ADDRESS(paddr) & PIF_RAM_DSIZE, val);
} else {
util::WriteAccess<T>(pifRam, paddr & PIF_RAM_DSIZE, val);
}
ProcessPIFCommands(pifRam, mmio.si.controller, *this); ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break; break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF: case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF: case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00800 ... 0x7FFFFFFF: case 0x80000000 ... 0xFFFFFFFF: break; case 0x1FC00800 ... 0x7FFFFFFF: case 0x80000000 ... 0xFFFFFFFF: break;
default: util::panic("Unimplemented {}-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", sizeof(T) * 8, paddr, val, (u64)regs.pc); default: util::panic("Unimplemented 32-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val, (u64)regs.pc);
} }
} }
template void Mem::Write<u8>(Registers& regs, u32 vaddr, u8 val, s64 pc); template <bool tlb>
template void Mem::Write<u16>(Registers& regs, u32 vaddr, u16 val, s64 pc); void Mem::Write64(Registers& regs, u32 vaddr, u64 val, s64 pc) {
template void Mem::Write<u32>(Registers& regs, u32 vaddr, u32 val, s64 pc); u32 paddr = vaddr;
template void Mem::Write<u64>(Registers& regs, u32 vaddr, u64 val, s64 pc); if(!MapVAddr<tlb>(regs, STORE, vaddr, paddr)) {
template void Mem::Write<u8, false>(Registers& regs, u32 vaddr, u8 val, s64 pc); HandleTLBException(regs, vaddr);
template void Mem::Write<u16, false>(Registers& regs, u32 vaddr, u16 val, s64 pc); FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, pc);
template void Mem::Write<u32, false>(Registers& regs, u32 vaddr, u32 val, s64 pc); }
template void Mem::Write<u64, false>(Registers& regs, u32 vaddr, u64 val, s64 pc);
template void Mem::Write<s8>(Registers& regs, u32 vaddr, s8 val, s64 pc); switch(paddr) {
template void Mem::Write<s16>(Registers& regs, u32 vaddr, s16 val, s64 pc); case 0x00000000 ... 0x007FFFFF:
template void Mem::Write<s32>(Registers& regs, u32 vaddr, s32 val, s64 pc); util::WriteAccess<u64>(mmio.rdp.dram.data(), paddr & RDRAM_DSIZE, val);
template void Mem::Write<s64>(Registers& regs, u32 vaddr, s64 val, s64 pc); break;
template void Mem::Write<s8, false>(Registers& regs, u32 vaddr, s8 val, s64 pc); case 0x04000000 ... 0x0403FFFF:
template void Mem::Write<s16, false>(Registers& regs, u32 vaddr, s16 val, s64 pc); val >>= 32;
template void Mem::Write<s32, false>(Registers& regs, u32 vaddr, s32 val, s64 pc); if(paddr & 0x1000)
template void Mem::Write<s64, false>(Registers& regs, u32 vaddr, s64 val, s64 pc); util::WriteAccess<u32>(mmio.rsp.imem, paddr & IMEM_DSIZE, val);
else
util::WriteAccess<u32>(mmio.rsp.dmem, paddr & DMEM_DSIZE, val);
break;
case 0x04040000 ... 0x040FFFFF: case 0x04100000 ... 0x041FFFFF:
case 0x04300000 ... 0x044FFFFF: case 0x04500000 ... 0x048FFFFF: mmio.Write(*this, regs, paddr, val); break;
case 0x10000000 ... 0x13FFFFFF: break;
case 0x1FC007C0 ... 0x1FC007FF:
util::WriteAccess<u64>(pifRam, paddr & PIF_RAM_DSIZE, htobe64(val));
ProcessPIFCommands(pifRam, mmio.si.controller, *this);
break;
case 0x00800000 ... 0x03FFFFFF: case 0x04200000 ... 0x042FFFFF:
case 0x08000000 ... 0x0FFFFFFF: case 0x04900000 ... 0x07FFFFFF:
case 0x1FC00800 ... 0x7FFFFFFF: case 0x80000000 ... 0xFFFFFFFF: break;
default: util::panic("Unimplemented 64-bit write at address {:08X} with value {:0X} (PC = {:016X})\n", paddr, val, (u64)regs.pc);
}
}
template void Mem::Write8<false>(Registers& regs, u32 vaddr, u32 val, s64 pc);
template void Mem::Write8<true>(Registers& regs, u32 vaddr, u32 val, s64 pc);
template void Mem::Write16<false>(Registers& regs, u32 vaddr, u32 val, s64 pc);
template void Mem::Write16<true>(Registers& regs, u32 vaddr, u32 val, s64 pc);
template void Mem::Write32<false>(Registers& regs, u32 vaddr, u32 val, s64 pc);
template void Mem::Write32<true>(Registers& regs, u32 vaddr, u32 val, s64 pc);
template void Mem::Write64<false>(Registers& regs, u32 vaddr, u64 val, s64 pc);
template void Mem::Write64<true>(Registers& regs, u32 vaddr, u64 val, s64 pc);
} }

View File

@@ -15,10 +15,24 @@ struct Mem {
[[nodiscard]] auto GetRDRAM() -> u8* { [[nodiscard]] auto GetRDRAM() -> u8* {
return mmio.rdp.dram.data(); return mmio.rdp.dram.data();
} }
template <class T, bool tlb = true>
T Read(Registers&, u32, s64); template <bool tlb = true>
template <class T, bool tlb = true> u8 Read8(Registers&, u32, s64);
void Write(Registers&, u32, T, s64); template <bool tlb = true>
u16 Read16(Registers&, u32, s64);
template <bool tlb = true>
u32 Read32(Registers&, u32, s64);
template <bool tlb = true>
u64 Read64(Registers&, u32, s64);
template <bool tlb = true>
void Write8(Registers&, u32, u32, s64);
template <bool tlb = true>
void Write16(Registers&, u32, u32, s64);
template <bool tlb = true>
void Write32(Registers&, u32, u32, s64);
template <bool tlb = true>
void Write64(Registers&, u32, u64, s64);
u8 pifRam[PIF_RAM_SIZE]{}; u8 pifRam[PIF_RAM_SIZE]{};
private: private:
friend struct SI; friend struct SI;

View File

@@ -175,7 +175,7 @@ void Cpu::lui(u32 instr) {
void Cpu::lb(Mem& mem, u32 instr) { void Cpu::lb(Mem& mem, u32 instr) {
u32 address = regs.gpr[RS(instr)] + (s16)instr; u32 address = regs.gpr[RS(instr)] + (s16)instr;
regs.gpr[RT(instr)] = mem.Read<s8>(regs, address, regs.oldPC); regs.gpr[RT(instr)] = (s8)mem.Read8(regs, address, regs.oldPC);
} }
void Cpu::lh(Mem& mem, u32 instr) { void Cpu::lh(Mem& mem, u32 instr) {
@@ -185,7 +185,7 @@ void Cpu::lh(Mem& mem, u32 instr) {
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
} }
regs.gpr[RT(instr)] = mem.Read<s16>(regs, address, regs.oldPC); regs.gpr[RT(instr)] = (s16)mem.Read16(regs, address, regs.oldPC);
} }
void Cpu::lw(Mem& mem, u32 instr) { void Cpu::lw(Mem& mem, u32 instr) {
@@ -195,7 +195,7 @@ void Cpu::lw(Mem& mem, u32 instr) {
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
} }
regs.gpr[RT(instr)] = mem.Read<s32>(regs, address, regs.oldPC); regs.gpr[RT(instr)] = (s32)mem.Read32(regs, address, regs.oldPC);
} }
void Cpu::ll(Mem& mem, u32 instr) { void Cpu::ll(Mem& mem, u32 instr) {
@@ -205,7 +205,7 @@ void Cpu::ll(Mem& mem, u32 instr) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
} else { } else {
regs.gpr[RT(instr)] = mem.Read<s32, false>(regs, physical, regs.oldPC); regs.gpr[RT(instr)] = (s32)mem.Read32<false>(regs, physical, regs.oldPC);
} }
regs.cop0.llbit = true; regs.cop0.llbit = true;
@@ -216,7 +216,7 @@ void Cpu::lwl(Mem& mem, u32 instr) {
u32 address = regs.gpr[RS(instr)] + (s16)instr; u32 address = regs.gpr[RS(instr)] + (s16)instr;
u32 shift = 8 * ((address ^ 0) & 3); u32 shift = 8 * ((address ^ 0) & 3);
u32 mask = 0xFFFFFFFF << shift; u32 mask = 0xFFFFFFFF << shift;
u32 data = mem.Read<u32>(regs, address & ~3, regs.oldPC); u32 data = mem.Read32(regs, address & ~3, regs.oldPC);
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
s32 result = (s32)((rt & ~mask) | (data << shift)); s32 result = (s32)((rt & ~mask) | (data << shift));
regs.gpr[RT(instr)] = result; regs.gpr[RT(instr)] = result;
@@ -226,7 +226,7 @@ void Cpu::lwr(Mem& mem, u32 instr) {
u32 address = regs.gpr[RS(instr)] + (s16)instr; u32 address = regs.gpr[RS(instr)] + (s16)instr;
u32 shift = 8 * ((address ^ 3) & 3); u32 shift = 8 * ((address ^ 3) & 3);
u32 mask = 0xFFFFFFFF >> shift; u32 mask = 0xFFFFFFFF >> shift;
u32 data = mem.Read<u32>(regs, address & ~3, regs.oldPC); u32 data = mem.Read32(regs, address & ~3, regs.oldPC);
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
s32 result = (s32)((rt & ~mask) | (data >> shift)); s32 result = (s32)((rt & ~mask) | (data >> shift));
regs.gpr[RT(instr)] = result; regs.gpr[RT(instr)] = result;
@@ -239,7 +239,7 @@ void Cpu::ld(Mem& mem, u32 instr) {
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
} }
s64 value = mem.Read<s64>(regs, address, regs.oldPC); s64 value = mem.Read64(regs, address, regs.oldPC);
regs.gpr[RT(instr)] = value; regs.gpr[RT(instr)] = value;
} }
@@ -250,7 +250,7 @@ void Cpu::lld(Mem& mem, u32 instr) {
HandleTLBException(regs, address); HandleTLBException(regs, address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
} else { } else {
regs.gpr[RT(instr)] = mem.Read<s64, false>(regs, physical, regs.oldPC); regs.gpr[RT(instr)] = mem.Read64<false>(regs, physical, regs.oldPC);
} }
regs.cop0.llbit = true; regs.cop0.llbit = true;
@@ -261,7 +261,7 @@ void Cpu::ldl(Mem& mem, u32 instr) {
u32 address = regs.gpr[RS(instr)] + (s16)instr; u32 address = regs.gpr[RS(instr)] + (s16)instr;
s32 shift = 8 * ((address ^ 0) & 7); s32 shift = 8 * ((address ^ 0) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF << shift; u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
u64 data = mem.Read<u64>(regs, address & ~7, regs.oldPC); u64 data = mem.Read64(regs, address & ~7, regs.oldPC);
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
s64 result = (s64)((rt & ~mask) | (data << shift)); s64 result = (s64)((rt & ~mask) | (data << shift));
regs.gpr[RT(instr)] = result; regs.gpr[RT(instr)] = result;
@@ -271,7 +271,7 @@ void Cpu::ldr(Mem& mem, u32 instr) {
u32 address = regs.gpr[RS(instr)] + (s16)instr; u32 address = regs.gpr[RS(instr)] + (s16)instr;
s32 shift = 8 * ((address ^ 7) & 7); s32 shift = 8 * ((address ^ 7) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
u64 data = mem.Read<u64>(regs, address & ~7, regs.oldPC); u64 data = mem.Read64(regs, address & ~7, regs.oldPC);
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
s64 result = (s64)((rt & ~mask) | (data >> shift)); s64 result = (s64)((rt & ~mask) | (data >> shift));
regs.gpr[RT(instr)] = result; regs.gpr[RT(instr)] = result;
@@ -279,7 +279,7 @@ void Cpu::ldr(Mem& mem, u32 instr) {
void Cpu::lbu(Mem& mem, u32 instr) { void Cpu::lbu(Mem& mem, u32 instr) {
u32 address = regs.gpr[RS(instr)] + (s16)instr; u32 address = regs.gpr[RS(instr)] + (s16)instr;
u8 value = mem.Read<u8>(regs, address, regs.oldPC); u8 value = mem.Read8(regs, address, regs.oldPC);
regs.gpr[RT(instr)] = value; regs.gpr[RT(instr)] = value;
} }
@@ -290,7 +290,7 @@ void Cpu::lhu(Mem& mem, u32 instr) {
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
} }
u16 value = mem.Read<u16>(regs, address, regs.oldPC); u16 value = mem.Read16(regs, address, regs.oldPC);
regs.gpr[RT(instr)] = value; regs.gpr[RT(instr)] = value;
} }
@@ -301,13 +301,13 @@ void Cpu::lwu(Mem& mem, u32 instr) {
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
} }
u32 value = mem.Read<u32>(regs, address, regs.oldPC); u32 value = mem.Read32(regs, address, regs.oldPC);
regs.gpr[RT(instr)] = value; regs.gpr[RT(instr)] = value;
} }
void Cpu::sb(Mem& mem, u32 instr) { void Cpu::sb(Mem& mem, u32 instr) {
u32 address = regs.gpr[RS(instr)] + (s16)instr; u32 address = regs.gpr[RS(instr)] + (s16)instr;
mem.Write<u8>(regs, address, regs.gpr[RT(instr)], regs.oldPC); mem.Write8(regs, address, regs.gpr[RT(instr)], regs.oldPC);
} }
void Cpu::sc(Mem& mem, u32 instr) { void Cpu::sc(Mem& mem, u32 instr) {
@@ -318,7 +318,7 @@ void Cpu::sc(Mem& mem, u32 instr) {
} }
if(regs.cop0.llbit) { if(regs.cop0.llbit) {
mem.Write<u32>(regs, address, regs.gpr[RT(instr)], regs.oldPC); mem.Write32(regs, address, regs.gpr[RT(instr)], regs.oldPC);
} }
regs.gpr[RT(instr)] = (u64)regs.cop0.llbit; regs.gpr[RT(instr)] = (u64)regs.cop0.llbit;
@@ -333,7 +333,7 @@ void Cpu::scd(Mem& mem, u32 instr) {
} }
if(regs.cop0.llbit) { if(regs.cop0.llbit) {
mem.Write<u64>(regs, address, regs.gpr[RT(instr)], regs.oldPC); mem.Write64(regs, address, regs.gpr[RT(instr)], regs.oldPC);
} }
regs.gpr[RT(instr)] = (s64)((u64)regs.cop0.llbit); regs.gpr[RT(instr)] = (s64)((u64)regs.cop0.llbit);
@@ -347,7 +347,7 @@ void Cpu::sh(Mem& mem, u32 instr) {
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
} }
mem.Write<u16>(regs, address, regs.gpr[RT(instr)], regs.oldPC); mem.Write16(regs, address, regs.gpr[RT(instr)], regs.oldPC);
} }
void Cpu::sw(Mem& mem, u32 instr) { void Cpu::sw(Mem& mem, u32 instr) {
@@ -357,7 +357,7 @@ void Cpu::sw(Mem& mem, u32 instr) {
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
} }
mem.Write<u32>(regs, address, regs.gpr[RT(instr)], regs.oldPC); mem.Write32(regs, address, regs.gpr[RT(instr)], regs.oldPC);
} }
void Cpu::sd(Mem& mem, u32 instr) { void Cpu::sd(Mem& mem, u32 instr) {
@@ -367,43 +367,43 @@ void Cpu::sd(Mem& mem, u32 instr) {
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
} }
mem.Write<u64>(regs, address, regs.gpr[RT(instr)], regs.oldPC); mem.Write64(regs, address, regs.gpr[RT(instr)], regs.oldPC);
} }
void Cpu::sdl(Mem& mem, u32 instr) { void Cpu::sdl(Mem& mem, u32 instr) {
u32 address = regs.gpr[RS(instr)] + (s16)instr; u32 address = regs.gpr[RS(instr)] + (s16)instr;
s32 shift = 8 * ((address ^ 0) & 7); s32 shift = 8 * ((address ^ 0) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
u64 data = mem.Read<u64>(regs, address & ~7, regs.oldPC); u64 data = mem.Read64(regs, address & ~7, regs.oldPC);
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
mem.Write<u64>(regs, address & ~7, (data & ~mask) | (rt >> shift), regs.oldPC); mem.Write64(regs, address & ~7, (data & ~mask) | (rt >> shift), regs.oldPC);
} }
void Cpu::sdr(Mem& mem, u32 instr) { void Cpu::sdr(Mem& mem, u32 instr) {
u32 address = regs.gpr[RS(instr)] + (s16)instr; u32 address = regs.gpr[RS(instr)] + (s16)instr;
s32 shift = 8 * ((address ^ 7) & 7); s32 shift = 8 * ((address ^ 7) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF << shift; u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
u64 data = mem.Read<u64>(regs, address & ~7, regs.oldPC); u64 data = mem.Read64(regs, address & ~7, regs.oldPC);
s64 rt = regs.gpr[RT(instr)]; s64 rt = regs.gpr[RT(instr)];
mem.Write<u64>(regs, address & ~7, (data & ~mask) | (rt << shift), regs.oldPC); mem.Write64(regs, address & ~7, (data & ~mask) | (rt << shift), regs.oldPC);
} }
void Cpu::swl(Mem& mem, u32 instr) { void Cpu::swl(Mem& mem, u32 instr) {
u32 address = regs.gpr[RS(instr)] + (s16)instr; u32 address = regs.gpr[RS(instr)] + (s16)instr;
u32 shift = 8 * ((address ^ 0) & 3); u32 shift = 8 * ((address ^ 0) & 3);
u32 mask = 0xFFFFFFFF >> shift; u32 mask = 0xFFFFFFFF >> shift;
u32 data = mem.Read<u32>(regs, address & ~3, regs.oldPC); u32 data = mem.Read32(regs, address & ~3, regs.oldPC);
u32 rt = regs.gpr[RT(instr)]; u32 rt = regs.gpr[RT(instr)];
mem.Write<u32>(regs, address & ~3, (data & ~mask) | (rt >> shift), regs.oldPC); mem.Write32(regs, address & ~3, (data & ~mask) | (rt >> shift), regs.oldPC);
} }
void Cpu::swr(Mem& mem, u32 instr) { void Cpu::swr(Mem& mem, u32 instr) {
u32 address = regs.gpr[RS(instr)] + (s16)instr; u32 address = regs.gpr[RS(instr)] + (s16)instr;
u32 shift = 8 * ((address ^ 3) & 3); u32 shift = 8 * ((address ^ 3) & 3);
u32 mask = 0xFFFFFFFF << shift; u32 mask = 0xFFFFFFFF << shift;
u32 data = mem.Read<u32>(regs, address & ~3, regs.oldPC); u32 data = mem.Read32(regs, address & ~3, regs.oldPC);
u32 rt = regs.gpr[RT(instr)]; u32 rt = regs.gpr[RT(instr)];
mem.Write<u32>(regs, address & ~3, (data & ~mask) | (rt << shift), regs.oldPC); mem.Write32(regs, address & ~3, (data & ~mask) | (rt << shift), regs.oldPC);
} }
void Cpu::ori(u32 instr) { void Cpu::ori(u32 instr) {

View File

@@ -415,18 +415,18 @@ void Cop1::floorwd(Registers& regs, u32 instr) {
void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) { void Cop1::lwc1(Registers& regs, Mem& mem, u32 instr) {
u32 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; u32 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
u32 data = mem.Read<u32>(regs, addr, regs.oldPC); u32 data = mem.Read32(regs, addr, regs.oldPC);
SetReg<u32>(regs.cop0, FT(instr), data); SetReg<u32>(regs.cop0, FT(instr), data);
} }
void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) { void Cop1::swc1(Registers& regs, Mem& mem, u32 instr) {
u32 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; u32 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
mem.Write<u32>(regs, addr, GetReg<u32>(regs.cop0, FT(instr)), regs.oldPC); mem.Write32(regs, addr, GetReg<u32>(regs.cop0, FT(instr)), regs.oldPC);
} }
void Cop1::ldc1(Registers& regs, Mem& mem, u32 instr) { void Cop1::ldc1(Registers& regs, Mem& mem, u32 instr) {
u32 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; u32 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
u64 data = mem.Read<u64>(regs, addr, regs.oldPC); u64 data = mem.Read64(regs, addr, regs.oldPC);
SetReg<u64>(regs.cop0, FT(instr), data); SetReg<u64>(regs.cop0, FT(instr), data);
} }
@@ -456,7 +456,7 @@ void Cop1::truncld(Registers& regs, u32 instr) {
void Cop1::sdc1(Registers& regs, Mem& mem, u32 instr) { void Cop1::sdc1(Registers& regs, Mem& mem, u32 instr) {
u32 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; u32 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
mem.Write<u64>(regs, addr, GetReg<u64>(regs.cop0, FT(instr)), regs.oldPC); mem.Write64(regs, addr, GetReg<u64>(regs.cop0, FT(instr)), regs.oldPC);
} }
void Cop1::mfc1(Registers& regs, u32 instr) { void Cop1::mfc1(Registers& regs, u32 instr) {

View File

@@ -81,7 +81,7 @@ void AI::Step(Mem& mem, Registers& regs, int cpuCycles, float volumeL, float vol
u32 address_hi = ((dmaAddr[0] >> 13) + dmaAddrCarry) & 0x7ff; u32 address_hi = ((dmaAddr[0] >> 13) + dmaAddrCarry) & 0x7ff;
dmaAddr[0] = (address_hi << 13) | dmaAddr[0] & 0x1fff; dmaAddr[0] = (address_hi << 13) | dmaAddr[0] & 0x1fff;
u32 data = mem.Read<u32, false>(regs, dmaAddr[0], regs.pc); u32 data = mem.Read32<false>(regs, dmaAddr[0], regs.pc);
s16 left = (s16)(data >> 16); s16 left = (s16)(data >> 16);
s16 right = (s16)data; s16 right = (s16)data;