diff options
author | tobhe <tobhe@cvs.openbsd.org> | 2020-07-25 12:26:10 +0000 |
---|---|---|
committer | tobhe <tobhe@cvs.openbsd.org> | 2020-07-25 12:26:10 +0000 |
commit | 9c5018cf092618712581b3a49e92cee88b98495e (patch) | |
tree | a0fd4dfcb9a48f8afecfa8d52445313f549aa907 | |
parent | 6aebf6970a28f34a305adffaa80c9faa84321f04 (diff) |
Port over NetBSD's arm64 disassembler for DDB.
ok kettenis@, patrick@
-rw-r--r-- | sys/arch/arm64/arm64/db_disasm.c | 60 | ||||
-rw-r--r-- | sys/arch/arm64/arm64/disasm.c | 4008 | ||||
-rw-r--r-- | sys/arch/arm64/arm64/disasm.h | 43 | ||||
-rw-r--r-- | sys/arch/arm64/conf/files.arm64 | 3 |
4 files changed, 4100 insertions, 14 deletions
diff --git a/sys/arch/arm64/arm64/db_disasm.c b/sys/arch/arm64/arm64/db_disasm.c index 920d6f427a5..66cce265fbf 100644 --- a/sys/arch/arm64/arm64/db_disasm.c +++ b/sys/arch/arm64/arm64/db_disasm.c @@ -1,18 +1,30 @@ -/* $OpenBSD: db_disasm.c,v 1.2 2019/11/07 11:04:21 mpi Exp $ */ +/* $OpenBSD: db_disasm.c,v 1.3 2020/07/25 12:26:09 tobhe Exp $ */ +/* $NetBSD: db_disasm.c,v 1.10 2020/07/09 23:43:41 ryo Exp $ */ + /* - * Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com> + * Copyright (c) 2017 Ryo Shimizu <ryo@nerv.org> + * All rights reserved. * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ #include <sys/param.h> @@ -22,8 +34,30 @@ #include <ddb/db_output.h> #include <ddb/db_access.h> +#include <arch/arm64/arm64/disasm.h> + +static db_expr_t +db_disasm_readword(db_expr_t address) +{ + return db_get_value(address, sizeof(uint32_t), false); +} + +static void +db_disasm_printaddr(db_expr_t address) +{ + db_printf("%lx <", address); + db_printsym((vaddr_t)address, DB_STGY_ANY, db_printf); + db_printf(">"); +} + +static const disasm_interface_t db_disasm_interface = { + .di_readword = db_disasm_readword, + .di_printaddr = db_disasm_printaddr, + .di_printf = db_printf +}; + vaddr_t db_disasm(vaddr_t loc, int altfmt) { - return loc + 4; + return disasm(&db_disasm_interface, loc); } diff --git a/sys/arch/arm64/arm64/disasm.c b/sys/arch/arm64/arm64/disasm.c new file mode 100644 index 00000000000..b0035b53f45 --- /dev/null +++ b/sys/arch/arm64/arm64/disasm.c @@ -0,0 +1,4008 @@ +/* $OpenBSD: disasm.c,v 1.1 2020/07/25 12:26:09 tobhe Exp $ */ +/* $NetBSD: disasm.c,v 1.8 2020/05/26 05:25:21 ryo Exp $ */ + +/* + * Copyright (c) 2018 Ryo Shimizu <ryo@nerv.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.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; +}; + +/* must be sorted by code */ +const struct sysreg_table sysreg_table[] = { + /* op0 op1 CRn CRm op2 name */ + { 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); + + /* special case for dbgdtrrx_el0(RO) and dbgdtrtx_el0(WO) */ + 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; +} + +/* rotate right. if n < 0, rotate left. */ +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; + } + + /* ALIAS: mov_tofromsp */ + 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) +{ + /* ALIAS: cmn_extreg */ + extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd, + "adds", "cmn"); +} + +OP5FUNC(op_adds_imm, sf, shift, imm12, Rn, Rd) +{ + /* ALIAS: cmn_imm */ + 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; + } + /* ALIAS: cmn_shiftreg */ + 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; + } + + /* ALIAS: tst_imm */ + 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) +{ + /* ALIAS: tst_shiftreg */ + 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; + + /* ALIAS: asr_imm,sbfiz,sbfx,sxtb,sxth,sxtw */ + 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) +{ + /* ALIAS: asrv */ + /* "asr" always the preferred disassembly */ + 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; + + /* ALIAS: at,dc,ic,sys,tlbi */ + 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; + } + + /* default, sys instruction */ + 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; + + /* ALIAS: bfm,bfxil */ + /* it is not disassembled as bfm */ + 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) +{ + /* ALIAS: cset,csinc */ + csetsel_common(di, pc, insn, sf, Rm, cond, Rn, Rd, + "csinc", "cset", "cinc"); +} + +OP5FUNC(op_csinv, sf, Rm, cond, Rn, Rd) +{ + /* ALIAS: csetm,cinv */ + 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) +{ + /* ALIAS: cmp_extreg */ + extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd, + "subs", "cmp"); +} + +OP5FUNC(op_subs_imm, sf, shift, imm12, Rn, Rd) +{ + /* ALIAS: cmp_imm */ + 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; + } + + /* ALIAS: negs,cmp_shiftreg */ + shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, + "subs", "negs", "cmp"); +} + +OP5FUNC(op_csneg, sf, Rm, cond, Rn, Rd) +{ + /* ALIAS: cneg */ + 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"; /* "crc32x" + SizeChar */ + + 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; + } + + /* ALIAS: extr */ + 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); + + /* ALIAS: nop,sev,sevl,wfe,wfi,yield */ + 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; + + /* ALIAS: lsr_imm,ubfiz,ubfm,ubfx,uxtb,uxth */ + 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) +{ + /* ALIAS: lslv */ + /* "lsl" always the preferred disassembly */ + PRINTF("lsl\t%s, %s, %s\n", + ZREGNAME(sf, Rd), + ZREGNAME(sf, Rn), + ZREGNAME(sf, Rm)); +} + +OP4FUNC(op_lsr_reg, sf, Rm, Rn, Rd) +{ + /* ALIAS: lsrv */ + /* "lsr" always the preferred disassembly */ + PRINTF("lsr\t%s, %s, %s\n", + ZREGNAME(sf, Rd), + ZREGNAME(sf, Rn), + ZREGNAME(sf, Rm)); +} + +OP5FUNC(op_madd, sf, Rm, Ra, Rn, Rd) +{ + /* ALIAS: mul */ + 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) +{ + /* ALIAS: mneg */ + 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; + } + + /* ALIAS: mov_bmimm */ +#if 1 + /* to distinguish from mov_iwimm */ + if ((Rn == 31) && !MoveWidePreferred(sf, n, imms, immr)) { +#else + /* "orr Rd, XZR, #imm" -> "mov Rd, #imm" */ + (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; + } + + /* ALIAS: mov_iwimm */ + if ((hw == 0) || (imm16 == 0)) { + PRINTF("mov\t%s, #0x%"PRIx64"\n", + ZREGNAME(sf, Rd), + (~(ZeroExtend(16, imm16, 1) & mask)) & mask); + } else { + /* movn */ + 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) +{ + /* ALIAS: mov_reg */ + 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) +{ + /* ALIAS: mov_wimm */ + 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 + /* same as objdump */ + 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) +{ + /* ALIAS: mvn */ + shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, + "orn", "mvn", NULL); +} + +OP6FUNC(op_sub_shiftreg, sf, shift, Rm, imm6, Rn, Rd) +{ + /* ALIAS: neg */ + shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd, + "sub", "neg", NULL); +} + +OP4FUNC(op_sbc, sf, Rm, Rn, Rd) +{ + /* ALIAS: ngc */ + 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) +{ + /* ALIAS: ngcs */ + 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) +{ + /* + * sf opc insn + * -- --- ------------- + * 0 00 rbit Wd,Wn + * 0 01 rev16 Wd,Wn + * 0 10 rev Wd,Wn + * 0 11 undefined + * 1 00 rbit Xd,Xn + * 1 01 rev16 Xd,Xn + * 1 10 rev32 Xd,Xn + * 1 11 rev Xd,Xn + */ + 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) +{ + /* ALIAS: rorv */ + /* "ror" always the preferred disassembly */ + 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) +{ + /* ALIAS: smull */ + 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) +{ + /* ALIAS: smnegl */ + 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"); +} + +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) +{ + /* ALIAS: umull */ + 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) +{ + /* ALIAS: umnegl */ + 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)); +} + +/* + * load/store SIMD instructions + */ +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"); +} + +/* + * SIMD instructions are not supported except some insns. + * They are disassembled as '.insn 0xXXXXXXXX'. + */ +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 code format { {bitpos, bitwidth}, ... (maximum 8 args) } */ +#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_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[] = { + /* mask, pattern, opcode format, opfunc */ + /* --------- ---------- --------------------------- ------------------ */ + { 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 }, + { 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; + + /* extract operands */ + 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 next address */ + return loc + sizeof(insn); +} diff --git a/sys/arch/arm64/arm64/disasm.h b/sys/arch/arm64/arm64/disasm.h new file mode 100644 index 00000000000..776d080f70f --- /dev/null +++ b/sys/arch/arm64/arm64/disasm.h @@ -0,0 +1,43 @@ +/* $OpenBSD: disasm.h,v 1.1 2020/07/25 12:26:09 tobhe Exp $ */ +/* $NetBSD: disasm.h,v 1.1 2018/04/01 04:35:03 ryo Exp $ */ + +/* + * Copyright (c) 2018 Ryo Shimizu <ryo@nerv.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ARM64_DISASM_H_ +#define _ARM64_DISASM_H_ + +typedef struct { + db_expr_t (*di_readword)(db_expr_t); + void (*di_printaddr)(db_expr_t); + int (*di_printf)(const char *, ...) + __attribute__((__format__(__kprintf__,1,2))); +} disasm_interface_t; + +void disasm_insn(const disasm_interface_t *, vaddr_t, uint32_t); +vaddr_t disasm(const disasm_interface_t *, vaddr_t); + +#endif /* _ARM64_DISASM_H_ */ diff --git a/sys/arch/arm64/conf/files.arm64 b/sys/arch/arm64/conf/files.arm64 index bd73af5a000..de03add89a8 100644 --- a/sys/arch/arm64/conf/files.arm64 +++ b/sys/arch/arm64/conf/files.arm64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.arm64,v 1.31 2020/05/14 15:44:07 kettenis Exp $ +# $OpenBSD: files.arm64,v 1.32 2020/07/25 12:26:09 tobhe Exp $ maxpartitions 16 maxusers 2 8 128 @@ -43,6 +43,7 @@ file arch/arm64/dev/pci_machdep.c file arch/arm64/arm64/db_disasm.c ddb file arch/arm64/arm64/db_interface.c ddb file arch/arm64/arm64/db_trace.c ddb +file arch/arm64/arm64/disasm.c ddb pseudo-device openprom file arch/arm64/arm64/openprom.c openprom needs-flag |