1/*-
2 * Copyright (c) 2016-2018 Ruslan Bukin <br@bsdpad.com>
3 * All rights reserved.
4 *
5 * Portions of this software were developed by SRI International and the
6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract
7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Portions of this software were developed by the University of Cambridge
10 * Computer Laboratory as part of the CTSRD Project, with support from the
11 * UK Higher Education Innovation Fund (HEIF).
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD$");
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <ddb/ddb.h>
41#include <ddb/db_access.h>
42#include <ddb/db_sym.h>
43
44#include <machine/encoding.h>
45
46#define	X_RA	1
47#define	X_SP	2
48#define	X_GP	3
49#define	X_TP	4
50#define	X_T0	5
51#define	X_T1	6
52#define	X_T2	7
53#define	X_T3	28
54
55#define	RD_SHIFT	7
56#define	RD_MASK		(0x1f << RD_SHIFT)
57#define	RS1_SHIFT	15
58#define	RS1_MASK	(0x1f << RS1_SHIFT)
59#define	RS2_SHIFT	20
60#define	RS2_MASK	(0x1f << RS2_SHIFT)
61#define	IMM_SHIFT	20
62#define	IMM_MASK	(0xfff << IMM_SHIFT)
63
64static char *reg_name[32] = {
65	"zero",	"ra",	"sp",	"gp",	"tp",	"t0",	"t1",	"t2",
66	"s0",	"s1",	"a0",	"a1",	"a2",	"a3",	"a4",	"a5",
67	"a6",	"a7",	"s2",	"s3",	"s4",	"s5",	"s6",	"s7",
68	"s8",	"s9",	"s10",	"s11",	"t3",	"t4",	"t5",	"t6"
69};
70
71static char *fp_reg_name[32] = {
72	"ft0", "ft1", "ft2",  "ft3",  "ft4", "ft5", "ft6",  "ft7",
73	"fs0", "fs1", "fa0",  "fa1",  "fa2", "fa3", "fa4",  "fa5",
74	"fa6", "fa7", "fs2",  "fs3",  "fs4", "fs5", "fs6",  "fs7",
75	"fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11"
76};
77
78struct riscv_op {
79	char *name;
80	char *fmt;
81	int match;
82	int mask;
83	int (*match_func)(struct riscv_op *op, uint32_t insn);
84};
85
86static int
87m_op(struct riscv_op *op, uint32_t insn)
88{
89
90	if (((insn ^ op->match) & op->mask) == 0)
91		return (1);
92
93	return (0);
94}
95
96static struct riscv_op riscv_opcodes[] = {
97	/* Aliases first */
98	{"ret","", MATCH_JALR | (X_RA << RS1_SHIFT),
99	    MASK_JALR | RD_MASK | RS1_MASK | IMM_MASK, m_op },
100
101	{ "beq",	"s,t,p", 	MATCH_BEQ, MASK_BEQ,		m_op },
102	{ "bne",	"s,t,p", 	MATCH_BNE, MASK_BNE,		m_op },
103	{ "blt",	"s,t,p", 	MATCH_BLT, MASK_BLT,		m_op },
104	{ "bge",	"s,t,p", 	MATCH_BGE, MASK_BGE,		m_op },
105	{ "bltu",	"s,t,p", 	MATCH_BLTU, MASK_BLTU,		m_op },
106	{ "bgeu",	"s,t,p", 	MATCH_BGEU, MASK_BGEU,		m_op },
107	{ "jalr",	"d,o(s)", 	MATCH_JALR, MASK_JALR,		m_op },
108	{ "jal",	"d,a", 		MATCH_JAL, MASK_JAL,		m_op },
109	{ "lui",	"d,u", 		MATCH_LUI, MASK_LUI,		m_op },
110	{ "auipc",	"d,u", 		MATCH_AUIPC, MASK_AUIPC,	m_op },
111	{ "addi",	"d,s,j", 	MATCH_ADDI, MASK_ADDI,		m_op },
112	{ "slli",	"d,s,>", 	MATCH_SLLI, MASK_SLLI,		m_op },
113	{ "slti",	"d,s,j", 	MATCH_SLTI, MASK_SLTI,		m_op },
114	{ "sltiu",	"d,s,j", 	MATCH_SLTIU, MASK_SLTIU,	m_op },
115	{ "xori",	"d,s,j", 	MATCH_XORI, MASK_XORI,		m_op },
116	{ "srli",	"d,s,>", 	MATCH_SRLI, MASK_SRLI,		m_op },
117	{ "srai",	"d,s,>", 	MATCH_SRAI, MASK_SRAI,		m_op },
118	{ "ori",	"d,s,j", 	MATCH_ORI, MASK_ORI,		m_op },
119	{ "andi",	"d,s,j", 	MATCH_ANDI, MASK_ANDI,		m_op },
120	{ "add",	"d,s,t", 	MATCH_ADD, MASK_ADD,		m_op },
121	{ "sub",	"d,s,t", 	MATCH_SUB, MASK_SUB,		m_op },
122	{ "sll",	"d,s,t", 	MATCH_SLL, MASK_SLL,		m_op },
123	{ "slt",	"d,s,t", 	MATCH_SLT, MASK_SLT,		m_op },
124	{ "sltu",	"d,s,t", 	MATCH_SLTU, MASK_SLTU,		m_op },
125	{ "xor",	"d,s,t", 	MATCH_XOR, MASK_XOR,		m_op },
126	{ "srl",	"d,s,t", 	MATCH_SRL, MASK_SRL,		m_op },
127	{ "sra",	"d,s,t", 	MATCH_SRA, MASK_SRA,		m_op },
128	{ "or",		"d,s,t", 	MATCH_OR, MASK_OR,		m_op },
129	{ "and",	"d,s,t", 	MATCH_AND, MASK_AND,		m_op },
130	{ "addiw",	"d,s,j", 	MATCH_ADDIW, MASK_ADDIW,	m_op },
131	{ "slliw",	"d,s,<", 	MATCH_SLLIW, MASK_SLLIW,	m_op },
132	{ "srliw",	"d,s,<", 	MATCH_SRLIW, MASK_SRLIW,	m_op },
133	{ "sraiw",	"d,s,<", 	MATCH_SRAIW, MASK_SRAIW,	m_op },
134	{ "addw",	"d,s,t", 	MATCH_ADDW, MASK_ADDW,		m_op },
135	{ "subw",	"d,s,t", 	MATCH_SUBW, MASK_SUBW,		m_op },
136	{ "sllw",	"d,s,t", 	MATCH_SLLW, MASK_SLLW,		m_op },
137	{ "srlw",	"d,s,t", 	MATCH_SRLW, MASK_SRLW,		m_op },
138	{ "sraw",	"d,s,t", 	MATCH_SRAW, MASK_SRAW,		m_op },
139	{ "lb",		"d,o(s)", 	MATCH_LB, MASK_LB,		m_op },
140	{ "lh",		"d,o(s)", 	MATCH_LH, MASK_LH,		m_op },
141	{ "lw",		"d,o(s)", 	MATCH_LW, MASK_LW,		m_op },
142	{ "ld",		"d,o(s)", 	MATCH_LD, MASK_LD,		m_op },
143	{ "lbu",	"d,o(s)", 	MATCH_LBU, MASK_LBU,		m_op },
144	{ "lhu",	"d,o(s)", 	MATCH_LHU, MASK_LHU,		m_op },
145	{ "lwu",	"d,o(s)", 	MATCH_LWU, MASK_LWU,		m_op },
146	{ "sb",		"t,q(s)", 	MATCH_SB, MASK_SB,		m_op },
147	{ "sh",		"t,q(s)", 	MATCH_SH, MASK_SH,		m_op },
148	{ "sw",		"t,q(s)", 	MATCH_SW, MASK_SW,		m_op },
149	{ "sd",		"t,q(s)", 	MATCH_SD, MASK_SD,		m_op },
150	{ "fence",	"P,Q",		MATCH_FENCE, MASK_FENCE,	m_op },
151	{ "fence.i",	"",		MATCH_FENCE_I, MASK_FENCE_I,	m_op },
152	{ "mul",	"d,s,t", 	MATCH_MUL, MASK_MUL,		m_op },
153	{ "mulh",	"d,s,t", 	MATCH_MULH, MASK_MULH,		m_op },
154	{ "mulhsu",	"d,s,t", 	MATCH_MULHSU, MASK_MULHSU,	m_op },
155	{ "mulhu",	"d,s,t", 	MATCH_MULHU, MASK_MULHU,	m_op },
156	{ "div",	"d,s,t", 	MATCH_DIV, MASK_DIV,		m_op },
157	{ "divu",	"d,s,t", 	MATCH_DIVU, MASK_DIVU,		m_op },
158	{ "rem",	"d,s,t", 	MATCH_REM, MASK_REM,		m_op },
159	{ "remu",	"d,s,t", 	MATCH_REMU, MASK_REMU,		m_op },
160	{ "mulw",	"d,s,t", 	MATCH_MULW, MASK_MULW,		m_op },
161	{ "divw",	"d,s,t", 	MATCH_DIVW, MASK_DIVW,		m_op },
162	{ "divuw",	"d,s,t", 	MATCH_DIVUW, MASK_DIVUW,	m_op },
163	{ "remw",	"d,s,t", 	MATCH_REMW, MASK_REMW,		m_op },
164	{ "remuw",	"d,s,t", 	MATCH_REMUW, MASK_REMUW,	m_op },
165	{ "amoadd.w",	"d,t,0(s)", 	MATCH_AMOADD_W, MASK_AMOADD_W,	m_op },
166	{ "amoxor.w",	"d,t,0(s)", 	MATCH_AMOXOR_W, MASK_AMOXOR_W,	m_op },
167	{ "amoor.w",	"d,t,0(s)", 	MATCH_AMOOR_W, MASK_AMOOR_W,	m_op },
168	{ "amoand.w",	"d,t,0(s)", 	MATCH_AMOAND_W, MASK_AMOAND_W,	m_op },
169	{ "amomin.w",	"d,t,0(s)", 	MATCH_AMOMIN_W, MASK_AMOMIN_W,	m_op },
170	{ "amomax.w",	"d,t,0(s)", 	MATCH_AMOMAX_W, MASK_AMOMAX_W,	m_op },
171	{ "amominu.w",	"d,t,0(s)", 	MATCH_AMOMINU_W, MASK_AMOMINU_W,m_op },
172	{ "amomaxu.w",	"d,t,0(s)", 	MATCH_AMOMAXU_W, MASK_AMOMAXU_W,m_op },
173	{ "amoswap.w",	"d,t,0(s)", 	MATCH_AMOSWAP_W, MASK_AMOSWAP_W,m_op },
174	{ "lr.w",	"d,0(s)", 	MATCH_LR_W, MASK_LR_W,		m_op },
175	{ "sc.w",	"d,t,0(s)", 	MATCH_SC_W, MASK_SC_W,		m_op },
176	{ "amoadd.d",	"d,t,0(s)", 	MATCH_AMOADD_D, MASK_AMOADD_D,	m_op },
177	{ "amoxor.d",	"d,t,0(s)", 	MATCH_AMOXOR_D, MASK_AMOXOR_D,	m_op },
178	{ "amoor.d",	"d,t,0(s)", 	MATCH_AMOOR_D, MASK_AMOOR_D,	m_op },
179	{ "amoand.d",	"d,t,0(s)", 	MATCH_AMOAND_D, MASK_AMOAND_D,	m_op },
180	{ "amomin.d",	"d,t,0(s)", 	MATCH_AMOMIN_D, MASK_AMOMIN_D,	m_op },
181	{ "amomax.d",	"d,t,0(s)", 	MATCH_AMOMAX_D, MASK_AMOMAX_D,	m_op },
182	{ "amominu.d",	"d,t,0(s)", 	MATCH_AMOMINU_D, MASK_AMOMINU_D,m_op },
183	{ "amomaxu.d",	"d,t,0(s)", 	MATCH_AMOMAXU_D, MASK_AMOMAXU_D,m_op },
184	{ "amoswap.d",	"d,t,0(s)", 	MATCH_AMOSWAP_D, MASK_AMOSWAP_D,m_op },
185	{ "lr.d",	"d,0(s)", 	MATCH_LR_D, MASK_LR_D,		m_op },
186	{ "sc.d",	"d,t,0(s)", 	MATCH_SC_D, MASK_SC_D,		m_op },
187	{ "ecall",	"", 		MATCH_ECALL, MASK_ECALL,	m_op },
188	{ "ebreak",	"", 		MATCH_EBREAK, MASK_EBREAK,	m_op },
189	{ "uret",	"", 		MATCH_URET, MASK_URET,		m_op },
190	{ "sret",	"", 		MATCH_SRET, MASK_SRET,		m_op },
191	{ "mret",	"", 		MATCH_MRET, MASK_MRET,		m_op },
192	{ "dret",	"", 		MATCH_DRET, MASK_DRET,		m_op },
193	{ "sfence.vma",	"", 	MATCH_SFENCE_VMA, MASK_SFENCE_VMA,	m_op },
194	{ "wfi",	"", 		MATCH_WFI, MASK_WFI,		m_op },
195	{ "csrrw",	"d,E,s", 	MATCH_CSRRW, MASK_CSRRW,	m_op },
196	{ "csrrs",	"d,E,s", 	MATCH_CSRRS, MASK_CSRRS,	m_op },
197	{ "csrrc",	"d,E,s", 	MATCH_CSRRC, MASK_CSRRC,	m_op },
198	{ "csrrwi",	"d,E,Z", 	MATCH_CSRRWI, MASK_CSRRWI,	m_op },
199	{ "csrrsi",	"d,E,Z", 	MATCH_CSRRSI, MASK_CSRRSI,	m_op },
200	{ "csrrci",	"d,E,Z", 	MATCH_CSRRCI, MASK_CSRRCI,	m_op },
201	{ "fadd.s",	"D,S,T", 	MATCH_FADD_S, MASK_FADD_S,	m_op },
202	{ "fsub.s",	"D,S,T", 	MATCH_FSUB_S, MASK_FSUB_S,	m_op },
203	{ "fmul.s",	"D,S,T", 	MATCH_FMUL_S, MASK_FMUL_S,	m_op },
204	{ "fdiv.s",	"D,S,T", 	MATCH_FDIV_S, MASK_FDIV_S,	m_op },
205	{ "fsgnj.s",	"D,S,T", 	MATCH_FSGNJ_S, MASK_FSGNJ_S,	m_op },
206	{ "fsgnjn.s",	"D,S,T", 	MATCH_FSGNJN_S, MASK_FSGNJN_S,	m_op },
207	{ "fsgnjx.s",	"D,S,T", 	MATCH_FSGNJX_S, MASK_FSGNJX_S,	m_op },
208	{ "fmin.s",	"D,S,T", 	MATCH_FMIN_S, MASK_FMIN_S,	m_op },
209	{ "fmax.s",	"D,S,T", 	MATCH_FMAX_S, MASK_FMAX_S,	m_op },
210	{ "fsqrt.s",	"D,S", 		MATCH_FSQRT_S, MASK_FSQRT_S,	m_op },
211	{ "fadd.d",	"D,S,T", 	MATCH_FADD_D, MASK_FADD_D,	m_op },
212	{ "fsub.d",	"D,S,T", 	MATCH_FSUB_D, MASK_FSUB_D,	m_op },
213	{ "fmul.d",	"D,S,T", 	MATCH_FMUL_D, MASK_FMUL_D,	m_op },
214	{ "fdiv.d",	"D,S,T", 	MATCH_FDIV_D, MASK_FDIV_D,	m_op },
215	{ "fsgnj.d",	"D,S,T", 	MATCH_FSGNJ_D, MASK_FSGNJ_D,	m_op },
216	{ "fsgnjn.d",	"D,S,T", 	MATCH_FSGNJN_D, MASK_FSGNJN_D,	m_op },
217	{ "fsgnjx.d",	"D,S,T", 	MATCH_FSGNJX_D, MASK_FSGNJX_D,	m_op },
218	{ "fmin.d",	"D,S,T", 	MATCH_FMIN_D, MASK_FMIN_D,	m_op },
219	{ "fmax.d",	"D,S,T", 	MATCH_FMAX_D, MASK_FMAX_D,	m_op },
220	{ "fcvt.s.d",	"D,S", 		MATCH_FCVT_S_D, MASK_FCVT_S_D,	m_op },
221	{ "fcvt.d.s",	"D,S", 		MATCH_FCVT_D_S, MASK_FCVT_D_S,	m_op },
222	{ "fsqrt.d",	"D,S", 		MATCH_FSQRT_D, MASK_FSQRT_D,	m_op },
223	{ "fadd.q",	"D,S,T", 	MATCH_FADD_Q, MASK_FADD_Q,	m_op },
224	{ "fsub.q",	"D,S,T", 	MATCH_FSUB_Q, MASK_FSUB_Q,	m_op },
225	{ "fmul.q",	"D,S,T", 	MATCH_FMUL_Q, MASK_FMUL_Q,	m_op },
226	{ "fdiv.q",	"D,S,T", 	MATCH_FDIV_Q, MASK_FDIV_Q,	m_op },
227	{ "fsgnj.q",	"D,S,T", 	MATCH_FSGNJ_Q, MASK_FSGNJ_Q,	m_op },
228	{ "fsgnjn.q",	"D,S,T", 	MATCH_FSGNJN_Q, MASK_FSGNJN_Q,	m_op },
229	{ "fsgnjx.q",	"D,S,T", 	MATCH_FSGNJX_Q, MASK_FSGNJX_Q,	m_op },
230	{ "fmin.q",	"D,S,T", 	MATCH_FMIN_Q, MASK_FMIN_Q,	m_op },
231	{ "fmax.q",	"D,S,T", 	MATCH_FMAX_Q, MASK_FMAX_Q,	m_op },
232	{ "fcvt.s.q",	"D,S", 		MATCH_FCVT_S_Q, MASK_FCVT_S_Q,	m_op },
233	{ "fcvt.q.s",	"D,S", 		MATCH_FCVT_Q_S, MASK_FCVT_Q_S,	m_op },
234	{ "fcvt.d.q",	"D,S", 		MATCH_FCVT_D_Q, MASK_FCVT_D_Q,	m_op },
235	{ "fcvt.q.d",	"D,S", 		MATCH_FCVT_Q_D, MASK_FCVT_Q_D,	m_op },
236	{ "fsqrt.q",	"D,S", 		MATCH_FSQRT_Q, MASK_FSQRT_Q,	m_op },
237	{ "fle.s",	"d,S,T", 	MATCH_FLE_S, MASK_FLE_S,	m_op },
238	{ "flt.s",	"d,S,T", 	MATCH_FLT_S, MASK_FLT_S,	m_op },
239	{ "feq.s",	"d,S,T", 	MATCH_FEQ_S, MASK_FEQ_S,	m_op },
240	{ "fle.d",	"d,S,T", 	MATCH_FLE_D, MASK_FLE_D,	m_op },
241	{ "flt.d",	"d,S,T", 	MATCH_FLT_D, MASK_FLT_D,	m_op },
242	{ "feq.d",	"d,S,T", 	MATCH_FEQ_D, MASK_FEQ_D,	m_op },
243	{ "fle.q",	"d,S,T", 	MATCH_FLE_Q, MASK_FLE_Q,	m_op },
244	{ "flt.q",	"d,S,T", 	MATCH_FLT_Q, MASK_FLT_Q,	m_op },
245	{ "feq.q",	"d,S,T", 	MATCH_FEQ_Q, MASK_FEQ_Q,	m_op },
246	{ "fcvt.w.s",	"d,S", 		MATCH_FCVT_W_S, MASK_FCVT_W_S,	m_op },
247	{ "fcvt.wu.s",	"d,S", 		MATCH_FCVT_WU_S, MASK_FCVT_WU_S,m_op },
248	{ "fcvt.l.s",	"d,S", 		MATCH_FCVT_L_S, MASK_FCVT_L_S,	m_op },
249	{ "fcvt.lu.s",	"d,S", 		MATCH_FCVT_LU_S, MASK_FCVT_LU_S,m_op },
250	{ "fmv.x.w",	"d,S", 		MATCH_FMV_X_W, MASK_FMV_X_W,	m_op },
251	{ "fclass.s",	"d,S", 		MATCH_FCLASS_S, MASK_FCLASS_S,	m_op },
252	{ "fcvt.w.d",	"d,S", 		MATCH_FCVT_W_D, MASK_FCVT_W_D,	m_op },
253	{ "fcvt.wu.d",	"d,S", 		MATCH_FCVT_WU_D, MASK_FCVT_WU_D,m_op },
254	{ "fcvt.l.d",	"d,S", 		MATCH_FCVT_L_D, MASK_FCVT_L_D,	m_op },
255	{ "fcvt.lu.d",	"d,S", 		MATCH_FCVT_LU_D, MASK_FCVT_LU_D,m_op },
256	{ "fmv.x.d",	"d,S", 		MATCH_FMV_X_D, MASK_FMV_X_D,	m_op },
257	{ "fclass.d",	"d,S", 		MATCH_FCLASS_D, MASK_FCLASS_D,	m_op },
258	{ "fcvt.w.q",	"d,S", 		MATCH_FCVT_W_Q, MASK_FCVT_W_Q,	m_op },
259	{ "fcvt.wu.q",	"d,S", 		MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q,m_op },
260	{ "fcvt.l.q",	"d,S", 		MATCH_FCVT_L_Q, MASK_FCVT_L_Q,	m_op },
261	{ "fcvt.lu.q",	"d,S", 		MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q,m_op },
262	{ "fmv.x.q",	"d,S", 		MATCH_FMV_X_Q, MASK_FMV_X_Q,	m_op },
263	{ "fclass.q",	"d,S", 		MATCH_FCLASS_Q, MASK_FCLASS_Q,	m_op },
264	{ "fcvt.s.w",	"D,s", 		MATCH_FCVT_S_W, MASK_FCVT_S_W,	m_op },
265	{ "fcvt.s.wu",	"D,s", 		MATCH_FCVT_S_WU, MASK_FCVT_S_WU,m_op },
266	{ "fcvt.s.l",	"D,s", 		MATCH_FCVT_S_L, MASK_FCVT_S_L,	m_op },
267	{ "fcvt.s.lu",	"D,s", 		MATCH_FCVT_S_LU, MASK_FCVT_S_LU,m_op },
268	{ "fmv.w.x",	"D,s", 		MATCH_FMV_W_X, MASK_FMV_W_X,	m_op },
269	{ "fcvt.d.w",	"D,s", 		MATCH_FCVT_D_W, MASK_FCVT_D_W,	m_op },
270	{ "fcvt.d.wu",	"D,s", 		MATCH_FCVT_D_WU, MASK_FCVT_D_WU,m_op },
271	{ "fcvt.d.l",	"D,s", 		MATCH_FCVT_D_L, MASK_FCVT_D_L,	m_op },
272	{ "fcvt.d.lu",	"D,s", 		MATCH_FCVT_D_LU, MASK_FCVT_D_LU,m_op },
273	{ "fmv.d.x",	"D,s", 		MATCH_FMV_D_X, MASK_FMV_D_X,	m_op },
274	{ "fcvt.q.w",	"D,s", 		MATCH_FCVT_Q_W, MASK_FCVT_Q_W,	m_op },
275	{ "fcvt.q.wu",	"D,s", 		MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU,m_op },
276	{ "fcvt.q.l",	"D,s", 		MATCH_FCVT_Q_L, MASK_FCVT_Q_L,	m_op },
277	{ "fcvt.q.lu",	"D,s", 		MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU,m_op },
278	{ "fmv.q.x",	"D,s", 		MATCH_FMV_Q_X, MASK_FMV_Q_X,	m_op },
279	{ "flw",	"D,o(s)", 	MATCH_FLW, MASK_FLW,		m_op },
280	{ "fld",	"D,o(s)", 	MATCH_FLD, MASK_FLD,		m_op },
281	{ "flq",	"D,o(s)", 	MATCH_FLQ, MASK_FLQ,		m_op },
282	{ "fsw",	"T,q(s)", 	MATCH_FSW, MASK_FSW,		m_op },
283	{ "fsd",	"T,q(s)", 	MATCH_FSD, MASK_FSD,		m_op },
284	{ "fsq",	"T,q(s)", 	MATCH_FSQ, MASK_FSQ,		m_op },
285	{ "fmadd.s",	"D,S,T,R", 	MATCH_FMADD_S, MASK_FMADD_S,	m_op },
286	{ "fmsub.s",	"D,S,T,R", 	MATCH_FMSUB_S, MASK_FMSUB_S,	m_op },
287	{ "fnmsub.s",	"D,S,T,R", 	MATCH_FNMSUB_S, MASK_FNMSUB_S,	m_op },
288	{ "fnmadd.s",	"D,S,T,R", 	MATCH_FNMADD_S, MASK_FNMADD_S,	m_op },
289	{ "fmadd.d",	"D,S,T,R", 	MATCH_FMADD_D, MASK_FMADD_D,	m_op },
290	{ "fmsub.d",	"D,S,T,R", 	MATCH_FMSUB_D, MASK_FMSUB_D,	m_op },
291	{ "fnmsub.d",	"D,S,T,R", 	MATCH_FNMSUB_D, MASK_FNMSUB_D,	m_op },
292	{ "fnmadd.d",	"D,S,T,R", 	MATCH_FNMADD_D, MASK_FNMADD_D,	m_op },
293	{ "fmadd.q",	"D,S,T,R", 	MATCH_FMADD_Q, MASK_FMADD_Q,	m_op },
294	{ "fmsub.q",	"D,S,T,R", 	MATCH_FMSUB_Q, MASK_FMSUB_Q,	m_op },
295	{ "fnmsub.q",	"D,S,T,R", 	MATCH_FNMSUB_Q, MASK_FNMSUB_Q,	m_op },
296	{ "fnmadd.q",	"D,S,T,R", 	MATCH_FNMADD_Q, MASK_FNMADD_Q,	m_op },
297	{ NULL, NULL, 0, 0, NULL },
298};
299
300static struct riscv_op riscv_c_opcodes[] = {
301	/* Aliases first */
302	{ "ret","",MATCH_C_JR | (X_RA << RD_SHIFT), MASK_C_JR | RD_MASK, m_op},
303
304	/* C-Compressed ISA Extension Instructions */
305	{ "c.nop",	"", 		MATCH_C_NOP, MASK_C_NOP,	m_op },
306	{ "c.ebreak",	"", 		MATCH_C_EBREAK, MASK_C_EBREAK,	m_op },
307	{ "c.jr",	"d", 		MATCH_C_JR, MASK_C_JR,		m_op },
308	{ "c.jalr",	"d", 		MATCH_C_JALR, MASK_C_JALR,	m_op },
309	{ "c.jal",	"Ca", 		MATCH_C_JAL, MASK_C_JAL,	m_op },
310	{ "c.ld",	"Ct,Cl(Cs)", 	MATCH_C_LD, MASK_C_LD,		m_op },
311	{ "c.sd",	"Ct,Cl(Cs)", 	MATCH_C_SD, MASK_C_SD,		m_op },
312	{ "c.addiw",	"d,Co", 	MATCH_C_ADDIW, MASK_C_ADDIW,	m_op },
313	{ "c.ldsp",	"d,Cn(Cc)", 	MATCH_C_LDSP, MASK_C_LDSP,	m_op },
314	{ "c.sdsp",	"CV,CN(Cc)", 	MATCH_C_SDSP, MASK_C_SDSP,	m_op },
315	{ "c.addi4spn",	"", 	MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN,	m_op },
316	{ "c.addi16sp",	"", 	MATCH_C_ADDI16SP, MASK_C_ADDI16SP,	m_op },
317	{ "c.fld",	"CD,Cl(Cs)", 	MATCH_C_FLD, MASK_C_FLD,	m_op },
318	{ "c.lw",	"Ct,Ck(Cs)", 	MATCH_C_LW, MASK_C_LW,		m_op },
319	{ "c.flw",	"CD,Ck(Cs)", 	MATCH_C_FLW, MASK_C_FLW,	m_op },
320	{ "c.fsd",	"CD,Cl(Cs)", 	MATCH_C_FSD, MASK_C_FSD,	m_op },
321	{ "c.sw",	"Ct,Ck(Cs)", 	MATCH_C_SW, MASK_C_SW,		m_op },
322	{ "c.fsw",	"CD,Ck(Cs)", 	MATCH_C_FSW, MASK_C_FSW,	m_op },
323	{ "c.addi",	"d,Co", 	MATCH_C_ADDI, MASK_C_ADDI,	m_op },
324	{ "c.li",	"d,Co", 	MATCH_C_LI, MASK_C_LI,		m_op },
325	{ "c.lui",	"d,Cu", 	MATCH_C_LUI, MASK_C_LUI,	m_op },
326	{ "c.srli",	"Cs,C>", 	MATCH_C_SRLI, MASK_C_SRLI,	m_op },
327	{ "c.srai",	"Cs,C>", 	MATCH_C_SRAI, MASK_C_SRAI,	m_op },
328	{ "c.andi",	"Cs,Co", 	MATCH_C_ANDI, MASK_C_ANDI,	m_op },
329	{ "c.sub",	"Cs,Ct", 	MATCH_C_SUB, MASK_C_SUB,	m_op },
330	{ "c.xor",	"Cs,Ct", 	MATCH_C_XOR, MASK_C_XOR,	m_op },
331	{ "c.or",	"Cs,Ct", 	MATCH_C_OR, MASK_C_OR,		m_op },
332	{ "c.and",	"Cs,Ct", 	MATCH_C_AND, MASK_C_AND,	m_op },
333	{ "c.subw",	"Cs,Ct", 	MATCH_C_SUBW, MASK_C_SUBW,	m_op },
334	{ "c.addw",	"Cs,Ct", 	MATCH_C_ADDW, MASK_C_ADDW,	m_op },
335	{ "c.j",	"Ca", 		MATCH_C_J, MASK_C_J,		m_op },
336	{ "c.beqz",	"Cs,Cp", 	MATCH_C_BEQZ, MASK_C_BEQZ,	m_op },
337	{ "c.bnez",	"Cs,Cp", 	MATCH_C_BNEZ, MASK_C_BNEZ,	m_op },
338	{ "c.slli",	"d,C>", 	MATCH_C_SLLI, MASK_C_SLLI,	m_op },
339	{ "c.fldsp",	"D,Cn(Cc)", 	MATCH_C_FLDSP, MASK_C_FLDSP,	m_op },
340	{ "c.lwsp",	"d,Cm(Cc)", 	MATCH_C_LWSP, MASK_C_LWSP,	m_op },
341	{ "c.flwsp",	"D,Cm(Cc)", 	MATCH_C_FLWSP, MASK_C_FLWSP,	m_op },
342	{ "c.mv",	"d,CV", 	MATCH_C_MV, MASK_C_MV,		m_op },
343	{ "c.add",	"d,CV", 	MATCH_C_ADD, MASK_C_ADD,	m_op },
344	{ "c.fsdsp",	"CT,CN(Cc)", 	MATCH_C_FSDSP, MASK_C_FSDSP,	m_op },
345	{ "c.swsp",	"CV,CM(Cc)", 	MATCH_C_SWSP, MASK_C_SWSP,	m_op },
346	{ "c.fswsp",	"CT,CM(Cc)", 	MATCH_C_FSWSP, MASK_C_FSWSP,	m_op },
347	{ NULL, NULL, 0, 0, NULL },
348};
349
350static int
351oprint(struct riscv_op *op, vm_offset_t loc, int insn)
352{
353	uint32_t rd, rs1, rs2, rs3;
354	uint32_t val;
355	const char *csr_name;
356	int imm;
357	char *p;
358
359	p = op->fmt;
360
361	rd = (insn & RD_MASK) >> RD_SHIFT;
362	rs1 = (insn & RS1_MASK) >> RS1_SHIFT;
363	rs2 = (insn & RS2_MASK) >> RS2_SHIFT;
364
365	db_printf("%s\t", op->name);
366
367	while (*p) {
368		switch (*p) {
369		case 'C':	/* C-Compressed ISA extension */
370			switch (*++p) {
371			case 't':
372				rd = (insn >> 2) & 0x7;
373				rd += 0x8;
374				db_printf("%s", reg_name[rd]);
375				break;
376			case 's':
377				rs2 = (insn >> 7) & 0x7;
378				rs2 += 0x8;
379				db_printf("%s", reg_name[rs2]);
380				break;
381			case 'l':
382				imm = ((insn >> 10) & 0x7) << 3;
383				imm |= ((insn >> 5) & 0x3) << 6;
384				if (imm & (1 << 8))
385					imm |= 0xffffff << 8;
386				db_printf("%d", imm);
387				break;
388			case 'k':
389				imm = ((insn >> 10) & 0x7) << 3;
390				imm |= ((insn >> 6) & 0x1) << 2;
391				imm |= ((insn >> 5) & 0x1) << 6;
392				if (imm & (1 << 8))
393					imm |= 0xffffff << 8;
394				db_printf("%d", imm);
395				break;
396			case 'c':
397				db_printf("sp");
398				break;
399			case 'n':
400				imm = ((insn >> 5) & 0x3) << 3;
401				imm |= ((insn >> 12) & 0x1) << 5;
402				imm |= ((insn >> 2) & 0x7) << 6;
403				if (imm & (1 << 8))
404					imm |= 0xffffff << 8;
405				db_printf("%d", imm);
406				break;
407			case 'N':
408				imm = ((insn >> 10) & 0x7) << 3;
409				imm |= ((insn >> 7) & 0x7) << 6;
410				if (imm & (1 << 8))
411					imm |= 0xffffff << 8;
412				db_printf("%d", imm);
413				break;
414			case 'u':
415				imm = ((insn >> 2) & 0x1f) << 0;
416				imm |= ((insn >> 12) & 0x1) << 5;
417				if (imm & (1 << 5))
418					imm |= (0x7ffffff << 5); /* sign ext */
419				db_printf("0x%x", imm);
420				break;
421			case 'o':
422				imm = ((insn >> 2) & 0x1f) << 0;
423				imm |= ((insn >> 12) & 0x1) << 5;
424				if (imm & (1 << 5))
425					imm |= (0x7ffffff << 5); /* sign ext */
426				db_printf("%d", imm);
427				break;
428			case 'a':
429				/* imm[11|4|9:8|10|6|7|3:1|5] << 2 */
430				imm = ((insn >> 3) & 0x7) << 1;
431				imm |= ((insn >> 11) & 0x1) << 4;
432				imm |= ((insn >> 2) & 0x1) << 5;
433				imm |= ((insn >> 7) & 0x1) << 6;
434				imm |= ((insn >> 6) & 0x1) << 7;
435				imm |= ((insn >> 9) & 0x3) << 8;
436				imm |= ((insn >> 8) & 0x1) << 10;
437				imm |= ((insn >> 12) & 0x1) << 11;
438				if (imm & (1 << 11))
439					imm |= (0xfffff << 12);	/* sign ext */
440				db_printf("0x%lx", (loc + imm));
441				break;
442			case 'V':
443				rs2 = (insn >> 2) & 0x1f;
444				db_printf("%s", reg_name[rs2]);
445				break;
446			case '>':
447				imm = ((insn >> 2) & 0x1f) << 0;
448				imm |= ((insn >> 12) & 0x1) << 5;
449				db_printf("%d", imm);
450			};
451			break;
452		case 'd':
453			db_printf("%s", reg_name[rd]);
454			break;
455		case 'D':
456			db_printf("%s", fp_reg_name[rd]);
457			break;
458		case 's':
459			db_printf("%s", reg_name[rs1]);
460			break;
461		case 'S':
462			db_printf("%s", fp_reg_name[rs1]);
463			break;
464		case 't':
465			db_printf("%s", reg_name[rs2]);
466			break;
467		case 'T':
468			db_printf("%s", fp_reg_name[rs2]);
469			break;
470		case 'R':
471			rs3 = (insn >> 27) & 0x1f;
472			db_printf("%s", fp_reg_name[rs3]);
473			break;
474		case 'Z':
475			imm = (insn >> 15) & 0x1f;
476			db_printf("%d", imm);
477			break;
478		case 'p':
479			imm = ((insn >> 8) & 0xf) << 1;
480			imm |= ((insn >> 25) & 0x3f) << 5;
481			imm |= ((insn >> 7) & 0x1) << 11;
482			imm |= ((insn >> 31) & 0x1) << 12;
483			if (imm & (1 << 12))
484				imm |= (0xfffff << 12);	/* sign extend */
485			db_printf("0x%016lx", (loc + imm));
486			break;
487		case '(':
488		case ')':
489		case '[':
490		case ']':
491		case ',':
492			db_printf("%c", *p);
493			break;
494		case '0':
495			if (!p[1])
496				db_printf("%c", *p);
497			break;
498
499		case 'o':
500			imm = (insn >> 20) & 0xfff;
501			if (imm & (1 << 11))
502				imm |= (0xfffff << 12);	/* sign extend */
503			db_printf("%d", imm);
504			break;
505		case 'q':
506			imm = (insn >> 7) & 0x1f;
507			imm |= ((insn >> 25) & 0x7f) << 5;
508			if (imm & (1 << 11))
509				imm |= (0xfffff << 12);	/* sign extend */
510			db_printf("%d", imm);
511			break;
512		case 'a':
513			/* imm[20|10:1|11|19:12] << 12 */
514			imm = ((insn >> 21) & 0x3ff) << 1;
515			imm |= ((insn >> 20) & 0x1) << 11;
516			imm |= ((insn >> 12) & 0xff) << 12;
517			imm |= ((insn >> 31) & 0x1) << 20;
518			if (imm & (1 << 20))
519				imm |= (0xfff << 20);	/* sign extend */
520			db_printf("0x%lx", (loc + imm));
521			break;
522		case 'u':
523			/* imm[31:12] << 12 */
524			imm = (insn >> 12) & 0xfffff;
525			if (imm & (1 << 20))
526				imm |= (0xfff << 20);	/* sign extend */
527			db_printf("0x%x", imm);
528			break;
529		case 'j':
530			/* imm[11:0] << 20 */
531			imm = (insn >> 20) & 0xfff;
532			if (imm & (1 << 11))
533				imm |= (0xfffff << 12); /* sign extend */
534			db_printf("%d", imm);
535			break;
536		case '>':
537			val = (insn >> 20) & 0x3f;
538			db_printf("0x%x", val);
539			break;
540		case '<':
541			val = (insn >> 20) & 0x1f;
542			db_printf("0x%x", val);
543			break;
544		case 'E':
545			val = (insn >> 20) & 0xfff;
546			csr_name = NULL;
547			switch (val) {
548#define DECLARE_CSR(name, num) case num: csr_name = #name; break;
549#include "machine/encoding.h"
550#undef DECLARE_CSR
551			}
552			if (csr_name)
553				db_printf("%s", csr_name);
554			else
555				db_printf("0x%x", val);
556			break;
557		case 'P':
558			if (insn & (1 << 27)) db_printf("i");
559			if (insn & (1 << 26)) db_printf("o");
560			if (insn & (1 << 25)) db_printf("r");
561			if (insn & (1 << 24)) db_printf("w");
562			break;
563		case 'Q':
564			if (insn & (1 << 23)) db_printf("i");
565			if (insn & (1 << 22)) db_printf("o");
566			if (insn & (1 << 21)) db_printf("r");
567			if (insn & (1 << 20)) db_printf("w");
568			break;
569		}
570
571		p++;
572	}
573
574	return (0);
575}
576
577vm_offset_t
578db_disasm(vm_offset_t loc, bool altfmt)
579{
580	struct riscv_op *op;
581	uint32_t insn;
582	int j;
583
584	insn = db_get_value(loc, 4, 0);
585	for (j = 0; riscv_opcodes[j].name != NULL; j++) {
586		op = &riscv_opcodes[j];
587		if (op->match_func(op, insn)) {
588			oprint(op, loc, insn);
589			return(loc + 4);
590		}
591	};
592
593	insn = db_get_value(loc, 2, 0);
594	for (j = 0; riscv_c_opcodes[j].name != NULL; j++) {
595		op = &riscv_c_opcodes[j];
596		if (op->match_func(op, insn)) {
597			oprint(op, loc, insn);
598			break;
599		}
600	};
601
602	return(loc + 2);
603}
604