#include <sys/param.h>
#include <sys/systm.h>
#include <sys/types.h>
#include <machine/db_machdep.h>
#include <lib/libkern/libkern.h>
#include <arch/arm64/arm64/disasm.h>
#ifndef PRId64
#define PRId64 "lld"
#endif
#ifndef PRIu64
#define PRIu64 "llu"
#endif
#ifndef PRIx64
#define PRIx64 "llx"
#endif
#define __arraycount(_a) nitems(_a)
#define fls64(_n) flsl(_n)
#define PRINTF di->di_printf
#define PRINTADDR di->di_printaddr
#define OPFUNC_DECL(func, a, b, c, d, e, f, g, h) \
func(const disasm_interface_t *di, uint64_t pc, uint32_t insn, \
uint64_t a, uint64_t b, uint64_t c, uint64_t d, \
uint64_t e, uint64_t f, uint64_t g, uint64_t h)
#define UNUSED0 arg0 __unused
#define UNUSED1 arg1 __unused
#define UNUSED2 arg2 __unused
#define UNUSED3 arg3 __unused
#define UNUSED4 arg4 __unused
#define UNUSED5 arg5 __unused
#define UNUSED6 arg6 __unused
#define UNUSED7 arg7 __unused
#define OP0FUNC(func) \
static void \
OPFUNC_DECL(func, \
UNUSED0, UNUSED1, UNUSED2, UNUSED3, \
UNUSED4, UNUSED5, UNUSED6, UNUSED7)
#define OP1FUNC(func, a) \
static void \
OPFUNC_DECL(func, a, \
UNUSED1, UNUSED2, UNUSED3, UNUSED4, \
UNUSED5, UNUSED6, UNUSED7)
#define OP2FUNC(func, a, b) \
static void \
OPFUNC_DECL(func, a, b, \
UNUSED2, UNUSED3, UNUSED4, UNUSED5, \
UNUSED6, UNUSED7)
#define OP3FUNC(func, a, b, c) \
static void \
OPFUNC_DECL(func, a, b, c, \
UNUSED3, UNUSED4, UNUSED5, UNUSED6, \
UNUSED7)
#define OP4FUNC(func, a, b, c, d) \
static void \
OPFUNC_DECL(func, a, b, c, d, \
UNUSED4, UNUSED5, UNUSED6, UNUSED7)
#define OP5FUNC(func, a, b, c, d, e) \
static void \
OPFUNC_DECL( func, a, b, c, d, e, \
UNUSED5, UNUSED6, UNUSED7)
#define OP6FUNC(func, a, b, c, d, e, f) \
static void \
OPFUNC_DECL(func, a, b, c, d, e, f, \
UNUSED6, UNUSED7)
#define OP7FUNC(func, a, b, c, d, e, f, g) \
static void \
OPFUNC_DECL(func, a, b, c, d, e, f, g, \
UNUSED7)
#define OP8FUNC(func, a, b, c, d, e, f, g, h) \
static void \
OPFUNC_DECL(func, a, b, c, d, e, f, g, h)
static const char *z_wxregs[2][32] = {
{
"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
"w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
"w24", "w25", "w26", "w27", "w28", "w29", "w30", "wzr"
},
{
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
"x24", "x25", "x26", "x27", "x28", "x29", "x30", "xzr"
}
};
static const char *s_wxregs[2][32] = {
{
"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
"w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
"w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp"
},
{
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
"x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp"
}
};
#define ZREGNAME(s, n) (z_wxregs[(s) & 1][(n) & 31])
#define SREGNAME(s, n) (s_wxregs[(s) & 1][(n) & 31])
static const char *simdregs[5][32] = {
{
"b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
"b8", "b9", "b10", "b11", "b12", "b13", "b14", "b15",
"b16", "b17", "b18", "b19", "b20", "b21", "b22", "b23",
"b24", "b25", "b26", "b27", "b28", "b29", "b30", "b31"
},
{
"h0", "h1", "h2", "h3", "h4", "h5", "h6", "h7",
"h8", "h9", "h10", "h11", "h12", "h13", "h14", "h15",
"h16", "h17", "h18", "h19", "h20", "h21", "h22", "h23",
"h24", "h25", "h26", "h27", "h28", "h29", "h30", "h31"
},
{
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
"s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
"s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"
},
{
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
"d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
"d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
"d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"
},
{
"q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15",
"q16", "q17", "q18", "q19", "q20", "q21", "q22", "q23",
"q24", "q25", "q26", "q27", "q28", "q29", "q30", "q31"
}
};
#define FREGSZ_B 0
#define FREGSZ_H 1
#define FREGSZ_S 2
#define FREGSZ_D 3
#define FREGSZ_Q 4
#define FREGNAME(s, n) (simdregs[(s)][(n) & 31])
static const char *vecregs[32] = {
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
};
#define VREGNAME(n) vecregs[(n) & 31]
static const char *cregs[16] = {
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7",
"C8", "C9", "C10", "C11", "C12", "C13", "C14", "C15"
};
#define CREGNAME(n) cregs[(n) & 15]
static const char *conditioncode[16] = {
"eq", "ne", "cs", "cc",
"mi", "pl", "vs", "vc",
"hi", "ls", "ge", "lt",
"gt", "le", "al", "nv"
};
#define CONDNAME(c) conditioncode[(c) & 15]
#define IVCONDNAME(c) conditioncode[((c) ^ 1) & 15]
static const char *barrierop[16] = {
"#0", "oshld", "oshst", "osh",
"#4", "nshld", "nshst", "nsh",
"#8", "ishld", "ishst", "ish",
"#12", "ld", "st", "sy"
};
#define BARRIERNAME(op) barrierop[(op) & 15]
static const char *prefetchop[32] = {
"pldl1keep", "pldl1strm", "pldl2keep", "pldl2strm",
"pldl3keep", "pldl3strm", "#6", "#7",
"plil1keep", "plil1strm", "plil2keep", "plil2strm",
"plil3keep", "plil3strm", "#14", "#15",
"pstl1keep", "pstl1strm", "pstl2keep", "pstl2strm",
"pstl3keep", "pstl3strm", "#22", "#23",
"#24", "#25", "#26", "#27",
"#28", "#29", "#30", "#31"
};
#define PREFETCHNAME(op) prefetchop[(op) & 31]
#define SYSREG_ENC(op0, op1, CRn, CRm, op2) \
(((op0)<<19)|((op1)<<16)|((CRn)<<12)|((CRm)<<8)|((op2)<<5))
struct sysreg_table {
uint32_t code;
const char *regname;
};
const struct sysreg_table sysreg_table[] = {
{ SYSREG_ENC(2, 0, 0, 0, 2), "osdtrrx_el1" },
{ SYSREG_ENC(2, 0, 0, 0, 4), "dbgbvr0_el1" },
{ SYSREG_ENC(2, 0, 0, 0, 5), "dbgbcr0_el1" },
{ SYSREG_ENC(2, 0, 0, 0, 6), "dbgwvr0_el1" },
{ SYSREG_ENC(2, 0, 0, 0, 7), "dbgwcr0_el1" },
{ SYSREG_ENC(2, 0, 0, 1, 4), "dbgbvr1_el1" },
{ SYSREG_ENC(2, 0, 0, 1, 5), "dbgbcr1_el1" },
{ SYSREG_ENC(2, 0, 0, 1, 6), "dbgwvr1_el1" },
{ SYSREG_ENC(2, 0, 0, 1, 7), "dbgwcr1_el1" },
{ SYSREG_ENC(2, 0, 0, 2, 0), "mdccint_el1" },
{ SYSREG_ENC(2, 0, 0, 2, 2), "mdscr_el1" },
{ SYSREG_ENC(2, 0, 0, 2, 4), "dbgbvr2_el1" },
{ SYSREG_ENC(2, 0, 0, 2, 5), "dbgbcr2_el1" },
{ SYSREG_ENC(2, 0, 0, 2, 6), "dbgwvr2_el1" },
{ SYSREG_ENC(2, 0, 0, 2, 7), "dbgwcr2_el1" },
{ SYSREG_ENC(2, 0, 0, 3, 2), "osdtrtx_el1" },
{ SYSREG_ENC(2, 0, 0, 3, 4), "dbgbvr3_el1" },
{ SYSREG_ENC(2, 0, 0, 3, 5), "dbgbcr3_el1" },
{ SYSREG_ENC(2, 0, 0, 3, 6), "dbgwvr3_el1" },
{ SYSREG_ENC(2, 0, 0, 3, 7), "dbgwcr3_el1" },
{ SYSREG_ENC(2, 0, 0, 4, 4), "dbgbvr4_el1" },
{ SYSREG_ENC(2, 0, 0, 4, 5), "dbgbcr4_el1" },
{ SYSREG_ENC(2, 0, 0, 4, 6), "dbgwvr4_el1" },
{ SYSREG_ENC(2, 0, 0, 4, 7), "dbgwcr4_el1" },
{ SYSREG_ENC(2, 0, 0, 5, 4), "dbgbvr5_el1" },
{ SYSREG_ENC(2, 0, 0, 5, 5), "dbgbcr5_el1" },
{ SYSREG_ENC(2, 0, 0, 5, 6), "dbgwvr5_el1" },
{ SYSREG_ENC(2, 0, 0, 5, 7), "dbgwcr5_el1" },
{ SYSREG_ENC(2, 0, 0, 6, 2), "oseccr_el1" },
{ SYSREG_ENC(2, 0, 0, 6, 4), "dbgbvr6_el1" },
{ SYSREG_ENC(2, 0, 0, 6, 5), "dbgbcr6_el1" },
{ SYSREG_ENC(2, 0, 0, 6, 6), "dbgwvr6_el1" },
{ SYSREG_ENC(2, 0, 0, 6, 7), "dbgwcr6_el1" },
{ SYSREG_ENC(2, 0, 0, 7, 4), "dbgbvr7_el1" },
{ SYSREG_ENC(2, 0, 0, 7, 5), "dbgbcr7_el1" },
{ SYSREG_ENC(2, 0, 0, 7, 6), "dbgwvr7_el1" },
{ SYSREG_ENC(2, 0, 0, 7, 7), "dbgwcr7_el1" },
{ SYSREG_ENC(2, 0, 0, 8, 4), "dbgbvr8_el1" },
{ SYSREG_ENC(2, 0, 0, 8, 5), "dbgbcr8_el1" },
{ SYSREG_ENC(2, 0, 0, 8, 6), "dbgwvr8_el1" },
{ SYSREG_ENC(2, 0, 0, 8, 7), "dbgwcr8_el1" },
{ SYSREG_ENC(2, 0, 0, 9, 4), "dbgbvr9_el1" },
{ SYSREG_ENC(2, 0, 0, 9, 5), "dbgbcr9_el1" },
{ SYSREG_ENC(2, 0, 0, 9, 6), "dbgwvr9_el1" },
{ SYSREG_ENC(2, 0, 0, 9, 7), "dbgwcr9_el1" },
{ SYSREG_ENC(2, 0, 0, 10, 4), "dbgbvr10_el1" },
{ SYSREG_ENC(2, 0, 0, 10, 5), "dbgbcr10_el1" },
{ SYSREG_ENC(2, 0, 0, 10, 6), "dbgwvr10_el1" },
{ SYSREG_ENC(2, 0, 0, 10, 7), "dbgwcr10_el1" },
{ SYSREG_ENC(2, 0, 0, 11, 4), "dbgbvr11_el1" },
{ SYSREG_ENC(2, 0, 0, 11, 5), "dbgbcr11_el1" },
{ SYSREG_ENC(2, 0, 0, 11, 6), "dbgwvr11_el1" },
{ SYSREG_ENC(2, 0, 0, 11, 7), "dbgwcr11_el1" },
{ SYSREG_ENC(2, 0, 0, 12, 4), "dbgbvr12_el1" },
{ SYSREG_ENC(2, 0, 0, 12, 5), "dbgbcr12_el1" },
{ SYSREG_ENC(2, 0, 0, 12, 6), "dbgwvr12_el1" },
{ SYSREG_ENC(2, 0, 0, 12, 7), "dbgwcr12_el1" },
{ SYSREG_ENC(2, 0, 0, 13, 4), "dbgbvr13_el1" },
{ SYSREG_ENC(2, 0, 0, 13, 5), "dbgbcr13_el1" },
{ SYSREG_ENC(2, 0, 0, 13, 6), "dbgwvr13_el1" },
{ SYSREG_ENC(2, 0, 0, 13, 7), "dbgwcr13_el1" },
{ SYSREG_ENC(2, 0, 0, 14, 4), "dbgbvr14_el1" },
{ SYSREG_ENC(2, 0, 0, 14, 5), "dbgbcr14_el1" },
{ SYSREG_ENC(2, 0, 0, 14, 6), "dbgwvr14_el1" },
{ SYSREG_ENC(2, 0, 0, 14, 7), "dbgwcr14_el1" },
{ SYSREG_ENC(2, 0, 0, 15, 4), "dbgbvr15_el1" },
{ SYSREG_ENC(2, 0, 0, 15, 5), "dbgbcr15_el1" },
{ SYSREG_ENC(2, 0, 0, 15, 6), "dbgwvr15_el1" },
{ SYSREG_ENC(2, 0, 0, 15, 7), "dbgwcr15_el1" },
{ SYSREG_ENC(2, 0, 1, 0, 0), "mdrar_el1" },
{ SYSREG_ENC(2, 0, 1, 0, 4), "oslar_el1" },
{ SYSREG_ENC(2, 0, 1, 1, 4), "oslsr_el1" },
{ SYSREG_ENC(2, 0, 1, 3, 4), "osdlr_el1" },
{ SYSREG_ENC(2, 0, 1, 4, 4), "dbgprcr_el1" },
{ SYSREG_ENC(2, 0, 7, 8, 6), "dbgclaimset_el1" },
{ SYSREG_ENC(2, 0, 7, 9, 6), "dbgclaimclr_el1" },
{ SYSREG_ENC(2, 0, 7, 14, 6), "dbgauthstatus_el1" },
{ SYSREG_ENC(2, 2, 0, 0, 0), "teecr32_el1" },
{ SYSREG_ENC(2, 2, 1, 0, 0), "teehbr32_el1" },
{ SYSREG_ENC(2, 3, 0, 1, 0), "mdccsr_el0" },
{ SYSREG_ENC(2, 3, 0, 4, 0), "dbgdtr_el0" },
{ SYSREG_ENC(2, 3, 0, 5, 0), "dbgdtrrx_el0" },
{ SYSREG_ENC(2, 4, 0, 7, 0), "dbgvcr32_el2" },
{ SYSREG_ENC(3, 0, 0, 0, 0), "midr_el1" },
{ SYSREG_ENC(3, 0, 0, 0, 5), "mpidr_el1" },
{ SYSREG_ENC(3, 0, 0, 0, 6), "revidr_el1" },
{ SYSREG_ENC(3, 0, 0, 1, 0), "id_pfr0_el1" },
{ SYSREG_ENC(3, 0, 0, 1, 1), "id_pfr1_el1" },
{ SYSREG_ENC(3, 0, 0, 1, 2), "id_dfr0_el1" },
{ SYSREG_ENC(3, 0, 0, 1, 3), "id_afr0_el1" },
{ SYSREG_ENC(3, 0, 0, 1, 4), "id_mmfr0_el1" },
{ SYSREG_ENC(3, 0, 0, 1, 5), "id_mmfr1_el1" },
{ SYSREG_ENC(3, 0, 0, 1, 6), "id_mmfr2_el1" },
{ SYSREG_ENC(3, 0, 0, 1, 7), "id_mmfr3_el1" },
{ SYSREG_ENC(3, 0, 0, 2, 0), "id_isar0_el1" },
{ SYSREG_ENC(3, 0, 0, 2, 1), "id_isar1_el1" },
{ SYSREG_ENC(3, 0, 0, 2, 2), "id_isar2_el1" },
{ SYSREG_ENC(3, 0, 0, 2, 3), "id_isar3_el1" },
{ SYSREG_ENC(3, 0, 0, 2, 4), "id_isar4_el1" },
{ SYSREG_ENC(3, 0, 0, 2, 5), "id_isar5_el1" },
{ SYSREG_ENC(3, 0, 0, 3, 0), "mvfr0_el1" },
{ SYSREG_ENC(3, 0, 0, 3, 1), "mvfr1_el1" },
{ SYSREG_ENC(3, 0, 0, 3, 2), "mvfr2_el1" },
{ SYSREG_ENC(3, 0, 0, 4, 0), "id_aa64pfr0_el1" },
{ SYSREG_ENC(3, 0, 0, 4, 1), "id_aa64pfr1_el1" },
{ SYSREG_ENC(3, 0, 0, 5, 0), "id_aa64dfr0_el1" },
{ SYSREG_ENC(3, 0, 0, 5, 1), "id_aa64dfr1_el1" },
{ SYSREG_ENC(3, 0, 0, 5, 4), "id_aa64afr0_el1" },
{ SYSREG_ENC(3, 0, 0, 5, 5), "id_aa64afr1_el1" },
{ SYSREG_ENC(3, 0, 0, 6, 0), "id_aa64isar0_el1" },
{ SYSREG_ENC(3, 0, 0, 6, 1), "id_aa64isar1_el1" },
{ SYSREG_ENC(3, 0, 0, 7, 0), "id_aa64mmfr0_el1" },
{ SYSREG_ENC(3, 0, 0, 7, 1), "id_aa64mmfr1_el1" },
{ SYSREG_ENC(3, 0, 1, 0, 0), "sctlr_el1" },
{ SYSREG_ENC(3, 0, 1, 0, 1), "actlr_el1" },
{ SYSREG_ENC(3, 0, 1, 0, 2), "cpacr_el1" },
{ SYSREG_ENC(3, 0, 2, 0, 0), "ttbr0_el1" },
{ SYSREG_ENC(3, 0, 2, 0, 1), "ttbr1_el1" },
{ SYSREG_ENC(3, 0, 2, 0, 2), "tcr_el1" },
{ SYSREG_ENC(3, 0, 4, 0, 0), "spsr_el1" },
{ SYSREG_ENC(3, 0, 4, 0, 1), "elr_el1" },
{ SYSREG_ENC(3, 0, 4, 1, 0), "sp_el0" },
{ SYSREG_ENC(3, 0, 4, 2, 0), "spsel" },
{ SYSREG_ENC(3, 0, 4, 2, 2), "currentel" },
{ SYSREG_ENC(3, 0, 5, 1, 0), "afsr0_el1" },
{ SYSREG_ENC(3, 0, 5, 1, 1), "afsr1_el1" },
{ SYSREG_ENC(3, 0, 5, 2, 0), "esr_el1" },
{ SYSREG_ENC(3, 0, 6, 0, 0), "far_el1" },
{ SYSREG_ENC(3, 0, 7, 4, 0), "par_el1" },
{ SYSREG_ENC(3, 0, 9, 14, 1), "pmintenset_el1" },
{ SYSREG_ENC(3, 0, 9, 14, 2), "pmintenclr_el1" },
{ SYSREG_ENC(3, 0, 10, 2, 0), "mair_el1" },
{ SYSREG_ENC(3, 0, 10, 3, 0), "amair_el1" },
{ SYSREG_ENC(3, 0, 12, 0, 0), "vbar_el1" },
{ SYSREG_ENC(3, 0, 12, 0, 1), "rvbar_el1" },
{ SYSREG_ENC(3, 0, 12, 0, 2), "rmr_el1" },
{ SYSREG_ENC(3, 0, 12, 1, 0), "isr_el1" },
{ SYSREG_ENC(3, 0, 13, 0, 1), "contextidr_el1" },
{ SYSREG_ENC(3, 0, 13, 0, 4), "tpidr_el1" },
{ SYSREG_ENC(3, 0, 14, 1, 0), "cntkctl_el1" },
{ SYSREG_ENC(3, 1, 0, 0, 0), "ccsidr_el1" },
{ SYSREG_ENC(3, 1, 0, 0, 1), "clidr_el1" },
{ SYSREG_ENC(3, 1, 0, 0, 7), "aidr_el1" },
{ SYSREG_ENC(3, 2, 0, 0, 0), "csselr_el1" },
{ SYSREG_ENC(3, 3, 0, 0, 1), "ctr_el0" },
{ SYSREG_ENC(3, 3, 0, 0, 7), "dczid_el0" },
{ SYSREG_ENC(3, 3, 4, 2, 0), "nzcv" },
{ SYSREG_ENC(3, 3, 4, 2, 1), "daif" },
{ SYSREG_ENC(3, 3, 4, 4, 0), "fpcr" },
{ SYSREG_ENC(3, 3, 4, 4, 1), "fpsr" },
{ SYSREG_ENC(3, 3, 4, 5, 0), "dspsr_el0" },
{ SYSREG_ENC(3, 3, 4, 5, 1), "dlr_el0" },
{ SYSREG_ENC(3, 3, 9, 12, 0), "pmcr_el0" },
{ SYSREG_ENC(3, 3, 9, 12, 1), "pmcntenset_el0" },
{ SYSREG_ENC(3, 3, 9, 12, 2), "pmcntenclr_el0" },
{ SYSREG_ENC(3, 3, 9, 12, 3), "pmovsclr_el0" },
{ SYSREG_ENC(3, 3, 9, 12, 4), "pmswinc_el0" },
{ SYSREG_ENC(3, 3, 9, 12, 5), "pmselr_el0" },
{ SYSREG_ENC(3, 3, 9, 12, 6), "pmceid0_el0" },
{ SYSREG_ENC(3, 3, 9, 12, 7), "pmceid1_el0" },
{ SYSREG_ENC(3, 3, 9, 13, 0), "pmccntr_el0" },
{ SYSREG_ENC(3, 3, 9, 13, 1), "pmxevtyper_el0" },
{ SYSREG_ENC(3, 3, 9, 13, 2), "pmxevcntr_el0" },
{ SYSREG_ENC(3, 3, 9, 14, 0), "pmuserenr_el0" },
{ SYSREG_ENC(3, 3, 9, 14, 3), "pmovsset_el0" },
{ SYSREG_ENC(3, 3, 13, 0, 2), "tpidr_el0" },
{ SYSREG_ENC(3, 3, 13, 0, 3), "tpidrro_el0" },
{ SYSREG_ENC(3, 3, 14, 0, 0), "cntfrq_el0" },
{ SYSREG_ENC(3, 3, 14, 0, 1), "cntpct_el0" },
{ SYSREG_ENC(3, 3, 14, 0, 2), "cntvct_el0" },
{ SYSREG_ENC(3, 3, 14, 2, 0), "cntp_tval_el0" },
{ SYSREG_ENC(3, 3, 14, 2, 1), "cntp_ctl_el0" },
{ SYSREG_ENC(3, 3, 14, 2, 2), "cntp_cval_el0" },
{ SYSREG_ENC(3, 3, 14, 3, 0), "cntv_tval_el0" },
{ SYSREG_ENC(3, 3, 14, 3, 1), "cntv_ctl_el0" },
{ SYSREG_ENC(3, 3, 14, 3, 2), "cntv_cval_el0" },
{ SYSREG_ENC(3, 3, 14, 8, 0), "pmevcntr0_el0" },
{ SYSREG_ENC(3, 3, 14, 8, 1), "pmevcntr1_el0" },
{ SYSREG_ENC(3, 3, 14, 8, 2), "pmevcntr2_el0" },
{ SYSREG_ENC(3, 3, 14, 8, 3), "pmevcntr3_el0" },
{ SYSREG_ENC(3, 3, 14, 8, 4), "pmevcntr4_el0" },
{ SYSREG_ENC(3, 3, 14, 8, 5), "pmevcntr5_el0" },
{ SYSREG_ENC(3, 3, 14, 8, 6), "pmevcntr6_el0" },
{ SYSREG_ENC(3, 3, 14, 8, 7), "pmevcntr7_el0" },
{ SYSREG_ENC(3, 3, 14, 9, 0), "pmevcntr8_el0" },
{ SYSREG_ENC(3, 3, 14, 9, 1), "pmevcntr9_el0" },
{ SYSREG_ENC(3, 3, 14, 9, 2), "pmevcntr10_el0" },
{ SYSREG_ENC(3, 3, 14, 9, 3), "pmevcntr11_el0" },
{ SYSREG_ENC(3, 3, 14, 9, 4), "pmevcntr12_el0" },
{ SYSREG_ENC(3, 3, 14, 9, 5), "pmevcntr13_el0" },
{ SYSREG_ENC(3, 3, 14, 9, 6), "pmevcntr14_el0" },
{ SYSREG_ENC(3, 3, 14, 9, 7), "pmevcntr15_el0" },
{ SYSREG_ENC(3, 3, 14, 10, 0), "pmevcntr16_el0" },
{ SYSREG_ENC(3, 3, 14, 10, 1), "pmevcntr17_el0" },
{ SYSREG_ENC(3, 3, 14, 10, 2), "pmevcntr18_el0" },
{ SYSREG_ENC(3, 3, 14, 10, 3), "pmevcntr19_el0" },
{ SYSREG_ENC(3, 3, 14, 10, 4), "pmevcntr20_el0" },
{ SYSREG_ENC(3, 3, 14, 10, 5), "pmevcntr21_el0" },
{ SYSREG_ENC(3, 3, 14, 10, 6), "pmevcntr22_el0" },
{ SYSREG_ENC(3, 3, 14, 10, 7), "pmevcntr23_el0" },
{ SYSREG_ENC(3, 3, 14, 11, 0), "pmevcntr24_el0" },
{ SYSREG_ENC(3, 3, 14, 11, 1), "pmevcntr25_el0" },
{ SYSREG_ENC(3, 3, 14, 11, 2), "pmevcntr26_el0" },
{ SYSREG_ENC(3, 3, 14, 11, 3), "pmevcntr27_el0" },
{ SYSREG_ENC(3, 3, 14, 11, 4), "pmevcntr28_el0" },
{ SYSREG_ENC(3, 3, 14, 11, 5), "pmevcntr29_el0" },
{ SYSREG_ENC(3, 3, 14, 11, 6), "pmevcntr30_el0" },
{ SYSREG_ENC(3, 3, 14, 12, 0), "pmevtyper0_el0" },
{ SYSREG_ENC(3, 3, 14, 12, 1), "pmevtyper1_el0" },
{ SYSREG_ENC(3, 3, 14, 12, 2), "pmevtyper2_el0" },
{ SYSREG_ENC(3, 3, 14, 12, 3), "pmevtyper3_el0" },
{ SYSREG_ENC(3, 3, 14, 12, 4), "pmevtyper4_el0" },
{ SYSREG_ENC(3, 3, 14, 12, 5), "pmevtyper5_el0" },
{ SYSREG_ENC(3, 3, 14, 12, 6), "pmevtyper6_el0" },
{ SYSREG_ENC(3, 3, 14, 12, 7), "pmevtyper7_el0" },
{ SYSREG_ENC(3, 3, 14, 13, 0), "pmevtyper8_el0" },
{ SYSREG_ENC(3, 3, 14, 13, 1), "pmevtyper9_el0" },
{ SYSREG_ENC(3, 3, 14, 13, 2), "pmevtyper10_el0" },
{ SYSREG_ENC(3, 3, 14, 13, 3), "pmevtyper11_el0" },
{ SYSREG_ENC(3, 3, 14, 13, 4), "pmevtyper12_el0" },
{ SYSREG_ENC(3, 3, 14, 13, 5), "pmevtyper13_el0" },
{ SYSREG_ENC(3, 3, 14, 13, 6), "pmevtyper14_el0" },
{ SYSREG_ENC(3, 3, 14, 13, 7), "pmevtyper15_el0" },
{ SYSREG_ENC(3, 3, 14, 14, 0), "pmevtyper16_el0" },
{ SYSREG_ENC(3, 3, 14, 14, 1), "pmevtyper17_el0" },
{ SYSREG_ENC(3, 3, 14, 14, 2), "pmevtyper18_el0" },
{ SYSREG_ENC(3, 3, 14, 14, 3), "pmevtyper19_el0" },
{ SYSREG_ENC(3, 3, 14, 14, 4), "pmevtyper20_el0" },
{ SYSREG_ENC(3, 3, 14, 14, 5), "pmevtyper21_el0" },
{ SYSREG_ENC(3, 3, 14, 14, 6), "pmevtyper22_el0" },
{ SYSREG_ENC(3, 3, 14, 14, 7), "pmevtyper23_el0" },
{ SYSREG_ENC(3, 3, 14, 15, 0), "pmevtyper24_el0" },
{ SYSREG_ENC(3, 3, 14, 15, 1), "pmevtyper25_el0" },
{ SYSREG_ENC(3, 3, 14, 15, 2), "pmevtyper26_el0" },
{ SYSREG_ENC(3, 3, 14, 15, 3), "pmevtyper27_el0" },
{ SYSREG_ENC(3, 3, 14, 15, 4), "pmevtyper28_el0" },
{ SYSREG_ENC(3, 3, 14, 15, 5), "pmevtyper29_el0" },
{ SYSREG_ENC(3, 3, 14, 15, 6), "pmevtyper30_el0" },
{ SYSREG_ENC(3, 3, 14, 15, 7), "pmccfiltr_el0" },
{ SYSREG_ENC(3, 4, 0, 0, 0), "vpidr_el2" },
{ SYSREG_ENC(3, 4, 0, 0, 5), "vmpidr_el2" },
{ SYSREG_ENC(3, 4, 1, 0, 0), "sctlr_el2" },
{ SYSREG_ENC(3, 4, 1, 0, 1), "actlr_el2" },
{ SYSREG_ENC(3, 4, 1, 1, 0), "hcr_el2" },
{ SYSREG_ENC(3, 4, 1, 1, 1), "mdcr_el2" },
{ SYSREG_ENC(3, 4, 1, 1, 2), "cptr_el2" },
{ SYSREG_ENC(3, 4, 1, 1, 3), "hstr_el2" },
{ SYSREG_ENC(3, 4, 1, 1, 7), "hacr_el2" },
{ SYSREG_ENC(3, 4, 2, 0, 0), "ttbr0_el2" },
{ SYSREG_ENC(3, 4, 2, 0, 2), "tcr_el2" },
{ SYSREG_ENC(3, 4, 2, 1, 0), "vttbr_el2" },
{ SYSREG_ENC(3, 4, 2, 1, 2), "vtcr_el2" },
{ SYSREG_ENC(3, 4, 3, 0, 0), "dacr32_el2" },
{ SYSREG_ENC(3, 4, 4, 0, 0), "spsr_el2" },
{ SYSREG_ENC(3, 4, 4, 0, 1), "elr_el2" },
{ SYSREG_ENC(3, 4, 4, 1, 0), "sp_el1" },
{ SYSREG_ENC(3, 4, 4, 3, 0), "spsr_irq" },
{ SYSREG_ENC(3, 4, 4, 3, 1), "spsr_abt" },
{ SYSREG_ENC(3, 4, 4, 3, 2), "spsr_und" },
{ SYSREG_ENC(3, 4, 4, 3, 3), "spsr_fiq" },
{ SYSREG_ENC(3, 4, 5, 0, 1), "ifsr32_el2" },
{ SYSREG_ENC(3, 4, 5, 1, 0), "afsr0_el2" },
{ SYSREG_ENC(3, 4, 5, 1, 1), "afsr1_el2" },
{ SYSREG_ENC(3, 4, 5, 2, 0), "esr_el2" },
{ SYSREG_ENC(3, 4, 5, 3, 0), "fpexc32_el2" },
{ SYSREG_ENC(3, 4, 6, 0, 0), "far_el2" },
{ SYSREG_ENC(3, 4, 6, 0, 4), "hpfar_el2" },
{ SYSREG_ENC(3, 4, 10, 2, 0), "mair_el2" },
{ SYSREG_ENC(3, 4, 10, 3, 0), "amair_el2" },
{ SYSREG_ENC(3, 4, 12, 0, 0), "vbar_el2" },
{ SYSREG_ENC(3, 4, 12, 0, 1), "rvbar_el2" },
{ SYSREG_ENC(3, 4, 12, 0, 2), "rmr_el2" },
{ SYSREG_ENC(3, 4, 13, 0, 2), "tpidr_el2" },
{ SYSREG_ENC(3, 4, 14, 0, 3), "cntvoff_el2" },
{ SYSREG_ENC(3, 4, 14, 1, 0), "cnthctl_el2" },
{ SYSREG_ENC(3, 4, 14, 2, 0), "cnthp_tval_el2" },
{ SYSREG_ENC(3, 4, 14, 2, 1), "cnthp_ctl_el2" },
{ SYSREG_ENC(3, 4, 14, 2, 2), "cnthp_cval_el2" },
{ SYSREG_ENC(3, 6, 1, 0, 0), "sctlr_el3" },
{ SYSREG_ENC(3, 6, 1, 0, 1), "actlr_el3" },
{ SYSREG_ENC(3, 6, 1, 1, 0), "scr_el3" },
{ SYSREG_ENC(3, 6, 1, 1, 1), "sder32_el3" },
{ SYSREG_ENC(3, 6, 1, 1, 2), "cptr_el3" },
{ SYSREG_ENC(3, 6, 1, 3, 1), "mdcr_el3" },
{ SYSREG_ENC(3, 6, 2, 0, 0), "ttbr0_el3" },
{ SYSREG_ENC(3, 6, 2, 0, 2), "tcr_el3" },
{ SYSREG_ENC(3, 6, 4, 0, 0), "spsr_el3" },
{ SYSREG_ENC(3, 6, 4, 0, 1), "elr_el3" },
{ SYSREG_ENC(3, 6, 4, 1, 0), "sp_el2" },
{ SYSREG_ENC(3, 6, 5, 1, 0), "afsr0_el3" },
{ SYSREG_ENC(3, 6, 5, 1, 1), "afsr1_el3" },
{ SYSREG_ENC(3, 6, 5, 2, 0), "esr_el3" },
{ SYSREG_ENC(3, 6, 6, 0, 0), "far_el3" },
{ SYSREG_ENC(3, 6, 10, 2, 0), "mair_el3" },
{ SYSREG_ENC(3, 6, 10, 3, 0), "amair_el3" },
{ SYSREG_ENC(3, 6, 12, 0, 0), "vbar_el3" },
{ SYSREG_ENC(3, 6, 12, 0, 1), "rvbar_el3" },
{ SYSREG_ENC(3, 6, 12, 0, 2), "rmr_el3" },
{ SYSREG_ENC(3, 6, 13, 0, 2), "tpidr_el3" },
{ SYSREG_ENC(3, 7, 14, 2, 0), "cntps_tval_el1" },
{ SYSREG_ENC(3, 7, 14, 2, 1), "cntps_ctl_el1" },
{ SYSREG_ENC(3, 7, 14, 2, 2), "cntps_cval_el1" }
};
static const char *
sysregname_bsearch(uint32_t code)
{
const struct sysreg_table *base, *p;
unsigned int lim;
int32_t cmp;
base = sysreg_table;
for (lim = __arraycount(sysreg_table); lim != 0; lim >>= 1) {
p = base + (lim >> 1);
cmp = code - p->code;
if (cmp == 0)
return p->regname;
if (cmp > 0) {
base = p + 1;
lim--;
}
}
return NULL;
}
#define SYSREG_OP_READ 0x01
#define SYSREG_OP_WRITE 0x02
static const char *
sysregname(char *buf, size_t buflen, uint32_t rw,
uint64_t op0, uint64_t op1, uint64_t CRn, uint64_t CRm, uint64_t op2)
{
const char *name;
uint32_t code;
code = SYSREG_ENC(op0, op1, CRn, CRm, op2);
if (code == SYSREG_ENC(2,3,0,5,0)) {
if (rw & SYSREG_OP_WRITE)
return "dbgdtrtx_el0";
return "dbgdtrrx_el0";
}
name = sysregname_bsearch(code);
if (name == NULL) {
#define SYSREGNAMEBUFLEN sizeof("s99_99_c99_c99_99")
snprintf(buf, buflen, "s%u_%u_c%u_c%u_%u",
(u_int)op0, (u_int)op1, (u_int)CRn, (u_int)CRm, (u_int)op2);
return buf;
}
return name;
}
#define RSYSREGNAME(buf, buflen, op0, op1, CRn, CRm, op2) \
sysregname(buf, buflen, SYSREG_OP_READ, op0, op1, CRn, CRm, op2)
#define WSYSREGNAME(buf, buflen, op0, op1, CRn, CRm, op2) \
sysregname(buf, buflen, SYSREG_OP_WRITE, op0, op1, CRn, CRm, op2)
static uint64_t
SignExtend(int bitwidth, uint64_t imm, unsigned int multiply)
{
const uint64_t signbit = ((uint64_t)1 << (bitwidth - 1));
const uint64_t immmax = signbit << 1;
if (imm & signbit)
imm -= immmax;
return imm * multiply;
}
static uint64_t
ZeroExtend(int bitwidth, uint64_t imm, unsigned int multiply)
{
return imm * multiply;
}
static uint64_t
rotate(int bitwidth, uint64_t v, int n)
{
uint64_t result;
n &= (bitwidth - 1);
result = (((v << (bitwidth - n)) | (v >> n)));
if (bitwidth < 64)
result &= ((1ULL << bitwidth) - 1);
return result;
}
static bool
ValidBitMasks(uint64_t sf, uint64_t n, uint64_t imms, uint64_t immr)
{
int esize, len;
if ((sf == 0) && (n != 0))
return false;
len = fls64((n << 6) + (~imms & 0x3f)) - 1;
if (len < 0)
return false;
esize = (1 << len);
imms &= (esize - 1);
if (imms == (uint64_t)(esize - 1))
return false;
return true;
}
static uint64_t
DecodeBitMasks(uint64_t sf, uint64_t n, uint64_t imms, uint64_t immr)
{
const int bitwidth = (sf == 0) ? 32 : 64;
uint64_t result;
int esize, len;
len = fls64((n << 6) + (~imms & 0x3f)) - 1;
esize = (1 << len);
imms &= (esize - 1);
immr &= (esize - 1);
result = rotate(esize, (1ULL << (imms + 1)) - 1, immr);
while (esize < bitwidth) {
result |= (result << esize);
esize <<= 1;
}
if (sf == 0)
result &= ((1ULL << bitwidth) - 1);
return result;
}
static bool
MoveWidePreferred(uint64_t sf, uint64_t n, uint64_t imms, uint64_t immr)
{
#if 1
uint64_t x = DecodeBitMasks(sf, n, imms, immr);
if (sf == 0)
x &= 0xffffffff;
if (((x & 0xffffffffffff0000UL) == 0) ||
((x & 0xffffffff0000ffffUL) == 0) ||
((x & 0xffff0000ffffffffUL) == 0) ||
((x & 0x0000ffffffffffffUL) == 0))
return true;
x = ~x;
if (sf == 0)
x &= 0xffffffff;
if (((x & 0xffffffffffff0000UL) == 0) ||
((x & 0xffffffff0000ffffUL) == 0) ||
((x & 0xffff0000ffffffffUL) == 0) ||
((x & 0x0000ffffffffffffUL) == 0))
return true;
return false;
#else
const int bitwidth = (sf == 0) ? 32 : 64;
if ((sf != 0) && (n == 0))
return false;
if ((sf == 0) && ((n != 0) || (immr > 0x1f)))
return false;
if (imms < 16)
return ((-immr & 15) <= (15 - imms));
if (imms >= (uint64_t)(bitwidth - 15))
return ((immr & 15) <= (imms - (bitwidth - 15)));
return false;
#endif
}
static bool
BFXPreferred(uint64_t sf, uint64_t opc, uint64_t imms, uint64_t immr)
{
const uint64_t bitwidth = (sf == 0) ? 32 : 64;
if (imms < immr)
return false;
if (imms == (bitwidth - 1))
return false;
if (immr == 0) {
if ((sf == 0) && ((imms == 7) || (imms == 15)))
return false;
if ((sf != 0) && (opc == 0) &&
((imms == 7) || (imms == 15) || (imms == 31)))
return false;
}
return true;
}
#define SHIFTOP2(s, op1, op2) \
((const char *[]){ op1, op2 })[(s) & 1]
#define SHIFTOP4(s, op1, op2, op3, op4) \
((const char *[]){ op1, op2, op3, op4 })[(s) & 3]
#define SHIFTOP8(s, op1, op2, op3, op4, op5, op6, op7, op8) \
((const char *[]){ op1, op2, op3, op4, op5, op6, op7, op8 })[(s) & 7]
static const char *
DecodeShift(uint64_t shift)
{
return SHIFTOP4(shift, "lsl", "lsr", "asr", "ror");
}
#ifdef DISASM_WITH_COMMENT
#define UNDEFINED(pc, insn, comment) \
PRINTF(".insn\t0x%08x\t# %s\n", insn, comment);
#else
#define UNDEFINED(pc, insn, comment) \
PRINTF(".insn\t0x%08x\n", insn);
#endif
static void
extendreg_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
uint64_t sf, uint64_t Rm, uint64_t option, uint64_t imm3,
uint64_t Rn, uint64_t Rd,
const char *op, const char *z_op)
{
const int r = (sf == 0) ? 0 : ((option & 3) == 3) ? 1 : 0;
if ((z_op != NULL) && (Rd == 31)) {
PRINTF("%s\t", z_op);
} else {
PRINTF("%s\t%s, ", op, SREGNAME(sf, Rd));
}
PRINTF("%s, %s", SREGNAME(sf, Rn), ZREGNAME(r, Rm));
if ((Rd == 31) || (Rn == 31)) {
if (imm3 == 0) {
if (!((sf == 0) && (option == 2)) &&
!((sf != 0) && (option == 3))) {
PRINTF(", %s",
SHIFTOP8(option,
"uxtb", "uxth", "uxtw", "uxtx",
"sxtb", "sxth", "sxtw", "sxtx"));
}
} else {
PRINTF(", %s #%u",
SHIFTOP8(option,
"uxtb", "uxth", "lsl", "lsl",
"sxtb", "sxth", "sxtw", "sxtx"),
(u_int)imm3);
}
} else {
PRINTF(", %s",
SHIFTOP8(option,
"uxtb", "uxth", "uxtw", "uxtx",
"sxtb", "sxth", "sxtw", "sxtx"));
if (imm3 != 0)
PRINTF(" #%u", (u_int)imm3);
}
PRINTF("\n");
}
static void
shiftreg_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
uint64_t sf, uint64_t shift, uint64_t Rm, uint64_t imm6,
uint64_t Rn, uint64_t Rd,
const char *dnm_op, const char *dzm_op, const char *znm_op)
{
if ((sf == 0) && (imm6 >= 32)) {
UNDEFINED(pc, insn, "illegal imm6");
return;
}
if ((dzm_op != NULL) && (Rn == 31)) {
PRINTF("%s\t%s, %s",
dzm_op,
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rm));
} else if ((znm_op != NULL) && (Rd == 31)) {
PRINTF("%s\t%s, %s",
znm_op,
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
} else {
PRINTF("%s\t%s, %s, %s",
dnm_op,
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
}
if (imm6 != 0)
PRINTF(", %s #%u", DecodeShift(shift), (u_int)imm6);
PRINTF("\n");
}
static inline int
regoffset_option_to_r(uint64_t option)
{
switch (option) {
case 2:
case 6:
return 0;
case 3:
case 7:
return 1;
default:
return -1;
}
}
static void
regoffset_b_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
uint64_t Rm, uint64_t option, uint64_t shift, uint64_t Rn, uint64_t Rt,
const char *op)
{
int r;
if ((r = regoffset_option_to_r(option)) < 0) {
UNDEFINED(pc, insn, "illegal option");
return;
}
if (shift == 0) {
PRINTF("%s\t%s, [%s,%s%s]\n",
op,
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm),
SHIFTOP8(option,
"", "", ",uxtw", "", "", "", ",sxtw", ",sxtx"));
} else {
PRINTF("%s\t%s, [%s,%s,%s #%d]\n",
op,
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm),
SHIFTOP8(option,
"", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"),
0);
}
}
static void
regoffset_h_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
uint64_t Rm, uint64_t option, uint64_t shift, uint64_t Rn, uint64_t Rt,
const char *op)
{
int r;
if ((r = regoffset_option_to_r(option)) < 0) {
UNDEFINED(pc, insn, "illegal option");
return;
}
if ((shift == 0) && (option == 3)) {
PRINTF("%s\t%s, [%s,%s]\n",
op,
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm));
} else if (shift == 0) {
PRINTF("%s\t%s, [%s,%s,%s]\n",
op,
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm),
SHIFTOP8(option,
"", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"));
} else {
PRINTF("%s\t%s, [%s,%s,%s #%u]\n",
op,
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm),
SHIFTOP8(option,
"", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"),
(u_int)shift);
}
}
static void
regoffset_w_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
uint64_t Rm, uint64_t option, uint64_t shift, uint64_t Rn, uint64_t Rt,
const char *op)
{
int r;
if ((r = regoffset_option_to_r(option)) < 0) {
UNDEFINED(pc, insn, "illegal option");
return;
}
if ((shift == 0) && (option == 3)) {
PRINTF("%s\t%s, [%s,%s]\n",
op,
ZREGNAME(1, Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm));
} else if (shift == 0) {
PRINTF("%s\t%s, [%s,%s,%s]\n",
op,
ZREGNAME(1, Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm),
SHIFTOP8(option,
"", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"));
} else {
PRINTF("%s\t%s, [%s,%s,%s #%u]\n",
op,
ZREGNAME(1, Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm),
SHIFTOP8(option,
"", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"),
(u_int)shift * 2);
}
}
static void
regoffset_x_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
uint64_t size, uint64_t Rm, uint64_t option, uint64_t shift,
uint64_t Rn, uint64_t Rt,
const char *op)
{
int r;
if ((r = regoffset_option_to_r(option)) < 0) {
UNDEFINED(pc, insn, "illegal option");
return;
}
if (shift == 0) {
PRINTF("%s\t%s, [%s,%s%s]\n",
op,
ZREGNAME(size, Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm),
SHIFTOP8(option,
"", "", ",uxtw", "", "", "", ",sxtw", ",sxtx"));
} else {
uint64_t amount = 2 + size;
PRINTF("%s\t%s, [%s,%s,%s #%u]\n",
op,
ZREGNAME(size, Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm),
SHIFTOP8(option,
"", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"),
(u_int)amount);
}
}
static void
addsub_imm_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
uint64_t sf, uint64_t shift, uint64_t imm12, uint64_t Rn, uint64_t Rd,
const char *op, const char *zop)
{
if (shift & 2) {
UNDEFINED(pc, insn, "illegal shift");
return;
}
if (Rd == 31) {
PRINTF("%s\t%s, #0x%"PRIx64"%s\n",
zop,
SREGNAME(sf, Rn),
ZeroExtend(12, imm12, 1),
SHIFTOP4(shift, "", ", lsl #12", "", ""));
} else {
PRINTF("%s\t%s, %s, #0x%"PRIx64"%s\n",
op,
ZREGNAME(sf, Rd),
SREGNAME(sf, Rn),
ZeroExtend(12, imm12, 1),
SHIFTOP4(shift, "", ", lsl #12", "", ""));
}
}
static void
csetsel_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
uint64_t sf, uint64_t Rm, uint64_t cond, uint64_t Rn, uint64_t Rd,
const char *op, const char *op2, const char *op3)
{
if ((Rn == Rm) && (Rn != 31) && ((cond & 0xe) != 0x0e)) {
PRINTF("%s\t%s, %s, %s\n",
op3,
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
IVCONDNAME(cond));
} else if ((Rn == Rm) && (Rn == 31) && ((cond & 0xe) != 0x0e)) {
PRINTF("%s\t%s, %s\n",
op2,
ZREGNAME(sf, Rd),
IVCONDNAME(cond));
} else {
PRINTF("%s\t%s, %s, %s, %s\n",
op,
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm),
CONDNAME(cond));
}
}
OP0FUNC(op_undefined)
{
UNDEFINED(pc, insn, "undefined");
}
OP4FUNC(op_adc, sf, Rm, Rn, Rd)
{
PRINTF("adc\t%s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
}
OP4FUNC(op_adcs, sf, Rm, Rn, Rd)
{
PRINTF("adcs\t%s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
}
OP6FUNC(op_add_extreg, sf, Rm, option, imm3, Rn, Rd)
{
extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd,
"add", NULL);
}
OP5FUNC(op_add_imm, sf, shift, imm12, Rn, Rd)
{
if (shift & 2) {
UNDEFINED(pc, insn, "illegal shift");
return;
}
if ((Rd == 31 || Rn == 31) && (imm12 == 0)) {
PRINTF("mov\t%s, %s\n",
SREGNAME(sf, Rd),
SREGNAME(sf, Rn));
} else {
PRINTF("add\t%s, %s, #0x%"PRIx64"%s\n",
SREGNAME(sf, Rd),
SREGNAME(sf, Rn),
ZeroExtend(12, imm12, 1),
SHIFTOP2(shift, "", ", lsl #12"));
}
}
OP6FUNC(op_add_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
{
if (shift == 3) {
UNDEFINED(pc, insn, "illegal shift");
return;
}
shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
"add", NULL, NULL);
}
OP6FUNC(op_adds_extreg, sf, Rm, option, imm3, Rn, Rd)
{
extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd,
"adds", "cmn");
}
OP5FUNC(op_adds_imm, sf, shift, imm12, Rn, Rd)
{
addsub_imm_common(di, pc, insn, sf, shift, imm12, Rn, Rd,
"adds", "cmn");
}
OP6FUNC(op_adds_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
{
if (shift == 3) {
UNDEFINED(pc, insn, "illegal shift");
return;
}
shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
"adds", NULL, "cmn");
}
OP3FUNC(op_adr, immlo, immhi, Rd)
{
uint64_t imm = ((immhi << 2) | immlo);
PRINTF("adr\t%s, ", ZREGNAME(1, Rd));
PRINTADDR(SignExtend(21, imm, 1) + pc);
PRINTF("\n");
}
OP3FUNC(op_adrp, immlo, immhi, Rd)
{
uint64_t imm = ((immhi << 2) | immlo);
PRINTF("adrp\t%s, ", ZREGNAME(1, Rd));
PRINTADDR(SignExtend(21, imm, 4096) + (pc & -4096));
PRINTF("\n");
}
OP6FUNC(op_and_imm, sf, n, immr, imms, Rn, Rd)
{
if (!ValidBitMasks(sf, n, imms, immr)) {
UNDEFINED(pc, insn, "illegal bitmasks");
return;
}
PRINTF("and\t%s, %s, #0x%"PRIx64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
DecodeBitMasks(sf, n, imms, immr));
}
OP6FUNC(op_and_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
{
shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
"and", NULL, NULL);
}
OP6FUNC(op_ands_imm, sf, n, immr, imms, Rn, Rd)
{
if (!ValidBitMasks(sf, n, imms, immr)) {
UNDEFINED(pc, insn, "illegal bitmasks");
return;
}
if (Rd == 31) {
PRINTF("tst\t%s, #0x%"PRIx64"\n",
ZREGNAME(sf, Rn),
DecodeBitMasks(sf, n, imms, immr));
} else {
PRINTF("ands\t%s, %s, #0x%"PRIx64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
DecodeBitMasks(sf, n, imms, immr));
}
}
OP6FUNC(op_ands_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
{
shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
"ands", NULL, "tst");
}
OP6FUNC(op_sbfm, sf, n, immr, imms, Rn, Rd)
{
const uint64_t bitwidth = (sf == 0) ? 32 : 64;
if ((imms != (bitwidth - 1)) && ((imms + 1) == immr)) {
PRINTF("asr\t%s, %s, #%"PRIu64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
bitwidth - immr);
} else if (imms == (bitwidth - 1)) {
PRINTF("asr\t%s, %s, #%"PRIu64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
immr);
} else if (imms < immr) {
PRINTF("sbfiz\t%s, %s, #%"PRIu64", #%"PRIu64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
(bitwidth - immr) & (bitwidth - 1),
(imms + 1) & (bitwidth - 1));
} else if (BFXPreferred(sf, 0, imms, immr)) {
PRINTF("sbfx\t%s, %s, #%"PRIu64", #%"PRIu64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
immr,
(imms - immr + 1) & (bitwidth - 1));
} else if ((immr == 0) && (imms == 7)) {
PRINTF("sxtb\t%s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(0, Rn));
} else if ((immr == 0) && (imms == 15)) {
PRINTF("sxth\t%s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(0, Rn));
} else if ((immr == 0) && (imms == 31)) {
PRINTF("sxtw\t%s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(0, Rn));
} else {
UNDEFINED(pc, insn, "undefined");
}
}
OP4FUNC(op_asr_reg, sf, Rm, Rn, Rd)
{
PRINTF("asr\t%s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
}
struct op_sys_table {
uint32_t code;
int flags;
#define OPE_NONE 0x00000000
#define OPE_XT 0x00000001
const char *opname;
};
static struct op_sys_table op_sys_table[] = {
{ SYSREG_ENC(1, 0, 7, 1, 0), OPE_NONE, "ic\tialluis" },
{ SYSREG_ENC(1, 0, 7, 5, 0), OPE_NONE, "ic\tiallu" },
{ SYSREG_ENC(1, 3, 7, 5, 1), OPE_XT, "ic\tivau" },
{ SYSREG_ENC(1, 0, 7, 6, 1), OPE_XT, "dc\tivac" },
{ SYSREG_ENC(1, 0, 7, 6, 2), OPE_XT, "dc\tisw" },
{ SYSREG_ENC(1, 0, 7, 10, 2), OPE_XT, "dc\tcsw" },
{ SYSREG_ENC(1, 0, 7, 14, 2), OPE_XT, "dc\tcisw" },
{ SYSREG_ENC(1, 3, 7, 10, 1), OPE_XT, "dc\tcvac" },
{ SYSREG_ENC(1, 3, 7, 11, 1), OPE_XT, "dc\tcvau" },
{ SYSREG_ENC(1, 3, 7, 14, 1), OPE_XT, "dc\tcivac" },
{ SYSREG_ENC(1, 3, 7, 4, 1), OPE_XT, "dc\tzva" },
{ SYSREG_ENC(1, 0, 7, 8, 0), OPE_XT, "at\ts1e1r" },
{ SYSREG_ENC(1, 0, 7, 8, 1), OPE_XT, "at\ts1e1w" },
{ SYSREG_ENC(1, 0, 7, 8, 2), OPE_XT, "at\ts1e0r" },
{ SYSREG_ENC(1, 0, 7, 8, 3), OPE_XT, "at\ts1e0w" },
{ SYSREG_ENC(1, 4, 7, 8, 0), OPE_XT, "at\ts1e2r" },
{ SYSREG_ENC(1, 4, 7, 8, 1), OPE_XT, "at\ts1e2w" },
{ SYSREG_ENC(1, 4, 7, 8, 4), OPE_XT, "at\ts12e1r" },
{ SYSREG_ENC(1, 4, 7, 8, 5), OPE_XT, "at\ts12e1w" },
{ SYSREG_ENC(1, 4, 7, 8, 6), OPE_XT, "at\ts12e0r" },
{ SYSREG_ENC(1, 4, 7, 8, 7), OPE_XT, "at\ts12e0w" },
{ SYSREG_ENC(1, 6, 7, 8, 0), OPE_XT, "at\ts1e3r" },
{ SYSREG_ENC(1, 6, 7, 8, 1), OPE_XT, "at\ts1e3w" },
{ SYSREG_ENC(1, 0, 8, 3, 0), OPE_NONE, "tlbi\tvmalle1is" },
{ SYSREG_ENC(1, 0, 8, 3, 1), OPE_XT, "tlbi\tvae1is" },
{ SYSREG_ENC(1, 0, 8, 3, 2), OPE_XT, "tlbi\taside1is" },
{ SYSREG_ENC(1, 0, 8, 3, 3), OPE_XT, "tlbi\tvaae1is" },
{ SYSREG_ENC(1, 0, 8, 3, 5), OPE_XT, "tlbi\tvale1is" },
{ SYSREG_ENC(1, 0, 8, 3, 7), OPE_XT, "tlbi\tvaale1is" },
{ SYSREG_ENC(1, 0, 8, 7, 0), OPE_NONE, "tlbi\tvmalle1" },
{ SYSREG_ENC(1, 0, 8, 7, 1), OPE_XT, "tlbi\tvae1" },
{ SYSREG_ENC(1, 0, 8, 7, 2), OPE_XT, "tlbi\taside1" },
{ SYSREG_ENC(1, 0, 8, 7, 3), OPE_XT, "tlbi\tvaae1" },
{ SYSREG_ENC(1, 0, 8, 7, 5), OPE_XT, "tlbi\tvale1" },
{ SYSREG_ENC(1, 0, 8, 7, 7), OPE_XT, "tlbi\tvaale1" },
{ SYSREG_ENC(1, 4, 8, 0, 1), OPE_XT, "tlbi\tipas2e1is" },
{ SYSREG_ENC(1, 4, 8, 0, 5), OPE_XT, "tlbi\tipas2le1is" },
{ SYSREG_ENC(1, 4, 8, 3, 0), OPE_NONE, "tlbi\talle2is" },
{ SYSREG_ENC(1, 4, 8, 3, 1), OPE_XT, "tlbi\tvae2is" },
{ SYSREG_ENC(1, 4, 8, 3, 4), OPE_NONE, "tlbi\talle1is" },
{ SYSREG_ENC(1, 4, 8, 3, 5), OPE_XT, "tlbi\tvale2is" },
{ SYSREG_ENC(1, 4, 8, 3, 6), OPE_NONE, "tlbi\tvmalls12e1is" },
{ SYSREG_ENC(1, 4, 8, 4, 1), OPE_XT, "tlbi\tipas2e1" },
{ SYSREG_ENC(1, 4, 8, 4, 5), OPE_XT, "tlbi\tipas2le1" },
{ SYSREG_ENC(1, 4, 8, 7, 0), OPE_NONE, "tlbi\talle2" },
{ SYSREG_ENC(1, 4, 8, 7, 1), OPE_XT, "tlbi\tvae2" },
{ SYSREG_ENC(1, 4, 8, 7, 4), OPE_NONE, "tlbi\talle1" },
{ SYSREG_ENC(1, 4, 8, 7, 5), OPE_XT, "tlbi\tvale2" },
{ SYSREG_ENC(1, 4, 8, 7, 6), OPE_NONE, "tlbi\tvmalls12e1" },
{ SYSREG_ENC(1, 6, 8, 3, 0), OPE_NONE, "tlbi\talle3is" },
{ SYSREG_ENC(1, 6, 8, 3, 1), OPE_XT, "tlbi\tvae3is" },
{ SYSREG_ENC(1, 6, 8, 3, 5), OPE_XT, "tlbi\tvale3is" },
{ SYSREG_ENC(1, 6, 8, 7, 0), OPE_NONE, "tlbi\talle3" },
{ SYSREG_ENC(1, 6, 8, 7, 1), OPE_XT, "tlbi\tvae3" },
{ SYSREG_ENC(1, 6, 8, 7, 5), OPE_XT, "tlbi\tvale3" }
};
OP5FUNC(op_sys, op1, CRn, CRm, op2, Rt)
{
uint32_t code;
size_t i;
code = SYSREG_ENC(1, op1, CRn, CRm, op2);
for (i = 0; i < __arraycount(op_sys_table); i++) {
if (op_sys_table[i].code != code)
continue;
if (((op_sys_table[i].flags & OPE_XT) != 0) || (Rt != 31)) {
PRINTF("%s, %s\n",
op_sys_table[i].opname,
ZREGNAME(1, Rt));
} else {
PRINTF("%s\n",
op_sys_table[i].opname);
}
return;
}
PRINTF("sys\t#%"PRIu64", %s, %s, #%"PRIu64", %s\n",
op1,
CREGNAME(CRn),
CREGNAME(CRm),
op2,
ZREGNAME(1,Rt));
}
OP1FUNC(op_b, imm26)
{
PRINTF("b\t");
PRINTADDR(SignExtend(26, imm26, 4) + pc);
PRINTF("\n");
}
OP2FUNC(op_b_cond, imm19, cond)
{
PRINTF("b.%s\t", CONDNAME(cond));
PRINTADDR(SignExtend(19, imm19, 4) + pc);
PRINTF("\n");
}
OP6FUNC(op_bfi, sf, n, immr, imms, Rn, Rd)
{
const uint64_t bitwidth = (sf == 0) ? 32 : 64;
if (imms < immr) {
PRINTF("bfi\t%s, %s, #%"PRIu64", #%"PRIu64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
(bitwidth - immr) & (bitwidth - 1),
(imms + 1) & (bitwidth - 1));
} else {
PRINTF("bfxil\t%s, %s, #%"PRIu64", #%"PRIu64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
immr,
(imms -immr + 1) & (bitwidth - 1));
}
}
OP6FUNC(op_bic_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
{
shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
"bic", NULL, NULL);
}
OP6FUNC(op_bics_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
{
shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
"bics", NULL, NULL);
}
OP1FUNC(op_bl, imm26)
{
PRINTF("bl\t");
PRINTADDR(SignExtend(26, imm26, 4) + pc);
PRINTF("\n");
}
OP1FUNC(op_blr, Rn)
{
PRINTF("blr\t%s\n", ZREGNAME(1, Rn));
}
OP1FUNC(op_br, Rn)
{
PRINTF("br\t%s\n", ZREGNAME(1, Rn));
}
OP1FUNC(op_brk, imm16)
{
PRINTF("brk\t#0x%"PRIx64"\n", imm16);
}
OP3FUNC(op_cbnz, sf, imm19, Rt)
{
PRINTF("cbnz\t%s, ", ZREGNAME(sf, Rt));
PRINTADDR(SignExtend(19, imm19, 4) + pc);
PRINTF("\n");
}
OP3FUNC(op_cbz, sf, imm19, Rt)
{
PRINTF("cbz\t%s, ", ZREGNAME(sf, Rt));
PRINTADDR(SignExtend(19, imm19, 4) + pc);
PRINTF("\n");
}
OP5FUNC(op_ccmn_imm, sf, imm5, cond, Rn, nzcv)
{
PRINTF("ccmn\t%s, #0x%"PRIx64", #0x%"PRIx64", %s\n",
ZREGNAME(sf, Rn),
imm5,
nzcv,
CONDNAME(cond));
}
OP5FUNC(op_ccmn_reg, sf, Rm, cond, Rn, nzcv)
{
PRINTF("ccmn\t%s, %s, #0x%"PRIx64", %s\n",
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm),
nzcv,
CONDNAME(cond));
}
OP5FUNC(op_ccmp_imm, sf, imm5, cond, Rn, nzcv)
{
PRINTF("ccmp\t%s, #0x%"PRIx64", #0x%"PRIx64", %s\n",
ZREGNAME(sf, Rn),
imm5,
nzcv,
CONDNAME(cond));
}
OP5FUNC(op_ccmp_reg, sf, Rm, cond, Rn, nzcv)
{
PRINTF("ccmp\t%s, %s, #0x%"PRIx64", %s\n",
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm),
nzcv,
CONDNAME(cond));
}
OP5FUNC(op_cinc, sf, Rm, cond, Rn, Rd)
{
csetsel_common(di, pc, insn, sf, Rm, cond, Rn, Rd,
"csinc", "cset", "cinc");
}
OP5FUNC(op_csinv, sf, Rm, cond, Rn, Rd)
{
csetsel_common(di, pc, insn, sf, Rm, cond, Rn, Rd,
"csinv", "csetm", "cinv");
}
OP1FUNC(op_clrex, CRm)
{
if (CRm == 15) {
PRINTF("clrex\n");
} else {
PRINTF("clrex\t#0x%"PRIx64"\n", CRm);
}
}
OP3FUNC(op_cls, sf, Rn, Rd)
{
PRINTF("cls\t%s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn));
}
OP3FUNC(op_clz, sf, Rn, Rd)
{
PRINTF("clz\t%s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn));
}
OP6FUNC(op_subs_extreg, sf, Rm, option, imm3, Rn, Rd)
{
extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd,
"subs", "cmp");
}
OP5FUNC(op_subs_imm, sf, shift, imm12, Rn, Rd)
{
addsub_imm_common(di, pc, insn, sf, shift, imm12, Rn, Rd,
"subs", "cmp");
}
OP6FUNC(op_subs_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
{
if (shift == 3) {
UNDEFINED(pc, insn, "illegal shift");
return;
}
shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
"subs", "negs", "cmp");
}
OP5FUNC(op_csneg, sf, Rm, cond, Rn, Rd)
{
if ((Rn == Rm) && ((cond & 0xe) != 0x0e)) {
PRINTF("cneg\t%s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
IVCONDNAME(cond));
} else {
PRINTF("csneg\t%s, %s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm),
CONDNAME(cond));
}
}
static void
crc32_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
uint64_t sf, uint64_t Rm, uint64_t sz, uint64_t Rn, uint64_t Rd,
const char *op)
{
const char bhwx[4] = "bhwx";
if (((sf != 0) && (sz != 3)) ||
((sf == 0) && (sz == 3))) {
UNDEFINED(pc, insn, "illegal size");
return;
}
PRINTF("%s%c\t%s, %s, %s\n",
op, bhwx[sz & 3],
ZREGNAME(0, Rd),
ZREGNAME(0, Rn),
ZREGNAME(sf, Rm));
}
OP5FUNC(op_crc32, sf, Rm, sz, Rn, Rd)
{
crc32_common(di, pc, insn, sf, Rm, sz, Rn, Rd, "crc32");
}
OP5FUNC(op_crc32c, sf, Rm, sz, Rn, Rd)
{
crc32_common(di, pc, insn, sf, Rm, sz, Rn, Rd, "crc32c");
}
OP5FUNC(op_csel, sf, Rm, cond, Rn, Rd)
{
PRINTF("csel\t%s, %s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm),
CONDNAME(cond));
}
OP2FUNC(op_dcps, imm16, ll)
{
if (ll == 0) {
UNDEFINED(pc, insn, "illegal level");
return;
}
if (imm16 == 0)
PRINTF("dcps%"PRIu64"\n", ll);
else
PRINTF("dcps%"PRIu64"\t#0x%"PRIx64"\n", ll, imm16);
}
OP0FUNC(op_drps)
{
PRINTF("drps\n");
}
OP1FUNC(op_dmb, CRm)
{
PRINTF("dmb\t%s\n", BARRIERNAME(CRm));
}
OP1FUNC(op_dsb, CRm)
{
PRINTF("dsb\t%s\n", BARRIERNAME(CRm));
}
OP6FUNC(op_eon_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
{
shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
"eon", NULL, NULL);
}
OP6FUNC(op_eor_imm, sf, n, immr, imms, Rn, Rd)
{
if (!ValidBitMasks(sf, n, imms, immr)) {
UNDEFINED(pc, insn, "illegal bitmasks");
return;
}
PRINTF("eor\t%s, %s, #0x%"PRIx64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
DecodeBitMasks(sf, n, imms, immr));
}
OP6FUNC(op_eor_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
{
shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
"eor", NULL, NULL);
}
OP0FUNC(op_eret)
{
PRINTF("eret\n");
}
OP6FUNC(op_ror_imm, sf, n, Rm, imms, Rn, Rd)
{
if (((sf ^ n) != 0) || (n == 0 && imms >= 0x20)) {
UNDEFINED(pc, insn, "illegal sf and N");
return;
}
if (Rn == Rm) {
PRINTF("ror\t%s, %s, #%"PRIu64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
imms);
} else {
PRINTF("extr\t%s, %s, %s, #%"PRIu64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm),
imms);
}
}
OP2FUNC(op_hint, CRm, op2)
{
#define CRm_OP2(crm,op) ((crm) << 3 | (op))
const uint64_t op = CRm_OP2(CRm, op2);
switch (op) {
case CRm_OP2(0, 0):
PRINTF("nop\n");
break;
case CRm_OP2(0, 1):
PRINTF("yield\n");
break;
case CRm_OP2(0, 2):
PRINTF("wfe\n");
break;
case CRm_OP2(0, 3):
PRINTF("wfi\n");
break;
case CRm_OP2(0, 4):
PRINTF("sev\n");
break;
case CRm_OP2(0, 5):
PRINTF("sevl\n");
break;
case CRm_OP2(0, 7):
PRINTF("xpaclri\n");
break;
case CRm_OP2(1, 0):
PRINTF("pacia1716\n");
break;
case CRm_OP2(1, 2):
PRINTF("pacib1716\n");
break;
case CRm_OP2(3, 0):
PRINTF("paciaz\n");
break;
case CRm_OP2(3, 1):
PRINTF("paciasp\n");
break;
case CRm_OP2(3, 2):
PRINTF("pacibz\n");
break;
case CRm_OP2(3, 3):
PRINTF("pacibsp\n");
break;
case CRm_OP2(4, 0):
PRINTF("bti\n");
break;
case CRm_OP2(4, 2):
PRINTF("bti\tc\n");
break;
case CRm_OP2(4, 4):
PRINTF("bti\tj\n");
break;
case CRm_OP2(4, 6):
PRINTF("bti\tjc\n");
break;
default:
PRINTF("hint\t#0x%"PRIx64"\n", op);
break;
}
}
OP1FUNC(op_hlt, imm16)
{
PRINTF("hlt\t#0x%"PRIx64"\n", imm16);
}
OP1FUNC(op_hvc, imm16)
{
PRINTF("hvc\t#0x%"PRIx64"\n", imm16);
}
OP1FUNC(op_isb, CRm)
{
if (CRm == 15)
PRINTF("isb\n");
else
PRINTF("isb\t#0x%"PRIx64"\n", CRm);
}
OP3FUNC(op_ldar, size, Rn, Rt)
{
PRINTF("ldar\t%s, [%s]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn));
}
OP2FUNC(op_ldarb, Rn, Rt)
{
PRINTF("ldarb\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
}
OP2FUNC(op_ldarh, Rn, Rt)
{
PRINTF("ldarh\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
}
OP4FUNC(op_ldaxp, size, Rt2, Rn, Rt)
{
PRINTF("ldaxp\t%s, %s, [%s]\n",
ZREGNAME(size, Rt),
ZREGNAME(size, Rt2),
SREGNAME(1, Rn));
}
OP3FUNC(op_ldaxr, size, Rn, Rt)
{
PRINTF("ldaxr\t%s, [%s]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn));
}
OP2FUNC(op_ldaxrb, Rn, Rt)
{
PRINTF("ldaxrb\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
}
OP2FUNC(op_ldaxrh, Rn, Rt)
{
PRINTF("ldaxrh\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
}
OP5FUNC(op_ldnp, sf, imm7, Rt2, Rn, Rt)
{
if (imm7 == 0) {
PRINTF("ldnp\t%s, %s, [%s]\n",
ZREGNAME(sf, Rt),
ZREGNAME(sf, Rt2),
SREGNAME(1, Rn));
} else {
PRINTF("ldnp\t%s, %s, [%s,#%"PRId64"]\n",
ZREGNAME(sf, Rt),
ZREGNAME(sf, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, (sf == 0) ? 4 : 8));
}
}
OP5FUNC(op_ldp_postidx, sf, imm7, Rt2, Rn, Rt)
{
PRINTF("ldp\t%s, %s, [%s],#%"PRId64"\n",
ZREGNAME(sf, Rt),
ZREGNAME(sf, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, (sf == 0) ? 4 : 8));
}
OP5FUNC(op_ldp_preidx, sf, imm7, Rt2, Rn, Rt)
{
PRINTF("ldp\t%s, %s, [%s,#%"PRId64"]!\n",
ZREGNAME(sf, Rt),
ZREGNAME(sf, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, (sf == 0) ? 4 : 8));
}
OP5FUNC(op_ldp_signed, sf, imm7, Rt2, Rn, Rt)
{
if (imm7 == 0) {
PRINTF("ldp\t%s, %s, [%s]\n",
ZREGNAME(sf, Rt),
ZREGNAME(sf, Rt2),
SREGNAME(1, Rn));
} else {
PRINTF("ldp\t%s, %s, [%s,#%"PRId64"]\n",
ZREGNAME(sf, Rt),
ZREGNAME(sf, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, (sf == 0) ? 4 : 8));
}
}
OP4FUNC(op_ldpsw_postidx, imm7, Rt2, Rn, Rt)
{
PRINTF("ldpsw\t%s, %s, [%s],#%"PRId64"\n",
ZREGNAME(1, Rt),
ZREGNAME(1, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, 4));
}
OP4FUNC(op_ldpsw_preidx, imm7, Rt2, Rn, Rt)
{
PRINTF("ldpsw\t%s, %s, [%s,#%"PRId64"]!\n",
ZREGNAME(1, Rt),
ZREGNAME(1, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, 4));
}
OP4FUNC(op_ldpsw_signed, imm7, Rt2, Rn, Rt)
{
if (imm7 == 0) {
PRINTF("ldpsw\t%s, %s, [%s]\n",
ZREGNAME(1, Rt),
ZREGNAME(1, Rt2),
SREGNAME(1, Rn));
} else {
PRINTF("ldpsw\t%s, %s, [%s,#%"PRId64"]\n",
ZREGNAME(1, Rt),
ZREGNAME(1, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, 4));
}
}
OP4FUNC(op_ldr_immpostidx, size, imm9, Rn, Rt)
{
PRINTF("ldr\t%s, [%s],#%"PRId64"\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP4FUNC(op_ldr_immpreidx, size, imm9, Rn, Rt)
{
PRINTF("ldr\t%s, [%s,#%"PRId64"]!\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP4FUNC(op_ldr_immunsign, size, imm12, Rn, Rt)
{
if (imm12 == 0) {
PRINTF("ldr\t%s, [%s]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldr\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn),
ZeroExtend(12, imm12, (size == 0) ? 4 : 8));
}
}
OP3FUNC(op_ldr_literal, size, imm19, Rt)
{
PRINTF("ldr\t%s, ", ZREGNAME(size, Rt));
PRINTADDR(SignExtend(19, imm19, 4) + pc);
PRINTF("\n");
}
OP6FUNC(op_ldr_reg, size, Rm, option, shift, Rn, Rt)
{
regoffset_x_common(di, pc, insn, size, Rm, option, shift, Rn, Rt,
"ldr");
}
OP3FUNC(op_ldrb_immpostidx, imm9, Rn, Rt)
{
PRINTF("ldrb\t%s, [%s],#%"PRId64"\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP3FUNC(op_ldrb_immpreidx, imm9, Rn, Rt)
{
PRINTF("ldrb\t%s, [%s,#%"PRId64"]!\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP3FUNC(op_ldrb_immunsign, imm12, Rn, Rt)
{
if (imm12 == 0) {
PRINTF("ldrb\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldrb\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
ZeroExtend(12, imm12, 1));
}
}
OP5FUNC(op_ldrb_reg, Rm, option, shift, Rn, Rt)
{
regoffset_b_common(di, pc, insn, Rm, option, shift, Rn, Rt, "ldrb");
}
OP3FUNC(op_ldrh_immpostidx, imm9, Rn, Rt)
{
PRINTF("ldrh\t%s, [%s],#%"PRId64"\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP3FUNC(op_ldrh_immpreidx, imm9, Rn, Rt)
{
PRINTF("ldrh\t%s, [%s,#%"PRId64"]!\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP3FUNC(op_ldrh_immunsign, imm12, Rn, Rt)
{
if (imm12 == 0) {
PRINTF("ldrh\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldrh\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
ZeroExtend(12, imm12, 2));
}
}
OP5FUNC(op_ldrh_reg, Rm, option, shift, Rn, Rt)
{
regoffset_h_common(di, pc, insn, Rm, option, shift, Rn, Rt, "ldrh");
}
OP4FUNC(op_ldrsb_immpostidx, opc, imm9, Rn, Rt)
{
PRINTF("ldrsb\t%s, [%s],#%"PRId64"\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP4FUNC(op_ldrsb_immpreidx, opc, imm9, Rn, Rt)
{
PRINTF("ldrsb\t%s, [%s,#%"PRId64"]!\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP4FUNC(op_ldrsb_immunsign, opc, imm12, Rn, Rt)
{
if (imm12 == 0) {
PRINTF("ldrsb\t%s, [%s]\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldrsb\t%s, [%s,#%"PRId64"]\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn),
ZeroExtend(12, imm12, 1));
}
}
OP6FUNC(op_ldrsb_reg, opc, Rm, option, shift, Rn, Rt)
{
regoffset_b_common(di, pc, insn, Rm, option, shift, Rn, Rt, "ldrsb");
}
OP4FUNC(op_ldrsh_immpostidx, opc, imm9, Rn, Rt)
{
PRINTF("ldrsh\t%s, [%s],#%"PRId64"\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP4FUNC(op_ldrsh_immpreidx, opc, imm9, Rn, Rt)
{
PRINTF("ldrsh\t%s, [%s,#%"PRId64"]!\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP4FUNC(op_ldrsh_immunsign, opc, imm12, Rn, Rt)
{
if (imm12 == 0) {
PRINTF("ldrsh\t%s, [%s]\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldrsh\t%s, [%s,#%"PRId64"]\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn),
ZeroExtend(12, imm12, 2));
}
}
OP6FUNC(op_ldrsh_reg, opc, Rm, option, shift, Rn, Rt)
{
regoffset_h_common(di, pc, insn, Rm, option, shift, Rn, Rt, "ldrsh");
}
OP3FUNC(op_ldrsw_immpostidx, imm9, Rn, Rt)
{
PRINTF("ldrsw\t%s, [%s],#%"PRId64"\n",
ZREGNAME(1, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP3FUNC(op_ldrsw_immpreidx, imm9, Rn, Rt)
{
PRINTF("ldrsw\t%s, [%s,#%"PRId64"]!\n",
ZREGNAME(1, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP3FUNC(op_ldrsw_immunsign, imm12, Rn, Rt)
{
if (imm12 == 0) {
PRINTF("ldrsw\t%s, [%s]\n",
ZREGNAME(1, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldrsw\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(1, Rt),
SREGNAME(1, Rn),
ZeroExtend(12, imm12, 4));
}
}
OP2FUNC(op_ldrsw_literal, imm19, Rt)
{
PRINTF("ldrsw\t%s, ", ZREGNAME(1, Rt));
PRINTADDR(SignExtend(19, imm19, 4) + pc);
PRINTF("\n");
}
OP5FUNC(op_ldrsw_reg, Rm, option, shift, Rn, Rt)
{
regoffset_w_common(di, pc, insn, Rm, option, shift, Rn, Rt, "ldrsw");
}
OP4FUNC(op_ldtr, size, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("ldtr\t%s, [%s]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldtr\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP3FUNC(op_ldtrb, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("ldtrb\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldtrb\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(12, imm9, 1));
}
}
OP3FUNC(op_ldtrh, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("ldtrh\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldtrh\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(12, imm9, 1));
}
}
OP4FUNC(op_ldtrsb, opc, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("ldtrsb\t%s, [%s]\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldtrsb\t%s, [%s,#%"PRId64"]\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP4FUNC(op_ldtrsh, opc, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("ldtrsh\t%s, [%s]\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldtrsh\t%s, [%s,#%"PRId64"]\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP3FUNC(op_ldtrsw, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("ldtrsw\t%s, [%s]\n",
ZREGNAME(1, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldtrsw\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(1, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP4FUNC(op_ldur, size, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("ldur\t%s, [%s]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldur\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP3FUNC(op_ldurb, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("ldurb\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldurb\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP3FUNC(op_ldurh, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("ldurh\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldurh\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP4FUNC(op_ldursb, opc, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("ldursb\t%s, [%s]\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldursb\t%s, [%s,#%"PRId64"]\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP4FUNC(op_ldursh, opc, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("ldursh\t%s, [%s]\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldursh\t%s, [%s,#%"PRId64"]\n",
ZREGNAME((opc ^ 1), Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP3FUNC(op_ldursw, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("ldursw\t%s, [%s]\n",
ZREGNAME(1, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("ldursw\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(1, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP4FUNC(op_ldxp, size, Rt2, Rn, Rt)
{
PRINTF("ldxp\t%s, %s, [%s]\n",
ZREGNAME(size, Rt),
ZREGNAME(size, Rt2),
SREGNAME(1, Rn));
}
OP3FUNC(op_ldxr, size, Rn, Rt)
{
PRINTF("ldxr\t%s, [%s]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn));
}
OP2FUNC(op_ldxrb, Rn, Rt)
{
PRINTF("ldxrb\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
}
OP2FUNC(op_ldxrh, Rn, Rt)
{
PRINTF("ldxrh\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
}
OP6FUNC(op_ubfm, sf, n, immr, imms, Rn, Rd)
{
const uint64_t bitwidth = (sf == 0) ? 32 : 64;
if ((imms != (bitwidth - 1)) && ((imms + 1) == immr)) {
PRINTF("lsl\t%s, %s, #%"PRIu64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
bitwidth - immr);
} else if (imms == (bitwidth - 1)) {
PRINTF("lsr\t%s, %s, #%"PRIu64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
immr);
} else if (imms < immr) {
PRINTF("ubfiz\t%s, %s, #%"PRIu64", #%"PRIu64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
(bitwidth - immr) & (bitwidth - 1),
(imms + 1) & (bitwidth - 1));
} else if (BFXPreferred(sf, 1, imms, immr)) {
PRINTF("ubfx\t%s, %s, #%"PRIu64", #%"PRIu64"\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
immr,
(imms - immr + 1) & (bitwidth - 1));
} else if ((immr == 0) && (imms == 7)) {
PRINTF("uxtb\t%s, %s\n",
ZREGNAME(0, Rd),
ZREGNAME(0, Rn));
} else if ((immr == 0) && (imms == 15)) {
PRINTF("uxth\t%s, %s\n",
ZREGNAME(0, Rd),
ZREGNAME(0, Rn));
} else {
UNDEFINED(pc, insn, "undefined");
}
}
OP4FUNC(op_lsl_reg, sf, Rm, Rn, Rd)
{
PRINTF("lsl\t%s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
}
OP4FUNC(op_lsr_reg, sf, Rm, Rn, Rd)
{
PRINTF("lsr\t%s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
}
OP5FUNC(op_madd, sf, Rm, Ra, Rn, Rd)
{
if (Ra == 31) {
PRINTF("mul\t%s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
} else {
PRINTF("madd\t%s, %s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm),
ZREGNAME(sf, Ra));
}
}
OP5FUNC(op_msub, sf, Rm, Ra, Rn, Rd)
{
if (Ra == 31) {
PRINTF("mneg\t%s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
} else {
PRINTF("msub\t%s, %s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm),
ZREGNAME(sf, Ra));
}
}
OP6FUNC(op_orr_imm, sf, n, immr, imms, Rn, Rd)
{
if (!ValidBitMasks(sf, n, imms, immr)) {
UNDEFINED(pc, insn, "illegal bitmasks");
return;
}
#if 1
if ((Rn == 31) && !MoveWidePreferred(sf, n, imms, immr)) {
#else
(void)MoveWidePreferred;
if (Rn == 31) {
#endif
PRINTF("mov\t%s, #0x%"PRIx64"\n",
SREGNAME(sf, Rd),
DecodeBitMasks(sf, n, imms, immr));
} else {
PRINTF("orr\t%s, %s, #0x%"PRIx64"\n",
SREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
DecodeBitMasks(sf, n, imms, immr));
}
}
OP4FUNC(op_movn, sf, hw, imm16, Rd)
{
const uint64_t mask = (sf == 0) ? 0xffffffff : 0xffffffffffffffffUL;
if ((sf == 0) && (hw >= 2)) {
UNDEFINED(pc, insn, "illegal size");
return;
}
if ((hw == 0) || (imm16 == 0)) {
PRINTF("mov\t%s, #0x%"PRIx64"\n",
ZREGNAME(sf, Rd),
(~(ZeroExtend(16, imm16, 1) & mask)) & mask);
} else {
const uint64_t shift = hw * 16;
PRINTF("mov\t%s, #0x%"PRIx64"\n",
ZREGNAME(sf, Rd),
~(ZeroExtend(16, imm16, 1) << shift) & mask);
}
}
OP6FUNC(op_orr_reg, sf, shift, Rm, imm6, Rn, Rd)
{
if ((Rn == 31) && (imm6 == 0)) {
PRINTF("mov\t%s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rm));
} else {
shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
"orr", NULL, NULL);
}
}
OP4FUNC(op_movz, sf, hw, imm16, Rd)
{
if ((hw == 0) || (imm16 == 0)) {
PRINTF("mov\t%s, #0x%"PRIx64"\n",
ZREGNAME(sf, Rd),
ZeroExtend(16, imm16, 1));
} else {
const int shift = hw * 16;
#if 0
PRINTF("movz\t%s, #0x%lx, lsl #%d\n",
ZREGNAME(sf, Rd),
ZeroExtend(16, imm16, 1), shift);
#else
PRINTF("mov\t%s, #0x%"PRIx64"\n",
ZREGNAME(sf, Rd),
ZeroExtend(16, imm16, 1) << shift);
#endif
}
}
OP4FUNC(op_movk, sf, hw, imm16, Rd)
{
const int shift = hw * 16;
if (hw == 0) {
PRINTF("movk\t%s, #0x%"PRIx64"\n",
ZREGNAME(sf, Rd),
ZeroExtend(16, imm16, 1));
} else {
PRINTF("movk\t%s, #0x%"PRIx64", lsl #%d\n",
ZREGNAME(sf, Rd),
ZeroExtend(16, imm16, 1), shift);
}
}
OP6FUNC(op_mrs, op0, op1, CRn, CRm, op2, Rt)
{
char buf[SYSREGNAMEBUFLEN];
PRINTF("mrs\t%s, %s\n",
ZREGNAME(1, Rt),
RSYSREGNAME(buf, sizeof(buf), op0, op1, CRn, CRm, op2));
}
OP6FUNC(op_msr, op0, op1, CRn, CRm, op2, Rt)
{
char buf[SYSREGNAMEBUFLEN];
PRINTF("msr\t%s, %s\n",
WSYSREGNAME(buf, sizeof(buf), op0, op1, CRn, CRm, op2),
ZREGNAME(1, Rt));
}
OP3FUNC(op_msr_imm, op1, CRm, op2)
{
const char *pstatefield;
#define MSRIMM_OP(op1, op2) (((op1) << 3) | (op2))
switch (MSRIMM_OP(op1, op2)) {
case MSRIMM_OP(0, 5):
pstatefield = "spsel";
break;
case MSRIMM_OP(3, 6):
pstatefield = "daifset";
break;
case MSRIMM_OP(3, 7):
pstatefield = "daifclr";
break;
default:
UNDEFINED(pc, insn, "illegal op1/op2");
return;
}
PRINTF("msr\t%s, #0x%"PRIx64"\n",
pstatefield, CRm);
}
OP6FUNC(op_orn, sf, shift, Rm, imm6, Rn, Rd)
{
shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
"orn", "mvn", NULL);
}
OP6FUNC(op_sub_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
{
shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
"sub", "neg", NULL);
}
OP4FUNC(op_sbc, sf, Rm, Rn, Rd)
{
if (Rn == 31) {
PRINTF("ngc\t%s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rm));
} else {
PRINTF("sbc\t%s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
}
}
OP4FUNC(op_sbcs, sf, Rm, Rn, Rd)
{
if (Rn == 31) {
PRINTF("ngcs\t%s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rm));
} else {
PRINTF("sbcs\t%s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
}
}
OP3FUNC(op_prfm_imm, imm12, Rn, Rt)
{
if (imm12 == 0) {
PRINTF("prfm\t%s, [%s]\n",
PREFETCHNAME(Rt),
SREGNAME(1, Rn));
} else {
PRINTF("prfm\t%s, [%s,#%"PRId64"]\n",
PREFETCHNAME(Rt),
SREGNAME(1, Rn),
SignExtend(12, imm12, 8));
}
}
OP2FUNC(op_prfm_literal, imm19, Rt)
{
PRINTF("prfm\t%s, ", PREFETCHNAME(Rt));
PRINTADDR(SignExtend(19, imm19, 4) + pc);
PRINTF("\n");
}
OP5FUNC(op_prfm_reg, Rm, option, shift, Rn, Rt)
{
int r;
if ((r = regoffset_option_to_r(option)) < 0) {
UNDEFINED(pc, insn, "illegal option");
return;
}
if (shift == 0) {
PRINTF("prfm\t%s, [%s,%s%s]\n",
PREFETCHNAME(Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm),
SHIFTOP8(option,
"", "", ",uxtw", "", "", "", ",sxtw", ",sxtx"));
} else {
PRINTF("prfm\t%s, [%s,%s,%s #%d]\n",
PREFETCHNAME(Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm),
SHIFTOP8(option,
"", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"),
3);
}
}
OP3FUNC(op_prfum, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("prfum\t%s, [%s]\n",
PREFETCHNAME(Rt),
SREGNAME(1, Rn));
} else {
PRINTF("prfum\t%s, [%s,#%"PRId64"]\n",
PREFETCHNAME(Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP1FUNC(op_ret, Rn)
{
if (Rn == 30)
PRINTF("ret\n");
else
PRINTF("ret\t%s\n", ZREGNAME(1, Rn));
}
OP4FUNC(op_rev, sf, opc, Rn, Rd)
{
const char *const opcode[2][4] = {
{ "rbit", "rev16", "rev", NULL },
{ "rbit", "rev16", "rev32", "rev" }
};
const char *const op = opcode[sf][opc];
if (op == NULL) {
UNDEFINED(pc, insn, "undefined");
return;
}
PRINTF("%s\t%s, %s\n",
op,
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn));
}
OP4FUNC(op_ror_reg, sf, Rm, Rn, Rd)
{
PRINTF("ror\t%s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
}
OP4FUNC(op_sdiv, sf, Rm, Rn, Rd)
{
PRINTF("sdiv\t%s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
}
OP4FUNC(op_smaddl, Rm, Ra, Rn, Rd)
{
if (Ra == 31) {
PRINTF("smull\t%s, %s, %s\n",
ZREGNAME(1, Rd),
ZREGNAME(0, Rn),
ZREGNAME(0, Rm));
} else {
PRINTF("smaddl\t%s, %s, %s, %s\n",
ZREGNAME(1, Rd),
ZREGNAME(0, Rn),
ZREGNAME(0, Rm),
ZREGNAME(1, Ra));
}
}
OP1FUNC(op_smc, imm16)
{
PRINTF("smc\t#0x%"PRIx64"\n", imm16);
}
OP4FUNC(op_smsubl, Rm, Ra, Rn, Rd)
{
if (Ra == 31) {
PRINTF("smnegl\t%s, %s, %s\n",
ZREGNAME(1, Rd),
ZREGNAME(1, Rn),
ZREGNAME(1, Rm));
} else {
PRINTF("smsubl\t%s, %s, %s, %s\n",
ZREGNAME(1, Rd),
ZREGNAME(1, Rn),
ZREGNAME(1, Rm),
ZREGNAME(1, Ra));
}
}
OP3FUNC(op_smulh, Rm, Rn, Rd)
{
PRINTF("smulh\t%s, %s, %s\n",
ZREGNAME(1, Rd),
ZREGNAME(1, Rn),
ZREGNAME(1, Rm));
}
OP3FUNC(op_stlr, size, Rn, Rt)
{
PRINTF("stlr\t%s, [%s]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn));
}
OP2FUNC(op_stlrb, Rn, Rt)
{
PRINTF("stlrb\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
}
OP2FUNC(op_stlrh, Rn, Rt)
{
PRINTF("stlrh\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
}
OP5FUNC(op_stlxp, size, Rs, Rt2, Rn, Rt)
{
PRINTF("stlxp\t%s, %s, [%s]\n",
ZREGNAME(size, Rt),
ZREGNAME(size, Rt2),
SREGNAME(1, Rn));
}
OP4FUNC(op_stlxr, size, Rs, Rn, Rt)
{
PRINTF("stlxr\t%s, [%s]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn));
}
OP3FUNC(op_stlxrb, Rs, Rn, Rt)
{
PRINTF("stlxrb\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
}
OP3FUNC(op_stlxrh, Rs, Rn, Rt)
{
PRINTF("stlxrh\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
}
OP5FUNC(op_stnp, sf, imm7, Rt2, Rn, Rt)
{
if (imm7 == 0) {
PRINTF("stnp\t%s, %s, [%s]\n",
ZREGNAME(sf, Rt),
ZREGNAME(sf, Rt2),
SREGNAME(1, Rn));
} else {
PRINTF("stnp\t%s, %s, [%s,#%"PRId64"]\n",
ZREGNAME(sf, Rt),
ZREGNAME(sf, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, (sf == 0) ? 4 : 8));
}
}
OP5FUNC(op_stp_postidx, sf, imm7, Rt2, Rn, Rt)
{
PRINTF("stp\t%s, %s, [%s],#%"PRId64"\n",
ZREGNAME(sf, Rt),
ZREGNAME(sf, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, (sf == 0) ? 4 : 8));
}
OP5FUNC(op_stp_preidx, sf, imm7, Rt2, Rn, Rt)
{
PRINTF("stp\t%s, %s, [%s,#%"PRId64"]!\n",
ZREGNAME(sf, Rt),
ZREGNAME(sf, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, (sf == 0) ? 4 : 8));
}
OP5FUNC(op_stp_signed, sf, imm7, Rt2, Rn, Rt)
{
if (imm7 == 0) {
PRINTF("stp\t%s, %s, [%s]\n",
ZREGNAME(sf, Rt),
ZREGNAME(sf, Rt2),
SREGNAME(1, Rn));
} else {
PRINTF("stp\t%s, %s, [%s,#%"PRId64"]\n",
ZREGNAME(sf, Rt),
ZREGNAME(sf, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, (sf == 0) ? 4 : 8));
}
}
OP4FUNC(op_str_immpostidx, size, imm9, Rn, Rt)
{
PRINTF("str\t%s, [%s],#%"PRId64"\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP4FUNC(op_str_immpreidx, size, imm9, Rn, Rt)
{
PRINTF("str\t%s, [%s,#%"PRId64"]!\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP4FUNC(op_str_immunsign, size, imm12, Rn, Rt)
{
if (imm12 == 0) {
PRINTF("str\t%s, [%s]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("str\t%s, [%s,#%"PRIu64"]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn),
ZeroExtend(12, imm12, (size == 0) ? 4 : 8));
}
}
OP6FUNC(op_str_reg, size, Rm, option, shift, Rn, Rt)
{
regoffset_x_common(di, pc, insn, size, Rm, option, shift, Rn, Rt,
"str");
}
OP3FUNC(op_strb_immpostidx, imm9, Rn, Rt)
{
PRINTF("strb\t%s, [%s],#%"PRId64"\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP3FUNC(op_strb_immpreidx, imm9, Rn, Rt)
{
PRINTF("strb\t%s, [%s,#%"PRId64"]!\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP3FUNC(op_strb_immunsign, imm12, Rn, Rt)
{
if (imm12 == 0) {
PRINTF("strb\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("strb\t%s, [%s,#%"PRIu64"]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
ZeroExtend(12, imm12, 1));
}
}
OP5FUNC(op_strb_reg, Rm, option, shift, Rn, Rt)
{
regoffset_b_common(di, pc, insn, Rm, option, shift, Rn, Rt, "strb");
}
OP3FUNC(op_strh_immpostidx, imm9, Rn, Rt)
{
PRINTF("strh\t%s, [%s],#%"PRId64"\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP3FUNC(op_strh_immpreidx, imm9, Rn, Rt)
{
PRINTF("strh\t%s, [%s,#%"PRId64"]!\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP3FUNC(op_strh_immunsign, imm12, Rn, Rt)
{
if (imm12 == 0) {
PRINTF("strh\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("strh\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
ZeroExtend(12, imm12, 2));
}
}
OP5FUNC(op_strh_reg, Rm, option, shift, Rn, Rt)
{
regoffset_h_common(di, pc, insn, Rm, option, shift, Rn, Rt, "strh");
}
OP4FUNC(op_sttr, size, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("sttr\t%s, [%s]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("sttr\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP3FUNC(op_sttrb, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("sttrb\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("sttrb\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(12, imm9, 1));
}
}
OP3FUNC(op_sttrh, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("sttrh\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("sttrh\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(12, imm9, 1));
}
}
OP4FUNC(op_stur, size, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("stur\t%s, [%s]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("stur\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(size, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP3FUNC(op_sturb, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("sturb\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("sturb\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP3FUNC(op_sturh, imm9, Rn, Rt)
{
if (imm9 == 0) {
PRINTF("sturh\t%s, [%s]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("sturh\t%s, [%s,#%"PRId64"]\n",
ZREGNAME(0, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
}
OP5FUNC(op_stxp, size, Rs, Rt2, Rn, Rt)
{
PRINTF("stxp\t%s, %s, [%s]\n",
ZREGNAME(size, Rt),
ZREGNAME(size, Rt2),
SREGNAME(1, Rn));
}
OP4FUNC(op_stxr, size, Rs, Rn, Rt)
{
PRINTF("stxr\t%s, %s, [%s]\n",
ZREGNAME(0, Rs),
ZREGNAME(size, Rt),
SREGNAME(1, Rn));
}
OP3FUNC(op_stxrb, Rs, Rn, Rt)
{
PRINTF("stxrb\t%s, %s, [%s]\n",
ZREGNAME(0, Rs),
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
}
OP3FUNC(op_stxrh, Rs, Rn, Rt)
{
PRINTF("stxrh\t%s, %s, [%s]\n",
ZREGNAME(0, Rs),
ZREGNAME(0, Rt),
SREGNAME(1, Rn));
}
OP6FUNC(op_sub_extreg, sf, Rm, option, imm3, Rn, Rd)
{
extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd,
"sub", NULL);
}
OP5FUNC(op_sub_imm, sf, shift, imm12, Rn, Rd)
{
if (shift & 2) {
UNDEFINED(pc, insn, "illegal shift");
return;
}
PRINTF("sub\t%s, %s, #0x%"PRIx64"%s\n",
SREGNAME(sf, Rd),
SREGNAME(sf, Rn),
ZeroExtend(12, imm12, 1),
SHIFTOP2(shift, "", ", lsl #12"));
}
OP1FUNC(op_svc, imm16)
{
PRINTF("svc\t#0x%"PRIx64"\n",
imm16);
}
OP5FUNC(op_sysl, op1, CRn, CRm, op2, Rt)
{
PRINTF("sysl\t%s, #%"PRIu64", %s, %s, #%"PRIu64"\n",
ZREGNAME(1, Rt),
op1,
CREGNAME(CRn),
CREGNAME(CRm),
op2);
}
OP4FUNC(op_tbnz, b5, b40, imm14, Rt)
{
uint64_t bit = (b5 << 5) + b40;
PRINTF("tbnz\t%s, #%"PRIu64", ",
ZREGNAME(b5, Rt),
bit);
PRINTADDR(SignExtend(14, imm14, 4) + pc);
PRINTF("\n");
}
OP4FUNC(op_tbz, b5, b40, imm14, Rt)
{
uint64_t bit = (b5 << 5) + b40;
PRINTF("tbz\t%s, #%"PRIu64", ",
ZREGNAME(b5, Rt),
bit);
PRINTADDR(SignExtend(14, imm14, 4) + pc);
PRINTF("\n");
}
OP1FUNC(op_udf, imm16)
{
PRINTF("udf\t#0x%"PRIx64"\n", imm16);
}
OP4FUNC(op_udiv, sf, Rm, Rn, Rd)
{
PRINTF("udiv\t%s, %s, %s\n",
ZREGNAME(sf, Rd),
ZREGNAME(sf, Rn),
ZREGNAME(sf, Rm));
}
OP4FUNC(op_umaddl, Rm, Ra, Rn, Rd)
{
if (Ra == 31) {
PRINTF("umull\t%s, %s, %s\n",
ZREGNAME(1, Rd),
ZREGNAME(0, Rn),
ZREGNAME(0, Rm));
} else {
PRINTF("umaddl\t%s, %s, %s, %s\n",
ZREGNAME(1, Rd),
ZREGNAME(0, Rn),
ZREGNAME(0, Rm),
ZREGNAME(1, Ra));
}
}
OP4FUNC(op_umsubl, Rm, Ra, Rn, Rd)
{
if (Ra == 31) {
PRINTF("umnegl\t%s, %s, %s\n",
ZREGNAME(1, Rd),
ZREGNAME(1, Rn),
ZREGNAME(1, Rm));
} else {
PRINTF("umsubl\t%s, %s, %s, %s\n",
ZREGNAME(1, Rd),
ZREGNAME(1, Rn),
ZREGNAME(1, Rm),
ZREGNAME(1, Ra));
}
}
OP3FUNC(op_umulh, Rm, Rn, Rd)
{
PRINTF("umulh\t%s, %s, %s\n",
ZREGNAME(1, Rd),
ZREGNAME(1, Rn),
ZREGNAME(1, Rm));
}
OP6FUNC(op_simd_ldstnp, opc, l, imm7, Rt2, Rn, Rt)
{
const char *op = (l == 0) ? "stnp" : "ldnp";
const int regsz = (opc & 3) + 2;
if (opc == 3) {
UNDEFINED(pc, insn, "illegal opc");
return;
}
if (imm7 == 0) {
PRINTF("%s\t%s, %s, [%s]\n",
op,
FREGNAME(regsz, Rt),
FREGNAME(regsz, Rt2),
SREGNAME(1, Rn));
} else {
PRINTF("%s\t%s, %s, [%s,#%"PRId64"]\n",
op,
FREGNAME(regsz, Rt),
FREGNAME(regsz, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, (4 << opc)));
}
}
OP6FUNC(op_simd_ldstp_postidx, opc, l, imm7, Rt2, Rn, Rt)
{
const char *op = (l == 0) ? "stp" : "ldp";
const int regsz = (opc & 3) + 2;
PRINTF("%s\t%s, %s, [%s],#%"PRId64"\n",
op,
FREGNAME(regsz, Rt),
FREGNAME(regsz, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, (4 << opc)));
}
OP6FUNC(op_simd_ldstp_preidx, opc, l, imm7, Rt2, Rn, Rt)
{
const char *op = (l == 0) ? "stp" : "ldp";
const int regsz = (opc & 3) + 2;
PRINTF("%s\t%s, %s, [%s,#%"PRId64"]!\n",
op,
FREGNAME(regsz, Rt),
FREGNAME(regsz, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, (4 << opc)));
}
OP6FUNC(op_simd_ldstp_signed, opc, l, imm7, Rt2, Rn, Rt)
{
const char *op = (l == 0) ? "stp" : "ldp";
const int regsz = (opc & 3) + 2;
if (opc == 3) {
UNDEFINED(pc, insn, "illegal opc");
return;
}
if (imm7 == 0) {
PRINTF("%s\t%s, %s, [%s]\n",
op,
FREGNAME(regsz, Rt),
FREGNAME(regsz, Rt2),
SREGNAME(1, Rn));
} else {
PRINTF("%s\t%s, %s, [%s,#%"PRId64"]\n",
op,
FREGNAME(regsz, Rt),
FREGNAME(regsz, Rt2),
SREGNAME(1, Rn),
SignExtend(7, imm7, (4 << opc)));
}
}
static inline int
simd_ldstr_regsz(uint64_t size, uint64_t opc)
{
if ((opc & 2) == 0)
return size;
if (size == 0)
return 4;
return -1;
}
OP5FUNC(op_simd_ldstr_immpostidx, size, opc, imm9, Rn, Rt)
{
const char *op = ((opc & 1) == 0) ? "str" : "ldr";
int regsz;
if ((regsz = simd_ldstr_regsz(size, opc)) < 0) {
UNDEFINED(pc, insn, "illegal size/opc");
return;
}
PRINTF("%s\t%s, [%s],#%"PRId64"\n",
op,
FREGNAME(regsz, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP5FUNC(op_simd_ldstr_immpreidx, size, opc, imm9, Rn, Rt)
{
const char *op = ((opc & 1) == 0) ? "str" : "ldr";
int regsz;
if ((regsz = simd_ldstr_regsz(size, opc)) < 0) {
UNDEFINED(pc, insn, "illegal size/opc");
return;
}
PRINTF("%s\t%s, [%s,#%"PRId64"]!\n",
op,
FREGNAME(regsz, Rt),
SREGNAME(1, Rn),
SignExtend(9, imm9, 1));
}
OP5FUNC(op_simd_ldstr_immunsign, size, opc, imm12, Rn, Rt)
{
const char *op = ((opc & 1) == 0) ? "str" : "ldr";
int regsz;
if ((regsz = simd_ldstr_regsz(size, opc)) < 0) {
UNDEFINED(pc, insn, "illegal size/opc");
return;
}
if (imm12 == 0) {
PRINTF("%s\t%s, [%s]\n",
op,
FREGNAME(regsz, Rt),
SREGNAME(1, Rn));
} else {
PRINTF("%s\t%s, [%s,#%"PRIu64"]\n",
op,
FREGNAME(regsz, Rt),
SREGNAME(1, Rn),
ZeroExtend(12, imm12, 1 << regsz));
}
}
OP7FUNC(op_simd_ldstr_reg, size, opc, Rm, option, S, Rn, Rt)
{
const char *op = ((opc & 1) == 0) ? "str" : "ldr";
int regsz, r;
if ((regsz = simd_ldstr_regsz(size, opc)) < 0) {
UNDEFINED(pc, insn, "illegal size/opc");
return;
}
if ((r = regoffset_option_to_r(option)) < 0) {
UNDEFINED(pc, insn, "illegal option");
return;
}
if (S == 0) {
PRINTF("%s\t%s, [%s,%s%s]\n",
op,
FREGNAME(regsz, Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm),
SHIFTOP8(option,
"", "", ",uxtw", "", "", "", ",sxtw", ",sxtx"));
} else {
u_int amount = regsz;
PRINTF("%s\t%s, [%s,%s,%s #%u]\n",
op,
FREGNAME(regsz, Rt),
SREGNAME(1, Rn),
ZREGNAME(r, Rm),
SHIFTOP8(option,
"", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"),
amount);
}
}
OP4FUNC(op_simd_aes, m, d, Rn, Rt)
{
const char *aesop[2][2] = {
{ "aese", "aesd", },
{ "aesmc", "aesimc" }
};
PRINTF("%s\t%s.16b, %s.16b\n",
aesop[m & 1][d & 1],
VREGNAME(Rn),
VREGNAME(Rt));
}
OP4FUNC(op_simd_sha_reg3, Rm, op, Rn, Rd)
{
const char *shaop[8] = {
"sha1c", "sha1p", "sha1m", "sha1su0",
"sha256h", "sha256h2", "sha256su1", NULL
};
switch (op) {
case 0:
case 1:
case 2:
PRINTF("%s\t%s, %s, %s.4s\n",
shaop[op],
FREGNAME(FREGSZ_Q, Rd),
FREGNAME(FREGSZ_S, Rn),
VREGNAME(Rm));
break;
case 4:
case 5:
PRINTF("%s\t%s, %s, %s.4s\n",
shaop[op],
FREGNAME(FREGSZ_Q, Rd),
FREGNAME(FREGSZ_Q, Rn),
VREGNAME(Rm));
break;
case 3:
case 6:
PRINTF("%s\t%s.4s, %s.4s, %s.4s\n",
shaop[op],
VREGNAME(Rd),
VREGNAME(Rn),
VREGNAME(Rm));
break;
default:
UNDEFINED(pc, insn, "illegal sha operation");
break;
}
}
OP3FUNC(op_simd_sha_reg2, op, Rn, Rd)
{
const char *shaop[4] = {
"sha1h", "sha1su1", "sha256su0", NULL
};
switch (op) {
case 0:
PRINTF("%s\t%s, %s\n",
shaop[op],
FREGNAME(FREGSZ_S, Rd),
FREGNAME(FREGSZ_S, Rn));
break;
case 1:
case 2:
PRINTF("%s\t%s.4s, %s.4s\n",
shaop[op],
VREGNAME(Rd),
VREGNAME(Rn));
break;
default:
UNDEFINED(pc, insn, "illegal sha operation");
break;
}
}
OP4FUNC(op_simd_sha512_reg3, Rm, op, Rn, Rd)
{
const char *shaop[4] = {
"sha512h", "sha512h2", "sha512su1", "rax1"
};
switch (op) {
case 0:
case 1:
PRINTF("%s\t%s, %s, %s.2d\n",
shaop[op],
FREGNAME(FREGSZ_Q, Rd),
FREGNAME(FREGSZ_Q, Rn),
VREGNAME(Rm));
break;
case 2:
case 3:
PRINTF("%s\t%s.2d, %s,.2d %s.2d\n",
shaop[op],
VREGNAME(Rd),
VREGNAME(Rn),
VREGNAME(Rm));
break;
}
}
OP3FUNC(op_simd_sha512_reg2, op, Rn, Rd)
{
const char *shaop[4] = {
"sha512su0", "sm4e", NULL, NULL
};
switch (op) {
case 0:
case 1:
PRINTF("%s\t%s.2d, %s.2d\n",
shaop[op],
VREGNAME(Rd),
VREGNAME(Rn));
break;
default:
UNDEFINED(pc, insn, "illegal sha512 operation");
break;
}
}
OP5FUNC(op_simd_pmull, q, size, Rm, Rn, Rd)
{
const char *op = (q == 0) ? "pmull" : "pmull2";
const char *regspec_Ta[4] = {
"8h", NULL, NULL, "1q"
};
const char *regspec_Tb[8] = {
"8b", "16b", NULL, NULL,
NULL, NULL, "1d", "2d"
};
if ((regspec_Ta[size & 3] != NULL) &&
(regspec_Tb[((size & 3) << 1) + (q & 1)] != NULL)) {
PRINTF("%s\t%s.%s, %s.%s, %s.%s\n",
op,
VREGNAME(Rd), regspec_Ta[size & 3],
VREGNAME(Rn), regspec_Tb[((size & 3) << 1) + (q & 1)],
VREGNAME(Rd), regspec_Tb[((size & 3) << 1) + (q & 1)]);
} else {
UNDEFINED(pc, insn, "illegal pmull size");
}
}
OP1FUNC(op_eretaa, m)
{
if (m == 0)
PRINTF("eretaa\n");
else
PRINTF("eretab\n");
}
OP1FUNC(op_retaa, m)
{
if (m == 0)
PRINTF("retaa\n");
else
PRINTF("retab\n");
}
OP4FUNC(op_blraa, z, m, Rn, Rm)
{
if (z == 0) {
if (Rm != 31) {
UNDEFINED(pc, insn, "undefined");
} else {
PRINTF("%s\t%s\n",
SHIFTOP2(m, "blraaz", "blrabz"),
SREGNAME(1, Rn));
}
} else {
PRINTF("%s\t%s, %s\n",
SHIFTOP2(m, "blraa", "blrab"),
SREGNAME(1, Rn),
SREGNAME(1, Rm));
}
}
OP4FUNC(op_braa, z, m, Rn, Rm)
{
if (z == 0) {
if (Rm != 31) {
UNDEFINED(pc, insn, "undefined");
} else {
PRINTF("%s\t%s\n",
SHIFTOP2(m, "braaz", "brabz"),
SREGNAME(1, Rn));
}
} else {
PRINTF("%s\t%s, %s\n",
SHIFTOP2(m, "braa", "brab"),
SREGNAME(1, Rn),
SREGNAME(1, Rm));
}
}
OP4FUNC(op_pacda, z, m, Rn, Rd)
{
if (z != 0) {
if (Rn != 31) {
UNDEFINED(pc, insn, "undefined");
} else {
PRINTF("%s\t%s\n",
SHIFTOP2(m, "pacdza", "pacdzb"),
SREGNAME(1, Rd));
}
} else {
PRINTF("%s\t%s, %s\n",
SHIFTOP2(m, "pacda", "pacdb"),
ZREGNAME(1, Rd),
SREGNAME(1, Rn));
}
}
OP4FUNC(op_pacia, z, m, Rn, Rd)
{
if (z != 0) {
if (Rn != 31) {
UNDEFINED(pc, insn, "undefined");
} else {
PRINTF("%s\t%s\n",
SHIFTOP2(m, "paciza", "pacizb"),
SREGNAME(1, Rd));
}
} else {
PRINTF("%s\t%s, %s\n",
SHIFTOP2(m, "pacia", "pacib"),
ZREGNAME(1, Rd),
SREGNAME(1, Rn));
}
}
OP3FUNC(op_pacga, Rm, Rn, Rd)
{
PRINTF("pacga\t%s, %s, %s\n",
ZREGNAME(1, Rd),
ZREGNAME(1, Rn),
SREGNAME(1, Rm));
}
OP1FUNC(op_xpaci, Rd)
{
PRINTF("xpaci\t%s\n",
ZREGNAME(1, Rd));
}
OP1FUNC(op_xpacd, Rd)
{
PRINTF("xpacd\t%s\n",
ZREGNAME(1, Rd));
}
OP0FUNC(op_xpaclri)
{
PRINTF("xpaclri\n");
}
struct bitpos {
uint8_t pos;
uint8_t width;
};
struct insn_info {
uint32_t mask;
uint32_t pattern;
#define INSN_MAXARG 8
struct bitpos bitinfo[INSN_MAXARG];
OPFUNC_DECL(void (*opfunc),,,,,,,,);
};
#define FMT_NOARG \
{{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_RD \
{{ 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_RN \
{{ 5, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_RN_RT \
{{ 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_M \
{{10, 1}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_CRM \
{{ 8, 4}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_CRM_OP2 \
{{ 8, 4}, { 5, 3}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_OP2_RN_RD \
{{10, 2}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_Z_M_RN_RD \
{{13, 1}, {10, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_M_D_RN_RD \
{{13, 1}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_OP3_RN_RD \
{{12, 3}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_OP1_CRM_OP2 \
{{16, 3}, { 8, 4}, { 5, 3}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_OP1_CRN_CRM_OP2_RT \
{{16, 3}, {12, 4}, { 8, 4}, { 5, 3}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_RM_RN_RD \
{{16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_RS_RN_RT \
{{16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_RM_OP2_RN_RD \
{{16, 5}, {10, 2}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_RM_OP_RN_RD \
{{16, 5}, {12, 3}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_RM_RA_RN_RD \
{{16, 5}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_IMM9_RN_RT \
{{12, 9}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_RM_OPT_SHIFT_RN_RT \
{{16, 5}, {13, 3}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_IMM16 \
{{ 5,16}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_IMM16_LL \
{{ 5,16}, { 0, 2}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_IMM16_UDF \
{{ 0,16}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_OP0_OP1_CRN_CRM_OP2_RT \
{{19, 2}, {16, 3}, {12, 4}, { 8, 4}, { 5, 3}, { 0, 5}, { 0, 0}, { 0, 0}}
#define FMT_IMM7_RT2_RN_RT \
{{15, 7}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_IMM12_RN_RT \
{{10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_OPC_IMM9_RN_RT \
{{22, 1}, {12, 9}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_OPC_RM_OPT_SHIFT_RN_RT \
{{22, 1}, {16, 5}, {13, 3}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
#define FMT_OPC_IMM12_RN_RT \
{{22, 1}, {10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_IMM19_COND \
{{ 5,19}, { 0, 4}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_IMM19_RT \
{{ 5,19}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_Z_M_RN_RM \
{{24, 1}, {10, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_IMM26 \
{{ 0,26}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SIZE_RN_RT \
{{30, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SIZE_RT2_RN_RT \
{{30, 1}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SIZE_RS_RN_RT \
{{30, 1}, {16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SIZE_RS_RT2_RN_RT \
{{30, 1}, {16, 5}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SIZE_IMM9_RN_RT \
{{30, 1}, {12, 9}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SIZE_RM_OPT_SHIFT_RN_RT \
{{30, 1}, {16, 5}, {13, 3}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
#define FMT_SIZE_IMM12_RN_RT \
{{30, 1}, {10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_Q_SIZE_RM_RN_RD \
{{30, 1}, {22, 2}, {16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SIZE_IMM19_RT \
{{30, 1}, { 5,19}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_IMMLO_IMMHI_RD \
{{29, 2}, { 5,19}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SF_RN_RD \
{{31, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SF_OPC_RN_RD \
{{31, 1}, {10, 2}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SF_RM_RN_RD \
{{31, 1}, {16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SF_RM_SZ_RN_RD \
{{31, 1}, {16, 5}, {10, 2}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SF_RM_RA_RN_RD \
{{31, 1}, {16, 5}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SF_IMM5_COND_RN_NZCV \
{{31, 1}, {16, 5}, {12, 4}, { 5, 5}, { 0, 4}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SF_RM_COND_RN_NZCV \
{{31, 1}, {16, 5}, {12, 4}, { 5, 5}, { 0, 4}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SF_RM_COND_RN_RD \
{{31, 1}, {16, 5}, {12, 4}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SF_RM_OPT_IMM3_RN_RD \
{{31, 1}, {16, 5}, {13, 3}, {10, 3}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
#define FMT_SF_RM_OP_IMM3_RN_RD \
{{31, 1}, {16, 5}, {13, 3}, {10, 3}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
#define FMT_SF_IMM7_RT2_RN_RT \
{{31, 1}, {15, 7}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SF_N_RM_IMM6_RN_RD \
{{31, 1}, {22, 1}, {16, 5}, {10, 6}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
#define FMT_SF_N_RM_IMMS_RN_RD \
{{31, 1}, {22, 1}, {16, 5}, {10, 6}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
#define FMT_SF_HW_IMM16_RD \
{{31, 1}, {21, 2}, { 5,16}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SF_N_IMMR_IMMS_RN_RD \
{{31, 1}, {22, 1}, {16, 6}, {10, 6}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
#define FMT_SF_SHIFT_RM_IMM6_RN_RD \
{{31, 1}, {22, 2}, {16, 5}, {10, 6}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
#define FMT_SF_SHIFT_IMM12_RN_RD \
{{31, 1}, {22, 2}, {10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SF_IMM19_RT \
{{31, 1}, { 5,19}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_B5_B40_IMM14_RT \
{{31, 1}, {19, 5}, { 5,14}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_OPC_L_IMM7_RT2_RN_RT \
{{30, 2}, {22, 1}, {15, 7}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
#define FMT_SIZE_OPC_IMM9_RN_RT \
{{30, 2}, {22, 2}, {12, 9}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
#define FMT_SIZE_OPC_RM_OPT_S_RN_RT \
{{30, 2}, {22, 2}, {16, 5}, {13, 3}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}}
#define FMT_SIZE_OPC_IMM12_RN_RT \
{{30, 2}, {22, 2}, {10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
static const struct insn_info insn_tables[] = {
{ 0xffffffff, 0xd6bf03e0, FMT_NOARG, op_drps },
{ 0xffffffff, 0xd69f03e0, FMT_NOARG, op_eret },
{ 0xffffffff, 0xd50320ff, FMT_NOARG, op_xpaclri },
{ 0xffffffe0, 0xdac143e0, FMT_RD, op_xpaci },
{ 0xffffffe0, 0xdac147e0, FMT_RD, op_xpacd },
{ 0xfffffc1f, 0xd63f0000, FMT_RN, op_blr },
{ 0xfffffc1f, 0xd61f0000, FMT_RN, op_br },
{ 0xfffffc1f, 0xd65f0000, FMT_RN, op_ret },
{ 0xfffffc00, 0x08dffc00, FMT_RN_RT, op_ldarb },
{ 0xfffffc00, 0x48dffc00, FMT_RN_RT, op_ldarh },
{ 0xfffffc00, 0x085ffc00, FMT_RN_RT, op_ldaxrb },
{ 0xfffffc00, 0x485ffc00, FMT_RN_RT, op_ldaxrh },
{ 0xfffffc00, 0x085f7c00, FMT_RN_RT, op_ldxrb },
{ 0xfffffc00, 0x485f7c00, FMT_RN_RT, op_ldxrh },
{ 0xfffffc00, 0x089ffc00, FMT_RN_RT, op_stlrb },
{ 0xfffffc00, 0x489ffc00, FMT_RN_RT, op_stlrh },
{ 0xfffffbff, 0xd69f0bff, FMT_M, op_eretaa },
{ 0xfffffbff, 0xd65f0bff, FMT_M, op_retaa },
{ 0xfffff0ff, 0xd503305f, FMT_CRM, op_clrex },
{ 0xfffff0ff, 0xd50330bf, FMT_CRM, op_dmb },
{ 0xfffff0ff, 0xd503309f, FMT_CRM, op_dsb },
{ 0xfffff0ff, 0xd50330df, FMT_CRM, op_isb },
{ 0xfffff01f, 0xd503201f, FMT_CRM_OP2, op_hint },
{ 0xfffff000, 0xcec08000, FMT_OP2_RN_RD, op_simd_sha512_reg2 },
{ 0xffffd800, 0xdac10800, FMT_Z_M_RN_RD, op_pacda },
{ 0xffffd800, 0xdac10000, FMT_Z_M_RN_RD, op_pacia },
{ 0xffffcc00, 0x4e284800, FMT_M_D_RN_RD, op_simd_aes },
{ 0xffff8c00, 0x5e280800, FMT_OP3_RN_RD, op_simd_sha_reg2 },
{ 0xffff0000, 0x00000000, FMT_IMM16_UDF, op_udf },
{ 0xfff8f01f, 0xd500401f, FMT_OP1_CRM_OP2, op_msr_imm },
{ 0xfff80000, 0xd5080000, FMT_OP1_CRN_CRM_OP2_RT, op_sys },
{ 0xfff80000, 0xd5280000, FMT_OP1_CRN_CRM_OP2_RT, op_sysl },
{ 0xffe0fc00, 0x9b407c00, FMT_RM_RN_RD, op_smulh },
{ 0xffe0fc00, 0x0800fc00, FMT_RS_RN_RT, op_stlxrb },
{ 0xffe0fc00, 0x4800fc00, FMT_RS_RN_RT, op_stlxrh },
{ 0xffe0fc00, 0x08007c00, FMT_RS_RN_RT, op_stxrb },
{ 0xffe0fc00, 0x48007c00, FMT_RS_RN_RT, op_stxrh },
{ 0xffe0fc00, 0x9bc07c00, FMT_RM_RN_RD, op_umulh },
{ 0xffe0fc00, 0x9ac03000, FMT_RM_RN_RD, op_pacga },
{ 0xffe0f000, 0xce608000, FMT_RM_OP2_RN_RD, op_simd_sha512_reg3 },
{ 0xffe08c00, 0x5e000000, FMT_RM_OP_RN_RD, op_simd_sha_reg3 },
{ 0xffe08000, 0x9b208000, FMT_RM_RA_RN_RD, op_smsubl },
{ 0xffe08000, 0x9ba08000, FMT_RM_RA_RN_RD, op_umsubl },
{ 0xffe08000, 0x9b200000, FMT_RM_RA_RN_RD, op_smaddl },
{ 0xffe08000, 0x9ba00000, FMT_RM_RA_RN_RD, op_umaddl },
{ 0xffe00c00, 0x38400400, FMT_IMM9_RN_RT, op_ldrb_immpostidx },
{ 0xffe00c00, 0x38400c00, FMT_IMM9_RN_RT, op_ldrb_immpreidx },
{ 0xffe00c00, 0x38600800, FMT_RM_OPT_SHIFT_RN_RT, op_ldrb_reg },
{ 0xffe00c00, 0x78400400, FMT_IMM9_RN_RT, op_ldrh_immpostidx },
{ 0xffe00c00, 0x78400c00, FMT_IMM9_RN_RT, op_ldrh_immpreidx },
{ 0xffe00c00, 0x78600800, FMT_RM_OPT_SHIFT_RN_RT, op_ldrh_reg },
{ 0xffe00c00, 0xb8800400, FMT_IMM9_RN_RT, op_ldrsw_immpostidx },
{ 0xffe00c00, 0xb8800c00, FMT_IMM9_RN_RT, op_ldrsw_immpreidx },
{ 0xffe00c00, 0xb8a00800, FMT_RM_OPT_SHIFT_RN_RT, op_ldrsw_reg },
{ 0xffe00c00, 0x38400800, FMT_IMM9_RN_RT, op_ldtrb },
{ 0xffe00c00, 0x78400800, FMT_IMM9_RN_RT, op_ldtrh },
{ 0xffe00c00, 0xb8800800, FMT_IMM9_RN_RT, op_ldtrsw },
{ 0xffe00c00, 0x38400000, FMT_IMM9_RN_RT, op_ldurb },
{ 0xffe00c00, 0x78400000, FMT_IMM9_RN_RT, op_ldurh },
{ 0xffe00c00, 0xb8800000, FMT_IMM9_RN_RT, op_ldursw },
{ 0xffe00c00, 0xf8a00800, FMT_RM_OPT_SHIFT_RN_RT, op_prfm_reg },
{ 0xffe00c00, 0xf8800000, FMT_IMM9_RN_RT, op_prfum },
{ 0xffe00c00, 0x38000400, FMT_IMM9_RN_RT, op_strb_immpostidx },
{ 0xffe00c00, 0x38000c00, FMT_IMM9_RN_RT, op_strb_immpreidx },
{ 0xffe00c00, 0x38200800, FMT_RM_OPT_SHIFT_RN_RT, op_strb_reg },
{ 0xffe00c00, 0x78000400, FMT_IMM9_RN_RT, op_strh_immpostidx },
{ 0xffe00c00, 0x78000c00, FMT_IMM9_RN_RT, op_strh_immpreidx },
{ 0xffe00c00, 0x78200800, FMT_RM_OPT_SHIFT_RN_RT, op_strh_reg },
{ 0xffe00c00, 0x38000800, FMT_IMM9_RN_RT, op_sttrb },
{ 0xffe00c00, 0x78000800, FMT_IMM9_RN_RT, op_sttrh },
{ 0xffe00c00, 0x38000000, FMT_IMM9_RN_RT, op_sturb },
{ 0xffe00c00, 0x78000000, FMT_IMM9_RN_RT, op_sturh },
{ 0xffe0001f, 0xd4200000, FMT_IMM16, op_brk },
{ 0xffe0001f, 0xd4400000, FMT_IMM16, op_hlt },
{ 0xffe0001f, 0xd4000002, FMT_IMM16, op_hvc },
{ 0xffe0001f, 0xd4000003, FMT_IMM16, op_smc },
{ 0xffe0001f, 0xd4000001, FMT_IMM16, op_svc },
{ 0xffe0001c, 0xd4a00000, FMT_IMM16_LL, op_dcps },
{ 0xffe00000, 0xd5200000, FMT_OP0_OP1_CRN_CRM_OP2_RT, op_mrs },
{ 0xffe00000, 0xd5000000, FMT_OP0_OP1_CRN_CRM_OP2_RT, op_msr },
{ 0xffc00000, 0x68c00000, FMT_IMM7_RT2_RN_RT, op_ldpsw_postidx },
{ 0xffc00000, 0x69c00000, FMT_IMM7_RT2_RN_RT, op_ldpsw_preidx },
{ 0xffc00000, 0x69400000, FMT_IMM7_RT2_RN_RT, op_ldpsw_signed },
{ 0xffc00000, 0x39400000, FMT_IMM12_RN_RT, op_ldrb_immunsign },
{ 0xffc00000, 0x79400000, FMT_IMM12_RN_RT, op_ldrh_immunsign },
{ 0xffc00000, 0xb9800000, FMT_IMM12_RN_RT, op_ldrsw_immunsign },
{ 0xffc00000, 0xf9800000, FMT_IMM12_RN_RT, op_prfm_imm },
{ 0xffc00000, 0x39000000, FMT_IMM12_RN_RT, op_strb_immunsign },
{ 0xffc00000, 0x79000000, FMT_IMM12_RN_RT, op_strh_immunsign },
{ 0xffa00c00, 0x38800400, FMT_OPC_IMM9_RN_RT, op_ldrsb_immpostidx },
{ 0xffa00c00, 0x38800c00, FMT_OPC_IMM9_RN_RT, op_ldrsb_immpreidx },
{ 0xffa00c00, 0x38a00800, FMT_OPC_RM_OPT_SHIFT_RN_RT, op_ldrsb_reg },
{ 0xffa00c00, 0x78800400, FMT_OPC_IMM9_RN_RT, op_ldrsh_immpostidx },
{ 0xffa00c00, 0x78800c00, FMT_OPC_IMM9_RN_RT, op_ldrsh_immpreidx },
{ 0xffa00c00, 0x78a00800, FMT_OPC_RM_OPT_SHIFT_RN_RT, op_ldrsh_reg },
{ 0xffa00c00, 0x38800800, FMT_OPC_IMM9_RN_RT, op_ldtrsb },
{ 0xffa00c00, 0x78800800, FMT_OPC_IMM9_RN_RT, op_ldtrsh },
{ 0xffa00c00, 0x38800000, FMT_OPC_IMM9_RN_RT, op_ldursb },
{ 0xffa00c00, 0x78800000, FMT_OPC_IMM9_RN_RT, op_ldursh },
{ 0xff800000, 0x39800000, FMT_OPC_IMM12_RN_RT, op_ldrsb_immunsign },
{ 0xff800000, 0x79800000, FMT_OPC_IMM12_RN_RT, op_ldrsh_immunsign },
{ 0xff000010, 0x54000000, FMT_IMM19_COND, op_b_cond },
{ 0xff000000, 0x98000000, FMT_IMM19_RT, op_ldrsw_literal },
{ 0xff000000, 0xd8000000, FMT_IMM19_RT, op_prfm_literal },
{ 0xfefff800, 0xd63f0800, FMT_Z_M_RN_RM, op_blraa },
{ 0xfefff800, 0xd61f0800, FMT_Z_M_RN_RM, op_braa },
{ 0xfc000000, 0x14000000, FMT_IMM26, op_b },
{ 0xfc000000, 0x94000000, FMT_IMM26, op_bl },
{ 0xbffffc00, 0x88dffc00, FMT_SIZE_RN_RT, op_ldar },
{ 0xbffffc00, 0x885ffc00, FMT_SIZE_RN_RT, op_ldaxr },
{ 0xbffffc00, 0x885f7c00, FMT_SIZE_RN_RT, op_ldxr },
{ 0xbffffc00, 0x889ffc00, FMT_SIZE_RN_RT, op_stlr },
{ 0xbfff8000, 0x887f8000, FMT_SIZE_RT2_RN_RT, op_ldaxp },
{ 0xbfff8000, 0x887f0000, FMT_SIZE_RT2_RN_RT, op_ldxp },
{ 0xbfe0fc00, 0x8800fc00, FMT_SIZE_RS_RN_RT, op_stlxr },
{ 0xbfe0fc00, 0x88007c00, FMT_SIZE_RS_RN_RT, op_stxr },
{ 0xbfe08000, 0x88208000, FMT_SIZE_RS_RT2_RN_RT, op_stlxp },
{ 0xbfe08000, 0x88200000, FMT_SIZE_RS_RT2_RN_RT, op_stxp },
{ 0xbfe00c00, 0xb8400400, FMT_SIZE_IMM9_RN_RT, op_ldr_immpostidx },
{ 0xbfe00c00, 0xb8400c00, FMT_SIZE_IMM9_RN_RT, op_ldr_immpreidx },
{ 0xbfe00c00, 0xb8600800, FMT_SIZE_RM_OPT_SHIFT_RN_RT, op_ldr_reg },
{ 0xbfe00c00, 0xb8400800, FMT_SIZE_IMM9_RN_RT, op_ldtr },
{ 0xbfe00c00, 0xb8400000, FMT_SIZE_IMM9_RN_RT, op_ldur },
{ 0xbfe00c00, 0xb8000400, FMT_SIZE_IMM9_RN_RT, op_str_immpostidx },
{ 0xbfe00c00, 0xb8000c00, FMT_SIZE_IMM9_RN_RT, op_str_immpreidx },
{ 0xbfe00c00, 0xb8200800, FMT_SIZE_RM_OPT_SHIFT_RN_RT, op_str_reg },
{ 0xbfe00c00, 0xb8000800, FMT_SIZE_IMM9_RN_RT, op_sttr },
{ 0xbfe00c00, 0xb8000000, FMT_SIZE_IMM9_RN_RT, op_stur },
{ 0xbfc00000, 0xb9400000, FMT_SIZE_IMM12_RN_RT, op_ldr_immunsign },
{ 0xbfc00000, 0xb9000000, FMT_SIZE_IMM12_RN_RT, op_str_immunsign },
{ 0xbf20fc00, 0x0e20e000, FMT_Q_SIZE_RM_RN_RD, op_simd_pmull },
{ 0xbf000000, 0x18000000, FMT_SIZE_IMM19_RT, op_ldr_literal },
{ 0x9f000000, 0x10000000, FMT_IMMLO_IMMHI_RD, op_adr },
{ 0x9f000000, 0x90000000, FMT_IMMLO_IMMHI_RD, op_adrp },
{ 0x7ffffc00, 0x5ac01400, FMT_SF_RN_RD, op_cls },
{ 0x7ffffc00, 0x5ac01000, FMT_SF_RN_RD, op_clz },
{ 0x7ffff000, 0x5ac00000, FMT_SF_OPC_RN_RD, op_rev },
{ 0x7fe0fc00, 0x5a000000, FMT_SF_RM_RN_RD, op_sbc },
{ 0x7fe0fc00, 0x7a000000, FMT_SF_RM_RN_RD, op_sbcs },
{ 0x7fe0fc00, 0x1a000000, FMT_SF_RM_RN_RD, op_adc },
{ 0x7fe0fc00, 0x3a000000, FMT_SF_RM_RN_RD, op_adcs },
{ 0x7fe0fc00, 0x1ac02800, FMT_SF_RM_RN_RD, op_asr_reg },
{ 0x7fe0fc00, 0x1ac02000, FMT_SF_RM_RN_RD, op_lsl_reg },
{ 0x7fe0fc00, 0x1ac02400, FMT_SF_RM_RN_RD, op_lsr_reg },
{ 0x7fe0fc00, 0x1ac02c00, FMT_SF_RM_RN_RD, op_ror_reg },
{ 0x7fe0fc00, 0x1ac00c00, FMT_SF_RM_RN_RD, op_sdiv },
{ 0x7fe0fc00, 0x1ac00800, FMT_SF_RM_RN_RD, op_udiv },
{ 0x7fe0f000, 0x1ac04000, FMT_SF_RM_SZ_RN_RD, op_crc32 },
{ 0x7fe0f000, 0x1ac05000, FMT_SF_RM_SZ_RN_RD, op_crc32c },
{ 0x7fe08000, 0x1b008000, FMT_SF_RM_RA_RN_RD, op_msub },
{ 0x7fe08000, 0x1b000000, FMT_SF_RM_RA_RN_RD, op_madd },
{ 0x7fe00c10, 0x3a400800, FMT_SF_IMM5_COND_RN_NZCV, op_ccmn_imm },
{ 0x7fe00c10, 0x3a400000, FMT_SF_RM_COND_RN_NZCV, op_ccmn_reg },
{ 0x7fe00c10, 0x7a400800, FMT_SF_IMM5_COND_RN_NZCV, op_ccmp_imm },
{ 0x7fe00c10, 0x7a400000, FMT_SF_RM_COND_RN_NZCV, op_ccmp_reg },
{ 0x7fe00c00, 0x5a800000, FMT_SF_RM_COND_RN_RD, op_csinv },
{ 0x7fe00c00, 0x5a800400, FMT_SF_RM_COND_RN_RD, op_csneg },
{ 0x7fe00c00, 0x1a800400, FMT_SF_RM_COND_RN_RD, op_cinc },
{ 0x7fe00c00, 0x1a800000, FMT_SF_RM_COND_RN_RD, op_csel },
{ 0x7fe00000, 0x6b200000, FMT_SF_RM_OPT_IMM3_RN_RD, op_subs_extreg },
{ 0x7fe00000, 0x0b200000, FMT_SF_RM_OPT_IMM3_RN_RD, op_add_extreg },
{ 0x7fe00000, 0x2b200000, FMT_SF_RM_OP_IMM3_RN_RD, op_adds_extreg },
{ 0x7fe00000, 0x4b200000, FMT_SF_RM_OPT_IMM3_RN_RD, op_sub_extreg },
{ 0x7fc00000, 0x28400000, FMT_SF_IMM7_RT2_RN_RT, op_ldnp },
{ 0x7fc00000, 0x28c00000, FMT_SF_IMM7_RT2_RN_RT, op_ldp_postidx },
{ 0x7fc00000, 0x29c00000, FMT_SF_IMM7_RT2_RN_RT, op_ldp_preidx },
{ 0x7fc00000, 0x29400000, FMT_SF_IMM7_RT2_RN_RT, op_ldp_signed },
{ 0x7fc00000, 0x28000000, FMT_SF_IMM7_RT2_RN_RT, op_stnp },
{ 0x7fc00000, 0x28800000, FMT_SF_IMM7_RT2_RN_RT, op_stp_postidx },
{ 0x7fc00000, 0x29800000, FMT_SF_IMM7_RT2_RN_RT, op_stp_preidx },
{ 0x7fc00000, 0x29000000, FMT_SF_IMM7_RT2_RN_RT, op_stp_signed },
{ 0x7fa00000, 0x13800000, FMT_SF_N_RM_IMM6_RN_RD, op_ror_imm },
{ 0x7f800000, 0x12800000, FMT_SF_HW_IMM16_RD, op_movn },
{ 0x7f800000, 0x52800000, FMT_SF_HW_IMM16_RD, op_movz },
{ 0x7f800000, 0x32000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_orr_imm },
{ 0x7f800000, 0x13000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_sbfm },
{ 0x7f800000, 0x53000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_ubfm },
{ 0x7f800000, 0x12000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_and_imm },
{ 0x7f800000, 0x72000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_ands_imm },
{ 0x7f800000, 0x33000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_bfi },
{ 0x7f800000, 0x52000000, FMT_SF_N_IMMR_IMMS_RN_RD, op_eor_imm },
{ 0x7f800000, 0x72800000, FMT_SF_HW_IMM16_RD, op_movk },
{ 0x7f200000, 0x2a200000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_orn },
{ 0x7f200000, 0x2a000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_orr_reg },
{ 0x7f200000, 0x4b000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_sub_shiftreg },
{ 0x7f200000, 0x6b000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_subs_shiftreg },
{ 0x7f200000, 0x0b000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_add_shiftreg },
{ 0x7f200000, 0x2b000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_adds_shiftreg },
{ 0x7f200000, 0x0a000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_and_shiftreg },
{ 0x7f200000, 0x6a000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_ands_shiftreg },
{ 0x7f200000, 0x0a200000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_bic_shiftreg },
{ 0x7f200000, 0x6a200000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_bics_shiftreg },
{ 0x7f200000, 0x4a200000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_eon_shiftreg },
{ 0x7f200000, 0x4a000000, FMT_SF_SHIFT_RM_IMM6_RN_RD, op_eor_shiftreg },
{ 0x7f000000, 0x71000000, FMT_SF_SHIFT_IMM12_RN_RD, op_subs_imm },
{ 0x7f000000, 0x11000000, FMT_SF_SHIFT_IMM12_RN_RD, op_add_imm },
{ 0x7f000000, 0x31000000, FMT_SF_SHIFT_IMM12_RN_RD, op_adds_imm },
{ 0x7f000000, 0x35000000, FMT_SF_IMM19_RT, op_cbnz },
{ 0x7f000000, 0x34000000, FMT_SF_IMM19_RT, op_cbz },
{ 0x7f000000, 0x51000000, FMT_SF_SHIFT_IMM12_RN_RD, op_sub_imm },
{ 0x7f000000, 0x37000000, FMT_B5_B40_IMM14_RT, op_tbnz },
{ 0x7f000000, 0x36000000, FMT_B5_B40_IMM14_RT, op_tbz },
{ 0x3f800000, 0x2c000000, FMT_OPC_L_IMM7_RT2_RN_RT, op_simd_ldstnp },
{ 0x3f800000, 0x2c800000, FMT_OPC_L_IMM7_RT2_RN_RT, op_simd_ldstp_postidx },
{ 0x3f800000, 0x2d800000, FMT_OPC_L_IMM7_RT2_RN_RT, op_simd_ldstp_preidx },
{ 0x3f800000, 0x2d000000, FMT_OPC_L_IMM7_RT2_RN_RT, op_simd_ldstp_signed },
{ 0x3f200c00, 0x3c000400, FMT_SIZE_OPC_IMM9_RN_RT, op_simd_ldstr_immpostidx },
{ 0x3f200c00, 0x3c000c00, FMT_SIZE_OPC_IMM9_RN_RT, op_simd_ldstr_immpreidx },
{ 0x3f200c00, 0x3c200800, FMT_SIZE_OPC_RM_OPT_S_RN_RT, op_simd_ldstr_reg },
{ 0x3f000000, 0x3d000000, FMT_SIZE_OPC_IMM12_RN_RT, op_simd_ldstr_immunsign },
{ 0x00000000, 0x00000000, FMT_NOARG, op_undefined }
};
#define WIDTHMASK(w) (0xffffffff >> (32 - (w)))
void
disasm_insn(const disasm_interface_t *di, vaddr_t loc, uint32_t insn)
{
uint64_t args[INSN_MAXARG];
unsigned int i, j;
for (i = 0; i < __arraycount(insn_tables); i++) {
if ((insn & insn_tables[i].mask) != insn_tables[i].pattern)
continue;
for (j = 0; j < INSN_MAXARG; j++) {
if (insn_tables[i].bitinfo[j].width == 0)
break;
args[j] = (insn >> insn_tables[i].bitinfo[j].pos) &
WIDTHMASK(insn_tables[i].bitinfo[j].width);
}
insn_tables[i].opfunc(di, loc, insn,
args[0], args[1], args[2], args[3],
args[4], args[5], args[6], args[7]);
break;
}
}
vaddr_t
disasm(const disasm_interface_t *di, vaddr_t loc)
{
uint32_t insn;
insn = di->di_readword(loc);
disasm_insn(di, loc, insn);
return loc + sizeof(insn);
}