Refactor Cop0

This commit is contained in:
SimoneN64
2024-05-12 22:43:08 +02:00
committed by Simone
parent da8760c6df
commit f8e45819c8
13 changed files with 219 additions and 225 deletions

View File

@@ -28,22 +28,22 @@ int Interpreter::Step() {
regs.delaySlot = false; regs.delaySlot = false;
if(check_address_error(0b11, u64(regs.pc))) [[unlikely]] { if(check_address_error(0b11, u64(regs.pc))) [[unlikely]] {
HandleTLBException(regs, regs.pc); regs.cop0.HandleTLBException(regs.pc);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.pc); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.pc);
return 1; return 1;
} }
u32 paddr = 0; u32 paddr = 0;
if(!MapVAddr(regs, LOAD, regs.pc, paddr)) { if(!regs.cop0.MapVAddr(Cop0::LOAD, regs.pc, paddr)) {
HandleTLBException(regs, regs.pc); regs.cop0.HandleTLBException(regs.pc);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.pc); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc);
return 1; return 1;
} }
u32 instruction = mem.Read<u32>(regs, paddr); u32 instruction = mem.Read<u32>(regs, paddr);
if(ShouldServiceInterrupt()) { if(ShouldServiceInterrupt()) {
FireException(regs, ExceptionCode::Interrupt, 0, regs.pc); regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc);
return 1; return 1;
} }

View File

