Refactor Cop0
This commit is contained in:
@@ -28,22 +28,22 @@ int Interpreter::Step() {
|
||||
regs.delaySlot = false;
|
||||
|
||||
if(check_address_error(0b11, u64(regs.pc))) [[unlikely]] {
|
||||
HandleTLBException(regs, regs.pc);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.pc);
|
||||
regs.cop0.HandleTLBException(regs.pc);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.pc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 paddr = 0;
|
||||
if(!MapVAddr(regs, LOAD, regs.pc, paddr)) {
|
||||
HandleTLBException(regs, regs.pc);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.pc);
|
||||
if(!regs.cop0.MapVAddr(Cop0::LOAD, regs.pc, paddr)) {
|
||||
regs.cop0.HandleTLBException(regs.pc);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.pc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 instruction = mem.Read<u32>(regs, paddr);
|
||||
|
||||
if(ShouldServiceInterrupt()) {
|
||||
FireException(regs, ExceptionCode::Interrupt, 0, regs.pc);
|
||||
regs.cop0.FireException(ExceptionCode::Interrupt, 0, regs.pc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ struct Interpreter : BaseCPU {
|
||||
private:
|
||||
u64 cop2Latch{};
|
||||
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;
|
||||
void CheckCompareInterrupt() override;
|
||||
std::vector<u8> Serialize() override;
|
||||
|
||||
@@ -19,8 +19,8 @@ void Interpreter::special(u32 instr) {
|
||||
case SRAV: srav(instr); break;
|
||||
case JR: jr(instr); break;
|
||||
case JALR: jalr(instr); break;
|
||||
case SYSCALL: FireException(regs, ExceptionCode::Syscall, 0, regs.oldPC); break;
|
||||
case BREAK: FireException(regs, ExceptionCode::Breakpoint, 0, regs.oldPC); break;
|
||||
case SYSCALL: regs.cop0.FireException(ExceptionCode::Syscall, 0, regs.oldPC); break;
|
||||
case BREAK: regs.cop0.FireException(ExceptionCode::Breakpoint, 0, regs.oldPC); break;
|
||||
case SYNC: break; // SYNC
|
||||
case MFHI: mfhi(instr); break;
|
||||
case MTHI: mthi(instr); break;
|
||||
@@ -93,7 +93,7 @@ void Interpreter::regimm(u32 instr) {
|
||||
|
||||
void Interpreter::cop2Decode(u32 instr) {
|
||||
if(!regs.cop0.status.cu2) {
|
||||
FireException(regs, ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
|
||||
regs.cop0.FireException(ExceptionCode::CoprocessorUnusable, 2, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
switch(RS(instr)) {
|
||||
@@ -104,7 +104,7 @@ void Interpreter::cop2Decode(u32 instr) {
|
||||
case 0x05: dmtc2(instr); break;
|
||||
case 0x06: ctc2(instr); break;
|
||||
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 LDL: ldl(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 LH: lh(instr); break;
|
||||
case LWL: lwl(instr); break;
|
||||
|
||||
@@ -9,7 +9,7 @@ void Interpreter::add(u32 instr) {
|
||||
u32 rt = (s32)regs.gpr[RT(instr)];
|
||||
u32 result = rs + rt;
|
||||
if(check_signed_overflow(rs, rt, result)) {
|
||||
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
} else {
|
||||
if (RD(instr) != 0) [[likely]] {
|
||||
regs.gpr[RD(instr)] = s32(result);
|
||||
@@ -31,7 +31,7 @@ void Interpreter::addi(u32 instr) {
|
||||
u32 imm = s32(s16(instr));
|
||||
u32 result = rs + imm;
|
||||
if(check_signed_overflow(rs, imm, result)) {
|
||||
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
} else {
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
regs.gpr[RT(instr)] = s32(result);
|
||||
@@ -53,7 +53,7 @@ void Interpreter::dadd(u32 instr) {
|
||||
u64 rt = regs.gpr[RT(instr)];
|
||||
u64 result = rt + rs;
|
||||
if(check_signed_overflow(rs, rt, result)) {
|
||||
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
} else {
|
||||
if (RD(instr) != 0) [[likely]] {
|
||||
regs.gpr[RD(instr)] = result;
|
||||
@@ -74,7 +74,7 @@ void Interpreter::daddi(u32 instr) {
|
||||
u64 rs = regs.gpr[RS(instr)];
|
||||
u64 result = imm + rs;
|
||||
if(check_signed_overflow(rs, imm, result)) {
|
||||
FireException(regs, ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
} else {
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
regs.gpr[RT(instr)] = result;
|
||||
@@ -215,9 +215,9 @@ void Interpreter::lui(u32 instr) {
|
||||
void Interpreter::lb(u32 instr) {
|
||||
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
u32 paddr = 0;
|
||||
if(!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
regs.gpr[RT(instr)] = (s8) mem.Read<u8>(regs, paddr);
|
||||
@@ -228,15 +228,15 @@ void Interpreter::lb(u32 instr) {
|
||||
void Interpreter::lh(u32 instr) {
|
||||
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
if (check_address_error(0b1, address)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 paddr = 0;
|
||||
if(!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
regs.gpr[RT(instr)] = (s16) mem.Read<u16>(regs, paddr);
|
||||
@@ -248,15 +248,15 @@ void Interpreter::lw(u32 instr) {
|
||||
s16 offset = instr;
|
||||
u64 address = regs.gpr[RS(instr)] + offset;
|
||||
if (check_address_error(0b11, address)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 physical = 0;
|
||||
if (!MapVAddr(regs, LOAD, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, physical)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
if(RT(instr) != 0) [[likely]] {
|
||||
regs.gpr[RT(instr)] = (s32) mem.Read<u32>(regs, physical);
|
||||
@@ -267,13 +267,13 @@ void Interpreter::lw(u32 instr) {
|
||||
void Interpreter::ll(u32 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, regs.oldPC);
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, physical)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
s32 result = mem.Read<u32>(regs, physical);
|
||||
if (check_address_error(0b11, address)) {
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -289,9 +289,9 @@ void Interpreter::ll(u32 instr) {
|
||||
void Interpreter::lwl(u32 instr) {
|
||||
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
u32 paddr = 0;
|
||||
if(!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
u32 shift = 8 * ((address ^ 0) & 3);
|
||||
u32 mask = 0xFFFFFFFF << shift;
|
||||
@@ -306,9 +306,9 @@ void Interpreter::lwl(u32 instr) {
|
||||
void Interpreter::lwr(u32 instr) {
|
||||
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
u32 paddr = 0;
|
||||
if(!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
u32 shift = 8 * ((address ^ 3) & 3);
|
||||
u32 mask = 0xFFFFFFFF >> shift;
|
||||
@@ -323,15 +323,15 @@ void Interpreter::lwr(u32 instr) {
|
||||
void Interpreter::ld(u32 instr) {
|
||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
if (check_address_error(0b111, address)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 paddr = 0;
|
||||
if(!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
s64 value = mem.Read<u64>(regs, paddr);
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
@@ -341,19 +341,19 @@ void Interpreter::ld(u32 instr) {
|
||||
}
|
||||
|
||||
void Interpreter::lld(u32 instr) {
|
||||
if (!regs.cop0.is_64bit_addressing && !regs.cop0.kernel_mode) {
|
||||
FireException(regs, ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
|
||||
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||
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, regs.oldPC);
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
if (check_address_error(0b111, address)) {
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
} else {
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
regs.gpr[RT(instr)] = mem.Read<u64>(regs, paddr);
|
||||
@@ -367,9 +367,9 @@ void Interpreter::lld(u32 instr) {
|
||||
void Interpreter::ldl(u32 instr) {
|
||||
u64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
u32 paddr = 0;
|
||||
if (!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
s32 shift = 8 * ((address ^ 0) & 7);
|
||||
u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
|
||||
@@ -384,9 +384,9 @@ void Interpreter::ldl(u32 instr) {
|
||||
void Interpreter::ldr(u32 instr) {
|
||||
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, regs.oldPC);
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
s32 shift = 8 * ((address ^ 7) & 7);
|
||||
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
|
||||
@@ -401,9 +401,9 @@ void Interpreter::ldr(u32 instr) {
|
||||
void Interpreter::lbu(u32 instr) {
|
||||
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, regs.oldPC);
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
u8 value = mem.Read<u8>(regs, paddr);
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
@@ -415,14 +415,14 @@ void Interpreter::lbu(u32 instr) {
|
||||
void Interpreter::lhu(u32 instr) {
|
||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
if (check_address_error(0b1, address)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
u16 value = mem.Read<u16>(regs, paddr);
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
@@ -434,15 +434,15 @@ void Interpreter::lhu(u32 instr) {
|
||||
void Interpreter::lwu(u32 instr) {
|
||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
if (check_address_error(0b11, address)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorLoad, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 paddr;
|
||||
if (!MapVAddr(regs, LOAD, address, paddr)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
u32 value = mem.Read<u32>(regs, paddr);
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
@@ -454,9 +454,9 @@ void Interpreter::lwu(u32 instr) {
|
||||
void Interpreter::sb(u32 instr) {
|
||||
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, regs.oldPC);
|
||||
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||
} else {
|
||||
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;
|
||||
|
||||
if (check_address_error(0b11, address)) {
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
if(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, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||
} else {
|
||||
mem.Write<u32>(regs, paddr, regs.gpr[RT(instr)]);
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
@@ -490,24 +490,24 @@ void Interpreter::sc(u32 instr) {
|
||||
}
|
||||
|
||||
void Interpreter::scd(u32 instr) {
|
||||
if (!regs.cop0.is_64bit_addressing && !regs.cop0.kernel_mode) {
|
||||
FireException(regs, ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||
if (!regs.cop0.is64BitAddressing && !regs.cop0.kernelMode) {
|
||||
regs.cop0.FireException(ExceptionCode::ReservedInstruction, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
if (check_address_error(0b111, address)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
if(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, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||
} else {
|
||||
mem.Write<u32>(regs, paddr, regs.gpr[RT(instr)]);
|
||||
if (RT(instr) != 0) [[likely]] {
|
||||
@@ -525,9 +525,9 @@ void Interpreter::sh(u32 instr) {
|
||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, STORE, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||
} else {
|
||||
mem.Write<u16>(regs, physical, regs.gpr[RT(instr)]);
|
||||
}
|
||||
@@ -537,15 +537,15 @@ void Interpreter::sw(u32 instr) {
|
||||
s16 offset = instr;
|
||||
u64 address = regs.gpr[RS(instr)] + offset;
|
||||
if (check_address_error(0b11, address)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, STORE, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||
} else {
|
||||
mem.Write<u32>(regs, physical, regs.gpr[RT(instr)]);
|
||||
}
|
||||
@@ -554,15 +554,15 @@ void Interpreter::sw(u32 instr) {
|
||||
void Interpreter::sd(u32 instr) {
|
||||
s64 address = regs.gpr[RS(instr)] + (s16)instr;
|
||||
if (check_address_error(0b111, address)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(ExceptionCode::AddressErrorStore, 0, regs.oldPC);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, STORE, address, physical)) {
|
||||
HandleTLBException(regs, address);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::STORE, address, physical)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||
} else {
|
||||
mem.Write(regs, physical, regs.gpr[RT(instr)]);
|
||||
}
|
||||
@@ -571,9 +571,9 @@ void Interpreter::sd(u32 instr) {
|
||||
void Interpreter::sdl(u32 instr) {
|
||||
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, regs.oldPC);
|
||||
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||
} else {
|
||||
s32 shift = 8 * ((address ^ 0) & 7);
|
||||
u64 mask = 0xFFFFFFFFFFFFFFFF >> shift;
|
||||
@@ -586,9 +586,9 @@ void Interpreter::sdl(u32 instr) {
|
||||
void Interpreter::sdr(u32 instr) {
|
||||
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, regs.oldPC);
|
||||
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||
} else {
|
||||
s32 shift = 8 * ((address ^ 7) & 7);
|
||||
u64 mask = 0xFFFFFFFFFFFFFFFF << shift;
|
||||
@@ -601,9 +601,9 @@ void Interpreter::sdr(u32 instr) {
|
||||
void Interpreter::swl(u32 instr) {
|
||||
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, regs.oldPC);
|
||||
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||
} else {
|
||||
u32 shift = 8 * ((address ^ 0) & 3);
|
||||
u32 mask = 0xFFFFFFFF >> shift;
|
||||
@@ -616,9 +616,9 @@ void Interpreter::swl(u32 instr) {
|
||||
void Interpreter::swr(u32 instr) {
|
||||
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, regs.oldPC);
|
||||
if (!regs.cop0.MapVAddr(Cop0::STORE, address, paddr)) {
|
||||
regs.cop0.HandleTLBException(address);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||
} else {
|
||||
u32 shift = 8 * ((address ^ 3) & 3);
|
||||
u32 mask = 0xFFFFFFFF << shift;
|
||||
@@ -863,7 +863,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);
|
||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
} else {
|
||||
if (RD(instr) != 0) [[likely]] {
|
||||
regs.gpr[RD(instr)] = result;
|
||||
@@ -885,7 +885,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);
|
||||
regs.cop0.FireException(ExceptionCode::Overflow, 0, regs.oldPC);
|
||||
} else {
|
||||
if (RD(instr) != 0) [[likely]] {
|
||||
regs.gpr[RD(instr)] = result;
|
||||
@@ -956,7 +956,7 @@ void Interpreter::mthi(u32 instr) {
|
||||
|
||||
void Interpreter::trap(bool cond) {
|
||||
if(cond) {
|
||||
FireException(regs, ExceptionCode::Trap, 0, regs.oldPC);
|
||||
regs.cop0.FireException(ExceptionCode::Trap, 0, regs.oldPC);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ void PIF::MaybeLoadMempak() {
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE size_t getSaveSize(SaveType saveType) {
|
||||
FORCE_INLINE size_t GetSaveSize(SaveType saveType) {
|
||||
switch (saveType) {
|
||||
case SAVE_NONE:
|
||||
return 0;
|
||||
@@ -87,7 +87,7 @@ void PIF::LoadEeprom(SaveType saveType, const std::string& path) {
|
||||
eeprom.unmap();
|
||||
}
|
||||
|
||||
eepromSize = getSaveSize(saveType);
|
||||
eepromSize = GetSaveSize(saveType);
|
||||
FILE *f = fopen(eepromPath.c_str(), "rb");
|
||||
if (!f) {
|
||||
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;
|
||||
for (int i = 0; i <= 32; i++) {
|
||||
for (int j = 7; j >= 0; j--) {
|
||||
u8 xor_val = ((crc & 0x80) != 0) ? 0x85 : 0x00;
|
||||
u8 xorVal = ((crc & 0x80) != 0) ? 0x85 : 0x00;
|
||||
|
||||
crc <<= 1;
|
||||
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 &= ~0x1F;
|
||||
|
||||
switch (getAccessoryType()) {
|
||||
switch (GetAccessoryType()) {
|
||||
case ACCESSORY_NONE:
|
||||
break;
|
||||
case ACCESSORY_MEMPACK:
|
||||
@@ -274,7 +274,7 @@ void PIF::MempakRead(const u8* cmd, u8* res) {
|
||||
}
|
||||
|
||||
// CRC byte
|
||||
res[32] = data_crc(res);
|
||||
res[32] = DataCRC(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 &= ~0x1F;
|
||||
|
||||
switch (getAccessoryType()) {
|
||||
switch (GetAccessoryType()) {
|
||||
case ACCESSORY_NONE:
|
||||
break;
|
||||
case ACCESSORY_MEMPACK:
|
||||
@@ -299,14 +299,14 @@ void PIF::MempakWrite(u8* cmd, u8* res) {
|
||||
case ACCESSORY_RUMBLE_PACK: break;
|
||||
}
|
||||
// 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 {
|
||||
assert(mem.saveType == SAVE_EEPROM_4k || mem.saveType == SAVE_EEPROM_16k);
|
||||
if (channel == 4) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
if (channel == 4) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ struct PIF {
|
||||
ram[addr & PIF_RAM_DSIZE] = val;
|
||||
}
|
||||
|
||||
FORCE_INLINE AccessoryType getAccessoryType() const {
|
||||
FORCE_INLINE AccessoryType GetAccessoryType() const {
|
||||
if (channel >= 4 || joybusDevices[channel].type != JOYBUS_CONTROLLER) {
|
||||
return ACCESSORY_NONE;
|
||||
} else {
|
||||
|
||||
@@ -34,7 +34,5 @@ struct SI {
|
||||
PIF pif;
|
||||
};
|
||||
|
||||
// just to silence warning, it is used.
|
||||
[[maybe_unused]] static void DMA(Mem& mem, Registers& regs);
|
||||
#define SI_DMA_DELAY (65536 * 2)
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <core/Interpreter.hpp>
|
||||
|
||||
namespace n64 {
|
||||
Cop0::Cop0() {
|
||||
Cop0::Cop0(Registers& regs) : regs(regs) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ static FORCE_INLINE u64 getVPN(u64 addr, u64 pageMask) {
|
||||
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++) {
|
||||
TLBEntry *entry = ®s.cop0.tlb[i];
|
||||
if(entry->initialized) {
|
||||
@@ -198,8 +198,8 @@ TLBEntry* TLBTryMatch(Registers& regs, u64 vaddr, int* match) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ProbeTLB(Registers& regs, TLBAccessType access_type, u64 vaddr, u32& paddr, int* match) {
|
||||
TLBEntry* entry = TLBTryMatch(regs, vaddr, match);
|
||||
bool Cop0::ProbeTLB(TLBAccessType access_type, u64 vaddr, u32& paddr, int* match) {
|
||||
TLBEntry* entry = TLBTryMatch(vaddr, match);
|
||||
if(!entry) {
|
||||
regs.cop0.tlbError = MISS;
|
||||
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;
|
||||
|
||||
if(!regs.cop0.status.exl) {
|
||||
@@ -294,7 +294,7 @@ void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc) {
|
||||
regs.cop0.Update();
|
||||
}
|
||||
|
||||
void HandleTLBException(Registers& regs, u64 vaddr) {
|
||||
void Cop0::HandleTLBException(u64 vaddr) {
|
||||
u64 vpn2 = (vaddr >> 13) & 0x7FFFF;
|
||||
u64 xvpn2 = (vaddr >> 13) & 0x7FFFFFF;
|
||||
regs.cop0.badVaddr = vaddr;
|
||||
@@ -305,7 +305,7 @@ void HandleTLBException(Registers& regs, u64 vaddr) {
|
||||
regs.cop0.entryHi.r = (vaddr >> 62) & 3;
|
||||
}
|
||||
|
||||
ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType) {
|
||||
ExceptionCode Cop0::GetTLBExceptionCode(TLBError error, TLBAccessType accessType) {
|
||||
switch(error) {
|
||||
case NONE: Util::panic("Getting TLB exception with error NONE");
|
||||
case INVALID: case MISS:
|
||||
@@ -324,7 +324,7 @@ ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType) {
|
||||
template<class T>
|
||||
void Cop0::decode(T& cpu, u32 instr) {
|
||||
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&>) {
|
||||
decodeJIT(cpu, instr);
|
||||
} 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_cop2 = instr & 0x3F;
|
||||
switch(mask_cop) {
|
||||
case 0x00: mfc0(regs, instr); break;
|
||||
case 0x01: dmfc0(regs, instr); break;
|
||||
case 0x04: mtc0(regs, instr); break;
|
||||
case 0x05: dmtc0(regs, instr); break;
|
||||
case 0x00: mfc0(instr); break;
|
||||
case 0x01: dmfc0(instr); break;
|
||||
case 0x04: mtc0(instr); break;
|
||||
case 0x05: dmtc0(instr); break;
|
||||
case 0x10 ... 0x1F:
|
||||
switch(mask_cop2) {
|
||||
case 0x01: tlbr(); break;
|
||||
case 0x02: tlbw(index.i); break;
|
||||
case 0x06: tlbw(GetRandom()); break;
|
||||
case 0x08: tlbp(regs); break;
|
||||
case 0x18: eret(regs); break;
|
||||
case 0x08: tlbp(); break;
|
||||
case 0x18: eret(); break;
|
||||
default: Util::panic("Unimplemented COP0 function {} {} ({:08X}) ({:016lX})", mask_cop2 >> 3, mask_cop2 & 7, instr, regs.oldPC);
|
||||
}
|
||||
break;
|
||||
@@ -361,23 +361,23 @@ void Cop0::decodeInterp(Registers& regs, u32 instr) {
|
||||
}
|
||||
}
|
||||
|
||||
bool MapVAddr(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) {
|
||||
if(regs.cop0.is_64bit_addressing) [[unlikely]] {
|
||||
if (regs.cop0.kernel_mode) [[likely]] {
|
||||
return MapVAddr64(regs, accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.user_mode) {
|
||||
return UserMapVAddr64(regs, accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.supervisor_mode) {
|
||||
bool Cop0::MapVAddr(TLBAccessType accessType, u64 vaddr, u32& paddr) {
|
||||
if(regs.cop0.is64BitAddressing) [[unlikely]] {
|
||||
if (regs.cop0.kernelMode) [[likely]] {
|
||||
return MapVAddr64(accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.userMode) {
|
||||
return UserMapVAddr64(accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.supervisorMode) {
|
||||
Util::panic("Supervisor mode memory access, 64 bit mode");
|
||||
} else {
|
||||
Util::panic("Unknown mode! This should never happen!");
|
||||
}
|
||||
} else {
|
||||
if (regs.cop0.kernel_mode) [[likely]] {
|
||||
return MapVAddr32(regs, accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.user_mode) {
|
||||
return UserMapVAddr32(regs, accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.supervisor_mode) {
|
||||
if (regs.cop0.kernelMode) [[likely]] {
|
||||
return MapVAddr32(accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.userMode) {
|
||||
return UserMapVAddr32(accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.supervisorMode) {
|
||||
Util::panic("Supervisor mode memory access, 32 bit mode");
|
||||
} else {
|
||||
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) {
|
||||
case VREGION_KUSEG:
|
||||
return ProbeTLB(regs, accessType, s64(s32(vaddr)), paddr, nullptr);
|
||||
return ProbeTLB(accessType, s64(s32(vaddr)), paddr, nullptr);
|
||||
default:
|
||||
regs.cop0.tlbError = DISALLOWED_ADDRESS;
|
||||
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) {
|
||||
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:
|
||||
paddr = vaddr & 0x1FFFFFFF;
|
||||
return true;
|
||||
@@ -410,22 +410,22 @@ bool MapVAddr32(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UserMapVAddr64(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) {
|
||||
bool Cop0::UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32& paddr) {
|
||||
switch (vaddr) {
|
||||
case VREGION_XKUSEG:
|
||||
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr);
|
||||
return ProbeTLB(accessType, vaddr, paddr, nullptr);
|
||||
default:
|
||||
regs.cop0.tlbError = DISALLOWED_ADDRESS;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MapVAddr64(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) {
|
||||
bool Cop0::MapVAddr64(TLBAccessType accessType, u64 vaddr, u32& paddr) {
|
||||
switch (vaddr) {
|
||||
case VREGION_XKUSEG: case VREGION_XKSSEG:
|
||||
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr);
|
||||
return ProbeTLB(accessType, vaddr, paddr, nullptr);
|
||||
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);
|
||||
}
|
||||
u8 high_two_bits = (vaddr >> 62) & 0b11;
|
||||
@@ -444,7 +444,7 @@ bool MapVAddr64(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr
|
||||
return true;
|
||||
}
|
||||
case VREGION_XKSEG:
|
||||
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr);
|
||||
return ProbeTLB(accessType, vaddr, paddr, nullptr);
|
||||
case VREGION_CKSEG0:
|
||||
// Identical to kseg0 in 32 bit mode.
|
||||
// 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:
|
||||
Util::panic("Resolving virtual address 0x{:016X} (VREGION_CKSSEG) in 64 bit mode", vaddr);
|
||||
case VREGION_CKSEG3:
|
||||
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr);
|
||||
return ProbeTLB(accessType, vaddr, paddr, nullptr);
|
||||
case VREGION_XBAD1:
|
||||
case VREGION_XBAD2:
|
||||
case VREGION_XBAD3:
|
||||
|
||||
@@ -189,8 +189,6 @@ enum class ExceptionCode : u8 {
|
||||
Watch = 23
|
||||
};
|
||||
|
||||
void FireException(Registers& regs, ExceptionCode code, int cop, s64 pc);
|
||||
|
||||
union Cop0Context {
|
||||
u64 raw;
|
||||
struct {
|
||||
@@ -211,7 +209,7 @@ union Cop0XContext {
|
||||
};
|
||||
|
||||
struct Cop0 {
|
||||
Cop0();
|
||||
Cop0(Registers&);
|
||||
|
||||
u32 GetReg32(u8);
|
||||
[[nodiscard]] u64 GetReg64(u8) const;
|
||||
@@ -221,10 +219,10 @@ struct Cop0 {
|
||||
|
||||
void Reset();
|
||||
|
||||
bool kernel_mode{true};
|
||||
bool supervisor_mode{false};
|
||||
bool user_mode{false};
|
||||
bool is_64bit_addressing{false};
|
||||
bool kernelMode{true};
|
||||
bool supervisorMode{false};
|
||||
bool userMode{false};
|
||||
bool is64BitAddressing{false};
|
||||
bool llbit{};
|
||||
|
||||
PageMask pageMask{};
|
||||
@@ -267,47 +265,45 @@ struct Cop0 {
|
||||
FORCE_INLINE void Update() {
|
||||
bool exception = status.exl || status.erl;
|
||||
|
||||
kernel_mode = exception || status.ksu == 0;
|
||||
supervisor_mode = !exception && status.ksu == 1;
|
||||
user_mode = !exception && status.ksu == 2;
|
||||
is_64bit_addressing =
|
||||
(kernel_mode && status.kx)
|
||||
|| (supervisor_mode && status.sx)
|
||||
|| (user_mode && status.ux);
|
||||
kernelMode = exception || status.ksu == 0;
|
||||
supervisorMode = !exception && status.ksu == 1;
|
||||
userMode = !exception && status.ksu == 2;
|
||||
is64BitAddressing =
|
||||
(kernelMode && status.kx)
|
||||
|| (supervisorMode && status.sx)
|
||||
|| (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:
|
||||
Registers& regs;
|
||||
[[nodiscard]] FORCE_INLINE u32 GetWired() const { return wired & 0x3F; }
|
||||
[[nodiscard]] FORCE_INLINE u32 GetCount() const { return u32(u64(count >> 1)); }
|
||||
|
||||
void decodeInterp(Registers&, u32);
|
||||
void decodeInterp(u32);
|
||||
void decodeJIT(JIT&, u32);
|
||||
void mtc0(Registers&, u32);
|
||||
void dmtc0(Registers&, u32);
|
||||
void mfc0(Registers&, u32);
|
||||
void dmfc0(Registers&, u32) const;
|
||||
void eret(Registers&);
|
||||
void mtc0(u32);
|
||||
void dmtc0(u32);
|
||||
void mfc0(u32);
|
||||
void dmfc0(u32) const;
|
||||
void eret();
|
||||
|
||||
void tlbr();
|
||||
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);
|
||||
}
|
||||
@@ -89,7 +89,7 @@ struct JIT;
|
||||
struct Registers;
|
||||
|
||||
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)
|
||||
Cop1();
|
||||
u32 fcr0{};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <core/registers/Registers.hpp>
|
||||
|
||||
namespace n64 {
|
||||
Registers::Registers() {
|
||||
Registers::Registers() : cop0(*this) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -3,23 +3,23 @@
|
||||
#include <log.hpp>
|
||||
|
||||
namespace n64 {
|
||||
void Cop0::mtc0(Registers& regs, u32 instr) {
|
||||
void Cop0::mtc0(u32 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)]);
|
||||
}
|
||||
|
||||
void Cop0::mfc0(Registers& regs, u32 instr) {
|
||||
void Cop0::mfc0(u32 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)));
|
||||
}
|
||||
|
||||
void Cop0::eret(Registers& regs) {
|
||||
void Cop0::eret() {
|
||||
if(status.erl) {
|
||||
regs.SetPC64(ErrorEPC);
|
||||
status.erl = false;
|
||||
@@ -69,9 +69,9 @@ void Cop0::tlbw(int index_) {
|
||||
tlb[index_].initialized = true;
|
||||
}
|
||||
|
||||
void Cop0::tlbp(Registers& regs) {
|
||||
void Cop0::tlbp() {
|
||||
int match = -1;
|
||||
TLBEntry* entry = TLBTryMatch(regs, entryHi.raw, &match);
|
||||
TLBEntry* entry = TLBTryMatch(entryHi.raw, &match);
|
||||
if(entry && match >= 0) {
|
||||
index.raw = match;
|
||||
} else {
|
||||
|
||||
@@ -58,7 +58,7 @@ FORCE_INLINE bool FireFPUException(Registers& regs) {
|
||||
FCR31& fcr31 = regs.cop1.fcr31;
|
||||
u32 enable = fcr31.enable | (1 << 5);
|
||||
if(fcr31.cause & enable) {
|
||||
FireException(regs, ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
regs.cop0.FireException(ExceptionCode::FloatingPointError, 0, regs.oldPC);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -982,9 +982,9 @@ void Cop1::lwc1Interp(Registers& regs, Mem& mem, u32 instr) {
|
||||
u64 addr = (s64)(s16)instr + regs.gpr[BASE(instr)];
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, LOAD, addr, physical)) {
|
||||
HandleTLBException(regs, addr);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) {
|
||||
regs.cop0.HandleTLBException(addr);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
u32 data = mem.Read<u32>(regs, physical);
|
||||
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)];
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, STORE, addr, physical)) {
|
||||
HandleTLBException(regs, addr);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) {
|
||||
regs.cop0.HandleTLBException(addr);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||
} else {
|
||||
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)];
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, LOAD, addr, physical)) {
|
||||
HandleTLBException(regs, addr);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, LOAD), 0, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::LOAD, addr, physical)) {
|
||||
regs.cop0.HandleTLBException(addr);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::LOAD), 0, regs.oldPC);
|
||||
} else {
|
||||
u64 data = mem.Read<u64>(regs, physical);
|
||||
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)];
|
||||
|
||||
u32 physical;
|
||||
if(!MapVAddr(regs, STORE, addr, physical)) {
|
||||
HandleTLBException(regs, addr);
|
||||
FireException(regs, GetTLBExceptionCode(regs.cop0.tlbError, STORE), 0, regs.oldPC);
|
||||
if(!regs.cop0.MapVAddr(Cop0::STORE, addr, physical)) {
|
||||
regs.cop0.HandleTLBException(addr);
|
||||
regs.cop0.FireException(regs.cop0.GetTLBExceptionCode(regs.cop0.tlbError, Cop0::STORE), 0, regs.oldPC);
|
||||
} else {
|
||||
mem.Write(regs, physical, FGR<u64>(regs.cop0.status, FT(instr)));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user