Refactor Cop0
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
@@ -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 = ®s.cop0.tlb[i];
|
TLBEntry *entry = ®s.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:
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
@@ -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{};
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user