@@ -12,7 +12,7 @@ struct Interpreter : BaseCPU {
private: private:
u64 cop2Latch{}; u64 cop2Latch{};
friend struct Cop1; friend struct Cop1;
#define check_address_error(mask, vaddr) (((!regs.cop0.is_64bit_addressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0)) #define check_address_error(mask, vaddr) (((!regs.cop0.is64BitAddressing) && (s32)(vaddr) != (vaddr)) || (((vaddr) & (mask)) != 0))
bool ShouldServiceInterrupt() override; bool ShouldServiceInterrupt() override;
void CheckCompareInterrupt() override; void CheckCompareInterrupt() override;
std::vector<u8> Serialize() override; std::vector<u8> Serialize() override;

View File

@@ -19,8 +19,8 @@ void Interpreter::special(u32 instr) {
case SRAV: srav(instr); break; case SRAV: srav(instr); break;
case JR: jr(instr); break; case JR: jr(instr); break;
case JALR: jalr(instr); break; case JALR: jalr(instr); break;
case SYSCALL: FireException(regs, ExceptionCode::Syscall, 0, regs.oldPC); break; case SYSCALL: regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC); break;
case BREAK: FireException(regs, ExceptionCode::Breakpoint, 0, regs.oldPC); break; case BREAK: regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC); break;
case SYNC: break; // SYNC case SYNC: break; // SYNC
case MFHI: mfhi(instr); break; case MFHI: mfhi(instr); break;
case MTHI: mthi(instr); break; case MTHI: mthi(instr); break;
@@ -93,7 +93,7 @@ void Interpreter::regimm(u32 instr) {
void Interpreter::cop2Decode(u32 instr) { void Interpreter::cop2Decode(u32 instr) {
if(!regs.cop0.status.cu2) { if(!regs.cop0.status.cu2) {
FireException(regs, ExceptionCode::CoprocessorUnusable, 2, regs.oldPC); regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
return; return;
} }
switch(RS(instr)) { switch(RS(instr)) {
@@ -104,7 +104,7 @@ void Interpreter::cop2Decode(u32 instr) {
case 0x05: dmtc2(instr); break; case 0x05: dmtc2(instr); break;
case 0x06: ctc2(instr); break; case 0x06: ctc2(instr); break;
default: default:
FireException(regs, ExceptionCode::ReservedInstruction, 2, regs.oldPC); regs.cop0.FireException(ExceptionCode::ReservedInstruction, 2, regs.oldPC);
} }
} }
@@ -142,7 +142,7 @@ void Interpreter::Exec(u32 instr) {
case DADDIU: daddiu(instr); break; case DADDIU: daddiu(instr); break;
case LDL: ldl(instr); break; case LDL: ldl(instr); break;
case LDR: ldr(instr); break; case LDR: ldr(instr); break;
case 0x1F: FireException(regs, ExceptionCode::ReservedInstruction, 0, regs.oldPC); break; case 0x1F: regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC); break;
case LB: lb(instr); break; case LB: lb(instr); break;
case LH: lh(instr); break; case LH: lh(instr); break;
case LWL: lwl(instr); break; case LWL: lwl(instr); break;

View File

@@ -9,7 +9,7 @@ void Interpreter::add(u32 instr) {
u32 rt = (s32)regs.gpr[RT(instr)]; u32 rt = (s32)regs.gpr[RT(instr)];
u32 result = rs + rt; u32 result = rs + rt;
if(check_signed_overflow(rs, rt, result)) { if(check_signed_overflow(rs, rt, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
} else { } else {
if (RD(instr) != 0) [[likely]] { if (RD(instr) != 0) [[likely]] {
regs.gpr[RD(instr)] = s32(result); regs.gpr[RD(instr)] = s32(result);
@@ -31,7 +31,7 @@ void Interpreter::addi(u32 instr) {
u32 imm = s32(s16(instr)); u32 imm = s32(s16(instr));
u32 result = rs + imm; u32 result = rs + imm;
if(check_signed_overflow(rs, imm, result)) { if(check_signed_overflow(rs, imm, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
} else { } else {
if (RT(instr) != 0) [[likely]] { if (RT(instr) != 0) [[likely]] {
regs.gpr[RT(instr)] = s32(result); regs.gpr[RT(instr)] = s32(result);
@@ -53,7 +53,7 @@ void Interpreter::dadd(u32 instr) {
u64 rt = regs.gpr[RT(instr)]; u64 rt = regs.gpr[RT(instr)];
u64 result = rt + rs; u64 result = rt + rs;
if(check_signed_overflow(rs, rt, result)) { if(check_signed_overflow(rs, rt, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
} else { } else {
if (RD(instr) != 0) [[likely]] { if (RD(instr) != 0) [[likely]] {
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
@@ -74,7 +74,7 @@ void Interpreter::daddi(u32 instr) {
u64 rs = regs.gpr[RS(instr)]; u64 rs = regs.gpr[RS(instr)];
u64 result = imm + rs; u64 result = imm + rs;
if(check_signed_overflow(rs, imm, result)) { if(check_signed_overflow(rs, imm, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
} else { } else {
if (RT(instr) != 0) [[likely]] { if (RT(instr) != 0) [[likely]] {
regs.gpr[RT(instr)] = result; regs.gpr[RT(instr)] = result;
@@ -215,9 +215,9 @@ void Interpreter::lui(u32 instr) {
void Interpreter::lb(u32 instr) { void Interpreter::lb(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr = 0; u32 paddr = 0;
if(!MapVAddr(regs, LOAD, address, paddr)) { if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
if (RT(instr) != 0) [[likely]] { if (RT(instr) != 0) [[likely]] {
regs.gpr[RT(instr)] = (s8) mem.Read<u8>(regs, paddr); regs.gpr[RT(instr)] = (s8) mem.Read<u8>(regs, paddr);
@@ -228,15 +228,15 @@ void Interpreter::lb(u32 instr) {
void Interpreter::lh(u32 instr) { void Interpreter::lh(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(0b1, address)) { if (check_address_error(0b1, address)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return; return;
} }
u32 paddr = 0; u32 paddr = 0;
if(!MapVAddr(regs, LOAD, address, paddr)) { if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
if (RT(instr) != 0) [[likely]] { if (RT(instr) != 0) [[likely]] {
regs.gpr[RT(instr)] = (s16) mem.Read<u16>(regs, paddr); regs.gpr[RT(instr)] = (s16) mem.Read<u16>(regs, paddr);
@@ -248,15 +248,15 @@ void Interpreter::lw(u32 instr) {
s16 offset = instr; s16 offset = instr;
u64 address = regs.gpr[RS(instr)] + offset; u64 address = regs.gpr[RS(instr)] + offset;
if (check_address_error(0b11, address)) { if (check_address_error(0b11, address)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return; return;
} }
u32 physical = 0; u32 physical = 0;
if (!MapVAddr(regs, LOAD, address, physical)) { if (!regs.cop0.MapVAddr(Cop0::LOAD, address, physical)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
if(RT(instr) != 0) [[likely]] { if(RT(instr) != 0) [[likely]] {
regs.gpr[RT(instr)] = (s32) mem.Read<u32>(regs, physical); regs.gpr[RT(instr)] = (s32) mem.Read<u32>(regs, physical);
@@ -267,13 +267,13 @@ void Interpreter::lw(u32 instr) {
void Interpreter::ll(u32 instr) { void Interpreter::ll(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 physical; u32 physical;
if (!MapVAddr(regs, LOAD, address, physical)) { if (!regs.cop0.MapVAddr(Cop0::LOAD, address, physical)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
s32 result = mem.Read<u32>(regs, physical); s32 result = mem.Read<u32>(regs, physical);
if (check_address_error(0b11, address)) { if (check_address_error(0b11, address)) {
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return; return;
} }
@@ -289,9 +289,9 @@ void Interpreter::ll(u32 instr) {
void Interpreter::lwl(u32 instr) { void Interpreter::lwl(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr = 0; u32 paddr = 0;
if(!MapVAddr(regs, LOAD, address, paddr)) { if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
u32 shift = 8 * ((address ^ 0) & 3); u32 shift = 8 * ((address ^ 0) & 3);
u32 mask = 0xFFFFFFFF << shift; u32 mask = 0xFFFFFFFF << shift;
@@ -306,9 +306,9 @@ void Interpreter::lwl(u32 instr) {
void Interpreter::lwr(u32 instr) { void Interpreter::lwr(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr = 0; u32 paddr = 0;
if(!MapVAddr(regs, LOAD, address, paddr)) { if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
u32 shift = 8 * ((address ^ 3) & 3); u32 shift = 8 * ((address ^ 3) & 3);
u32 mask = 0xFFFFFFFF >> shift; u32 mask = 0xFFFFFFFF >> shift;
@@ -323,15 +323,15 @@ void Interpreter::lwr(u32 instr) {
void Interpreter::ld(u32 instr) { void Interpreter::ld(u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(0b111, address)) { if (check_address_error(0b111, address)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return; return;
} }
u32 paddr = 0; u32 paddr = 0;
if(!MapVAddr(regs, LOAD, address, paddr)) { if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
s64 value = mem.Read<u64>(regs, paddr); s64 value = mem.Read<u64>(regs, paddr);
if (RT(instr) != 0) [[likely]] { if (RT(instr) != 0) [[likely]] {
@@ -341,19 +341,19 @@ void Interpreter::ld(u32 instr) {
} }
void Interpreter::lld(u32 instr) { void Interpreter::lld(u32 instr) {
if (!regs.cop0.is_64bit_addressing && !regs.cop0.kernel_mode) { if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
FireException(regs, ExceptionCode::ReservedInstruction, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
return; return;
} }
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, LOAD, address, paddr)) { if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
if (check_address_error(0b111, address)) { if (check_address_error(0b111, address)) {
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
} else { } else {
if (RT(instr) != 0) [[likely]] { if (RT(instr) != 0) [[likely]] {
regs.gpr[RT(instr)] = mem.Read<u64>(regs, paddr); regs.gpr[RT(instr)] = mem.Read<u64>(regs, paddr);
@@ -367,9 +367,9 @@ void Interpreter::lld(u32 instr) {
void Interpreter::ldl(u32 instr) { void Interpreter::ldl(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr = 0; u32 paddr = 0;
if (!MapVAddr(regs, LOAD, address, paddr)) { if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
s32 shift = 8 * ((address ^ 0) & 7); s32 shift = 8 * ((address ^ 0) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF << shift; u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
@@ -384,9 +384,9 @@ void Interpreter::ldl(u32 instr) {
void Interpreter::ldr(u32 instr) { void Interpreter::ldr(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, LOAD, address, paddr)) { if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
s32 shift = 8 * ((address ^ 7) & 7); s32 shift = 8 * ((address ^ 7) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
@@ -401,9 +401,9 @@ void Interpreter::ldr(u32 instr) {
void Interpreter::lbu(u32 instr) { void Interpreter::lbu(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, LOAD, address, paddr)) { if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
u8 value = mem.Read<u8>(regs, paddr); u8 value = mem.Read<u8>(regs, paddr);
if (RT(instr) != 0) [[likely]] { if (RT(instr) != 0) [[likely]] {
@@ -415,14 +415,14 @@ void Interpreter::lbu(u32 instr) {
void Interpreter::lhu(u32 instr) { void Interpreter::lhu(u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(0b1, address)) { if (check_address_error(0b1, address)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return; return;
} }
u32 paddr; u32 paddr;
if (!MapVAddr(regs, LOAD, address, paddr)) { if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
u16 value = mem.Read<u16>(regs, paddr); u16 value = mem.Read<u16>(regs, paddr);
if (RT(instr) != 0) [[likely]] { if (RT(instr) != 0) [[likely]] {
@@ -434,15 +434,15 @@ void Interpreter::lhu(u32 instr) {
void Interpreter::lwu(u32 instr) { void Interpreter::lwu(u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(0b11, address)) { if (check_address_error(0b11, address)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
return; return;
} }
u32 paddr; u32 paddr;
if (!MapVAddr(regs, LOAD, address, paddr)) { if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
u32 value = mem.Read<u32>(regs, paddr); u32 value = mem.Read<u32>(regs, paddr);
if (RT(instr) != 0) [[likely]] { if (RT(instr) != 0) [[likely]] {
@@ -454,9 +454,9 @@ void Interpreter::lwu(u32 instr) {
void Interpreter::sb(u32 instr) { void Interpreter::sb(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) { if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else { } else {
mem.Write<u8>(regs, paddr, regs.gpr[RT(instr)]); mem.Write<u8>(regs, paddr, regs.gpr[RT(instr)]);
} }
@@ -466,16 +466,16 @@ void Interpreter::sc(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(0b11, address)) { if (check_address_error(0b11, address)) {
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
return; return;
} }
if(regs.cop0.llbit) { if(regs.cop0.llbit) {
regs.cop0.llbit = false; regs.cop0.llbit = false;
u32 paddr = 0; u32 paddr = 0;
if(!MapVAddr(regs, STORE, address, paddr)) { if(!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else { } else {
mem.Write<u32>(regs, paddr, regs.gpr[RT(instr)]); mem.Write<u32>(regs, paddr, regs.gpr[RT(instr)]);
if (RT(instr) != 0) [[likely]] { if (RT(instr) != 0) [[likely]] {
@@ -490,24 +490,24 @@ void Interpreter::sc(u32 instr) {
} }
void Interpreter::scd(u32 instr) { void Interpreter::scd(u32 instr) {
if (!regs.cop0.is_64bit_addressing && !regs.cop0.kernel_mode) { if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
FireException(regs, ExceptionCode::ReservedInstruction, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
return; return;
} }
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(0b111, address)) { if (check_address_error(0b111, address)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
return; return;
} }
if(regs.cop0.llbit) { if(regs.cop0.llbit) {
regs.cop0.llbit = false; regs.cop0.llbit = false;
u32 paddr = 0; u32 paddr = 0;
if(!MapVAddr(regs, STORE, address, paddr)) { if(!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else { } else {
mem.Write<u32>(regs, paddr, regs.gpr[RT(instr)]); mem.Write<u32>(regs, paddr, regs.gpr[RT(instr)]);
if (RT(instr) != 0) [[likely]] { if (RT(instr) != 0) [[likely]] {
@@ -525,9 +525,9 @@ void Interpreter::sh(u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 physical; u32 physical;
if(!MapVAddr(regs, STORE, address, physical)) { if(!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else { } else {
mem.Write<u16>(regs, physical, regs.gpr[RT(instr)]); mem.Write<u16>(regs, physical, regs.gpr[RT(instr)]);
} }
@@ -537,15 +537,15 @@ void Interpreter::sw(u32 instr) {
s16 offset = instr; s16 offset = instr;
u64 address = regs.gpr[RS(instr)] + offset; u64 address = regs.gpr[RS(instr)] + offset;
if (check_address_error(0b11, address)) { if (check_address_error(0b11, address)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
return; return;
} }
u32 physical; u32 physical;
if(!MapVAddr(regs, STORE, address, physical)) { if(!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else { } else {
mem.Write<u32>(regs, physical, regs.gpr[RT(instr)]); mem.Write<u32>(regs, physical, regs.gpr[RT(instr)]);
} }
@@ -554,15 +554,15 @@ void Interpreter::sw(u32 instr) {
void Interpreter::sd(u32 instr) { void Interpreter::sd(u32 instr) {
s64 address = regs.gpr[RS(instr)] + (s16)instr; s64 address = regs.gpr[RS(instr)] + (s16)instr;
if (check_address_error(0b111, address)) { if (check_address_error(0b111, address)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
return; return;
} }
u32 physical; u32 physical;
if(!MapVAddr(regs, STORE, address, physical)) { if(!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else { } else {
mem.Write(regs, physical, regs.gpr[RT(instr)]); mem.Write(regs, physical, regs.gpr[RT(instr)]);
} }
@@ -571,9 +571,9 @@ void Interpreter::sd(u32 instr) {
void Interpreter::sdl(u32 instr) { void Interpreter::sdl(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) { if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else { } else {
s32 shift = 8 * ((address ^ 0) & 7); s32 shift = 8 * ((address ^ 0) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift; u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
@@ -586,9 +586,9 @@ void Interpreter::sdl(u32 instr) {
void Interpreter::sdr(u32 instr) { void Interpreter::sdr(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) { if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else { } else {
s32 shift = 8 * ((address ^ 7) & 7); s32 shift = 8 * ((address ^ 7) & 7);
u64 mask = 0xFFFFFFFFFFFFFFFF << shift; u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
@@ -601,9 +601,9 @@ void Interpreter::sdr(u32 instr) {
void Interpreter::swl(u32 instr) { void Interpreter::swl(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) { if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else { } else {
u32 shift = 8 * ((address ^ 0) & 3); u32 shift = 8 * ((address ^ 0) & 3);
u32 mask = 0xFFFFFFFF >> shift; u32 mask = 0xFFFFFFFF >> shift;
@@ -616,9 +616,9 @@ void Interpreter::swl(u32 instr) {
void Interpreter::swr(u32 instr) { void Interpreter::swr(u32 instr) {
u64 address = regs.gpr[RS(instr)] + (s16)instr; u64 address = regs.gpr[RS(instr)] + (s16)instr;
u32 paddr; u32 paddr;
if (!MapVAddr(regs, STORE, address, paddr)) { if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
HandleTLBException(regs, address); regs.cop0.HandleTLBException(address);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else { } else {
u32 shift = 8 * ((address ^ 3) & 3); u32 shift = 8 * ((address ^ 3) & 3);
u32 mask = 0xFFFFFFFF << shift; u32 mask = 0xFFFFFFFF << shift;
@@ -863,7 +863,7 @@ void Interpreter::dsub(u32 instr) {
s64 rs = regs.gpr[RS(instr)]; s64 rs = regs.gpr[RS(instr)];
s64 result = rs - rt; s64 result = rs - rt;
if(check_signed_underflow(rs, rt, result)) { if(check_signed_underflow(rs, rt, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
} else { } else {
if (RD(instr) != 0) [[likely]] { if (RD(instr) != 0) [[likely]] {
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
@@ -885,7 +885,7 @@ void Interpreter::sub(u32 instr) {
s32 rs = regs.gpr[RS(instr)]; s32 rs = regs.gpr[RS(instr)];
s32 result = rs - rt; s32 result = rs - rt;
if(check_signed_underflow(rs, rt, result)) { if(check_signed_underflow(rs, rt, result)) {
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
} else { } else {
if (RD(instr) != 0) [[likely]] { if (RD(instr) != 0) [[likely]] {
regs.gpr[RD(instr)] = result; regs.gpr[RD(instr)] = result;
@@ -956,7 +956,7 @@ void Interpreter::mthi(u32 instr) {
void Interpreter::trap(bool cond) { void Interpreter::trap(bool cond) {
if(cond) { if(cond) {
FireException(regs, ExceptionCode::Trap, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::Trap, 0, regs.oldPC);
} }
} }

View File

@@ -60,7 +60,7 @@ void PIF::MaybeLoadMempak() {
} }
} }
FORCE_INLINE size_t getSaveSize(SaveType saveType) { FORCE_INLINE size_t GetSaveSize(SaveType saveType) {
switch (saveType) { switch (saveType) {
case SAVE_NONE: case SAVE_NONE:
return 0; return 0;
@@ -87,7 +87,7 @@ void PIF::LoadEeprom(SaveType saveType, const std::string& path) {
eeprom.unmap(); eeprom.unmap();
} }
eepromSize = getSaveSize(saveType); eepromSize = GetSaveSize(saveType);
FILE *f = fopen(eepromPath.c_str(), "rb"); FILE *f = fopen(eepromPath.c_str(), "rb");
if (!f) { if (!f) {
f = fopen(eepromPath.c_str(), "wb"); f = fopen(eepromPath.c_str(), "wb");
@@ -133,11 +133,11 @@ void PIF::CICChallenge() {
} }
} }
FORCE_INLINE u8 data_crc(const u8* data) { FORCE_INLINE u8 DataCRC(const u8* data) {
u8 crc = 0; u8 crc = 0;
for (int i = 0; i <= 32; i++) { for (int i = 0; i <= 32; i++) {
for (int j = 7; j >= 0; j--) { for (int j = 7; j >= 0; j--) {
u8 xor_val = ((crc & 0x80) != 0) ? 0x85 : 0x00; u8 xorVal = ((crc & 0x80) != 0) ? 0x85 : 0x00;
crc <<= 1; crc <<= 1;
if (i < 32) { if (i < 32) {
@@ -146,7 +146,7 @@ FORCE_INLINE u8 data_crc(const u8* data) {
} }
} }
crc ^= xor_val; crc ^= xorVal;
} }
} }
@@ -260,7 +260,7 @@ void PIF::MempakRead(const u8* cmd, u8* res) {
// offset must be 32-byte aligned // offset must be 32-byte aligned
offset &= ~0x1F; offset &= ~0x1F;
switch (getAccessoryType()) { switch (GetAccessoryType()) {
case ACCESSORY_NONE: case ACCESSORY_NONE:
break; break;
case ACCESSORY_MEMPACK: case ACCESSORY_MEMPACK:
@@ -274,7 +274,7 @@ void PIF::MempakRead(const u8* cmd, u8* res) {
} }
// CRC byte // CRC byte
res[32] = data_crc(res); res[32] = DataCRC(res);
} }
void PIF::MempakWrite(u8* cmd, u8* res) { void PIF::MempakWrite(u8* cmd, u8* res) {
@@ -288,7 +288,7 @@ void PIF::MempakWrite(u8* cmd, u8* res) {
// offset must be 32-byte aligned // offset must be 32-byte aligned
offset &= ~0x1F; offset &= ~0x1F;
switch (getAccessoryType()) { switch (GetAccessoryType()) {
case ACCESSORY_NONE: case ACCESSORY_NONE:
break; break;
case ACCESSORY_MEMPACK: case ACCESSORY_MEMPACK:
@@ -299,14 +299,14 @@ void PIF::MempakWrite(u8* cmd, u8* res) {
case ACCESSORY_RUMBLE_PACK: break; case ACCESSORY_RUMBLE_PACK: break;
} }
// CRC byte // CRC byte
res[0] = data_crc(&cmd[5]); res[0] = DataCRC(&cmd[5]);
} }
void PIF::EepromRead(const u8* cmd, u8* res, const Mem& mem) const { void PIF::EepromRead(const u8* cmd, u8* res, const Mem& mem) const {
assert(mem.saveType == SAVE_EEPROM_4k || mem.saveType == SAVE_EEPROM_16k); assert(mem.saveType == SAVE_EEPROM_4k || mem.saveType == SAVE_EEPROM_16k);
if (channel == 4) { if (channel == 4) {
u8 offset = cmd[3]; u8 offset = cmd[3];
if ((offset * 8) >= getSaveSize(mem.saveType)) { if ((offset * 8) >= GetSaveSize(mem.saveType)) {
Util::panic("Out of range EEPROM read! offset: {:02X}", offset); Util::panic("Out of range EEPROM read! offset: {:02X}", offset);
} }
@@ -320,7 +320,7 @@ void PIF::EepromWrite(const u8* cmd, u8* res, const Mem& mem) {
assert(mem.saveType == SAVE_EEPROM_4k || mem.saveType == SAVE_EEPROM_16k); assert(mem.saveType == SAVE_EEPROM_4k || mem.saveType == SAVE_EEPROM_16k);
if (channel == 4) { if (channel == 4) {
u8 offset = cmd[3]; u8 offset = cmd[3];
if ((offset * 8) >= getSaveSize(mem.saveType)) { if ((offset * 8) >= GetSaveSize(mem.saveType)) {
Util::panic("Out of range EEPROM write! offset: {:02X}", offset); Util::panic("Out of range EEPROM write! offset: {:02X}", offset);
} }

View File

@@ -191,7 +191,7 @@ struct PIF {
ram[addr & PIF_RAM_DSIZE] = val; ram[addr & PIF_RAM_DSIZE] = val;
} }
FORCE_INLINE AccessoryType getAccessoryType() const { FORCE_INLINE AccessoryType GetAccessoryType() const {
if (channel >= 4 || joybusDevices[channel].type != JOYBUS_CONTROLLER) { if (channel >= 4 || joybusDevices[channel].type != JOYBUS_CONTROLLER) {
return ACCESSORY_NONE; return ACCESSORY_NONE;
} else { } else {

View File

@@ -34,7 +34,5 @@ struct SI {
PIF pif; PIF pif;
}; };
// just to silence warning, it is used.
[[maybe_unused]] static void DMA(Mem& mem, Registers& regs);
#define SI_DMA_DELAY (65536 * 2) #define SI_DMA_DELAY (65536 * 2)
} }

View File

@@ -3,7 +3,7 @@
#include <core/Interpreter.hpp> #include <core/Interpreter.hpp>
namespace n64 { namespace n64 {
Cop0::Cop0() { Cop0::Cop0(Registers& regs) : regs(regs) {
Reset(); Reset();
} }
@@ -176,7 +176,7 @@ static FORCE_INLINE u64 getVPN(u64 addr, u64 pageMask) {
return vpn & ~mask; return vpn & ~mask;
} }
TLBEntry* TLBTryMatch(Registers& regs, u64 vaddr, int* match) { TLBEntry* Cop0::TLBTryMatch(u64 vaddr, int* match) {
for(int i = 0; i < 32; i++) { for(int i = 0; i < 32; i++) {
TLBEntry *entry = &regs.cop0.tlb[i]; TLBEntry *entry = &regs.cop0.tlb[i];
if(entry->initialized) { if(entry->initialized) {
@@ -198,8 +198,8 @@ TLBEntry* TLBTryMatch(Registers& regs, u64 vaddr, int* match) {
return nullptr; return nullptr;
} }
bool ProbeTLB(Registers& regs, TLBAccessType access_type, u64 vaddr, u32& paddr, int* match) { bool Cop0::ProbeTLB(TLBAccessType access_type, u64 vaddr, u32& paddr, int* match) {
TLBEntry* entry = TLBTryMatch(regs, vaddr, match); TLBEntry* entry = TLBTryMatch(vaddr, match);
if(!entry) { if(!entry) {
regs.cop0.tlbError = MISS; regs.cop0.tlbError = MISS;
return false; return false;
@@ -250,7 +250,7 @@ FORCE_INLINE bool Is64BitAddressing(Cop0& cp0, u64 addr) {
} }
} }
void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc) { void Cop0::FireException(ExceptionCode code, int cop, s64 pc) {
bool old_exl = regs.cop0.status.exl; bool old_exl = regs.cop0.status.exl;
if(!regs.cop0.status.exl) { if(!regs.cop0.status.exl) {
@@ -294,7 +294,7 @@ void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc) {
regs.cop0.Update(); regs.cop0.Update();
} }
void HandleTLBException(Registers& regs, u64 vaddr) { void Cop0::HandleTLBException(u64 vaddr) {
u64 vpn2 = (vaddr >> 13) & 0x7FFFF; u64 vpn2 = (vaddr >> 13) & 0x7FFFF;
u64 xvpn2 = (vaddr >> 13) & 0x7FFFFFF; u64 xvpn2 = (vaddr >> 13) & 0x7FFFFFF;
regs.cop0.badVaddr = vaddr; regs.cop0.badVaddr = vaddr;
@@ -305,7 +305,7 @@ void HandleTLBException(Registers& regs, u64 vaddr) {
regs.cop0.entryHi.r = (vaddr >> 62) & 3; regs.cop0.entryHi.r = (vaddr >> 62) & 3;
} }
ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType) { ExceptionCode Cop0::GetTLBExceptionCode(TLBError error, TLBAccessType accessType) {
switch(error) { switch(error) {
case NONE: Util::panic("Getting TLB exception with error NONE"); case NONE: Util::panic("Getting TLB exception with error NONE");
case INVALID: case MISS: case INVALID: case MISS:
@@ -324,7 +324,7 @@ ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType) {
template<class T> template<class T>
void Cop0::decode(T& cpu, u32 instr) { void Cop0::decode(T& cpu, u32 instr) {
if constexpr (std::is_same_v<decltype(cpu), Interpreter&>) { if constexpr (std::is_same_v<decltype(cpu), Interpreter&>) {
decodeInterp(cpu.regs, instr); decodeInterp(instr);
} else if constexpr (std::is_same_v<decltype(cpu), JIT&>) { } else if constexpr (std::is_same_v<decltype(cpu), JIT&>) {
decodeJIT(cpu, instr); decodeJIT(cpu, instr);
} else { } else {
@@ -339,21 +339,21 @@ void Cop0::decodeJIT(JIT& cpu, u32 instr) {
} }
void Cop0::decodeInterp(Registers& regs, u32 instr) { void Cop0::decodeInterp(u32 instr) {
u8 mask_cop = (instr >> 21) & 0x1F; u8 mask_cop = (instr >> 21) & 0x1F;
u8 mask_cop2 = instr & 0x3F; u8 mask_cop2 = instr & 0x3F;
switch(mask_cop) { switch(mask_cop) {
case 0x00: mfc0(regs, instr); break; case 0x00: mfc0(instr); break;
case 0x01: dmfc0(regs, instr); break; case 0x01: dmfc0(instr); break;
case 0x04: mtc0(regs, instr); break; case 0x04: mtc0(instr); break;
case 0x05: dmtc0(regs, instr); break; case 0x05: dmtc0(instr); break;
case 0x10 ... 0x1F: case 0x10 ... 0x1F:
switch(mask_cop2) { switch(mask_cop2) {
case 0x01: tlbr(); break; case 0x01: tlbr(); break;
case 0x02: tlbw(index.i); break; case 0x02: tlbw(index.i); break;
case 0x06: tlbw(GetRandom()); break; case 0x06: tlbw(GetRandom()); break;
case 0x08: tlbp(regs); break; case 0x08: tlbp(); break;
case 0x18: eret(regs); break; case 0x18: eret(); break;
default: Util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, regs.oldPC); default: Util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, regs.oldPC);
} }
break; break;
@@ -361,23 +361,23 @@ void Cop0::decodeInterp(Registers& regs, u32 instr) {
} }
} }
bool MapVAddr(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) { bool Cop0::MapVAddr(TLBAccessType accessType, u64 vaddr, u32& paddr) {
if(regs.cop0.is_64bit_addressing) [[unlikely]] { if(regs.cop0.is64BitAddressing) [[unlikely]] {
if (regs.cop0.kernel_mode) [[likely]] { if (regs.cop0.kernelMode) [[likely]] {
return MapVAddr64(regs, accessType, vaddr, paddr); return MapVAddr64(accessType, vaddr, paddr);
} else if (regs.cop0.user_mode) { } else if (regs.cop0.userMode) {
return UserMapVAddr64(regs, accessType, vaddr, paddr); return UserMapVAddr64(accessType, vaddr, paddr);
} else if (regs.cop0.supervisor_mode) { } else if (regs.cop0.supervisorMode) {
Util::panic("Supervisor mode memory access, 64 bit mode"); Util::panic("Supervisor mode memory access, 64 bit mode");
} else { } else {
Util::panic("Unknown mode! This should never happen!"); Util::panic("Unknown mode! This should never happen!");
} }
} else { } else {
if (regs.cop0.kernel_mode) [[likely]] { if (regs.cop0.kernelMode) [[likely]] {
return MapVAddr32(regs, accessType, vaddr, paddr); return MapVAddr32(accessType, vaddr, paddr);
} else if (regs.cop0.user_mode) { } else if (regs.cop0.userMode) {
return UserMapVAddr32(regs, accessType, vaddr, paddr); return UserMapVAddr32(accessType, vaddr, paddr);
} else if (regs.cop0.supervisor_mode) { } else if (regs.cop0.supervisorMode) {
Util::panic("Supervisor mode memory access, 32 bit mode"); Util::panic("Supervisor mode memory access, 32 bit mode");
} else { } else {
Util::panic("Unknown mode! This should never happen!"); Util::panic("Unknown mode! This should never happen!");
@@ -385,20 +385,20 @@ bool MapVAddr(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr)
} }
} }
bool UserMapVAddr32(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) { bool Cop0::UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32& paddr) {
switch (vaddr) { switch (vaddr) {
case VREGION_KUSEG: case VREGION_KUSEG:
return ProbeTLB(regs, accessType, s64(s32(vaddr)), paddr, nullptr); return ProbeTLB(accessType, s64(s32(vaddr)), paddr, nullptr);
default: default:
regs.cop0.tlbError = DISALLOWED_ADDRESS; regs.cop0.tlbError = DISALLOWED_ADDRESS;
return false; return false;
} }
} }
bool MapVAddr32(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) { bool Cop0::MapVAddr32(TLBAccessType accessType, u64 vaddr, u32& paddr) {
switch((u32(vaddr) >> 29) & 7) { switch((u32(vaddr) >> 29) & 7) {
case 0 ... 3: case 7: case 0 ... 3: case 7:
return ProbeTLB(regs, accessType, s64(s32(vaddr)), paddr, nullptr); return ProbeTLB(accessType, s64(s32(vaddr)), paddr, nullptr);
case 4 ... 5: case 4 ... 5:
paddr = vaddr & 0x1FFFFFFF; paddr = vaddr & 0x1FFFFFFF;
return true; return true;
@@ -410,22 +410,22 @@ bool MapVAddr32(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr
return false; return false;
} }
bool UserMapVAddr64(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) { bool Cop0::UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32& paddr) {
switch (vaddr) { switch (vaddr) {
case VREGION_XKUSEG: case VREGION_XKUSEG:
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr); return ProbeTLB(accessType, vaddr, paddr, nullptr);
default: default:
regs.cop0.tlbError = DISALLOWED_ADDRESS; regs.cop0.tlbError = DISALLOWED_ADDRESS;
return false; return false;
} }
} }
bool MapVAddr64(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) { bool Cop0::MapVAddr64(TLBAccessType accessType, u64 vaddr, u32& paddr) {
switch (vaddr) { switch (vaddr) {
case VREGION_XKUSEG: case VREGION_XKSSEG: case VREGION_XKUSEG: case VREGION_XKSSEG:
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr); return ProbeTLB(accessType, vaddr, paddr, nullptr);
case VREGION_XKPHYS: { case VREGION_XKPHYS: {
if (!regs.cop0.kernel_mode) { if (!regs.cop0.kernelMode) {
Util::panic("Access to XKPHYS address 0x{:016X} when outside kernel mode!", vaddr); Util::panic("Access to XKPHYS address 0x{:016X} when outside kernel mode!", vaddr);
} }
u8 high_two_bits = (vaddr >> 62) & 0b11; u8 high_two_bits = (vaddr >> 62) & 0b11;
@@ -444,7 +444,7 @@ bool MapVAddr64(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr
return true; return true;
} }
case VREGION_XKSEG: case VREGION_XKSEG:
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr); return ProbeTLB(accessType, vaddr, paddr, nullptr);
case VREGION_CKSEG0: case VREGION_CKSEG0:
// Identical to kseg0 in 32 bit mode. // Identical to kseg0 in 32 bit mode.
// Unmapped translation. Subtract the base address of the space to get the physical address. // Unmapped translation. Subtract the base address of the space to get the physical address.
@@ -460,7 +460,7 @@ bool MapVAddr64(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr
case VREGION_CKSSEG: case VREGION_CKSSEG:
Util::panic("Resolving virtual address 0x{:016X} (VREGION_CKSSEG) in 64 bit mode", vaddr); Util::panic("Resolving virtual address 0x{:016X} (VREGION_CKSSEG) in 64 bit mode", vaddr);
case VREGION_CKSEG3: case VREGION_CKSEG3:
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr); return ProbeTLB(accessType, vaddr, paddr, nullptr);
case VREGION_XBAD1: case VREGION_XBAD1:
case VREGION_XBAD2: case VREGION_XBAD2:
case VREGION_XBAD3: case VREGION_XBAD3:

View File

@@ -189,8 +189,6 @@ enum class ExceptionCode : u8 {
Watch = 23 Watch = 23
}; };
void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc);
union Cop0Context { union Cop0Context {
u64 raw; u64 raw;
struct { struct {
@@ -211,7 +209,7 @@ union Cop0XContext {
}; };
struct Cop0 { struct Cop0 {
Cop0(); Cop0(Registers&);
u32 GetReg32(u8); u32 GetReg32(u8);
[[nodiscard]] u64 GetReg64(u8) const; [[nodiscard]] u64 GetReg64(u8) const;
@@ -221,10 +219,10 @@ struct Cop0 {
void Reset(); void Reset();
bool kernel_mode{true}; bool kernelMode{true};
bool supervisor_mode{false}; bool supervisorMode{false};
bool user_mode{false}; bool userMode{false};
bool is_64bit_addressing{false}; bool is64BitAddressing{false};
bool llbit{}; bool llbit{};
PageMask pageMask{}; PageMask pageMask{};
@@ -267,47 +265,45 @@ struct Cop0 {
FORCE_INLINE void Update() { FORCE_INLINE void Update() {
bool exception = status.exl || status.erl; bool exception = status.exl || status.erl;
kernel_mode = exception || status.ksu == 0; kernelMode = exception || status.ksu == 0;
supervisor_mode = !exception && status.ksu == 1; supervisorMode = !exception && status.ksu == 1;
user_mode = !exception && status.ksu == 2; userMode = !exception && status.ksu == 2;
is_64bit_addressing = is64BitAddressing =
(kernel_mode && status.kx) (kernelMode && status.kx)
|| (supervisor_mode && status.sx) || (supervisorMode && status.sx)
|| (user_mode && status.ux); || (userMode && status.ux);
} }
enum TLBAccessType {
LOAD, STORE
};
bool ProbeTLB(TLBAccessType access_type, u64 vaddr, u32& paddr, int* match);
void FireException(ExceptionCode code, int cop, s64 pc);
bool MapVAddr(TLBAccessType accessType, u64 vaddr, u32& paddr);
bool UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32& paddr);
bool MapVAddr32(TLBAccessType accessType, u64 vaddr, u32& paddr);
bool UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32& paddr);
bool MapVAddr64(TLBAccessType accessType, u64 vaddr, u32& paddr);
TLBEntry* TLBTryMatch(u64 vaddr, int* match);
void HandleTLBException(u64 vaddr);
ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType access_type);
private: private:
Registers& regs;
[[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; } [[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; }
[[nodiscard]] FORCE_INLINE u32 GetCount() const { return u32(u64(count >> 1)); } [[nodiscard]] FORCE_INLINE u32 GetCount() const { return u32(u64(count >> 1)); }
void decodeInterp(Registers&, u32); void decodeInterp(u32);
void decodeJIT(JIT&, u32); void decodeJIT(JIT&, u32);
void mtc0(Registers&, u32); void mtc0(u32);
void dmtc0(Registers&, u32); void dmtc0(u32);
void mfc0(Registers&, u32); void mfc0(u32);
void dmfc0(Registers&, u32) const; void dmfc0(u32) const;
void eret(Registers&); void eret();
void tlbr(); void tlbr();
void tlbw(int); void tlbw(int);
void tlbp(n64::Registers&); void tlbp();
}; };
struct Registers;
enum class ExceptionCode : u8;
enum TLBAccessType {
LOAD, STORE
};
bool ProbeTLB(Registers& regs, TLBAccessType access_type, u64 vaddr, u32& paddr, int* match);
bool MapVAddr(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr);
bool UserMapVAddr32(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr);
bool MapVAddr32(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr);
bool UserMapVAddr64(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr);
bool MapVAddr64(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr);
TLBEntry* TLBTryMatch(Registers& regs, u64 vaddr, int* match);
void HandleTLBException(Registers& regs, u64 vaddr);
ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType access_type);
} }

View File

@@ -89,7 +89,7 @@ struct JIT;
struct Registers; struct Registers;
struct Cop1 { struct Cop1 {
#define CheckFPUUsable_PreserveCause() do { if(!regs.cop0.status.cu1) { FireException(regs, ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); return; } } while(0) #define CheckFPUUsable_PreserveCause() do { if(!regs.cop0.status.cu1) { regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 1, regs.oldPC); return; } } while(0)
#define CheckFPUUsable() do { CheckFPUUsable_PreserveCause(); regs.cop1.fcr31.cause = 0; } while(0) #define CheckFPUUsable() do { CheckFPUUsable_PreserveCause(); regs.cop1.fcr31.cause = 0; } while(0)
Cop1(); Cop1();
u32 fcr0{}; u32 fcr0{};

View File

@@ -1,7 +1,7 @@
#include <core/registers/Registers.hpp> #include <core/registers/Registers.hpp>
namespace n64 { namespace n64 {
Registers::Registers() { Registers::Registers() : cop0(*this) {
Reset(); Reset();
} }

View File

@@ -3,23 +3,23 @@
#include <log.hpp> #include <log.hpp>
namespace n64 { namespace n64 {
void Cop0::mtc0(Registers& regs, u32 instr) { void Cop0::mtc0(u32 instr) {
SetReg32(RD(instr), regs.gpr[RT(instr)]); SetReg32(RD(instr), regs.gpr[RT(instr)]);
} }
void Cop0::dmtc0(Registers& regs, u32 instr) { void Cop0::dmtc0(u32 instr) {
SetReg64(RD(instr), regs.gpr[RT(instr)]); SetReg64(RD(instr), regs.gpr[RT(instr)]);
} }
void Cop0::mfc0(Registers& regs, u32 instr) { void Cop0::mfc0(u32 instr) {
regs.gpr[RT(instr)] = s32(GetReg32(RD(instr))); regs.gpr[RT(instr)] = s32(GetReg32(RD(instr)));
} }
void Cop0::dmfc0(Registers& regs, u32 instr) const { void Cop0::dmfc0(u32 instr) const {
regs.gpr[RT(instr)] = s64(GetReg64(RD(instr))); regs.gpr[RT(instr)] = s64(GetReg64(RD(instr)));
} }
void Cop0::eret(Registers& regs) { void Cop0::eret() {
if(status.erl) { if(status.erl) {
regs.SetPC64(ErrorEPC); regs.SetPC64(ErrorEPC);
status.erl = false; status.erl = false;
@@ -69,9 +69,9 @@ void Cop0::tlbw(int index_) {
tlb[index_].initialized = true; tlb[index_].initialized = true;
} }
void Cop0::tlbp(Registers& regs) { void Cop0::tlbp() {
int match = -1; int match = -1;
TLBEntry* entry = TLBTryMatch(regs, entryHi.raw, &match); TLBEntry* entry = TLBTryMatch(entryHi.raw, &match);
if(entry && match >= 0) { if(entry && match >= 0) {
index.raw = match; index.raw = match;
} else { } else {

View File

@@ -58,7 +58,7 @@ FORCE_INLINE bool FireFPUException(Registers& regs) {
FCR31& fcr31 = regs.cop1.fcr31; FCR31& fcr31 = regs.cop1.fcr31;
u32 enable = fcr31.enable | (1 << 5); u32 enable = fcr31.enable | (1 << 5);
if(fcr31.cause & enable) { if(fcr31.cause & enable) {
FireException(regs, ExceptionCode::FloatingPointError, 0, regs.oldPC); regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
return true; return true;
} }
@@ -982,9 +982,9 @@ void Cop1::lwc1Interp(Registers& regs, Mem& mem, u32 instr) {
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
u32 physical; u32 physical;
if(!MapVAddr(regs, LOAD, addr, physical)) { if(!regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) {
HandleTLBException(regs, addr); regs.cop0.HandleTLBException(addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
u32 data = mem.Read<u32>(regs, physical); u32 data = mem.Read<u32>(regs, physical);
FGR<u32>(regs.cop0.status, FT(instr)) = data; FGR<u32>(regs.cop0.status, FT(instr)) = data;
@@ -995,9 +995,9 @@ void Cop1::swc1Interp(Registers& regs, Mem& mem, u32 instr) {
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
u32 physical; u32 physical;
if(!MapVAddr(regs, STORE, addr, physical)) { if(!regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) {
HandleTLBException(regs, addr); regs.cop0.HandleTLBException(addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else { } else {
mem.Write<u32>(regs, physical, FGR<u32>(regs.cop0.status, FT(instr))); mem.Write<u32>(regs, physical, FGR<u32>(regs.cop0.status, FT(instr)));
} }
@@ -1013,9 +1013,9 @@ void Cop1::ldc1Interp(Registers& regs, Mem& mem, u32 instr) {
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
u32 physical; u32 physical;
if(!MapVAddr(regs, LOAD, addr, physical)) { if(!regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) {
HandleTLBException(regs, addr); regs.cop0.HandleTLBException(addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
} else { } else {
u64 data = mem.Read<u64>(regs, physical); u64 data = mem.Read<u64>(regs, physical);
FGR<u64>(regs.cop0.status, FT(instr)) = data; FGR<u64>(regs.cop0.status, FT(instr)) = data;
@@ -1026,9 +1026,9 @@ void Cop1::sdc1Interp(Registers& regs, Mem& mem, u32 instr) {
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)]; u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
u32 physical; u32 physical;
if(!MapVAddr(regs, STORE, addr, physical)) { if(!regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) {
HandleTLBException(regs, addr); regs.cop0.HandleTLBException(addr);
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC); regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
} else { } else {
mem.Write(regs, physical, FGR<u64>(regs.cop0.status, FT(instr))); mem.Write(regs, physical, FGR<u64>(regs.cop0.status, FT(instr)));
} }