CPU: Refactoring, implement LWC/SWC
This commit is contained in:
parent
2875a22987
commit
948ac50020
|
@ -283,6 +283,117 @@ void Core::WriteRegDelayed(Reg rd, u32 value)
|
|||
m_regs.r[static_cast<u8>(rd)] = value;
|
||||
}
|
||||
|
||||
u32 Core::ReadCop0Reg(Cop0Reg reg)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case Cop0Reg::BPC:
|
||||
return m_cop0_regs.BPC;
|
||||
|
||||
case Cop0Reg::BPCM:
|
||||
return m_cop0_regs.BPCM;
|
||||
|
||||
case Cop0Reg::BDA:
|
||||
return m_cop0_regs.BDA;
|
||||
|
||||
case Cop0Reg::BDAM:
|
||||
return m_cop0_regs.BDAM;
|
||||
|
||||
case Cop0Reg::DCIC:
|
||||
return m_cop0_regs.dcic.bits;
|
||||
|
||||
case Cop0Reg::JUMPDEST:
|
||||
return m_cop0_regs.JUMPDEST;
|
||||
|
||||
case Cop0Reg::BadVaddr:
|
||||
return m_cop0_regs.BadVaddr;
|
||||
|
||||
case Cop0Reg::SR:
|
||||
return m_cop0_regs.sr.bits;
|
||||
|
||||
case Cop0Reg::CAUSE:
|
||||
return m_cop0_regs.cause.bits;
|
||||
|
||||
case Cop0Reg::EPC:
|
||||
return m_cop0_regs.EPC;
|
||||
|
||||
case Cop0Reg::PRID:
|
||||
return m_cop0_regs.PRID;
|
||||
|
||||
default:
|
||||
Panic("Unknown COP0 reg");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Core::WriteCop0Reg(Cop0Reg reg, u32 value)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case Cop0Reg::BPC:
|
||||
{
|
||||
m_cop0_regs.BPC = value;
|
||||
Log_WarningPrintf("COP0 BPC <- %08X", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::BPCM:
|
||||
{
|
||||
m_cop0_regs.BPCM = value;
|
||||
Log_WarningPrintf("COP0 BPCM <- %08X", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::BDA:
|
||||
{
|
||||
m_cop0_regs.BDA = value;
|
||||
Log_WarningPrintf("COP0 BDA <- %08X", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::BDAM:
|
||||
{
|
||||
m_cop0_regs.BDAM = value;
|
||||
Log_WarningPrintf("COP0 BDAM <- %08X", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::JUMPDEST:
|
||||
{
|
||||
Log_WarningPrintf("Ignoring write to Cop0 JUMPDEST");
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::DCIC:
|
||||
{
|
||||
m_cop0_regs.dcic.bits =
|
||||
(m_cop0_regs.dcic.bits & ~Cop0Registers::DCIC::WRITE_MASK) | (value & Cop0Registers::DCIC::WRITE_MASK);
|
||||
Log_WarningPrintf("COP0 DCIC <- %08X (now %08X)", value, m_cop0_regs.dcic.bits);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::SR:
|
||||
{
|
||||
m_cop0_regs.sr.bits =
|
||||
(m_cop0_regs.sr.bits & ~Cop0Registers::SR::WRITE_MASK) | (value & Cop0Registers::SR::WRITE_MASK);
|
||||
Log_WarningPrintf("COP0 SR <- %08X (now %08X)", value, m_cop0_regs.sr.bits);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::CAUSE:
|
||||
{
|
||||
m_cop0_regs.cause.bits =
|
||||
(m_cop0_regs.cause.bits & ~Cop0Registers::CAUSE::WRITE_MASK) | (value & Cop0Registers::CAUSE::WRITE_MASK);
|
||||
Log_WarningPrintf("COP0 CAUSE <- %08X (now %08X)", value, m_cop0_regs.cause.bits);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Panic("Unknown COP0 reg");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Core::WriteCacheControl(u32 value)
|
||||
{
|
||||
Log_WarningPrintf("Cache control <- 0x%08X", value);
|
||||
|
@ -895,7 +1006,7 @@ void Core::ExecuteInstruction(Instruction inst)
|
|||
|
||||
case InstructionOp::cop0:
|
||||
{
|
||||
if (!m_cop0_regs.sr.CU0 && InUserMode())
|
||||
if (InUserMode() && !m_cop0_regs.sr.CU0)
|
||||
{
|
||||
Log_WarningPrintf("Coprocessor 0 not present in user mode");
|
||||
RaiseException(Exception::CpU, 0);
|
||||
|
@ -908,7 +1019,7 @@ void Core::ExecuteInstruction(Instruction inst)
|
|||
|
||||
case InstructionOp::cop2:
|
||||
{
|
||||
if (!m_cop0_regs.sr.CU0 && InUserMode())
|
||||
if (InUserMode() && !m_cop0_regs.sr.CU2)
|
||||
{
|
||||
Log_WarningPrintf("Coprocessor 2 not present in user mode");
|
||||
RaiseException(Exception::CpU, 2);
|
||||
|
@ -919,9 +1030,46 @@ void Core::ExecuteInstruction(Instruction inst)
|
|||
}
|
||||
break;
|
||||
|
||||
case InstructionOp::lwc2:
|
||||
{
|
||||
if (InUserMode() && !m_cop0_regs.sr.CU2)
|
||||
{
|
||||
Log_WarningPrintf("Coprocessor 2 not present in user mode");
|
||||
RaiseException(Exception::CpU, 2);
|
||||
return;
|
||||
}
|
||||
|
||||
const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32();
|
||||
u32 value;
|
||||
if (!ReadMemoryWord(addr, &value))
|
||||
return;
|
||||
|
||||
m_cop2.WriteDataRegister(ZeroExtend32(static_cast<u8>(inst.i.rt.GetValue())), value);
|
||||
}
|
||||
break;
|
||||
|
||||
case InstructionOp::swc2:
|
||||
{
|
||||
if (InUserMode() && !m_cop0_regs.sr.CU2)
|
||||
{
|
||||
Log_WarningPrintf("Coprocessor 2 not present in user mode");
|
||||
RaiseException(Exception::CpU, 2);
|
||||
return;
|
||||
}
|
||||
|
||||
const VirtualMemoryAddress addr = ReadReg(inst.i.rs) + inst.i.imm_sext32();
|
||||
const u32 value = m_cop2.ReadDataRegister(ZeroExtend32(static_cast<u8>(inst.i.rt.GetValue())));
|
||||
WriteMemoryWord(addr, value);
|
||||
}
|
||||
break;
|
||||
|
||||
// COP1/COP3 are not present
|
||||
case InstructionOp::cop1:
|
||||
case InstructionOp::cop3:
|
||||
case InstructionOp::lwc1:
|
||||
case InstructionOp::swc1:
|
||||
case InstructionOp::lwc3:
|
||||
case InstructionOp::swc3:
|
||||
{
|
||||
RaiseException(Exception::CpU, inst.cop.cop_n);
|
||||
}
|
||||
|
@ -935,137 +1083,27 @@ void Core::ExecuteInstruction(Instruction inst)
|
|||
|
||||
void Core::ExecuteCop0Instruction(Instruction inst)
|
||||
{
|
||||
switch (inst.cop.cop0_op())
|
||||
if (inst.cop.IsCommonInstruction())
|
||||
{
|
||||
case Cop0Instruction::mtc0:
|
||||
switch (inst.cop.CommonOp())
|
||||
{
|
||||
const u32 value = ReadReg(inst.r.rt);
|
||||
switch (static_cast<Cop0Reg>(inst.r.rd.GetValue()))
|
||||
{
|
||||
case Cop0Reg::BPC:
|
||||
{
|
||||
m_cop0_regs.BPC = value;
|
||||
Log_WarningPrintf("COP0 BPC <- %08X", value);
|
||||
}
|
||||
case CopCommonInstruction::mfcn:
|
||||
WriteRegDelayed(inst.r.rt, ReadCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue())));
|
||||
break;
|
||||
|
||||
case Cop0Reg::BPCM:
|
||||
{
|
||||
m_cop0_regs.BPCM = value;
|
||||
Log_WarningPrintf("COP0 BPCM <- %08X", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::BDA:
|
||||
{
|
||||
m_cop0_regs.BDA = value;
|
||||
Log_WarningPrintf("COP0 BDA <- %08X", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::BDAM:
|
||||
{
|
||||
m_cop0_regs.BDAM = value;
|
||||
Log_WarningPrintf("COP0 BDAM <- %08X", value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::JUMPDEST:
|
||||
{
|
||||
Log_WarningPrintf("Ignoring write to Cop0 JUMPDEST");
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::DCIC:
|
||||
{
|
||||
m_cop0_regs.dcic.bits =
|
||||
(m_cop0_regs.dcic.bits & ~Cop0Registers::DCIC::WRITE_MASK) | (value & Cop0Registers::DCIC::WRITE_MASK);
|
||||
Log_WarningPrintf("COP0 DCIC <- %08X (now %08X)", value, m_cop0_regs.dcic.bits);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::SR:
|
||||
{
|
||||
m_cop0_regs.sr.bits =
|
||||
(m_cop0_regs.sr.bits & ~Cop0Registers::SR::WRITE_MASK) | (value & Cop0Registers::SR::WRITE_MASK);
|
||||
Log_WarningPrintf("COP0 SR <- %08X (now %08X)", value, m_cop0_regs.sr.bits);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Reg::CAUSE:
|
||||
{
|
||||
m_cop0_regs.cause.bits =
|
||||
(m_cop0_regs.cause.bits & ~Cop0Registers::CAUSE::WRITE_MASK) | (value & Cop0Registers::CAUSE::WRITE_MASK);
|
||||
Log_WarningPrintf("COP0 CAUSE <- %08X (now %08X)", value, m_cop0_regs.cause.bits);
|
||||
}
|
||||
case CopCommonInstruction::mtcn:
|
||||
WriteCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue()), ReadReg(inst.r.rt));
|
||||
break;
|
||||
|
||||
default:
|
||||
Panic("Unknown COP0 reg");
|
||||
Panic("Missing implementation");
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Instruction::mfc0:
|
||||
else
|
||||
{
|
||||
u32 value;
|
||||
switch (static_cast<Cop0Reg>(inst.r.rd.GetValue()))
|
||||
switch (inst.cop.Cop0Op())
|
||||
{
|
||||
case Cop0Reg::BPC:
|
||||
value = m_cop0_regs.BPC;
|
||||
break;
|
||||
|
||||
case Cop0Reg::BPCM:
|
||||
value = m_cop0_regs.BPCM;
|
||||
break;
|
||||
|
||||
case Cop0Reg::BDA:
|
||||
value = m_cop0_regs.BDA;
|
||||
break;
|
||||
|
||||
case Cop0Reg::BDAM:
|
||||
value = m_cop0_regs.BDAM;
|
||||
break;
|
||||
|
||||
case Cop0Reg::DCIC:
|
||||
value = m_cop0_regs.dcic.bits;
|
||||
break;
|
||||
|
||||
case Cop0Reg::JUMPDEST:
|
||||
value = m_cop0_regs.JUMPDEST;
|
||||
break;
|
||||
|
||||
case Cop0Reg::BadVaddr:
|
||||
value = m_cop0_regs.BadVaddr;
|
||||
break;
|
||||
|
||||
case Cop0Reg::SR:
|
||||
value = m_cop0_regs.sr.bits;
|
||||
break;
|
||||
|
||||
case Cop0Reg::CAUSE:
|
||||
value = m_cop0_regs.cause.bits;
|
||||
break;
|
||||
|
||||
case Cop0Reg::EPC:
|
||||
value = m_cop0_regs.EPC;
|
||||
break;
|
||||
|
||||
case Cop0Reg::PRID:
|
||||
value = m_cop0_regs.PRID;
|
||||
break;
|
||||
|
||||
default:
|
||||
Panic("Unknown COP0 reg");
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
WriteRegDelayed(inst.r.rt, value);
|
||||
}
|
||||
break;
|
||||
|
||||
case Cop0Instruction::rfe:
|
||||
{
|
||||
// restore mode
|
||||
|
@ -1074,30 +1112,36 @@ void Core::ExecuteCop0Instruction(Instruction inst)
|
|||
break;
|
||||
|
||||
default:
|
||||
Panic("Unhandled instruction");
|
||||
Panic("Missing implementation");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Core::ExecuteCop2Instruction(Instruction inst)
|
||||
{
|
||||
if (inst.cop.IsCommonInstruction())
|
||||
{
|
||||
// TODO: Combine with cop0.
|
||||
switch (inst.cop.cop2_op())
|
||||
switch (inst.cop.CommonOp())
|
||||
{
|
||||
case Cop2Instruction::mfc2:
|
||||
case Cop2Instruction::cfc2:
|
||||
case Cop2Instruction::mtc2:
|
||||
case Cop2Instruction::ctc2:
|
||||
{
|
||||
const u32 index = static_cast<u32>(inst.r.rd.GetValue());
|
||||
const u32 value = ReadReg(inst.r.rt);
|
||||
m_cop2.WriteControlRegister(index, value);
|
||||
}
|
||||
case CopCommonInstruction::cfcn:
|
||||
WriteRegDelayed(inst.r.rt, m_cop2.ReadControlRegister(static_cast<u32>(inst.r.rd.GetValue())));
|
||||
break;
|
||||
|
||||
case Cop2Instruction::bc2c:
|
||||
case CopCommonInstruction::ctcn:
|
||||
m_cop2.WriteControlRegister(static_cast<u32>(inst.r.rd.GetValue()), ReadReg(inst.r.rt));
|
||||
break;
|
||||
|
||||
case CopCommonInstruction::mfcn:
|
||||
WriteRegDelayed(inst.r.rt, m_cop2.ReadDataRegister(static_cast<u32>(inst.r.rd.GetValue())));
|
||||
break;
|
||||
|
||||
case CopCommonInstruction::mtcn:
|
||||
m_cop2.WriteDataRegister(static_cast<u32>(inst.r.rd.GetValue()), ReadReg(inst.r.rt));
|
||||
break;
|
||||
|
||||
case CopCommonInstruction::bcnc:
|
||||
default:
|
||||
Panic("Missing implementation");
|
||||
break;
|
||||
|
|
|
@ -103,6 +103,10 @@ private:
|
|||
// write to cache control register
|
||||
void WriteCacheControl(u32 value);
|
||||
|
||||
// read/write cop0 regs
|
||||
u32 ReadCop0Reg(Cop0Reg reg);
|
||||
void WriteCop0Reg(Cop0Reg reg, u32 value);
|
||||
|
||||
Bus* m_bus = nullptr;
|
||||
|
||||
// ticks the CPU has executed
|
||||
|
|
|
@ -160,20 +160,14 @@ static const std::array<const char*, 64> s_special_table = {{
|
|||
"UNKNOWN" // 63
|
||||
}};
|
||||
|
||||
static const std::array<std::pair<Cop0Instruction, const char*>, 6> s_cop0_table = {
|
||||
{{Cop0Instruction::mfc0, "mfc0 $rt, $coprd"},
|
||||
{Cop0Instruction::cfc0, "cfc0 $rt, $copcr"},
|
||||
{Cop0Instruction::mtc0, "mtc0 $rt, $coprd"},
|
||||
{Cop0Instruction::ctc0, "ctc0 $rt, $copcr"},
|
||||
{Cop0Instruction::bc0c, "bc0$copcc $rel"},
|
||||
{Cop0Instruction::rfe, "rfe"}}};
|
||||
static const std::array<std::pair<CopCommonInstruction, const char*>, 5> s_cop_common_table = {
|
||||
{{CopCommonInstruction::mfcn, "mfc$cop $rt, $coprd"},
|
||||
{CopCommonInstruction::cfcn, "cfc$cop $rt, $copcr"},
|
||||
{CopCommonInstruction::mtcn, "mtc$cop $rt, $coprd"},
|
||||
{CopCommonInstruction::ctcn, "ctc$cop $rt, $copcr"},
|
||||
{CopCommonInstruction::bcnc, "bc$cop$copcc $rel"}}};
|
||||
|
||||
static const std::array<std::pair<Cop2Instruction, const char*>, 6> s_cop2_common_table = {
|
||||
{{Cop2Instruction::mfc2, "mfc2 $rt, $coprd"},
|
||||
{Cop2Instruction::cfc2, "cfc2 $rt, $copcr"},
|
||||
{Cop2Instruction::mtc2, "mtc2 $rt, $coprd"},
|
||||
{Cop2Instruction::ctc2, "ctc2 $rt, $copcr"},
|
||||
{Cop2Instruction::bc2c, "bc2$copcc $rel"}}};
|
||||
static const std::array<std::pair<Cop0Instruction, const char*>, 1> s_cop0_table = {{{Cop0Instruction::rfe, "rfe"}}};
|
||||
|
||||
static void FormatInstruction(String* dest, const Instruction inst, u32 pc, const char* format)
|
||||
{
|
||||
|
@ -286,26 +280,35 @@ void DisassembleInstruction(String* dest, u32 pc, u32 bits)
|
|||
return;
|
||||
|
||||
case InstructionOp::cop0:
|
||||
FormatCopInstruction(dest, pc, inst, s_cop0_table.data(), s_cop0_table.size(), inst.cop.cop0_op());
|
||||
return;
|
||||
|
||||
case InstructionOp::cop1:
|
||||
case InstructionOp::cop2:
|
||||
case InstructionOp::cop3:
|
||||
{
|
||||
if (inst.cop.IsCommonInstruction())
|
||||
{
|
||||
FormatCopInstruction(dest, pc, inst, s_cop2_common_table.data(), s_cop2_common_table.size(),
|
||||
inst.cop.cop2_op());
|
||||
FormatCopInstruction(dest, pc, inst, s_cop_common_table.data(), s_cop_common_table.size(), inst.cop.CommonOp());
|
||||
}
|
||||
else
|
||||
{
|
||||
dest->Format("<cop%u 0x%08X>", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue());
|
||||
}
|
||||
switch (inst.op)
|
||||
{
|
||||
case InstructionOp::cop0:
|
||||
{
|
||||
FormatCopInstruction(dest, pc, inst, s_cop0_table.data(), s_cop0_table.size(), inst.cop.Cop0Op());
|
||||
}
|
||||
break;
|
||||
|
||||
case InstructionOp::cop1:
|
||||
case InstructionOp::cop2:
|
||||
case InstructionOp::cop3:
|
||||
default:
|
||||
{
|
||||
dest->Format("<cop%u 0x%08X>", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// special case for bltz/bgez{al}
|
||||
|
|
|
@ -74,7 +74,15 @@ enum class InstructionOp : u8
|
|||
sh = 41,
|
||||
swl = 42,
|
||||
sw = 43,
|
||||
swr = 46
|
||||
swr = 46,
|
||||
lwc0 = 48,
|
||||
lwc1 = 49,
|
||||
lwc2 = 50,
|
||||
lwc3 = 51,
|
||||
swc0 = 56,
|
||||
swc1 = 57,
|
||||
swc2 = 58,
|
||||
swc3 = 59,
|
||||
};
|
||||
constexpr u8 INSTRUCTION_COP_BITS = 0x10;
|
||||
constexpr u8 INSTRUCTION_COP_MASK = 0x3C;
|
||||
|
@ -113,27 +121,22 @@ enum class InstructionFunct : u8
|
|||
sltu = 43
|
||||
};
|
||||
|
||||
enum class Cop0Instruction : u32 // 25:21 | 0:5
|
||||
enum class CopCommonInstruction : u32
|
||||
{
|
||||
mfc0 = 0b00000'000000,
|
||||
cfc0 = 0b00010'000000,
|
||||
mtc0 = 0b00100'000000,
|
||||
ctc0 = 0b00110'000000,
|
||||
bc0c = 0b01000'000000,
|
||||
tlbr = 0b10000'000001,
|
||||
tlbwi = 0b10000'000010,
|
||||
tlbwr = 0b10000'000100,
|
||||
tlbp = 0b10000'001000,
|
||||
rfe = 0b10000'010000,
|
||||
mfcn = 0b0000,
|
||||
cfcn = 0b0010,
|
||||
mtcn = 0b0100,
|
||||
ctcn = 0b0110,
|
||||
bcnc = 0b1000,
|
||||
};
|
||||
|
||||
enum class Cop2Instruction : u32 // 25:21
|
||||
enum class Cop0Instruction : u32
|
||||
{
|
||||
mfc2 = 0b0000,
|
||||
cfc2 = 0b0010,
|
||||
mtc2 = 0b0100,
|
||||
ctc2 = 0b0110,
|
||||
bc2c = 0b1000,
|
||||
tlbr = 0x01,
|
||||
tlbwi = 0x02,
|
||||
tlbwr = 0x04,
|
||||
tlbp = 0x08,
|
||||
rfe = 0x10,
|
||||
};
|
||||
|
||||
union Instruction
|
||||
|
@ -175,15 +178,9 @@ union Instruction
|
|||
|
||||
bool IsCommonInstruction() const { return (bits & (UINT32_C(1) << 25)) == 0; }
|
||||
|
||||
Cop0Instruction cop0_op() const
|
||||
{
|
||||
return static_cast<Cop0Instruction>(((bits >> 15) & UINT32_C(0b11111000000)) | (bits & UINT32_C(0b111111)));
|
||||
}
|
||||
CopCommonInstruction CommonOp() const { return static_cast<CopCommonInstruction>((bits >> 21) & UINT32_C(0b1111)); }
|
||||
|
||||
Cop2Instruction cop2_op() const
|
||||
{
|
||||
return static_cast<Cop2Instruction>((bits >> 21) & UINT32_C(0b1111));
|
||||
}
|
||||
Cop0Instruction Cop0Op() const { return static_cast<Cop0Instruction>(bits & UINT32_C(0x3F)); }
|
||||
} cop;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue