mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-04-28 21:08:04 +03:00
746 lines
32 KiB
C++
746 lines
32 KiB
C++
// Copyright 2008 Dolphin Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include "Core/PowerPC/PPCTables.h"
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <cstdio>
|
|
#include <vector>
|
|
|
|
#include <fmt/format.h>
|
|
|
|
#include "Common/Assert.h"
|
|
#include "Common/CommonTypes.h"
|
|
#include "Common/FileUtil.h"
|
|
#include "Common/IOFile.h"
|
|
#include "Common/Logging/Log.h"
|
|
#include "Common/StringUtil.h"
|
|
|
|
#include "Core/PowerPC/PowerPC.h"
|
|
|
|
namespace PPCTables
|
|
{
|
|
namespace
|
|
{
|
|
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<GekkoOPTemplate, 54> 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_IN_A0 | FL_LOADSTORE},
|
|
{47, "stmw", OpType::System, 11, 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<GekkoOPTemplate, 13> 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<GekkoOPTemplate, 17> 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<GekkoOPTemplate, 4> 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<GekkoOPTemplate, 13> 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, 0},
|
|
{129, "crandc", OpType::CR, 1, 0},
|
|
{289, "creqv", OpType::CR, 1, 0},
|
|
{225, "crnand", OpType::CR, 1, 0},
|
|
{33, "crnor", OpType::CR, 1, 0},
|
|
{449, "cror", OpType::CR, 1, 0},
|
|
{417, "crorc", OpType::CR, 1, 0},
|
|
{193, "crxor", OpType::CR, 1, 0},
|
|
|
|
{150, "isync", OpType::InstructionCache, 1, FL_NO_REORDER},
|
|
{0, "mcrf", OpType::System, 1, FL_SET_CRn | FL_READ_CRn},
|
|
|
|
{50, "rfi", OpType::System, 2, FL_ENDBLOCK | FL_CHECKEXCEPTIONS | FL_PROGRAMEXCEPTION},
|
|
}};
|
|
|
|
constexpr std::array<GekkoOPTemplate, 107> 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_IN_S | FL_IN_A0B | FL_SET_CR0 | FL_LOADSTORE},
|
|
{20, "lwarx", OpType::Load, 1, FL_OUT_D | FL_IN_A0B | FL_SET_CR0 | FL_LOADSTORE},
|
|
|
|
// load string (Inst these)
|
|
{533, "lswx", OpType::Load, 1, FL_IN_A0B | FL_OUT_D | FL_LOADSTORE},
|
|
{597, "lswi", OpType::Load, 1, 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_IN_A0B | FL_LOADSTORE},
|
|
{725, "stswi", OpType::Store, 1, 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_ENDBLOCK | 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<GekkoOPTemplate, 9> 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<GekkoOPTemplate, 15> 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<GekkoOPTemplate, 10> 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<GekkoOPInfo, TOTAL_INSTRUCTION_COUNT> all_instructions{};
|
|
u32 unknown_op_info;
|
|
std::array<u32, 64> primary_table{};
|
|
std::array<u32, 1024> table4{};
|
|
std::array<u32, 1024> table19{};
|
|
std::array<u32, 1024> table31{};
|
|
std::array<u32, 32> table59{};
|
|
std::array<u32, 1024> table63{};
|
|
};
|
|
} // namespace
|
|
|
|
static std::array<GekkoOPStats, TOTAL_INSTRUCTION_COUNT> 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;
|
|
|
|
tables.primary_table.fill(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);
|
|
};
|
|
|
|
tables.table4.fill(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);
|
|
}
|
|
|
|
tables.table19.fill(unknown_op_info);
|
|
for (auto& tpl : s_table19)
|
|
{
|
|
ASSERT(tables.table19[tpl.opcode] == unknown_op_info);
|
|
tables.table19[tpl.opcode] = make_info(tpl);
|
|
};
|
|
|
|
tables.table31.fill(unknown_op_info);
|
|
for (auto& tpl : s_table31)
|
|
{
|
|
ASSERT(tables.table31[tpl.opcode] == unknown_op_info);
|
|
tables.table31[tpl.opcode] = make_info(tpl);
|
|
};
|
|
|
|
tables.table59.fill(unknown_op_info);
|
|
for (auto& tpl : s_table59)
|
|
{
|
|
ASSERT(tables.table59[tpl.opcode] == unknown_op_info);
|
|
tables.table59[tpl.opcode] = make_info(tpl);
|
|
};
|
|
|
|
tables.table63.fill(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, u32 pc)
|
|
{
|
|
const GekkoOPInfo* info = &s_tables.all_instructions[s_tables.primary_table[inst.OPCD]];
|
|
if (info->type == OpType::Subtable)
|
|
{
|
|
switch (inst.OPCD)
|
|
{
|
|
case 4:
|
|
return &s_tables.all_instructions[s_tables.table4[inst.SUBOP10]];
|
|
case 19:
|
|
return &s_tables.all_instructions[s_tables.table19[inst.SUBOP10]];
|
|
case 31:
|
|
return &s_tables.all_instructions[s_tables.table31[inst.SUBOP10]];
|
|
case 59:
|
|
return &s_tables.all_instructions[s_tables.table59[inst.SUBOP5]];
|
|
case 63:
|
|
return &s_tables.all_instructions[s_tables.table63[inst.SUBOP10]];
|
|
default:
|
|
ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid subtable op {:08x} @ {:08x}", inst.hex, pc);
|
|
return &s_tables.all_instructions[s_tables.unknown_op_info];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (info->type == OpType::Invalid)
|
|
{
|
|
ASSERT_MSG(POWERPC, 0, "GetOpInfo - invalid op {:08x} @ {:08x}", inst.hex, pc);
|
|
return &s_tables.all_instructions[s_tables.unknown_op_info];
|
|
}
|
|
return info;
|
|
}
|
|
}
|
|
|
|
// #define OPLOG
|
|
// #define OP_TO_LOG "mtfsb0x"
|
|
|
|
#ifdef OPLOG
|
|
namespace
|
|
{
|
|
std::vector<u32> rsplocations;
|
|
}
|
|
#endif
|
|
|
|
const char* GetInstructionName(UGeckoInstruction inst, u32 pc)
|
|
{
|
|
const GekkoOPInfo* info = GetOpInfo(inst, pc);
|
|
return info->opname;
|
|
}
|
|
|
|
bool IsValidInstruction(UGeckoInstruction inst, u32 pc)
|
|
{
|
|
const GekkoOPInfo* info = GetOpInfo(inst, pc);
|
|
return info->type != OpType::Invalid && info->type != OpType::Unknown;
|
|
}
|
|
|
|
void CountInstruction(UGeckoInstruction inst, u32 pc)
|
|
{
|
|
const GekkoOPInfo* info = GetOpInfo(inst, pc);
|
|
info->stats->run_count++;
|
|
}
|
|
|
|
void CountInstructionCompile(const GekkoOPInfo* info, u32 pc)
|
|
{
|
|
info->stats->compile_count++;
|
|
info->stats->last_use = pc;
|
|
|
|
#ifdef OPLOG
|
|
if (!strcmp(info->opname, OP_TO_LOG))
|
|
{
|
|
rsplocations.push_back(pc);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void PrintInstructionRunCounts()
|
|
{
|
|
typedef std::pair<const char*, u64> OpInfo;
|
|
std::array<OpInfo, TOTAL_INSTRUCTION_COUNT> temp;
|
|
for (size_t i = 0; i < TOTAL_INSTRUCTION_COUNT; i++)
|
|
{
|
|
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; });
|
|
|
|
for (auto& inst : temp)
|
|
{
|
|
if (inst.second == 0)
|
|
break;
|
|
|
|
INFO_LOG_FMT(POWERPC, "{} : {}", inst.first, inst.second);
|
|
}
|
|
}
|
|
|
|
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 < TOTAL_INSTRUCTION_COUNT; i++)
|
|
{
|
|
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", 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 < TOTAL_INSTRUCTION_COUNT; i++)
|
|
{
|
|
const GekkoOPInfo& info = s_tables.all_instructions[i];
|
|
if (info.stats->compile_count == 0)
|
|
{
|
|
f.WriteString(fmt::format("{0}\t{1}\t{2}\n", info.opname, info.stats->compile_count,
|
|
info.stats->run_count));
|
|
}
|
|
}
|
|
|
|
#ifdef OPLOG
|
|
f.Open(fmt::format("{}" OP_TO_LOG "_at{}.txt", File::GetUserPath(D_LOGS_IDX), time), "w");
|
|
for (auto& rsplocation : rsplocations)
|
|
{
|
|
f.WriteString(fmt::format(OP_TO_LOG ": {0:08x}\n", rsplocation));
|
|
}
|
|
#endif
|
|
|
|
++time;
|
|
}
|
|
|
|
} // namespace PPCTables
|