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