diff --git a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp index 52a6239485..d85f8ece18 100644 --- a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp +++ b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp @@ -270,7 +270,7 @@ void CachedInterpreter::Jit(u32 address) { PPCAnalyst::CodeOp& op = m_code_buffer[i]; - js.downcountAmount += op.opinfo->numCycles; + js.downcountAmount += op.opinfo->num_cycles; if (op.opinfo->flags & FL_LOADSTORE) ++js.numLoadStoreInst; if (op.opinfo->flags & FL_USE_FPU) @@ -301,7 +301,7 @@ void CachedInterpreter::Jit(u32 address) js.firstFPInstructionFound = true; } - m_code.emplace_back(PPCTables::GetInterpreterOp(op.inst), op.inst); + m_code.emplace_back(Interpreter::GetInterpreterOp(op.inst), op.inst); if (memcheck) m_code.emplace_back(CheckDSI, js.downcountAmount); if (check_program_exception) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index 7f91883bb1..a1e60da662 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -34,14 +34,6 @@ u32 last_pc; bool Interpreter::m_end_block; -// function tables -std::array Interpreter::m_op_table; -std::array Interpreter::m_op_table4; -std::array Interpreter::m_op_table19; -std::array Interpreter::m_op_table31; -std::array Interpreter::m_op_table59; -std::array Interpreter::m_op_table63; - namespace { // Determines whether or not the given instruction is one where its execution @@ -79,30 +71,8 @@ void UpdatePC() } } // Anonymous namespace -void Interpreter::RunTable4(UGeckoInstruction inst) -{ - m_op_table4[inst.SUBOP10](inst); -} -void Interpreter::RunTable19(UGeckoInstruction inst) -{ - m_op_table19[inst.SUBOP10](inst); -} -void Interpreter::RunTable31(UGeckoInstruction inst) -{ - m_op_table31[inst.SUBOP10](inst); -} -void Interpreter::RunTable59(UGeckoInstruction inst) -{ - m_op_table59[inst.SUBOP5](inst); -} -void Interpreter::RunTable63(UGeckoInstruction inst) -{ - m_op_table63[inst.SUBOP10](inst); -} - void Interpreter::Init() { - InitializeInstructionTables(); m_end_block = false; } @@ -150,7 +120,7 @@ int Interpreter::SingleStepInner() if (HandleFunctionHooking(PowerPC::ppcState.pc)) { UpdatePC(); - return PPCTables::GetOpInfo(m_prev_inst)->numCycles; + return PPCTables::GetOpInfo(m_prev_inst)->num_cycles; } PowerPC::ppcState.npc = PowerPC::ppcState.pc + sizeof(UGeckoInstruction); @@ -181,7 +151,7 @@ int Interpreter::SingleStepInner() } else if (PowerPC::ppcState.msr.FP) { - m_op_table[m_prev_inst.OPCD](m_prev_inst); + RunInterpreterOp(m_prev_inst); if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0) { CheckExceptions(); @@ -197,7 +167,7 @@ int Interpreter::SingleStepInner() } else { - m_op_table[m_prev_inst.OPCD](m_prev_inst); + RunInterpreterOp(m_prev_inst); if ((PowerPC::ppcState.Exceptions & EXCEPTION_DSI) != 0) { CheckExceptions(); @@ -214,9 +184,9 @@ int Interpreter::SingleStepInner() UpdatePC(); const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(m_prev_inst); - PowerPC::UpdatePerformanceMonitor(opinfo->numCycles, (opinfo->flags & FL_LOADSTORE) != 0, + PowerPC::UpdatePerformanceMonitor(opinfo->num_cycles, (opinfo->flags & FL_LOADSTORE) != 0, (opinfo->flags & FL_USE_FPU) != 0, PowerPC::ppcState); - return opinfo->numCycles; + return opinfo->num_cycles; } void Interpreter::SingleStep() diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter.h index 2f7d5906d9..0dd01fa3c7 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.h @@ -262,12 +262,9 @@ public: static void isync(UGeckoInstruction inst); using Instruction = void (*)(UGeckoInstruction inst); - static std::array m_op_table; - static std::array m_op_table4; - static std::array m_op_table19; - static std::array m_op_table31; - static std::array m_op_table59; - static std::array m_op_table63; + + static Instruction GetInterpreterOp(UGeckoInstruction inst); + static void RunInterpreterOp(UGeckoInstruction inst); // singleton static Interpreter* getInstance(); @@ -283,8 +280,6 @@ public: private: void CheckExceptions(); - static void InitializeInstructionTables(); - static bool HandleFunctionHooking(u32 address); // flag helper diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp index 8b14bb4b1e..f85c5570e9 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Tables.cpp @@ -5,492 +5,492 @@ #include +#include "Common/Assert.h" +#include "Common/TypeUtils.h" #include "Core/PowerPC/Gekko.h" -#include "Core/PowerPC/PPCTables.h" namespace { -struct GekkoOPTemplate +struct InterpreterOpTemplate { - int opcode; - Interpreter::Instruction Inst; - GekkoOPInfo opinfo; + u32 opcode; + Interpreter::Instruction fn; }; } // namespace -// clang-format off -static GekkoOPInfo unknownopinfo = { "unknown_instruction", OpType::Unknown, FL_ENDBLOCK, 0, 0, 0, 0 }; +constexpr std::array s_primary_table{{ + {4, Interpreter::RunTable4}, // RunTable4 + {19, Interpreter::RunTable19}, // RunTable19 + {31, Interpreter::RunTable31}, // RunTable31 + {59, Interpreter::RunTable59}, // RunTable59 + {63, Interpreter::RunTable63}, // RunTable63 -static std::array primarytable = -{{ - {4, Interpreter::RunTable4, {"RunTable4", OpType::Subtable, 0, 0, 0, 0, 0}}, - {19, Interpreter::RunTable19, {"RunTable19", OpType::Subtable, 0, 0, 0, 0, 0}}, - {31, Interpreter::RunTable31, {"RunTable31", OpType::Subtable, 0, 0, 0, 0, 0}}, - {59, Interpreter::RunTable59, {"RunTable59", OpType::Subtable, 0, 0, 0, 0, 0}}, - {63, Interpreter::RunTable63, {"RunTable63", OpType::Subtable, 0, 0, 0, 0, 0}}, + {16, Interpreter::bcx}, // bcx + {18, Interpreter::bx}, // bx - {16, Interpreter::bcx, {"bcx", OpType::Branch, FL_ENDBLOCK | FL_READ_CR_BI, 1, 0, 0, 0}}, - {18, Interpreter::bx, {"bx", OpType::Branch, FL_ENDBLOCK, 1, 0, 0, 0}}, + {3, Interpreter::twi}, // twi + {17, Interpreter::sc}, // sc - {3, Interpreter::twi, {"twi", OpType::System, FL_IN_A | FL_ENDBLOCK, 1, 0, 0, 0}}, - {17, Interpreter::sc, {"sc", OpType::System, FL_ENDBLOCK, 2, 0, 0, 0}}, + {7, Interpreter::mulli}, // mulli + {8, Interpreter::subfic}, // subfic + {10, Interpreter::cmpli}, // cmpli + {11, Interpreter::cmpi}, // cmpi + {12, Interpreter::addic}, // addic + {13, Interpreter::addic_rc}, // addic_rc + {14, Interpreter::addi}, // addi + {15, Interpreter::addis}, // addis - {7, Interpreter::mulli, {"mulli", OpType::Integer, FL_OUT_D | FL_IN_A, 3, 0, 0, 0}}, - {8, Interpreter::subfic, {"subfic", OpType::Integer, FL_OUT_D | FL_IN_A | FL_SET_CA, 1, 0, 0, 0}}, - {10, Interpreter::cmpli, {"cmpli", OpType::Integer, FL_IN_A | FL_SET_CRn, 1, 0, 0, 0}}, - {11, Interpreter::cmpi, {"cmpi", OpType::Integer, FL_IN_A | FL_SET_CRn, 1, 0, 0, 0}}, - {12, Interpreter::addic, {"addic", OpType::Integer, FL_OUT_D | FL_IN_A | FL_SET_CA, 1, 0, 0, 0}}, - {13, Interpreter::addic_rc, {"addic_rc", OpType::Integer, FL_OUT_D | FL_IN_A | FL_SET_CA | FL_SET_CR0, 1, 0, 0, 0}}, - {14, Interpreter::addi, {"addi", OpType::Integer, FL_OUT_D | FL_IN_A0, 1, 0, 0, 0}}, - {15, Interpreter::addis, {"addis", OpType::Integer, FL_OUT_D | FL_IN_A0, 1, 0, 0, 0}}, + {20, Interpreter::rlwimix}, // rlwimix + {21, Interpreter::rlwinmx}, // rlwinmx + {23, Interpreter::rlwnmx}, // rlwnmx - {20, Interpreter::rlwimix, {"rlwimix", OpType::Integer, FL_OUT_A | FL_IN_A | FL_IN_S | FL_RC_BIT, 1, 0, 0, 0}}, - {21, Interpreter::rlwinmx, {"rlwinmx", OpType::Integer, FL_OUT_A | FL_IN_S | FL_RC_BIT, 1, 0, 0, 0}}, - {23, Interpreter::rlwnmx, {"rlwnmx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}}, + {24, Interpreter::ori}, // ori + {25, Interpreter::oris}, // oris + {26, Interpreter::xori}, // xori + {27, Interpreter::xoris}, // xoris + {28, Interpreter::andi_rc}, // andi_rc + {29, Interpreter::andis_rc}, // andis_rc - {24, Interpreter::ori, {"ori", OpType::Integer, FL_OUT_A | FL_IN_S, 1, 0, 0, 0}}, - {25, Interpreter::oris, {"oris", OpType::Integer, FL_OUT_A | FL_IN_S, 1, 0, 0, 0}}, - {26, Interpreter::xori, {"xori", OpType::Integer, FL_OUT_A | FL_IN_S, 1, 0, 0, 0}}, - {27, Interpreter::xoris, {"xoris", OpType::Integer, FL_OUT_A | FL_IN_S, 1, 0, 0, 0}}, - {28, Interpreter::andi_rc, {"andi_rc", OpType::Integer, FL_OUT_A | FL_IN_S | FL_SET_CR0, 1, 0, 0, 0}}, - {29, Interpreter::andis_rc, {"andis_rc", OpType::Integer, FL_OUT_A | FL_IN_S | FL_SET_CR0, 1, 0, 0, 0}}, + {32, Interpreter::lwz}, // lwz + {33, Interpreter::lwzu}, // lwzu + {34, Interpreter::lbz}, // lbz + {35, Interpreter::lbzu}, // lbzu + {40, Interpreter::lhz}, // lhz + {41, Interpreter::lhzu}, // lhzu - {32, Interpreter::lwz, {"lwz", OpType::Load, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE, 1, 0, 0, 0}}, - {33, Interpreter::lwzu, {"lwzu", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE, 1, 0, 0, 0}}, - {34, Interpreter::lbz, {"lbz", OpType::Load, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE, 1, 0, 0, 0}}, - {35, Interpreter::lbzu, {"lbzu", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE, 1, 0, 0, 0}}, - {40, Interpreter::lhz, {"lhz", OpType::Load, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE, 1, 0, 0, 0}}, - {41, Interpreter::lhzu, {"lhzu", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE, 1, 0, 0, 0}}, + {42, Interpreter::lha}, // lha + {43, Interpreter::lhau}, // lhau - {42, Interpreter::lha, {"lha", OpType::Load, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE, 1, 0, 0, 0}}, - {43, Interpreter::lhau, {"lhau", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE, 1, 0, 0, 0}}, + {44, Interpreter::sth}, // sth + {45, Interpreter::sthu}, // sthu + {36, Interpreter::stw}, // stw + {37, Interpreter::stwu}, // stwu + {38, Interpreter::stb}, // stb + {39, Interpreter::stbu}, // stbu - {44, Interpreter::sth, {"sth", OpType::Store, FL_IN_A0 | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}}, - {45, Interpreter::sthu, {"sthu", OpType::Store, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}}, - {36, Interpreter::stw, {"stw", OpType::Store, FL_IN_A0 | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}}, - {37, Interpreter::stwu, {"stwu", OpType::Store, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}}, - {38, Interpreter::stb, {"stb", OpType::Store, FL_IN_A0 | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}}, - {39, Interpreter::stbu, {"stbu", OpType::Store, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}}, + {46, Interpreter::lmw}, // lmw + {47, Interpreter::stmw}, // stmw - {46, Interpreter::lmw, {"lmw", OpType::System, FL_EVIL | FL_IN_A0 | FL_LOADSTORE, 11, 0, 0, 0}}, - {47, Interpreter::stmw, {"stmw", OpType::System, FL_EVIL | FL_IN_A0 | FL_LOADSTORE, 11, 0, 0, 0}}, + {48, Interpreter::lfs}, // lfs + {49, Interpreter::lfsu}, // lfsu + {50, Interpreter::lfd}, // lfd + {51, Interpreter::lfdu}, // lfdu - {48, Interpreter::lfs, {"lfs", OpType::LoadFP, FL_OUT_FLOAT_D | FL_IN_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {49, Interpreter::lfsu, {"lfsu", OpType::LoadFP, FL_OUT_FLOAT_D | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {50, Interpreter::lfd, {"lfd", OpType::LoadFP, FL_INOUT_FLOAT_D | FL_IN_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {51, Interpreter::lfdu, {"lfdu", OpType::LoadFP, FL_INOUT_FLOAT_D | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, + {52, Interpreter::stfs}, // stfs + {53, Interpreter::stfsu}, // stfsu + {54, Interpreter::stfd}, // stfd + {55, Interpreter::stfdu}, // stfdu - {52, Interpreter::stfs, {"stfs", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {53, Interpreter::stfsu, {"stfsu", OpType::StoreFP, FL_IN_FLOAT_S | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {54, Interpreter::stfd, {"stfd", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {55, Interpreter::stfdu, {"stfdu", OpType::StoreFP, FL_IN_FLOAT_S | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, + {56, Interpreter::psq_l}, // psq_l + {57, Interpreter::psq_lu}, // psq_lu + {60, Interpreter::psq_st}, // psq_st + {61, Interpreter::psq_stu}, // psq_stu - {56, Interpreter::psq_l, {"psq_l", OpType::LoadPS, FL_OUT_FLOAT_D | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {57, Interpreter::psq_lu, {"psq_lu", OpType::LoadPS, FL_OUT_FLOAT_D | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {60, Interpreter::psq_st, {"psq_st", OpType::StorePS, FL_IN_FLOAT_S | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {61, Interpreter::psq_stu, {"psq_stu", OpType::StorePS, FL_IN_FLOAT_S | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - - //missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58 + // missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58 }}; -static std::array table4 = -{{ //SUBOP10 - {0, Interpreter::ps_cmpu0, {"ps_cmpu0", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {32, Interpreter::ps_cmpo0, {"ps_cmpo0", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {40, Interpreter::ps_neg, {"ps_neg", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {136, Interpreter::ps_nabs, {"ps_nabs", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {264, Interpreter::ps_abs, {"ps_abs", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {64, Interpreter::ps_cmpu1, {"ps_cmpu1", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {72, Interpreter::ps_mr, {"ps_mr", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {96, Interpreter::ps_cmpo1, {"ps_cmpo1", OpType::PS, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {528, Interpreter::ps_merge00, {"ps_merge00", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {560, Interpreter::ps_merge01, {"ps_merge01", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {592, Interpreter::ps_merge10, {"ps_merge10", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {624, Interpreter::ps_merge11, {"ps_merge11", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, +constexpr std::array s_table4{{ + // SUBOP10 + {0, Interpreter::ps_cmpu0}, // ps_cmpu0 + {32, Interpreter::ps_cmpo0}, // ps_cmpo0 + {40, Interpreter::ps_neg}, // ps_neg + {136, Interpreter::ps_nabs}, // ps_nabs + {264, Interpreter::ps_abs}, // ps_abs + {64, Interpreter::ps_cmpu1}, // ps_cmpu1 + {72, Interpreter::ps_mr}, // ps_mr + {96, Interpreter::ps_cmpo1}, // ps_cmpo1 + {528, Interpreter::ps_merge00}, // ps_merge00 + {560, Interpreter::ps_merge01}, // ps_merge01 + {592, Interpreter::ps_merge10}, // ps_merge10 + {624, Interpreter::ps_merge11}, // ps_merge11 - {1014, Interpreter::dcbz_l, {"dcbz_l", OpType::System, FL_IN_A0B | FL_LOADSTORE | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, + {1014, Interpreter::dcbz_l}, // dcbz_l }}; -static std::array table4_2 = -{{ - {10, Interpreter::ps_sum0, {"ps_sum0", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {11, Interpreter::ps_sum1, {"ps_sum1", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {12, Interpreter::ps_muls0, {"ps_muls0", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {13, Interpreter::ps_muls1, {"ps_muls1", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {14, Interpreter::ps_madds0, {"ps_madds0", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {15, Interpreter::ps_madds1, {"ps_madds1", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {18, Interpreter::ps_div, {"ps_div", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 17, 0, 0, 0}}, - {20, Interpreter::ps_sub, {"ps_sub", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {21, Interpreter::ps_add, {"ps_add", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {23, Interpreter::ps_sel, {"ps_sel", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_IN_FLOAT_BC_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {24, Interpreter::ps_res, {"ps_res", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 1, 0, 0, 0}}, - {25, Interpreter::ps_mul, {"ps_mul", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {26, Interpreter::ps_rsqrte, {"ps_rsqrte", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 2, 0, 0, 0}}, - {28, Interpreter::ps_msub, {"ps_msub", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {29, Interpreter::ps_madd, {"ps_madd", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {30, Interpreter::ps_nmsub, {"ps_nmsub", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {31, Interpreter::ps_nmadd, {"ps_nmadd", OpType::PS, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, +constexpr std::array s_table4_2{{ + {10, Interpreter::ps_sum0}, // ps_sum0 + {11, Interpreter::ps_sum1}, // ps_sum1 + {12, Interpreter::ps_muls0}, // ps_muls0 + {13, Interpreter::ps_muls1}, // ps_muls1 + {14, Interpreter::ps_madds0}, // ps_madds0 + {15, Interpreter::ps_madds1}, // ps_madds1 + {18, Interpreter::ps_div}, // ps_div + {20, Interpreter::ps_sub}, // ps_sub + {21, Interpreter::ps_add}, // ps_add + {23, Interpreter::ps_sel}, // ps_sel + {24, Interpreter::ps_res}, // ps_res + {25, Interpreter::ps_mul}, // ps_mul + {26, Interpreter::ps_rsqrte}, // ps_rsqrte + {28, Interpreter::ps_msub}, // ps_msub + {29, Interpreter::ps_madd}, // ps_madd + {30, Interpreter::ps_nmsub}, // ps_nmsub + {31, Interpreter::ps_nmadd}, // ps_nmadd }}; - -static std::array table4_3 = -{{ - {6, Interpreter::psq_lx, {"psq_lx", OpType::LoadPS, FL_OUT_FLOAT_D | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {7, Interpreter::psq_stx, {"psq_stx", OpType::StorePS, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {38, Interpreter::psq_lux, {"psq_lux", OpType::LoadPS, FL_OUT_FLOAT_D | FL_OUT_A | FL_IN_AB | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {39, Interpreter::psq_stux, {"psq_stux", OpType::StorePS, FL_IN_FLOAT_S | FL_OUT_A | FL_IN_AB | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, +constexpr std::array s_table4_3{{ + {6, Interpreter::psq_lx}, // psq_lx + {7, Interpreter::psq_stx}, // psq_stx + {38, Interpreter::psq_lux}, // psq_lux + {39, Interpreter::psq_stux}, // psq_stux }}; -static std::array table19 = -{{ - {528, Interpreter::bcctrx, {"bcctrx", OpType::Branch, FL_ENDBLOCK | FL_READ_CR_BI, 1, 0, 0, 0}}, - {16, Interpreter::bclrx, {"bclrx", OpType::Branch, FL_ENDBLOCK | FL_READ_CR_BI, 1, 0, 0, 0}}, - {257, Interpreter::crand, {"crand", OpType::CR, FL_EVIL, 1, 0, 0, 0}}, - {129, Interpreter::crandc, {"crandc", OpType::CR, FL_EVIL, 1, 0, 0, 0}}, - {289, Interpreter::creqv, {"creqv", OpType::CR, FL_EVIL, 1, 0, 0, 0}}, - {225, Interpreter::crnand, {"crnand", OpType::CR, FL_EVIL, 1, 0, 0, 0}}, - {33, Interpreter::crnor, {"crnor", OpType::CR, FL_EVIL, 1, 0, 0, 0}}, - {449, Interpreter::cror, {"cror", OpType::CR, FL_EVIL, 1, 0, 0, 0}}, - {417, Interpreter::crorc, {"crorc", OpType::CR, FL_EVIL, 1, 0, 0, 0}}, - {193, Interpreter::crxor, {"crxor", OpType::CR, FL_EVIL, 1, 0, 0, 0}}, +constexpr std::array s_table19{{ + {528, Interpreter::bcctrx}, // bcctrx + {16, Interpreter::bclrx}, // bclrx + {257, Interpreter::crand}, // crand + {129, Interpreter::crandc}, // crandc + {289, Interpreter::creqv}, // creqv + {225, Interpreter::crnand}, // crnand + {33, Interpreter::crnor}, // crnor + {449, Interpreter::cror}, // cror + {417, Interpreter::crorc}, // crorc + {193, Interpreter::crxor}, // crxor - {150, Interpreter::isync, {"isync", OpType::InstructionCache, FL_EVIL, 1, 0, 0, 0}}, - {0, Interpreter::mcrf, {"mcrf", OpType::System, FL_EVIL | FL_SET_CRn | FL_READ_CRn, 1, 0, 0, 0}}, + {150, Interpreter::isync}, // isync + {0, Interpreter::mcrf}, // mcrf - {50, Interpreter::rfi, {"rfi", OpType::System, FL_ENDBLOCK | FL_CHECKEXCEPTIONS | FL_PROGRAMEXCEPTION, 2, 0, 0, 0}}, + {50, Interpreter::rfi}, // rfi }}; -static std::array table31 = -{{ - {266, Interpreter::addx, {"addx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 1, 0, 0, 0}}, - {778, Interpreter::addx, {"addox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}}, - {10, Interpreter::addcx, {"addcx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}}, - {522, Interpreter::addcx, {"addcox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}}, - {138, Interpreter::addex, {"addex", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}}, - {650, Interpreter::addex, {"addeox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}}, - {234, Interpreter::addmex, {"addmex", OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}}, - {746, Interpreter::addmex, {"addmeox", OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}}, - {202, Interpreter::addzex, {"addzex", OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}}, - {714, Interpreter::addzex, {"addzeox", OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}}, - {491, Interpreter::divwx, {"divwx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 40, 0, 0, 0}}, - {1003, Interpreter::divwx, {"divwox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE, 40, 0, 0, 0}}, - {459, Interpreter::divwux, {"divwux", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 40, 0, 0, 0}}, - {971, Interpreter::divwux, {"divwuox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE, 40, 0, 0, 0}}, - {75, Interpreter::mulhwx, {"mulhwx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 5, 0, 0, 0}}, - {11, Interpreter::mulhwux, {"mulhwux", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 5, 0, 0, 0}}, - {235, Interpreter::mullwx, {"mullwx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 5, 0, 0, 0}}, - {747, Interpreter::mullwx, {"mullwox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE, 5, 0, 0, 0}}, - {104, Interpreter::negx, {"negx", OpType::Integer, FL_OUT_D | FL_IN_A | FL_RC_BIT, 1, 0, 0, 0}}, - {616, Interpreter::negx, {"negox", OpType::Integer, FL_OUT_D | FL_IN_A | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}}, - {40, Interpreter::subfx, {"subfx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 1, 0, 0, 0}}, - {552, Interpreter::subfx, {"subfox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}}, - {8, Interpreter::subfcx, {"subfcx", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}}, - {520, Interpreter::subfcx, {"subfcox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}}, - {136, Interpreter::subfex, {"subfex", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}}, - {648, Interpreter::subfex, {"subfeox", OpType::Integer, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}}, - {232, Interpreter::subfmex, {"subfmex", OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}}, - {744, Interpreter::subfmex, {"subfmeox",OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}}, - {200, Interpreter::subfzex, {"subfzex", OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}}, - {712, Interpreter::subfzex, {"subfzeox",OpType::Integer, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE, 1, 0, 0, 0}}, +constexpr std::array s_table31{{ + {266, Interpreter::addx}, // addx + {778, Interpreter::addx}, // addox + {10, Interpreter::addcx}, // addcx + {522, Interpreter::addcx}, // addcox + {138, Interpreter::addex}, // addex + {650, Interpreter::addex}, // addeox + {234, Interpreter::addmex}, // addmex + {746, Interpreter::addmex}, // addmeox + {202, Interpreter::addzex}, // addzex + {714, Interpreter::addzex}, // addzeox + {491, Interpreter::divwx}, // divwx + {1003, Interpreter::divwx}, // divwox + {459, Interpreter::divwux}, // divwux + {971, Interpreter::divwux}, // divwuox + {75, Interpreter::mulhwx}, // mulhwx + {11, Interpreter::mulhwux}, // mulhwux + {235, Interpreter::mullwx}, // mullwx + {747, Interpreter::mullwx}, // mullwox + {104, Interpreter::negx}, // negx + {616, Interpreter::negx}, // negox + {40, Interpreter::subfx}, // subfx + {552, Interpreter::subfx}, // subfox + {8, Interpreter::subfcx}, // subfcx + {520, Interpreter::subfcx}, // subfcox + {136, Interpreter::subfex}, // subfex + {648, Interpreter::subfex}, // subfeox + {232, Interpreter::subfmex}, // subfmex + {744, Interpreter::subfmex}, // subfmeox + {200, Interpreter::subfzex}, // subfzex + {712, Interpreter::subfzex}, // subfzeox - {28, Interpreter::andx, {"andx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}}, - {60, Interpreter::andcx, {"andcx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}}, - {444, Interpreter::orx, {"orx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}}, - {124, Interpreter::norx, {"norx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}}, - {316, Interpreter::xorx, {"xorx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}}, - {412, Interpreter::orcx, {"orcx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}}, - {476, Interpreter::nandx, {"nandx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}}, - {284, Interpreter::eqvx, {"eqvx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}}, - {0, Interpreter::cmp, {"cmp", OpType::Integer, FL_IN_AB | FL_SET_CRn, 1, 0, 0, 0}}, - {32, Interpreter::cmpl, {"cmpl", OpType::Integer, FL_IN_AB | FL_SET_CRn, 1, 0, 0, 0}}, - {26, Interpreter::cntlzwx, {"cntlzwx",OpType::Integer, FL_OUT_A | FL_IN_S | FL_RC_BIT, 1, 0, 0, 0}}, - {922, Interpreter::extshx, {"extshx", OpType::Integer, FL_OUT_A | FL_IN_S | FL_RC_BIT, 1, 0, 0, 0}}, - {954, Interpreter::extsbx, {"extsbx", OpType::Integer, FL_OUT_A | FL_IN_S | FL_RC_BIT, 1, 0, 0, 0}}, - {536, Interpreter::srwx, {"srwx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}}, - {792, Interpreter::srawx, {"srawx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}}, - {824, Interpreter::srawix, {"srawix", OpType::Integer, FL_OUT_A | FL_IN_S | FL_SET_CA | FL_RC_BIT, 1, 0, 0, 0}}, - {24, Interpreter::slwx, {"slwx", OpType::Integer, FL_OUT_A | FL_IN_SB | FL_RC_BIT, 1, 0, 0, 0}}, + {28, Interpreter::andx}, // andx + {60, Interpreter::andcx}, // andcx + {444, Interpreter::orx}, // orx + {124, Interpreter::norx}, // norx + {316, Interpreter::xorx}, // xorx + {412, Interpreter::orcx}, // orcx + {476, Interpreter::nandx}, // nandx + {284, Interpreter::eqvx}, // eqvx + {0, Interpreter::cmp}, // cmp + {32, Interpreter::cmpl}, // cmpl + {26, Interpreter::cntlzwx}, // cntlzwx + {922, Interpreter::extshx}, // extshx + {954, Interpreter::extsbx}, // extsbx + {536, Interpreter::srwx}, // srwx + {792, Interpreter::srawx}, // srawx + {824, Interpreter::srawix}, // srawix + {24, Interpreter::slwx}, // slwx - {54, Interpreter::dcbst, {"dcbst", OpType::DataCache, FL_IN_A0B | FL_LOADSTORE, 5, 0, 0, 0}}, - {86, Interpreter::dcbf, {"dcbf", OpType::DataCache, FL_IN_A0B | FL_LOADSTORE, 5, 0, 0, 0}}, - {246, Interpreter::dcbtst, {"dcbtst", OpType::DataCache, 0, 2, 0, 0, 0}}, - {278, Interpreter::dcbt, {"dcbt", OpType::DataCache, 0, 2, 0, 0, 0}}, - {470, Interpreter::dcbi, {"dcbi", OpType::DataCache, FL_IN_A0B | FL_LOADSTORE | FL_PROGRAMEXCEPTION, 5, 0, 0, 0}}, - {758, Interpreter::dcba, {"dcba", OpType::DataCache, 0, 5, 0, 0, 0}}, - {1014, Interpreter::dcbz, {"dcbz", OpType::DataCache, FL_IN_A0B | FL_LOADSTORE, 5, 0, 0, 0}}, + {54, Interpreter::dcbst}, // dcbst + {86, Interpreter::dcbf}, // dcbf + {246, Interpreter::dcbtst}, // dcbtst + {278, Interpreter::dcbt}, // dcbt + {470, Interpreter::dcbi}, // dcbi + {758, Interpreter::dcba}, // dcba + {1014, Interpreter::dcbz}, // dcbz - //load word - {23, Interpreter::lwzx, {"lwzx", OpType::Load, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}}, - {55, Interpreter::lwzux, {"lwzux", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}}, + // load word + {23, Interpreter::lwzx}, // lwzx + {55, Interpreter::lwzux}, // lwzux - //load halfword - {279, Interpreter::lhzx, {"lhzx", OpType::Load, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}}, - {311, Interpreter::lhzux, {"lhzux", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}}, + // load halfword + {279, Interpreter::lhzx}, // lhzx + {311, Interpreter::lhzux}, // lhzux - //load halfword signextend - {343, Interpreter::lhax, {"lhax", OpType::Load, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}}, - {375, Interpreter::lhaux, {"lhaux", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}}, + // load halfword signextend + {343, Interpreter::lhax}, // lhax + {375, Interpreter::lhaux}, // lhaux - //load byte - {87, Interpreter::lbzx, {"lbzx", OpType::Load, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}}, - {119, Interpreter::lbzux, {"lbzux", OpType::Load, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}}, + // load byte + {87, Interpreter::lbzx}, // lbzx + {119, Interpreter::lbzux}, // lbzux - //load byte reverse - {534, Interpreter::lwbrx, {"lwbrx", OpType::Load, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}}, - {790, Interpreter::lhbrx, {"lhbrx", OpType::Load, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}}, + // load byte reverse + {534, Interpreter::lwbrx}, // lwbrx + {790, Interpreter::lhbrx}, // lhbrx - // Conditional load/store (Wii SMP) - {150, Interpreter::stwcxd, {"stwcxd", OpType::Store, FL_EVIL | FL_IN_S | FL_IN_A0B | FL_SET_CR0 | FL_LOADSTORE, 1, 0, 0, 0}}, - {20, Interpreter::lwarx, {"lwarx", OpType::Load, FL_EVIL | FL_OUT_D | FL_IN_A0B | FL_SET_CR0 | FL_LOADSTORE, 1, 0, 0, 0}}, + // Conditional load/store (Wii SMP) + {150, Interpreter::stwcxd}, // stwcxd + {20, Interpreter::lwarx}, // lwarx - //load string (Inst these) - {533, Interpreter::lswx, {"lswx", OpType::Load, FL_EVIL | FL_IN_A0B | FL_OUT_D | FL_LOADSTORE, 1, 0, 0, 0}}, - {597, Interpreter::lswi, {"lswi", OpType::Load, FL_EVIL | FL_IN_A0 | FL_OUT_D | FL_LOADSTORE, 1, 0, 0, 0}}, + // load string (Inst these) + {533, Interpreter::lswx}, // lswx + {597, Interpreter::lswi}, // lswi - //store word - {151, Interpreter::stwx, {"stwx", OpType::Store, FL_IN_S | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}}, - {183, Interpreter::stwux, {"stwux", OpType::Store, FL_IN_S | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}}, + // store word + {151, Interpreter::stwx}, // stwx + {183, Interpreter::stwux}, // stwux - //store halfword - {407, Interpreter::sthx, {"sthx", OpType::Store, FL_IN_S | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}}, - {439, Interpreter::sthux, {"sthux", OpType::Store, FL_IN_S | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}}, + // store halfword + {407, Interpreter::sthx}, // sthx + {439, Interpreter::sthux}, // sthux - //store byte - {215, Interpreter::stbx, {"stbx", OpType::Store, FL_IN_S | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}}, - {247, Interpreter::stbux, {"stbux", OpType::Store, FL_IN_S | FL_OUT_A | FL_IN_AB | FL_LOADSTORE, 1, 0, 0, 0}}, + // store byte + {215, Interpreter::stbx}, // stbx + {247, Interpreter::stbux}, // stbux - //store bytereverse - {662, Interpreter::stwbrx, {"stwbrx", OpType::Store, FL_IN_S | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}}, - {918, Interpreter::sthbrx, {"sthbrx", OpType::Store, FL_IN_S | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}}, + // store bytereverse + {662, Interpreter::stwbrx}, // stwbrx + {918, Interpreter::sthbrx}, // sthbrx - {661, Interpreter::stswx, {"stswx", OpType::Store, FL_EVIL | FL_IN_A0B | FL_LOADSTORE, 1, 0, 0, 0}}, - {725, Interpreter::stswi, {"stswi", OpType::Store, FL_EVIL | FL_IN_A0 | FL_LOADSTORE, 1, 0, 0, 0}}, + {661, Interpreter::stswx}, // stswx + {725, Interpreter::stswi}, // stswi - // fp load/store - {535, Interpreter::lfsx, {"lfsx", OpType::LoadFP, FL_OUT_FLOAT_D | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {567, Interpreter::lfsux, {"lfsux", OpType::LoadFP, FL_OUT_FLOAT_D | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {599, Interpreter::lfdx, {"lfdx", OpType::LoadFP, FL_INOUT_FLOAT_D | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {631, Interpreter::lfdux, {"lfdux", OpType::LoadFP, FL_INOUT_FLOAT_D | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, + // fp load/store + {535, Interpreter::lfsx}, // lfsx + {567, Interpreter::lfsux}, // lfsux + {599, Interpreter::lfdx}, // lfdx + {631, Interpreter::lfdux}, // lfdux - {663, Interpreter::stfsx, {"stfsx", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {695, Interpreter::stfsux, {"stfsux", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {727, Interpreter::stfdx, {"stfdx", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {759, Interpreter::stfdux, {"stfdux", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, - {983, Interpreter::stfiwx, {"stfiwx", OpType::StoreFP, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE, 1, 0, 0, 0}}, + {663, Interpreter::stfsx}, // stfsx + {695, Interpreter::stfsux}, // stfsux + {727, Interpreter::stfdx}, // stfdx + {759, Interpreter::stfdux}, // stfdux + {983, Interpreter::stfiwx}, // stfiwx - {19, Interpreter::mfcr, {"mfcr", OpType::System, FL_OUT_D | FL_READ_ALL_CR, 1, 0, 0, 0}}, - {83, Interpreter::mfmsr, {"mfmsr", OpType::System, FL_OUT_D | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {144, Interpreter::mtcrf, {"mtcrf", OpType::System, FL_IN_S | FL_SET_ALL_CR | FL_READ_ALL_CR, 1, 0, 0, 0}}, - {146, Interpreter::mtmsr, {"mtmsr", OpType::System, FL_IN_S | FL_ENDBLOCK | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {210, Interpreter::mtsr, {"mtsr", OpType::System, FL_IN_S | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {242, Interpreter::mtsrin, {"mtsrin", OpType::System, FL_IN_SB | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {339, Interpreter::mfspr, {"mfspr", OpType::SPR, FL_OUT_D | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {467, Interpreter::mtspr, {"mtspr", OpType::SPR, FL_IN_S | FL_PROGRAMEXCEPTION, 2, 0, 0, 0}}, - {371, Interpreter::mftb, {"mftb", OpType::System, FL_OUT_D | FL_TIMER | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {512, Interpreter::mcrxr, {"mcrxr", OpType::System, FL_SET_CRn | FL_READ_CA | FL_SET_CA, 1, 0, 0, 0}}, - {595, Interpreter::mfsr, {"mfsr", OpType::System, FL_OUT_D | FL_PROGRAMEXCEPTION, 3, 0, 0, 0}}, - {659, Interpreter::mfsrin, {"mfsrin", OpType::System, FL_OUT_D | FL_IN_B | FL_PROGRAMEXCEPTION, 3, 0, 0, 0}}, + {19, Interpreter::mfcr}, // mfcr + {83, Interpreter::mfmsr}, // mfmsr + {144, Interpreter::mtcrf}, // mtcrf + {146, Interpreter::mtmsr}, // mtmsr + {210, Interpreter::mtsr}, // mtsr + {242, Interpreter::mtsrin}, // mtsrin + {339, Interpreter::mfspr}, // mfspr + {467, Interpreter::mtspr}, // mtspr + {371, Interpreter::mftb}, // mftb + {512, Interpreter::mcrxr}, // mcrxr + {595, Interpreter::mfsr}, // mfsr + {659, Interpreter::mfsrin}, // mfsrin - {4, Interpreter::tw, {"tw", OpType::System, FL_IN_AB | FL_ENDBLOCK, 2, 0, 0, 0}}, - {598, Interpreter::sync, {"sync", OpType::System, 0, 3, 0, 0, 0}}, - {982, Interpreter::icbi, {"icbi", OpType::System, FL_IN_A0B | FL_ENDBLOCK | FL_LOADSTORE, 4, 0, 0, 0}}, + {4, Interpreter::tw}, // tw + {598, Interpreter::sync}, // sync + {982, Interpreter::icbi}, // icbi - // Unused instructions on GC - {310, Interpreter::eciwx, {"eciwx", OpType::System, FL_IN_A0B | FL_OUT_D | FL_LOADSTORE, 1, 0, 0, 0}}, - {438, Interpreter::ecowx, {"ecowx", OpType::System, FL_IN_A0B | FL_IN_S | FL_LOADSTORE, 1, 0, 0, 0}}, - {854, Interpreter::eieio, {"eieio", OpType::System, 0, 1, 0, 0, 0}}, - {306, Interpreter::tlbie, {"tlbie", OpType::System, FL_IN_B | FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, - {566, Interpreter::tlbsync, {"tlbsync", OpType::System, FL_PROGRAMEXCEPTION, 1, 0, 0, 0}}, + // Unused instructions on GC + {310, Interpreter::eciwx}, // eciwx + {438, Interpreter::ecowx}, // ecowx + {854, Interpreter::eieio}, // eieio + {306, Interpreter::tlbie}, // tlbie + {566, Interpreter::tlbsync}, // tlbsync }}; -static std::array table59 = -{{ - {18, Interpreter::fdivsx, {"fdivsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 17, 0, 0, 0}}, // TODO - {20, Interpreter::fsubsx, {"fsubsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {21, Interpreter::faddsx, {"faddsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {24, Interpreter::fresx, {"fresx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 1, 0, 0, 0}}, - {25, Interpreter::fmulsx, {"fmulsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {28, Interpreter::fmsubsx, {"fmsubsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {29, Interpreter::fmaddsx, {"fmaddsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {30, Interpreter::fnmsubsx, {"fnmsubsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {31, Interpreter::fnmaddsx, {"fnmaddsx", OpType::SingleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, +constexpr std::array s_table59{{ + {18, Interpreter::fdivsx}, // fdivsx // TODO + {20, Interpreter::fsubsx}, // fsubsx + {21, Interpreter::faddsx}, // faddsx + {24, Interpreter::fresx}, // fresx + {25, Interpreter::fmulsx}, // fmulsx + {28, Interpreter::fmsubsx}, // fmsubsx + {29, Interpreter::fmaddsx}, // fmaddsx + {30, Interpreter::fnmsubsx}, // fnmsubsx + {31, Interpreter::fnmaddsx}, // fnmaddsx }}; -static std::array table63 = -{{ - {264, Interpreter::fabsx, {"fabsx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU, 1, 0, 0, 0}}, +constexpr std::array s_table63{{ + {264, Interpreter::fabsx}, // fabsx + {32, Interpreter::fcmpo}, // fcmpo + {0, Interpreter::fcmpu}, // fcmpu + {14, Interpreter::fctiwx}, // fctiwx + {15, Interpreter::fctiwzx}, // fctiwzx + {72, Interpreter::fmrx}, // fmrx + {136, Interpreter::fnabsx}, // fnabsx + {40, Interpreter::fnegx}, // fnegx + {12, Interpreter::frspx}, // frspx - // FIXME: fcmp modifies the FPRF flags, but if the flags are clobbered later, - // we don't actually need to calculate or store them here. So FL_READ_FPRF and FL_SET_FPRF is not - // an ideal representation of fcmp's effect on FPRF flags and might result in - // slightly sub-optimal code. - {32, Interpreter::fcmpo, {"fcmpo", OpType::DoubleFP, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {0, Interpreter::fcmpu, {"fcmpu", OpType::DoubleFP, FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - - {14, Interpreter::fctiwx, {"fctiwx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {15, Interpreter::fctiwzx, {"fctiwzx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {72, Interpreter::fmrx, {"fmrx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU, 1, 0, 0, 0}}, - {136, Interpreter::fnabsx, {"fnabsx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_IN_FLOAT_B_BITEXACT | FL_USE_FPU, 1, 0, 0, 0}}, - {40, Interpreter::fnegx, {"fnegx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_IN_FLOAT_B_BITEXACT | FL_USE_FPU, 1, 0, 0, 0}}, - {12, Interpreter::frspx, {"frspx", OpType::DoubleFP, FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - - {64, Interpreter::mcrfs, {"mcrfs", OpType::SystemFP, FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF, 1, 0, 0, 0}}, - {583, Interpreter::mffsx, {"mffsx", OpType::SystemFP, FL_RC_BIT_F | FL_INOUT_FLOAT_D | FL_USE_FPU | FL_READ_FPRF, 1, 0, 0, 0}}, - {70, Interpreter::mtfsb0x, {"mtfsb0x", OpType::SystemFP, FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF, 3, 0, 0, 0}}, - {38, Interpreter::mtfsb1x, {"mtfsb1x", OpType::SystemFP, FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 3, 0, 0, 0}}, - {134, Interpreter::mtfsfix, {"mtfsfix", OpType::SystemFP, FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 3, 0, 0, 0}}, - {711, Interpreter::mtfsfx, {"mtfsfx", OpType::SystemFP, FL_RC_BIT_F | FL_IN_FLOAT_B | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 3, 0, 0, 0}}, + {64, Interpreter::mcrfs}, // mcrfs + {583, Interpreter::mffsx}, // mffsx + {70, Interpreter::mtfsb0x}, // mtfsb0x + {38, Interpreter::mtfsb1x}, // mtfsb1x + {134, Interpreter::mtfsfix}, // mtfsfix + {711, Interpreter::mtfsfx}, // mtfsfx }}; -static std::array table63_2 = -{{ - {18, Interpreter::fdivx, {"fdivx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 31, 0, 0, 0}}, - {20, Interpreter::fsubx, {"fsubx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {21, Interpreter::faddx, {"faddx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {23, Interpreter::fselx, {"fselx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_IN_FLOAT_BC_BITEXACT | FL_RC_BIT_F | FL_USE_FPU, 1, 0, 0, 0}}, - {25, Interpreter::fmulx, {"fmulx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {26, Interpreter::frsqrtex, {"frsqrtex", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV, 1, 0, 0, 0}}, - {28, Interpreter::fmsubx, {"fmsubx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {29, Interpreter::fmaddx, {"fmaddx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {30, Interpreter::fnmsubx, {"fnmsubx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, - {31, Interpreter::fnmaddx, {"fnmaddx", OpType::DoubleFP, FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION, 1, 0, 0, 0}}, +constexpr std::array s_table63_2{{ + {18, Interpreter::fdivx}, // fdivx + {20, Interpreter::fsubx}, // fsubx + {21, Interpreter::faddx}, // faddx + {23, Interpreter::fselx}, // fselx + {25, Interpreter::fmulx}, // fmulx + {26, Interpreter::frsqrtex}, // frsqrtex + {28, Interpreter::fmsubx}, // fmsubx + {29, Interpreter::fmaddx}, // fmaddx + {30, Interpreter::fnmsubx}, // fnmsubx + {31, Interpreter::fnmaddx}, // fnmaddx }}; -// clang-format on -constexpr size_t TotalInstructionFunctionCount() +constexpr std::array s_interpreter_op_table = []() consteval { - return primarytable.size() + table4_2.size() + table4_3.size() + table4.size() + table31.size() + - table19.size() + table59.size() + table63.size() + table63_2.size(); + std::array table{}; + Common::Fill(table, Interpreter::unknown_instruction); + for (auto& tpl : s_primary_table) + { + ASSERT(table[tpl.opcode] == Interpreter::unknown_instruction); + table[tpl.opcode] = tpl.fn; + }; + return table; +} +(); +constexpr std::array s_interpreter_op_table4 = []() consteval +{ + std::array table{}; + Common::Fill(table, Interpreter::unknown_instruction); + + for (u32 i = 0; i < 32; i++) + { + const u32 fill = i << 5; + for (const auto& tpl : s_table4_2) + { + const u32 op = fill + tpl.opcode; + ASSERT(table[op] == Interpreter::unknown_instruction); + table[op] = tpl.fn; + } + } + + for (u32 i = 0; i < 16; i++) + { + const u32 fill = i << 6; + for (const auto& tpl : s_table4_3) + { + const u32 op = fill + tpl.opcode; + ASSERT(table[op] == Interpreter::unknown_instruction); + table[op] = tpl.fn; + } + } + + for (const auto& tpl : s_table4) + { + const u32 op = tpl.opcode; + ASSERT(table[op] == Interpreter::unknown_instruction); + table[op] = tpl.fn; + } + + return table; +} +(); +constexpr std::array s_interpreter_op_table19 = []() consteval +{ + std::array table{}; + Common::Fill(table, Interpreter::unknown_instruction); + for (auto& tpl : s_table19) + { + ASSERT(table[tpl.opcode] == Interpreter::unknown_instruction); + table[tpl.opcode] = tpl.fn; + }; + return table; +} +(); +constexpr std::array s_interpreter_op_table31 = []() consteval +{ + std::array table{}; + Common::Fill(table, Interpreter::unknown_instruction); + for (auto& tpl : s_table31) + { + ASSERT(table[tpl.opcode] == Interpreter::unknown_instruction); + table[tpl.opcode] = tpl.fn; + }; + return table; +} +(); +constexpr std::array s_interpreter_op_table59 = []() consteval +{ + std::array table{}; + Common::Fill(table, Interpreter::unknown_instruction); + for (auto& tpl : s_table59) + { + ASSERT(table[tpl.opcode] == Interpreter::unknown_instruction); + table[tpl.opcode] = tpl.fn; + }; + return table; +} +(); +constexpr std::array s_interpreter_op_table63 = []() consteval +{ + std::array table{}; + Common::Fill(table, Interpreter::unknown_instruction); + for (auto& tpl : s_table63) + { + ASSERT(table[tpl.opcode] == Interpreter::unknown_instruction); + table[tpl.opcode] = tpl.fn; + }; + + for (u32 i = 0; i < 32; i++) + { + const u32 fill = i << 5; + for (const auto& tpl : s_table63_2) + { + const u32 op = fill + tpl.opcode; + ASSERT(table[op] == Interpreter::unknown_instruction); + table[op] = tpl.fn; + } + } + + return table; +} +(); + +Interpreter::Instruction Interpreter::GetInterpreterOp(UGeckoInstruction inst) +{ + // Check for the appropriate subtable ahead of time. + // (This is used by the cached interpreter and JIT, and called once per instruction, so spending a + // bit of extra time to optimise is worthwhile) + Interpreter::Instruction result = s_interpreter_op_table[inst.OPCD]; + if (result == Interpreter::RunTable4) + return s_interpreter_op_table4[inst.SUBOP10]; + else if (result == Interpreter::RunTable19) + return s_interpreter_op_table19[inst.SUBOP10]; + else if (result == Interpreter::RunTable31) + return s_interpreter_op_table31[inst.SUBOP10]; + else if (result == Interpreter::RunTable59) + return s_interpreter_op_table59[inst.SUBOP5]; + else if (result == Interpreter::RunTable63) + return s_interpreter_op_table63[inst.SUBOP10]; + else + return result; } -static_assert(TotalInstructionFunctionCount() < m_allInstructions.size(), - "m_allInstructions is too small"); - -void Interpreter::InitializeInstructionTables() +void Interpreter::RunInterpreterOp(UGeckoInstruction inst) { - // once initialized, tables are read-only - static bool initialized = false; - if (initialized) - return; - - // clear - for (int i = 0; i < 64; i++) - { - m_op_table[i] = Interpreter::unknown_instruction; - m_infoTable[i] = &unknownopinfo; - } - - for (int i = 0; i < 32; i++) - { - m_op_table59[i] = Interpreter::unknown_instruction; - m_infoTable59[i] = &unknownopinfo; - } - - for (int i = 0; i < 1024; i++) - { - m_op_table4[i] = Interpreter::unknown_instruction; - m_op_table19[i] = Interpreter::unknown_instruction; - m_op_table31[i] = Interpreter::unknown_instruction; - m_op_table63[i] = Interpreter::unknown_instruction; - m_infoTable4[i] = &unknownopinfo; - m_infoTable19[i] = &unknownopinfo; - m_infoTable31[i] = &unknownopinfo; - m_infoTable63[i] = &unknownopinfo; - } - - for (auto& tpl : primarytable) - { - m_op_table[tpl.opcode] = tpl.Inst; - m_infoTable[tpl.opcode] = &tpl.opinfo; - } - - for (int i = 0; i < 32; i++) - { - int fill = i << 5; - for (auto& tpl : table4_2) - { - int op = fill + tpl.opcode; - m_op_table4[op] = tpl.Inst; - m_infoTable4[op] = &tpl.opinfo; - } - } - - for (int i = 0; i < 16; i++) - { - int fill = i << 6; - for (auto& tpl : table4_3) - { - int op = fill + tpl.opcode; - m_op_table4[op] = tpl.Inst; - m_infoTable4[op] = &tpl.opinfo; - } - } - - for (auto& tpl : table4) - { - int op = tpl.opcode; - m_op_table4[op] = tpl.Inst; - m_infoTable4[op] = &tpl.opinfo; - } - - for (auto& tpl : table31) - { - int op = tpl.opcode; - m_op_table31[op] = tpl.Inst; - m_infoTable31[op] = &tpl.opinfo; - } - - for (auto& tpl : table19) - { - int op = tpl.opcode; - m_op_table19[op] = tpl.Inst; - m_infoTable19[op] = &tpl.opinfo; - } - - for (auto& tpl : table59) - { - int op = tpl.opcode; - m_op_table59[op] = tpl.Inst; - m_infoTable59[op] = &tpl.opinfo; - } - - for (auto& tpl : table63) - { - int op = tpl.opcode; - m_op_table63[op] = tpl.Inst; - m_infoTable63[op] = &tpl.opinfo; - } - - for (int i = 0; i < 32; i++) - { - int fill = i << 5; - for (auto& tpl : table63_2) - { - int op = fill + tpl.opcode; - m_op_table63[op] = tpl.Inst; - m_infoTable63[op] = &tpl.opinfo; - } - } - - m_numInstructions = 0; - for (auto& tpl : primarytable) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table4_2) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table4_3) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table4) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table31) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table19) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table59) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table63) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - for (auto& tpl : table63_2) - m_allInstructions[m_numInstructions++] = &tpl.opinfo; - - initialized = true; + // Will handle subtables using RunTable4 etc. + s_interpreter_op_table[inst.OPCD](inst); +} + +void Interpreter::RunTable4(UGeckoInstruction inst) +{ + s_interpreter_op_table4[inst.SUBOP10](inst); +} +void Interpreter::RunTable19(UGeckoInstruction inst) +{ + s_interpreter_op_table19[inst.SUBOP10](inst); +} +void Interpreter::RunTable31(UGeckoInstruction inst) +{ + s_interpreter_op_table31[inst.SUBOP10](inst); +} +void Interpreter::RunTable59(UGeckoInstruction inst) +{ + s_interpreter_op_table59[inst.SUBOP5](inst); +} +void Interpreter::RunTable63(UGeckoInstruction inst) +{ + s_interpreter_op_table63[inst.SUBOP10](inst); } diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index 071a35628a..6d287a9a5c 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -342,7 +342,7 @@ void Jit64::FallBackToInterpreter(UGeckoInstruction inst) MOV(32, PPCSTATE(npc), Imm32(js.compilerPC + 4)); } - Interpreter::Instruction instr = PPCTables::GetInterpreterOp(inst); + Interpreter::Instruction instr = Interpreter::GetInterpreterOp(inst); ABI_PushRegistersAndAdjustStack({}, 0); ABI_CallFunctionC(instr, inst.hex); ABI_PopRegistersAndAdjustStack({}, 0); @@ -921,7 +921,7 @@ bool Jit64::DoJit(u32 em_address, JitBlock* b, u32 nextPC) js.instructionNumber = i; js.instructionsLeft = (code_block.m_num_instructions - 1) - i; const GekkoOPInfo* opinfo = op.opinfo; - js.downcountAmount += opinfo->numCycles; + js.downcountAmount += opinfo->num_cycles; js.fastmemLoadStore = nullptr; js.fixupExceptionHandler = false; diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp index 32e5207773..f15adbd23d 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_LoadStore.cpp @@ -267,7 +267,7 @@ void Jit64::dcbx(UGeckoInstruction inst) // Alright, now figure out how many loops we want to do. const u8 cycle_count_per_loop = - js.op[0].opinfo->numCycles + js.op[1].opinfo->numCycles + js.op[2].opinfo->numCycles; + js.op[0].opinfo->num_cycles + js.op[1].opinfo->num_cycles + js.op[2].opinfo->num_cycles; // This is both setting the adjusted loop count to 0 for the downcount <= 0 case and clearing // the upper bits for the DIV instruction in the downcount > 0 case. diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index b8ddf1b5d6..57fa29e2e3 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -197,7 +197,7 @@ void JitArm64::FallBackToInterpreter(UGeckoInstruction inst) gpr.Unlock(WA); } - Interpreter::Instruction instr = PPCTables::GetInterpreterOp(inst); + Interpreter::Instruction instr = Interpreter::GetInterpreterOp(inst); MOVP2R(ARM64Reg::X8, instr); MOVI2R(ARM64Reg::W0, inst.hex); BLR(ARM64Reg::X8); @@ -903,7 +903,7 @@ bool JitArm64::DoJit(u32 em_address, JitBlock* b, u32 nextPC) js.instructionNumber = i; js.instructionsLeft = (code_block.m_num_instructions - 1) - i; const GekkoOPInfo* opinfo = op.opinfo; - js.downcountAmount += opinfo->numCycles; + js.downcountAmount += opinfo->num_cycles; js.isLastInstruction = i == (code_block.m_num_instructions - 1); if (!m_enable_debugging) diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp index 996b6e887f..e37db3a774 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_LoadStore.cpp @@ -677,7 +677,7 @@ void JitArm64::dcbx(UGeckoInstruction inst) // Figure out how many loops we want to do. const u8 cycle_count_per_loop = - js.op[0].opinfo->numCycles + js.op[1].opinfo->numCycles + js.op[2].opinfo->numCycles; + js.op[0].opinfo->num_cycles + js.op[1].opinfo->num_cycles + js.op[2].opinfo->num_cycles; LDR(IndexType::Unsigned, reg_downcount, PPC_REG, PPCSTATE_OFF(downcount)); MOVI2R(WA, 0); diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/PowerPC/PPCAnalyst.cpp index d9ee2834fd..0a04b8b9d9 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.cpp +++ b/Source/Core/Core/PowerPC/PPCAnalyst.cpp @@ -770,13 +770,13 @@ u32 PPCAnalyzer::Analyze(u32 address, CodeBlock* block, CodeBuffer* buffer, num_inst++; const UGeckoInstruction inst = result.hex; - GekkoOPInfo* opinfo = PPCTables::GetOpInfo(inst); + const GekkoOPInfo* opinfo = PPCTables::GetOpInfo(inst); code[i] = {}; code[i].opinfo = opinfo; code[i].address = address; code[i].inst = inst; code[i].skip = false; - block->m_stats->numCycles += opinfo->numCycles; + block->m_stats->numCycles += opinfo->num_cycles; block->m_physical_addresses.insert(result.physical_address); SetInstructionStats(block, &code[i], opinfo); diff --git a/Source/Core/Core/PowerPC/PPCAnalyst.h b/Source/Core/Core/PowerPC/PPCAnalyst.h index 571dc94c38..1c24120cc9 100644 --- a/Source/Core/Core/PowerPC/PPCAnalyst.h +++ b/Source/Core/Core/PowerPC/PPCAnalyst.h @@ -29,7 +29,7 @@ namespace PPCAnalyst struct CodeOp // 16B { UGeckoInstruction inst; - GekkoOPInfo* opinfo = nullptr; + const GekkoOPInfo* opinfo = nullptr; u32 address = 0; u32 branchTo = 0; // if UINT32_MAX, not a branch BitSet32 regsOut; diff --git a/Source/Core/Core/PowerPC/PPCTables.cpp b/Source/Core/Core/PowerPC/PPCTables.cpp index c87aea0ac6..eeb5b80270 100644 --- a/Source/Core/Core/PowerPC/PPCTables.cpp +++ b/Source/Core/Core/PowerPC/PPCTables.cpp @@ -17,43 +17,623 @@ #include "Common/IOFile.h" #include "Common/Logging/Log.h" #include "Common/StringUtil.h" +#include "Common/TypeUtils.h" #include "Core/PowerPC/Interpreter/Interpreter.h" #include "Core/PowerPC/PowerPC.h" -std::array m_infoTable; -std::array m_infoTable4; -std::array m_infoTable19; -std::array m_infoTable31; -std::array m_infoTable59; -std::array m_infoTable63; - -std::array m_allInstructions; -size_t m_numInstructions; - namespace PPCTables { -GekkoOPInfo* GetOpInfo(UGeckoInstruction inst) +namespace { - const GekkoOPInfo* info = m_infoTable[inst.OPCD]; +struct GekkoOPTemplate +{ + u32 opcode; + const char* opname; + OpType type; + u32 num_cycles; + u64 flags; +}; + +constexpr GekkoOPTemplate s_unknown_op_info = {0, "unknown_instruction", OpType::Unknown, 0, + FL_ENDBLOCK}; + +constexpr std::array s_primary_table{{ + {4, "RunTable4", OpType::Subtable, 0, 0}, + {19, "RunTable19", OpType::Subtable, 0, 0}, + {31, "RunTable31", OpType::Subtable, 0, 0}, + {59, "RunTable59", OpType::Subtable, 0, 0}, + {63, "RunTable63", OpType::Subtable, 0, 0}, + + {16, "bcx", OpType::Branch, 1, FL_ENDBLOCK | FL_READ_CR_BI}, + {18, "bx", OpType::Branch, 1, FL_ENDBLOCK}, + + {3, "twi", OpType::System, 1, FL_IN_A | FL_ENDBLOCK}, + {17, "sc", OpType::System, 2, FL_ENDBLOCK}, + + {7, "mulli", OpType::Integer, 3, FL_OUT_D | FL_IN_A}, + {8, "subfic", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_SET_CA}, + {10, "cmpli", OpType::Integer, 1, FL_IN_A | FL_SET_CRn}, + {11, "cmpi", OpType::Integer, 1, FL_IN_A | FL_SET_CRn}, + {12, "addic", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_SET_CA}, + {13, "addic_rc", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_SET_CA | FL_SET_CR0}, + {14, "addi", OpType::Integer, 1, FL_OUT_D | FL_IN_A0}, + {15, "addis", OpType::Integer, 1, FL_OUT_D | FL_IN_A0}, + + {20, "rlwimix", OpType::Integer, 1, FL_OUT_A | FL_IN_A | FL_IN_S | FL_RC_BIT}, + {21, "rlwinmx", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_RC_BIT}, + {23, "rlwnmx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT}, + + {24, "ori", OpType::Integer, 1, FL_OUT_A | FL_IN_S}, + {25, "oris", OpType::Integer, 1, FL_OUT_A | FL_IN_S}, + {26, "xori", OpType::Integer, 1, FL_OUT_A | FL_IN_S}, + {27, "xoris", OpType::Integer, 1, FL_OUT_A | FL_IN_S}, + {28, "andi_rc", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_SET_CR0}, + {29, "andis_rc", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_SET_CR0}, + + {32, "lwz", OpType::Load, 1, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE}, + {33, "lwzu", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE}, + {34, "lbz", OpType::Load, 1, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE}, + {35, "lbzu", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE}, + {40, "lhz", OpType::Load, 1, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE}, + {41, "lhzu", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE}, + + {42, "lha", OpType::Load, 1, FL_OUT_D | FL_IN_A0 | FL_LOADSTORE}, + {43, "lhau", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_A | FL_LOADSTORE}, + + {44, "sth", OpType::Store, 1, FL_IN_A0 | FL_IN_S | FL_LOADSTORE}, + {45, "sthu", OpType::Store, 1, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE}, + {36, "stw", OpType::Store, 1, FL_IN_A0 | FL_IN_S | FL_LOADSTORE}, + {37, "stwu", OpType::Store, 1, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE}, + {38, "stb", OpType::Store, 1, FL_IN_A0 | FL_IN_S | FL_LOADSTORE}, + {39, "stbu", OpType::Store, 1, FL_OUT_A | FL_IN_A | FL_IN_S | FL_LOADSTORE}, + + {46, "lmw", OpType::System, 11, FL_EVIL | FL_IN_A0 | FL_LOADSTORE}, + {47, "stmw", OpType::System, 11, FL_EVIL | FL_IN_A0 | FL_LOADSTORE}, + + {48, "lfs", OpType::LoadFP, 1, FL_OUT_FLOAT_D | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}, + {49, "lfsu", OpType::LoadFP, 1, + FL_OUT_FLOAT_D | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}, + {50, "lfd", OpType::LoadFP, 1, FL_INOUT_FLOAT_D | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}, + {51, "lfdu", OpType::LoadFP, 1, + FL_INOUT_FLOAT_D | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}, + + {52, "stfs", OpType::StoreFP, 1, FL_IN_FLOAT_S | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE}, + {53, "stfsu", OpType::StoreFP, 1, + FL_IN_FLOAT_S | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}, + {54, "stfd", OpType::StoreFP, 1, FL_IN_FLOAT_S | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE}, + {55, "stfdu", OpType::StoreFP, 1, + FL_IN_FLOAT_S | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE}, + + {56, "psq_l", OpType::LoadPS, 1, + FL_OUT_FLOAT_D | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION}, + {57, "psq_lu", OpType::LoadPS, 1, + FL_OUT_FLOAT_D | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION}, + {60, "psq_st", OpType::StorePS, 1, + FL_IN_FLOAT_S | FL_IN_A0 | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION}, + {61, "psq_stu", OpType::StorePS, 1, + FL_IN_FLOAT_S | FL_OUT_A | FL_IN_A | FL_USE_FPU | FL_LOADSTORE | FL_PROGRAMEXCEPTION}, + + // missing: 0, 1, 2, 5, 6, 9, 22, 30, 62, 58 +}}; + +constexpr std::array s_table4{{ + // SUBOP10 + {0, "ps_cmpu0", OpType::PS, 1, + FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | + FL_FLOAT_EXCEPTION}, + {32, "ps_cmpo0", OpType::PS, 1, + FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | + FL_FLOAT_EXCEPTION}, + {40, "ps_neg", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | + FL_PROGRAMEXCEPTION}, + {136, "ps_nabs", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | + FL_PROGRAMEXCEPTION}, + {264, "ps_abs", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | + FL_PROGRAMEXCEPTION}, + {64, "ps_cmpu1", OpType::PS, 1, + FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | + FL_FLOAT_EXCEPTION}, + {72, "ps_mr", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | + FL_PROGRAMEXCEPTION}, + {96, "ps_cmpo1", OpType::PS, 1, + FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_PROGRAMEXCEPTION | + FL_FLOAT_EXCEPTION}, + {528, "ps_merge00", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | + FL_PROGRAMEXCEPTION}, + {560, "ps_merge01", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | + FL_PROGRAMEXCEPTION}, + {592, "ps_merge10", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | + FL_PROGRAMEXCEPTION}, + {624, "ps_merge11", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_IN_FLOAT_AB_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | + FL_PROGRAMEXCEPTION}, + + {1014, "dcbz_l", OpType::System, 1, FL_IN_A0B | FL_LOADSTORE | FL_PROGRAMEXCEPTION}, +}}; + +constexpr std::array s_table4_2{{ + {10, "ps_sum0", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + {11, "ps_sum1", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + {12, "ps_muls0", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + {13, "ps_muls1", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + {14, "ps_madds0", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + {15, "ps_madds1", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + {18, "ps_div", OpType::PS, 17, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION | FL_FLOAT_DIV}, + {20, "ps_sub", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + {21, "ps_add", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + {23, "ps_sel", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_IN_FLOAT_BC_BITEXACT | FL_RC_BIT_F | FL_USE_FPU | + FL_PROGRAMEXCEPTION}, + {24, "ps_res", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | + FL_FLOAT_EXCEPTION | FL_FLOAT_DIV}, + {25, "ps_mul", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + {26, "ps_rsqrte", OpType::PS, 2, + FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_PROGRAMEXCEPTION | + FL_FLOAT_EXCEPTION | FL_FLOAT_DIV}, + {28, "ps_msub", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + {29, "ps_madd", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + {30, "ps_nmsub", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + {31, "ps_nmadd", OpType::PS, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, +}}; + +constexpr std::array s_table4_3{{ + {6, "psq_lx", OpType::LoadPS, 1, FL_OUT_FLOAT_D | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE}, + {7, "psq_stx", OpType::StorePS, 1, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE}, + {38, "psq_lux", OpType::LoadPS, 1, + FL_OUT_FLOAT_D | FL_OUT_A | FL_IN_AB | FL_USE_FPU | FL_LOADSTORE}, + {39, "psq_stux", OpType::StorePS, 1, + FL_IN_FLOAT_S | FL_OUT_A | FL_IN_AB | FL_USE_FPU | FL_LOADSTORE}, +}}; + +constexpr std::array s_table19{{ + {528, "bcctrx", OpType::Branch, 1, FL_ENDBLOCK | FL_READ_CR_BI}, + {16, "bclrx", OpType::Branch, 1, FL_ENDBLOCK | FL_READ_CR_BI}, + {257, "crand", OpType::CR, 1, FL_EVIL}, + {129, "crandc", OpType::CR, 1, FL_EVIL}, + {289, "creqv", OpType::CR, 1, FL_EVIL}, + {225, "crnand", OpType::CR, 1, FL_EVIL}, + {33, "crnor", OpType::CR, 1, FL_EVIL}, + {449, "cror", OpType::CR, 1, FL_EVIL}, + {417, "crorc", OpType::CR, 1, FL_EVIL}, + {193, "crxor", OpType::CR, 1, FL_EVIL}, + + {150, "isync", OpType::InstructionCache, 1, FL_EVIL}, + {0, "mcrf", OpType::System, 1, FL_EVIL | FL_SET_CRn | FL_READ_CRn}, + + {50, "rfi", OpType::System, 2, FL_ENDBLOCK | FL_CHECKEXCEPTIONS | FL_PROGRAMEXCEPTION}, +}}; + +constexpr std::array s_table31{{ + {266, "addx", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_RC_BIT}, + {778, "addox", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE}, + {10, "addcx", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}, + {522, "addcox", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT | FL_SET_OE}, + {138, "addex", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}, + {650, "addeox", OpType::Integer, 1, + FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE}, + {234, "addmex", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT}, + {746, "addmeox", OpType::Integer, 1, + FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE}, + {202, "addzex", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT}, + {714, "addzeox", OpType::Integer, 1, + FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE}, + {491, "divwx", OpType::Integer, 40, FL_OUT_D | FL_IN_AB | FL_RC_BIT}, + {1003, "divwox", OpType::Integer, 40, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE}, + {459, "divwux", OpType::Integer, 40, FL_OUT_D | FL_IN_AB | FL_RC_BIT}, + {971, "divwuox", OpType::Integer, 40, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE}, + {75, "mulhwx", OpType::Integer, 5, FL_OUT_D | FL_IN_AB | FL_RC_BIT}, + {11, "mulhwux", OpType::Integer, 5, FL_OUT_D | FL_IN_AB | FL_RC_BIT}, + {235, "mullwx", OpType::Integer, 5, FL_OUT_D | FL_IN_AB | FL_RC_BIT}, + {747, "mullwox", OpType::Integer, 5, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE}, + {104, "negx", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_RC_BIT}, + {616, "negox", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_RC_BIT | FL_SET_OE}, + {40, "subfx", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_RC_BIT}, + {552, "subfox", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_RC_BIT | FL_SET_OE}, + {8, "subfcx", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}, + {520, "subfcox", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT | FL_SET_OE}, + {136, "subfex", OpType::Integer, 1, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}, + {648, "subfeox", OpType::Integer, 1, + FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE}, + {232, "subfmex", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT}, + {744, "subfmeox", OpType::Integer, 1, + FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE}, + {200, "subfzex", OpType::Integer, 1, FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT}, + {712, "subfzeox", OpType::Integer, 1, + FL_OUT_D | FL_IN_A | FL_READ_CA | FL_SET_CA | FL_RC_BIT | FL_SET_OE}, + + {28, "andx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT}, + {60, "andcx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT}, + {444, "orx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT}, + {124, "norx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT}, + {316, "xorx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT}, + {412, "orcx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT}, + {476, "nandx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT}, + {284, "eqvx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT}, + {0, "cmp", OpType::Integer, 1, FL_IN_AB | FL_SET_CRn}, + {32, "cmpl", OpType::Integer, 1, FL_IN_AB | FL_SET_CRn}, + {26, "cntlzwx", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_RC_BIT}, + {922, "extshx", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_RC_BIT}, + {954, "extsbx", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_RC_BIT}, + {536, "srwx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT}, + {792, "srawx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_SET_CA | FL_RC_BIT}, + {824, "srawix", OpType::Integer, 1, FL_OUT_A | FL_IN_S | FL_SET_CA | FL_RC_BIT}, + {24, "slwx", OpType::Integer, 1, FL_OUT_A | FL_IN_SB | FL_RC_BIT}, + + {54, "dcbst", OpType::DataCache, 5, FL_IN_A0B | FL_LOADSTORE}, + {86, "dcbf", OpType::DataCache, 5, FL_IN_A0B | FL_LOADSTORE}, + {246, "dcbtst", OpType::DataCache, 2, 0}, + {278, "dcbt", OpType::DataCache, 2, 0}, + {470, "dcbi", OpType::DataCache, 5, FL_IN_A0B | FL_LOADSTORE | FL_PROGRAMEXCEPTION}, + {758, "dcba", OpType::DataCache, 5, 0}, + {1014, "dcbz", OpType::DataCache, 5, FL_IN_A0B | FL_LOADSTORE}, + + // load word + {23, "lwzx", OpType::Load, 1, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE}, + {55, "lwzux", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE}, + + // load halfword + {279, "lhzx", OpType::Load, 1, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE}, + {311, "lhzux", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE}, + + // load halfword signextend + {343, "lhax", OpType::Load, 1, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE}, + {375, "lhaux", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE}, + + // load byte + {87, "lbzx", OpType::Load, 1, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE}, + {119, "lbzux", OpType::Load, 1, FL_OUT_D | FL_OUT_A | FL_IN_AB | FL_LOADSTORE}, + + // load byte reverse + {534, "lwbrx", OpType::Load, 1, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE}, + {790, "lhbrx", OpType::Load, 1, FL_OUT_D | FL_IN_A0B | FL_LOADSTORE}, + + // Conditional load/store (Wii SMP) + {150, "stwcxd", OpType::Store, 1, FL_EVIL | FL_IN_S | FL_IN_A0B | FL_SET_CR0 | FL_LOADSTORE}, + {20, "lwarx", OpType::Load, 1, FL_EVIL | FL_OUT_D | FL_IN_A0B | FL_SET_CR0 | FL_LOADSTORE}, + + // load string (Inst these) + {533, "lswx", OpType::Load, 1, FL_EVIL | FL_IN_A0B | FL_OUT_D | FL_LOADSTORE}, + {597, "lswi", OpType::Load, 1, FL_EVIL | FL_IN_A0 | FL_OUT_D | FL_LOADSTORE}, + + // store word + {151, "stwx", OpType::Store, 1, FL_IN_S | FL_IN_A0B | FL_LOADSTORE}, + {183, "stwux", OpType::Store, 1, FL_IN_S | FL_OUT_A | FL_IN_AB | FL_LOADSTORE}, + + // store halfword + {407, "sthx", OpType::Store, 1, FL_IN_S | FL_IN_A0B | FL_LOADSTORE}, + {439, "sthux", OpType::Store, 1, FL_IN_S | FL_OUT_A | FL_IN_AB | FL_LOADSTORE}, + + // store byte + {215, "stbx", OpType::Store, 1, FL_IN_S | FL_IN_A0B | FL_LOADSTORE}, + {247, "stbux", OpType::Store, 1, FL_IN_S | FL_OUT_A | FL_IN_AB | FL_LOADSTORE}, + + // store bytereverse + {662, "stwbrx", OpType::Store, 1, FL_IN_S | FL_IN_A0B | FL_LOADSTORE}, + {918, "sthbrx", OpType::Store, 1, FL_IN_S | FL_IN_A0B | FL_LOADSTORE}, + + {661, "stswx", OpType::Store, 1, FL_EVIL | FL_IN_A0B | FL_LOADSTORE}, + {725, "stswi", OpType::Store, 1, FL_EVIL | FL_IN_A0 | FL_LOADSTORE}, + + // fp load/store + {535, "lfsx", OpType::LoadFP, 1, FL_OUT_FLOAT_D | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE}, + {567, "lfsux", OpType::LoadFP, 1, + FL_OUT_FLOAT_D | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE}, + {599, "lfdx", OpType::LoadFP, 1, FL_INOUT_FLOAT_D | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE}, + {631, "lfdux", OpType::LoadFP, 1, + FL_INOUT_FLOAT_D | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE}, + + {663, "stfsx", OpType::StoreFP, 1, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE}, + {695, "stfsux", OpType::StoreFP, 1, + FL_IN_FLOAT_S | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE}, + {727, "stfdx", OpType::StoreFP, 1, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE}, + {759, "stfdux", OpType::StoreFP, 1, + FL_IN_FLOAT_S | FL_IN_AB | FL_OUT_A | FL_USE_FPU | FL_LOADSTORE}, + {983, "stfiwx", OpType::StoreFP, 1, FL_IN_FLOAT_S | FL_IN_A0B | FL_USE_FPU | FL_LOADSTORE}, + + {19, "mfcr", OpType::System, 1, FL_OUT_D | FL_READ_ALL_CR}, + {83, "mfmsr", OpType::System, 1, FL_OUT_D | FL_PROGRAMEXCEPTION}, + {144, "mtcrf", OpType::System, 1, FL_IN_S | FL_SET_ALL_CR | FL_READ_ALL_CR}, + {146, "mtmsr", OpType::System, 1, + FL_IN_S | FL_ENDBLOCK | FL_PROGRAMEXCEPTION | FL_FLOAT_EXCEPTION}, + {210, "mtsr", OpType::System, 1, FL_IN_S | FL_PROGRAMEXCEPTION}, + {242, "mtsrin", OpType::System, 1, FL_IN_SB | FL_PROGRAMEXCEPTION}, + {339, "mfspr", OpType::SPR, 1, FL_OUT_D | FL_PROGRAMEXCEPTION}, + {467, "mtspr", OpType::SPR, 2, FL_IN_S | FL_PROGRAMEXCEPTION}, + {371, "mftb", OpType::System, 1, FL_OUT_D | FL_TIMER | FL_PROGRAMEXCEPTION}, + {512, "mcrxr", OpType::System, 1, FL_SET_CRn | FL_READ_CA | FL_SET_CA}, + {595, "mfsr", OpType::System, 3, FL_OUT_D | FL_PROGRAMEXCEPTION}, + {659, "mfsrin", OpType::System, 3, FL_OUT_D | FL_IN_B | FL_PROGRAMEXCEPTION}, + + {4, "tw", OpType::System, 2, FL_IN_AB | FL_ENDBLOCK}, + {598, "sync", OpType::System, 3, 0}, + {982, "icbi", OpType::System, 4, FL_IN_A0B | FL_ENDBLOCK | FL_LOADSTORE}, + + // Unused instructions on GC + {310, "eciwx", OpType::System, 1, FL_IN_A0B | FL_OUT_D | FL_LOADSTORE}, + {438, "ecowx", OpType::System, 1, FL_IN_A0B | FL_IN_S | FL_LOADSTORE}, + {854, "eieio", OpType::System, 1, 0}, + {306, "tlbie", OpType::System, 1, FL_IN_B | FL_PROGRAMEXCEPTION}, + {566, "tlbsync", OpType::System, 1, FL_PROGRAMEXCEPTION}, +}}; + +constexpr std::array s_table59{{ + {18, "fdivsx", OpType::SingleFP, 17, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | + FL_FLOAT_DIV}, // TODO + {20, "fsubsx", OpType::SingleFP, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION}, + {21, "faddsx", OpType::SingleFP, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION}, + {24, "fresx", OpType::SingleFP, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION | + FL_FLOAT_DIV}, + {25, "fmulsx", OpType::SingleFP, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION}, + {28, "fmsubsx", OpType::SingleFP, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_FLOAT_EXCEPTION}, + {29, "fmaddsx", OpType::SingleFP, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_FLOAT_EXCEPTION}, + {30, "fnmsubsx", OpType::SingleFP, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_FLOAT_EXCEPTION}, + {31, "fnmaddsx", OpType::SingleFP, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_FLOAT_EXCEPTION}, +}}; + +constexpr std::array s_table63{{ + {264, "fabsx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU}, + + // FIXME: fcmp modifies the FPRF flags, but if the flags are clobbered later, + // we don't actually need to calculate or store them here. So FL_READ_FPRF and FL_SET_FPRF is + // not an ideal representation of fcmp's effect on FPRF flags and might result in slightly + // sub-optimal code. + {32, "fcmpo", OpType::DoubleFP, 1, + FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION}, + {0, "fcmpu", OpType::DoubleFP, 1, + FL_IN_FLOAT_AB | FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION}, + + {14, "fctiwx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_FLOAT_EXCEPTION}, + {15, "fctiwzx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_FLOAT_EXCEPTION}, + {72, "fmrx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_IN_FLOAT_B_BITEXACT | FL_RC_BIT_F | FL_USE_FPU}, + {136, "fnabsx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_IN_FLOAT_B_BITEXACT | FL_USE_FPU}, + {40, "fnegx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_IN_FLOAT_B_BITEXACT | FL_USE_FPU}, + {12, "frspx", OpType::DoubleFP, 1, + FL_OUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | FL_FLOAT_EXCEPTION}, + + {64, "mcrfs", OpType::SystemFP, 1, FL_SET_CRn | FL_USE_FPU | FL_READ_FPRF}, + {583, "mffsx", OpType::SystemFP, 1, FL_RC_BIT_F | FL_INOUT_FLOAT_D | FL_USE_FPU | FL_READ_FPRF}, + {70, "mtfsb0x", OpType::SystemFP, 3, FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF}, + {38, "mtfsb1x", OpType::SystemFP, 3, + FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION}, + {134, "mtfsfix", OpType::SystemFP, 3, + FL_RC_BIT_F | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION}, + {711, "mtfsfx", OpType::SystemFP, 3, + FL_RC_BIT_F | FL_IN_FLOAT_B | FL_USE_FPU | FL_READ_FPRF | FL_SET_FPRF | FL_FLOAT_EXCEPTION}, +}}; + +constexpr std::array s_table63_2{{ + {18, "fdivx", OpType::DoubleFP, 31, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_FLOAT_EXCEPTION | FL_FLOAT_DIV}, + {20, "fsubx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_FLOAT_EXCEPTION}, + {21, "faddx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_AB | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_FLOAT_EXCEPTION}, + {23, "fselx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_IN_FLOAT_BC_BITEXACT | FL_RC_BIT_F | FL_USE_FPU}, + {25, "fmulx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_AC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_FLOAT_EXCEPTION}, + {26, "frsqrtex", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_B | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_FLOAT_EXCEPTION | FL_FLOAT_DIV}, + {28, "fmsubx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_FLOAT_EXCEPTION}, + {29, "fmaddx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_FLOAT_EXCEPTION}, + {30, "fnmsubx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_FLOAT_EXCEPTION}, + {31, "fnmaddx", OpType::DoubleFP, 1, + FL_INOUT_FLOAT_D | FL_IN_FLOAT_ABC | FL_RC_BIT_F | FL_USE_FPU | FL_SET_FPRF | + FL_FLOAT_EXCEPTION}, +}}; + +constexpr size_t TOTAL_INSTRUCTION_COUNT = + 1 + s_primary_table.size() + s_table4_2.size() + s_table4_3.size() + s_table4.size() + + s_table31.size() + s_table19.size() + s_table59.size() + s_table63.size() + s_table63_2.size(); + +struct Tables +{ + std::array all_instructions{}; + u32 unknown_op_info; + std::array primary_table{}; + std::array table4{}; + std::array table19{}; + std::array table31{}; + std::array table59{}; + std::array table63{}; +}; +} // namespace + +static std::array s_all_instructions_stats; + +constexpr Tables s_tables = []() consteval +{ + Tables tables{}; + + u32 counter = 0; + auto make_info = [&](const GekkoOPTemplate& inst) consteval->u32 + { + ASSERT(counter < TOTAL_INSTRUCTION_COUNT); + GekkoOPInfo* info = &tables.all_instructions[counter]; + info->opname = inst.opname; + info->flags = inst.flags; + info->type = inst.type; + info->num_cycles = inst.num_cycles; + info->stats = &s_all_instructions_stats[counter]; + return counter++; + }; + + u32 unknown_op_info = make_info(s_unknown_op_info); + tables.unknown_op_info = unknown_op_info; + + Common::Fill(tables.primary_table, unknown_op_info); + for (auto& tpl : s_primary_table) + { + ASSERT(tables.primary_table[tpl.opcode] == unknown_op_info); + tables.primary_table[tpl.opcode] = make_info(tpl); + }; + + Common::Fill(tables.table4, unknown_op_info); + + for (const auto& tpl : s_table4_2) + { + u32 info = make_info(tpl); + for (u32 i = 0; i < 32; i++) + { + const u32 fill = i << 5; + const u32 op = fill + tpl.opcode; + ASSERT(tables.table4[op] == unknown_op_info); + tables.table4[op] = info; + } + } + + for (const auto& tpl : s_table4_3) + { + u32 info = make_info(tpl); + for (u32 i = 0; i < 16; i++) + { + const u32 fill = i << 6; + const u32 op = fill + tpl.opcode; + ASSERT(tables.table4[op] == unknown_op_info); + tables.table4[op] = info; + } + } + + for (const auto& tpl : s_table4) + { + const u32 op = tpl.opcode; + ASSERT(tables.table4[op] == unknown_op_info); + tables.table4[op] = make_info(tpl); + } + + Common::Fill(tables.table19, unknown_op_info); + for (auto& tpl : s_table19) + { + ASSERT(tables.table19[tpl.opcode] == unknown_op_info); + tables.table19[tpl.opcode] = make_info(tpl); + }; + + Common::Fill(tables.table31, unknown_op_info); + for (auto& tpl : s_table31) + { + ASSERT(tables.table31[tpl.opcode] == unknown_op_info); + tables.table31[tpl.opcode] = make_info(tpl); + }; + + Common::Fill(tables.table59, unknown_op_info); + for (auto& tpl : s_table59) + { + ASSERT(tables.table59[tpl.opcode] == unknown_op_info); + tables.table59[tpl.opcode] = make_info(tpl); + }; + + Common::Fill(tables.table63, unknown_op_info); + for (auto& tpl : s_table63) + { + ASSERT(tables.table63[tpl.opcode] == unknown_op_info); + tables.table63[tpl.opcode] = make_info(tpl); + }; + + for (const auto& tpl : s_table63_2) + { + u32 info = make_info(tpl); + for (u32 i = 0; i < 32; i++) + { + const u32 fill = i << 5; + const u32 op = fill + tpl.opcode; + ASSERT(tables.table63[op] == unknown_op_info); + tables.table63[op] = info; + } + } + + ASSERT(counter == TOTAL_INSTRUCTION_COUNT); + return tables; +} +(); + +const GekkoOPInfo* GetOpInfo(UGeckoInstruction inst) +{ + const GekkoOPInfo* info = &s_tables.all_instructions[s_tables.primary_table[inst.OPCD]]; if (info->type == OpType::Subtable) { switch (inst.OPCD) { case 4: - return m_infoTable4[inst.SUBOP10]; + return &s_tables.all_instructions[s_tables.table4[inst.SUBOP10]]; case 19: - return m_infoTable19[inst.SUBOP10]; + return &s_tables.all_instructions[s_tables.table19[inst.SUBOP10]]; case 31: - return m_infoTable31[inst.SUBOP10]; + return &s_tables.all_instructions[s_tables.table31[inst.SUBOP10]]; case 59: - return m_infoTable59[inst.SUBOP5]; + return &s_tables.all_instructions[s_tables.table59[inst.SUBOP5]]; case 63: - return m_infoTable63[inst.SUBOP10]; + return &s_tables.all_instructions[s_tables.table63[inst.SUBOP10]]; default: ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid subtable op {:08x} @ {:08x}", inst.hex, PowerPC::ppcState.pc); - return nullptr; + return &s_tables.all_instructions[s_tables.unknown_op_info]; } } else @@ -62,50 +642,15 @@ GekkoOPInfo* GetOpInfo(UGeckoInstruction inst) { ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid op {:08x} @ {:08x}", inst.hex, PowerPC::ppcState.pc); - return nullptr; + return &s_tables.all_instructions[s_tables.unknown_op_info]; } - return m_infoTable[inst.OPCD]; - } -} - -Interpreter::Instruction GetInterpreterOp(UGeckoInstruction inst) -{ - const GekkoOPInfo* info = m_infoTable[inst.OPCD]; - if (info->type == OpType::Subtable) - { - switch (inst.OPCD) - { - case 4: - return Interpreter::m_op_table4[inst.SUBOP10]; - case 19: - return Interpreter::m_op_table19[inst.SUBOP10]; - case 31: - return Interpreter::m_op_table31[inst.SUBOP10]; - case 59: - return Interpreter::m_op_table59[inst.SUBOP5]; - case 63: - return Interpreter::m_op_table63[inst.SUBOP10]; - default: - ASSERT_MSG(POWERPC, 0, "GetInterpreterOp - invalid subtable op {:08x} @ {:08x}", inst.hex, - PowerPC::ppcState.pc); - return nullptr; - } - } - else - { - if (info->type == OpType::Invalid) - { - ASSERT_MSG(POWERPC, 0, "GetInterpreterOp - invalid op {:08x} @ {:08x}", inst.hex, - PowerPC::ppcState.pc); - return nullptr; - } - return Interpreter::m_op_table[inst.OPCD]; + return info; } } bool UsesFPU(UGeckoInstruction inst) { - GekkoOPInfo* const info = GetOpInfo(inst); + const GekkoOPInfo* const info = GetOpInfo(inst); return (info->flags & FL_USE_FPU) != 0; } @@ -123,28 +668,25 @@ std::vector rsplocations; const char* GetInstructionName(UGeckoInstruction inst) { const GekkoOPInfo* info = GetOpInfo(inst); - return info ? info->opname : nullptr; + return info->opname; } bool IsValidInstruction(UGeckoInstruction inst) { const GekkoOPInfo* info = GetOpInfo(inst); - return info != nullptr && info->type != OpType::Unknown; + return info->type != OpType::Invalid && info->type != OpType::Unknown; } void CountInstruction(UGeckoInstruction inst) { - GekkoOPInfo* info = GetOpInfo(inst); - if (info) - { - info->runCount++; - } + const GekkoOPInfo* info = GetOpInfo(inst); + info->stats->run_count++; } -void CountInstructionCompile(GekkoOPInfo* info, u32 pc) +void CountInstructionCompile(const GekkoOPInfo* info, u32 pc) { - info->compileCount++; - info->lastUse = pc; + info->stats->compile_count++; + info->stats->last_use = pc; #ifdef OPLOG if (!strcmp(info->opname, OP_TO_LOG)) @@ -157,12 +699,11 @@ void CountInstructionCompile(GekkoOPInfo* info, u32 pc) void PrintInstructionRunCounts() { typedef std::pair OpInfo; - std::vector temp; - temp.reserve(m_numInstructions); - for (size_t i = 0; i < m_numInstructions; ++i) + std::array temp; + for (size_t i = 0; i < TOTAL_INSTRUCTION_COUNT; i++) { - GekkoOPInfo* pInst = m_allInstructions[i]; - temp.emplace_back(pInst->opname, pInst->runCount); + const GekkoOPInfo& info = s_tables.all_instructions[i]; + temp[i] = std::make_pair(info.opname, info.stats->run_count); } std::sort(temp.begin(), temp.end(), [](const OpInfo& a, const OpInfo& b) { return a.second > b.second; }); @@ -172,7 +713,7 @@ void PrintInstructionRunCounts() if (inst.second == 0) break; - DEBUG_LOG_FMT(POWERPC, "{} : {}", inst.first, inst.second); + INFO_LOG_FMT(POWERPC, "{} : {}", inst.first, inst.second); } } @@ -181,24 +722,24 @@ void LogCompiledInstructions() static unsigned int time = 0; File::IOFile f(fmt::format("{}inst_log{}.txt", File::GetUserPath(D_LOGS_IDX), time), "w"); - for (size_t i = 0; i < m_numInstructions; i++) + for (size_t i = 0; i < TOTAL_INSTRUCTION_COUNT; i++) { - GekkoOPInfo* pInst = m_allInstructions[i]; - if (pInst->compileCount > 0) + const GekkoOPInfo& info = s_tables.all_instructions[i]; + if (info.stats->compile_count > 0) { - f.WriteString(fmt::format("{0}\t{1}\t{2}\t{3:08x}\n", pInst->opname, pInst->compileCount, - pInst->runCount, pInst->lastUse)); + f.WriteString(fmt::format("{0}\t{1}\t{2}\t{3:08x}\n", info.opname, info.stats->compile_count, + info.stats->run_count, info.stats->last_use)); } } f.Open(fmt::format("{}inst_not{}.txt", File::GetUserPath(D_LOGS_IDX), time), "w"); - for (size_t i = 0; i < m_numInstructions; i++) + for (size_t i = 0; i < TOTAL_INSTRUCTION_COUNT; i++) { - GekkoOPInfo* pInst = m_allInstructions[i]; - if (pInst->compileCount == 0) + const GekkoOPInfo& info = s_tables.all_instructions[i]; + if (info.stats->compile_count == 0) { - f.WriteString( - fmt::format("{0}\t{1}\t{2}\n", pInst->opname, pInst->compileCount, pInst->runCount)); + f.WriteString(fmt::format("{0}\t{1}\t{2}\n", info.opname, info.stats->compile_count, + info.stats->run_count)); } } diff --git a/Source/Core/Core/PowerPC/PPCTables.h b/Source/Core/Core/PowerPC/PPCTables.h index d6ea5c7791..5b610e5663 100644 --- a/Source/Core/Core/PowerPC/PPCTables.h +++ b/Source/Core/Core/PowerPC/PPCTables.h @@ -5,6 +5,7 @@ #include #include +#include #include "Common/CommonTypes.h" #include "Core/PowerPC/Gekko.h" @@ -98,36 +99,32 @@ enum class OpType Unknown, }; +struct GekkoOPStats +{ + u64 run_count; + u32 compile_count; + u32 last_use; +}; + struct GekkoOPInfo { const char* opname; OpType type; + u32 num_cycles; u64 flags; - int numCycles; - u64 runCount; - int compileCount; - u32 lastUse; + // Mutable + GekkoOPStats* stats; }; -extern std::array m_infoTable; -extern std::array m_infoTable4; -extern std::array m_infoTable19; -extern std::array m_infoTable31; -extern std::array m_infoTable59; -extern std::array m_infoTable63; - -extern std::array m_allInstructions; -extern size_t m_numInstructions; namespace PPCTables { -GekkoOPInfo* GetOpInfo(UGeckoInstruction inst); -Interpreter::Instruction GetInterpreterOp(UGeckoInstruction inst); +const GekkoOPInfo* GetOpInfo(UGeckoInstruction inst); bool IsValidInstruction(UGeckoInstruction inst); bool UsesFPU(UGeckoInstruction inst); void CountInstruction(UGeckoInstruction inst); -void CountInstructionCompile(GekkoOPInfo* info, u32 pc); +void CountInstructionCompile(const GekkoOPInfo* info, u32 pc); void PrintInstructionRunCounts(); void LogCompiledInstructions(); const char* GetInstructionName(UGeckoInstruction inst);