1/*	$NetBSD: disasm.c,v 1.16 2024/02/07 04:20:26 msaitoh Exp $	*/
2
3/*
4 * Copyright (c) 2018 Ryo Shimizu
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: disasm.c,v 1.16 2024/02/07 04:20:26 msaitoh Exp $");
31
32#include <sys/param.h>
33#include <sys/types.h>
34#include <sys/bitops.h>
35
36#include <arch/aarch64/aarch64/disasm.h>
37
38#ifndef _KERNEL
39#include <stdio.h>
40#include <stdbool.h>
41#endif
42
43#define PRINTF		di->di_printf
44#define PRINTADDR	di->di_printaddr
45
46#define OPFUNC_DECL(func, a, b, c, d, e, f, g, h)		\
47func(const disasm_interface_t *di, uint64_t pc, uint32_t insn,	\
48    uint64_t a, uint64_t b, uint64_t c, uint64_t d,		\
49    uint64_t e, uint64_t f, uint64_t g, uint64_t h)
50
51#define UNUSED0	arg0 __unused
52#define UNUSED1	arg1 __unused
53#define UNUSED2	arg2 __unused
54#define UNUSED3	arg3 __unused
55#define UNUSED4	arg4 __unused
56#define UNUSED5	arg5 __unused
57#define UNUSED6	arg6 __unused
58#define UNUSED7	arg7 __unused
59
60#define OP0FUNC(func)						\
61	static void						\
62	OPFUNC_DECL(func,					\
63	    UNUSED0, UNUSED1, UNUSED2, UNUSED3,			\
64	    UNUSED4, UNUSED5, UNUSED6, UNUSED7)
65#define OP1FUNC(func, a)					\
66	static void						\
67	OPFUNC_DECL(func, a,					\
68	    UNUSED1, UNUSED2, UNUSED3, UNUSED4,			\
69	    UNUSED5, UNUSED6, UNUSED7)
70#define OP2FUNC(func, a, b)					\
71	static void						\
72	OPFUNC_DECL(func, a, b,					\
73	    UNUSED2, UNUSED3, UNUSED4, UNUSED5,			\
74	    UNUSED6, UNUSED7)
75#define OP3FUNC(func, a, b, c)					\
76	static void						\
77	OPFUNC_DECL(func, a, b, c,				\
78	    UNUSED3, UNUSED4, UNUSED5, UNUSED6,			\
79	    UNUSED7)
80#define OP4FUNC(func, a, b, c, d)				\
81	static void						\
82	OPFUNC_DECL(func, a, b, c, d,				\
83	    UNUSED4, UNUSED5, UNUSED6, UNUSED7)
84#define OP5FUNC(func, a, b, c, d, e)				\
85	static void						\
86	OPFUNC_DECL(  func, a, b, c, d, e,			\
87	    UNUSED5, UNUSED6, UNUSED7)
88#define OP6FUNC(func, a, b, c, d, e, f)				\
89	static void						\
90	OPFUNC_DECL(func, a, b, c, d, e, f,			\
91	    UNUSED6, UNUSED7)
92#define OP7FUNC(func, a, b, c, d, e, f, g)			\
93	static void						\
94	OPFUNC_DECL(func, a, b, c, d, e, f, g,			\
95	    UNUSED7)
96#define OP8FUNC(func, a, b, c, d, e, f, g, h)			\
97	static void						\
98	OPFUNC_DECL(func, a, b, c, d, e, f, g, h)
99
100static const char *z_wxregs[2][32] = {
101	{
102		 "w0",  "w1",  "w2",  "w3",  "w4",  "w5",  "w6",  "w7",
103		 "w8",  "w9", "w10", "w11", "w12", "w13", "w14", "w15",
104		"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
105		"w24", "w25", "w26", "w27", "w28", "w29", "w30", "wzr"
106	},
107	{
108		 "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
109		 "x8",  "x9", "x10", "x11", "x12", "x13", "x14", "x15",
110		"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
111		"x24", "x25", "x26", "x27", "x28", "x29", "x30", "xzr"
112	}
113};
114
115static const char *s_wxregs[2][32] = {
116	{
117		 "w0",  "w1",  "w2",  "w3",  "w4",  "w5",  "w6",  "w7",
118		 "w8",  "w9", "w10", "w11", "w12", "w13", "w14", "w15",
119		"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
120		"w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp"
121	},
122	{
123		 "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
124		 "x8",  "x9", "x10", "x11", "x12", "x13", "x14", "x15",
125		"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
126		"x24", "x25", "x26", "x27", "x28", "x29", "x30",  "sp"
127	}
128};
129#define ZREGNAME(s, n)	(z_wxregs[(s) & 1][(n) & 31])
130#define SREGNAME(s, n)	(s_wxregs[(s) & 1][(n) & 31])
131
132static const char *simdregs[5][32] = {
133	{
134		 "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7",
135		 "b8",  "b9", "b10", "b11", "b12", "b13", "b14", "b15",
136		"b16", "b17", "b18", "b19", "b20", "b21", "b22", "b23",
137		"b24", "b25", "b26", "b27", "b28", "b29", "b30", "b31"
138	},
139	{
140		 "h0",  "h1",  "h2",  "h3",  "h4",  "h5",  "h6",  "h7",
141		 "h8",  "h9", "h10", "h11", "h12", "h13", "h14", "h15",
142		"h16", "h17", "h18", "h19", "h20", "h21", "h22", "h23",
143		"h24", "h25", "h26", "h27", "h28", "h29", "h30", "h31"
144	},
145	{
146		 "s0",  "s1",  "s2",  "s3",  "s4",  "s5",  "s6",  "s7",
147		 "s8",  "s9", "s10", "s11", "s12", "s13", "s14", "s15",
148		"s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
149		"s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"
150	},
151	{
152		 "d0",  "d1",  "d2",  "d3",  "d4",  "d5",  "d6",  "d7",
153		 "d8",  "d9", "d10", "d11", "d12", "d13", "d14", "d15",
154		"d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
155		"d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"
156	},
157	{
158		 "q0",  "q1",  "q2",  "q3",  "q4",  "q5",  "q6",  "q7",
159		 "q8",  "q9", "q10", "q11", "q12", "q13", "q14", "q15",
160		"q16", "q17", "q18", "q19", "q20", "q21", "q22", "q23",
161		"q24", "q25", "q26", "q27", "q28", "q29", "q30", "q31"
162	}
163};
164#define FREGSZ_B	0
165#define FREGSZ_H	1
166#define FREGSZ_S	2
167#define FREGSZ_D	3
168#define FREGSZ_Q	4
169#define FREGNAME(s, n)	(simdregs[(s)][(n) & 31])
170
171static const char *vecregs[32] = {
172	 "v0",  "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7",
173	 "v8",  "v9", "v10", "v11", "v12", "v13", "v14", "v15",
174	"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
175	"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
176};
177#define VREGNAME(n)	vecregs[(n) & 31]
178
179static const char *cregs[16] = {
180	 "C0",  "C1",  "C2",  "C3",  "C4",  "C5",  "C6",  "C7",
181	 "C8",  "C9", "C10", "C11", "C12", "C13", "C14", "C15"
182};
183#define CREGNAME(n)	cregs[(n) & 15]
184
185static const char *conditioncode[16] = {
186	"eq", "ne", "cs", "cc",
187	"mi", "pl", "vs", "vc",
188	"hi", "ls", "ge", "lt",
189	"gt", "le", "al", "nv"
190};
191#define CONDNAME(c)	conditioncode[(c) & 15]
192#define IVCONDNAME(c)	conditioncode[((c) ^ 1) & 15]
193
194static const char *barrierop[16] = {
195	 "#0", "oshld", "oshst", "osh",
196	 "#4", "nshld", "nshst", "nsh",
197	 "#8", "ishld", "ishst", "ish",
198	"#12",    "ld",    "st",  "sy"
199};
200#define BARRIERNAME(op)	barrierop[(op) & 15]
201
202static const char *prefetchop[32] = {
203	"pldl1keep", "pldl1strm", "pldl2keep", "pldl2strm",
204	"pldl3keep", "pldl3strm",        "#6",        "#7",
205	"plil1keep", "plil1strm", "plil2keep", "plil2strm",
206	"plil3keep", "plil3strm",       "#14",       "#15",
207	"pstl1keep", "pstl1strm", "pstl2keep", "pstl2strm",
208	"pstl3keep", "pstl3strm",       "#22",       "#23",
209	      "#24",       "#25",       "#26",       "#27",
210	      "#28",       "#29",       "#30",       "#31"
211};
212#define PREFETCHNAME(op)	prefetchop[(op) & 31]
213
214
215#define SYSREG_ENC(op0, op1, CRn, CRm, op2)		\
216	(((op0)<<19)|((op1)<<16)|((CRn)<<12)|((CRm)<<8)|((op2)<<5))
217
218struct sysreg_table {
219	uint32_t code;
220	const char *regname;
221};
222
223/* must be sorted by code */
224const struct sysreg_table sysreg_table[] = {
225	/*	         op0 op1 CRn CRm op2 name			*/
226	{	SYSREG_ENC(2, 0,  0,  0, 2), "osdtrrx_el1"		},
227	{	SYSREG_ENC(2, 0,  0,  0, 4), "dbgbvr0_el1"		},
228	{	SYSREG_ENC(2, 0,  0,  0, 5), "dbgbcr0_el1"		},
229	{	SYSREG_ENC(2, 0,  0,  0, 6), "dbgwvr0_el1"		},
230	{	SYSREG_ENC(2, 0,  0,  0, 7), "dbgwcr0_el1"		},
231	{	SYSREG_ENC(2, 0,  0,  1, 4), "dbgbvr1_el1"		},
232	{	SYSREG_ENC(2, 0,  0,  1, 5), "dbgbcr1_el1"		},
233	{	SYSREG_ENC(2, 0,  0,  1, 6), "dbgwvr1_el1"		},
234	{	SYSREG_ENC(2, 0,  0,  1, 7), "dbgwcr1_el1"		},
235	{	SYSREG_ENC(2, 0,  0,  2, 0), "mdccint_el1"		},
236	{	SYSREG_ENC(2, 0,  0,  2, 2), "mdscr_el1"		},
237	{	SYSREG_ENC(2, 0,  0,  2, 4), "dbgbvr2_el1"		},
238	{	SYSREG_ENC(2, 0,  0,  2, 5), "dbgbcr2_el1"		},
239	{	SYSREG_ENC(2, 0,  0,  2, 6), "dbgwvr2_el1"		},
240	{	SYSREG_ENC(2, 0,  0,  2, 7), "dbgwcr2_el1"		},
241	{	SYSREG_ENC(2, 0,  0,  3, 2), "osdtrtx_el1"		},
242	{	SYSREG_ENC(2, 0,  0,  3, 4), "dbgbvr3_el1"		},
243	{	SYSREG_ENC(2, 0,  0,  3, 5), "dbgbcr3_el1"		},
244	{	SYSREG_ENC(2, 0,  0,  3, 6), "dbgwvr3_el1"		},
245	{	SYSREG_ENC(2, 0,  0,  3, 7), "dbgwcr3_el1"		},
246	{	SYSREG_ENC(2, 0,  0,  4, 4), "dbgbvr4_el1"		},
247	{	SYSREG_ENC(2, 0,  0,  4, 5), "dbgbcr4_el1"		},
248	{	SYSREG_ENC(2, 0,  0,  4, 6), "dbgwvr4_el1"		},
249	{	SYSREG_ENC(2, 0,  0,  4, 7), "dbgwcr4_el1"		},
250	{	SYSREG_ENC(2, 0,  0,  5, 4), "dbgbvr5_el1"		},
251	{	SYSREG_ENC(2, 0,  0,  5, 5), "dbgbcr5_el1"		},
252	{	SYSREG_ENC(2, 0,  0,  5, 6), "dbgwvr5_el1"		},
253	{	SYSREG_ENC(2, 0,  0,  5, 7), "dbgwcr5_el1"		},
254	{	SYSREG_ENC(2, 0,  0,  6, 2), "oseccr_el1"		},
255	{	SYSREG_ENC(2, 0,  0,  6, 4), "dbgbvr6_el1"		},
256	{	SYSREG_ENC(2, 0,  0,  6, 5), "dbgbcr6_el1"		},
257	{	SYSREG_ENC(2, 0,  0,  6, 6), "dbgwvr6_el1"		},
258	{	SYSREG_ENC(2, 0,  0,  6, 7), "dbgwcr6_el1"		},
259	{	SYSREG_ENC(2, 0,  0,  7, 4), "dbgbvr7_el1"		},
260	{	SYSREG_ENC(2, 0,  0,  7, 5), "dbgbcr7_el1"		},
261	{	SYSREG_ENC(2, 0,  0,  7, 6), "dbgwvr7_el1"		},
262	{	SYSREG_ENC(2, 0,  0,  7, 7), "dbgwcr7_el1"		},
263	{	SYSREG_ENC(2, 0,  0,  8, 4), "dbgbvr8_el1"		},
264	{	SYSREG_ENC(2, 0,  0,  8, 5), "dbgbcr8_el1"		},
265	{	SYSREG_ENC(2, 0,  0,  8, 6), "dbgwvr8_el1"		},
266	{	SYSREG_ENC(2, 0,  0,  8, 7), "dbgwcr8_el1"		},
267	{	SYSREG_ENC(2, 0,  0,  9, 4), "dbgbvr9_el1"		},
268	{	SYSREG_ENC(2, 0,  0,  9, 5), "dbgbcr9_el1"		},
269	{	SYSREG_ENC(2, 0,  0,  9, 6), "dbgwvr9_el1"		},
270	{	SYSREG_ENC(2, 0,  0,  9, 7), "dbgwcr9_el1"		},
271	{	SYSREG_ENC(2, 0,  0, 10, 4), "dbgbvr10_el1"		},
272	{	SYSREG_ENC(2, 0,  0, 10, 5), "dbgbcr10_el1"		},
273	{	SYSREG_ENC(2, 0,  0, 10, 6), "dbgwvr10_el1"		},
274	{	SYSREG_ENC(2, 0,  0, 10, 7), "dbgwcr10_el1"		},
275	{	SYSREG_ENC(2, 0,  0, 11, 4), "dbgbvr11_el1"		},
276	{	SYSREG_ENC(2, 0,  0, 11, 5), "dbgbcr11_el1"		},
277	{	SYSREG_ENC(2, 0,  0, 11, 6), "dbgwvr11_el1"		},
278	{	SYSREG_ENC(2, 0,  0, 11, 7), "dbgwcr11_el1"		},
279	{	SYSREG_ENC(2, 0,  0, 12, 4), "dbgbvr12_el1"		},
280	{	SYSREG_ENC(2, 0,  0, 12, 5), "dbgbcr12_el1"		},
281	{	SYSREG_ENC(2, 0,  0, 12, 6), "dbgwvr12_el1"		},
282	{	SYSREG_ENC(2, 0,  0, 12, 7), "dbgwcr12_el1"		},
283	{	SYSREG_ENC(2, 0,  0, 13, 4), "dbgbvr13_el1"		},
284	{	SYSREG_ENC(2, 0,  0, 13, 5), "dbgbcr13_el1"		},
285	{	SYSREG_ENC(2, 0,  0, 13, 6), "dbgwvr13_el1"		},
286	{	SYSREG_ENC(2, 0,  0, 13, 7), "dbgwcr13_el1"		},
287	{	SYSREG_ENC(2, 0,  0, 14, 4), "dbgbvr14_el1"		},
288	{	SYSREG_ENC(2, 0,  0, 14, 5), "dbgbcr14_el1"		},
289	{	SYSREG_ENC(2, 0,  0, 14, 6), "dbgwvr14_el1"		},
290	{	SYSREG_ENC(2, 0,  0, 14, 7), "dbgwcr14_el1"		},
291	{	SYSREG_ENC(2, 0,  0, 15, 4), "dbgbvr15_el1"		},
292	{	SYSREG_ENC(2, 0,  0, 15, 5), "dbgbcr15_el1"		},
293	{	SYSREG_ENC(2, 0,  0, 15, 6), "dbgwvr15_el1"		},
294	{	SYSREG_ENC(2, 0,  0, 15, 7), "dbgwcr15_el1"		},
295	{	SYSREG_ENC(2, 0,  1,  0, 0), "mdrar_el1"		},
296	{	SYSREG_ENC(2, 0,  1,  0, 4), "oslar_el1"		},
297	{	SYSREG_ENC(2, 0,  1,  1, 4), "oslsr_el1"		},
298	{	SYSREG_ENC(2, 0,  1,  3, 4), "osdlr_el1"		},
299	{	SYSREG_ENC(2, 0,  1,  4, 4), "dbgprcr_el1"		},
300	{	SYSREG_ENC(2, 0,  7,  8, 6), "dbgclaimset_el1"		},
301	{	SYSREG_ENC(2, 0,  7,  9, 6), "dbgclaimclr_el1"		},
302	{	SYSREG_ENC(2, 0,  7, 14, 6), "dbgauthstatus_el1"	},
303	{	SYSREG_ENC(2, 2,  0,  0, 0), "teecr32_el1"		},
304	{	SYSREG_ENC(2, 2,  1,  0, 0), "teehbr32_el1"		},
305	{	SYSREG_ENC(2, 3,  0,  1, 0), "mdccsr_el0"		},
306	{	SYSREG_ENC(2, 3,  0,  4, 0), "dbgdtr_el0"		},
307	{	SYSREG_ENC(2, 3,  0,  5, 0), "dbgdtrrx_el0"		},
308	{	SYSREG_ENC(2, 4,  0,  7, 0), "dbgvcr32_el2"		},
309	{	SYSREG_ENC(3, 0,  0,  0, 0), "midr_el1"			},
310	{	SYSREG_ENC(3, 0,  0,  0, 5), "mpidr_el1"		},
311	{	SYSREG_ENC(3, 0,  0,  0, 6), "revidr_el1"		},
312	{	SYSREG_ENC(3, 0,  0,  1, 0), "id_pfr0_el1"		},
313	{	SYSREG_ENC(3, 0,  0,  1, 1), "id_pfr1_el1"		},
314	{	SYSREG_ENC(3, 0,  0,  1, 2), "id_dfr0_el1"		},
315	{	SYSREG_ENC(3, 0,  0,  1, 3), "id_afr0_el1"		},
316	{	SYSREG_ENC(3, 0,  0,  1, 4), "id_mmfr0_el1"		},
317	{	SYSREG_ENC(3, 0,  0,  1, 5), "id_mmfr1_el1"		},
318	{	SYSREG_ENC(3, 0,  0,  1, 6), "id_mmfr2_el1"		},
319	{	SYSREG_ENC(3, 0,  0,  1, 7), "id_mmfr3_el1"		},
320	{	SYSREG_ENC(3, 0,  0,  2, 0), "id_isar0_el1"		},
321	{	SYSREG_ENC(3, 0,  0,  2, 1), "id_isar1_el1"		},
322	{	SYSREG_ENC(3, 0,  0,  2, 2), "id_isar2_el1"		},
323	{	SYSREG_ENC(3, 0,  0,  2, 3), "id_isar3_el1"		},
324	{	SYSREG_ENC(3, 0,  0,  2, 4), "id_isar4_el1"		},
325	{	SYSREG_ENC(3, 0,  0,  2, 5), "id_isar5_el1"		},
326	{	SYSREG_ENC(3, 0,  0,  2, 6), "id_mmfr4_el1"		},
327	{	SYSREG_ENC(3, 0,  0,  2, 7), "id_isar6_el1"		},
328	{	SYSREG_ENC(3, 0,  0,  3, 0), "mvfr0_el1"		},
329	{	SYSREG_ENC(3, 0,  0,  3, 1), "mvfr1_el1"		},
330	{	SYSREG_ENC(3, 0,  0,  3, 2), "mvfr2_el1"		},
331	{	SYSREG_ENC(3, 0,  0,  3, 4), "id_pfr2_el1"		},
332	{	SYSREG_ENC(3, 0,  0,  3, 5), "id_dfr1_el1"		},
333	{	SYSREG_ENC(3, 0,  0,  3, 6), "id_mmfr5_el1"		},
334	{	SYSREG_ENC(3, 0,  0,  4, 0), "id_aa64pfr0_el1"		},
335	{	SYSREG_ENC(3, 0,  0,  4, 1), "id_aa64pfr1_el1"		},
336	{	SYSREG_ENC(3, 0,  0,  5, 0), "id_aa64dfr0_el1"		},
337	{	SYSREG_ENC(3, 0,  0,  5, 1), "id_aa64dfr1_el1"		},
338	{	SYSREG_ENC(3, 0,  0,  5, 4), "id_aa64afr0_el1"		},
339	{	SYSREG_ENC(3, 0,  0,  5, 5), "id_aa64afr1_el1"		},
340	{	SYSREG_ENC(3, 0,  0,  6, 0), "id_aa64isar0_el1"		},
341	{	SYSREG_ENC(3, 0,  0,  6, 1), "id_aa64isar1_el1"		},
342	{	SYSREG_ENC(3, 0,  0,  7, 0), "id_aa64mmfr0_el1"		},
343	{	SYSREG_ENC(3, 0,  0,  7, 1), "id_aa64mmfr1_el1"		},
344	{	SYSREG_ENC(3, 0,  0,  7, 2), "id_aa64mmfr2_el1"		},
345	{	SYSREG_ENC(3, 0,  1,  0, 0), "sctlr_el1"		},
346	{	SYSREG_ENC(3, 0,  1,  0, 1), "actlr_el1"		},
347	{	SYSREG_ENC(3, 0,  1,  0, 2), "cpacr_el1"		},
348	{	SYSREG_ENC(3, 0,  1,  0, 5), "rgsr_el1"			},
349	{	SYSREG_ENC(3, 0,  1,  0, 6), "gcr_el1"			},
350	{	SYSREG_ENC(3, 0,  2,  0, 0), "ttbr0_el1"		},
351	{	SYSREG_ENC(3, 0,  2,  0, 1), "ttbr1_el1"		},
352	{	SYSREG_ENC(3, 0,  2,  0, 2), "tcr_el1"			},
353	{	SYSREG_ENC(3, 0,  2,  1, 0), "apiakeylo_el1"		},
354	{	SYSREG_ENC(3, 0,  2,  1, 1), "apiakeyhi_el1"		},
355	{	SYSREG_ENC(3, 0,  2,  1, 2), "apibkeylo_el1"		},
356	{	SYSREG_ENC(3, 0,  2,  1, 3), "apibkeyhi_el1"		},
357	{	SYSREG_ENC(3, 0,  2,  2, 0), "apdakeylo_el1"		},
358	{	SYSREG_ENC(3, 0,  2,  2, 1), "apdakeyhi_el1"		},
359	{	SYSREG_ENC(3, 0,  2,  2, 2), "apdbkeylo_el1"		},
360	{	SYSREG_ENC(3, 0,  2,  2, 3), "apdbkeyhi_el1"		},
361	{	SYSREG_ENC(3, 0,  2,  3, 0), "apgakeylo_el1"		},
362	{	SYSREG_ENC(3, 0,  2,  3, 1), "apgakeyhi_el1"		},
363	{	SYSREG_ENC(3, 0,  4,  0, 0), "spsr_el1"			},
364	{	SYSREG_ENC(3, 0,  4,  0, 1), "elr_el1"			},
365	{	SYSREG_ENC(3, 0,  4,  1, 0), "sp_el0"			},
366	{	SYSREG_ENC(3, 0,  4,  2, 0), "spsel"			},
367	{	SYSREG_ENC(3, 0,  4,  2, 2), "currentel"		},
368	{	SYSREG_ENC(3, 0,  4,  2, 3), "pan"			},
369	{	SYSREG_ENC(3, 0,  4,  2, 4), "uao"			},
370	{	SYSREG_ENC(3, 0,  5,  1, 0), "afsr0_el1"		},
371	{	SYSREG_ENC(3, 0,  5,  1, 1), "afsr1_el1"		},
372	{	SYSREG_ENC(3, 0,  5,  2, 0), "esr_el1"			},
373	{	SYSREG_ENC(3, 0,  5,  6, 0), "tfsr_el1"			},
374	{	SYSREG_ENC(3, 0,  5,  6, 1), "tfsre0_el1"		},
375	{	SYSREG_ENC(3, 0,  6,  0, 0), "far_el1"			},
376	{	SYSREG_ENC(3, 0,  7,  4, 0), "par_el1"			},
377	{	SYSREG_ENC(3, 0,  9, 14, 1), "pmintenset_el1"		},
378	{	SYSREG_ENC(3, 0,  9, 14, 2), "pmintenclr_el1"		},
379	{	SYSREG_ENC(3, 0, 10,  2, 0), "mair_el1"			},
380	{	SYSREG_ENC(3, 0, 10,  3, 0), "amair_el1"		},
381	{	SYSREG_ENC(3, 0, 10,  4, 0), "lorsa_el1"		},
382	{	SYSREG_ENC(3, 0, 10,  4, 1), "lorea_el1"		},
383	{	SYSREG_ENC(3, 0, 10,  4, 2), "lorn_el1"			},
384	{	SYSREG_ENC(3, 0, 10,  4, 3), "lorc_el1"			},
385	{	SYSREG_ENC(3, 0, 10,  4, 7), "lorid_el1"		},
386	{	SYSREG_ENC(3, 0, 12,  0, 0), "vbar_el1"			},
387	{	SYSREG_ENC(3, 0, 12,  0, 1), "rvbar_el1"		},
388	{	SYSREG_ENC(3, 0, 12,  0, 2), "rmr_el1"			},
389	{	SYSREG_ENC(3, 0, 12,  1, 0), "isr_el1"			},
390	{	SYSREG_ENC(3, 0, 13,  0, 1), "contextidr_el1"		},
391	{	SYSREG_ENC(3, 0, 13,  0, 4), "tpidr_el1"		},
392	{	SYSREG_ENC(3, 0, 13,  0, 7), "scxtnum_el1"		},
393	{	SYSREG_ENC(3, 0, 14,  1, 0), "cntkctl_el1"		},
394	{	SYSREG_ENC(3, 1,  0,  0, 0), "ccsidr_el1"		},
395	{	SYSREG_ENC(3, 1,  0,  0, 1), "clidr_el1"		},
396	{	SYSREG_ENC(3, 1,  0,  0, 2), "ccsidr2_el1"		},
397	{	SYSREG_ENC(3, 1,  0,  0, 4), "gmid_el1"			},
398	{	SYSREG_ENC(3, 1,  0,  0, 7), "aidr_el1"			},
399	{	SYSREG_ENC(3, 2,  0,  0, 0), "csselr_el1"		},
400	{	SYSREG_ENC(3, 3,  0,  0, 1), "ctr_el0"			},
401	{	SYSREG_ENC(3, 3,  0,  0, 7), "dczid_el0"		},
402	{	SYSREG_ENC(3, 3,  2,  4, 0), "rndr"			},
403	{	SYSREG_ENC(3, 3,  2,  4, 1), "rndrrs"			},
404	{	SYSREG_ENC(3, 3,  4,  2, 0), "nzcv"			},
405	{	SYSREG_ENC(3, 3,  4,  2, 1), "daif"			},
406	{	SYSREG_ENC(3, 3,  4,  2, 5), "dit"			},
407	{	SYSREG_ENC(3, 3,  4,  2, 6), "ssbs"			},
408	{	SYSREG_ENC(3, 3,  4,  2, 7), "tco"			},
409	{	SYSREG_ENC(3, 3,  4,  4, 0), "fpcr"			},
410	{	SYSREG_ENC(3, 3,  4,  4, 1), "fpsr"			},
411	{	SYSREG_ENC(3, 3,  4,  5, 0), "dspsr_el0"		},
412	{	SYSREG_ENC(3, 3,  4,  5, 1), "dlr_el0"			},
413	{	SYSREG_ENC(3, 3,  9, 12, 0), "pmcr_el0"			},
414	{	SYSREG_ENC(3, 3,  9, 12, 1), "pmcntenset_el0"		},
415	{	SYSREG_ENC(3, 3,  9, 12, 2), "pmcntenclr_el0"		},
416	{	SYSREG_ENC(3, 3,  9, 12, 3), "pmovsclr_el0"		},
417	{	SYSREG_ENC(3, 3,  9, 12, 4), "pmswinc_el0"		},
418	{	SYSREG_ENC(3, 3,  9, 12, 5), "pmselr_el0"		},
419	{	SYSREG_ENC(3, 3,  9, 12, 6), "pmceid0_el0"		},
420	{	SYSREG_ENC(3, 3,  9, 12, 7), "pmceid1_el0"		},
421	{	SYSREG_ENC(3, 3,  9, 13, 0), "pmccntr_el0"		},
422	{	SYSREG_ENC(3, 3,  9, 13, 1), "pmxevtyper_el0"		},
423	{	SYSREG_ENC(3, 3,  9, 13, 2), "pmxevcntr_el0"		},
424	{	SYSREG_ENC(3, 3,  9, 14, 0), "pmuserenr_el0"		},
425	{	SYSREG_ENC(3, 3,  9, 14, 3), "pmovsset_el0"		},
426	{	SYSREG_ENC(3, 3, 13,  0, 2), "tpidr_el0"		},
427	{	SYSREG_ENC(3, 3, 13,  0, 3), "tpidrro_el0"		},
428	{	SYSREG_ENC(3, 3, 13,  0, 7), "scxtnum_el0"		},
429	{	SYSREG_ENC(3, 3, 14,  0, 0), "cntfrq_el0"		},
430	{	SYSREG_ENC(3, 3, 14,  0, 1), "cntpct_el0"		},
431	{	SYSREG_ENC(3, 3, 14,  0, 2), "cntvct_el0"		},
432	{	SYSREG_ENC(3, 3, 14,  2, 0), "cntp_tval_el0"		},
433	{	SYSREG_ENC(3, 3, 14,  2, 1), "cntp_ctl_el0"		},
434	{	SYSREG_ENC(3, 3, 14,  2, 2), "cntp_cval_el0"		},
435	{	SYSREG_ENC(3, 3, 14,  3, 0), "cntv_tval_el0"		},
436	{	SYSREG_ENC(3, 3, 14,  3, 1), "cntv_ctl_el0"		},
437	{	SYSREG_ENC(3, 3, 14,  3, 2), "cntv_cval_el0"		},
438	{	SYSREG_ENC(3, 3, 14,  8, 0), "pmevcntr0_el0"		},
439	{	SYSREG_ENC(3, 3, 14,  8, 1), "pmevcntr1_el0"		},
440	{	SYSREG_ENC(3, 3, 14,  8, 2), "pmevcntr2_el0"		},
441	{	SYSREG_ENC(3, 3, 14,  8, 3), "pmevcntr3_el0"		},
442	{	SYSREG_ENC(3, 3, 14,  8, 4), "pmevcntr4_el0"		},
443	{	SYSREG_ENC(3, 3, 14,  8, 5), "pmevcntr5_el0"		},
444	{	SYSREG_ENC(3, 3, 14,  8, 6), "pmevcntr6_el0"		},
445	{	SYSREG_ENC(3, 3, 14,  8, 7), "pmevcntr7_el0"		},
446	{	SYSREG_ENC(3, 3, 14,  9, 0), "pmevcntr8_el0"		},
447	{	SYSREG_ENC(3, 3, 14,  9, 1), "pmevcntr9_el0"		},
448	{	SYSREG_ENC(3, 3, 14,  9, 2), "pmevcntr10_el0"		},
449	{	SYSREG_ENC(3, 3, 14,  9, 3), "pmevcntr11_el0"		},
450	{	SYSREG_ENC(3, 3, 14,  9, 4), "pmevcntr12_el0"		},
451	{	SYSREG_ENC(3, 3, 14,  9, 5), "pmevcntr13_el0"		},
452	{	SYSREG_ENC(3, 3, 14,  9, 6), "pmevcntr14_el0"		},
453	{	SYSREG_ENC(3, 3, 14,  9, 7), "pmevcntr15_el0"		},
454	{	SYSREG_ENC(3, 3, 14, 10, 0), "pmevcntr16_el0"		},
455	{	SYSREG_ENC(3, 3, 14, 10, 1), "pmevcntr17_el0"		},
456	{	SYSREG_ENC(3, 3, 14, 10, 2), "pmevcntr18_el0"		},
457	{	SYSREG_ENC(3, 3, 14, 10, 3), "pmevcntr19_el0"		},
458	{	SYSREG_ENC(3, 3, 14, 10, 4), "pmevcntr20_el0"		},
459	{	SYSREG_ENC(3, 3, 14, 10, 5), "pmevcntr21_el0"		},
460	{	SYSREG_ENC(3, 3, 14, 10, 6), "pmevcntr22_el0"		},
461	{	SYSREG_ENC(3, 3, 14, 10, 7), "pmevcntr23_el0"		},
462	{	SYSREG_ENC(3, 3, 14, 11, 0), "pmevcntr24_el0"		},
463	{	SYSREG_ENC(3, 3, 14, 11, 1), "pmevcntr25_el0"		},
464	{	SYSREG_ENC(3, 3, 14, 11, 2), "pmevcntr26_el0"		},
465	{	SYSREG_ENC(3, 3, 14, 11, 3), "pmevcntr27_el0"		},
466	{	SYSREG_ENC(3, 3, 14, 11, 4), "pmevcntr28_el0"		},
467	{	SYSREG_ENC(3, 3, 14, 11, 5), "pmevcntr29_el0"		},
468	{	SYSREG_ENC(3, 3, 14, 11, 6), "pmevcntr30_el0"		},
469	{	SYSREG_ENC(3, 3, 14, 12, 0), "pmevtyper0_el0"		},
470	{	SYSREG_ENC(3, 3, 14, 12, 1), "pmevtyper1_el0"		},
471	{	SYSREG_ENC(3, 3, 14, 12, 2), "pmevtyper2_el0"		},
472	{	SYSREG_ENC(3, 3, 14, 12, 3), "pmevtyper3_el0"		},
473	{	SYSREG_ENC(3, 3, 14, 12, 4), "pmevtyper4_el0"		},
474	{	SYSREG_ENC(3, 3, 14, 12, 5), "pmevtyper5_el0"		},
475	{	SYSREG_ENC(3, 3, 14, 12, 6), "pmevtyper6_el0"		},
476	{	SYSREG_ENC(3, 3, 14, 12, 7), "pmevtyper7_el0"		},
477	{	SYSREG_ENC(3, 3, 14, 13, 0), "pmevtyper8_el0"		},
478	{	SYSREG_ENC(3, 3, 14, 13, 1), "pmevtyper9_el0"		},
479	{	SYSREG_ENC(3, 3, 14, 13, 2), "pmevtyper10_el0"		},
480	{	SYSREG_ENC(3, 3, 14, 13, 3), "pmevtyper11_el0"		},
481	{	SYSREG_ENC(3, 3, 14, 13, 4), "pmevtyper12_el0"		},
482	{	SYSREG_ENC(3, 3, 14, 13, 5), "pmevtyper13_el0"		},
483	{	SYSREG_ENC(3, 3, 14, 13, 6), "pmevtyper14_el0"		},
484	{	SYSREG_ENC(3, 3, 14, 13, 7), "pmevtyper15_el0"		},
485	{	SYSREG_ENC(3, 3, 14, 14, 0), "pmevtyper16_el0"		},
486	{	SYSREG_ENC(3, 3, 14, 14, 1), "pmevtyper17_el0"		},
487	{	SYSREG_ENC(3, 3, 14, 14, 2), "pmevtyper18_el0"		},
488	{	SYSREG_ENC(3, 3, 14, 14, 3), "pmevtyper19_el0"		},
489	{	SYSREG_ENC(3, 3, 14, 14, 4), "pmevtyper20_el0"		},
490	{	SYSREG_ENC(3, 3, 14, 14, 5), "pmevtyper21_el0"		},
491	{	SYSREG_ENC(3, 3, 14, 14, 6), "pmevtyper22_el0"		},
492	{	SYSREG_ENC(3, 3, 14, 14, 7), "pmevtyper23_el0"		},
493	{	SYSREG_ENC(3, 3, 14, 15, 0), "pmevtyper24_el0"		},
494	{	SYSREG_ENC(3, 3, 14, 15, 1), "pmevtyper25_el0"		},
495	{	SYSREG_ENC(3, 3, 14, 15, 2), "pmevtyper26_el0"		},
496	{	SYSREG_ENC(3, 3, 14, 15, 3), "pmevtyper27_el0"		},
497	{	SYSREG_ENC(3, 3, 14, 15, 4), "pmevtyper28_el0"		},
498	{	SYSREG_ENC(3, 3, 14, 15, 5), "pmevtyper29_el0"		},
499	{	SYSREG_ENC(3, 3, 14, 15, 6), "pmevtyper30_el0"		},
500	{	SYSREG_ENC(3, 3, 14, 15, 7), "pmccfiltr_el0"		},
501	{	SYSREG_ENC(3, 4,  0,  0, 0), "vpidr_el2"		},
502	{	SYSREG_ENC(3, 4,  0,  0, 5), "vmpidr_el2"		},
503	{	SYSREG_ENC(3, 4,  1,  0, 0), "sctlr_el2"		},
504	{	SYSREG_ENC(3, 4,  1,  0, 1), "actlr_el2"		},
505	{	SYSREG_ENC(3, 4,  1,  1, 0), "hcr_el2"			},
506	{	SYSREG_ENC(3, 4,  1,  1, 1), "mdcr_el2"			},
507	{	SYSREG_ENC(3, 4,  1,  1, 2), "cptr_el2"			},
508	{	SYSREG_ENC(3, 4,  1,  1, 3), "hstr_el2"			},
509	{	SYSREG_ENC(3, 4,  1,  1, 4), "hfgrtr_el2"		},
510	{	SYSREG_ENC(3, 4,  1,  1, 5), "hfgwtr_el2"		},
511	{	SYSREG_ENC(3, 4,  1,  1, 6), "hfgitr_el2"		},
512	{	SYSREG_ENC(3, 4,  1,  1, 7), "hacr_el2"			},
513	{	SYSREG_ENC(3, 4,  2,  0, 0), "ttbr0_el2"		},
514	{	SYSREG_ENC(3, 4,  2,  0, 1), "ttbr1_el2"		},
515	{	SYSREG_ENC(3, 4,  2,  0, 2), "tcr_el2"			},
516	{	SYSREG_ENC(3, 4,  2,  1, 0), "vttbr_el2"		},
517	{	SYSREG_ENC(3, 4,  2,  1, 2), "vtcr_el2"			},
518	{	SYSREG_ENC(3, 4,  2,  2, 0), "vncr_el2"			},
519	{	SYSREG_ENC(3, 4,  2,  6, 0), "vsttbr_el2"		},
520	{	SYSREG_ENC(3, 4,  2,  6, 2), "vstcr_el2"		},
521	{	SYSREG_ENC(3, 4,  3,  0, 0), "dacr32_el2"		},
522	{	SYSREG_ENC(3, 4,  3,  1, 4), "hdfgrtr_el2"		},
523	{	SYSREG_ENC(3, 4,  3,  1, 5), "hdfgwtr_el2"		},
524	{	SYSREG_ENC(3, 4,  3,  1, 6), "hafgrtr_el2"		},
525	{	SYSREG_ENC(3, 4,  4,  0, 0), "spsr_el2"			},
526	{	SYSREG_ENC(3, 4,  4,  0, 1), "elr_el2"			},
527	{	SYSREG_ENC(3, 4,  4,  1, 0), "sp_el1"			},
528	{	SYSREG_ENC(3, 4,  4,  3, 0), "spsr_irq"			},
529	{	SYSREG_ENC(3, 4,  4,  3, 1), "spsr_abt"			},
530	{	SYSREG_ENC(3, 4,  4,  3, 2), "spsr_und"			},
531	{	SYSREG_ENC(3, 4,  4,  3, 3), "spsr_fiq"			},
532	{	SYSREG_ENC(3, 4,  5,  0, 1), "ifsr32_el2"		},
533	{	SYSREG_ENC(3, 4,  5,  1, 0), "afsr0_el2"		},
534	{	SYSREG_ENC(3, 4,  5,  1, 1), "afsr1_el2"		},
535	{	SYSREG_ENC(3, 4,  5,  2, 0), "esr_el2"			},
536	{	SYSREG_ENC(3, 4,  5,  3, 0), "fpexc32_el2"		},
537	{	SYSREG_ENC(3, 4,  5,  6, 0), "tfsr_el2"			},
538	{	SYSREG_ENC(3, 4,  6,  0, 0), "far_el2"			},
539	{	SYSREG_ENC(3, 4,  6,  0, 4), "hpfar_el2"		},
540	{	SYSREG_ENC(3, 4, 10,  2, 0), "mair_el2"			},
541	{	SYSREG_ENC(3, 4, 10,  3, 0), "amair_el2"		},
542	{	SYSREG_ENC(3, 4, 12,  0, 0), "vbar_el2"			},
543	{	SYSREG_ENC(3, 4, 12,  0, 1), "rvbar_el2"		},
544	{	SYSREG_ENC(3, 4, 12,  0, 2), "rmr_el2"			},
545	{	SYSREG_ENC(3, 4, 13,  0, 1), "contextidr_el2"		},
546	{	SYSREG_ENC(3, 4, 13,  0, 2), "tpidr_el2"		},
547	{	SYSREG_ENC(3, 4, 13,  0, 7), "scxtnum_el2"		},
548	{	SYSREG_ENC(3, 4, 14,  0, 3), "cntvoff_el2"		},
549	{	SYSREG_ENC(3, 4, 14,  1, 0), "cnthctl_el2"		},
550	{	SYSREG_ENC(3, 4, 14,  2, 0), "cnthp_tval_el2"		},
551	{	SYSREG_ENC(3, 4, 14,  2, 1), "cnthp_ctl_el2"		},
552	{	SYSREG_ENC(3, 4, 14,  2, 2), "cnthp_cval_el2"		},
553	{	SYSREG_ENC(3, 4, 14,  3, 0), "cnthv_tval_el2"		},
554	{	SYSREG_ENC(3, 4, 14,  3, 1), "cnthv_ctl_el2"		},
555	{	SYSREG_ENC(3, 4, 14,  3, 2), "cnthv_cval_el2"		},
556	{	SYSREG_ENC(3, 4, 14,  4, 0), "cnthvs_tval_el2"		},
557	{	SYSREG_ENC(3, 4, 14,  4, 1), "cnthvs_ctl_el2"		},
558	{	SYSREG_ENC(3, 4, 14,  4, 2), "cnthvs_cval_el2"		},
559	{	SYSREG_ENC(3, 4, 14,  5, 0), "cnthps_tval_el2"		},
560	{	SYSREG_ENC(3, 4, 14,  5, 1), "cnthps_ctl_el2"		},
561	{	SYSREG_ENC(3, 4, 14,  5, 2), "cnthps_cval_el2"		},
562	{	SYSREG_ENC(3, 6,  1,  0, 0), "sctlr_el3"		},
563	{	SYSREG_ENC(3, 6,  1,  0, 1), "actlr_el3"		},
564	{	SYSREG_ENC(3, 6,  1,  1, 0), "scr_el3"			},
565	{	SYSREG_ENC(3, 6,  1,  1, 1), "sder32_el3"		},
566	{	SYSREG_ENC(3, 6,  1,  1, 2), "cptr_el3"			},
567	{	SYSREG_ENC(3, 6,  1,  3, 1), "mdcr_el3"			},
568	{	SYSREG_ENC(3, 6,  2,  0, 0), "ttbr0_el3"		},
569	{	SYSREG_ENC(3, 6,  2,  0, 2), "tcr_el3"			},
570	{	SYSREG_ENC(3, 6,  4,  0, 0), "spsr_el3"			},
571	{	SYSREG_ENC(3, 6,  4,  0, 1), "elr_el3"			},
572	{	SYSREG_ENC(3, 6,  4,  1, 0), "sp_el2"			},
573	{	SYSREG_ENC(3, 6,  5,  1, 0), "afsr0_el3"		},
574	{	SYSREG_ENC(3, 6,  5,  1, 1), "afsr1_el3"		},
575	{	SYSREG_ENC(3, 6,  5,  2, 0), "esr_el3"			},
576	{	SYSREG_ENC(3, 6,  5,  6, 0), "tfsr_el3"			},
577	{	SYSREG_ENC(3, 6,  6,  0, 0), "far_el3"			},
578	{	SYSREG_ENC(3, 6, 10,  2, 0), "mair_el3"			},
579	{	SYSREG_ENC(3, 6, 10,  3, 0), "amair_el3"		},
580	{	SYSREG_ENC(3, 6, 12,  0, 0), "vbar_el3"			},
581	{	SYSREG_ENC(3, 6, 12,  0, 1), "rvbar_el3"		},
582	{	SYSREG_ENC(3, 6, 12,  0, 2), "rmr_el3"			},
583	{	SYSREG_ENC(3, 6, 13,  0, 2), "tpidr_el3"		},
584	{	SYSREG_ENC(3, 6, 13,  0, 7), "scxtnum_el3"		},
585	{	SYSREG_ENC(3, 7, 14,  2, 0), "cntps_tval_el1"		},
586	{	SYSREG_ENC(3, 7, 14,  2, 1), "cntps_ctl_el1"		},
587	{	SYSREG_ENC(3, 7, 14,  2, 2), "cntps_cval_el1"		}
588};
589
590static const char *
591sysregname_bsearch(uint32_t code)
592{
593	const struct sysreg_table *base, *p;
594	unsigned int lim;
595	int32_t cmp;
596
597	base = sysreg_table;
598	for (lim = __arraycount(sysreg_table); lim != 0; lim >>= 1) {
599		p = base + (lim >> 1);
600		cmp = code - p->code;
601		if (cmp == 0)
602			return p->regname;
603		if (cmp > 0) {
604			base = p + 1;
605			lim--;
606		}
607	}
608	return NULL;
609}
610
611#define SYSREG_OP_READ	0x01
612#define SYSREG_OP_WRITE	0x02
613
614static const char *
615sysregname(char *buf, size_t buflen, uint32_t rw,
616    uint64_t op0, uint64_t op1, uint64_t CRn, uint64_t CRm, uint64_t op2)
617{
618	const char *name;
619	uint32_t code;
620
621	code = SYSREG_ENC(op0, op1, CRn, CRm, op2);
622
623	/* special case for dbgdtrrx_el0(RO) and dbgdtrtx_el0(WO) */
624	if (code == SYSREG_ENC(2,3,0,5,0)) {
625		if (rw & SYSREG_OP_WRITE)
626			return "dbgdtrtx_el0";
627		return "dbgdtrrx_el0";
628	}
629
630	name = sysregname_bsearch(code);
631	if (name == NULL) {
632#define SYSREGNAMEBUFLEN	sizeof("s99_99_c99_c99_99")
633		snprintf(buf, buflen, "s%u_%u_c%u_c%u_%u",
634		    (u_int)op0, (u_int)op1, (u_int)CRn, (u_int)CRm, (u_int)op2);
635		return buf;
636	}
637	return name;
638}
639#define RSYSREGNAME(buf, buflen, op0, op1, CRn, CRm, op2)		\
640	sysregname(buf, buflen, SYSREG_OP_READ, op0, op1, CRn, CRm, op2)
641#define WSYSREGNAME(buf, buflen, op0, op1, CRn, CRm, op2)		\
642	sysregname(buf, buflen, SYSREG_OP_WRITE, op0, op1, CRn, CRm, op2)
643
644
645static uint64_t
646SignExtend(int bitwidth, uint64_t imm, unsigned int multiply)
647{
648	const uint64_t signbit = ((uint64_t)1 << (bitwidth - 1));
649	const uint64_t immmax = signbit << 1;
650
651	if (imm & signbit)
652		imm -= immmax;
653	return imm * multiply;
654}
655
656static uint64_t
657ZeroExtend(int bitwidth, uint64_t imm, unsigned int multiply)
658{
659	return imm * multiply;
660}
661
662/* rotate right. if n < 0, rotate left. */
663static uint64_t
664rotate(int bitwidth, uint64_t v, int n)
665{
666	uint64_t result;
667
668	n &= (bitwidth - 1);
669	result = (((v << (bitwidth - n)) | (v >> n)));
670	if (bitwidth < 64)
671		result &= ((1ULL << bitwidth) - 1);
672	return result;
673}
674
675static bool
676ValidBitMasks(uint64_t sf, uint64_t n, uint64_t imms, uint64_t immr)
677{
678	int esize, len;
679
680	if ((sf == 0) && (n != 0))
681		return false;
682
683	len = fls64((n << 6) + (~imms & 0x3f)) - 1;
684	if (len < 0)
685		return false;
686
687	esize = (1 << len);
688	imms &= (esize - 1);
689	if (imms == (uint64_t)(esize - 1))
690		return false;
691
692	return true;
693}
694
695static uint64_t
696DecodeBitMasks(uint64_t sf, uint64_t n, uint64_t imms, uint64_t immr)
697{
698	const int bitwidth = (sf == 0) ? 32 : 64;
699	uint64_t result;
700	int esize, len;
701
702	len = fls64((n << 6) + (~imms & 0x3f)) - 1;
703	esize = (1 << len);
704	imms &= (esize - 1);
705	immr &= (esize - 1);
706	result = rotate(esize, (1ULL << (imms + 1)) - 1, immr);
707	while (esize < bitwidth) {
708		result |= (result << esize);
709		esize <<= 1;
710	}
711	if (sf == 0)
712		result &= ((1ULL << bitwidth) - 1);
713	return result;
714}
715
716static bool
717MoveWidePreferred(uint64_t sf, uint64_t n, uint64_t imms, uint64_t immr)
718{
719#if 1
720	uint64_t x = DecodeBitMasks(sf, n, imms, immr);
721
722	if (sf == 0)
723		x &= 0xffffffff;
724	if (((x & 0xffffffffffff0000UL) == 0) ||
725	    ((x & 0xffffffff0000ffffUL) == 0) ||
726	    ((x & 0xffff0000ffffffffUL) == 0) ||
727	    ((x & 0x0000ffffffffffffUL) == 0))
728		return true;
729
730	x = ~x;
731	if (sf == 0)
732		x &= 0xffffffff;
733	if (((x & 0xffffffffffff0000UL) == 0) ||
734	    ((x & 0xffffffff0000ffffUL) == 0) ||
735	    ((x & 0xffff0000ffffffffUL) == 0) ||
736	    ((x & 0x0000ffffffffffffUL) == 0))
737		return true;
738
739	return false;
740#else
741	const int bitwidth = (sf == 0) ? 32 : 64;
742
743	if ((sf != 0) && (n == 0))
744		return false;
745	if ((sf == 0) && ((n != 0) || (immr > 0x1f)))
746		return false;
747	if (imms < 16)
748		return ((-immr & 15) <= (15 - imms));
749	if (imms >= (uint64_t)(bitwidth - 15))
750		return ((immr & 15) <= (imms - (bitwidth - 15)));
751	return false;
752#endif
753}
754
755static bool
756BFXPreferred(uint64_t sf, uint64_t opc, uint64_t imms, uint64_t immr)
757{
758	const uint64_t bitwidth = (sf == 0) ? 32 : 64;
759
760	if (imms < immr)
761		return false;
762	if (imms == (bitwidth - 1))
763		return false;
764	if (immr == 0) {
765		if ((sf == 0) && ((imms == 7) || (imms == 15)))
766			return false;
767		if ((sf != 0) && (opc == 0) &&
768		    ((imms == 7) || (imms == 15) || (imms == 31)))
769			return false;
770	}
771
772	return true;
773}
774
775#define SHIFTOP2(s, op1, op2)					\
776	((const char *[]){ op1, op2 })[(s) & 1]
777#define SHIFTOP4(s, op1, op2, op3, op4)				\
778	((const char *[]){ op1, op2, op3, op4 })[(s) & 3]
779#define SHIFTOP8(s, op1, op2, op3, op4, op5, op6, op7, op8)	\
780	((const char *[]){ op1, op2, op3, op4, op5, op6, op7, op8 })[(s) & 7]
781
782static const char *
783DecodeShift(uint64_t shift)
784{
785	return SHIFTOP4(shift, "lsl", "lsr", "asr", "ror");
786}
787
788#ifdef DISASM_WITH_COMMENT
789#define UNDEFINED(pc, insn, comment)	\
790	PRINTF(".insn\t0x%08x\t# %s\n", insn, comment);
791#else
792#define UNDEFINED(pc, insn, comment)	\
793	PRINTF(".insn\t0x%08x\n", insn);
794#endif
795
796static void
797extendreg_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
798    uint64_t sf, uint64_t Rm, uint64_t option, uint64_t imm3,
799    uint64_t Rn, uint64_t Rd,
800    const char *op, const char *z_op)
801{
802	const int r = (sf == 0) ? 0 : ((option & 3) == 3) ? 1 : 0;
803
804	if ((z_op != NULL) && (Rd == 31)) {
805		PRINTF("%s\t", z_op);
806	} else {
807		PRINTF("%s\t%s, ", op, SREGNAME(sf, Rd));
808	}
809
810	PRINTF("%s, %s", SREGNAME(sf, Rn), ZREGNAME(r, Rm));
811
812	if ((Rd == 31) || (Rn == 31)) {
813		if (imm3 == 0) {
814			if (!((sf == 0) && (option == 2)) &&
815			    !((sf != 0) && (option == 3))) {
816				PRINTF(", %s",
817				    SHIFTOP8(option,
818				    "uxtb", "uxth", "uxtw", "uxtx",
819				    "sxtb", "sxth", "sxtw", "sxtx"));
820			}
821		} else {
822			PRINTF(", %s #%u",
823			    SHIFTOP8(option,
824			    "uxtb", "uxth", "lsl", "lsl",
825			    "sxtb", "sxth", "sxtw", "sxtx"),
826			    (u_int)imm3);
827		}
828	} else {
829		PRINTF(", %s",
830		    SHIFTOP8(option,
831		    "uxtb", "uxth", "uxtw", "uxtx",
832		    "sxtb", "sxth", "sxtw", "sxtx"));
833		if (imm3 != 0)
834			PRINTF(" #%u", (u_int)imm3);
835	}
836	PRINTF("\n");
837}
838
839static void
840shiftreg_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
841    uint64_t sf, uint64_t shift, uint64_t Rm, uint64_t imm6,
842    uint64_t Rn, uint64_t Rd,
843    const char *dnm_op, const char *dzm_op, const char *znm_op)
844{
845	if ((sf == 0) && (imm6 >= 32)) {
846		UNDEFINED(pc, insn, "illegal imm6");
847		return;
848	}
849
850	if ((dzm_op != NULL) && (Rn == 31)) {
851		PRINTF("%s\t%s, %s",
852		    dzm_op,
853		    ZREGNAME(sf, Rd),
854		    ZREGNAME(sf, Rm));
855	} else if ((znm_op != NULL) && (Rd == 31)) {
856		PRINTF("%s\t%s, %s",
857		    znm_op,
858		    ZREGNAME(sf, Rn),
859		    ZREGNAME(sf, Rm));
860	} else {
861		PRINTF("%s\t%s, %s, %s",
862		    dnm_op,
863		    ZREGNAME(sf, Rd),
864		    ZREGNAME(sf, Rn),
865		    ZREGNAME(sf, Rm));
866	}
867	if (imm6 != 0)
868		PRINTF(", %s #%u", DecodeShift(shift), (u_int)imm6);
869	PRINTF("\n");
870}
871
872static inline int
873regoffset_option_to_r(uint64_t option)
874{
875	switch (option) {
876	case 2:
877	case 6:
878		return 0;
879	case 3:
880	case 7:
881		return 1;
882	default:
883		return -1;
884	}
885}
886
887static void
888regoffset_b_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
889    uint64_t Rm, uint64_t option, uint64_t shift, uint64_t Rn, uint64_t Rt,
890    const char *op)
891{
892	int r;
893
894	if ((r = regoffset_option_to_r(option)) < 0) {
895		UNDEFINED(pc, insn, "illegal option");
896		return;
897	}
898
899	if (shift == 0) {
900		PRINTF("%s\t%s, [%s,%s%s]\n",
901		    op,
902		    ZREGNAME(0, Rt),
903		    SREGNAME(1, Rn),
904		    ZREGNAME(r, Rm),
905		    SHIFTOP8(option,
906		        "", "", ",uxtw", "", "", "", ",sxtw", ",sxtx"));
907	} else {
908		PRINTF("%s\t%s, [%s,%s,%s #%d]\n",
909		    op,
910		    ZREGNAME(0, Rt),
911		    SREGNAME(1, Rn),
912		    ZREGNAME(r, Rm),
913		    SHIFTOP8(option,
914		        "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"),
915		    0);
916	}
917}
918
919static void
920regoffset_h_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
921    uint64_t Rm, uint64_t option, uint64_t shift, uint64_t Rn, uint64_t Rt,
922    uint64_t RtSz, const char *op)
923{
924	int r;
925
926	if ((r = regoffset_option_to_r(option)) < 0) {
927		UNDEFINED(pc, insn, "illegal option");
928		return;
929	}
930
931	if ((shift == 0) && (option == 3)) {
932		PRINTF("%s\t%s, [%s,%s]\n",
933		    op,
934		    ZREGNAME(RtSz, Rt),
935		    SREGNAME(1, Rn),
936		    ZREGNAME(r, Rm));
937	} else if (shift == 0) {
938		PRINTF("%s\t%s, [%s,%s,%s]\n",
939		    op,
940		    ZREGNAME(RtSz, Rt),
941		    SREGNAME(1, Rn),
942		    ZREGNAME(r, Rm),
943		    SHIFTOP8(option,
944		        "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"));
945	} else {
946		PRINTF("%s\t%s, [%s,%s,%s #%u]\n",
947		    op,
948		    ZREGNAME(RtSz, Rt),
949		    SREGNAME(1, Rn),
950		    ZREGNAME(r, Rm),
951		    SHIFTOP8(option,
952		        "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"),
953		    (u_int)shift);
954	}
955}
956
957static void
958regoffset_w_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
959    uint64_t Rm, uint64_t option, uint64_t shift, uint64_t Rn, uint64_t Rt,
960    const char *op)
961{
962	int r;
963
964	if ((r = regoffset_option_to_r(option)) < 0) {
965		UNDEFINED(pc, insn, "illegal option");
966		return;
967	}
968
969	if ((shift == 0) && (option == 3)) {
970		PRINTF("%s\t%s, [%s,%s]\n",
971		    op,
972		    ZREGNAME(1, Rt),
973		    SREGNAME(1, Rn),
974		    ZREGNAME(r, Rm));
975	} else if (shift == 0) {
976		PRINTF("%s\t%s, [%s,%s,%s]\n",
977		    op,
978		    ZREGNAME(1, Rt),
979		    SREGNAME(1, Rn),
980		    ZREGNAME(r, Rm),
981		    SHIFTOP8(option,
982		        "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"));
983	} else {
984		PRINTF("%s\t%s, [%s,%s,%s #%u]\n",
985		    op,
986		    ZREGNAME(1, Rt),
987		    SREGNAME(1, Rn),
988		    ZREGNAME(r, Rm),
989		    SHIFTOP8(option,
990		        "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"),
991		    (u_int)shift * 2);
992	}
993}
994
995static void
996regoffset_x_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
997    uint64_t size, uint64_t Rm, uint64_t option, uint64_t shift,
998    uint64_t Rn, uint64_t Rt,
999    const char *op)
1000{
1001	int r;
1002
1003	if ((r = regoffset_option_to_r(option)) < 0) {
1004		UNDEFINED(pc, insn, "illegal option");
1005		return;
1006	}
1007
1008	if (shift == 0) {
1009		PRINTF("%s\t%s, [%s,%s%s]\n",
1010		    op,
1011		    ZREGNAME(size, Rt),
1012		    SREGNAME(1, Rn),
1013		    ZREGNAME(r, Rm),
1014		    SHIFTOP8(option,
1015		        "", "", ",uxtw", "", "", "", ",sxtw", ",sxtx"));
1016	} else {
1017		uint64_t amount = 2 + size;
1018		PRINTF("%s\t%s, [%s,%s,%s #%u]\n",
1019		    op,
1020		    ZREGNAME(size, Rt),
1021		    SREGNAME(1, Rn),
1022		    ZREGNAME(r, Rm),
1023		    SHIFTOP8(option,
1024		        "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"),
1025		    (u_int)amount);
1026	}
1027}
1028
1029static void
1030addsub_imm_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
1031    uint64_t sf, uint64_t shift, uint64_t imm12, uint64_t Rn, uint64_t Rd,
1032    const char *op, const char *zop)
1033{
1034	if (shift & 2) {
1035		UNDEFINED(pc, insn, "illegal shift");
1036		return;
1037	}
1038
1039	if (Rd == 31) {
1040		PRINTF("%s\t%s, #0x%"PRIx64"%s\n",
1041		    zop,
1042		    SREGNAME(sf, Rn),
1043		    ZeroExtend(12, imm12, 1),
1044		    SHIFTOP4(shift, "", ", lsl #12", "", ""));
1045	} else {
1046		PRINTF("%s\t%s, %s, #0x%"PRIx64"%s\n",
1047		    op,
1048		    ZREGNAME(sf, Rd),
1049		    SREGNAME(sf, Rn),
1050		    ZeroExtend(12, imm12, 1),
1051		    SHIFTOP4(shift, "", ", lsl #12", "", ""));
1052	}
1053}
1054
1055static void
1056csetsel_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
1057    uint64_t sf, uint64_t Rm, uint64_t cond, uint64_t Rn, uint64_t Rd,
1058    const char *op, const char *op2, const char *op3)
1059{
1060	if ((Rn == Rm) && (Rn != 31) && ((cond & 0xe) != 0x0e)) {
1061		PRINTF("%s\t%s, %s, %s\n",
1062		    op3,
1063		    ZREGNAME(sf, Rd),
1064		    ZREGNAME(sf, Rn),
1065		    IVCONDNAME(cond));
1066	} else if ((Rn == Rm) && (Rn == 31) && ((cond & 0xe) != 0x0e)) {
1067		PRINTF("%s\t%s, %s\n",
1068		    op2,
1069		    ZREGNAME(sf, Rd),
1070		    IVCONDNAME(cond));
1071	} else {
1072		PRINTF("%s\t%s, %s, %s, %s\n",
1073		    op,
1074		    ZREGNAME(sf, Rd),
1075		    ZREGNAME(sf, Rn),
1076		    ZREGNAME(sf, Rm),
1077		    CONDNAME(cond));
1078	}
1079}
1080
1081OP0FUNC(op_undefined)
1082{
1083	UNDEFINED(pc, insn, "undefined");
1084}
1085
1086OP4FUNC(op_adc, sf, Rm, Rn, Rd)
1087{
1088	PRINTF("adc\t%s, %s, %s\n",
1089	    ZREGNAME(sf, Rd),
1090	    ZREGNAME(sf, Rn),
1091	    ZREGNAME(sf, Rm));
1092}
1093
1094OP4FUNC(op_adcs, sf, Rm, Rn, Rd)
1095{
1096	PRINTF("adcs\t%s, %s, %s\n",
1097	    ZREGNAME(sf, Rd),
1098	    ZREGNAME(sf, Rn),
1099	    ZREGNAME(sf, Rm));
1100}
1101
1102OP6FUNC(op_add_extreg, sf, Rm, option, imm3, Rn, Rd)
1103{
1104	extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd,
1105	    "add", NULL);
1106}
1107
1108OP5FUNC(op_add_imm, sf, shift, imm12, Rn, Rd)
1109{
1110	if (shift & 2) {
1111		UNDEFINED(pc, insn, "illegal shift");
1112		return;
1113	}
1114
1115	/* ALIAS: mov_tofromsp */
1116	if ((Rd == 31 || Rn == 31) && (imm12 == 0)) {
1117		PRINTF("mov\t%s, %s\n",
1118		    SREGNAME(sf, Rd),
1119		    SREGNAME(sf, Rn));
1120	} else {
1121		PRINTF("add\t%s, %s, #0x%"PRIx64"%s\n",
1122		    SREGNAME(sf, Rd),
1123		    SREGNAME(sf, Rn),
1124		    ZeroExtend(12, imm12, 1),
1125		    SHIFTOP2(shift, "", ", lsl #12"));
1126	}
1127}
1128
1129OP6FUNC(op_add_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
1130{
1131	if (shift == 3) {
1132		UNDEFINED(pc, insn, "illegal shift");
1133		return;
1134	}
1135	shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
1136	    "add", NULL, NULL);
1137}
1138
1139OP6FUNC(op_adds_extreg, sf, Rm, option, imm3, Rn, Rd)
1140{
1141	/* ALIAS: cmn_extreg */
1142	extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd,
1143	    "adds", "cmn");
1144}
1145
1146OP5FUNC(op_adds_imm, sf, shift, imm12, Rn, Rd)
1147{
1148	/* ALIAS: cmn_imm */
1149	addsub_imm_common(di, pc, insn, sf, shift, imm12, Rn, Rd,
1150	    "adds", "cmn");
1151}
1152
1153OP6FUNC(op_adds_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
1154{
1155	if (shift == 3) {
1156		UNDEFINED(pc, insn, "illegal shift");
1157		return;
1158	}
1159	/* ALIAS: cmn_shiftreg */
1160	shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
1161	    "adds", NULL, "cmn");
1162}
1163
1164OP3FUNC(op_adr, immlo, immhi, Rd)
1165{
1166	uint64_t imm = ((immhi << 2) | immlo);
1167
1168	PRINTF("adr\t%s, ", ZREGNAME(1, Rd));
1169	PRINTADDR(SignExtend(21, imm, 1) + pc);
1170	PRINTF("\n");
1171}
1172
1173OP3FUNC(op_adrp, immlo, immhi, Rd)
1174{
1175	uint64_t imm = ((immhi << 2) | immlo);
1176
1177	PRINTF("adrp\t%s, ", ZREGNAME(1, Rd));
1178	PRINTADDR(SignExtend(21, imm, 4096) + (pc & -4096));
1179	PRINTF("\n");
1180}
1181
1182OP6FUNC(op_and_imm, sf, n, immr, imms, Rn, Rd)
1183{
1184	if (!ValidBitMasks(sf, n, imms, immr)) {
1185		UNDEFINED(pc, insn, "illegal bitmasks");
1186		return;
1187	}
1188
1189	PRINTF("and\t%s, %s, #0x%"PRIx64"\n",
1190	    ZREGNAME(sf, Rd),
1191	    ZREGNAME(sf, Rn),
1192	    DecodeBitMasks(sf, n, imms, immr));
1193}
1194
1195OP6FUNC(op_and_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
1196{
1197	shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
1198	    "and", NULL, NULL);
1199}
1200
1201OP6FUNC(op_ands_imm, sf, n, immr, imms, Rn, Rd)
1202{
1203	if (!ValidBitMasks(sf, n, imms, immr)) {
1204		UNDEFINED(pc, insn, "illegal bitmasks");
1205		return;
1206	}
1207
1208	/* ALIAS: tst_imm */
1209	if (Rd == 31) {
1210		PRINTF("tst\t%s, #0x%"PRIx64"\n",
1211		    ZREGNAME(sf, Rn),
1212		    DecodeBitMasks(sf, n, imms, immr));
1213	} else {
1214		PRINTF("ands\t%s, %s, #0x%"PRIx64"\n",
1215		    ZREGNAME(sf, Rd),
1216		    ZREGNAME(sf, Rn),
1217		    DecodeBitMasks(sf, n, imms, immr));
1218	}
1219}
1220
1221OP6FUNC(op_ands_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
1222{
1223	/* ALIAS: tst_shiftreg */
1224	shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
1225	    "ands", NULL, "tst");
1226}
1227
1228OP6FUNC(op_sbfm, sf, n, immr, imms, Rn, Rd)
1229{
1230	const uint64_t bitwidth = (sf == 0) ? 32 : 64;
1231
1232	/* ALIAS: asr_imm,sbfiz,sbfx,sxtb,sxth,sxtw */
1233	if ((imms != (bitwidth - 1)) && ((imms + 1) == immr)) {
1234		PRINTF("asr\t%s, %s, #%"PRIu64"\n",
1235		    ZREGNAME(sf, Rd),
1236		    ZREGNAME(sf, Rn),
1237		    bitwidth - immr);
1238	} else if (imms == (bitwidth - 1)) {
1239		PRINTF("asr\t%s, %s, #%"PRIu64"\n",
1240		    ZREGNAME(sf, Rd),
1241		    ZREGNAME(sf, Rn),
1242		    immr);
1243	} else if (imms < immr) {
1244		PRINTF("sbfiz\t%s, %s, #%"PRIu64", #%"PRIu64"\n",
1245		    ZREGNAME(sf, Rd),
1246		    ZREGNAME(sf, Rn),
1247		    (bitwidth - immr) & (bitwidth - 1),
1248		    (imms + 1) & (bitwidth - 1));
1249	} else if (BFXPreferred(sf, 0, imms, immr)) {
1250		PRINTF("sbfx\t%s, %s, #%"PRIu64", #%"PRIu64"\n",
1251		    ZREGNAME(sf, Rd),
1252		    ZREGNAME(sf, Rn),
1253		    immr,
1254		    (imms - immr + 1) & (bitwidth - 1));
1255	} else if ((immr == 0) && (imms == 7)) {
1256		PRINTF("sxtb\t%s, %s\n",
1257		    ZREGNAME(sf, Rd),
1258		    ZREGNAME(0, Rn));
1259	} else if ((immr == 0) && (imms == 15)) {
1260		PRINTF("sxth\t%s, %s\n",
1261		    ZREGNAME(sf, Rd),
1262		    ZREGNAME(0, Rn));
1263	} else if ((immr == 0) && (imms == 31)) {
1264		PRINTF("sxtw\t%s, %s\n",
1265		    ZREGNAME(sf, Rd),
1266		    ZREGNAME(0, Rn));
1267	} else {
1268		UNDEFINED(pc, insn, "undefined");
1269	}
1270}
1271
1272OP4FUNC(op_asr_reg, sf, Rm, Rn, Rd)
1273{
1274	/* ALIAS: asrv */
1275	/* "asr" always the preferred disassembly */
1276	PRINTF("asr\t%s, %s, %s\n",
1277	    ZREGNAME(sf, Rd),
1278	    ZREGNAME(sf, Rn),
1279	    ZREGNAME(sf, Rm));
1280}
1281
1282struct op_sys_table {
1283	uint32_t code;
1284	int flags;
1285#define OPE_NONE	0x00000000
1286#define OPE_XT		0x00000001
1287	const char *opname;
1288};
1289
1290static struct op_sys_table op_sys_table[] = {
1291	{ SYSREG_ENC(1, 0, 7,  1, 0), OPE_NONE,	"ic\tialluis"		},
1292	{ SYSREG_ENC(1, 0, 7,  5, 0), OPE_NONE,	"ic\tiallu"		},
1293	{ SYSREG_ENC(1, 3, 7,  5, 1), OPE_XT,	"ic\tivau"		},
1294	{ SYSREG_ENC(1, 0, 7,  6, 1), OPE_XT,	"dc\tivac"		},
1295	{ SYSREG_ENC(1, 0, 7,  6, 2), OPE_XT,	"dc\tisw"		},
1296	{ SYSREG_ENC(1, 0, 7, 10, 2), OPE_XT,	"dc\tcsw"		},
1297	{ SYSREG_ENC(1, 0, 7, 14, 2), OPE_XT,	"dc\tcisw"		},
1298	{ SYSREG_ENC(1, 3, 7, 10, 1), OPE_XT,	"dc\tcvac"		},
1299	{ SYSREG_ENC(1, 3, 7, 11, 1), OPE_XT,	"dc\tcvau"		},
1300	{ SYSREG_ENC(1, 3, 7, 14, 1), OPE_XT,	"dc\tcivac"		},
1301	{ SYSREG_ENC(1, 3, 7,  4, 1), OPE_XT,	"dc\tzva"		},
1302	{ SYSREG_ENC(1, 0, 7,  6, 3), OPE_XT,	"dc\tigvac"		},
1303	{ SYSREG_ENC(1, 0, 7,  6, 4), OPE_XT,	"dc\tigsw"		},
1304	{ SYSREG_ENC(1, 0, 7,  6, 5), OPE_XT,	"dc\tigdvac"		},
1305	{ SYSREG_ENC(1, 0, 7,  6, 6), OPE_XT,	"dc\tigdsw"		},
1306	{ SYSREG_ENC(1, 0, 7, 10, 4), OPE_XT,	"dc\tcgsw"		},
1307	{ SYSREG_ENC(1, 0, 7, 10, 6), OPE_XT,	"dc\tcgdsw"		},
1308	{ SYSREG_ENC(1, 0, 7, 14, 4), OPE_XT,	"dc\tcigsw"		},
1309	{ SYSREG_ENC(1, 0, 7, 14, 6), OPE_XT,	"dc\tcigdsw"		},
1310	{ SYSREG_ENC(1, 3, 7,  4, 3), OPE_XT,	"dc\tgva"		},
1311	{ SYSREG_ENC(1, 3, 7,  4, 4), OPE_XT,	"dc\tgzva"		},
1312	{ SYSREG_ENC(1, 3, 7, 10, 3), OPE_XT,	"dc\tcgvac"		},
1313	{ SYSREG_ENC(1, 3, 7, 10, 5), OPE_XT,	"dc\tcgdvac"		},
1314	{ SYSREG_ENC(1, 3, 7, 12, 3), OPE_XT,	"dc\tcgvap"		},
1315	{ SYSREG_ENC(1, 3, 7, 12, 5), OPE_XT,	"dc\tcgdvap"		},
1316	{ SYSREG_ENC(1, 3, 7, 13, 3), OPE_XT,	"dc\tcgvadp"		},
1317	{ SYSREG_ENC(1, 3, 7, 13, 5), OPE_XT,	"dc\tcgdvadp"		},
1318	{ SYSREG_ENC(1, 3, 7, 14, 3), OPE_XT,	"dc\tcigvac"		},
1319	{ SYSREG_ENC(1, 3, 7, 14, 5), OPE_XT,	"dc\tcigdvac"		},
1320	{ SYSREG_ENC(1, 3, 7, 12, 1), OPE_XT,	"dc\tcvap"		},
1321	{ SYSREG_ENC(1, 3, 7, 13, 1), OPE_XT,	"dc\tcvadp"		},
1322
1323	{ SYSREG_ENC(1, 0, 7,  8, 0), OPE_XT,	"at\ts1e1r"		},
1324	{ SYSREG_ENC(1, 0, 7,  8, 1), OPE_XT,	"at\ts1e1w"		},
1325	{ SYSREG_ENC(1, 0, 7,  8, 2), OPE_XT,	"at\ts1e0r"		},
1326	{ SYSREG_ENC(1, 0, 7,  8, 3), OPE_XT,	"at\ts1e0w"		},
1327	{ SYSREG_ENC(1, 0, 7,  9, 0), OPE_XT,	"at\ts1e1rp"		},
1328	{ SYSREG_ENC(1, 0, 7,  9, 1), OPE_XT,	"at\ts1e1wp"		},
1329	{ SYSREG_ENC(1, 4, 7,  8, 0), OPE_XT,	"at\ts1e2r"		},
1330	{ SYSREG_ENC(1, 4, 7,  8, 1), OPE_XT,	"at\ts1e2w"		},
1331	{ SYSREG_ENC(1, 4, 7,  8, 4), OPE_XT,	"at\ts12e1r"		},
1332	{ SYSREG_ENC(1, 4, 7,  8, 5), OPE_XT,	"at\ts12e1w"		},
1333	{ SYSREG_ENC(1, 4, 7,  8, 6), OPE_XT,	"at\ts12e0r"		},
1334	{ SYSREG_ENC(1, 4, 7,  8, 7), OPE_XT,	"at\ts12e0w"		},
1335	{ SYSREG_ENC(1, 6, 7,  8, 0), OPE_XT,	"at\ts1e3r"		},
1336	{ SYSREG_ENC(1, 6, 7,  8, 1), OPE_XT,	"at\ts1e3w"		},
1337
1338	{ SYSREG_ENC(1, 3, 7,  3, 4), OPE_XT,	"cfp\trctx"		},
1339	{ SYSREG_ENC(1, 3, 7,  3, 5), OPE_XT,	"dvp\trctx"		},
1340	{ SYSREG_ENC(1, 3, 7,  3, 7), OPE_XT,	"cpp\trctx"		},
1341
1342	{ SYSREG_ENC(1, 0, 8,  3, 0), OPE_NONE,	"tlbi\tvmalle1is"	},
1343	{ SYSREG_ENC(1, 0, 8,  3, 1), OPE_XT,	"tlbi\tvae1is"		},
1344	{ SYSREG_ENC(1, 0, 8,  3, 2), OPE_XT,	"tlbi\taside1is"	},
1345	{ SYSREG_ENC(1, 0, 8,  3, 3), OPE_XT,	"tlbi\tvaae1is"		},
1346	{ SYSREG_ENC(1, 0, 8,  3, 5), OPE_XT,	"tlbi\tvale1is"		},
1347	{ SYSREG_ENC(1, 0, 8,  3, 7), OPE_XT,	"tlbi\tvaale1is"	},
1348	{ SYSREG_ENC(1, 0, 8,  7, 0), OPE_NONE,	"tlbi\tvmalle1"		},
1349	{ SYSREG_ENC(1, 0, 8,  7, 1), OPE_XT,	"tlbi\tvae1"		},
1350	{ SYSREG_ENC(1, 0, 8,  7, 2), OPE_XT,	"tlbi\taside1"		},
1351	{ SYSREG_ENC(1, 0, 8,  7, 3), OPE_XT,	"tlbi\tvaae1"		},
1352	{ SYSREG_ENC(1, 0, 8,  7, 5), OPE_XT,	"tlbi\tvale1"		},
1353	{ SYSREG_ENC(1, 0, 8,  7, 7), OPE_XT,	"tlbi\tvaale1"		},
1354	{ SYSREG_ENC(1, 4, 8,  0, 1), OPE_XT,	"tlbi\tipas2e1is"	},
1355	{ SYSREG_ENC(1, 4, 8,  0, 5), OPE_XT,	"tlbi\tipas2le1is"	},
1356	{ SYSREG_ENC(1, 4, 8,  3, 0), OPE_NONE,	"tlbi\talle2is"		},
1357	{ SYSREG_ENC(1, 4, 8,  3, 1), OPE_XT,	"tlbi\tvae2is"		},
1358	{ SYSREG_ENC(1, 4, 8,  3, 4), OPE_NONE,	"tlbi\talle1is"		},
1359	{ SYSREG_ENC(1, 4, 8,  3, 5), OPE_XT,	"tlbi\tvale2is"		},
1360	{ SYSREG_ENC(1, 4, 8,  3, 6), OPE_NONE,	"tlbi\tvmalls12e1is"	},
1361	{ SYSREG_ENC(1, 4, 8,  4, 1), OPE_XT,	"tlbi\tipas2e1"		},
1362	{ SYSREG_ENC(1, 4, 8,  4, 5), OPE_XT,	"tlbi\tipas2le1"	},
1363	{ SYSREG_ENC(1, 4, 8,  7, 0), OPE_NONE,	"tlbi\talle2"		},
1364	{ SYSREG_ENC(1, 4, 8,  7, 1), OPE_XT,	"tlbi\tvae2"		},
1365	{ SYSREG_ENC(1, 4, 8,  7, 4), OPE_NONE,	"tlbi\talle1"		},
1366	{ SYSREG_ENC(1, 4, 8,  7, 5), OPE_XT,	"tlbi\tvale2"		},
1367	{ SYSREG_ENC(1, 4, 8,  7, 6), OPE_NONE,	"tlbi\tvmalls12e1"	},
1368	{ SYSREG_ENC(1, 6, 8,  3, 0), OPE_NONE,	"tlbi\talle3is"		},
1369	{ SYSREG_ENC(1, 6, 8,  3, 1), OPE_XT,	"tlbi\tvae3is"		},
1370	{ SYSREG_ENC(1, 6, 8,  3, 5), OPE_XT,	"tlbi\tvale3is"		},
1371	{ SYSREG_ENC(1, 6, 8,  7, 0), OPE_NONE,	"tlbi\talle3"		},
1372	{ SYSREG_ENC(1, 6, 8,  7, 1), OPE_XT,	"tlbi\tvae3"		},
1373	{ SYSREG_ENC(1, 6, 8,  7, 5), OPE_XT,	"tlbi\tvale3"		}
1374};
1375
1376OP5FUNC(op_sys, op1, CRn, CRm, op2, Rt)
1377{
1378	uint32_t code;
1379	size_t i;
1380
1381	/* ALIAS: at,dc,ic,sys,tlbi */
1382	code = SYSREG_ENC(1, op1, CRn, CRm, op2);
1383	for (i = 0; i < __arraycount(op_sys_table); i++) {
1384		if (op_sys_table[i].code != code)
1385			continue;
1386
1387		if (((op_sys_table[i].flags & OPE_XT) != 0) || (Rt != 31)) {
1388			PRINTF("%s, %s\n",
1389			    op_sys_table[i].opname,
1390			    ZREGNAME(1, Rt));
1391		} else {
1392			PRINTF("%s\n",
1393			    op_sys_table[i].opname);
1394		}
1395		return;
1396	}
1397
1398	/* default, sys instruction */
1399	PRINTF("sys\t#%"PRIu64", %s, %s, #%"PRIu64", %s\n",
1400	    op1,
1401	    CREGNAME(CRn),
1402	    CREGNAME(CRm),
1403	    op2,
1404	    ZREGNAME(1,Rt));
1405}
1406
1407OP1FUNC(op_b, imm26)
1408{
1409	PRINTF("b\t");
1410	PRINTADDR(SignExtend(26, imm26, 4) + pc);
1411	PRINTF("\n");
1412}
1413
1414OP2FUNC(op_b_cond, imm19, cond)
1415{
1416	PRINTF("b.%s\t", CONDNAME(cond));
1417	PRINTADDR(SignExtend(19, imm19, 4) + pc);
1418	PRINTF("\n");
1419}
1420
1421OP6FUNC(op_bfi, sf, n, immr, imms, Rn, Rd)
1422{
1423	const uint64_t bitwidth = (sf == 0) ? 32 : 64;
1424
1425	/* ALIAS: bfm,bfxil */
1426	/* it is not disassembled as bfm */
1427
1428	/* XXX: if Rn=31, should be used "bfc"? (armv8.2) */
1429	if (imms < immr) {
1430		PRINTF("bfi\t%s, %s, #%"PRIu64", #%"PRIu64"\n",
1431		    ZREGNAME(sf, Rd),
1432		    ZREGNAME(sf, Rn),
1433		    (bitwidth - immr) & (bitwidth - 1),
1434		    (imms + 1) & (bitwidth - 1));
1435	} else {
1436		PRINTF("bfxil\t%s, %s, #%"PRIu64", #%"PRIu64"\n",
1437		    ZREGNAME(sf, Rd),
1438		    ZREGNAME(sf, Rn),
1439		    immr,
1440		    (imms -immr + 1) & (bitwidth - 1));
1441	}
1442}
1443
1444OP6FUNC(op_bic_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
1445{
1446	shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
1447	    "bic", NULL, NULL);
1448}
1449
1450OP6FUNC(op_bics_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
1451{
1452	shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
1453	    "bics", NULL, NULL);
1454}
1455
1456OP1FUNC(op_bl, imm26)
1457{
1458	PRINTF("bl\t");
1459	PRINTADDR(SignExtend(26, imm26, 4) + pc);
1460	PRINTF("\n");
1461}
1462
1463OP1FUNC(op_blr, Rn)
1464{
1465	PRINTF("blr\t%s\n", ZREGNAME(1, Rn));
1466}
1467
1468OP1FUNC(op_br, Rn)
1469{
1470	PRINTF("br\t%s\n", ZREGNAME(1, Rn));
1471}
1472
1473OP1FUNC(op_brk, imm16)
1474{
1475	PRINTF("brk\t#0x%"PRIx64"\n", imm16);
1476}
1477
1478OP3FUNC(op_cbnz, sf, imm19, Rt)
1479{
1480	PRINTF("cbnz\t%s, ", ZREGNAME(sf, Rt));
1481	PRINTADDR(SignExtend(19, imm19, 4) + pc);
1482	PRINTF("\n");
1483}
1484
1485OP3FUNC(op_cbz, sf, imm19, Rt)
1486{
1487	PRINTF("cbz\t%s, ", ZREGNAME(sf, Rt));
1488	PRINTADDR(SignExtend(19, imm19, 4) + pc);
1489	PRINTF("\n");
1490}
1491
1492OP5FUNC(op_ccmn_imm, sf, imm5, cond, Rn, nzcv)
1493{
1494	PRINTF("ccmn\t%s, #0x%"PRIx64", #0x%"PRIx64", %s\n",
1495	    ZREGNAME(sf, Rn),
1496	    imm5,
1497	    nzcv,
1498	    CONDNAME(cond));
1499}
1500
1501OP5FUNC(op_ccmn_reg, sf, Rm, cond, Rn, nzcv)
1502{
1503	PRINTF("ccmn\t%s, %s, #0x%"PRIx64", %s\n",
1504	    ZREGNAME(sf, Rn),
1505	    ZREGNAME(sf, Rm),
1506	    nzcv,
1507	    CONDNAME(cond));
1508}
1509
1510OP5FUNC(op_ccmp_imm, sf, imm5, cond, Rn, nzcv)
1511{
1512	PRINTF("ccmp\t%s, #0x%"PRIx64", #0x%"PRIx64", %s\n",
1513	    ZREGNAME(sf, Rn),
1514	    imm5,
1515	    nzcv,
1516	    CONDNAME(cond));
1517}
1518
1519OP5FUNC(op_ccmp_reg, sf, Rm, cond, Rn, nzcv)
1520{
1521	PRINTF("ccmp\t%s, %s, #0x%"PRIx64", %s\n",
1522	    ZREGNAME(sf, Rn),
1523	    ZREGNAME(sf, Rm),
1524	    nzcv,
1525	    CONDNAME(cond));
1526}
1527
1528OP5FUNC(op_cinc, sf, Rm, cond, Rn, Rd)
1529{
1530	/* ALIAS: cset,csinc */
1531	csetsel_common(di, pc, insn, sf, Rm, cond, Rn, Rd,
1532	    "csinc", "cset", "cinc");
1533}
1534
1535OP5FUNC(op_csinv, sf, Rm, cond, Rn, Rd)
1536{
1537	/* ALIAS: csetm,cinv */
1538	csetsel_common(di, pc, insn, sf, Rm, cond, Rn, Rd,
1539	    "csinv", "csetm", "cinv");
1540}
1541
1542OP1FUNC(op_clrex, CRm)
1543{
1544	if (CRm == 15) {
1545		PRINTF("clrex\n");
1546	} else {
1547		PRINTF("clrex\t#0x%"PRIx64"\n", CRm);
1548	}
1549}
1550
1551OP3FUNC(op_cls, sf, Rn, Rd)
1552{
1553	PRINTF("cls\t%s, %s\n",
1554	    ZREGNAME(sf, Rd),
1555	    ZREGNAME(sf, Rn));
1556}
1557
1558OP3FUNC(op_clz, sf, Rn, Rd)
1559{
1560	PRINTF("clz\t%s, %s\n",
1561	    ZREGNAME(sf, Rd),
1562	    ZREGNAME(sf, Rn));
1563}
1564
1565OP6FUNC(op_subs_extreg, sf, Rm, option, imm3, Rn, Rd)
1566{
1567	/* ALIAS: cmp_extreg */
1568	extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd,
1569	    "subs", "cmp");
1570}
1571
1572OP5FUNC(op_subs_imm, sf, shift, imm12, Rn, Rd)
1573{
1574	/* ALIAS: cmp_imm */
1575	addsub_imm_common(di, pc, insn, sf, shift, imm12, Rn, Rd,
1576	    "subs", "cmp");
1577}
1578
1579OP6FUNC(op_subs_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
1580{
1581	if (shift == 3) {
1582		UNDEFINED(pc, insn, "illegal shift");
1583		return;
1584	}
1585
1586	/* ALIAS: negs,cmp_shiftreg */
1587	shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
1588	    "subs", "negs", "cmp");
1589}
1590
1591OP5FUNC(op_csneg, sf, Rm, cond, Rn, Rd)
1592{
1593	/* ALIAS: cneg */
1594	if ((Rn == Rm) && ((cond & 0xe) != 0x0e)) {
1595		PRINTF("cneg\t%s, %s, %s\n",
1596		    ZREGNAME(sf, Rd),
1597		    ZREGNAME(sf, Rn),
1598		    IVCONDNAME(cond));
1599	} else {
1600		PRINTF("csneg\t%s, %s, %s, %s\n",
1601		    ZREGNAME(sf, Rd),
1602		    ZREGNAME(sf, Rn),
1603		    ZREGNAME(sf, Rm),
1604		    CONDNAME(cond));
1605	}
1606}
1607
1608static void
1609crc32_common(const disasm_interface_t *di, uint64_t pc, uint32_t insn,
1610    uint64_t sf, uint64_t Rm, uint64_t sz, uint64_t Rn, uint64_t Rd,
1611    const char *op)
1612{
1613	const char bhwx[4] = "bhwx";	/* "crc32x" + SizeChar */
1614
1615	if (((sf != 0) && (sz != 3)) ||
1616	    ((sf == 0) && (sz == 3))) {
1617		UNDEFINED(pc, insn, "illegal size");
1618		return;
1619	}
1620
1621	PRINTF("%s%c\t%s, %s, %s\n",
1622	    op, bhwx[sz & 3],
1623	    ZREGNAME(0, Rd),
1624	    ZREGNAME(0, Rn),
1625	    ZREGNAME(sf, Rm));
1626}
1627
1628OP5FUNC(op_crc32, sf, Rm, sz, Rn, Rd)
1629{
1630	crc32_common(di, pc, insn, sf, Rm, sz, Rn, Rd, "crc32");
1631}
1632
1633OP5FUNC(op_crc32c, sf, Rm, sz, Rn, Rd)
1634{
1635	crc32_common(di, pc, insn, sf, Rm, sz, Rn, Rd, "crc32c");
1636}
1637
1638OP5FUNC(op_csel, sf, Rm, cond, Rn, Rd)
1639{
1640	PRINTF("csel\t%s, %s, %s, %s\n",
1641	    ZREGNAME(sf, Rd),
1642	    ZREGNAME(sf, Rn),
1643	    ZREGNAME(sf, Rm),
1644	    CONDNAME(cond));
1645}
1646
1647OP2FUNC(op_dcps, imm16, ll)
1648{
1649	if (ll == 0) {
1650		UNDEFINED(pc, insn, "illegal level");
1651		return;
1652	}
1653
1654	if (imm16 == 0)
1655		PRINTF("dcps%"PRIu64"\n", ll);
1656	else
1657		PRINTF("dcps%"PRIu64"\t#0x%"PRIx64"\n", ll, imm16);
1658}
1659
1660OP0FUNC(op_drps)
1661{
1662	PRINTF("drps\n");
1663}
1664
1665OP1FUNC(op_dmb, CRm)
1666{
1667	PRINTF("dmb\t%s\n", BARRIERNAME(CRm));
1668}
1669
1670OP1FUNC(op_dsb, CRm)
1671{
1672	PRINTF("dsb\t%s\n", BARRIERNAME(CRm));
1673}
1674
1675OP6FUNC(op_eon_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
1676{
1677	shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
1678	    "eon", NULL, NULL);
1679}
1680
1681OP6FUNC(op_eor_imm, sf, n, immr, imms, Rn, Rd)
1682{
1683	if (!ValidBitMasks(sf, n, imms, immr)) {
1684		UNDEFINED(pc, insn, "illegal bitmasks");
1685		return;
1686	}
1687
1688	PRINTF("eor\t%s, %s, #0x%"PRIx64"\n",
1689	    ZREGNAME(sf, Rd),
1690	    ZREGNAME(sf, Rn),
1691	    DecodeBitMasks(sf, n, imms, immr));
1692}
1693
1694OP6FUNC(op_eor_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
1695{
1696	shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
1697	    "eor", NULL, NULL);
1698}
1699
1700OP0FUNC(op_eret)
1701{
1702	PRINTF("eret\n");
1703}
1704
1705OP6FUNC(op_ror_imm, sf, n, Rm, imms, Rn, Rd)
1706{
1707	if (((sf ^ n) != 0) || (n == 0 && imms >= 0x20)) {
1708		UNDEFINED(pc, insn, "illegal sf and N");
1709		return;
1710	}
1711
1712	/* ALIAS: extr */
1713	if (Rn == Rm) {
1714		PRINTF("ror\t%s, %s, #%"PRIu64"\n",
1715		    ZREGNAME(sf, Rd),
1716		    ZREGNAME(sf, Rn),
1717		    imms);
1718	} else {
1719		PRINTF("extr\t%s, %s, %s, #%"PRIu64"\n",
1720		    ZREGNAME(sf, Rd),
1721		    ZREGNAME(sf, Rn),
1722		    ZREGNAME(sf, Rm),
1723		    imms);
1724	}
1725}
1726
1727#define CRm_OP2(crm,op)	((crm) << 3 | (op))
1728static const char *hint_table[] = {
1729	[CRm_OP2(0, 0)] = "nop",
1730	[CRm_OP2(0, 1)] = "yield",
1731	[CRm_OP2(0, 2)] = "wfe",
1732	[CRm_OP2(0, 3)] = "wfi",
1733	[CRm_OP2(0, 4)] = "sev",
1734	[CRm_OP2(0, 5)] = "sevl",
1735	[CRm_OP2(0, 7)] = "xpaclri",
1736	[CRm_OP2(1, 0)] = "pacia1716",
1737	[CRm_OP2(1, 2)] = "pacib1716",
1738	[CRm_OP2(1, 4)] = "autia1716",
1739	[CRm_OP2(1, 6)] = "autib1716",
1740	[CRm_OP2(2, 0)] = "esb",
1741	[CRm_OP2(2, 1)] = "psb\tcsync",
1742	[CRm_OP2(2, 2)] = "tsb\tcsync",
1743	[CRm_OP2(2, 4)] = "csdb",
1744	[CRm_OP2(3, 0)] = "paciaz",
1745	[CRm_OP2(3, 1)] = "paciasp",
1746	[CRm_OP2(3, 2)] = "pacibz",
1747	[CRm_OP2(3, 3)] = "pacibsp",
1748	[CRm_OP2(3, 4)] = "autiaz",
1749	[CRm_OP2(3, 5)] = "autiasp",
1750	[CRm_OP2(3, 6)] = "autibz",
1751	[CRm_OP2(3, 7)] = "autibsp",
1752	[CRm_OP2(4, 0)] = "bti",
1753	[CRm_OP2(4, 2)] = "bti\tc",
1754	[CRm_OP2(4, 4)] = "bti\tj",
1755	[CRm_OP2(4, 6)] = "bti\tjc",
1756};
1757
1758OP2FUNC(op_hint, CRm, op2)
1759{
1760	const uint64_t op = CRm_OP2(CRm, op2);
1761
1762	/* ALIAS: nop,sev,sevl,wfe,wfi,yield,etc,.. */
1763	if (op < __arraycount(hint_table) &&
1764	    hint_table[op] != NULL) {
1765		PRINTF("%s\n", hint_table[op]);
1766	} else {
1767		PRINTF("hint\t#0x%"PRIx64"\n", op);
1768	}
1769}
1770
1771OP1FUNC(op_hlt, imm16)
1772{
1773	PRINTF("hlt\t#0x%"PRIx64"\n", imm16);
1774}
1775
1776OP1FUNC(op_hvc, imm16)
1777{
1778	PRINTF("hvc\t#0x%"PRIx64"\n", imm16);
1779}
1780
1781OP1FUNC(op_isb, CRm)
1782{
1783	if (CRm == 15)
1784		PRINTF("isb\n");
1785	else
1786		PRINTF("isb\t#0x%"PRIx64"\n", CRm);
1787}
1788
1789OP3FUNC(op_ldar, size, Rn, Rt)
1790{
1791	PRINTF("ldar\t%s, [%s]\n",
1792	    ZREGNAME(size, Rt),
1793	    SREGNAME(1, Rn));
1794}
1795
1796OP2FUNC(op_ldarb, Rn, Rt)
1797{
1798	PRINTF("ldarb\t%s, [%s]\n",
1799	    ZREGNAME(0, Rt),
1800	    SREGNAME(1, Rn));
1801}
1802
1803OP2FUNC(op_ldarh, Rn, Rt)
1804{
1805	PRINTF("ldarh\t%s, [%s]\n",
1806	    ZREGNAME(0, Rt),
1807	    SREGNAME(1, Rn));
1808}
1809
1810OP4FUNC(op_ldaxp, size, Rt2, Rn, Rt)
1811{
1812	PRINTF("ldaxp\t%s, %s, [%s]\n",
1813	    ZREGNAME(size, Rt),
1814	    ZREGNAME(size, Rt2),
1815	    SREGNAME(1, Rn));
1816}
1817
1818OP3FUNC(op_ldaxr, size, Rn, Rt)
1819{
1820	PRINTF("ldaxr\t%s, [%s]\n",
1821	    ZREGNAME(size, Rt),
1822	    SREGNAME(1, Rn));
1823}
1824
1825OP2FUNC(op_ldaxrb, Rn, Rt)
1826{
1827	PRINTF("ldaxrb\t%s, [%s]\n",
1828	    ZREGNAME(0, Rt),
1829	    SREGNAME(1, Rn));
1830}
1831
1832OP2FUNC(op_ldaxrh, Rn, Rt)
1833{
1834	PRINTF("ldaxrh\t%s, [%s]\n",
1835	    ZREGNAME(0, Rt),
1836	    SREGNAME(1, Rn));
1837}
1838
1839OP5FUNC(op_ldnp, sf, imm7, Rt2, Rn, Rt)
1840{
1841	if (imm7 == 0) {
1842		PRINTF("ldnp\t%s, %s, [%s]\n",
1843		    ZREGNAME(sf, Rt),
1844		    ZREGNAME(sf, Rt2),
1845		    SREGNAME(1, Rn));
1846	} else {
1847		PRINTF("ldnp\t%s, %s, [%s,#%"PRId64"]\n",
1848		    ZREGNAME(sf, Rt),
1849		    ZREGNAME(sf, Rt2),
1850		    SREGNAME(1, Rn),
1851		    SignExtend(7, imm7, (sf == 0) ? 4 : 8));
1852	}
1853}
1854
1855OP5FUNC(op_ldp_postidx, sf, imm7, Rt2, Rn, Rt)
1856{
1857	PRINTF("ldp\t%s, %s, [%s],#%"PRId64"\n",
1858	    ZREGNAME(sf, Rt),
1859	    ZREGNAME(sf, Rt2),
1860	    SREGNAME(1, Rn),
1861	    SignExtend(7, imm7, (sf == 0) ? 4 : 8));
1862}
1863
1864OP5FUNC(op_ldp_preidx, sf, imm7, Rt2, Rn, Rt)
1865{
1866	PRINTF("ldp\t%s, %s, [%s,#%"PRId64"]!\n",
1867	    ZREGNAME(sf, Rt),
1868	    ZREGNAME(sf, Rt2),
1869	    SREGNAME(1, Rn),
1870	    SignExtend(7, imm7, (sf == 0) ? 4 : 8));
1871}
1872
1873OP5FUNC(op_ldp_signed, sf, imm7, Rt2, Rn, Rt)
1874{
1875	if (imm7 == 0) {
1876		PRINTF("ldp\t%s, %s, [%s]\n",
1877		    ZREGNAME(sf, Rt),
1878		    ZREGNAME(sf, Rt2),
1879		    SREGNAME(1, Rn));
1880	} else {
1881		PRINTF("ldp\t%s, %s, [%s,#%"PRId64"]\n",
1882		    ZREGNAME(sf, Rt),
1883		    ZREGNAME(sf, Rt2),
1884		    SREGNAME(1, Rn),
1885		    SignExtend(7, imm7, (sf == 0) ? 4 : 8));
1886	}
1887}
1888
1889OP4FUNC(op_ldpsw_postidx, imm7, Rt2, Rn, Rt)
1890{
1891	PRINTF("ldpsw\t%s, %s, [%s],#%"PRId64"\n",
1892	    ZREGNAME(1, Rt),
1893	    ZREGNAME(1, Rt2),
1894	    SREGNAME(1, Rn),
1895	    SignExtend(7, imm7, 4));
1896}
1897
1898OP4FUNC(op_ldpsw_preidx, imm7, Rt2, Rn, Rt)
1899{
1900	PRINTF("ldpsw\t%s, %s, [%s,#%"PRId64"]!\n",
1901	    ZREGNAME(1, Rt),
1902	    ZREGNAME(1, Rt2),
1903	    SREGNAME(1, Rn),
1904	    SignExtend(7, imm7, 4));
1905}
1906
1907OP4FUNC(op_ldpsw_signed, imm7, Rt2, Rn, Rt)
1908{
1909	if (imm7 == 0) {
1910		PRINTF("ldpsw\t%s, %s, [%s]\n",
1911		    ZREGNAME(1, Rt),
1912		    ZREGNAME(1, Rt2),
1913		    SREGNAME(1, Rn));
1914	} else {
1915		PRINTF("ldpsw\t%s, %s, [%s,#%"PRId64"]\n",
1916		    ZREGNAME(1, Rt),
1917		    ZREGNAME(1, Rt2),
1918		    SREGNAME(1, Rn),
1919		    SignExtend(7, imm7, 4));
1920	}
1921}
1922
1923OP4FUNC(op_ldr_immpostidx, size, imm9, Rn, Rt)
1924{
1925	PRINTF("ldr\t%s, [%s],#%"PRId64"\n",
1926	    ZREGNAME(size, Rt),
1927	    SREGNAME(1, Rn),
1928	    SignExtend(9, imm9, 1));
1929}
1930
1931OP4FUNC(op_ldr_immpreidx, size, imm9, Rn, Rt)
1932{
1933	PRINTF("ldr\t%s, [%s,#%"PRId64"]!\n",
1934	    ZREGNAME(size, Rt),
1935	    SREGNAME(1, Rn),
1936	    SignExtend(9, imm9, 1));
1937}
1938
1939OP4FUNC(op_ldr_immunsign, size, imm12, Rn, Rt)
1940{
1941	if (imm12 == 0) {
1942		PRINTF("ldr\t%s, [%s]\n",
1943		    ZREGNAME(size, Rt),
1944		    SREGNAME(1, Rn));
1945	} else {
1946		PRINTF("ldr\t%s, [%s,#%"PRId64"]\n",
1947		    ZREGNAME(size, Rt),
1948		    SREGNAME(1, Rn),
1949		    ZeroExtend(12, imm12, (size == 0) ? 4 : 8));
1950	}
1951}
1952
1953OP3FUNC(op_ldr_literal, size, imm19, Rt)
1954{
1955	PRINTF("ldr\t%s, ", ZREGNAME(size, Rt));
1956	PRINTADDR(SignExtend(19, imm19, 4) + pc);
1957	PRINTF("\n");
1958}
1959
1960OP6FUNC(op_ldr_reg, size, Rm, option, shift, Rn, Rt)
1961{
1962	regoffset_x_common(di, pc, insn, size, Rm, option, shift, Rn, Rt,
1963	    "ldr");
1964}
1965
1966OP3FUNC(op_ldrb_immpostidx, imm9, Rn, Rt)
1967{
1968	PRINTF("ldrb\t%s, [%s],#%"PRId64"\n",
1969	    ZREGNAME(0, Rt),
1970	    SREGNAME(1, Rn),
1971	    SignExtend(9, imm9, 1));
1972}
1973
1974OP3FUNC(op_ldrb_immpreidx, imm9, Rn, Rt)
1975{
1976	PRINTF("ldrb\t%s, [%s,#%"PRId64"]!\n",
1977	    ZREGNAME(0, Rt),
1978	    SREGNAME(1, Rn),
1979	    SignExtend(9, imm9, 1));
1980}
1981
1982OP3FUNC(op_ldrb_immunsign, imm12, Rn, Rt)
1983{
1984	if (imm12 == 0) {
1985		PRINTF("ldrb\t%s, [%s]\n",
1986		    ZREGNAME(0, Rt),
1987		    SREGNAME(1, Rn));
1988	} else {
1989		PRINTF("ldrb\t%s, [%s,#%"PRId64"]\n",
1990		    ZREGNAME(0, Rt),
1991		    SREGNAME(1, Rn),
1992		    ZeroExtend(12, imm12, 1));
1993	}
1994}
1995
1996OP5FUNC(op_ldrb_reg, Rm, option, shift, Rn, Rt)
1997{
1998	regoffset_b_common(di, pc, insn, Rm, option, shift, Rn, Rt, "ldrb");
1999}
2000
2001OP3FUNC(op_ldrh_immpostidx, imm9, Rn, Rt)
2002{
2003	PRINTF("ldrh\t%s, [%s],#%"PRId64"\n",
2004	    ZREGNAME(0, Rt),
2005	    SREGNAME(1, Rn),
2006	    SignExtend(9, imm9, 1));
2007}
2008
2009OP3FUNC(op_ldrh_immpreidx, imm9, Rn, Rt)
2010{
2011	PRINTF("ldrh\t%s, [%s,#%"PRId64"]!\n",
2012	    ZREGNAME(0, Rt),
2013	    SREGNAME(1, Rn),
2014	    SignExtend(9, imm9, 1));
2015}
2016
2017OP3FUNC(op_ldrh_immunsign, imm12, Rn, Rt)
2018{
2019	if (imm12 == 0) {
2020		PRINTF("ldrh\t%s, [%s]\n",
2021		    ZREGNAME(0, Rt),
2022		    SREGNAME(1, Rn));
2023	} else {
2024		PRINTF("ldrh\t%s, [%s,#%"PRId64"]\n",
2025		    ZREGNAME(0, Rt),
2026		    SREGNAME(1, Rn),
2027		    ZeroExtend(12, imm12, 2));
2028	}
2029}
2030
2031OP5FUNC(op_ldrh_reg, Rm, option, shift, Rn, Rt)
2032{
2033	regoffset_h_common(di, pc, insn, Rm, option, shift, Rn, Rt, 0, "ldrh");
2034}
2035
2036OP4FUNC(op_ldrsb_immpostidx, opc, imm9, Rn, Rt)
2037{
2038	PRINTF("ldrsb\t%s, [%s],#%"PRId64"\n",
2039	    ZREGNAME((opc ^ 1), Rt),
2040	    SREGNAME(1, Rn),
2041	    SignExtend(9, imm9, 1));
2042}
2043
2044OP4FUNC(op_ldrsb_immpreidx, opc, imm9, Rn, Rt)
2045{
2046	PRINTF("ldrsb\t%s, [%s,#%"PRId64"]!\n",
2047	    ZREGNAME((opc ^ 1), Rt),
2048	    SREGNAME(1, Rn),
2049	    SignExtend(9, imm9, 1));
2050}
2051
2052OP4FUNC(op_ldrsb_immunsign, opc, imm12, Rn, Rt)
2053{
2054	if (imm12 == 0) {
2055		PRINTF("ldrsb\t%s, [%s]\n",
2056		    ZREGNAME((opc ^ 1), Rt),
2057		    SREGNAME(1, Rn));
2058	} else {
2059		PRINTF("ldrsb\t%s, [%s,#%"PRId64"]\n",
2060		    ZREGNAME((opc ^ 1), Rt),
2061		    SREGNAME(1, Rn),
2062		    ZeroExtend(12, imm12, 1));
2063	}
2064}
2065
2066OP6FUNC(op_ldrsb_reg, opc, Rm, option, shift, Rn, Rt)
2067{
2068	regoffset_b_common(di, pc, insn, Rm, option, shift, Rn, Rt, "ldrsb");
2069}
2070
2071OP4FUNC(op_ldrsh_immpostidx, opc, imm9, Rn, Rt)
2072{
2073	PRINTF("ldrsh\t%s, [%s],#%"PRId64"\n",
2074	    ZREGNAME((opc ^ 1), Rt),
2075	    SREGNAME(1, Rn),
2076	    SignExtend(9, imm9, 1));
2077}
2078
2079OP4FUNC(op_ldrsh_immpreidx, opc, imm9, Rn, Rt)
2080{
2081	PRINTF("ldrsh\t%s, [%s,#%"PRId64"]!\n",
2082	    ZREGNAME((opc ^ 1), Rt),
2083	    SREGNAME(1, Rn),
2084	    SignExtend(9, imm9, 1));
2085}
2086
2087OP4FUNC(op_ldrsh_immunsign, opc, imm12, Rn, Rt)
2088{
2089	if (imm12 == 0) {
2090		PRINTF("ldrsh\t%s, [%s]\n",
2091		    ZREGNAME((opc ^ 1), Rt),
2092		    SREGNAME(1, Rn));
2093	} else {
2094		PRINTF("ldrsh\t%s, [%s,#%"PRId64"]\n",
2095		    ZREGNAME((opc ^ 1), Rt),
2096		    SREGNAME(1, Rn),
2097		    ZeroExtend(12, imm12, 2));
2098	}
2099}
2100
2101OP6FUNC(op_ldrsh_reg, opc, Rm, option, shift, Rn, Rt)
2102{
2103	regoffset_h_common(di, pc, insn, Rm, option, shift, Rn, Rt, opc ^ 1,
2104	    "ldrsh");
2105}
2106
2107OP3FUNC(op_ldrsw_immpostidx, imm9, Rn, Rt)
2108{
2109	PRINTF("ldrsw\t%s, [%s],#%"PRId64"\n",
2110	    ZREGNAME(1, Rt),
2111	    SREGNAME(1, Rn),
2112	    SignExtend(9, imm9, 1));
2113}
2114
2115OP3FUNC(op_ldrsw_immpreidx, imm9, Rn, Rt)
2116{
2117	PRINTF("ldrsw\t%s, [%s,#%"PRId64"]!\n",
2118	    ZREGNAME(1, Rt),
2119	    SREGNAME(1, Rn),
2120	    SignExtend(9, imm9, 1));
2121}
2122
2123OP3FUNC(op_ldrsw_immunsign, imm12, Rn, Rt)
2124{
2125	if (imm12 == 0) {
2126		PRINTF("ldrsw\t%s, [%s]\n",
2127		    ZREGNAME(1, Rt),
2128		    SREGNAME(1, Rn));
2129	} else {
2130		PRINTF("ldrsw\t%s, [%s,#%"PRId64"]\n",
2131		    ZREGNAME(1, Rt),
2132		    SREGNAME(1, Rn),
2133		    ZeroExtend(12, imm12, 4));
2134	}
2135}
2136
2137OP2FUNC(op_ldrsw_literal, imm19, Rt)
2138{
2139	PRINTF("ldrsw\t%s, ", ZREGNAME(1, Rt));
2140	PRINTADDR(SignExtend(19, imm19, 4) + pc);
2141	PRINTF("\n");
2142}
2143
2144OP5FUNC(op_ldrsw_reg, Rm, option, shift, Rn, Rt)
2145{
2146	regoffset_w_common(di, pc, insn, Rm, option, shift, Rn, Rt, "ldrsw");
2147}
2148
2149OP4FUNC(op_ldtr, size, imm9, Rn, Rt)
2150{
2151	if (imm9 == 0) {
2152		PRINTF("ldtr\t%s, [%s]\n",
2153		    ZREGNAME(size, Rt),
2154		    SREGNAME(1, Rn));
2155	} else {
2156		PRINTF("ldtr\t%s, [%s,#%"PRId64"]\n",
2157		    ZREGNAME(size, Rt),
2158		    SREGNAME(1, Rn),
2159		    SignExtend(9, imm9, 1));
2160	}
2161}
2162
2163OP3FUNC(op_ldtrb, imm9, Rn, Rt)
2164{
2165	if (imm9 == 0) {
2166		PRINTF("ldtrb\t%s, [%s]\n",
2167		    ZREGNAME(0, Rt),
2168		    SREGNAME(1, Rn));
2169	} else {
2170		PRINTF("ldtrb\t%s, [%s,#%"PRId64"]\n",
2171		    ZREGNAME(0, Rt),
2172		    SREGNAME(1, Rn),
2173		    SignExtend(9, imm9, 1));
2174	}
2175}
2176
2177OP3FUNC(op_ldtrh, imm9, Rn, Rt)
2178{
2179	if (imm9 == 0) {
2180		PRINTF("ldtrh\t%s, [%s]\n",
2181		    ZREGNAME(0, Rt),
2182		    SREGNAME(1, Rn));
2183	} else {
2184		PRINTF("ldtrh\t%s, [%s,#%"PRId64"]\n",
2185		    ZREGNAME(0, Rt),
2186		    SREGNAME(1, Rn),
2187		    SignExtend(9, imm9, 1));
2188	}
2189}
2190
2191OP4FUNC(op_ldtrsb, opc, imm9, Rn, Rt)
2192{
2193	if (imm9 == 0) {
2194		PRINTF("ldtrsb\t%s, [%s]\n",
2195		    ZREGNAME((opc ^ 1), Rt),
2196		    SREGNAME(1, Rn));
2197	} else {
2198		PRINTF("ldtrsb\t%s, [%s,#%"PRId64"]\n",
2199		    ZREGNAME((opc ^ 1), Rt),
2200		    SREGNAME(1, Rn),
2201		    SignExtend(9, imm9, 1));
2202	}
2203}
2204
2205OP4FUNC(op_ldtrsh, opc, imm9, Rn, Rt)
2206{
2207	if (imm9 == 0) {
2208		PRINTF("ldtrsh\t%s, [%s]\n",
2209		    ZREGNAME((opc ^ 1), Rt),
2210		    SREGNAME(1, Rn));
2211	} else {
2212		PRINTF("ldtrsh\t%s, [%s,#%"PRId64"]\n",
2213		    ZREGNAME((opc ^ 1), Rt),
2214		    SREGNAME(1, Rn),
2215		    SignExtend(9, imm9, 1));
2216	}
2217}
2218
2219OP3FUNC(op_ldtrsw, imm9, Rn, Rt)
2220{
2221	if (imm9 == 0) {
2222		PRINTF("ldtrsw\t%s, [%s]\n",
2223		    ZREGNAME(1, Rt),
2224		    SREGNAME(1, Rn));
2225	} else {
2226		PRINTF("ldtrsw\t%s, [%s,#%"PRId64"]\n",
2227		    ZREGNAME(1, Rt),
2228		    SREGNAME(1, Rn),
2229		    SignExtend(9, imm9, 1));
2230	}
2231}
2232
2233OP4FUNC(op_ldur, size, imm9, Rn, Rt)
2234{
2235	if (imm9 == 0) {
2236		PRINTF("ldur\t%s, [%s]\n",
2237		    ZREGNAME(size, Rt),
2238		    SREGNAME(1, Rn));
2239	} else {
2240		PRINTF("ldur\t%s, [%s,#%"PRId64"]\n",
2241		    ZREGNAME(size, Rt),
2242		    SREGNAME(1, Rn),
2243		    SignExtend(9, imm9, 1));
2244	}
2245}
2246
2247OP3FUNC(op_ldurb, imm9, Rn, Rt)
2248{
2249	if (imm9 == 0) {
2250		PRINTF("ldurb\t%s, [%s]\n",
2251		    ZREGNAME(0, Rt),
2252		    SREGNAME(1, Rn));
2253	} else {
2254		PRINTF("ldurb\t%s, [%s,#%"PRId64"]\n",
2255		    ZREGNAME(0, Rt),
2256		    SREGNAME(1, Rn),
2257		    SignExtend(9, imm9, 1));
2258	}
2259}
2260
2261OP3FUNC(op_ldurh, imm9, Rn, Rt)
2262{
2263	if (imm9 == 0) {
2264		PRINTF("ldurh\t%s, [%s]\n",
2265		    ZREGNAME(0, Rt),
2266		    SREGNAME(1, Rn));
2267	} else {
2268		PRINTF("ldurh\t%s, [%s,#%"PRId64"]\n",
2269		    ZREGNAME(0, Rt),
2270		    SREGNAME(1, Rn),
2271		    SignExtend(9, imm9, 1));
2272	}
2273}
2274
2275OP4FUNC(op_ldursb, opc, imm9, Rn, Rt)
2276{
2277	if (imm9 == 0) {
2278		PRINTF("ldursb\t%s, [%s]\n",
2279		    ZREGNAME((opc ^ 1), Rt),
2280		    SREGNAME(1, Rn));
2281	} else {
2282		PRINTF("ldursb\t%s, [%s,#%"PRId64"]\n",
2283		    ZREGNAME((opc ^ 1), Rt),
2284		    SREGNAME(1, Rn),
2285		    SignExtend(9, imm9, 1));
2286	}
2287}
2288
2289OP4FUNC(op_ldursh, opc, imm9, Rn, Rt)
2290{
2291	if (imm9 == 0) {
2292		PRINTF("ldursh\t%s, [%s]\n",
2293		    ZREGNAME((opc ^ 1), Rt),
2294		    SREGNAME(1, Rn));
2295	} else {
2296		PRINTF("ldursh\t%s, [%s,#%"PRId64"]\n",
2297		    ZREGNAME((opc ^ 1), Rt),
2298		    SREGNAME(1, Rn),
2299		    SignExtend(9, imm9, 1));
2300	}
2301}
2302
2303OP3FUNC(op_ldursw, imm9, Rn, Rt)
2304{
2305	if (imm9 == 0) {
2306		PRINTF("ldursw\t%s, [%s]\n",
2307		    ZREGNAME(1, Rt),
2308		    SREGNAME(1, Rn));
2309	} else {
2310		PRINTF("ldursw\t%s, [%s,#%"PRId64"]\n",
2311		    ZREGNAME(1, Rt),
2312		    SREGNAME(1, Rn),
2313		    SignExtend(9, imm9, 1));
2314	}
2315}
2316
2317OP4FUNC(op_ldxp, size, Rt2, Rn, Rt)
2318{
2319	PRINTF("ldxp\t%s, %s, [%s]\n",
2320	    ZREGNAME(size, Rt),
2321	    ZREGNAME(size, Rt2),
2322	    SREGNAME(1, Rn));
2323}
2324
2325OP3FUNC(op_ldxr, size, Rn, Rt)
2326{
2327	PRINTF("ldxr\t%s, [%s]\n",
2328	    ZREGNAME(size, Rt),
2329	    SREGNAME(1, Rn));
2330}
2331
2332OP2FUNC(op_ldxrb, Rn, Rt)
2333{
2334	PRINTF("ldxrb\t%s, [%s]\n",
2335	    ZREGNAME(0, Rt),
2336	    SREGNAME(1, Rn));
2337}
2338
2339OP2FUNC(op_ldxrh, Rn, Rt)
2340{
2341	PRINTF("ldxrh\t%s, [%s]\n",
2342	    ZREGNAME(0, Rt),
2343	    SREGNAME(1, Rn));
2344}
2345
2346OP6FUNC(op_ubfm, sf, n, immr, imms, Rn, Rd)
2347{
2348	const uint64_t bitwidth = (sf == 0) ? 32 : 64;
2349
2350	/* ALIAS: lsr_imm,ubfiz,ubfm,ubfx,uxtb,uxth */
2351	if ((imms != (bitwidth - 1)) && ((imms + 1) == immr)) {
2352		PRINTF("lsl\t%s, %s, #%"PRIu64"\n",
2353		    ZREGNAME(sf, Rd),
2354		    ZREGNAME(sf, Rn),
2355		    bitwidth - immr);
2356	} else if (imms == (bitwidth - 1)) {
2357		PRINTF("lsr\t%s, %s, #%"PRIu64"\n",
2358		    ZREGNAME(sf, Rd),
2359		    ZREGNAME(sf, Rn),
2360		    immr);
2361	} else if (imms < immr) {
2362		PRINTF("ubfiz\t%s, %s, #%"PRIu64", #%"PRIu64"\n",
2363		    ZREGNAME(sf, Rd),
2364		    ZREGNAME(sf, Rn),
2365		    (bitwidth - immr) & (bitwidth - 1),
2366		    (imms + 1) & (bitwidth - 1));
2367	} else if (BFXPreferred(sf, 1, imms, immr)) {
2368		PRINTF("ubfx\t%s, %s, #%"PRIu64", #%"PRIu64"\n",
2369		    ZREGNAME(sf, Rd),
2370		    ZREGNAME(sf, Rn),
2371		    immr,
2372		    (imms - immr + 1) & (bitwidth - 1));
2373	} else if ((immr == 0) && (imms == 7)) {
2374		PRINTF("uxtb\t%s, %s\n",
2375		    ZREGNAME(0, Rd),
2376		    ZREGNAME(0, Rn));
2377	} else if ((immr == 0) && (imms == 15)) {
2378		PRINTF("uxth\t%s, %s\n",
2379		    ZREGNAME(0, Rd),
2380		    ZREGNAME(0, Rn));
2381	} else {
2382		UNDEFINED(pc, insn, "undefined");
2383	}
2384}
2385
2386OP4FUNC(op_lsl_reg, sf, Rm, Rn, Rd)
2387{
2388	/* ALIAS: lslv */
2389	/* "lsl" always the preferred disassembly */
2390	PRINTF("lsl\t%s, %s, %s\n",
2391	    ZREGNAME(sf, Rd),
2392	    ZREGNAME(sf, Rn),
2393	    ZREGNAME(sf, Rm));
2394}
2395
2396OP4FUNC(op_lsr_reg, sf, Rm, Rn, Rd)
2397{
2398	/* ALIAS: lsrv */
2399	/* "lsr" always the preferred disassembly */
2400	PRINTF("lsr\t%s, %s, %s\n",
2401	    ZREGNAME(sf, Rd),
2402	    ZREGNAME(sf, Rn),
2403	    ZREGNAME(sf, Rm));
2404}
2405
2406OP5FUNC(op_madd, sf, Rm, Ra, Rn, Rd)
2407{
2408	/* ALIAS: mul */
2409	if (Ra == 31) {
2410		PRINTF("mul\t%s, %s, %s\n",
2411		    ZREGNAME(sf, Rd),
2412		    ZREGNAME(sf, Rn),
2413		    ZREGNAME(sf, Rm));
2414	} else {
2415		PRINTF("madd\t%s, %s, %s, %s\n",
2416		    ZREGNAME(sf, Rd),
2417		    ZREGNAME(sf, Rn),
2418		    ZREGNAME(sf, Rm),
2419		    ZREGNAME(sf, Ra));
2420	}
2421}
2422
2423OP5FUNC(op_msub, sf, Rm, Ra, Rn, Rd)
2424{
2425	/* ALIAS: mneg */
2426	if (Ra == 31) {
2427		PRINTF("mneg\t%s, %s, %s\n",
2428		    ZREGNAME(sf, Rd),
2429		    ZREGNAME(sf, Rn),
2430		    ZREGNAME(sf, Rm));
2431	} else {
2432		PRINTF("msub\t%s, %s, %s, %s\n",
2433		    ZREGNAME(sf, Rd),
2434		    ZREGNAME(sf, Rn),
2435		    ZREGNAME(sf, Rm),
2436		    ZREGNAME(sf, Ra));
2437	}
2438}
2439
2440OP6FUNC(op_orr_imm, sf, n, immr, imms, Rn, Rd)
2441{
2442	if (!ValidBitMasks(sf, n, imms, immr)) {
2443		UNDEFINED(pc, insn, "illegal bitmasks");
2444		return;
2445	}
2446
2447	/* ALIAS: mov_bmimm */
2448#if 1
2449	/* to distinguish from mov_iwimm */
2450	if ((Rn == 31) && !MoveWidePreferred(sf, n, imms, immr)) {
2451#else
2452	/* "orr Rd, XZR, #imm" -> "mov Rd, #imm" */
2453	(void)MoveWidePreferred;
2454	if (Rn == 31) {
2455#endif
2456		PRINTF("mov\t%s, #0x%"PRIx64"\n",
2457		    SREGNAME(sf, Rd),
2458		    DecodeBitMasks(sf, n, imms, immr));
2459	} else {
2460		PRINTF("orr\t%s, %s, #0x%"PRIx64"\n",
2461		    SREGNAME(sf, Rd),
2462		    ZREGNAME(sf, Rn),
2463		    DecodeBitMasks(sf, n, imms, immr));
2464	}
2465}
2466
2467OP4FUNC(op_movn, sf, hw, imm16, Rd)
2468{
2469	const uint64_t mask = (sf == 0) ? 0xffffffff : 0xffffffffffffffffUL;
2470
2471	if ((sf == 0) && (hw >= 2)) {
2472		UNDEFINED(pc, insn, "illegal size");
2473		return;
2474	}
2475
2476	/* ALIAS: mov_iwimm */
2477	if ((hw == 0) || (imm16 == 0)) {
2478		PRINTF("mov\t%s, #0x%"PRIx64"\n",
2479		    ZREGNAME(sf, Rd),
2480		    (~(ZeroExtend(16, imm16, 1) & mask)) & mask);
2481	} else {
2482		/* movn */
2483		const uint64_t shift = hw * 16;
2484		PRINTF("mov\t%s, #0x%"PRIx64"\n",
2485		    ZREGNAME(sf, Rd),
2486		    ~(ZeroExtend(16, imm16, 1) << shift) & mask);
2487	}
2488}
2489
2490OP6FUNC(op_orr_reg, sf, shift, Rm, imm6, Rn, Rd)
2491{
2492	/* ALIAS: mov_reg */
2493	if ((Rn == 31) && (imm6 == 0)) {
2494		PRINTF("mov\t%s, %s\n",
2495		    ZREGNAME(sf, Rd),
2496		    ZREGNAME(sf, Rm));
2497	} else {
2498		shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
2499		    "orr", NULL, NULL);
2500	}
2501}
2502
2503OP4FUNC(op_movz, sf, hw, imm16, Rd)
2504{
2505	/* ALIAS: mov_wimm */
2506	if ((hw == 0) || (imm16 == 0)) {
2507		PRINTF("mov\t%s, #0x%"PRIx64"\n",
2508		    ZREGNAME(sf, Rd),
2509		    ZeroExtend(16, imm16, 1));
2510	} else {
2511		const int shift = hw * 16;
2512#if 0
2513		PRINTF("movz\t%s, #0x%lx, lsl #%d\n",
2514		    ZREGNAME(sf, Rd),
2515		    ZeroExtend(16, imm16, 1), shift);
2516#else
2517		/* same as objdump */
2518		PRINTF("mov\t%s, #0x%"PRIx64"\n",
2519		    ZREGNAME(sf, Rd),
2520		    ZeroExtend(16, imm16, 1) << shift);
2521#endif
2522	}
2523}
2524
2525OP4FUNC(op_movk, sf, hw, imm16, Rd)
2526{
2527	const int shift = hw * 16;
2528
2529	if (hw == 0) {
2530		PRINTF("movk\t%s, #0x%"PRIx64"\n",
2531		    ZREGNAME(sf, Rd),
2532		    ZeroExtend(16, imm16, 1));
2533	} else {
2534		PRINTF("movk\t%s, #0x%"PRIx64", lsl #%d\n",
2535		    ZREGNAME(sf, Rd),
2536		    ZeroExtend(16, imm16, 1), shift);
2537	}
2538}
2539
2540OP6FUNC(op_mrs, op0, op1, CRn, CRm, op2, Rt)
2541{
2542	char buf[SYSREGNAMEBUFLEN];
2543
2544	PRINTF("mrs\t%s, %s\n",
2545	    ZREGNAME(1, Rt),
2546	    RSYSREGNAME(buf, sizeof(buf), op0, op1, CRn, CRm, op2));
2547}
2548
2549OP6FUNC(op_msr, op0, op1, CRn, CRm, op2, Rt)
2550{
2551	char buf[SYSREGNAMEBUFLEN];
2552
2553	PRINTF("msr\t%s, %s\n",
2554	    WSYSREGNAME(buf, sizeof(buf), op0, op1, CRn, CRm, op2),
2555	    ZREGNAME(1, Rt));
2556}
2557
2558OP3FUNC(op_msr_imm, op1, CRm, op2)
2559{
2560	const char *pstatefield;
2561
2562#define MSRIMM_OP(op1, op2)	(((op1) << 3) | (op2))
2563
2564	switch (MSRIMM_OP(op1, op2)) {
2565	case MSRIMM_OP(0, 0):
2566		PRINTF("cfinv\n");
2567		return;
2568	case MSRIMM_OP(0, 1):
2569		PRINTF("xaflag\n");
2570		return;
2571	case MSRIMM_OP(0, 2):
2572		PRINTF("axflag\n");
2573		return;
2574	case MSRIMM_OP(0, 3):
2575		pstatefield = "uao";
2576		break;
2577	case MSRIMM_OP(0, 4):
2578		pstatefield = "pan";
2579		break;
2580	case MSRIMM_OP(0, 5):
2581		pstatefield = "spsel";
2582		break;
2583	case MSRIMM_OP(3, 1):
2584		pstatefield = "ssbs";
2585		break;
2586	case MSRIMM_OP(3, 2):
2587		pstatefield = "dit";
2588		break;
2589	case MSRIMM_OP(3, 4):
2590		pstatefield = "tco";
2591		break;
2592	case MSRIMM_OP(3, 6):
2593		pstatefield = "daifset";
2594		break;
2595	case MSRIMM_OP(3, 7):
2596		pstatefield = "daifclr";
2597		break;
2598	default:
2599		UNDEFINED(pc, insn, "illegal op1/op2");
2600		return;
2601	}
2602
2603	PRINTF("msr\t%s, #0x%"PRIx64"\n",
2604	    pstatefield, CRm);
2605}
2606
2607OP6FUNC(op_orn, sf, shift, Rm, imm6, Rn, Rd)
2608{
2609	/* ALIAS: mvn */
2610	shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
2611	    "orn", "mvn", NULL);
2612}
2613
2614OP6FUNC(op_sub_shiftreg, sf, shift, Rm, imm6, Rn, Rd)
2615{
2616	/* ALIAS: neg */
2617	shiftreg_common(di, pc, insn, sf, shift, Rm, imm6, Rn, Rd,
2618	    "sub", "neg", NULL);
2619}
2620
2621OP4FUNC(op_sbc, sf, Rm, Rn, Rd)
2622{
2623	/* ALIAS: ngc */
2624	if (Rn == 31) {
2625		PRINTF("ngc\t%s, %s\n",
2626		    ZREGNAME(sf, Rd),
2627		    ZREGNAME(sf, Rm));
2628	} else {
2629		PRINTF("sbc\t%s, %s, %s\n",
2630		    ZREGNAME(sf, Rd),
2631		    ZREGNAME(sf, Rn),
2632		    ZREGNAME(sf, Rm));
2633	}
2634}
2635
2636OP4FUNC(op_sbcs, sf, Rm, Rn, Rd)
2637{
2638	/* ALIAS: ngcs */
2639	if (Rn == 31) {
2640		PRINTF("ngcs\t%s, %s\n",
2641		    ZREGNAME(sf, Rd),
2642		    ZREGNAME(sf, Rm));
2643	} else {
2644		PRINTF("sbcs\t%s, %s, %s\n",
2645		    ZREGNAME(sf, Rd),
2646		    ZREGNAME(sf, Rn),
2647		    ZREGNAME(sf, Rm));
2648	}
2649}
2650
2651OP3FUNC(op_prfm_imm, imm12, Rn, Rt)
2652{
2653	if (imm12 == 0) {
2654		PRINTF("prfm\t%s, [%s]\n",
2655		    PREFETCHNAME(Rt),
2656		    SREGNAME(1, Rn));
2657	} else {
2658		PRINTF("prfm\t%s, [%s,#%"PRId64"]\n",
2659		    PREFETCHNAME(Rt),
2660		    SREGNAME(1, Rn),
2661		    SignExtend(12, imm12, 8));
2662	}
2663}
2664
2665OP2FUNC(op_prfm_literal, imm19, Rt)
2666{
2667	PRINTF("prfm\t%s, ", PREFETCHNAME(Rt));
2668	PRINTADDR(SignExtend(19, imm19, 4) + pc);
2669	PRINTF("\n");
2670}
2671
2672OP5FUNC(op_prfm_reg, Rm, option, shift, Rn, Rt)
2673{
2674	int r;
2675
2676	if ((r = regoffset_option_to_r(option)) < 0) {
2677		UNDEFINED(pc, insn, "illegal option");
2678		return;
2679	}
2680
2681	if (shift == 0) {
2682		PRINTF("prfm\t%s, [%s,%s%s]\n",
2683		    PREFETCHNAME(Rt),
2684		    SREGNAME(1, Rn),
2685		    ZREGNAME(r, Rm),
2686		    SHIFTOP8(option,
2687		        "", "", ",uxtw", "", "", "", ",sxtw", ",sxtx"));
2688	} else {
2689		PRINTF("prfm\t%s, [%s,%s,%s #%d]\n",
2690		    PREFETCHNAME(Rt),
2691		    SREGNAME(1, Rn),
2692		    ZREGNAME(r, Rm),
2693		    SHIFTOP8(option,
2694		        "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"),
2695		    3);
2696	}
2697}
2698
2699OP3FUNC(op_prfum, imm9, Rn, Rt)
2700{
2701	if (imm9 == 0) {
2702		PRINTF("prfum\t%s, [%s]\n",
2703		    PREFETCHNAME(Rt),
2704		    SREGNAME(1, Rn));
2705	} else {
2706		PRINTF("prfum\t%s, [%s,#%"PRId64"]\n",
2707		    PREFETCHNAME(Rt),
2708		    SREGNAME(1, Rn),
2709		    SignExtend(9, imm9, 1));
2710	}
2711}
2712
2713OP1FUNC(op_ret, Rn)
2714{
2715	if (Rn == 30)
2716		PRINTF("ret\n");
2717	else
2718		PRINTF("ret\t%s\n", ZREGNAME(1, Rn));
2719}
2720
2721OP4FUNC(op_rev, sf, opc, Rn, Rd)
2722{
2723	/*
2724	 * sf opc insn
2725	 * -- --- -------------
2726	 * 0  00  rbit    Wd,Wn
2727	 * 0  01  rev16   Wd,Wn
2728	 * 0  10  rev     Wd,Wn
2729	 * 0  11  undefined
2730	 * 1  00  rbit    Xd,Xn
2731	 * 1  01  rev16   Xd,Xn
2732	 * 1  10  rev32   Xd,Xn
2733	 * 1  11  rev     Xd,Xn
2734	 */
2735	const char *const opcode[2][4] = {
2736		{ "rbit", "rev16", "rev",   NULL  },
2737		{ "rbit", "rev16", "rev32", "rev" }
2738	};
2739	const char *const op = opcode[sf][opc];
2740
2741	if (op == NULL) {
2742		UNDEFINED(pc, insn, "undefined");
2743		return;
2744	}
2745
2746	PRINTF("%s\t%s, %s\n",
2747	    op,
2748	    ZREGNAME(sf, Rd),
2749	    ZREGNAME(sf, Rn));
2750}
2751
2752OP4FUNC(op_ror_reg, sf, Rm, Rn, Rd)
2753{
2754	/* ALIAS: rorv */
2755	/* "ror" always the preferred disassembly */
2756	PRINTF("ror\t%s, %s, %s\n",
2757	    ZREGNAME(sf, Rd),
2758	    ZREGNAME(sf, Rn),
2759	    ZREGNAME(sf, Rm));
2760}
2761
2762OP4FUNC(op_sdiv, sf, Rm, Rn, Rd)
2763{
2764	PRINTF("sdiv\t%s, %s, %s\n",
2765	    ZREGNAME(sf, Rd),
2766	    ZREGNAME(sf, Rn),
2767	    ZREGNAME(sf, Rm));
2768}
2769
2770OP4FUNC(op_smaddl, Rm, Ra, Rn, Rd)
2771{
2772	/* ALIAS: smull */
2773	if (Ra == 31) {
2774		PRINTF("smull\t%s, %s, %s\n",
2775		    ZREGNAME(1, Rd),
2776		    ZREGNAME(0, Rn),
2777		    ZREGNAME(0, Rm));
2778	} else {
2779		PRINTF("smaddl\t%s, %s, %s, %s\n",
2780		    ZREGNAME(1, Rd),
2781		    ZREGNAME(0, Rn),
2782		    ZREGNAME(0, Rm),
2783		    ZREGNAME(1, Ra));
2784	}
2785}
2786
2787OP1FUNC(op_smc, imm16)
2788{
2789	PRINTF("smc\t#0x%"PRIx64"\n", imm16);
2790}
2791
2792OP4FUNC(op_smsubl, Rm, Ra, Rn, Rd)
2793{
2794	/* ALIAS: smnegl */
2795	if (Ra == 31) {
2796		PRINTF("smnegl\t%s, %s, %s\n",
2797		    ZREGNAME(1, Rd),
2798		    ZREGNAME(0, Rn),
2799		    ZREGNAME(0, Rm));
2800	} else {
2801		PRINTF("smsubl\t%s, %s, %s, %s\n",
2802		    ZREGNAME(1, Rd),
2803		    ZREGNAME(0, Rn),
2804		    ZREGNAME(0, Rm),
2805		    ZREGNAME(1, Ra));
2806	}
2807}
2808
2809OP3FUNC(op_smulh, Rm, Rn, Rd)
2810{
2811	PRINTF("smulh\t%s, %s, %s\n",
2812	    ZREGNAME(1, Rd),
2813	    ZREGNAME(1, Rn),
2814	    ZREGNAME(1, Rm));
2815}
2816
2817OP3FUNC(op_stlr, size, Rn, Rt)
2818{
2819	PRINTF("stlr\t%s, [%s]\n",
2820	    ZREGNAME(size, Rt),
2821	    SREGNAME(1, Rn));
2822}
2823
2824OP2FUNC(op_stlrb, Rn, Rt)
2825{
2826	PRINTF("stlrb\t%s, [%s]\n",
2827	    ZREGNAME(0, Rt),
2828	    SREGNAME(1, Rn));
2829}
2830
2831OP2FUNC(op_stlrh, Rn, Rt)
2832{
2833	PRINTF("stlrh\t%s, [%s]\n",
2834	    ZREGNAME(0, Rt),
2835	    SREGNAME(1, Rn));
2836}
2837
2838OP5FUNC(op_stlxp, size, Rs, Rt2, Rn, Rt)
2839{
2840	PRINTF("stlxp\t%s, %s, [%s]\n",
2841	    ZREGNAME(size, Rt),
2842	    ZREGNAME(size, Rt2),
2843	    SREGNAME(1, Rn));
2844}
2845
2846OP4FUNC(op_stlxr, size, Rs, Rn, Rt)
2847{
2848	PRINTF("stlxr\t%s, [%s]\n",
2849	    ZREGNAME(size, Rt),
2850	    SREGNAME(1, Rn));
2851}
2852
2853OP3FUNC(op_stlxrb, Rs, Rn, Rt)
2854{
2855	PRINTF("stlxrb\t%s, [%s]\n",
2856	    ZREGNAME(0, Rt),
2857	    SREGNAME(1, Rn));
2858}
2859
2860OP3FUNC(op_stlxrh, Rs, Rn, Rt)
2861{
2862	PRINTF("stlxrh\t%s, [%s]\n",
2863	    ZREGNAME(0, Rt),
2864	    SREGNAME(1, Rn));
2865}
2866
2867OP5FUNC(op_stnp, sf, imm7, Rt2, Rn, Rt)
2868{
2869	if (imm7 == 0) {
2870		PRINTF("stnp\t%s, %s, [%s]\n",
2871		    ZREGNAME(sf, Rt),
2872		    ZREGNAME(sf, Rt2),
2873		    SREGNAME(1, Rn));
2874	} else {
2875		PRINTF("stnp\t%s, %s, [%s,#%"PRId64"]\n",
2876		    ZREGNAME(sf, Rt),
2877		    ZREGNAME(sf, Rt2),
2878		    SREGNAME(1, Rn),
2879		    SignExtend(7, imm7, (sf == 0) ? 4 : 8));
2880	}
2881}
2882
2883OP5FUNC(op_stp_postidx, sf, imm7, Rt2, Rn, Rt)
2884{
2885	PRINTF("stp\t%s, %s, [%s],#%"PRId64"\n",
2886	    ZREGNAME(sf, Rt),
2887	    ZREGNAME(sf, Rt2),
2888	    SREGNAME(1, Rn),
2889	    SignExtend(7, imm7, (sf == 0) ? 4 : 8));
2890}
2891
2892OP5FUNC(op_stp_preidx, sf, imm7, Rt2, Rn, Rt)
2893{
2894	PRINTF("stp\t%s, %s, [%s,#%"PRId64"]!\n",
2895	    ZREGNAME(sf, Rt),
2896	    ZREGNAME(sf, Rt2),
2897	    SREGNAME(1, Rn),
2898	    SignExtend(7, imm7, (sf == 0) ? 4 : 8));
2899}
2900
2901OP5FUNC(op_stp_signed, sf, imm7, Rt2, Rn, Rt)
2902{
2903	if (imm7 == 0) {
2904		PRINTF("stp\t%s, %s, [%s]\n",
2905		    ZREGNAME(sf, Rt),
2906		    ZREGNAME(sf, Rt2),
2907		    SREGNAME(1, Rn));
2908	} else {
2909		PRINTF("stp\t%s, %s, [%s,#%"PRId64"]\n",
2910		    ZREGNAME(sf, Rt),
2911		    ZREGNAME(sf, Rt2),
2912		    SREGNAME(1, Rn),
2913		    SignExtend(7, imm7, (sf == 0) ? 4 : 8));
2914	}
2915}
2916
2917OP4FUNC(op_str_immpostidx, size, imm9, Rn, Rt)
2918{
2919	PRINTF("str\t%s, [%s],#%"PRId64"\n",
2920	    ZREGNAME(size, Rt),
2921	    SREGNAME(1, Rn),
2922	    SignExtend(9, imm9, 1));
2923}
2924
2925OP4FUNC(op_str_immpreidx, size, imm9, Rn, Rt)
2926{
2927	PRINTF("str\t%s, [%s,#%"PRId64"]!\n",
2928	    ZREGNAME(size, Rt),
2929	    SREGNAME(1, Rn),
2930	    SignExtend(9, imm9, 1));
2931}
2932
2933OP4FUNC(op_str_immunsign, size, imm12, Rn, Rt)
2934{
2935	if (imm12 == 0) {
2936		PRINTF("str\t%s, [%s]\n",
2937		    ZREGNAME(size, Rt),
2938		    SREGNAME(1, Rn));
2939	} else {
2940		PRINTF("str\t%s, [%s,#%"PRIu64"]\n",
2941		    ZREGNAME(size, Rt),
2942		    SREGNAME(1, Rn),
2943		    ZeroExtend(12, imm12, (size == 0) ? 4 : 8));
2944	}
2945}
2946
2947OP6FUNC(op_str_reg, size, Rm, option, shift, Rn, Rt)
2948{
2949	regoffset_x_common(di, pc, insn, size, Rm, option, shift, Rn, Rt,
2950	    "str");
2951}
2952
2953OP3FUNC(op_strb_immpostidx, imm9, Rn, Rt)
2954{
2955	PRINTF("strb\t%s, [%s],#%"PRId64"\n",
2956	    ZREGNAME(0, Rt),
2957	    SREGNAME(1, Rn),
2958	    SignExtend(9, imm9, 1));
2959}
2960
2961OP3FUNC(op_strb_immpreidx, imm9, Rn, Rt)
2962{
2963	PRINTF("strb\t%s, [%s,#%"PRId64"]!\n",
2964	    ZREGNAME(0, Rt),
2965	    SREGNAME(1, Rn),
2966	    SignExtend(9, imm9, 1));
2967}
2968
2969OP3FUNC(op_strb_immunsign, imm12, Rn, Rt)
2970{
2971	if (imm12 == 0) {
2972		PRINTF("strb\t%s, [%s]\n",
2973		    ZREGNAME(0, Rt),
2974		    SREGNAME(1, Rn));
2975	} else {
2976		PRINTF("strb\t%s, [%s,#%"PRIu64"]\n",
2977		    ZREGNAME(0, Rt),
2978		    SREGNAME(1, Rn),
2979		    ZeroExtend(12, imm12, 1));
2980	}
2981}
2982
2983OP5FUNC(op_strb_reg, Rm, option, shift, Rn, Rt)
2984{
2985	regoffset_b_common(di, pc, insn, Rm, option, shift, Rn, Rt, "strb");
2986}
2987
2988OP3FUNC(op_strh_immpostidx, imm9, Rn, Rt)
2989{
2990	PRINTF("strh\t%s, [%s],#%"PRId64"\n",
2991	    ZREGNAME(0, Rt),
2992	    SREGNAME(1, Rn),
2993	    SignExtend(9, imm9, 1));
2994}
2995
2996OP3FUNC(op_strh_immpreidx, imm9, Rn, Rt)
2997{
2998	PRINTF("strh\t%s, [%s,#%"PRId64"]!\n",
2999	    ZREGNAME(0, Rt),
3000	    SREGNAME(1, Rn),
3001	    SignExtend(9, imm9, 1));
3002}
3003
3004OP3FUNC(op_strh_immunsign, imm12, Rn, Rt)
3005{
3006	if (imm12 == 0) {
3007		PRINTF("strh\t%s, [%s]\n",
3008		    ZREGNAME(0, Rt),
3009		    SREGNAME(1, Rn));
3010	} else {
3011		PRINTF("strh\t%s, [%s,#%"PRId64"]\n",
3012		    ZREGNAME(0, Rt),
3013		    SREGNAME(1, Rn),
3014		    ZeroExtend(12, imm12, 2));
3015	}
3016}
3017
3018OP5FUNC(op_strh_reg, Rm, option, shift, Rn, Rt)
3019{
3020	regoffset_h_common(di, pc, insn, Rm, option, shift, Rn, Rt, 0, "strh");
3021}
3022
3023OP4FUNC(op_sttr, size, imm9, Rn, Rt)
3024{
3025	if (imm9 == 0) {
3026		PRINTF("sttr\t%s, [%s]\n",
3027		    ZREGNAME(size, Rt),
3028		    SREGNAME(1, Rn));
3029	} else {
3030		PRINTF("sttr\t%s, [%s,#%"PRId64"]\n",
3031		    ZREGNAME(size, Rt),
3032		    SREGNAME(1, Rn),
3033		    SignExtend(9, imm9, 1));
3034	}
3035}
3036
3037OP3FUNC(op_sttrb, imm9, Rn, Rt)
3038{
3039	if (imm9 == 0) {
3040		PRINTF("sttrb\t%s, [%s]\n",
3041		    ZREGNAME(0, Rt),
3042		    SREGNAME(1, Rn));
3043	} else {
3044		PRINTF("sttrb\t%s, [%s,#%"PRId64"]\n",
3045		    ZREGNAME(0, Rt),
3046		    SREGNAME(1, Rn),
3047		    SignExtend(9, imm9, 1));
3048	}
3049}
3050
3051OP3FUNC(op_sttrh, imm9, Rn, Rt)
3052{
3053	if (imm9 == 0) {
3054		PRINTF("sttrh\t%s, [%s]\n",
3055		    ZREGNAME(0, Rt),
3056		    SREGNAME(1, Rn));
3057	} else {
3058		PRINTF("sttrh\t%s, [%s,#%"PRId64"]\n",
3059		    ZREGNAME(0, Rt),
3060		    SREGNAME(1, Rn),
3061		    SignExtend(9, imm9, 1));
3062	}
3063}
3064
3065OP4FUNC(op_stur, size, imm9, Rn, Rt)
3066{
3067	if (imm9 == 0) {
3068		PRINTF("stur\t%s, [%s]\n",
3069		    ZREGNAME(size, Rt),
3070		    SREGNAME(1, Rn));
3071	} else {
3072		PRINTF("stur\t%s, [%s,#%"PRId64"]\n",
3073		    ZREGNAME(size, Rt),
3074		    SREGNAME(1, Rn),
3075		    SignExtend(9, imm9, 1));
3076	}
3077}
3078
3079OP3FUNC(op_sturb, imm9, Rn, Rt)
3080{
3081	if (imm9 == 0) {
3082		PRINTF("sturb\t%s, [%s]\n",
3083		    ZREGNAME(0, Rt),
3084		    SREGNAME(1, Rn));
3085	} else {
3086		PRINTF("sturb\t%s, [%s,#%"PRId64"]\n",
3087		    ZREGNAME(0, Rt),
3088		    SREGNAME(1, Rn),
3089		    SignExtend(9, imm9, 1));
3090	}
3091}
3092
3093OP3FUNC(op_sturh, imm9, Rn, Rt)
3094{
3095	if (imm9 == 0) {
3096		PRINTF("sturh\t%s, [%s]\n",
3097		    ZREGNAME(0, Rt),
3098		    SREGNAME(1, Rn));
3099	} else {
3100		PRINTF("sturh\t%s, [%s,#%"PRId64"]\n",
3101		    ZREGNAME(0, Rt),
3102		    SREGNAME(1, Rn),
3103		    SignExtend(9, imm9, 1));
3104	}
3105}
3106
3107OP5FUNC(op_stxp, size, Rs, Rt2, Rn, Rt)
3108{
3109	PRINTF("stxp\t%s, %s, [%s]\n",
3110	    ZREGNAME(size, Rt),
3111	    ZREGNAME(size, Rt2),
3112	    SREGNAME(1, Rn));
3113}
3114
3115OP4FUNC(op_stxr, size, Rs, Rn, Rt)
3116{
3117	PRINTF("stxr\t%s, %s, [%s]\n",
3118	    ZREGNAME(0, Rs),
3119	    ZREGNAME(size, Rt),
3120	    SREGNAME(1, Rn));
3121}
3122
3123OP3FUNC(op_stxrb, Rs, Rn, Rt)
3124{
3125	PRINTF("stxrb\t%s, %s, [%s]\n",
3126	    ZREGNAME(0, Rs),
3127	    ZREGNAME(0, Rt),
3128	    SREGNAME(1, Rn));
3129}
3130
3131OP3FUNC(op_stxrh, Rs, Rn, Rt)
3132{
3133	PRINTF("stxrh\t%s, %s, [%s]\n",
3134	    ZREGNAME(0, Rs),
3135	    ZREGNAME(0, Rt),
3136	    SREGNAME(1, Rn));
3137}
3138
3139OP6FUNC(op_sub_extreg, sf, Rm, option, imm3, Rn, Rd)
3140{
3141	extendreg_common(di, pc, insn, sf, Rm, option, imm3, Rn, Rd,
3142	    "sub", NULL);
3143}
3144
3145OP5FUNC(op_sub_imm, sf, shift, imm12, Rn, Rd)
3146{
3147	if (shift & 2) {
3148		UNDEFINED(pc, insn, "illegal shift");
3149		return;
3150	}
3151
3152	PRINTF("sub\t%s, %s, #0x%"PRIx64"%s\n",
3153	    SREGNAME(sf, Rd),
3154	    SREGNAME(sf, Rn),
3155	    ZeroExtend(12, imm12, 1),
3156	    SHIFTOP2(shift, "", ", lsl #12"));
3157}
3158
3159OP1FUNC(op_svc, imm16)
3160{
3161	PRINTF("svc\t#0x%"PRIx64"\n",
3162	    imm16);
3163}
3164
3165OP5FUNC(op_sysl, op1, CRn, CRm, op2, Rt)
3166{
3167	PRINTF("sysl\t%s, #%"PRIu64", %s, %s, #%"PRIu64"\n",
3168	    ZREGNAME(1, Rt),
3169	    op1,
3170	    CREGNAME(CRn),
3171	    CREGNAME(CRm),
3172	    op2);
3173}
3174
3175OP4FUNC(op_tbnz, b5, b40, imm14, Rt)
3176{
3177	uint64_t bit = (b5 << 5) + b40;
3178
3179	PRINTF("tbnz\t%s, #%"PRIu64", ",
3180	    ZREGNAME(b5, Rt),
3181	    bit);
3182	PRINTADDR(SignExtend(14, imm14, 4) + pc);
3183	PRINTF("\n");
3184}
3185
3186OP4FUNC(op_tbz, b5, b40, imm14, Rt)
3187{
3188	uint64_t bit = (b5 << 5) + b40;
3189
3190	PRINTF("tbz\t%s, #%"PRIu64", ",
3191	    ZREGNAME(b5, Rt),
3192	    bit);
3193	PRINTADDR(SignExtend(14, imm14, 4) + pc);
3194	PRINTF("\n");
3195}
3196
3197OP4FUNC(op_udiv, sf, Rm, Rn, Rd)
3198{
3199	PRINTF("udiv\t%s, %s, %s\n",
3200	    ZREGNAME(sf, Rd),
3201	    ZREGNAME(sf, Rn),
3202	    ZREGNAME(sf, Rm));
3203}
3204
3205OP4FUNC(op_umaddl, Rm, Ra, Rn, Rd)
3206{
3207	/* ALIAS: umull */
3208	if (Ra == 31) {
3209		PRINTF("umull\t%s, %s, %s\n",
3210		    ZREGNAME(1, Rd),
3211		    ZREGNAME(0, Rn),
3212		    ZREGNAME(0, Rm));
3213	} else {
3214		PRINTF("umaddl\t%s, %s, %s, %s\n",
3215		    ZREGNAME(1, Rd),
3216		    ZREGNAME(0, Rn),
3217		    ZREGNAME(0, Rm),
3218		    ZREGNAME(1, Ra));
3219	}
3220}
3221
3222OP4FUNC(op_umsubl, Rm, Ra, Rn, Rd)
3223{
3224	/* ALIAS: umnegl */
3225	if (Ra == 31) {
3226		PRINTF("umnegl\t%s, %s, %s\n",
3227		    ZREGNAME(1, Rd),
3228		    ZREGNAME(1, Rn),
3229		    ZREGNAME(1, Rm));
3230	} else {
3231		PRINTF("umsubl\t%s, %s, %s, %s\n",
3232		    ZREGNAME(1, Rd),
3233		    ZREGNAME(1, Rn),
3234		    ZREGNAME(1, Rm),
3235		    ZREGNAME(1, Ra));
3236	}
3237}
3238
3239OP3FUNC(op_umulh, Rm, Rn, Rd)
3240{
3241	PRINTF("umulh\t%s, %s, %s\n",
3242	    ZREGNAME(1, Rd),
3243	    ZREGNAME(1, Rn),
3244	    ZREGNAME(1, Rm));
3245}
3246
3247/*
3248 * load/store SIMD instructions
3249 */
3250OP6FUNC(op_simd_ldstnp, opc, l, imm7, Rt2, Rn, Rt)
3251{
3252	const char *op = (l == 0) ? "stnp" : "ldnp";
3253	const int regsz = (opc & 3) + 2;
3254
3255	if (opc == 3) {
3256		UNDEFINED(pc, insn, "illegal opc");
3257		return;
3258	}
3259
3260	if (imm7 == 0) {
3261		PRINTF("%s\t%s, %s, [%s]\n",
3262		    op,
3263		    FREGNAME(regsz, Rt),
3264		    FREGNAME(regsz, Rt2),
3265		    SREGNAME(1, Rn));
3266	} else {
3267		PRINTF("%s\t%s, %s, [%s,#%"PRId64"]\n",
3268		    op,
3269		    FREGNAME(regsz, Rt),
3270		    FREGNAME(regsz, Rt2),
3271		    SREGNAME(1, Rn),
3272		    SignExtend(7, imm7, (4 << opc)));
3273	}
3274}
3275
3276OP6FUNC(op_simd_ldstp_postidx, opc, l, imm7, Rt2, Rn, Rt)
3277{
3278	const char *op = (l == 0) ? "stp" : "ldp";
3279	const int regsz = (opc & 3) + 2;
3280
3281	PRINTF("%s\t%s, %s, [%s],#%"PRId64"\n",
3282	    op,
3283	    FREGNAME(regsz, Rt),
3284	    FREGNAME(regsz, Rt2),
3285	    SREGNAME(1, Rn),
3286	    SignExtend(7, imm7, (4 << opc)));
3287}
3288
3289OP6FUNC(op_simd_ldstp_preidx, opc, l, imm7, Rt2, Rn, Rt)
3290{
3291	const char *op = (l == 0) ? "stp" : "ldp";
3292	const int regsz = (opc & 3) + 2;
3293
3294	PRINTF("%s\t%s, %s, [%s,#%"PRId64"]!\n",
3295	    op,
3296	    FREGNAME(regsz, Rt),
3297	    FREGNAME(regsz, Rt2),
3298	    SREGNAME(1, Rn),
3299	    SignExtend(7, imm7, (4 << opc)));
3300}
3301
3302OP6FUNC(op_simd_ldstp_signed, opc, l, imm7, Rt2, Rn, Rt)
3303{
3304	const char *op = (l == 0) ? "stp" : "ldp";
3305	const int regsz = (opc & 3) + 2;
3306
3307	if (opc == 3) {
3308		UNDEFINED(pc, insn, "illegal opc");
3309		return;
3310	}
3311
3312	if (imm7 == 0) {
3313		PRINTF("%s\t%s, %s, [%s]\n",
3314		    op,
3315		    FREGNAME(regsz, Rt),
3316		    FREGNAME(regsz, Rt2),
3317		    SREGNAME(1, Rn));
3318	} else {
3319		PRINTF("%s\t%s, %s, [%s,#%"PRId64"]\n",
3320		    op,
3321		    FREGNAME(regsz, Rt),
3322		    FREGNAME(regsz, Rt2),
3323		    SREGNAME(1, Rn),
3324		    SignExtend(7, imm7, (4 << opc)));
3325	}
3326}
3327
3328static inline int
3329simd_ldstr_regsz(uint64_t size, uint64_t opc)
3330{
3331	if ((opc & 2) == 0)
3332		return size;
3333	if (size == 0)
3334		return 4;
3335	return -1;
3336}
3337
3338OP5FUNC(op_simd_ldstr_immpostidx, size, opc, imm9, Rn, Rt)
3339{
3340	const char *op = ((opc & 1) == 0) ? "str" : "ldr";
3341	int regsz;
3342
3343	if ((regsz = simd_ldstr_regsz(size, opc)) < 0) {
3344		UNDEFINED(pc, insn, "illegal size/opc");
3345		return;
3346	}
3347
3348	PRINTF("%s\t%s, [%s],#%"PRId64"\n",
3349	    op,
3350	    FREGNAME(regsz, Rt),
3351	    SREGNAME(1, Rn),
3352	    SignExtend(9, imm9, 1));
3353}
3354
3355OP5FUNC(op_simd_ldstr_immpreidx, size, opc, imm9, Rn, Rt)
3356{
3357	const char *op = ((opc & 1) == 0) ? "str" : "ldr";
3358	int regsz;
3359
3360	if ((regsz = simd_ldstr_regsz(size, opc)) < 0) {
3361		UNDEFINED(pc, insn, "illegal size/opc");
3362		return;
3363	}
3364
3365	PRINTF("%s\t%s, [%s,#%"PRId64"]!\n",
3366	    op,
3367	    FREGNAME(regsz, Rt),
3368	    SREGNAME(1, Rn),
3369	    SignExtend(9, imm9, 1));
3370}
3371
3372OP5FUNC(op_simd_ldstr_immunsign, size, opc, imm12, Rn, Rt)
3373{
3374	const char *op = ((opc & 1) == 0) ? "str" : "ldr";
3375	int regsz;
3376
3377	if ((regsz = simd_ldstr_regsz(size, opc)) < 0) {
3378		UNDEFINED(pc, insn, "illegal size/opc");
3379		return;
3380	}
3381
3382	if (imm12 == 0) {
3383		PRINTF("%s\t%s, [%s]\n",
3384		    op,
3385		    FREGNAME(regsz, Rt),
3386		    SREGNAME(1, Rn));
3387	} else {
3388		PRINTF("%s\t%s, [%s,#%"PRIu64"]\n",
3389		    op,
3390		    FREGNAME(regsz, Rt),
3391		    SREGNAME(1, Rn),
3392		    ZeroExtend(12, imm12, 1 << regsz));
3393	}
3394}
3395
3396OP7FUNC(op_simd_ldstr_reg, size, opc, Rm, option, S, Rn, Rt)
3397{
3398	const char *op = ((opc & 1) == 0) ? "str" : "ldr";
3399	int regsz, r;
3400
3401	if ((regsz = simd_ldstr_regsz(size, opc)) < 0) {
3402		UNDEFINED(pc, insn, "illegal size/opc");
3403		return;
3404	}
3405
3406	if ((r = regoffset_option_to_r(option)) < 0) {
3407		UNDEFINED(pc, insn, "illegal option");
3408		return;
3409	}
3410
3411	if (S == 0) {
3412		PRINTF("%s\t%s, [%s,%s%s]\n",
3413		    op,
3414		    FREGNAME(regsz, Rt),
3415		    SREGNAME(1, Rn),
3416		    ZREGNAME(r, Rm),
3417		    SHIFTOP8(option,
3418		        "", "", ",uxtw", "", "", "", ",sxtw", ",sxtx"));
3419	} else {
3420		u_int amount = regsz;
3421		PRINTF("%s\t%s, [%s,%s,%s #%u]\n",
3422		    op,
3423		    FREGNAME(regsz, Rt),
3424		    SREGNAME(1, Rn),
3425		    ZREGNAME(r, Rm),
3426		    SHIFTOP8(option,
3427		        "", "", "uxtw", "lsl", "", "", "sxtw", "sxtx"),
3428		    amount);
3429	}
3430}
3431
3432OP4FUNC(op_simd_aes, m, d, Rn, Rt)
3433{
3434	const char *aesop[2][2] = {
3435		{	"aese",  "aesd",	},
3436		{	"aesmc", "aesimc"	}
3437	};
3438
3439	PRINTF("%s\t%s.16b, %s.16b\n",
3440	    aesop[m & 1][d & 1],
3441	    VREGNAME(Rn),
3442	    VREGNAME(Rt));
3443}
3444
3445OP4FUNC(op_simd_sha_reg3, Rm, op, Rn, Rd)
3446{
3447	const char *shaop[8] = {
3448		"sha1c",   "sha1p",    "sha1m",     "sha1su0",
3449		"sha256h", "sha256h2", "sha256su1", NULL
3450	};
3451
3452	switch (op) {
3453	case 0:
3454	case 1:
3455	case 2:
3456		PRINTF("%s\t%s, %s, %s.4s\n",
3457		    shaop[op],
3458		    FREGNAME(FREGSZ_Q, Rd),
3459		    FREGNAME(FREGSZ_S, Rn),
3460		    VREGNAME(Rm));
3461		break;
3462
3463	case 4:
3464	case 5:
3465		PRINTF("%s\t%s, %s, %s.4s\n",
3466		    shaop[op],
3467		    FREGNAME(FREGSZ_Q, Rd),
3468		    FREGNAME(FREGSZ_Q, Rn),
3469		    VREGNAME(Rm));
3470		break;
3471
3472	case 3:
3473	case 6:
3474		PRINTF("%s\t%s.4s, %s.4s, %s.4s\n",
3475		    shaop[op],
3476		    VREGNAME(Rd),
3477		    VREGNAME(Rn),
3478		    VREGNAME(Rm));
3479		break;
3480
3481	default:
3482		UNDEFINED(pc, insn, "illegal sha operation");
3483		break;
3484	}
3485}
3486
3487OP3FUNC(op_simd_sha_reg2, op, Rn, Rd)
3488{
3489	const char *shaop[4] = {
3490		"sha1h", "sha1su1", "sha256su0", NULL
3491	};
3492
3493	switch (op) {
3494	case 0:
3495		PRINTF("%s\t%s, %s\n",
3496		    shaop[op],
3497		    FREGNAME(FREGSZ_S, Rd),
3498		    FREGNAME(FREGSZ_S, Rn));
3499		break;
3500	case 1:
3501	case 2:
3502		PRINTF("%s\t%s.4s, %s.4s\n",
3503		    shaop[op],
3504		    VREGNAME(Rd),
3505		    VREGNAME(Rn));
3506		break;
3507	default:
3508		UNDEFINED(pc, insn, "illegal sha operation");
3509		break;
3510	}
3511}
3512
3513OP4FUNC(op_simd_sha512_reg3, Rm, op, Rn, Rd)
3514{
3515	const char *shaop[4] = {
3516		"sha512h", "sha512h2", "sha512su1", "rax1"
3517	};
3518
3519	switch (op) {
3520	case 0:
3521	case 1:
3522		PRINTF("%s\t%s, %s, %s.2d\n",
3523		    shaop[op],
3524		    FREGNAME(FREGSZ_Q, Rd),
3525		    FREGNAME(FREGSZ_Q, Rn),
3526		    VREGNAME(Rm));
3527		break;
3528	case 2:
3529	case 3:
3530		PRINTF("%s\t%s.2d, %s,.2d %s.2d\n",
3531		    shaop[op],
3532		    VREGNAME(Rd),
3533		    VREGNAME(Rn),
3534		    VREGNAME(Rm));
3535		break;
3536	}
3537}
3538
3539OP3FUNC(op_simd_sha512_reg2, op, Rn, Rd)
3540{
3541	const char *shaop[4] = {
3542		"sha512su0", "sm4e", NULL, NULL
3543	};
3544
3545	switch (op) {
3546	case 0:
3547	case 1:
3548		PRINTF("%s\t%s.2d, %s.2d\n",
3549		    shaop[op],
3550		    VREGNAME(Rd),
3551		    VREGNAME(Rn));
3552		break;
3553	default:
3554		UNDEFINED(pc, insn, "illegal sha512 operation");
3555		break;
3556	}
3557}
3558
3559OP5FUNC(op_simd_pmull, q, size, Rm, Rn, Rd)
3560{
3561	const char *op = (q == 0) ? "pmull" : "pmull2";
3562	const char *regspec_Ta[4] = {
3563		"8h", NULL, NULL, "1q"
3564	};
3565	const char *regspec_Tb[8] = {
3566		"8b", "16b", NULL, NULL,
3567		NULL, NULL, "1d", "2d"
3568	};
3569
3570	if ((regspec_Ta[size & 3] != NULL) &&
3571	    (regspec_Tb[((size & 3) << 1) + (q & 1)] != NULL)) {
3572		PRINTF("%s\t%s.%s, %s.%s, %s.%s\n",
3573		    op,
3574		    VREGNAME(Rd), regspec_Ta[size & 3],
3575		    VREGNAME(Rn), regspec_Tb[((size & 3) << 1) + (q & 1)],
3576		    VREGNAME(Rd), regspec_Tb[((size & 3) << 1) + (q & 1)]);
3577	} else {
3578		UNDEFINED(pc, insn, "illegal pmull size");
3579	}
3580}
3581
3582OP1FUNC(op_eretaa, m)
3583{
3584	if (m == 0)
3585		PRINTF("eretaa\n");
3586	else
3587		PRINTF("eretab\n");
3588
3589}
3590
3591OP1FUNC(op_retaa, m)
3592{
3593	if (m == 0)
3594		PRINTF("retaa\n");
3595	else
3596		PRINTF("retab\n");
3597}
3598
3599OP4FUNC(op_blraa, z, m, Rn, Rm)
3600{
3601	if (z == 0) {
3602		if (Rm != 31) {
3603			UNDEFINED(pc, insn, "undefined");
3604		} else {
3605			PRINTF("%s\t%s\n",
3606			    SHIFTOP2(m, "blraaz", "blrabz"),
3607			    SREGNAME(1, Rn));
3608		}
3609	} else {
3610		PRINTF("%s\t%s, %s\n",
3611		    SHIFTOP2(m, "blraa", "blrab"),
3612		    SREGNAME(1, Rn),
3613		    SREGNAME(1, Rm));
3614	}
3615}
3616
3617OP4FUNC(op_braa, z, m, Rn, Rm)
3618{
3619	if (z == 0) {
3620		if (Rm != 31) {
3621			UNDEFINED(pc, insn, "undefined");
3622		} else {
3623			PRINTF("%s\t%s\n",
3624			    SHIFTOP2(m, "braaz", "brabz"),
3625			    SREGNAME(1, Rn));
3626		}
3627	} else {
3628		PRINTF("%s\t%s, %s\n",
3629		    SHIFTOP2(m, "braa", "brab"),
3630		    SREGNAME(1, Rn),
3631		    SREGNAME(1, Rm));
3632	}
3633}
3634
3635OP4FUNC(op_pacda, z, m, Rn, Rd)
3636{
3637	if (z != 0) {
3638		if (Rn != 31) {
3639			UNDEFINED(pc, insn, "undefined");
3640		} else {
3641			PRINTF("%s\t%s\n",
3642			    SHIFTOP2(m, "pacdza", "pacdzb"),
3643			    SREGNAME(1, Rd));
3644		}
3645	} else {
3646		PRINTF("%s\t%s, %s\n",
3647		    SHIFTOP2(m, "pacda", "pacdb"),
3648		    ZREGNAME(1, Rd),
3649		    SREGNAME(1, Rn));
3650	}
3651}
3652
3653OP4FUNC(op_pacia, z, m, Rn, Rd)
3654{
3655	if (z != 0) {
3656		if (Rn != 31) {
3657			UNDEFINED(pc, insn, "undefined");
3658		} else {
3659			PRINTF("%s\t%s\n",
3660			    SHIFTOP2(m, "paciza", "pacizb"),
3661			    SREGNAME(1, Rd));
3662		}
3663	} else {
3664		PRINTF("%s\t%s, %s\n",
3665		    SHIFTOP2(m, "pacia", "pacib"),
3666		    ZREGNAME(1, Rd),
3667		    SREGNAME(1, Rn));
3668	}
3669}
3670
3671OP3FUNC(op_pacga, Rm, Rn, Rd)
3672{
3673	PRINTF("pacga\t%s, %s, %s\n",
3674	    ZREGNAME(1, Rd),
3675	    ZREGNAME(1, Rn),
3676	    SREGNAME(1, Rm));
3677}
3678
3679OP1FUNC(op_xpaci, Rd)
3680{
3681	PRINTF("xpaci\t%s\n",
3682	    ZREGNAME(1, Rd));
3683}
3684
3685OP1FUNC(op_xpacd, Rd)
3686{
3687	PRINTF("xpacd\t%s\n",
3688	    ZREGNAME(1, Rd));
3689}
3690
3691OP0FUNC(op_xpaclri)
3692{
3693	PRINTF("xpaclri\n");
3694}
3695
3696/*
3697 * SIMD instructions are not supported except some insns.
3698 * They are disassembled as '.insn 0xXXXXXXXX'.
3699 */
3700struct bitpos {
3701	uint8_t pos;
3702	uint8_t width;
3703};
3704
3705struct insn_info {
3706	uint32_t mask;
3707	uint32_t pattern;
3708#define INSN_MAXARG	8
3709	struct bitpos bitinfo[INSN_MAXARG];
3710	OPFUNC_DECL(void (*opfunc),,,,,,,,);
3711};
3712
3713/* define code format  { {bitpos, bitwidth}, ... (maximum 8 args) } */
3714#define FMT_NOARG			\
3715	{{ 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3716#define FMT_RD				\
3717	{{ 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3718#define FMT_RN				\
3719	{{ 5, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3720#define FMT_RN_RT			\
3721	{{ 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3722#define FMT_M				\
3723	{{10, 1}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3724#define FMT_CRM				\
3725	{{ 8, 4}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3726#define FMT_CRM_OP2			\
3727	{{ 8, 4}, { 5, 3}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3728#define FMT_OP2_RN_RD			\
3729	{{10, 2}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3730#define FMT_Z_M_RN_RD			\
3731	{{13, 1}, {10, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3732#define FMT_M_D_RN_RD			\
3733	{{13, 1}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3734#define FMT_OP3_RN_RD			\
3735	{{12, 3}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3736#define FMT_OP1_CRM_OP2			\
3737	{{16, 3}, { 8, 4}, { 5, 3}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3738#define FMT_OP1_CRN_CRM_OP2_RT		\
3739	{{16, 3}, {12, 4}, { 8, 4}, { 5, 3}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
3740#define FMT_RM_RN_RD			\
3741	{{16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3742#define FMT_RS_RN_RT			\
3743	{{16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3744#define FMT_RM_OP2_RN_RD		\
3745	{{16, 5}, {10, 2}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3746#define FMT_RM_OP_RN_RD			\
3747	{{16, 5}, {12, 3}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3748#define FMT_RM_RA_RN_RD			\
3749	{{16, 5}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3750#define FMT_IMM9_RN_RT			\
3751	{{12, 9}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3752#define FMT_RM_OPT_SHIFT_RN_RT		\
3753	{{16, 5}, {13, 3}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
3754#define FMT_IMM16			\
3755	{{ 5,16}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3756#define FMT_IMM16_LL			\
3757	{{ 5,16}, { 0, 2}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3758#define FMT_OP0_OP1_CRN_CRM_OP2_RT	\
3759	{{19, 2}, {16, 3}, {12, 4}, { 8, 4}, { 5, 3}, { 0, 5}, { 0, 0}, { 0, 0}}
3760#define FMT_IMM7_RT2_RN_RT		\
3761	{{15, 7}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3762#define FMT_IMM12_RN_RT			\
3763	{{10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3764#define FMT_OPC_IMM9_RN_RT		\
3765	{{22, 1}, {12, 9}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3766#define FMT_OPC_RM_OPT_SHIFT_RN_RT	\
3767	{{22, 1}, {16, 5}, {13, 3}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
3768#define FMT_OPC_IMM12_RN_RT		\
3769	{{22, 1}, {10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3770#define FMT_IMM19_COND			\
3771	{{ 5,19}, { 0, 4}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3772#define FMT_IMM19_RT			\
3773	{{ 5,19}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3774#define FMT_Z_M_RN_RM			\
3775	{{24, 1}, {10, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3776#define FMT_IMM26			\
3777	{{ 0,26}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3778#define FMT_SIZE_RN_RT			\
3779	{{30, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3780#define FMT_SIZE_RT2_RN_RT		\
3781	{{30, 1}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3782#define FMT_SIZE_RS_RN_RT		\
3783	{{30, 1}, {16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3784#define FMT_SIZE_RS_RT2_RN_RT		\
3785	{{30, 1}, {16, 5}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
3786#define FMT_SIZE_IMM9_RN_RT		\
3787	{{30, 1}, {12, 9}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3788#define FMT_SIZE_RM_OPT_SHIFT_RN_RT	\
3789	{{30, 1}, {16, 5}, {13, 3}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
3790#define FMT_SIZE_IMM12_RN_RT		\
3791	{{30, 1}, {10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3792#define FMT_Q_SIZE_RM_RN_RD		\
3793	{{30, 1}, {22, 2}, {16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
3794#define FMT_SIZE_IMM19_RT		\
3795	{{30, 1}, { 5,19}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3796#define FMT_IMMLO_IMMHI_RD		\
3797	{{29, 2}, { 5,19}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3798#define FMT_SF_RN_RD			\
3799	{{31, 1}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3800#define FMT_SF_OPC_RN_RD		\
3801	{{31, 1}, {10, 2}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3802#define FMT_SF_RM_RN_RD			\
3803	{{31, 1}, {16, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3804#define FMT_SF_RM_SZ_RN_RD		\
3805	{{31, 1}, {16, 5}, {10, 2}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
3806#define FMT_SF_RM_RA_RN_RD		\
3807	{{31, 1}, {16, 5}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
3808#define FMT_SF_IMM5_COND_RN_NZCV	\
3809	{{31, 1}, {16, 5}, {12, 4}, { 5, 5}, { 0, 4}, { 0, 0}, { 0, 0}, { 0, 0}}
3810#define FMT_SF_RM_COND_RN_NZCV		\
3811	{{31, 1}, {16, 5}, {12, 4}, { 5, 5}, { 0, 4}, { 0, 0}, { 0, 0}, { 0, 0}}
3812#define FMT_SF_RM_COND_RN_RD		\
3813	{{31, 1}, {16, 5}, {12, 4}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
3814#define FMT_SF_RM_OPT_IMM3_RN_RD	\
3815	{{31, 1}, {16, 5}, {13, 3}, {10, 3}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
3816#define FMT_SF_RM_OP_IMM3_RN_RD		\
3817	{{31, 1}, {16, 5}, {13, 3}, {10, 3}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
3818#define FMT_SF_IMM7_RT2_RN_RT		\
3819	{{31, 1}, {15, 7}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
3820#define FMT_SF_N_RM_IMM6_RN_RD		\
3821	{{31, 1}, {22, 1}, {16, 5}, {10, 6}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
3822#define FMT_SF_N_RM_IMMS_RN_RD		\
3823	{{31, 1}, {22, 1}, {16, 5}, {10, 6}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
3824#define FMT_SF_HW_IMM16_RD		\
3825	{{31, 1}, {21, 2}, { 5,16}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3826#define FMT_SF_N_IMMR_IMMS_RN_RD	\
3827	{{31, 1}, {22, 1}, {16, 6}, {10, 6}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
3828#define FMT_SF_SHIFT_RM_IMM6_RN_RD	\
3829	{{31, 1}, {22, 2}, {16, 5}, {10, 6}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
3830#define FMT_SF_SHIFT_IMM12_RN_RD	\
3831	{{31, 1}, {22, 2}, {10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
3832#define FMT_SF_IMM19_RT			\
3833	{{31, 1}, { 5,19}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3834#define FMT_B5_B40_IMM14_RT		\
3835	{{31, 1}, {19, 5}, { 5,14}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}}
3836#define FMT_OPC_L_IMM7_RT2_RN_RT	\
3837	{{30, 2}, {22, 1}, {15, 7}, {10, 5}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}}
3838#define FMT_SIZE_OPC_IMM9_RN_RT		\
3839	{{30, 2}, {22, 2}, {12, 9}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
3840#define FMT_SIZE_OPC_RM_OPT_S_RN_RT	\
3841	{{30, 2}, {22, 2}, {16, 5}, {13, 3}, {12, 1}, { 5, 5}, { 0, 5}, { 0, 0}}
3842#define FMT_SIZE_OPC_IMM12_RN_RT	\
3843	{{30, 2}, {22, 2}, {10,12}, { 5, 5}, { 0, 5}, { 0, 0}, { 0, 0}, { 0, 0}}
3844
3845static const struct insn_info insn_tables[] = {
3846 /* mask,      pattern,    opcode format,               opfunc             */
3847 /* ---------  ----------  ---------------------------  ------------------ */
3848 { 0xffffffff, 0xd6bf03e0, FMT_NOARG,                   op_drps },
3849 { 0xffffffff, 0xd69f03e0, FMT_NOARG,                   op_eret },
3850 { 0xffffffff, 0xd50320ff, FMT_NOARG,                   op_xpaclri },
3851 { 0xffffffe0, 0xdac143e0, FMT_RD,                      op_xpaci },
3852 { 0xffffffe0, 0xdac147e0, FMT_RD,                      op_xpacd },
3853 { 0xfffffc1f, 0xd63f0000, FMT_RN,                      op_blr },
3854 { 0xfffffc1f, 0xd61f0000, FMT_RN,                      op_br },
3855 { 0xfffffc1f, 0xd65f0000, FMT_RN,                      op_ret },
3856 { 0xfffffc00, 0x08dffc00, FMT_RN_RT,                   op_ldarb },
3857 { 0xfffffc00, 0x48dffc00, FMT_RN_RT,                   op_ldarh },
3858 { 0xfffffc00, 0x085ffc00, FMT_RN_RT,                   op_ldaxrb },
3859 { 0xfffffc00, 0x485ffc00, FMT_RN_RT,                   op_ldaxrh },
3860 { 0xfffffc00, 0x085f7c00, FMT_RN_RT,                   op_ldxrb },
3861 { 0xfffffc00, 0x485f7c00, FMT_RN_RT,                   op_ldxrh },
3862 { 0xfffffc00, 0x089ffc00, FMT_RN_RT,                   op_stlrb },
3863 { 0xfffffc00, 0x489ffc00, FMT_RN_RT,                   op_stlrh },
3864 { 0xfffffbff, 0xd69f0bff, FMT_M,                       op_eretaa },
3865 { 0xfffffbff, 0xd65f0bff, FMT_M,                       op_retaa },
3866 { 0xfffff0ff, 0xd503305f, FMT_CRM,                     op_clrex },
3867 { 0xfffff0ff, 0xd50330bf, FMT_CRM,                     op_dmb },
3868 { 0xfffff0ff, 0xd503309f, FMT_CRM,                     op_dsb },
3869 { 0xfffff0ff, 0xd50330df, FMT_CRM,                     op_isb },
3870 { 0xfffff01f, 0xd503201f, FMT_CRM_OP2,                 op_hint },
3871 { 0xfffff000, 0xcec08000, FMT_OP2_RN_RD,               op_simd_sha512_reg2 },
3872 { 0xffffd800, 0xdac10800, FMT_Z_M_RN_RD,               op_pacda },
3873 { 0xffffd800, 0xdac10000, FMT_Z_M_RN_RD,               op_pacia },
3874 { 0xffffcc00, 0x4e284800, FMT_M_D_RN_RD,               op_simd_aes },
3875 { 0xffff8c00, 0x5e280800, FMT_OP3_RN_RD,               op_simd_sha_reg2 },
3876 { 0xfff8f01f, 0xd500401f, FMT_OP1_CRM_OP2,             op_msr_imm },
3877 { 0xfff80000, 0xd5080000, FMT_OP1_CRN_CRM_OP2_RT,      op_sys },
3878 { 0xfff80000, 0xd5280000, FMT_OP1_CRN_CRM_OP2_RT,      op_sysl },
3879 { 0xffe0fc00, 0x9b407c00, FMT_RM_RN_RD,                op_smulh },
3880 { 0xffe0fc00, 0x0800fc00, FMT_RS_RN_RT,                op_stlxrb },
3881 { 0xffe0fc00, 0x4800fc00, FMT_RS_RN_RT,                op_stlxrh },
3882 { 0xffe0fc00, 0x08007c00, FMT_RS_RN_RT,                op_stxrb },
3883 { 0xffe0fc00, 0x48007c00, FMT_RS_RN_RT,                op_stxrh },
3884 { 0xffe0fc00, 0x9bc07c00, FMT_RM_RN_RD,                op_umulh },
3885 { 0xffe0fc00, 0x9ac03000, FMT_RM_RN_RD,                op_pacga },
3886 { 0xffe0f000, 0xce608000, FMT_RM_OP2_RN_RD,            op_simd_sha512_reg3 },
3887 { 0xffe08c00, 0x5e000000, FMT_RM_OP_RN_RD,             op_simd_sha_reg3 },
3888 { 0xffe08000, 0x9b208000, FMT_RM_RA_RN_RD,             op_smsubl },
3889 { 0xffe08000, 0x9ba08000, FMT_RM_RA_RN_RD,             op_umsubl },
3890 { 0xffe08000, 0x9b200000, FMT_RM_RA_RN_RD,             op_smaddl },
3891 { 0xffe08000, 0x9ba00000, FMT_RM_RA_RN_RD,             op_umaddl },
3892 { 0xffe00c00, 0x38400400, FMT_IMM9_RN_RT,              op_ldrb_immpostidx },
3893 { 0xffe00c00, 0x38400c00, FMT_IMM9_RN_RT,              op_ldrb_immpreidx },
3894 { 0xffe00c00, 0x38600800, FMT_RM_OPT_SHIFT_RN_RT,      op_ldrb_reg },
3895 { 0xffe00c00, 0x78400400, FMT_IMM9_RN_RT,              op_ldrh_immpostidx },
3896 { 0xffe00c00, 0x78400c00, FMT_IMM9_RN_RT,              op_ldrh_immpreidx },
3897 { 0xffe00c00, 0x78600800, FMT_RM_OPT_SHIFT_RN_RT,      op_ldrh_reg },
3898 { 0xffe00c00, 0xb8800400, FMT_IMM9_RN_RT,              op_ldrsw_immpostidx },
3899 { 0xffe00c00, 0xb8800c00, FMT_IMM9_RN_RT,              op_ldrsw_immpreidx },
3900 { 0xffe00c00, 0xb8a00800, FMT_RM_OPT_SHIFT_RN_RT,      op_ldrsw_reg },
3901 { 0xffe00c00, 0x38400800, FMT_IMM9_RN_RT,              op_ldtrb },
3902 { 0xffe00c00, 0x78400800, FMT_IMM9_RN_RT,              op_ldtrh },
3903 { 0xffe00c00, 0xb8800800, FMT_IMM9_RN_RT,              op_ldtrsw },
3904 { 0xffe00c00, 0x38400000, FMT_IMM9_RN_RT,              op_ldurb },
3905 { 0xffe00c00, 0x78400000, FMT_IMM9_RN_RT,              op_ldurh },
3906 { 0xffe00c00, 0xb8800000, FMT_IMM9_RN_RT,              op_ldursw },
3907 { 0xffe00c00, 0xf8a00800, FMT_RM_OPT_SHIFT_RN_RT,      op_prfm_reg },
3908 { 0xffe00c00, 0xf8800000, FMT_IMM9_RN_RT,              op_prfum },
3909 { 0xffe00c00, 0x38000400, FMT_IMM9_RN_RT,              op_strb_immpostidx },
3910 { 0xffe00c00, 0x38000c00, FMT_IMM9_RN_RT,              op_strb_immpreidx },
3911 { 0xffe00c00, 0x38200800, FMT_RM_OPT_SHIFT_RN_RT,      op_strb_reg },
3912 { 0xffe00c00, 0x78000400, FMT_IMM9_RN_RT,              op_strh_immpostidx },
3913 { 0xffe00c00, 0x78000c00, FMT_IMM9_RN_RT,              op_strh_immpreidx },
3914 { 0xffe00c00, 0x78200800, FMT_RM_OPT_SHIFT_RN_RT,      op_strh_reg },
3915 { 0xffe00c00, 0x38000800, FMT_IMM9_RN_RT,              op_sttrb },
3916 { 0xffe00c00, 0x78000800, FMT_IMM9_RN_RT,              op_sttrh },
3917 { 0xffe00c00, 0x38000000, FMT_IMM9_RN_RT,              op_sturb },
3918 { 0xffe00c00, 0x78000000, FMT_IMM9_RN_RT,              op_sturh },
3919 { 0xffe0001f, 0xd4200000, FMT_IMM16,                   op_brk },
3920 { 0xffe0001f, 0xd4400000, FMT_IMM16,                   op_hlt },
3921 { 0xffe0001f, 0xd4000002, FMT_IMM16,                   op_hvc },
3922 { 0xffe0001f, 0xd4000003, FMT_IMM16,                   op_smc },
3923 { 0xffe0001f, 0xd4000001, FMT_IMM16,                   op_svc },
3924 { 0xffe0001c, 0xd4a00000, FMT_IMM16_LL,                op_dcps },
3925 { 0xffe00000, 0xd5200000, FMT_OP0_OP1_CRN_CRM_OP2_RT,  op_mrs },
3926 { 0xffe00000, 0xd5000000, FMT_OP0_OP1_CRN_CRM_OP2_RT,  op_msr },
3927 { 0xffc00000, 0x68c00000, FMT_IMM7_RT2_RN_RT,          op_ldpsw_postidx },
3928 { 0xffc00000, 0x69c00000, FMT_IMM7_RT2_RN_RT,          op_ldpsw_preidx },
3929 { 0xffc00000, 0x69400000, FMT_IMM7_RT2_RN_RT,          op_ldpsw_signed },
3930 { 0xffc00000, 0x39400000, FMT_IMM12_RN_RT,             op_ldrb_immunsign },
3931 { 0xffc00000, 0x79400000, FMT_IMM12_RN_RT,             op_ldrh_immunsign },
3932 { 0xffc00000, 0xb9800000, FMT_IMM12_RN_RT,             op_ldrsw_immunsign },
3933 { 0xffc00000, 0xf9800000, FMT_IMM12_RN_RT,             op_prfm_imm },
3934 { 0xffc00000, 0x39000000, FMT_IMM12_RN_RT,             op_strb_immunsign },
3935 { 0xffc00000, 0x79000000, FMT_IMM12_RN_RT,             op_strh_immunsign },
3936 { 0xffa00c00, 0x38800400, FMT_OPC_IMM9_RN_RT,          op_ldrsb_immpostidx },
3937 { 0xffa00c00, 0x38800c00, FMT_OPC_IMM9_RN_RT,          op_ldrsb_immpreidx },
3938 { 0xffa00c00, 0x38a00800, FMT_OPC_RM_OPT_SHIFT_RN_RT,  op_ldrsb_reg },
3939 { 0xffa00c00, 0x78800400, FMT_OPC_IMM9_RN_RT,          op_ldrsh_immpostidx },
3940 { 0xffa00c00, 0x78800c00, FMT_OPC_IMM9_RN_RT,          op_ldrsh_immpreidx },
3941 { 0xffa00c00, 0x78a00800, FMT_OPC_RM_OPT_SHIFT_RN_RT,  op_ldrsh_reg },
3942 { 0xffa00c00, 0x38800800, FMT_OPC_IMM9_RN_RT,          op_ldtrsb },
3943 { 0xffa00c00, 0x78800800, FMT_OPC_IMM9_RN_RT,          op_ldtrsh },
3944 { 0xffa00c00, 0x38800000, FMT_OPC_IMM9_RN_RT,          op_ldursb },
3945 { 0xffa00c00, 0x78800000, FMT_OPC_IMM9_RN_RT,          op_ldursh },
3946 { 0xff800000, 0x39800000, FMT_OPC_IMM12_RN_RT,         op_ldrsb_immunsign },
3947 { 0xff800000, 0x79800000, FMT_OPC_IMM12_RN_RT,         op_ldrsh_immunsign },
3948 { 0xff000010, 0x54000000, FMT_IMM19_COND,              op_b_cond },
3949 { 0xff000000, 0x98000000, FMT_IMM19_RT,                op_ldrsw_literal },
3950 { 0xff000000, 0xd8000000, FMT_IMM19_RT,                op_prfm_literal },
3951 { 0xfefff800, 0xd63f0800, FMT_Z_M_RN_RM,               op_blraa },
3952 { 0xfefff800, 0xd61f0800, FMT_Z_M_RN_RM,               op_braa },
3953 { 0xfc000000, 0x14000000, FMT_IMM26,                   op_b },
3954 { 0xfc000000, 0x94000000, FMT_IMM26,                   op_bl },
3955 { 0xbffffc00, 0x88dffc00, FMT_SIZE_RN_RT,              op_ldar },
3956 { 0xbffffc00, 0x885ffc00, FMT_SIZE_RN_RT,              op_ldaxr },
3957 { 0xbffffc00, 0x885f7c00, FMT_SIZE_RN_RT,              op_ldxr },
3958 { 0xbffffc00, 0x889ffc00, FMT_SIZE_RN_RT,              op_stlr },
3959 { 0xbfff8000, 0x887f8000, FMT_SIZE_RT2_RN_RT,          op_ldaxp },
3960 { 0xbfff8000, 0x887f0000, FMT_SIZE_RT2_RN_RT,          op_ldxp },
3961 { 0xbfe0fc00, 0x8800fc00, FMT_SIZE_RS_RN_RT,           op_stlxr },
3962 { 0xbfe0fc00, 0x88007c00, FMT_SIZE_RS_RN_RT,           op_stxr },
3963 { 0xbfe08000, 0x88208000, FMT_SIZE_RS_RT2_RN_RT,       op_stlxp },
3964 { 0xbfe08000, 0x88200000, FMT_SIZE_RS_RT2_RN_RT,       op_stxp },
3965 { 0xbfe00c00, 0xb8400400, FMT_SIZE_IMM9_RN_RT,         op_ldr_immpostidx },
3966 { 0xbfe00c00, 0xb8400c00, FMT_SIZE_IMM9_RN_RT,         op_ldr_immpreidx },
3967 { 0xbfe00c00, 0xb8600800, FMT_SIZE_RM_OPT_SHIFT_RN_RT, op_ldr_reg },
3968 { 0xbfe00c00, 0xb8400800, FMT_SIZE_IMM9_RN_RT,         op_ldtr },
3969 { 0xbfe00c00, 0xb8400000, FMT_SIZE_IMM9_RN_RT,         op_ldur },
3970 { 0xbfe00c00, 0xb8000400, FMT_SIZE_IMM9_RN_RT,         op_str_immpostidx },
3971 { 0xbfe00c00, 0xb8000c00, FMT_SIZE_IMM9_RN_RT,         op_str_immpreidx },
3972 { 0xbfe00c00, 0xb8200800, FMT_SIZE_RM_OPT_SHIFT_RN_RT, op_str_reg },
3973 { 0xbfe00c00, 0xb8000800, FMT_SIZE_IMM9_RN_RT,         op_sttr },
3974 { 0xbfe00c00, 0xb8000000, FMT_SIZE_IMM9_RN_RT,         op_stur },
3975 { 0xbfc00000, 0xb9400000, FMT_SIZE_IMM12_RN_RT,        op_ldr_immunsign },
3976 { 0xbfc00000, 0xb9000000, FMT_SIZE_IMM12_RN_RT,        op_str_immunsign },
3977 { 0xbf20fc00, 0x0e20e000, FMT_Q_SIZE_RM_RN_RD,         op_simd_pmull },
3978 { 0xbf000000, 0x18000000, FMT_SIZE_IMM19_RT,           op_ldr_literal },
3979 { 0x9f000000, 0x10000000, FMT_IMMLO_IMMHI_RD,          op_adr },
3980 { 0x9f000000, 0x90000000, FMT_IMMLO_IMMHI_RD,          op_adrp },
3981 { 0x7ffffc00, 0x5ac01400, FMT_SF_RN_RD,                op_cls },
3982 { 0x7ffffc00, 0x5ac01000, FMT_SF_RN_RD,                op_clz },
3983 { 0x7ffff000, 0x5ac00000, FMT_SF_OPC_RN_RD,            op_rev },
3984 { 0x7fe0fc00, 0x5a000000, FMT_SF_RM_RN_RD,             op_sbc },
3985 { 0x7fe0fc00, 0x7a000000, FMT_SF_RM_RN_RD,             op_sbcs },
3986 { 0x7fe0fc00, 0x1a000000, FMT_SF_RM_RN_RD,             op_adc },
3987 { 0x7fe0fc00, 0x3a000000, FMT_SF_RM_RN_RD,             op_adcs },
3988 { 0x7fe0fc00, 0x1ac02800, FMT_SF_RM_RN_RD,             op_asr_reg },
3989 { 0x7fe0fc00, 0x1ac02000, FMT_SF_RM_RN_RD,             op_lsl_reg },
3990 { 0x7fe0fc00, 0x1ac02400, FMT_SF_RM_RN_RD,             op_lsr_reg },
3991 { 0x7fe0fc00, 0x1ac02c00, FMT_SF_RM_RN_RD,             op_ror_reg },
3992 { 0x7fe0fc00, 0x1ac00c00, FMT_SF_RM_RN_RD,             op_sdiv },
3993 { 0x7fe0fc00, 0x1ac00800, FMT_SF_RM_RN_RD,             op_udiv },
3994 { 0x7fe0f000, 0x1ac04000, FMT_SF_RM_SZ_RN_RD,          op_crc32 },
3995 { 0x7fe0f000, 0x1ac05000, FMT_SF_RM_SZ_RN_RD,          op_crc32c },
3996 { 0x7fe08000, 0x1b008000, FMT_SF_RM_RA_RN_RD,          op_msub },
3997 { 0x7fe08000, 0x1b000000, FMT_SF_RM_RA_RN_RD,          op_madd },
3998 { 0x7fe00c10, 0x3a400800, FMT_SF_IMM5_COND_RN_NZCV,    op_ccmn_imm },
3999 { 0x7fe00c10, 0x3a400000, FMT_SF_RM_COND_RN_NZCV,      op_ccmn_reg },
4000 { 0x7fe00c10, 0x7a400800, FMT_SF_IMM5_COND_RN_NZCV,    op_ccmp_imm },
4001 { 0x7fe00c10, 0x7a400000, FMT_SF_RM_COND_RN_NZCV,      op_ccmp_reg },
4002 { 0x7fe00c00, 0x5a800000, FMT_SF_RM_COND_RN_RD,        op_csinv },
4003 { 0x7fe00c00, 0x5a800400, FMT_SF_RM_COND_RN_RD,        op_csneg },
4004 { 0x7fe00c00, 0x1a800400, FMT_SF_RM_COND_RN_RD,        op_cinc },
4005 { 0x7fe00c00, 0x1a800000, FMT_SF_RM_COND_RN_RD,        op_csel },
4006 { 0x7fe00000, 0x6b200000, FMT_SF_RM_OPT_IMM3_RN_RD,    op_subs_extreg },
4007 { 0x7fe00000, 0x0b200000, FMT_SF_RM_OPT_IMM3_RN_RD,    op_add_extreg },
4008 { 0x7fe00000, 0x2b200000, FMT_SF_RM_OP_IMM3_RN_RD,     op_adds_extreg },
4009 { 0x7fe00000, 0x4b200000, FMT_SF_RM_OPT_IMM3_RN_RD,    op_sub_extreg },
4010 { 0x7fc00000, 0x28400000, FMT_SF_IMM7_RT2_RN_RT,       op_ldnp },
4011 { 0x7fc00000, 0x28c00000, FMT_SF_IMM7_RT2_RN_RT,       op_ldp_postidx },
4012 { 0x7fc00000, 0x29c00000, FMT_SF_IMM7_RT2_RN_RT,       op_ldp_preidx },
4013 { 0x7fc00000, 0x29400000, FMT_SF_IMM7_RT2_RN_RT,       op_ldp_signed },
4014 { 0x7fc00000, 0x28000000, FMT_SF_IMM7_RT2_RN_RT,       op_stnp },
4015 { 0x7fc00000, 0x28800000, FMT_SF_IMM7_RT2_RN_RT,       op_stp_postidx },
4016 { 0x7fc00000, 0x29800000, FMT_SF_IMM7_RT2_RN_RT,       op_stp_preidx },
4017 { 0x7fc00000, 0x29000000, FMT_SF_IMM7_RT2_RN_RT,       op_stp_signed },
4018 { 0x7fa00000, 0x13800000, FMT_SF_N_RM_IMM6_RN_RD,      op_ror_imm },
4019 { 0x7f800000, 0x12800000, FMT_SF_HW_IMM16_RD,          op_movn },
4020 { 0x7f800000, 0x52800000, FMT_SF_HW_IMM16_RD,          op_movz },
4021 { 0x7f800000, 0x32000000, FMT_SF_N_IMMR_IMMS_RN_RD,    op_orr_imm },
4022 { 0x7f800000, 0x13000000, FMT_SF_N_IMMR_IMMS_RN_RD,    op_sbfm },
4023 { 0x7f800000, 0x53000000, FMT_SF_N_IMMR_IMMS_RN_RD,    op_ubfm },
4024 { 0x7f800000, 0x12000000, FMT_SF_N_IMMR_IMMS_RN_RD,    op_and_imm },
4025 { 0x7f800000, 0x72000000, FMT_SF_N_IMMR_IMMS_RN_RD,    op_ands_imm },
4026 { 0x7f800000, 0x33000000, FMT_SF_N_IMMR_IMMS_RN_RD,    op_bfi },
4027 { 0x7f800000, 0x52000000, FMT_SF_N_IMMR_IMMS_RN_RD,    op_eor_imm },
4028 { 0x7f800000, 0x72800000, FMT_SF_HW_IMM16_RD,          op_movk },
4029 { 0x7f200000, 0x2a200000, FMT_SF_SHIFT_RM_IMM6_RN_RD,  op_orn },
4030 { 0x7f200000, 0x2a000000, FMT_SF_SHIFT_RM_IMM6_RN_RD,  op_orr_reg },
4031 { 0x7f200000, 0x4b000000, FMT_SF_SHIFT_RM_IMM6_RN_RD,  op_sub_shiftreg },
4032 { 0x7f200000, 0x6b000000, FMT_SF_SHIFT_RM_IMM6_RN_RD,  op_subs_shiftreg },
4033 { 0x7f200000, 0x0b000000, FMT_SF_SHIFT_RM_IMM6_RN_RD,  op_add_shiftreg },
4034 { 0x7f200000, 0x2b000000, FMT_SF_SHIFT_RM_IMM6_RN_RD,  op_adds_shiftreg },
4035 { 0x7f200000, 0x0a000000, FMT_SF_SHIFT_RM_IMM6_RN_RD,  op_and_shiftreg },
4036 { 0x7f200000, 0x6a000000, FMT_SF_SHIFT_RM_IMM6_RN_RD,  op_ands_shiftreg },
4037 { 0x7f200000, 0x0a200000, FMT_SF_SHIFT_RM_IMM6_RN_RD,  op_bic_shiftreg },
4038 { 0x7f200000, 0x6a200000, FMT_SF_SHIFT_RM_IMM6_RN_RD,  op_bics_shiftreg },
4039 { 0x7f200000, 0x4a200000, FMT_SF_SHIFT_RM_IMM6_RN_RD,  op_eon_shiftreg },
4040 { 0x7f200000, 0x4a000000, FMT_SF_SHIFT_RM_IMM6_RN_RD,  op_eor_shiftreg },
4041 { 0x7f000000, 0x71000000, FMT_SF_SHIFT_IMM12_RN_RD,    op_subs_imm },
4042 { 0x7f000000, 0x11000000, FMT_SF_SHIFT_IMM12_RN_RD,    op_add_imm },
4043 { 0x7f000000, 0x31000000, FMT_SF_SHIFT_IMM12_RN_RD,    op_adds_imm },
4044 { 0x7f000000, 0x35000000, FMT_SF_IMM19_RT,             op_cbnz },
4045 { 0x7f000000, 0x34000000, FMT_SF_IMM19_RT,             op_cbz },
4046 { 0x7f000000, 0x51000000, FMT_SF_SHIFT_IMM12_RN_RD,    op_sub_imm },
4047 { 0x7f000000, 0x37000000, FMT_B5_B40_IMM14_RT,         op_tbnz },
4048 { 0x7f000000, 0x36000000, FMT_B5_B40_IMM14_RT,         op_tbz },
4049 { 0x3f800000, 0x2c000000, FMT_OPC_L_IMM7_RT2_RN_RT,    op_simd_ldstnp },
4050 { 0x3f800000, 0x2c800000, FMT_OPC_L_IMM7_RT2_RN_RT, op_simd_ldstp_postidx },
4051 { 0x3f800000, 0x2d800000, FMT_OPC_L_IMM7_RT2_RN_RT,    op_simd_ldstp_preidx },
4052 { 0x3f800000, 0x2d000000, FMT_OPC_L_IMM7_RT2_RN_RT,    op_simd_ldstp_signed },
4053 { 0x3f200c00, 0x3c000400, FMT_SIZE_OPC_IMM9_RN_RT, op_simd_ldstr_immpostidx },
4054 { 0x3f200c00, 0x3c000c00, FMT_SIZE_OPC_IMM9_RN_RT, op_simd_ldstr_immpreidx },
4055 { 0x3f200c00, 0x3c200800, FMT_SIZE_OPC_RM_OPT_S_RN_RT, op_simd_ldstr_reg },
4056 { 0x3f000000, 0x3d000000, FMT_SIZE_OPC_IMM12_RN_RT, op_simd_ldstr_immunsign },
4057 { 0x00000000, 0x00000000, FMT_NOARG,                   op_undefined }
4058};
4059
4060#define WIDTHMASK(w)	(0xffffffff >> (32 - (w)))
4061
4062void
4063disasm_insn(const disasm_interface_t *di, uintptr_t loc, uint32_t insn)
4064{
4065	uint64_t args[INSN_MAXARG];
4066	unsigned int i, j;
4067
4068	for (i = 0; i < __arraycount(insn_tables); i++) {
4069		if ((insn & insn_tables[i].mask) != insn_tables[i].pattern)
4070			continue;
4071
4072		/* extract operands */
4073		for (j = 0; j < INSN_MAXARG; j++) {
4074			if (insn_tables[i].bitinfo[j].width == 0)
4075				break;
4076			args[j] = (insn >> insn_tables[i].bitinfo[j].pos) &
4077			    WIDTHMASK(insn_tables[i].bitinfo[j].width);
4078		}
4079		insn_tables[i].opfunc(di, loc, insn,
4080		    args[0], args[1], args[2], args[3],
4081		    args[4], args[5], args[6], args[7]);
4082		break;
4083	}
4084}
4085
4086uintptr_t
4087disasm(const disasm_interface_t *di, uintptr_t loc)
4088{
4089	uint32_t insn;
4090
4091	insn = le32toh(di->di_readword(loc));
4092	disasm_insn(di, loc, insn);
4093
4094	/* return next address */
4095	return loc + sizeof(insn);
4096}
4097