From 948ac500209a43dce7b8dafdae28284efc629237 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sun, 22 Sep 2019 02:06:47 +1000 Subject: [PATCH] CPU: Refactoring, implement LWC/SWC --- src/pse/cpu_core.cpp | 344 +++++++++++++++++++++++------------------ src/pse/cpu_core.h | 4 + src/pse/cpu_disasm.cpp | 51 +++--- src/pse/cpu_types.h | 49 +++--- 4 files changed, 248 insertions(+), 200 deletions(-) diff --git a/src/pse/cpu_core.cpp b/src/pse/cpu_core.cpp index c67682f5e..d40ad9231 100644 --- a/src/pse/cpu_core.cpp +++ b/src/pse/cpu_core.cpp @@ -283,6 +283,117 @@ void Core::WriteRegDelayed(Reg rd, u32 value) m_regs.r[static_cast(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(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(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,147 +1083,38 @@ 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(inst.r.rd.GetValue())) + case CopCommonInstruction::mfcn: + WriteRegDelayed(inst.r.rt, ReadCop0Reg(static_cast(inst.r.rd.GetValue()))); + break; + + case CopCommonInstruction::mtcn: + WriteCop0Reg(static_cast(inst.r.rd.GetValue()), ReadReg(inst.r.rt)); + break; + + default: + Panic("Missing implementation"); + break; + } + } + else + { + switch (inst.cop.Cop0Op()) + { + case Cop0Instruction::rfe: { - 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; + // restore mode + m_cop0_regs.sr.mode_bits = (m_cop0_regs.sr.mode_bits & UINT32_C(0b110000)) | (m_cop0_regs.sr.mode_bits >> 2); } - } - break; - - case Cop0Instruction::mfc0: - { - u32 value; - switch (static_cast(inst.r.rd.GetValue())) - { - 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 - m_cop0_regs.sr.mode_bits = (m_cop0_regs.sr.mode_bits & UINT32_C(0b110000)) | (m_cop0_regs.sr.mode_bits >> 2); - } - break; - - default: - Panic("Unhandled instruction"); break; + + default: + Panic("Missing implementation"); + break; + } } } @@ -1084,20 +1123,25 @@ 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(inst.r.rd.GetValue()); - const u32 value = ReadReg(inst.r.rt); - m_cop2.WriteControlRegister(index, value); - } - break; + case CopCommonInstruction::cfcn: + WriteRegDelayed(inst.r.rt, m_cop2.ReadControlRegister(static_cast(inst.r.rd.GetValue()))); + break; - case Cop2Instruction::bc2c: + case CopCommonInstruction::ctcn: + m_cop2.WriteControlRegister(static_cast(inst.r.rd.GetValue()), ReadReg(inst.r.rt)); + break; + + case CopCommonInstruction::mfcn: + WriteRegDelayed(inst.r.rt, m_cop2.ReadDataRegister(static_cast(inst.r.rd.GetValue()))); + break; + + case CopCommonInstruction::mtcn: + m_cop2.WriteDataRegister(static_cast(inst.r.rd.GetValue()), ReadReg(inst.r.rt)); + break; + + case CopCommonInstruction::bcnc: default: Panic("Missing implementation"); break; diff --git a/src/pse/cpu_core.h b/src/pse/cpu_core.h index 818e00abd..6c24d2376 100644 --- a/src/pse/cpu_core.h +++ b/src/pse/cpu_core.h @@ -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 diff --git a/src/pse/cpu_disasm.cpp b/src/pse/cpu_disasm.cpp index 8b2948d58..322b316c7 100644 --- a/src/pse/cpu_disasm.cpp +++ b/src/pse/cpu_disasm.cpp @@ -160,20 +160,14 @@ static const std::array s_special_table = {{ "UNKNOWN" // 63 }}; -static const std::array, 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, 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, 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, 1> s_cop0_table = {{{Cop0Instruction::rfe, "rfe"}}}; static void FormatInstruction(String* dest, const Instruction inst, u32 pc, const char* format) { @@ -286,28 +280,37 @@ 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("", 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("", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue()); + } + break; + } } } break; - case InstructionOp::cop1: - case InstructionOp::cop3: - dest->Format("", ZeroExtend32(inst.cop.cop_n.GetValue()), inst.cop.imm25.GetValue()); - break; - // special case for bltz/bgez{al} case InstructionOp::b: { diff --git a/src/pse/cpu_types.h b/src/pse/cpu_types.h index 5380563d4..65675dced 100644 --- a/src/pse/cpu_types.h +++ b/src/pse/cpu_types.h @@ -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(((bits >> 15) & UINT32_C(0b11111000000)) | (bits & UINT32_C(0b111111))); - } + CopCommonInstruction CommonOp() const { return static_cast((bits >> 21) & UINT32_C(0b1111)); } - Cop2Instruction cop2_op() const - { - return static_cast((bits >> 21) & UINT32_C(0b1111)); - } + Cop0Instruction Cop0Op() const { return static_cast(bits & UINT32_C(0x3F)); } } cop; };