// Copyright 2023 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "Common/Assembler/AssemblerTables.h" #include "Common/Assembler/AssemblerShared.h" #include "Common/Assembler/CaseInsensitiveDict.h" #include "Common/CommonTypes.h" namespace Common::GekkoAssembler::detail { namespace { constexpr size_t PLAIN_MNEMONIC = 0x0; constexpr size_t RECORD_BIT = 0x1; constexpr size_t OVERFLOW_EXCEPTION = 0x2; // Since RC/OE are mutually exclusive from LK/AA, they can occupy the same slot constexpr size_t LINK_BIT = 0x1; constexpr size_t ABSOLUTE_ADDRESS_BIT = 0x2; // Compile-time helpers for mnemonic generation // Generate inclusive mask [left, right] -- MSB=0 LSB=31 constexpr u32 Mask(u32 left, u32 right) { return static_cast(((u64{1} << (32 - left)) - 1) & ~((u64{1} << (31 - right)) - 1)); } constexpr u32 InsertVal(u32 val, u32 left, u32 right) { return val << (31 - right) & Mask(left, right); } constexpr u32 InsertOpcode(u32 opcode) { return InsertVal(opcode, 0, 5); } constexpr u32 SprBitswap(u32 spr) { return ((spr & 0b0000011111) << 5) | ((spr & 0b1111100000) >> 5); } constexpr MnemonicDesc INVALID_MNEMONIC = {0, 0, {}}; constexpr ExtendedMnemonicDesc INVALID_EXT_MNEMONIC = {0, nullptr}; // All operands as referenced by the Gekko/Broadway user manual // See section 12.1.2 under Chapter 12 constexpr OperandDesc OpDesc_A = OperandDesc{Mask(11, 15), {16, false}}; constexpr OperandDesc OpDesc_B = OperandDesc{Mask(16, 20), {11, false}}; constexpr OperandDesc OpDesc_BD = OperandDesc{Mask(16, 29), {0, true}}; constexpr OperandDesc OpDesc_BI = OperandDesc{Mask(11, 15), {16, false}}; constexpr OperandDesc OpDesc_BO = OperandDesc{Mask(6, 10), {21, false}}; constexpr OperandDesc OpDesc_C = OperandDesc{Mask(21, 25), {6, false}}; constexpr OperandDesc OpDesc_Crba = OperandDesc{Mask(11, 15), {16, false}}; constexpr OperandDesc OpDesc_Crbb = OperandDesc{Mask(16, 20), {11, false}}; constexpr OperandDesc OpDesc_Crbd = OperandDesc{Mask(6, 10), {21, false}}; constexpr OperandDesc OpDesc_Crfd = OperandDesc{Mask(6, 8), {23, false}}; constexpr OperandDesc OpDesc_Crfs = OperandDesc{Mask(11, 13), {18, false}}; constexpr OperandDesc OpDesc_CRM = OperandDesc{Mask(12, 19), {12, false}}; constexpr OperandDesc OpDesc_D = OperandDesc{Mask(6, 10), {21, false}}; constexpr OperandDesc OpDesc_FM = OperandDesc{Mask(7, 14), {17, false}}; constexpr OperandDesc OpDesc_W1 = OperandDesc{Mask(16, 16), {15, false}}; constexpr OperandDesc OpDesc_W2 = OperandDesc{Mask(21, 21), {10, false}}; constexpr OperandDesc OpDesc_IMM = OperandDesc{Mask(16, 19), {12, false}}; constexpr OperandDesc OpDesc_L = OperandDesc{Mask(10, 10), {21, false}}; constexpr OperandDesc OpDesc_LI = OperandDesc{Mask(6, 29), {0, true}}; constexpr OperandDesc OpDesc_MB = OperandDesc{Mask(21, 25), {6, false}}; constexpr OperandDesc OpDesc_ME = OperandDesc{Mask(26, 30), {1, false}}; constexpr OperandDesc OpDesc_NB = OperandDesc{Mask(16, 20), {11, false}}; constexpr OperandDesc OpDesc_Offd = OperandDesc{Mask(16, 31), {0, true}}; constexpr OperandDesc OpDesc_OffdPs = OperandDesc{Mask(20, 31), {0, true}}; constexpr OperandDesc OpDesc_S = OperandDesc{Mask(6, 10), {21, false}}; constexpr OperandDesc OpDesc_SH = OperandDesc{Mask(16, 20), {11, false}}; constexpr OperandDesc OpDesc_SIMM = OperandDesc{Mask(16, 31), {0, true}}; constexpr OperandDesc OpDesc_SPR = OperandDesc{Mask(11, 20), {11, false}}; constexpr OperandDesc OpDesc_SR = OperandDesc{Mask(12, 15), {16, false}}; constexpr OperandDesc OpDesc_TO = OperandDesc{Mask(6, 10), {21, false}}; constexpr OperandDesc OpDesc_TPR = OperandDesc{Mask(11, 20), {11, false}}; constexpr OperandDesc OpDesc_UIMM = OperandDesc{Mask(16, 31), {0, false}}; constexpr OperandDesc OpDesc_I1 = OperandDesc{Mask(17, 19), {12, false}}; constexpr OperandDesc OpDesc_I2 = OperandDesc{Mask(22, 24), {7, false}}; } // namespace void OperandList::Insert(size_t before, u32 val) { overfill = count == MAX_OPERANDS; for (size_t i = before + 1; i <= count && i < MAX_OPERANDS; i++) { std::swap(list[i], list[before]); } list[before] = Tagged({0, 0}, val); if (!overfill) { count++; } } // OperandDesc holds the shift position for an operand, as well as the mask // Whether the user provided a valid input for an operand can be determined by the mask u32 OperandDesc::MaxVal() const { const u32 mask_sh = mask >> shift; if (is_signed) { const u32 mask_hibit = (mask_sh & (mask_sh ^ (mask_sh >> 1))); return mask_hibit - 1; } return mask_sh; } u32 OperandDesc::MinVal() const { if (is_signed) { return ~MaxVal(); } return 0; } u32 OperandDesc::TruncBits() const { const u32 mask_sh = mask >> shift; const u32 mask_lobit = mask_sh & (mask_sh ^ (mask_sh << 1)); return mask_lobit - 1; } bool OperandDesc::Fits(u32 val) const { const u32 mask_sh = mask >> shift; if (is_signed) { // Get high bit and low bit from a range mask const u32 mask_hibit = mask_sh & (mask_sh ^ (mask_sh >> 1)); const u32 mask_lobit = mask_sh & (mask_sh ^ (mask_sh << 1)); // Positive max is (signbit - 1) // Negative min is ~(Positive Max) const u32 positive_max = mask_hibit - 1; const u32 negative_max = ~positive_max; // Truncated bits are any bits right of the mask that are 0 after shifting const u32 truncate_bits = mask_lobit - 1; return (val <= positive_max || val >= negative_max) && !(val & truncate_bits); } return (mask_sh & val) == val; } u32 OperandDesc::Fit(u32 val) const { return (val << shift) & mask; } /////////////////// // PARSER TABLES // /////////////////// extern const CaseInsensitiveDict sprg_map = { {"xer", 1}, {"lr", 8}, {"ctr", 9}, {"dsisr", 18}, {"dar", 19}, {"dec", 22}, {"sdr1", 25}, {"srr0", 26}, {"srr1", 27}, {"sprg0", 272}, {"sprg1", 273}, {"sprg2", 274}, {"sprg3", 275}, {"ear", 282}, {"tbl", 284}, {"tbu", 285}, {"ibat0u", 528}, {"ibat0l", 529}, {"ibat1u", 530}, {"ibat1l", 531}, {"ibat2u", 532}, {"ibat2l", 533}, {"ibat3u", 534}, {"ibat3l", 535}, {"dbat0u", 536}, {"dbat0l", 537}, {"dbat1u", 538}, {"dbat1l", 539}, {"dbat2u", 540}, {"dbat2l", 541}, {"dbat3u", 542}, {"dbat3l", 543}, {"gqr0", 912}, {"gqr1", 913}, {"gqr2", 914}, {"gqr3", 915}, {"gqr4", 916}, {"gqr5", 917}, {"gqr6", 918}, {"gqr7", 919}, {"hid2", 920}, {"wpar", 921}, {"dma_u", 922}, {"dma_l", 923}, {"ummcr0", 936}, {"upmc1", 937}, {"upmc2", 938}, {"usia", 939}, {"ummcr1", 940}, {"upmc3", 941}, {"upmc4", 942}, {"usda", 943}, {"mmcr0", 952}, {"pmc1", 953}, {"pmc2", 954}, {"sia", 955}, {"mmcr1", 956}, {"pmc3", 957}, {"pmc4", 958}, {"sda", 959}, {"hid0", 1008}, {"hid1", 1009}, {"iabr", 1010}, {"dabr", 1013}, {"l2cr", 1017}, {"ictc", 1019}, {"thrm1", 1020}, {"thrm2", 1021}, {"thrm3", 1022}}; extern const CaseInsensitiveDict directives_map = { {"byte", GekkoDirective::Byte}, {"2byte", GekkoDirective::_2byte}, {"4byte", GekkoDirective::_4byte}, {"8byte", GekkoDirective::_8byte}, {"float", GekkoDirective::Float}, {"double", GekkoDirective::Double}, {"locate", GekkoDirective::Locate}, {"padalign", GekkoDirective::PadAlign}, {"align", GekkoDirective::Align}, {"zeros", GekkoDirective::Zeros}, {"skip", GekkoDirective::Skip}, {"defvar", GekkoDirective::DefVar}, {"ascii", GekkoDirective::Ascii}, {"asciz", GekkoDirective::Asciz}, }; #define MNEMONIC(mnemonic_str, mnemonic_enum, variant_bits, alg) \ { \ mnemonic_str, \ { \ static_cast(mnemonic_enum) * VARIANT_PERMUTATIONS + (variant_bits), alg \ } \ } #define PLAIN_MNEMONIC(mnemonic_str, mnemonic_enum, alg) \ MNEMONIC(mnemonic_str, mnemonic_enum, PLAIN_MNEMONIC, alg) #define RC_MNEMONIC(mnemonic_str, mnemonic_enum, alg) \ MNEMONIC(mnemonic_str, mnemonic_enum, PLAIN_MNEMONIC, alg), \ MNEMONIC(mnemonic_str ".", mnemonic_enum, RECORD_BIT, alg) #define OERC_MNEMONIC(mnemonic_str, mnemonic_enum, alg) \ MNEMONIC(mnemonic_str, mnemonic_enum, PLAIN_MNEMONIC, alg), \ MNEMONIC(mnemonic_str ".", mnemonic_enum, RECORD_BIT, alg), \ MNEMONIC(mnemonic_str "o", mnemonic_enum, OVERFLOW_EXCEPTION, alg), \ MNEMONIC(mnemonic_str "o.", mnemonic_enum, (RECORD_BIT | OVERFLOW_EXCEPTION), alg) #define LK_MNEMONIC(mnemonic_str, mnemonic_enum, alg) \ MNEMONIC(mnemonic_str, mnemonic_enum, PLAIN_MNEMONIC, alg), \ MNEMONIC(mnemonic_str "l", mnemonic_enum, LINK_BIT, alg) #define AALK_MNEMONIC(mnemonic_str, mnemonic_enum, alg) \ MNEMONIC(mnemonic_str, mnemonic_enum, PLAIN_MNEMONIC, alg), \ MNEMONIC(mnemonic_str "l", mnemonic_enum, LINK_BIT, alg), \ MNEMONIC(mnemonic_str "a", mnemonic_enum, ABSOLUTE_ADDRESS_BIT, alg), \ MNEMONIC(mnemonic_str "la", mnemonic_enum, (LINK_BIT | ABSOLUTE_ADDRESS_BIT), alg) extern const CaseInsensitiveDict mnemonic_tokens = { OERC_MNEMONIC("add", GekkoMnemonic::Add, ParseAlg::Op3), OERC_MNEMONIC("addc", GekkoMnemonic::Addc, ParseAlg::Op3), OERC_MNEMONIC("adde", GekkoMnemonic::Adde, ParseAlg::Op3), PLAIN_MNEMONIC("addi", GekkoMnemonic::Addi, ParseAlg::Op3), PLAIN_MNEMONIC("addic", GekkoMnemonic::Addic, ParseAlg::Op3), PLAIN_MNEMONIC("addic.", GekkoMnemonic::AddicDot, ParseAlg::Op3), PLAIN_MNEMONIC("addis", GekkoMnemonic::Addis, ParseAlg::Op3), OERC_MNEMONIC("addme", GekkoMnemonic::Addme, ParseAlg::Op2), OERC_MNEMONIC("addze", GekkoMnemonic::Addze, ParseAlg::Op2), RC_MNEMONIC("and", GekkoMnemonic::And, ParseAlg::Op3), RC_MNEMONIC("andc", GekkoMnemonic::Andc, ParseAlg::Op3), PLAIN_MNEMONIC("andi.", GekkoMnemonic::AndiDot, ParseAlg::Op3), PLAIN_MNEMONIC("andis.", GekkoMnemonic::AndisDot, ParseAlg::Op3), AALK_MNEMONIC("b", GekkoMnemonic::B, ParseAlg::Op1), AALK_MNEMONIC("bc", GekkoMnemonic::Bc, ParseAlg::Op3), LK_MNEMONIC("bcctr", GekkoMnemonic::Bcctr, ParseAlg::Op2), LK_MNEMONIC("bclr", GekkoMnemonic::Bclr, ParseAlg::Op2), PLAIN_MNEMONIC("cmp", GekkoMnemonic::Cmp, ParseAlg::Op4), PLAIN_MNEMONIC("cmpi", GekkoMnemonic::Cmpi, ParseAlg::Op4), PLAIN_MNEMONIC("cmpl", GekkoMnemonic::Cmpl, ParseAlg::Op4), PLAIN_MNEMONIC("cmpli", GekkoMnemonic::Cmpli, ParseAlg::Op4), RC_MNEMONIC("cntlzw", GekkoMnemonic::Cntlzw, ParseAlg::Op2), PLAIN_MNEMONIC("crand", GekkoMnemonic::Crand, ParseAlg::Op3), PLAIN_MNEMONIC("crandc", GekkoMnemonic::Crandc, ParseAlg::Op3), PLAIN_MNEMONIC("creqv", GekkoMnemonic::Creqv, ParseAlg::Op3), PLAIN_MNEMONIC("crnand", GekkoMnemonic::Crnand, ParseAlg::Op3), PLAIN_MNEMONIC("crnor", GekkoMnemonic::Crnor, ParseAlg::Op3), PLAIN_MNEMONIC("cror", GekkoMnemonic::Cror, ParseAlg::Op3), PLAIN_MNEMONIC("crorc", GekkoMnemonic::Crorc, ParseAlg::Op3), PLAIN_MNEMONIC("crxor", GekkoMnemonic::Crxor, ParseAlg::Op3), PLAIN_MNEMONIC("dcbf", GekkoMnemonic::Dcbf, ParseAlg::Op2), PLAIN_MNEMONIC("dcbi", GekkoMnemonic::Dcbi, ParseAlg::Op2), PLAIN_MNEMONIC("dcbst", GekkoMnemonic::Dcbst, ParseAlg::Op2), PLAIN_MNEMONIC("dcbt", GekkoMnemonic::Dcbt, ParseAlg::Op2), PLAIN_MNEMONIC("dcbtst", GekkoMnemonic::Dcbtst, ParseAlg::Op2), PLAIN_MNEMONIC("dcbz", GekkoMnemonic::Dcbz, ParseAlg::Op2), PLAIN_MNEMONIC("dcbz_l", GekkoMnemonic::Dcbz_l, ParseAlg::Op2), OERC_MNEMONIC("divw", GekkoMnemonic::Divw, ParseAlg::Op3), OERC_MNEMONIC("divwu", GekkoMnemonic::Divwu, ParseAlg::Op3), PLAIN_MNEMONIC("eciwx", GekkoMnemonic::Eciwx, ParseAlg::Op3), PLAIN_MNEMONIC("ecowx", GekkoMnemonic::Ecowx, ParseAlg::Op3), PLAIN_MNEMONIC("eieio", GekkoMnemonic::Eieio, ParseAlg::None), RC_MNEMONIC("eqv", GekkoMnemonic::Eqv, ParseAlg::Op3), RC_MNEMONIC("extsb", GekkoMnemonic::Extsb, ParseAlg::Op2), RC_MNEMONIC("extsh", GekkoMnemonic::Extsh, ParseAlg::Op2), RC_MNEMONIC("fabs", GekkoMnemonic::Fabs, ParseAlg::Op2), RC_MNEMONIC("fadd", GekkoMnemonic::Fadd, ParseAlg::Op3), RC_MNEMONIC("fadds", GekkoMnemonic::Fadds, ParseAlg::Op3), PLAIN_MNEMONIC("fcmpo", GekkoMnemonic::Fcmpo, ParseAlg::Op3), PLAIN_MNEMONIC("fcmpu", GekkoMnemonic::Fcmpu, ParseAlg::Op3), RC_MNEMONIC("fctiw", GekkoMnemonic::Fctiw, ParseAlg::Op2), RC_MNEMONIC("fctiwz", GekkoMnemonic::Fctiwz, ParseAlg::Op2), RC_MNEMONIC("fdiv", GekkoMnemonic::Fdiv, ParseAlg::Op3), RC_MNEMONIC("fdivs", GekkoMnemonic::Fdivs, ParseAlg::Op3), RC_MNEMONIC("fmadd", GekkoMnemonic::Fmadd, ParseAlg::Op4), RC_MNEMONIC("fmadds", GekkoMnemonic::Fmadds, ParseAlg::Op4), RC_MNEMONIC("fmr", GekkoMnemonic::Fmr, ParseAlg::Op2), RC_MNEMONIC("fmsub", GekkoMnemonic::Fmsub, ParseAlg::Op4), RC_MNEMONIC("fmsubs", GekkoMnemonic::Fmsubs, ParseAlg::Op4), RC_MNEMONIC("fmul", GekkoMnemonic::Fmul, ParseAlg::Op3), RC_MNEMONIC("fmuls", GekkoMnemonic::Fmuls, ParseAlg::Op3), RC_MNEMONIC("fnabs", GekkoMnemonic::Fnabs, ParseAlg::Op2), RC_MNEMONIC("fneg", GekkoMnemonic::Fneg, ParseAlg::Op2), RC_MNEMONIC("fnmadd", GekkoMnemonic::Fnmadd, ParseAlg::Op4), RC_MNEMONIC("fnmadds", GekkoMnemonic::Fnmadds, ParseAlg::Op4), RC_MNEMONIC("fnmsub", GekkoMnemonic::Fnmsub, ParseAlg::Op4), RC_MNEMONIC("fnmsubs", GekkoMnemonic::Fnmsubs, ParseAlg::Op4), RC_MNEMONIC("fres", GekkoMnemonic::Fres, ParseAlg::Op2), RC_MNEMONIC("frsp", GekkoMnemonic::Frsp, ParseAlg::Op2), RC_MNEMONIC("frsqrte", GekkoMnemonic::Frsqrte, ParseAlg::Op2), RC_MNEMONIC("fsel", GekkoMnemonic::Fsel, ParseAlg::Op4), RC_MNEMONIC("fsub", GekkoMnemonic::Fsub, ParseAlg::Op3), RC_MNEMONIC("fsubs", GekkoMnemonic::Fsubs, ParseAlg::Op3), PLAIN_MNEMONIC("icbi", GekkoMnemonic::Icbi, ParseAlg::Op2), PLAIN_MNEMONIC("isync", GekkoMnemonic::Isync, ParseAlg::None), PLAIN_MNEMONIC("lbz", GekkoMnemonic::Lbz, ParseAlg::Op1Off1), PLAIN_MNEMONIC("lbzu", GekkoMnemonic::Lbzu, ParseAlg::Op1Off1), PLAIN_MNEMONIC("lbzux", GekkoMnemonic::Lbzux, ParseAlg::Op3), PLAIN_MNEMONIC("lbzx", GekkoMnemonic::Lbzx, ParseAlg::Op3), PLAIN_MNEMONIC("lfd", GekkoMnemonic::Lfd, ParseAlg::Op1Off1), PLAIN_MNEMONIC("lfdu", GekkoMnemonic::Lfdu, ParseAlg::Op1Off1), PLAIN_MNEMONIC("lfdux", GekkoMnemonic::Lfdux, ParseAlg::Op3), PLAIN_MNEMONIC("lfdx", GekkoMnemonic::Lfdx, ParseAlg::Op3), PLAIN_MNEMONIC("lfs", GekkoMnemonic::Lfs, ParseAlg::Op1Off1), PLAIN_MNEMONIC("lfsu", GekkoMnemonic::Lfsu, ParseAlg::Op1Off1), PLAIN_MNEMONIC("lfsux", GekkoMnemonic::Lfsux, ParseAlg::Op3), PLAIN_MNEMONIC("lfsx", GekkoMnemonic::Lfsx, ParseAlg::Op3), PLAIN_MNEMONIC("lha", GekkoMnemonic::Lha, ParseAlg::Op1Off1), PLAIN_MNEMONIC("lhau", GekkoMnemonic::Lhau, ParseAlg::Op1Off1), PLAIN_MNEMONIC("lhaux", GekkoMnemonic::Lhaux, ParseAlg::Op3), PLAIN_MNEMONIC("lhax", GekkoMnemonic::Lhax, ParseAlg::Op3), PLAIN_MNEMONIC("lhbrx", GekkoMnemonic::Lhbrx, ParseAlg::Op3), PLAIN_MNEMONIC("lhz", GekkoMnemonic::Lhz, ParseAlg::Op1Off1), PLAIN_MNEMONIC("lhzu", GekkoMnemonic::Lhzu, ParseAlg::Op1Off1), PLAIN_MNEMONIC("lhzux", GekkoMnemonic::Lhzux, ParseAlg::Op3), PLAIN_MNEMONIC("lhzx", GekkoMnemonic::Lhzx, ParseAlg::Op3), PLAIN_MNEMONIC("lmw", GekkoMnemonic::Lmw, ParseAlg::Op1Off1), PLAIN_MNEMONIC("lswi", GekkoMnemonic::Lswi, ParseAlg::Op3), PLAIN_MNEMONIC("lswx", GekkoMnemonic::Lswx, ParseAlg::Op3), PLAIN_MNEMONIC("lwarx", GekkoMnemonic::Lwarx, ParseAlg::Op3), PLAIN_MNEMONIC("lwbrx", GekkoMnemonic::Lwbrx, ParseAlg::Op3), PLAIN_MNEMONIC("lwz", GekkoMnemonic::Lwz, ParseAlg::Op1Off1), PLAIN_MNEMONIC("lwzu", GekkoMnemonic::Lwzu, ParseAlg::Op1Off1), PLAIN_MNEMONIC("lwzux", GekkoMnemonic::Lwzux, ParseAlg::Op3), PLAIN_MNEMONIC("lwzx", GekkoMnemonic::Lwzx, ParseAlg::Op3), PLAIN_MNEMONIC("mcrf", GekkoMnemonic::Mcrf, ParseAlg::Op2), PLAIN_MNEMONIC("mcrfs", GekkoMnemonic::Mcrfs, ParseAlg::Op2), PLAIN_MNEMONIC("mcrxr", GekkoMnemonic::Mcrxr, ParseAlg::Op1), PLAIN_MNEMONIC("mfcr", GekkoMnemonic::Mfcr, ParseAlg::Op1), RC_MNEMONIC("mffs", GekkoMnemonic::Mffs, ParseAlg::Op1), PLAIN_MNEMONIC("mfmsr", GekkoMnemonic::Mfmsr, ParseAlg::Op1), PLAIN_MNEMONIC("mfspr_nobitswap", GekkoMnemonic::Mfspr_nobitswap, ParseAlg::Op2), PLAIN_MNEMONIC("mfsr", GekkoMnemonic::Mfsr, ParseAlg::Op2), PLAIN_MNEMONIC("mfsrin", GekkoMnemonic::Mfsrin, ParseAlg::Op2), PLAIN_MNEMONIC("mftb_nobitswap", GekkoMnemonic::Mftb_nobitswap, ParseAlg::Op2), PLAIN_MNEMONIC("mtcrf", GekkoMnemonic::Mtcrf, ParseAlg::Op2), RC_MNEMONIC("mtfsb0", GekkoMnemonic::Mtfsb0, ParseAlg::Op1), RC_MNEMONIC("mtfsb1", GekkoMnemonic::Mtfsb1, ParseAlg::Op1), RC_MNEMONIC("mtfsf", GekkoMnemonic::Mtfsf, ParseAlg::Op2), RC_MNEMONIC("mtfsfi", GekkoMnemonic::Mtfsfi, ParseAlg::Op2), PLAIN_MNEMONIC("mtmsr", GekkoMnemonic::Mtmsr, ParseAlg::Op1), PLAIN_MNEMONIC("mtspr_nobitswap", GekkoMnemonic::Mtspr_nobitswap, ParseAlg::Op2), PLAIN_MNEMONIC("mtsr", GekkoMnemonic::Mtsr, ParseAlg::Op2), PLAIN_MNEMONIC("mtsrin", GekkoMnemonic::Mtsrin, ParseAlg::Op2), RC_MNEMONIC("mulhw", GekkoMnemonic::Mulhw, ParseAlg::Op3), RC_MNEMONIC("mulhwu", GekkoMnemonic::Mulhwu, ParseAlg::Op3), PLAIN_MNEMONIC("mulli", GekkoMnemonic::Mulli, ParseAlg::Op3), OERC_MNEMONIC("mullw", GekkoMnemonic::Mullw, ParseAlg::Op3), RC_MNEMONIC("nand", GekkoMnemonic::Nand, ParseAlg::Op3), OERC_MNEMONIC("neg", GekkoMnemonic::Neg, ParseAlg::Op2), RC_MNEMONIC("nor", GekkoMnemonic::Nor, ParseAlg::Op3), RC_MNEMONIC("or", GekkoMnemonic::Or, ParseAlg::Op3), RC_MNEMONIC("orc", GekkoMnemonic::Orc, ParseAlg::Op3), PLAIN_MNEMONIC("ori", GekkoMnemonic::Ori, ParseAlg::Op3), PLAIN_MNEMONIC("oris", GekkoMnemonic::Oris, ParseAlg::Op3), PLAIN_MNEMONIC("psq_l", GekkoMnemonic::Psq_l, ParseAlg::Op1Off1Op2), PLAIN_MNEMONIC("psq_lu", GekkoMnemonic::Psq_lu, ParseAlg::Op1Off1Op2), PLAIN_MNEMONIC("psq_lux", GekkoMnemonic::Psq_lux, ParseAlg::Op5), PLAIN_MNEMONIC("psq_lx", GekkoMnemonic::Psq_lx, ParseAlg::Op5), PLAIN_MNEMONIC("psq_st", GekkoMnemonic::Psq_st, ParseAlg::Op1Off1Op2), PLAIN_MNEMONIC("psq_stu", GekkoMnemonic::Psq_stu, ParseAlg::Op1Off1Op2), PLAIN_MNEMONIC("psq_stux", GekkoMnemonic::Psq_stux, ParseAlg::Op5), PLAIN_MNEMONIC("psq_stx", GekkoMnemonic::Psq_stx, ParseAlg::Op5), RC_MNEMONIC("ps_abs", GekkoMnemonic::Ps_abs, ParseAlg::Op2), RC_MNEMONIC("ps_add", GekkoMnemonic::Ps_add, ParseAlg::Op3), PLAIN_MNEMONIC("ps_cmpo0", GekkoMnemonic::Ps_cmpo0, ParseAlg::Op3), PLAIN_MNEMONIC("ps_cmpo1", GekkoMnemonic::Ps_cmpo1, ParseAlg::Op3), PLAIN_MNEMONIC("ps_cmpu0", GekkoMnemonic::Ps_cmpu0, ParseAlg::Op3), PLAIN_MNEMONIC("ps_cmpu1", GekkoMnemonic::Ps_cmpu1, ParseAlg::Op3), RC_MNEMONIC("ps_div", GekkoMnemonic::Ps_div, ParseAlg::Op3), RC_MNEMONIC("ps_madd", GekkoMnemonic::Ps_madd, ParseAlg::Op4), RC_MNEMONIC("ps_madds0", GekkoMnemonic::Ps_madds0, ParseAlg::Op4), RC_MNEMONIC("ps_madds1", GekkoMnemonic::Ps_madds1, ParseAlg::Op4), RC_MNEMONIC("ps_merge00", GekkoMnemonic::Ps_merge00, ParseAlg::Op3), RC_MNEMONIC("ps_merge01", GekkoMnemonic::Ps_merge01, ParseAlg::Op3), RC_MNEMONIC("ps_merge10", GekkoMnemonic::Ps_merge10, ParseAlg::Op3), RC_MNEMONIC("ps_merge11", GekkoMnemonic::Ps_merge11, ParseAlg::Op3), RC_MNEMONIC("ps_mr", GekkoMnemonic::Ps_mr, ParseAlg::Op2), RC_MNEMONIC("ps_msub", GekkoMnemonic::Ps_msub, ParseAlg::Op4), RC_MNEMONIC("ps_mul", GekkoMnemonic::Ps_mul, ParseAlg::Op3), RC_MNEMONIC("ps_muls0", GekkoMnemonic::Ps_muls0, ParseAlg::Op3), RC_MNEMONIC("ps_muls1", GekkoMnemonic::Ps_muls1, ParseAlg::Op3), RC_MNEMONIC("ps_nabs", GekkoMnemonic::Ps_nabs, ParseAlg::Op2), RC_MNEMONIC("ps_neg", GekkoMnemonic::Ps_neg, ParseAlg::Op2), RC_MNEMONIC("ps_nmadd", GekkoMnemonic::Ps_nmadd, ParseAlg::Op4), RC_MNEMONIC("ps_nmsub", GekkoMnemonic::Ps_nmsub, ParseAlg::Op4), RC_MNEMONIC("ps_res", GekkoMnemonic::Ps_res, ParseAlg::Op2), RC_MNEMONIC("ps_rsqrte", GekkoMnemonic::Ps_rsqrte, ParseAlg::Op2), RC_MNEMONIC("ps_sel", GekkoMnemonic::Ps_sel, ParseAlg::Op4), RC_MNEMONIC("ps_sub", GekkoMnemonic::Ps_sub, ParseAlg::Op3), RC_MNEMONIC("ps_sum0", GekkoMnemonic::Ps_sum0, ParseAlg::Op4), RC_MNEMONIC("ps_sum1", GekkoMnemonic::Ps_sum1, ParseAlg::Op4), PLAIN_MNEMONIC("rfi", GekkoMnemonic::Rfi, ParseAlg::None), RC_MNEMONIC("rlwimi", GekkoMnemonic::Rlwimi, ParseAlg::Op5), RC_MNEMONIC("rlwinm", GekkoMnemonic::Rlwinm, ParseAlg::Op5), RC_MNEMONIC("rlwnm", GekkoMnemonic::Rlwnm, ParseAlg::Op5), PLAIN_MNEMONIC("sc", GekkoMnemonic::Sc, ParseAlg::None), RC_MNEMONIC("slw", GekkoMnemonic::Slw, ParseAlg::Op3), RC_MNEMONIC("sraw", GekkoMnemonic::Sraw, ParseAlg::Op3), RC_MNEMONIC("srawi", GekkoMnemonic::Srawi, ParseAlg::Op3), RC_MNEMONIC("srw", GekkoMnemonic::Srw, ParseAlg::Op3), PLAIN_MNEMONIC("stb", GekkoMnemonic::Stb, ParseAlg::Op1Off1), PLAIN_MNEMONIC("stbu", GekkoMnemonic::Stbu, ParseAlg::Op1Off1), PLAIN_MNEMONIC("stbux", GekkoMnemonic::Stbux, ParseAlg::Op3), PLAIN_MNEMONIC("stbx", GekkoMnemonic::Stbx, ParseAlg::Op3), PLAIN_MNEMONIC("stfd", GekkoMnemonic::Stfd, ParseAlg::Op1Off1), PLAIN_MNEMONIC("stfdu", GekkoMnemonic::Stfdu, ParseAlg::Op1Off1), PLAIN_MNEMONIC("stfdux", GekkoMnemonic::Stfdux, ParseAlg::Op3), PLAIN_MNEMONIC("stfdx", GekkoMnemonic::Stfdx, ParseAlg::Op3), PLAIN_MNEMONIC("stfiwx", GekkoMnemonic::Stfiwx, ParseAlg::Op3), PLAIN_MNEMONIC("stfs", GekkoMnemonic::Stfs, ParseAlg::Op1Off1), PLAIN_MNEMONIC("stfsu", GekkoMnemonic::Stfsu, ParseAlg::Op1Off1), PLAIN_MNEMONIC("stfsux", GekkoMnemonic::Stfsux, ParseAlg::Op3), PLAIN_MNEMONIC("stfsx", GekkoMnemonic::Stfsx, ParseAlg::Op3), PLAIN_MNEMONIC("sth", GekkoMnemonic::Sth, ParseAlg::Op1Off1), PLAIN_MNEMONIC("sthbrx", GekkoMnemonic::Sthbrx, ParseAlg::Op3), PLAIN_MNEMONIC("sthu", GekkoMnemonic::Sthu, ParseAlg::Op1Off1), PLAIN_MNEMONIC("sthux", GekkoMnemonic::Sthux, ParseAlg::Op3), PLAIN_MNEMONIC("sthx", GekkoMnemonic::Sthx, ParseAlg::Op3), PLAIN_MNEMONIC("stmw", GekkoMnemonic::Stmw, ParseAlg::Op1Off1), PLAIN_MNEMONIC("stswi", GekkoMnemonic::Stswi, ParseAlg::Op3), PLAIN_MNEMONIC("stswx", GekkoMnemonic::Stswx, ParseAlg::Op3), PLAIN_MNEMONIC("stw", GekkoMnemonic::Stw, ParseAlg::Op1Off1), PLAIN_MNEMONIC("stwbrx", GekkoMnemonic::Stwbrx, ParseAlg::Op3), PLAIN_MNEMONIC("stwcx.", GekkoMnemonic::StwcxDot, ParseAlg::Op3), PLAIN_MNEMONIC("stwu", GekkoMnemonic::Stwu, ParseAlg::Op1Off1), PLAIN_MNEMONIC("stwux", GekkoMnemonic::Stwux, ParseAlg::Op3), PLAIN_MNEMONIC("stwx", GekkoMnemonic::Stwx, ParseAlg::Op3), OERC_MNEMONIC("subf", GekkoMnemonic::Subf, ParseAlg::Op3), OERC_MNEMONIC("subfc", GekkoMnemonic::Subfc, ParseAlg::Op3), OERC_MNEMONIC("subfe", GekkoMnemonic::Subfe, ParseAlg::Op3), PLAIN_MNEMONIC("subfic", GekkoMnemonic::Subfic, ParseAlg::Op3), OERC_MNEMONIC("subfme", GekkoMnemonic::Subfme, ParseAlg::Op2), OERC_MNEMONIC("subfze", GekkoMnemonic::Subfze, ParseAlg::Op2), PLAIN_MNEMONIC("sync", GekkoMnemonic::Sync, ParseAlg::None), PLAIN_MNEMONIC("tlbie", GekkoMnemonic::Tlbie, ParseAlg::Op1), PLAIN_MNEMONIC("tlbsync", GekkoMnemonic::Tlbsync, ParseAlg::None), PLAIN_MNEMONIC("tw", GekkoMnemonic::Tw, ParseAlg::Op3), PLAIN_MNEMONIC("twi", GekkoMnemonic::Twi, ParseAlg::Op3), RC_MNEMONIC("xor", GekkoMnemonic::Xor, ParseAlg::Op3), PLAIN_MNEMONIC("xori", GekkoMnemonic::Xori, ParseAlg::Op3), PLAIN_MNEMONIC("xoris", GekkoMnemonic::Xoris, ParseAlg::Op3), }; #define PSEUDO(mnemonic, base, variant_bits, alg) \ { \ mnemonic, { static_cast(base) * VARIANT_PERMUTATIONS + (variant_bits), alg } \ } #define PLAIN_PSEUDO(mnemonic, base, alg) PSEUDO(mnemonic, base, PLAIN_MNEMONIC, alg) #define RC_PSEUDO(mnemonic, base, alg) \ PSEUDO(mnemonic, base, PLAIN_MNEMONIC, alg), PSEUDO(mnemonic ".", base, RECORD_BIT, alg) #define OERC_PSEUDO(mnemonic, base, alg) \ PSEUDO(mnemonic, base, PLAIN_MNEMONIC, alg), PSEUDO(mnemonic ".", base, RECORD_BIT, alg), \ PSEUDO(mnemonic "o", base, OVERFLOW_EXCEPTION, alg), \ PSEUDO(mnemonic "o.", base, (RECORD_BIT | OVERFLOW_EXCEPTION), alg) #define LK_PSEUDO(mnemonic, base, alg) \ PSEUDO(mnemonic, base, PLAIN_MNEMONIC, alg), PSEUDO(mnemonic "l", base, LINK_BIT, alg) #define LKAA_PSEUDO(mnemonic, base, alg) \ PSEUDO(mnemonic, base, PLAIN_MNEMONIC, alg), PSEUDO(mnemonic "l", base, LINK_BIT, alg), \ PSEUDO(mnemonic "a", base, ABSOLUTE_ADDRESS_BIT, alg), \ PSEUDO(mnemonic "la", base, (LINK_BIT | ABSOLUTE_ADDRESS_BIT), alg) #define LKPRED_PSEUDO(mnemonic, base, alg) \ PSEUDO(mnemonic, base, PLAIN_MNEMONIC, alg), PSEUDO(mnemonic "l", base, LINK_BIT, alg), \ PSEUDO(mnemonic "-", base, PLAIN_MNEMONIC, alg), PSEUDO(mnemonic "l-", base, LINK_BIT, alg), \ PSEUDO(mnemonic "+", base##Predict, PLAIN_MNEMONIC, alg), \ PSEUDO(mnemonic "l+", base##Predict, LINK_BIT, alg) #define LKAAPRED_PSEUDO(mnemonic, base, alg) \ PSEUDO(mnemonic, base, PLAIN_MNEMONIC, alg), PSEUDO(mnemonic "l", base, LINK_BIT, alg), \ PSEUDO(mnemonic "a", base, ABSOLUTE_ADDRESS_BIT, alg), \ PSEUDO(mnemonic "la", base, (LINK_BIT | ABSOLUTE_ADDRESS_BIT), alg), \ PSEUDO(mnemonic "-", base, PLAIN_MNEMONIC, alg), PSEUDO(mnemonic "l-", base, LINK_BIT, alg), \ PSEUDO(mnemonic "a-", base, ABSOLUTE_ADDRESS_BIT, alg), \ PSEUDO(mnemonic "la-", base, (LINK_BIT | ABSOLUTE_ADDRESS_BIT), alg), \ PSEUDO(mnemonic "+", base##Predict, PLAIN_MNEMONIC, alg), \ PSEUDO(mnemonic "l+", base##Predict, LINK_BIT, alg), \ PSEUDO(mnemonic "a+", base##Predict, ABSOLUTE_ADDRESS_BIT, alg), \ PSEUDO(mnemonic "la+", base##Predict, (LINK_BIT | ABSOLUTE_ADDRESS_BIT), alg) extern const CaseInsensitiveDict extended_mnemonic_tokens = { PLAIN_PSEUDO("subi", ExtendedGekkoMnemonic::Subi, ParseAlg::Op3), PLAIN_PSEUDO("subis", ExtendedGekkoMnemonic::Subis, ParseAlg::Op3), PLAIN_PSEUDO("subic", ExtendedGekkoMnemonic::Subic, ParseAlg::Op3), PLAIN_PSEUDO("subic.", ExtendedGekkoMnemonic::SubicDot, ParseAlg::Op3), OERC_PSEUDO("sub", ExtendedGekkoMnemonic::Sub, ParseAlg::Op3), OERC_PSEUDO("subc", ExtendedGekkoMnemonic::Subc, ParseAlg::Op3), PLAIN_PSEUDO("cmpwi", ExtendedGekkoMnemonic::Cmpwi, ParseAlg::Op2Or3), PLAIN_PSEUDO("cmpw", ExtendedGekkoMnemonic::Cmpw, ParseAlg::Op2Or3), PLAIN_PSEUDO("cmplwi", ExtendedGekkoMnemonic::Cmplwi, ParseAlg::Op2Or3), PLAIN_PSEUDO("cmplw", ExtendedGekkoMnemonic::Cmplw, ParseAlg::Op2Or3), RC_PSEUDO("extlwi", ExtendedGekkoMnemonic::Extlwi, ParseAlg::Op4), RC_PSEUDO("extrwi", ExtendedGekkoMnemonic::Extrwi, ParseAlg::Op4), RC_PSEUDO("inslwi", ExtendedGekkoMnemonic::Inslwi, ParseAlg::Op4), RC_PSEUDO("insrwi", ExtendedGekkoMnemonic::Insrwi, ParseAlg::Op4), RC_PSEUDO("rotlwi", ExtendedGekkoMnemonic::Rotlwi, ParseAlg::Op3), RC_PSEUDO("rotrwi", ExtendedGekkoMnemonic::Rotrwi, ParseAlg::Op3), RC_PSEUDO("rotlw", ExtendedGekkoMnemonic::Rotlw, ParseAlg::Op3), RC_PSEUDO("slwi", ExtendedGekkoMnemonic::Slwi, ParseAlg::Op3), RC_PSEUDO("srwi", ExtendedGekkoMnemonic::Srwi, ParseAlg::Op3), RC_PSEUDO("clrlwi", ExtendedGekkoMnemonic::Clrlwi, ParseAlg::Op3), RC_PSEUDO("clrrwi", ExtendedGekkoMnemonic::Clrrwi, ParseAlg::Op3), RC_PSEUDO("clrlslwi", ExtendedGekkoMnemonic::Clrlslwi, ParseAlg::Op4), LKAAPRED_PSEUDO("bt", ExtendedGekkoMnemonic::Bt, ParseAlg::Op2), LKAAPRED_PSEUDO("bf", ExtendedGekkoMnemonic::Bf, ParseAlg::Op2), LKAAPRED_PSEUDO("bdnz", ExtendedGekkoMnemonic::Bdnz, ParseAlg::Op1), LKAAPRED_PSEUDO("bdnzt", ExtendedGekkoMnemonic::Bdnzt, ParseAlg::Op2), LKAAPRED_PSEUDO("bdnzf", ExtendedGekkoMnemonic::Bdnzf, ParseAlg::Op2), LKAAPRED_PSEUDO("bdz", ExtendedGekkoMnemonic::Bdz, ParseAlg::Op1), LKAAPRED_PSEUDO("bdzt", ExtendedGekkoMnemonic::Bdzt, ParseAlg::Op2), LKAAPRED_PSEUDO("bdzf", ExtendedGekkoMnemonic::Bdzf, ParseAlg::Op2), LK_PSEUDO("blr", ExtendedGekkoMnemonic::Blr, ParseAlg::None), LK_PSEUDO("bctr", ExtendedGekkoMnemonic::Bctr, ParseAlg::None), LKPRED_PSEUDO("btlr", ExtendedGekkoMnemonic::Btlr, ParseAlg::Op1), LKPRED_PSEUDO("btctr", ExtendedGekkoMnemonic::Btctr, ParseAlg::Op1), LKPRED_PSEUDO("bflr", ExtendedGekkoMnemonic::Bflr, ParseAlg::Op1), LKPRED_PSEUDO("bfctr", ExtendedGekkoMnemonic::Bfctr, ParseAlg::Op1), LKPRED_PSEUDO("bdnzlr", ExtendedGekkoMnemonic::Bdnzlr, ParseAlg::None), LKPRED_PSEUDO("bdnztlr", ExtendedGekkoMnemonic::Bdnztlr, ParseAlg::Op1), LKPRED_PSEUDO("bdnzflr", ExtendedGekkoMnemonic::Bdnzflr, ParseAlg::Op1), LKPRED_PSEUDO("bdzlr", ExtendedGekkoMnemonic::Bdzlr, ParseAlg::None), LKPRED_PSEUDO("bdztlr", ExtendedGekkoMnemonic::Bdztlr, ParseAlg::Op1), LKPRED_PSEUDO("bdzflr", ExtendedGekkoMnemonic::Bdzflr, ParseAlg::Op1), LKAAPRED_PSEUDO("blt", ExtendedGekkoMnemonic::Blt, ParseAlg::Op1Or2), LKAAPRED_PSEUDO("ble", ExtendedGekkoMnemonic::Ble, ParseAlg::Op1Or2), LKAAPRED_PSEUDO("beq", ExtendedGekkoMnemonic::Beq, ParseAlg::Op1Or2), LKAAPRED_PSEUDO("bge", ExtendedGekkoMnemonic::Bge, ParseAlg::Op1Or2), LKAAPRED_PSEUDO("bgt", ExtendedGekkoMnemonic::Bgt, ParseAlg::Op1Or2), LKAAPRED_PSEUDO("bnl", ExtendedGekkoMnemonic::Bnl, ParseAlg::Op1Or2), LKAAPRED_PSEUDO("bne", ExtendedGekkoMnemonic::Bne, ParseAlg::Op1Or2), LKAAPRED_PSEUDO("bng", ExtendedGekkoMnemonic::Bng, ParseAlg::Op1Or2), LKAAPRED_PSEUDO("bso", ExtendedGekkoMnemonic::Bso, ParseAlg::Op1Or2), LKAAPRED_PSEUDO("bns", ExtendedGekkoMnemonic::Bns, ParseAlg::Op1Or2), LKAAPRED_PSEUDO("bun", ExtendedGekkoMnemonic::Bun, ParseAlg::Op1Or2), LKAAPRED_PSEUDO("bnu", ExtendedGekkoMnemonic::Bnu, ParseAlg::Op1Or2), LKPRED_PSEUDO("bltlr", ExtendedGekkoMnemonic::Bltlr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bltctr", ExtendedGekkoMnemonic::Bltctr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("blelr", ExtendedGekkoMnemonic::Blelr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("blectr", ExtendedGekkoMnemonic::Blectr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("beqlr", ExtendedGekkoMnemonic::Beqlr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("beqctr", ExtendedGekkoMnemonic::Beqctr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bgelr", ExtendedGekkoMnemonic::Bgelr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bgectr", ExtendedGekkoMnemonic::Bgectr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bgtlr", ExtendedGekkoMnemonic::Bgtlr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bgtctr", ExtendedGekkoMnemonic::Bgtctr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bnllr", ExtendedGekkoMnemonic::Bnllr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bnlctr", ExtendedGekkoMnemonic::Bnlctr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bnelr", ExtendedGekkoMnemonic::Bnelr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bnectr", ExtendedGekkoMnemonic::Bnectr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bnglr", ExtendedGekkoMnemonic::Bnglr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bngctr", ExtendedGekkoMnemonic::Bngctr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bsolr", ExtendedGekkoMnemonic::Bsolr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bsoctr", ExtendedGekkoMnemonic::Bsoctr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bnslr", ExtendedGekkoMnemonic::Bnslr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bnsctr", ExtendedGekkoMnemonic::Bnsctr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bunlr", ExtendedGekkoMnemonic::Bunlr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bunctr", ExtendedGekkoMnemonic::Bunctr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bnulr", ExtendedGekkoMnemonic::Bnulr, ParseAlg::NoneOrOp1), LKPRED_PSEUDO("bnuctr", ExtendedGekkoMnemonic::Bnuctr, ParseAlg::NoneOrOp1), PLAIN_PSEUDO("crset", ExtendedGekkoMnemonic::Crset, ParseAlg::Op1), PLAIN_PSEUDO("crclr", ExtendedGekkoMnemonic::Crclr, ParseAlg::Op1), PLAIN_PSEUDO("crmove", ExtendedGekkoMnemonic::Crmove, ParseAlg::Op2), PLAIN_PSEUDO("crnot", ExtendedGekkoMnemonic::Crnot, ParseAlg::Op2), PLAIN_PSEUDO("twlt", ExtendedGekkoMnemonic::Twlt, ParseAlg::Op2), PLAIN_PSEUDO("twlti", ExtendedGekkoMnemonic::Twlti, ParseAlg::Op2), PLAIN_PSEUDO("twle", ExtendedGekkoMnemonic::Twle, ParseAlg::Op2), PLAIN_PSEUDO("twlei", ExtendedGekkoMnemonic::Twlei, ParseAlg::Op2), PLAIN_PSEUDO("tweq", ExtendedGekkoMnemonic::Tweq, ParseAlg::Op2), PLAIN_PSEUDO("tweqi", ExtendedGekkoMnemonic::Tweqi, ParseAlg::Op2), PLAIN_PSEUDO("twge", ExtendedGekkoMnemonic::Twge, ParseAlg::Op2), PLAIN_PSEUDO("twgei", ExtendedGekkoMnemonic::Twgei, ParseAlg::Op2), PLAIN_PSEUDO("twgt", ExtendedGekkoMnemonic::Twgt, ParseAlg::Op2), PLAIN_PSEUDO("twgti", ExtendedGekkoMnemonic::Twgti, ParseAlg::Op2), PLAIN_PSEUDO("twnl", ExtendedGekkoMnemonic::Twnl, ParseAlg::Op2), PLAIN_PSEUDO("twnli", ExtendedGekkoMnemonic::Twnli, ParseAlg::Op2), PLAIN_PSEUDO("twne", ExtendedGekkoMnemonic::Twne, ParseAlg::Op2), PLAIN_PSEUDO("twnei", ExtendedGekkoMnemonic::Twnei, ParseAlg::Op2), PLAIN_PSEUDO("twng", ExtendedGekkoMnemonic::Twng, ParseAlg::Op2), PLAIN_PSEUDO("twngi", ExtendedGekkoMnemonic::Twngi, ParseAlg::Op2), PLAIN_PSEUDO("twllt", ExtendedGekkoMnemonic::Twllt, ParseAlg::Op2), PLAIN_PSEUDO("twllti", ExtendedGekkoMnemonic::Twllti, ParseAlg::Op2), PLAIN_PSEUDO("twlle", ExtendedGekkoMnemonic::Twlle, ParseAlg::Op2), PLAIN_PSEUDO("twllei", ExtendedGekkoMnemonic::Twllei, ParseAlg::Op2), PLAIN_PSEUDO("twlge", ExtendedGekkoMnemonic::Twlge, ParseAlg::Op2), PLAIN_PSEUDO("twlgei", ExtendedGekkoMnemonic::Twlgei, ParseAlg::Op2), PLAIN_PSEUDO("twlgt", ExtendedGekkoMnemonic::Twlgt, ParseAlg::Op2), PLAIN_PSEUDO("twlgti", ExtendedGekkoMnemonic::Twlgti, ParseAlg::Op2), PLAIN_PSEUDO("twlnl", ExtendedGekkoMnemonic::Twlnl, ParseAlg::Op2), PLAIN_PSEUDO("twlnli", ExtendedGekkoMnemonic::Twlnli, ParseAlg::Op2), PLAIN_PSEUDO("twlng", ExtendedGekkoMnemonic::Twlng, ParseAlg::Op2), PLAIN_PSEUDO("twlngi", ExtendedGekkoMnemonic::Twlngi, ParseAlg::Op2), PLAIN_PSEUDO("trap", ExtendedGekkoMnemonic::Trap, ParseAlg::None), PLAIN_PSEUDO("mtxer", ExtendedGekkoMnemonic::Mtxer, ParseAlg::Op1), PLAIN_PSEUDO("mfxer", ExtendedGekkoMnemonic::Mfxer, ParseAlg::Op1), PLAIN_PSEUDO("mtlr", ExtendedGekkoMnemonic::Mtlr, ParseAlg::Op1), PLAIN_PSEUDO("mflr", ExtendedGekkoMnemonic::Mflr, ParseAlg::Op1), PLAIN_PSEUDO("mtctr", ExtendedGekkoMnemonic::Mtctr, ParseAlg::Op1), PLAIN_PSEUDO("mfctr", ExtendedGekkoMnemonic::Mfctr, ParseAlg::Op1), PLAIN_PSEUDO("mtdsisr", ExtendedGekkoMnemonic::Mtdsisr, ParseAlg::Op1), PLAIN_PSEUDO("mfdsisr", ExtendedGekkoMnemonic::Mfdsisr, ParseAlg::Op1), PLAIN_PSEUDO("mtdar", ExtendedGekkoMnemonic::Mtdar, ParseAlg::Op1), PLAIN_PSEUDO("mfdar", ExtendedGekkoMnemonic::Mfdar, ParseAlg::Op1), PLAIN_PSEUDO("mtdec", ExtendedGekkoMnemonic::Mtdec, ParseAlg::Op1), PLAIN_PSEUDO("mfdec", ExtendedGekkoMnemonic::Mfdec, ParseAlg::Op1), PLAIN_PSEUDO("mtsdr1", ExtendedGekkoMnemonic::Mtsdr1, ParseAlg::Op1), PLAIN_PSEUDO("mfsdr1", ExtendedGekkoMnemonic::Mfsdr1, ParseAlg::Op1), PLAIN_PSEUDO("mtsrr0", ExtendedGekkoMnemonic::Mtsrr0, ParseAlg::Op1), PLAIN_PSEUDO("mfsrr0", ExtendedGekkoMnemonic::Mfsrr0, ParseAlg::Op1), PLAIN_PSEUDO("mtsrr1", ExtendedGekkoMnemonic::Mtsrr1, ParseAlg::Op1), PLAIN_PSEUDO("mfsrr1", ExtendedGekkoMnemonic::Mfsrr1, ParseAlg::Op1), PLAIN_PSEUDO("mtasr", ExtendedGekkoMnemonic::Mtasr, ParseAlg::Op1), PLAIN_PSEUDO("mfasr", ExtendedGekkoMnemonic::Mfasr, ParseAlg::Op1), PLAIN_PSEUDO("mtear", ExtendedGekkoMnemonic::Mtear, ParseAlg::Op1), PLAIN_PSEUDO("mfear", ExtendedGekkoMnemonic::Mfear, ParseAlg::Op1), PLAIN_PSEUDO("mttbl", ExtendedGekkoMnemonic::Mttbl, ParseAlg::Op1), PLAIN_PSEUDO("mftbl", ExtendedGekkoMnemonic::Mftbl, ParseAlg::Op1), PLAIN_PSEUDO("mttbu", ExtendedGekkoMnemonic::Mttbu, ParseAlg::Op1), PLAIN_PSEUDO("mftbu", ExtendedGekkoMnemonic::Mftbu, ParseAlg::Op1), PLAIN_PSEUDO("mtsprg", ExtendedGekkoMnemonic::Mtsprg, ParseAlg::Op2), PLAIN_PSEUDO("mfsprg", ExtendedGekkoMnemonic::Mfsprg, ParseAlg::Op2), PLAIN_PSEUDO("mtibatu", ExtendedGekkoMnemonic::Mtibatu, ParseAlg::Op2), PLAIN_PSEUDO("mfibatu", ExtendedGekkoMnemonic::Mfibatu, ParseAlg::Op2), PLAIN_PSEUDO("mtibatl", ExtendedGekkoMnemonic::Mtibatl, ParseAlg::Op2), PLAIN_PSEUDO("mfibatl", ExtendedGekkoMnemonic::Mfibatl, ParseAlg::Op2), PLAIN_PSEUDO("mtdbatu", ExtendedGekkoMnemonic::Mtdbatu, ParseAlg::Op2), PLAIN_PSEUDO("mfdbatu", ExtendedGekkoMnemonic::Mfdbatu, ParseAlg::Op2), PLAIN_PSEUDO("mtdbatl", ExtendedGekkoMnemonic::Mtdbatl, ParseAlg::Op2), PLAIN_PSEUDO("mfdbatl", ExtendedGekkoMnemonic::Mfdbatl, ParseAlg::Op2), PLAIN_PSEUDO("nop", ExtendedGekkoMnemonic::Nop, ParseAlg::None), PLAIN_PSEUDO("li", ExtendedGekkoMnemonic::Li, ParseAlg::Op2), PLAIN_PSEUDO("lis", ExtendedGekkoMnemonic::Lis, ParseAlg::Op2), PLAIN_PSEUDO("la", ExtendedGekkoMnemonic::La, ParseAlg::Op1Off1), RC_PSEUDO("mr", ExtendedGekkoMnemonic::Mr, ParseAlg::Op2), RC_PSEUDO("not", ExtendedGekkoMnemonic::Not, ParseAlg::Op2), PLAIN_PSEUDO("mtcr", ExtendedGekkoMnemonic::Mtcr, ParseAlg::Op1), PLAIN_PSEUDO("mfspr", ExtendedGekkoMnemonic::Mfspr, ParseAlg::Op2), PLAIN_PSEUDO("mftb", ExtendedGekkoMnemonic::Mftb, ParseAlg::Op2), PLAIN_PSEUDO("mtspr", ExtendedGekkoMnemonic::Mtspr, ParseAlg::Op2), }; #undef MNEMONIC #undef PLAIN_MNEMONIC #undef RC_MNEMONIC #undef OERC_MNEMONIC #undef LK_MNEMONIC #undef AALK_MNEMONIC #undef PSEUDO #undef PLAIN_PSEUDO #undef RC_PSEUDO #undef OERC_PSEUDO #undef LK_PSEUDO #undef LKAA_PSEUDO #undef LKPRED_PSEUDO #undef LKAAPRED_PSEUDO ////////////////////// // ASSEMBLER TABLES // ////////////////////// #define EMIT_MNEMONIC_ENTRY(opcode_val, extra_bits, ...) \ MnemonicDesc \ { \ InsertOpcode(opcode_val) | (extra_bits), \ static_cast(std::initializer_list{__VA_ARGS__}.size()), \ { \ __VA_ARGS__ \ } \ } #define MNEMONIC(opcode_val, extra_bits, ...) \ EMIT_MNEMONIC_ENTRY(opcode_val, extra_bits, __VA_ARGS__), INVALID_MNEMONIC, INVALID_MNEMONIC, \ INVALID_MNEMONIC #define BASIC_MNEMONIC(opcode_val, ...) MNEMONIC(opcode_val, 0, __VA_ARGS__) #define RC_MNEMONIC(opcode_val, extra_bits, ...) \ EMIT_MNEMONIC_ENTRY(opcode_val, extra_bits, __VA_ARGS__), \ EMIT_MNEMONIC_ENTRY(opcode_val, ((extra_bits) | InsertVal(1, 31, 31)), __VA_ARGS__), \ INVALID_MNEMONIC, INVALID_MNEMONIC #define OERC_MNEMONIC(opcode_val, extra_bits, ...) \ EMIT_MNEMONIC_ENTRY(opcode_val, extra_bits, __VA_ARGS__), \ EMIT_MNEMONIC_ENTRY(opcode_val, ((extra_bits) | InsertVal(1, 31, 31)), __VA_ARGS__), \ EMIT_MNEMONIC_ENTRY(opcode_val, ((extra_bits) | InsertVal(1, 21, 21)), __VA_ARGS__), \ EMIT_MNEMONIC_ENTRY( \ opcode_val, ((extra_bits) | InsertVal(1, 31, 31) | InsertVal(1, 21, 21)), __VA_ARGS__) #define LK_MNEMONIC(opcode_val, extra_bits, ...) \ EMIT_MNEMONIC_ENTRY(opcode_val, extra_bits, __VA_ARGS__), \ EMIT_MNEMONIC_ENTRY(opcode_val, ((extra_bits) | InsertVal(1, 31, 31)), __VA_ARGS__), \ INVALID_MNEMONIC, INVALID_MNEMONIC #define AALK_MNEMONIC(opcode_val, extra_bits, ...) \ EMIT_MNEMONIC_ENTRY(opcode_val, extra_bits, __VA_ARGS__), \ EMIT_MNEMONIC_ENTRY(opcode_val, ((extra_bits) | InsertVal(0b01, 30, 31)), __VA_ARGS__), \ EMIT_MNEMONIC_ENTRY(opcode_val, ((extra_bits) | InsertVal(0b10, 30, 31)), __VA_ARGS__), \ EMIT_MNEMONIC_ENTRY(opcode_val, ((extra_bits) | InsertVal(0b11, 30, 31)), __VA_ARGS__) // Defines all basic mnemonics that Broadway/Gekko supports extern const std::array mnemonics = { // A-2 OERC_MNEMONIC(31, InsertVal(266, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // add OERC_MNEMONIC(31, InsertVal(10, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // addc OERC_MNEMONIC(31, InsertVal(138, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // adde BASIC_MNEMONIC(14, OpDesc_D, OpDesc_A, OpDesc_SIMM), // addi BASIC_MNEMONIC(12, OpDesc_D, OpDesc_A, OpDesc_SIMM), // addic BASIC_MNEMONIC(13, OpDesc_D, OpDesc_A, OpDesc_SIMM), // addic. BASIC_MNEMONIC(15, OpDesc_D, OpDesc_A, OpDesc_SIMM), // addis OERC_MNEMONIC(31, InsertVal(234, 22, 30), OpDesc_D, OpDesc_A), // addme OERC_MNEMONIC(31, InsertVal(202, 22, 30), OpDesc_D, OpDesc_A), // addze OERC_MNEMONIC(31, InsertVal(491, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // divw OERC_MNEMONIC(31, InsertVal(459, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // divwu RC_MNEMONIC(31, InsertVal(75, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // mulhw RC_MNEMONIC(31, InsertVal(11, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // mulhwu BASIC_MNEMONIC(7, OpDesc_D, OpDesc_A, OpDesc_SIMM), // mulli OERC_MNEMONIC(31, InsertVal(235, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // mullw OERC_MNEMONIC(31, InsertVal(104, 22, 30), OpDesc_D, OpDesc_A), // neg OERC_MNEMONIC(31, InsertVal(40, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // subf OERC_MNEMONIC(31, InsertVal(8, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // subfc OERC_MNEMONIC(31, InsertVal(136, 22, 30), OpDesc_D, OpDesc_A, OpDesc_B), // subfe BASIC_MNEMONIC(8, OpDesc_D, OpDesc_A, OpDesc_SIMM), // subfic OERC_MNEMONIC(31, InsertVal(232, 22, 30), OpDesc_D, OpDesc_A), // subfme OERC_MNEMONIC(31, InsertVal(200, 22, 30), OpDesc_D, OpDesc_A), // subfze // A-3 MNEMONIC(31, InsertVal(0, 21, 30), OpDesc_Crfd, OpDesc_L, OpDesc_A, OpDesc_B), // cmp BASIC_MNEMONIC(11, OpDesc_Crfd, OpDesc_L, OpDesc_A, OpDesc_SIMM), // cmpi MNEMONIC(31, InsertVal(32, 21, 30), OpDesc_Crfd, OpDesc_L, OpDesc_A, OpDesc_B), // cmpl BASIC_MNEMONIC(10, OpDesc_Crfd, OpDesc_L, OpDesc_A, OpDesc_UIMM), // cmpli // A-4 RC_MNEMONIC(31, InsertVal(28, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // and RC_MNEMONIC(31, InsertVal(60, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // andc BASIC_MNEMONIC(28, OpDesc_A, OpDesc_S, OpDesc_UIMM), // andi. BASIC_MNEMONIC(29, OpDesc_A, OpDesc_S, OpDesc_UIMM), // andis. RC_MNEMONIC(31, InsertVal(26, 21, 30), OpDesc_A, OpDesc_S), // cntlzw RC_MNEMONIC(31, InsertVal(284, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // eqv RC_MNEMONIC(31, InsertVal(954, 21, 30), OpDesc_A, OpDesc_S), // extsb RC_MNEMONIC(31, InsertVal(922, 21, 30), OpDesc_A, OpDesc_S), // extsh RC_MNEMONIC(31, InsertVal(476, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // nand RC_MNEMONIC(31, InsertVal(124, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // nor RC_MNEMONIC(31, InsertVal(444, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // or RC_MNEMONIC(31, InsertVal(412, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // orc BASIC_MNEMONIC(24, OpDesc_A, OpDesc_S, OpDesc_UIMM), // ori BASIC_MNEMONIC(25, OpDesc_A, OpDesc_S, OpDesc_UIMM), // oris RC_MNEMONIC(31, InsertVal(316, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // xor BASIC_MNEMONIC(26, OpDesc_A, OpDesc_S, OpDesc_UIMM), // xori BASIC_MNEMONIC(27, OpDesc_A, OpDesc_S, OpDesc_UIMM), // xoris // A-5 RC_MNEMONIC(20, 0, OpDesc_A, OpDesc_S, OpDesc_SH, OpDesc_MB, OpDesc_ME), // rlwimi RC_MNEMONIC(21, 0, OpDesc_A, OpDesc_S, OpDesc_SH, OpDesc_MB, OpDesc_ME), // rlwinm RC_MNEMONIC(23, 0, OpDesc_A, OpDesc_S, OpDesc_B, OpDesc_MB, OpDesc_ME), // rlwnm // A-6 RC_MNEMONIC(31, InsertVal(24, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // slw RC_MNEMONIC(31, InsertVal(792, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // sraw RC_MNEMONIC(31, InsertVal(824, 21, 30), OpDesc_A, OpDesc_S, OpDesc_SH), // srawi RC_MNEMONIC(31, InsertVal(536, 21, 30), OpDesc_A, OpDesc_S, OpDesc_B), // srw // A-7 RC_MNEMONIC(63, InsertVal(21, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // fadd RC_MNEMONIC(59, InsertVal(21, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // fadds RC_MNEMONIC(63, InsertVal(18, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // fdiv RC_MNEMONIC(59, InsertVal(18, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // fdivs RC_MNEMONIC(63, InsertVal(25, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C), // fmul RC_MNEMONIC(59, InsertVal(25, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C), // fmuls RC_MNEMONIC(59, InsertVal(24, 26, 30), OpDesc_D, OpDesc_B), // fres RC_MNEMONIC(63, InsertVal(26, 26, 30), OpDesc_D, OpDesc_B), // frsqrte RC_MNEMONIC(63, InsertVal(20, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // fsub RC_MNEMONIC(59, InsertVal(20, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // fsubs RC_MNEMONIC(63, InsertVal(23, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fsel // A-8 RC_MNEMONIC(63, InsertVal(29, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fmadd RC_MNEMONIC(59, InsertVal(29, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fmadds RC_MNEMONIC(63, InsertVal(28, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fmsub RC_MNEMONIC(59, InsertVal(28, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fmsubs RC_MNEMONIC(63, InsertVal(31, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fnmadd RC_MNEMONIC(59, InsertVal(31, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fnmadds RC_MNEMONIC(63, InsertVal(30, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fnmsub RC_MNEMONIC(59, InsertVal(30, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // fnmsubs // A-9 RC_MNEMONIC(63, InsertVal(14, 21, 30), OpDesc_D, OpDesc_B), // fctiw RC_MNEMONIC(63, InsertVal(15, 21, 30), OpDesc_D, OpDesc_B), // fctiwz RC_MNEMONIC(63, InsertVal(12, 21, 30), OpDesc_D, OpDesc_B), // frsp // A-10 MNEMONIC(63, InsertVal(32, 21, 30), OpDesc_Crfd, OpDesc_A, OpDesc_B), // fcmpo MNEMONIC(63, InsertVal(0, 21, 30), OpDesc_Crfd, OpDesc_A, OpDesc_B), // fcmpu // A-11 MNEMONIC(63, InsertVal(64, 21, 30), OpDesc_Crfd, OpDesc_Crfs), // mcrfs RC_MNEMONIC(63, InsertVal(583, 21, 30), OpDesc_D), // mffs RC_MNEMONIC(63, InsertVal(70, 21, 30), OpDesc_Crbd), // mtfsb0 RC_MNEMONIC(63, InsertVal(38, 21, 30), OpDesc_Crbd), // mtfsb1 RC_MNEMONIC(63, InsertVal(711, 21, 30), OpDesc_FM, OpDesc_B), // mtfsf RC_MNEMONIC(63, InsertVal(134, 21, 30), OpDesc_Crfd, OpDesc_IMM), // mtfsfi // A-12 BASIC_MNEMONIC(34, OpDesc_D, OpDesc_Offd, OpDesc_A), // lbz BASIC_MNEMONIC(35, OpDesc_D, OpDesc_Offd, OpDesc_A), // lbzu MNEMONIC(31, InsertVal(119, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lbzux MNEMONIC(31, InsertVal(87, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lbzx BASIC_MNEMONIC(42, OpDesc_D, OpDesc_Offd, OpDesc_A), // lha BASIC_MNEMONIC(43, OpDesc_D, OpDesc_Offd, OpDesc_A), // lhau MNEMONIC(31, InsertVal(375, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lhaux MNEMONIC(31, InsertVal(343, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lhax BASIC_MNEMONIC(40, OpDesc_D, OpDesc_Offd, OpDesc_A), // lhz BASIC_MNEMONIC(41, OpDesc_D, OpDesc_Offd, OpDesc_A), // lhzu MNEMONIC(31, InsertVal(311, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lhzux MNEMONIC(31, InsertVal(279, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lhzx BASIC_MNEMONIC(32, OpDesc_D, OpDesc_Offd, OpDesc_A), // lwz BASIC_MNEMONIC(33, OpDesc_D, OpDesc_Offd, OpDesc_A), // lwzu MNEMONIC(31, InsertVal(55, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lwzux MNEMONIC(31, InsertVal(23, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lwzx // A-13 BASIC_MNEMONIC(38, OpDesc_S, OpDesc_Offd, OpDesc_A), // stb BASIC_MNEMONIC(39, OpDesc_S, OpDesc_Offd, OpDesc_A), // stbu MNEMONIC(31, InsertVal(247, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stbux MNEMONIC(31, InsertVal(215, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stbx BASIC_MNEMONIC(44, OpDesc_S, OpDesc_Offd, OpDesc_A), // sth BASIC_MNEMONIC(45, OpDesc_S, OpDesc_Offd, OpDesc_A), // sthu MNEMONIC(31, InsertVal(439, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // sthux MNEMONIC(31, InsertVal(407, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // sthx BASIC_MNEMONIC(36, OpDesc_S, OpDesc_Offd, OpDesc_A), // stw BASIC_MNEMONIC(37, OpDesc_S, OpDesc_Offd, OpDesc_A), // stwu MNEMONIC(31, InsertVal(183, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stwux MNEMONIC(31, InsertVal(151, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stwx // A-14 MNEMONIC(31, InsertVal(790, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lhbrx MNEMONIC(31, InsertVal(534, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lwbrx MNEMONIC(31, InsertVal(918, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // sthbrx MNEMONIC(31, InsertVal(662, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stwbrx // A-15 BASIC_MNEMONIC(46, OpDesc_D, OpDesc_Offd, OpDesc_A), // lmw BASIC_MNEMONIC(47, OpDesc_S, OpDesc_Offd, OpDesc_A), // stmw // A-16 MNEMONIC(31, InsertVal(597, 21, 30), OpDesc_D, OpDesc_A, OpDesc_NB), // lswi MNEMONIC(31, InsertVal(533, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lswx MNEMONIC(31, InsertVal(725, 21, 30), OpDesc_S, OpDesc_A, OpDesc_NB), // stswi MNEMONIC(31, InsertVal(661, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stswx // A-17 MNEMONIC(31, InsertVal(854, 21, 30)), // eieio MNEMONIC(19, InsertVal(150, 21, 30)), // isync MNEMONIC(31, InsertVal(20, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lwarx MNEMONIC(31, InsertVal(150, 21, 30) | InsertVal(1, 31, 31), OpDesc_S, OpDesc_A, OpDesc_B), // stwcx. MNEMONIC(31, InsertVal(598, 21, 30)), // sync // A-18 BASIC_MNEMONIC(50, OpDesc_D, OpDesc_Offd, OpDesc_A), // lfd BASIC_MNEMONIC(51, OpDesc_D, OpDesc_Offd, OpDesc_A), // lfdu MNEMONIC(31, InsertVal(631, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lfdux MNEMONIC(31, InsertVal(599, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lfdx BASIC_MNEMONIC(48, OpDesc_D, OpDesc_Offd, OpDesc_A), // lfs BASIC_MNEMONIC(49, OpDesc_D, OpDesc_Offd, OpDesc_A), // lfsu MNEMONIC(31, InsertVal(567, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lfsux MNEMONIC(31, InsertVal(535, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // lfsx // A-19 BASIC_MNEMONIC(54, OpDesc_S, OpDesc_Offd, OpDesc_A), // stfd BASIC_MNEMONIC(55, OpDesc_S, OpDesc_Offd, OpDesc_A), // stfdu MNEMONIC(31, InsertVal(759, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stfdux MNEMONIC(31, InsertVal(727, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stfdx MNEMONIC(31, InsertVal(983, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stfiwx BASIC_MNEMONIC(52, OpDesc_S, OpDesc_Offd, OpDesc_A), // stfs BASIC_MNEMONIC(53, OpDesc_S, OpDesc_Offd, OpDesc_A), // stfsu MNEMONIC(31, InsertVal(695, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stfsux MNEMONIC(31, InsertVal(663, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // stfsx // A-20 RC_MNEMONIC(63, InsertVal(264, 21, 30), OpDesc_D, OpDesc_B), // fabs RC_MNEMONIC(63, InsertVal(72, 21, 30), OpDesc_D, OpDesc_B), // fmr RC_MNEMONIC(63, InsertVal(136, 21, 30), OpDesc_D, OpDesc_B), // fnabs RC_MNEMONIC(63, InsertVal(40, 21, 30), OpDesc_D, OpDesc_B), // fneg // A-21 AALK_MNEMONIC(18, 0, OpDesc_LI), // b AALK_MNEMONIC(16, 0, OpDesc_BO, OpDesc_BI, OpDesc_BD), // bc LK_MNEMONIC(19, InsertVal(528, 21, 30), OpDesc_BO, OpDesc_BI), // bcctr LK_MNEMONIC(19, InsertVal(16, 21, 30), OpDesc_BO, OpDesc_BI), // bclr // A-22 MNEMONIC(19, InsertVal(257, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // crand MNEMONIC(19, InsertVal(129, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // crandc MNEMONIC(19, InsertVal(289, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // creqv MNEMONIC(19, InsertVal(225, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // crnand MNEMONIC(19, InsertVal(33, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // crnor MNEMONIC(19, InsertVal(449, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // cror MNEMONIC(19, InsertVal(417, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // crorc MNEMONIC(19, InsertVal(193, 21, 30), OpDesc_Crbd, OpDesc_Crba, OpDesc_Crbb), // crxor MNEMONIC(19, InsertVal(0, 21, 30), OpDesc_Crfd, OpDesc_Crfs), // mcrf // A-23 MNEMONIC(19, InsertVal(50, 21, 30)), // rfi MNEMONIC(17, InsertVal(1, 30, 30)), // sc // A-24 MNEMONIC(31, InsertVal(4, 21, 30), OpDesc_TO, OpDesc_A, OpDesc_B), // tw BASIC_MNEMONIC(3, OpDesc_TO, OpDesc_A, OpDesc_SIMM), // twi // A-25 MNEMONIC(31, InsertVal(512, 21, 30), OpDesc_Crfd), // mcrxr MNEMONIC(31, InsertVal(19, 21, 30), OpDesc_D), // mfcr MNEMONIC(31, InsertVal(83, 21, 30), OpDesc_D), // mfmsr MNEMONIC(31, InsertVal(339, 21, 30), OpDesc_D, OpDesc_SPR), // mfspr MNEMONIC(31, InsertVal(371, 21, 30), OpDesc_D, OpDesc_TPR), // mftb MNEMONIC(31, InsertVal(144, 21, 30), OpDesc_CRM, OpDesc_S), // mtcrf MNEMONIC(31, InsertVal(146, 21, 30), OpDesc_S), // mtmsr MNEMONIC(31, InsertVal(467, 21, 30), OpDesc_SPR, OpDesc_D), // mtspr // A-26 MNEMONIC(31, InsertVal(86, 21, 30), OpDesc_A, OpDesc_B), // dcbf MNEMONIC(31, InsertVal(470, 21, 30), OpDesc_A, OpDesc_B), // dcbi MNEMONIC(31, InsertVal(54, 21, 30), OpDesc_A, OpDesc_B), // dcbst MNEMONIC(31, InsertVal(278, 21, 30), OpDesc_A, OpDesc_B), // dcbt MNEMONIC(31, InsertVal(246, 21, 30), OpDesc_A, OpDesc_B), // dcbtst MNEMONIC(31, InsertVal(1014, 21, 30), OpDesc_A, OpDesc_B), // dcbz MNEMONIC(31, InsertVal(982, 21, 30), OpDesc_A, OpDesc_B), // icbi // A-27 MNEMONIC(31, InsertVal(595, 21, 30), OpDesc_D, OpDesc_SR), // mfsr MNEMONIC(31, InsertVal(659, 21, 30), OpDesc_D, OpDesc_B), // mfsrin MNEMONIC(31, InsertVal(210, 21, 30), OpDesc_SR, OpDesc_S), // mtsr MNEMONIC(31, InsertVal(242, 21, 30), OpDesc_S, OpDesc_B), // mtsrin // A-28 MNEMONIC(31, InsertVal(306, 21, 30), OpDesc_B), // tlbie MNEMONIC(31, InsertVal(566, 21, 30)), // tlbsync // A-29 MNEMONIC(31, InsertVal(310, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // eciwx MNEMONIC(31, InsertVal(438, 21, 30), OpDesc_S, OpDesc_A, OpDesc_B), // ecowx // A-30 MNEMONIC(4, InsertVal(6, 25, 30), OpDesc_D, OpDesc_A, OpDesc_B, OpDesc_W2, OpDesc_I2), // psq_lx MNEMONIC(4, InsertVal(7, 25, 30), OpDesc_S, OpDesc_A, OpDesc_B, OpDesc_W2, OpDesc_I2), // psq_stx MNEMONIC(4, InsertVal(38, 25, 30), OpDesc_D, OpDesc_A, OpDesc_B, OpDesc_W2, OpDesc_I2), // psq_lux MNEMONIC(4, InsertVal(39, 25, 30), OpDesc_S, OpDesc_A, OpDesc_B, OpDesc_W2, OpDesc_I2), // psq_stux BASIC_MNEMONIC(56, OpDesc_D, OpDesc_OffdPs, OpDesc_A, OpDesc_W1, OpDesc_I1), // psq_l BASIC_MNEMONIC(57, OpDesc_D, OpDesc_OffdPs, OpDesc_A, OpDesc_W1, OpDesc_I1), // psq_lu BASIC_MNEMONIC(60, OpDesc_S, OpDesc_OffdPs, OpDesc_A, OpDesc_W1, OpDesc_I1), // psq_st BASIC_MNEMONIC(61, OpDesc_S, OpDesc_OffdPs, OpDesc_A, OpDesc_W1, OpDesc_I1), // psq_stu // A-31 RC_MNEMONIC(4, InsertVal(18, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_div RC_MNEMONIC(4, InsertVal(20, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_sub RC_MNEMONIC(4, InsertVal(21, 26, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_add RC_MNEMONIC(4, InsertVal(23, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_sel RC_MNEMONIC(4, InsertVal(24, 26, 30), OpDesc_D, OpDesc_B), // ps_res RC_MNEMONIC(4, InsertVal(25, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C), // ps_mul RC_MNEMONIC(4, InsertVal(26, 26, 30), OpDesc_D, OpDesc_B), // ps_rsqrte RC_MNEMONIC(4, InsertVal(28, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_msub RC_MNEMONIC(4, InsertVal(29, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_madd RC_MNEMONIC(4, InsertVal(30, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_nmsub RC_MNEMONIC(4, InsertVal(31, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_nmadd RC_MNEMONIC(4, InsertVal(40, 21, 30), OpDesc_D, OpDesc_B), // ps_neg RC_MNEMONIC(4, InsertVal(72, 21, 30), OpDesc_D, OpDesc_B), // ps_mr RC_MNEMONIC(4, InsertVal(136, 21, 30), OpDesc_D, OpDesc_B), // ps_nabs RC_MNEMONIC(4, InsertVal(264, 21, 30), OpDesc_D, OpDesc_B), // ps_abs // A-32 RC_MNEMONIC(4, InsertVal(10, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_sum0 RC_MNEMONIC(4, InsertVal(11, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_sum1 RC_MNEMONIC(4, InsertVal(12, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C), // ps_muls0 RC_MNEMONIC(4, InsertVal(13, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C), // ps_muls1 RC_MNEMONIC(4, InsertVal(14, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_madds0 RC_MNEMONIC(4, InsertVal(15, 26, 30), OpDesc_D, OpDesc_A, OpDesc_C, OpDesc_B), // ps_madds1 MNEMONIC(4, InsertVal(0, 21, 30), OpDesc_Crfd, OpDesc_A, OpDesc_B), // ps_cmpu0 MNEMONIC(4, InsertVal(32, 21, 30), OpDesc_Crfd, OpDesc_A, OpDesc_B), // ps_cmpo0 MNEMONIC(4, InsertVal(64, 21, 30), OpDesc_Crfd, OpDesc_A, OpDesc_B), // ps_cmpu1 MNEMONIC(4, InsertVal(96, 21, 30), OpDesc_Crfd, OpDesc_A, OpDesc_B), // ps_cmpo1 RC_MNEMONIC(4, InsertVal(528, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_merge00 RC_MNEMONIC(4, InsertVal(560, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_merge01 RC_MNEMONIC(4, InsertVal(592, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_merge10 RC_MNEMONIC(4, InsertVal(624, 21, 30), OpDesc_D, OpDesc_A, OpDesc_B), // ps_merge11 MNEMONIC(4, InsertVal(1014, 21, 30), OpDesc_A, OpDesc_B), // dcbz_l }; namespace { // Reused operand translators for extended mnemonics void NegateSIMM(OperandList& operands) { operands[2] = static_cast(-static_cast(operands[2])); } void SwapOps1And2(OperandList& operands) { std::swap(operands[1], operands[2]); } void SetCompareWordMode(OperandList& operands) { if (operands.count == 2) { operands.Insert(0, 0); } operands.Insert(1, 0); } template void FillBOBI(OperandList& operands) { operands.Insert(0, BO); operands.Insert(1, BI); } template void BitswapIdx(OperandList& operands) { operands[Idx] = SprBitswap(operands[Idx]); } template void FillBOBICond(OperandList& operands) { if (operands.count < ParamCount) { operands.Insert(0, 0); } operands[0] = (operands[0] << 2) | Cond; operands.Insert(0, BO); } template void FillBO(OperandList& operands) { operands.Insert(0, BO); } template void TrapSetTO(OperandList& operands) { operands.Insert(0, TO); } template void FillMtspr(OperandList& operands) { operands.Insert(0, SPRG); } template void FillMfspr(OperandList& operands) { operands.Insert(1, SPRG); } template void FillMtsprBatAndBitswap(OperandList& operands) { operands[0] = SprBitswap(2 * operands[0] + SPRG); } template void FillMfsprBatAndBitswap(OperandList& operands) { operands[1] = SprBitswap(2 * operands[1] + SPRG); } } // namespace #define PSEUDO(base, variant_bits, cb) \ ExtendedMnemonicDesc { static_cast(base) * VARIANT_PERMUTATIONS + variant_bits, cb } #define PLAIN_PSEUDO(base, cb) \ PSEUDO(base, PLAIN_MNEMONIC, cb), INVALID_EXT_MNEMONIC, INVALID_EXT_MNEMONIC, INVALID_EXT_MNEMONIC #define RC_PSEUDO(base, cb) \ PSEUDO(base, PLAIN_MNEMONIC, cb), PSEUDO(base, RECORD_BIT, cb), INVALID_EXT_MNEMONIC, \ INVALID_EXT_MNEMONIC #define OERC_PSEUDO(base, cb) \ PSEUDO(base, PLAIN_MNEMONIC, cb), PSEUDO(base, RECORD_BIT, cb), \ PSEUDO(base, OVERFLOW_EXCEPTION, cb), PSEUDO(base, (RECORD_BIT | OVERFLOW_EXCEPTION), cb) #define LK_PSEUDO(base, cb) \ PSEUDO(base, PLAIN_MNEMONIC, cb), PSEUDO(base, LINK_BIT, cb), INVALID_EXT_MNEMONIC, \ INVALID_EXT_MNEMONIC #define LKAA_PSEUDO(base, cb) \ PSEUDO(base, PLAIN_MNEMONIC, cb), PSEUDO(base, LINK_BIT, cb), \ PSEUDO(base, ABSOLUTE_ADDRESS_BIT, cb), PSEUDO(base, (LINK_BIT | ABSOLUTE_ADDRESS_BIT), cb) extern const std::array extended_mnemonics = { // E.2.1 PLAIN_PSEUDO(GekkoMnemonic::Addi, NegateSIMM), // subi PLAIN_PSEUDO(GekkoMnemonic::Addis, NegateSIMM), // subis PLAIN_PSEUDO(GekkoMnemonic::Addic, NegateSIMM), // subic PLAIN_PSEUDO(GekkoMnemonic::AddicDot, NegateSIMM), // subic. // E.2.2 OERC_PSEUDO(GekkoMnemonic::Subf, SwapOps1And2), // sub OERC_PSEUDO(GekkoMnemonic::Subfc, SwapOps1And2), // subc // E.3.2 PLAIN_PSEUDO(GekkoMnemonic::Cmpi, SetCompareWordMode), // cmpwi PLAIN_PSEUDO(GekkoMnemonic::Cmp, SetCompareWordMode), // cmpw PLAIN_PSEUDO(GekkoMnemonic::Cmpli, SetCompareWordMode), // cmplwi PLAIN_PSEUDO(GekkoMnemonic::Cmpl, SetCompareWordMode), // cmplw // E.4.2 RC_PSEUDO(GekkoMnemonic::Rlwinm, ([](OperandList& operands) { const u32 n = operands[2], b = operands[3]; operands[2] = b; operands[3] = 0; operands.Insert(4, n - 1); })), // extlwi RC_PSEUDO(GekkoMnemonic::Rlwinm, ([](OperandList& operands) { const u32 n = operands[2], b = operands[3]; operands[2] = b + n; operands[3] = 32 - n; operands.Insert(4, 31); })), // extrwi RC_PSEUDO(GekkoMnemonic::Rlwimi, ([](OperandList& operands) { const u32 n = operands[2], b = operands[3]; operands[2] = 32 - b; operands[3] = b; operands.Insert(4, b + n - 1); })), // inslwi RC_PSEUDO(GekkoMnemonic::Rlwimi, ([](OperandList& operands) { const u32 n = operands[2], b = operands[3]; operands[2] = 32 - (b + n); operands[3] = b; operands.Insert(4, b + n - 1); })), // insrwi RC_PSEUDO(GekkoMnemonic::Rlwinm, ([](OperandList& operands) { operands.Insert(3, 0); operands.Insert(4, 31); })), // rotlwi RC_PSEUDO(GekkoMnemonic::Rlwinm, ([](OperandList& operands) { const u32 n = operands[2]; operands[2] = 32 - n; operands.Insert(3, 0); operands.Insert(4, 31); })), // rotrwi RC_PSEUDO(GekkoMnemonic::Rlwnm, ([](OperandList& operands) { operands.Insert(3, 0); operands.Insert(4, 31); })), // rotlw RC_PSEUDO(GekkoMnemonic::Rlwinm, ([](OperandList& operands) { const u32 n = operands[2]; operands.Insert(3, 0); operands.Insert(4, 31 - n); })), // slwi RC_PSEUDO(GekkoMnemonic::Rlwinm, ([](OperandList& operands) { const u32 n = operands[2]; operands[2] = 32 - n; operands.Insert(3, n); operands.Insert(4, 31); })), // srwi RC_PSEUDO(GekkoMnemonic::Rlwinm, ([](OperandList& operands) { const u32 n = operands[2]; operands[2] = 0; operands.Insert(3, n); operands.Insert(4, 31); })), // clrlwi RC_PSEUDO(GekkoMnemonic::Rlwinm, ([](OperandList& operands) { const u32 n = operands[2]; operands[2] = 0; operands.Insert(3, 0); operands.Insert(4, 31 - n); })), // clrrwi RC_PSEUDO(GekkoMnemonic::Rlwinm, ([](OperandList& operands) { const u32 b = operands[2], n = operands[3]; operands[2] = n; operands[3] = b - n; operands.Insert(4, 31 - n); })), // clrlslwi // E.5.2 LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBO<12>)), // bt LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBO<4>)), // bf LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBI<16, 0>)), // bdnz LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBO<8>)), // bdnzt LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBO<0>)), // bdnzf LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBI<18, 0>)), // bdz LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBO<10>)), // bdzt LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBO<2>)), // bdzf LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBO<13>)), // bt+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBO<5>)), // bf+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBI<17, 0>)), // bdnz+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBO<9>)), // bdnzt+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBO<1>)), // bdnzf+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBI<19, 0>)), // bdz+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBO<11>)), // bdzt+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBO<3>)), // bdzf+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBI<20, 0>)), // blr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBO<12>)), // btlr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBO<4>)), // bflr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBI<16, 0>)), // bdnzlr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBO<8>)), // bdnztlr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBO<0>)), // bdnzflr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBI<18, 0>)), // bdzlr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBO<10>)), // bdztlr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBO<2>)), // bdzflr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBO<13>)), // btlr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBO<5>)), // bflr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBI<17, 0>)), // bdnzlr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBO<9>)), // bdnztlr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBO<1>)), // bdnzflr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBI<19, 0>)), // bdzlr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBO<11>)), // bdztlr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBO<3>)), // bdzflr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBI<20, 0>)), // bctr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBO<12>)), // btctr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBO<4>)), // bfctr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBO<13>)), // btctr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBO<5>)), // bfctr+ // E.5.3 LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<12, 0, 2>)), // blt LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<4, 1, 2>)), // ble LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<12, 2, 2>)), // beq LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<4, 0, 2>)), // bge LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<12, 1, 2>)), // bgt LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<4, 0, 2>)), // bnl LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<4, 2, 2>)), // bne LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<4, 1, 2>)), // bng LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<12, 3, 2>)), // bso LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<4, 3, 2>)), // bns LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<12, 3, 2>)), // bun LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<4, 3, 2>)), // bnu LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<13, 0, 2>)), // blt+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<5, 1, 2>)), // ble+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<13, 2, 2>)), // beq+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<5, 0, 2>)), // bge+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<13, 1, 2>)), // bgt+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<5, 0, 2>)), // bnl+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<5, 2, 2>)), // bne+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<5, 1, 2>)), // bng+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<13, 3, 2>)), // bso+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<5, 3, 2>)), // bns+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<13, 3, 2>)), // bun+ LKAA_PSEUDO(GekkoMnemonic::Bc, (FillBOBICond<5, 3, 2>)), // bnu+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<12, 0, 1>)), // bltlr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<4, 1, 1>)), // blelr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<12, 2, 1>)), // beqlr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<4, 0, 1>)), // bgelr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<12, 1, 1>)), // bgtlr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<4, 0, 1>)), // bnllr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<4, 2, 1>)), // bnelr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<4, 1, 1>)), // bnglr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<12, 3, 1>)), // bsolr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<4, 3, 1>)), // bnslr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<12, 3, 1>)), // bunlr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<4, 3, 1>)), // bnulr LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<13, 0, 1>)), // bltlr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<5, 1, 1>)), // blelr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<13, 2, 1>)), // beqlr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<5, 0, 1>)), // bgelr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<13, 1, 1>)), // bgtlr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<5, 0, 1>)), // bnllr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<5, 2, 1>)), // bnelr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<5, 1, 1>)), // bnglr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<13, 3, 1>)), // bsolr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<5, 3, 1>)), // bnslr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<13, 3, 1>)), // bunlr+ LK_PSEUDO(GekkoMnemonic::Bclr, (FillBOBICond<5, 3, 1>)), // bnulr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<12, 0, 1>)), // bltctr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<4, 1, 1>)), // blectr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<12, 2, 1>)), // beqctr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<4, 0, 1>)), // bgectr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<12, 1, 1>)), // bgtctr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<4, 0, 1>)), // bnlctr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<4, 2, 1>)), // bnectr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<4, 1, 1>)), // bngctr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<12, 3, 1>)), // bsoctr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<4, 3, 1>)), // bnsctr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<12, 3, 1>)), // bunctr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<4, 3, 1>)), // bnuctr LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<13, 0, 1>)), // bltctr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<5, 1, 1>)), // blectr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<13, 2, 1>)), // beqctr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<5, 0, 1>)), // bgectr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<13, 1, 1>)), // bgtctr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<5, 0, 1>)), // bnlctr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<5, 2, 1>)), // bnectr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<5, 1, 1>)), // bngctr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<13, 3, 1>)), // bsoctr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<5, 3, 1>)), // bnsctr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<13, 3, 1>)), // bunctr+ LK_PSEUDO(GekkoMnemonic::Bcctr, (FillBOBICond<5, 3, 1>)), // bnuctr+ // E.6 PLAIN_PSEUDO(GekkoMnemonic::Creqv, [](OperandList& operands) { operands.Insert(1, operands[0]); operands.Insert(2, operands[0]); }), // crset PLAIN_PSEUDO(GekkoMnemonic::Crxor, [](OperandList& operands) { operands.Insert(1, operands[0]); operands.Insert(2, operands[0]); }), // crclr PLAIN_PSEUDO(GekkoMnemonic::Cror, [](OperandList& operands) { operands.Insert(2, operands[1]); }), // crmove PLAIN_PSEUDO(GekkoMnemonic::Crnor, [](OperandList& operands) { operands.Insert(2, operands[1]); }), // crnot // E.7 PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<16>), // twlt PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<16>), // twlti PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<20>), // twle PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<20>), // twlei PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<4>), // tweq PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<4>), // tweqi PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<12>), // twge PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<12>), // twgei PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<8>), // twgt PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<8>), // twgti PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<12>), // twnl PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<12>), // twnli PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<24>), // twne PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<24>), // twnei PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<20>), // twng PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<20>), // twngi PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<2>), // twllt PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<2>), // twllti PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<6>), // twlle PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<6>), // twllei PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<5>), // twlge PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<5>), // twlgei PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<1>), // twlgt PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<1>), // twlgti PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<5>), // twlnl PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<5>), // twlnli PLAIN_PSEUDO(GekkoMnemonic::Tw, TrapSetTO<6>), // twlng PLAIN_PSEUDO(GekkoMnemonic::Twi, TrapSetTO<6>), // twlngi PLAIN_PSEUDO(GekkoMnemonic::Tw, [](OperandList& operands) { operands.Insert(0, 31); operands.Insert(1, 0); operands.Insert(2, 0); }), // trap // E.8 PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtspr), // mtxer PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfspr), // mfxer PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtspr), // mtlr PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfspr), // mflr PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtspr), // mtctr PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfspr), // mfctr PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtspr), // mtdsisr PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfspr), // mfdsisr PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtspr), // mtdar PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfspr), // mfdar PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtspr), // mtdec PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfspr), // mfdec PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtspr), // mtsdr1 PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfspr), // mfsdr1 PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtspr), // mtsrr0 PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfspr), // mfsrr0 PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtspr), // mtsrr1 PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfspr), // mfsrr1 PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtspr), // mtasr PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfspr), // mfasr PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtspr), // mtear PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfspr), // mfear PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtspr), // mttbl PLAIN_PSEUDO(GekkoMnemonic::Mftb_nobitswap, FillMfspr), // mftbl PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtspr), // mttbu PLAIN_PSEUDO(GekkoMnemonic::Mftb_nobitswap, FillMfspr), // mftbu PLAIN_PSEUDO( GekkoMnemonic::Mtspr_nobitswap, [](OperandList& operands) { operands[0] = SprBitswap(operands[0] + 272); }), // mtsprg PLAIN_PSEUDO( GekkoMnemonic::Mfspr_nobitswap, [](OperandList& operands) { operands[1] = SprBitswap(operands[1] + 272); }), // mfsprg PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtsprBatAndBitswap<528>), // mtibatu PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfsprBatAndBitswap<528>), // mfibatu PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtsprBatAndBitswap<529>), // mtibatl PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfsprBatAndBitswap<529>), // mfibatl PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtsprBatAndBitswap<536>), // mtdbatu PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfsprBatAndBitswap<536>), // mfdbatu PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, FillMtsprBatAndBitswap<537>), // mtdbatl PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, FillMfsprBatAndBitswap<537>), // mfdbatl // E.9 PLAIN_PSEUDO(GekkoMnemonic::Ori, [](OperandList& operands) { operands.Insert(0, 0); operands.Insert(1, 0); operands.Insert(2, 0); }), // nop PLAIN_PSEUDO(GekkoMnemonic::Addi, [](OperandList& operands) { operands.Insert(1, 0); }), // li PLAIN_PSEUDO(GekkoMnemonic::Addis, [](OperandList& operands) { operands.Insert(1, 0); }), // lis PLAIN_PSEUDO(GekkoMnemonic::Addi, SwapOps1And2), // la RC_PSEUDO(GekkoMnemonic::Or, ([](OperandList& operands) { operands.Insert(2, operands[1]); })), // mr RC_PSEUDO(GekkoMnemonic::Nor, ([](OperandList& operands) { operands.Insert(2, operands[1]); })), // not PLAIN_PSEUDO(GekkoMnemonic::Mtcrf, [](OperandList& operands) { operands.Insert(0, 0xff); }), // mtcr // Additional mnemonics PLAIN_PSEUDO(GekkoMnemonic::Mfspr_nobitswap, BitswapIdx<1>), // mfspr PLAIN_PSEUDO(GekkoMnemonic::Mftb_nobitswap, BitswapIdx<1>), // mfspr PLAIN_PSEUDO(GekkoMnemonic::Mtspr_nobitswap, BitswapIdx<0>), // mtspr }; #undef EMIT_MNEMONIC_ENTRY #undef MNEMONIC #undef BASIC_MNEMONIC #undef RC_MNEMONIC #undef OERC_MNEMONIC #undef LK_MNEMONIC #undef AALK_MNEMONIC #undef PSEUDO #undef PLAIN_PSEUDO #undef RC_PSEUDO #undef OERC_PSEUDO #undef LK_PSEUDO #undef LKAA_PSEUDO ////////////////// // LEXER TABLES // ////////////////// namespace { constexpr TransitionF HasPlusOrMinus = [](char c) { return c == '+' || c == '-'; }; constexpr TransitionF HasDigit = [](char c) -> bool { return std::isdigit(c); }; constexpr TransitionF HasE = [](char c) { return c == 'e'; }; constexpr TransitionF HasDot = [](char c) { return c == '.'; }; // Normal string characters constexpr TransitionF HasNormal = [](char c) { return c != '\n' && c != '"' && c != '\\'; }; // Invalid characters in string constexpr TransitionF HasInvalid = [](char c) { return c == '\n'; }; // Octal digits constexpr TransitionF HasOctal = [](char c) { return c >= '0' && c <= '7'; }; // Hex digits constexpr TransitionF HasHex = [](char c) -> bool { return std::isxdigit(c); }; // Normal - octal constexpr TransitionF HasNormalMinusOctal = [](char c) { return HasNormal(c) && !HasOctal(c); }; // Normal - hex constexpr TransitionF HasNormalMinusHex = [](char c) { return HasNormal(c) && !HasHex(c); }; // Escape start constexpr TransitionF HasEscape = [](char c) { return c == '\\'; }; // All single-character escapes constexpr TransitionF HasSCE = [](char c) { return !HasOctal(c) && c != 'x' && c != '\n'; }; // Hex escape constexpr TransitionF HasHexStart = [](char c) { return c == 'x'; }; constexpr TransitionF HasQuote = [](char c) { return c == '"'; }; } // namespace extern const std::vector float_dfa = { {{DfaEdge(HasPlusOrMinus, 1), DfaEdge(HasDigit, 2), DfaEdge(HasDot, 5)}, "Invalid float: No numeric value"}, {{DfaEdge(HasDigit, 2), DfaEdge(HasDot, 5)}, "Invalid float: No numeric value"}, {{DfaEdge(HasDigit, 2), DfaEdge(HasDot, 3), DfaEdge(HasE, 7)}, std::nullopt}, {{DfaEdge(HasDigit, 4)}, "Invalid float: No numeric value after decimal point"}, {{DfaEdge(HasDigit, 4), DfaEdge(HasE, 7)}, std::nullopt}, {{DfaEdge(HasDigit, 6)}, "Invalid float: No numeric value after decimal point"}, {{DfaEdge(HasDigit, 6), DfaEdge(HasE, 7)}, std::nullopt}, {{DfaEdge(HasDigit, 9), DfaEdge(HasPlusOrMinus, 8)}, "Invalid float: No numeric value following exponent signifier"}, {{DfaEdge(HasDigit, 9)}, "Invalid float: No numeric value following exponent signifier"}, {{DfaEdge(HasDigit, 9)}, std::nullopt}, }; extern const std::vector string_dfa = { // Base character check {{DfaEdge(HasNormal, 0), DfaEdge(HasInvalid, 1), DfaEdge(HasQuote, 2), DfaEdge(HasEscape, 3)}, "Invalid string: No terminating \""}, // Invalid (unescaped newline) {{}, "Invalid string: No terminating \""}, // String end {{}, std::nullopt}, // Escape character breakout {{DfaEdge(HasSCE, 0), DfaEdge(HasInvalid, 1), DfaEdge(HasOctal, 4), DfaEdge(HasHexStart, 6)}, "Invalid string: No terminating \""}, // Octal characters, at most 3 {{DfaEdge(HasNormalMinusOctal, 0), DfaEdge(HasInvalid, 1), DfaEdge(HasQuote, 2), DfaEdge(HasEscape, 3), DfaEdge(HasOctal, 5)}, "Invalid string: No terminating \""}, {{DfaEdge(HasNormal, 0), DfaEdge(HasInvalid, 1), DfaEdge(HasQuote, 2), DfaEdge(HasEscape, 3)}, "Invalid string: No terminating \""}, // Hex characters, 1 or more {{DfaEdge(HasHex, 7)}, "Invalid string: bad hex escape"}, {{DfaEdge(HasNormalMinusHex, 0), DfaEdge(HasInvalid, 1), DfaEdge(HasQuote, 2), DfaEdge(HasEscape, 3), DfaEdge(HasHex, 7)}, "Invalid string: No terminating \""}, }; } // namespace Common::GekkoAssembler::detail