CPU/Intepreter: Raise #RI on invalid COP0 move
This commit is contained in:
parent
62414b0c4c
commit
c6746e76f1
|
@ -48,9 +48,6 @@ static u32 ReadReg(Reg rs);
|
|||
static void WriteReg(Reg rd, u32 value);
|
||||
static void WriteRegDelayed(Reg rd, u32 value);
|
||||
|
||||
static u32 ReadCop0Reg(Cop0Reg reg);
|
||||
static void WriteCop0Reg(Cop0Reg reg, u32 value);
|
||||
|
||||
static void DispatchCop0Breakpoint();
|
||||
static bool IsCop0ExecutionBreakpointUnmasked();
|
||||
static void Cop0ExecutionBreakpointCheck();
|
||||
|
@ -494,123 +491,6 @@ ALWAYS_INLINE_RELEASE void CPU::WriteRegDelayed(Reg rd, u32 value)
|
|||
g_state.next_load_delay_value = value;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE_RELEASE u32 CPU::ReadCop0Reg(Cop0Reg reg)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case Cop0Reg::BPC:
|
||||
return g_state.cop0_regs.BPC;
|
||||
|
||||
case Cop0Reg::BPCM:
|
||||
return g_state.cop0_regs.BPCM;
|
||||
|
||||
case Cop0Reg::BDA:
|
||||
return g_state.cop0_regs.BDA;
|
||||
|
||||
case Cop0Reg::BDAM:
|
||||
return g_state.cop0_regs.BDAM;
|
||||
|
||||
case Cop0Reg::DCIC:
|
||||
return g_state.cop0_regs.dcic.bits;
|
||||
|
||||
case Cop0Reg::JUMPDEST:
|
||||
return g_state.cop0_regs.TAR;
|
||||
|
||||
case Cop0Reg::BadVaddr:
|
||||
return g_state.cop0_regs.BadVaddr;
|
||||
|
||||
case Cop0Reg::SR:
|
||||
return g_state.cop0_regs.sr.bits;
|
||||
|
||||
case Cop0Reg::CAUSE:
|
||||
return g_state.cop0_regs.cause.bits;
|
||||
|
||||
case Cop0Reg::EPC:
|
||||
return g_state.cop0_regs.EPC;
|
||||
|
||||
case Cop0Reg::PRID:
|
||||
return g_state.cop0_regs.PRID;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE_RELEASE void CPU::WriteCop0Reg(Cop0Reg reg, u32 value)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case Cop0Reg::BPC:
|
||||
{
|
||||
g_state.cop0_regs.BPC = value;
|
||||
DEV_LOG("COP0 BPC <- {:08X}", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::BPCM:
|
||||
{
|
||||
g_state.cop0_regs.BPCM = value;
|
||||
DEV_LOG("COP0 BPCM <- {:08X}", value);
|
||||
if (UpdateDebugDispatcherFlag())
|
||||
ExitExecution();
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::BDA:
|
||||
{
|
||||
g_state.cop0_regs.BDA = value;
|
||||
DEV_LOG("COP0 BDA <- {:08X}", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::BDAM:
|
||||
{
|
||||
g_state.cop0_regs.BDAM = value;
|
||||
DEV_LOG("COP0 BDAM <- {:08X}", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::JUMPDEST:
|
||||
{
|
||||
WARNING_LOG("Ignoring write to Cop0 JUMPDEST");
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::DCIC:
|
||||
{
|
||||
g_state.cop0_regs.dcic.bits =
|
||||
(g_state.cop0_regs.dcic.bits & ~Cop0Registers::DCIC::WRITE_MASK) | (value & Cop0Registers::DCIC::WRITE_MASK);
|
||||
DEV_LOG("COP0 DCIC <- {:08X} (now {:08X})", value, g_state.cop0_regs.dcic.bits);
|
||||
if (UpdateDebugDispatcherFlag())
|
||||
ExitExecution();
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::SR:
|
||||
{
|
||||
g_state.cop0_regs.sr.bits =
|
||||
(g_state.cop0_regs.sr.bits & ~Cop0Registers::SR::WRITE_MASK) | (value & Cop0Registers::SR::WRITE_MASK);
|
||||
DEBUG_LOG("COP0 SR <- {:08X} (now {:08X})", value, g_state.cop0_regs.sr.bits);
|
||||
UpdateMemoryPointers();
|
||||
CheckForPendingInterrupt();
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::CAUSE:
|
||||
{
|
||||
g_state.cop0_regs.cause.bits =
|
||||
(g_state.cop0_regs.cause.bits & ~Cop0Registers::CAUSE::WRITE_MASK) | (value & Cop0Registers::CAUSE::WRITE_MASK);
|
||||
DEBUG_LOG("COP0 CAUSE <- {:08X} (now {:08X})", value, g_state.cop0_regs.cause.bits);
|
||||
CheckForPendingInterrupt();
|
||||
}
|
||||
break;
|
||||
|
||||
[[unlikely]] default:
|
||||
DEV_LOG("Unknown COP0 reg write {} ({:08X})", static_cast<u8>(reg), value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE_RELEASE bool CPU::IsCop0ExecutionBreakpointUnmasked()
|
||||
{
|
||||
static constexpr const u32 code_address_ranges[][2] = {
|
||||
|
@ -1776,7 +1656,59 @@ restart_instruction:
|
|||
{
|
||||
case CopCommonInstruction::mfcn:
|
||||
{
|
||||
const u32 value = ReadCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue()));
|
||||
u32 value;
|
||||
|
||||
switch (static_cast<Cop0Reg>(inst.r.rd.GetValue()))
|
||||
{
|
||||
case Cop0Reg::BPC:
|
||||
value = g_state.cop0_regs.BPC;
|
||||
break;
|
||||
|
||||
case Cop0Reg::BPCM:
|
||||
value = g_state.cop0_regs.BPCM;
|
||||
break;
|
||||
|
||||
case Cop0Reg::BDA:
|
||||
value = g_state.cop0_regs.BDA;
|
||||
break;
|
||||
|
||||
case Cop0Reg::BDAM:
|
||||
value = g_state.cop0_regs.BDAM;
|
||||
break;
|
||||
|
||||
case Cop0Reg::DCIC:
|
||||
value = g_state.cop0_regs.dcic.bits;
|
||||
break;
|
||||
|
||||
case Cop0Reg::JUMPDEST:
|
||||
value = g_state.cop0_regs.TAR;
|
||||
break;
|
||||
|
||||
case Cop0Reg::BadVaddr:
|
||||
value = g_state.cop0_regs.BadVaddr;
|
||||
break;
|
||||
|
||||
case Cop0Reg::SR:
|
||||
value = g_state.cop0_regs.sr.bits;
|
||||
break;
|
||||
|
||||
case Cop0Reg::CAUSE:
|
||||
value = g_state.cop0_regs.cause.bits;
|
||||
break;
|
||||
|
||||
case Cop0Reg::EPC:
|
||||
value = g_state.cop0_regs.EPC;
|
||||
break;
|
||||
|
||||
case Cop0Reg::PRID:
|
||||
value = g_state.cop0_regs.PRID;
|
||||
break;
|
||||
|
||||
default:
|
||||
RaiseException(Exception::RI);
|
||||
return;
|
||||
}
|
||||
|
||||
WriteRegDelayed(inst.r.rt, value);
|
||||
|
||||
if constexpr (pgxp_mode == PGXPMode::CPU)
|
||||
|
@ -1786,11 +1718,86 @@ restart_instruction:
|
|||
|
||||
case CopCommonInstruction::mtcn:
|
||||
{
|
||||
const u32 rtVal = ReadReg(inst.r.rt);
|
||||
WriteCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue()), rtVal);
|
||||
u32 value = ReadReg(inst.r.rt);
|
||||
[[maybe_unused]] const u32 orig_value = value;
|
||||
|
||||
switch (static_cast<Cop0Reg>(inst.r.rd.GetValue()))
|
||||
{
|
||||
case Cop0Reg::BPC:
|
||||
{
|
||||
g_state.cop0_regs.BPC = value;
|
||||
DEV_LOG("COP0 BPC <- {:08X}", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::BPCM:
|
||||
{
|
||||
g_state.cop0_regs.BPCM = value;
|
||||
DEV_LOG("COP0 BPCM <- {:08X}", value);
|
||||
if (UpdateDebugDispatcherFlag())
|
||||
ExitExecution();
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::BDA:
|
||||
{
|
||||
g_state.cop0_regs.BDA = value;
|
||||
DEV_LOG("COP0 BDA <- {:08X}", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::BDAM:
|
||||
{
|
||||
g_state.cop0_regs.BDAM = value;
|
||||
DEV_LOG("COP0 BDAM <- {:08X}", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::JUMPDEST:
|
||||
{
|
||||
WARNING_LOG("Ignoring write to Cop0 JUMPDEST");
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::DCIC:
|
||||
{
|
||||
g_state.cop0_regs.dcic.bits = (g_state.cop0_regs.dcic.bits & ~Cop0Registers::DCIC::WRITE_MASK) |
|
||||
(value & Cop0Registers::DCIC::WRITE_MASK);
|
||||
DEV_LOG("COP0 DCIC <- {:08X} (now {:08X})", value, g_state.cop0_regs.dcic.bits);
|
||||
value = g_state.cop0_regs.dcic.bits;
|
||||
if (UpdateDebugDispatcherFlag())
|
||||
ExitExecution();
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::SR:
|
||||
{
|
||||
g_state.cop0_regs.sr.bits = (g_state.cop0_regs.sr.bits & ~Cop0Registers::SR::WRITE_MASK) |
|
||||
(value & Cop0Registers::SR::WRITE_MASK);
|
||||
DEBUG_LOG("COP0 SR <- {:08X} (now {:08X})", value, g_state.cop0_regs.sr.bits);
|
||||
value = g_state.cop0_regs.sr.bits;
|
||||
UpdateMemoryPointers();
|
||||
CheckForPendingInterrupt();
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::CAUSE:
|
||||
{
|
||||
g_state.cop0_regs.cause.bits = (g_state.cop0_regs.cause.bits & ~Cop0Registers::CAUSE::WRITE_MASK) |
|
||||
(value & Cop0Registers::CAUSE::WRITE_MASK);
|
||||
DEBUG_LOG("COP0 CAUSE <- {:08X} (now {:08X})", value, g_state.cop0_regs.cause.bits);
|
||||
value = g_state.cop0_regs.cause.bits;
|
||||
CheckForPendingInterrupt();
|
||||
}
|
||||
break;
|
||||
|
||||
[[unlikely]] default:
|
||||
RaiseException(Exception::RI);
|
||||
return;
|
||||
}
|
||||
|
||||
if constexpr (pgxp_mode == PGXPMode::CPU)
|
||||
PGXP::CPU_MTC0(inst, ReadCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue())), rtVal);
|
||||
PGXP::CPU_MTC0(inst, value, orig_value);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1818,7 +1825,7 @@ restart_instruction:
|
|||
case Cop0Instruction::tlbwr:
|
||||
case Cop0Instruction::tlbp:
|
||||
RaiseException(Exception::RI);
|
||||
break;
|
||||
return;
|
||||
|
||||
default:
|
||||
[[unlikely]] ERROR_LOG("Unhandled instruction at {:08X}: {:08X}", g_state.current_instruction_pc,
|
||||
|
|
Loading…
Reference in New Issue