xref: /inferno-os/utils/libmach/idb.c (revision e5242bb522d11e83d4ae2e9dab758ec8433940d7)
1 #include <lib9.h>
2 #include <bio.h>
3 #include <mach.h>
4 #include "ic/i.out.h"
5 
6 static char *riscvexcep(Map*, Rgetter);
7 
8 /*
9  * RISCV-specific debugger interface
10  */
11 
12 typedef struct	Instr	Instr;
13 struct	Instr
14 {
15 	Map	*map;
16 	ulong	w;
17 	uvlong	addr;
18 	char *fmt;
19 	int n;
20 	int	op;
21 	int	func3;
22 	int	func7;
23 	char	rs1, rs2, rs3, rd;
24 	char	rv64;
25 	long	imm;
26 
27 	char*	curr;			/* fill point in buffer */
28 	char*	end;			/* end of buffer */
29 };
30 
31 typedef struct Optab	Optab;
32 struct Optab {
33 	int	func7;
34 	int	op[8];
35 };
36 
37 typedef struct Opclass	Opclass;
38 struct Opclass {
39 	char	*fmt;
40 	Optab	tab[4];
41 };
42 
43 /* Major opcodes */
44 enum {
45 	OLOAD,	 OLOAD_FP,  Ocustom_0,	OMISC_MEM, OOP_IMM, OAUIPC, OOP_IMM_32,	O48b,
46 	OSTORE,	 OSTORE_FP, Ocustom_1,	OAMO,	   OOP,	    OLUI,   OOP_32,	O64b,
47 	OMADD,	 OMSUB,	    ONMSUB,	ONMADD,	   OOP_FP,  Ores_0, Ocustom_2,	O48b_2,
48 	OBRANCH, OJALR,	    Ores_1,	OJAL,	   OSYSTEM, Ores_2, Ocustom_3,	O80b
49 };
50 
51 /* copy anames from compiler */
52 static
53 #include "ic/enam.c"
54 
55 static Opclass opOLOAD = {
56 	"a,d",
57 	0,	AMOVB,	AMOVH,	AMOVW,	AMOV,	AMOVBU,	AMOVHU,	AMOVWU,	0,
58 };
59 static Opclass opOLOAD_FP = {
60 	"a,fd",
61 	0,	0,	0,	AMOVF,	AMOVD,	0,	0,	0,	0,
62 };
63 static Opclass opOMISC_MEM = {
64 	"",
65 	0,	AFENCE,	AFENCE_I,0,	0,	0,	0,	0,	0,
66 };
67 static Opclass opOOP_IMM = {
68 	"$i,s,d",
69 	0x20,	0,	0,	0,	0,	0,	ASRA,	0,	0,
70 	0,	AADD,	ASLL,	ASLT,	ASLTU,	AXOR,	ASRL,	AOR,	AAND,
71 };
72 static Opclass opOAUIPC = {
73 	"$i(PC),d",
74 	0,	ALUI,	ALUI,	ALUI,	ALUI,	ALUI,	ALUI,	ALUI,	ALUI,
75 };
76 static Opclass opOOP_IMM_32 = {
77 	"$i,s,d",
78 	0x20,	0,	0,	0,	0,	0,	ASRAW,	0,	0,
79 	0,	AADDW,	ASLLW,	0,	0,	0,	ASRLW,	0,	0,
80 };
81 static Opclass opOSTORE = {
82 	"2,a",
83 	0,	AMOVB,	AMOVH,	AMOVW,	AMOV,	0,	0,	0,	0,
84 };
85 static Opclass opOSTORE_FP = {
86 	"f2,a",
87 	0,	0,	0,	AMOVF,	AMOVD,	0,	0,	0,	0,
88 };
89 static Opclass opOAMO = {
90 	"7,2,s,d",
91 	0x04,	0,	0,	ASWAP_W,ASWAP_D,0,	0,	0,	0,
92 	0x08,	0,	0,	ALR_W,	ALR_D,	0,	0,	0,	0,
93 	0x0C,	0,	0,	ASC_W,	ASC_D,	0,	0,	0,	0,
94 	0,	0,	0,	AAMO_W,	AAMO_D,	0,	0,	0,	0,
95 };
96 static Opclass opOOP = {
97 	"2,s,d",
98 	0x01,	AMUL,	AMULH,	AMULHSU,AMULHU,	ADIV,	ADIVU,	AREM,	AREMU,
99 	0x20,	ASUB,	0,	0,	0,	0,	ASRA,	0,	0,
100 	0,	AADD,	ASLL,	ASLT,	ASLTU,	AXOR,	ASRL,	AOR,	AAND,
101 };
102 static Opclass opOLUI = {
103 	"$i,d",
104 	0,	ALUI,	ALUI,	ALUI,	ALUI,	ALUI,	ALUI,	ALUI,	ALUI,
105 };
106 static Opclass opOOP_32 = {
107 	"2,s,d",
108 	0x01,	AMULW,	0,	0,	0,	ADIVW,	ADIVUW,	AREMW,	AREMUW,
109 	0x20,	ASUBW,	0,	0,	0,	0,	ASRAW,	0,	0,
110 	0,	AADDW,	ASLLW,	0,	0,	0,	ASRLW,	0,	0,
111 };
112 static Opclass opOBRANCH = {
113 	"2,s,p",
114 	0,	ABEQ,	ABNE,	0,	0,	ABLT,	ABGE,	ABLTU,	ABGEU,
115 };
116 static Opclass opOJALR = {
117 	"d,a",
118 	0,	AJALR,	AJALR,	AJALR,	AJALR,	AJALR,	AJALR,	AJALR,	AJALR,
119 };
120 static Opclass opOJAL = {
121 	"d,p",
122 	0,	AJAL,	AJAL,	AJAL,	AJAL,	AJAL,	AJAL,	AJAL,	AJAL,
123 };
124 static Opclass opOSYSTEM = {
125 	"",
126 	0,	ASYS,	ACSRRW,	ACSRRS,	ACSRRC,	0,	ACSRRWI,ACSRRSI,ACSRRCI,
127 };
128 static char fmtcsr[] = "c,s,d";
129 static char fmtcsri[] = "c,js,d";
130 static char *fmtOSYSTEM[8] = {
131 	"$i", fmtcsr, fmtcsr, fmtcsr, "", fmtcsri, fmtcsri, fmtcsri,
132 };
133 static Opclass opOOP_FP = {
134 	"fs,fd",
135 	0x0,	AADDF,	ASUBF,	AMULF,	ADIVF,	AMOVF,	0,	0,	0,
136 	0x1,	AMOVDF,	0,	0,	0,	0,	0,	0,	0,
137 	0x2,	ACMPLEF,ACMPLTF,ACMPEQF,0,	0,	0,	0,	0,
138 	0x3,	AMOVFW,	0,	AMOVFV,	0,	AMOVWF,	AMOVUF,	AMOVVF,	AMOVUVF,
139 };
140 static Opclass opOOP_DP = {
141 	"f2,fs,fd",
142 	0x0,	AADDD,	ASUBD,	AMULD,	ADIVD,	AMOVD,	0,	0,	0,
143 	0x1,	AMOVFD,	0,	0,	0,	0,	0,	0,	0,
144 	0x2,	ACMPLED,ACMPLTD,ACMPEQD,0,	0,	0,	0,	0,
145 	0x3,	AMOVDW,	0,	AMOVDV,	0,	AMOVWD,	AMOVUD,	AMOVVD,	AMOVUVD,
146 };
147 
148 typedef struct Compclass Compclass;
149 struct Compclass {
150 	char	*fmt;
151 	uchar	immbits[18];
152 };
153 
154 static Compclass rv32compressed[0x2D] = {
155 /* 00-07 ([1:0] = 0) ([15:13] = 0-7) */
156 	{"ADDI4SPN $i,d", 22, 6, 5, 11, 12, 7, 8, 9, 10},          /* 12:5 → 5:4|9:6|2|3 */
157 	{"FLD a,fd",      24, 10, 11, 12, 5, 6},                   /* 12:10|6:5 → 5:3|7:6 */
158 	{"LW a,d",        25, 6, 10, 11, 12, 5},                   /* 12:10|6:5 → 5:2|6 */
159 	{"FLW a,fd",      25, 6, 10, 11, 12, 5},                   /* 12:10|6:5 → 5:2|6 rv32 */
160 	{"? ",	0},
161 	{"FSD f2,a",      24, 10, 11, 12, 5, 6},                   /* 12:10|6:5 → 5:3|7:6 */
162 	{"SW 2,a",        25, 6, 10, 11, 12, 5},                   /* 12:10|6:5 → 5:2|6 */
163 	{"FSW f2,a",      25, 6, 10, 11, 12, 5},                   /* 12:10|6:5 → 5:2|6 rv32 */
164 
165 /* 08-0F ([1:0] = 1) ([15:13] = 0-7 not 4) */
166 	{"ADDI $i,d",    ~26, 2, 3, 4, 5, 6, 12},                  /* 12|6:2 → * 5:0 */
167 	{"JAL p",        ~20, 3, 4, 5, 11, 2, 7, 6, 9, 10, 8, 12}, /* 12:2 → * 11|4|9:8|10|6|7|3:1|5 rv32 D*/
168 	{"LI $i,d",      ~26, 2, 3, 4, 5, 6, 12},                  /* 12|6:2 → * 5:0 */
169 	{"LUI $i,d",     ~14, 2, 3, 4, 5, 6, 12},                  /* 12|6:2 → * 17:12 */
170 	{"? ",	0},
171 	{"J p",          ~20, 3, 4, 5, 11, 2, 7, 6, 9, 10, 8, 12}, /* 12:2 → * 11|4|9:8|10|6|7|3:1|5 */
172 	{"BEQZ s,p",     ~23, 3, 4, 10, 11, 2, 5, 6, 12},          /* 12:10|6:2 → * 8|4|3|7:6|2:1|5 */
173 	{"BNEZ s,p",     ~23, 3, 4, 10, 11, 2, 5, 6, 12},          /* 12:10|6:2 → * 8|4|3|7:6|2:1|5 */
174 
175 /* 10-17  ([1:0] = 2) ([15:13] = 0-7 not 4) */
176 	{"SLLI $i,d",     26, 2, 3, 4, 5, 6, 12},                  /* 12|6:2 → 5:0 */
177 	{"FLDSP i,fd",    23, 5, 6, 12, 2, 3, 4},                  /* 12|6:2 → 5:3|8:6 */
178 	{"LWSP i,d",      24, 4, 5, 6, 12, 2, 3},                  /* 12|6:2 → 5:2|7:6 */
179 	{"FLWSP i,fd",    24, 4, 5, 6, 12, 2, 3},                  /* 12|6:2 → 5:2|7:6 rv32 */
180 	{"? ",	0},
181 	{"FSDSP f2,$i",   23, 10, 11, 12, 7, 8, 9},                /* 12:7 → 5:3|8:6 */
182 	{"SWSP 2,$i",     24, 9, 10, 11, 12, 7, 8},                /* 12:7 → 5:2|7:6 */
183 	{"FSWSP f2,$i",   24, 9, 10, 11, 12, 7, 8},                /* 12:7 → 5:2|7:6 rv32 */
184 
185 /* 18-1A  ([1:0] = 1) ([15:13] = 4) ([11:10] = 0-2) */
186 	{"SRLI $i,d",     26, 2, 3, 4, 5, 6, 12},                  /* 12|6:2 → 5:0 */
187 	{"SRAI $i,d",     26, 2, 3, 4, 5, 6, 12},                  /* 12|6:2 → 5:0 */
188 	{"ANDI $i,d",    ~26, 2, 3, 4, 5, 6, 12},                  /* 12|6:2 → * 5:0 */
189 
190 /* 1B-22 ([1:0] = 1) ([15:13] = 4) ([11:10] = 3) ([12] = 0-1) ([6:5] = 0-3) */
191 	{"SUB 2,d",	0},
192 	{"XOR 2,d",	0},
193 	{"OR 2,d",	0},
194 	{"AND 2,d",	0},
195 	{"SUBW 2,d",	0},		/* rv64 */
196 	{"ADDW 2,d",	0},		/* rv64 */
197 	{"? ",	0},
198 	{"? ",	0},
199 
200 /* 23-26 ([1:0] = 2) ([15:13] = 4) ((rs2 != 0) = 0-1) */
201 	{"JR s",	0},
202 	{"MV 2,d",	0},
203 	{"JALR s",	0},
204 	{"ADD 2,d",	0},
205 
206 /* 27-27 ([1:0] = 1) ([15:13] = 3) ( rd = 2) */
207 	{"ADDI16SP $i",  ~22, 6, 2, 5, 3, 4, 12},                  /* 12|6:2 → * 9|4|6|8:7|5 */
208 
209 /* 28-2C  rv64 alternates */
210 	{"LD a,d",	24, 10, 11, 12, 5, 6},                         /* 12:10|6:5 → 5:3|7:6 */
211 	{"SD 2,a",	24, 10, 11, 12, 5, 6},                         /* 12:10|6:5 → 5:3|7:6 */
212 	{"ADDIW $i,d",	~26, 2, 3, 4, 5, 6, 12},                   /* 12|6:2 → * 5:0 */
213 	{"LDSP i,d",	23, 5, 6, 12, 2, 3, },                     /* 12|6:2 → 5:3|8:6 */
214 	{"SDSP 2,i",	23, 10, 11, 12, 7, 8, 9}	               /* 12:7 → 5:3|8:6 */
215 };
216 
217 /* map major opcodes to opclass table */
218 static Opclass *opclass[32] = {
219 	[OLOAD]		&opOLOAD,
220 	[OLOAD_FP]	&opOLOAD_FP,
221 	[OMISC_MEM]	&opOMISC_MEM,
222 	[OOP_IMM]	&opOOP_IMM,
223 	[OAUIPC]	&opOAUIPC,
224 	[OOP_IMM_32]	&opOOP_IMM_32,
225 	[OSTORE]	&opOSTORE,
226 	[OSTORE_FP]	&opOSTORE_FP,
227 	[OAMO]		&opOAMO,
228 	[OOP]		&opOOP,
229 	[OLUI]		&opOLUI,
230 	[OOP_FP]	&opOOP_FP,
231 	[OOP_32]	&opOOP_32,
232 	[OBRANCH]	&opOBRANCH,
233 	[OJALR]		&opOJALR,
234 	[OJAL]		&opOJAL,
235 	[OSYSTEM]	&opOSYSTEM,
236 };
237 
238 /*
239  * Print value v as name[+offset]
240  */
241 static int
242 gsymoff(char *buf, int n, ulong v, int space)
243 {
244 	Symbol s;
245 	int r;
246 	long delta;
247 
248 	r = delta = 0;		/* to shut compiler up */
249 	if (v) {
250 		r = findsym(v, space, &s);
251 		if (r)
252 			delta = v-s.value;
253 		if (delta < 0)
254 			delta = -delta;
255 	}
256 	if (v == 0 || r == 0 || delta >= 4096)
257 		return snprint(buf, n, "#%lux", v);
258 	if (strcmp(s.name, ".string") == 0)
259 		return snprint(buf, n, "#%lux", v);
260 	if (!delta)
261 		return snprint(buf, n, "%s", s.name);
262 	if (s.type != 't' && s.type != 'T')
263 		return snprint(buf, n, "%s+%llux", s.name, v-s.value);
264 	else
265 		return snprint(buf, n, "#%lux", v);
266 }
267 
268 #pragma	varargck	argpos	bprint		2
269 
270 static void
271 bprint(Instr *i, char *fmt, ...)
272 {
273 	va_list arg;
274 
275 	va_start(arg, fmt);
276 	i->curr = vseprint(i->curr, i->end, fmt, arg);
277 	va_end(arg);
278 }
279 
280 static void
281 format(Instr *i, char *opcode, char *f)
282 {
283 	int c;
284 	long imm;
285 	char reg;
286 
287 	reg = 'R';
288 	if(opcode != nil){
289 		bprint(i, "%s", opcode);
290 		if(f == 0)
291 			return;
292 		bprint(i, "\t");
293 	}else
294 		bprint(i, "C.");
295 	for(; (c = *f); f++){
296 		switch(c){
297 		default:
298 			bprint(i, "%c", c);
299 			break;
300 		case ' ':
301 			bprint(i, "\t");
302 			break;
303 		case 'f':
304 			reg = 'F';
305 			break;
306 		case 'j':
307 			reg = '$';
308 			break;
309 		case 's':
310 			bprint(i, "%c%d", reg, i->rs1);
311 			reg = 'R';
312 			break;
313 		case '2':
314 			bprint(i, "%c%d", reg, i->rs2);
315 			reg = 'R';
316 			break;
317 		case '3':
318 			bprint(i, "%c%d", reg, i->rs3);
319 			break;
320 		case 'd':
321 			bprint(i, "%c%d", reg, i->rd);
322 			reg = 'R';
323 			break;
324 		case 'i':
325 			imm = i->imm;
326 			if(imm < 0)
327 				bprint(i, "-%lux", -imm);
328 			else
329 				bprint(i, "%lux", imm);
330 			break;
331 		case 'p':
332 			imm = i->addr + i->imm;
333 			i->curr += gsymoff(i->curr, i->end-i->curr, imm, CANY);
334 			break;
335 		case 'a':
336 			if(i->rs1 == REGSB && mach->sb){
337 				i->curr += gsymoff(i->curr, i->end-i->curr, i->imm+mach->sb, CANY);
338 				bprint(i, "(SB)");
339 				break;
340 			}
341 			bprint(i, "%lx(R%d)", i->imm, i->rs1);
342 			break;
343 		case '7':
344 			bprint(i, "%ux", i->func7);
345 			break;
346 		case 'c':
347 			bprint(i, "CSR(%lx)", i->imm&0xFFF);
348 			break;
349 		}
350 	}
351 }
352 
353 static int
354 badinst(Instr *i)
355 {
356 	format(i, "???", 0);
357 	return 4;
358 }
359 
360 static long
361 immshuffle(uint w, uchar *p)
362 {
363 	int shift, i;
364 	ulong imm;
365 
366 	shift = *p++;
367 	imm = 0;
368 	while((i = *p++) != 0){
369 		imm >>= 1;
370 		if((w>>i) & 0x01)
371 			imm |= (1<<31);
372 	}
373 	if(shift & 0x80)
374 		imm = (long)imm >> (shift ^ 0xFF);
375 	else
376 		imm >>= shift;
377 	return imm;
378 }
379 
380 static int
381 decompress(Instr *i)
382 {
383 	ushort w;
384 	int op, aop;
385 	Compclass *cop;
386 
387 	w = i->w;
388 	i->n = 2;
389 	i->func3 = (w>>13)&0x7;
390 	op = w&0x3;
391 	i->op = op;
392 	switch(op){
393 	case 0:
394 		i->rd  = 8 + ((w>>2)&0x7);
395 		i->rs1 = 8 + ((w>>7)&0x7);
396 		i->rs2 = i->rd;
397 		break;
398 	case 1:
399 		i->rd = (w>>7)&0x1F;
400 		if((i->func3&0x4) != 0)
401 			i->rd = 8 + (i->rd&0x7);
402 		i->rs1 = i->rd;
403 		i->rs2 = 8 + ((w>>2)&0x7);
404 		break;
405 	case 2:
406 		i->rd = (w>>7)&0x1F;
407 		i->rs1 = i->rd;
408 		i->rs2 = (w>>2)&0x1F;
409 	}
410 	aop = (op << 3) + i->func3;
411 	if((aop & 0x7) == 4){
412 		switch(op){
413 		case 1:
414 			aop = 0x18 + ((w>>10) & 0x7);
415 			if(aop == 0x1B)
416 				aop += (w>>5) & 0x3;
417 			break;
418 		case 2:
419 			aop = 0x23 + ((w>>11) & 0x2) + (i->rs2 != 0);
420 			break;
421 		}
422 	}
423 	if(aop == 0x0B && i->rd == 2)
424 		aop = 0x27;
425 	if(i->rv64) switch(aop){
426 	case 0x03:	aop = 0x28; break;
427 	case 0x07:	aop = 0x29; break;
428 	case 0x09:	aop = 0x2A; break;
429 	case 0x13:	aop = 0x2B; break;
430 	case 0x17:	aop = 0x2C; break;
431 	}
432 	cop = &rv32compressed[aop];
433 	i->fmt = cop->fmt;
434 	i->imm = immshuffle(w, cop->immbits);
435 	return 2;
436 }
437 
438 static int
439 decode(Map *map, uvlong pc, Instr *i)
440 {
441 	ulong w;
442 	int op;
443 
444 	if(get4(map, pc, &w) < 0) {
445 		werrstr("can't read instruction: %r");
446 		return -1;
447 	}
448 	i->addr = pc;
449 	i->map = map;
450 	if((w&0x3) != 3){
451 		i->w = w & 0xFFFF;
452 		return decompress(i);
453 	}
454 	i->w = w;
455 	i->n = 4;
456 	op = (w&0x7F);
457 	i->op = op;
458 	i->func3 = (w>>12)&0x7;
459 	i->func7 = (w>>25)&0x7F;
460 	i->rs1 = (w>>15)&0x1F;
461 	i->rs2 = (w>>20)&0x1F;
462 	i->rs3 = (w>>27)&0x1F;
463 	i->rd = (w>>7)&0x1F;
464 #define FIELD(hi,lo,off)	(w>>(lo-off))&(((1<<(hi-lo+1))-1)<<off)
465 #define LFIELD(hi,lo,off)	(w<<(off-lo))&(((1<<(hi-lo+1))-1)<<off)
466 #define SFIELD(lo,off)		((long)(w&((~0)<<lo))>>(lo-off))
467 	switch(op>>2) {
468 	case OSTORE:	/* S-type */
469 	case OSTORE_FP:
470 		i->imm = SFIELD(25,5) | FIELD(11,7,0);
471 		break;
472 	case OBRANCH:	/* B-type */
473 		i->imm = SFIELD(31,12) | LFIELD(7,7,11) | FIELD(30,25,5) | FIELD(11,8,1);
474 		break;
475 	case OOP_IMM:	/* I-type */
476 	case OOP_IMM_32:
477 		if(i->func3 == 1 || i->func3 == 5){		/* special case ASL/ASR */
478 			i->imm = FIELD(25,20,0);
479 			break;
480 		}
481 	/* fall through */
482 	case OLOAD:
483 	case OLOAD_FP:
484 	case OMISC_MEM:
485 	case OJALR:
486 	case OSYSTEM:
487 		i->imm = SFIELD(20,0);
488 		break;
489 	case OAUIPC:	/* U-type */
490 	case OLUI:
491 		i->imm = SFIELD(12,12);
492 		break;
493 	case OJAL:	/* J-type */
494 		i->imm = SFIELD(31,20) | FIELD(19,12,12) | FIELD(20,20,11) | FIELD(30,21,1);
495 		break;
496 	}
497 	return 4;
498 }
499 
500 static int
501 pseudo(Instr *i, int aop)
502 {
503 	char *op;
504 
505 	switch(aop){
506 	case AJAL:
507 		if(i->rd == 0){
508 			format(i, "JMP",	"p");
509 			return 1;
510 		}
511 		break;
512 	case AJALR:
513 		if(i->rd == 0){
514 			format(i, "JMP", "a");
515 			return 1;
516 		}
517 		break;
518 	case AADD:
519 		if((i->op>>2) == OOP_IMM){
520 			op = i->rv64 ? "MOV" : "MOVW";
521 			if(i->rs1 == 0)
522 				format(i, op, "$i,d");
523 			else if(i->rs1 == REGSB && mach->sb && i->rd != REGSB)
524 				format(i, op, "$a,d");
525 			else if(i->imm == 0)
526 				format(i, op, "s,d");
527 			else break;
528 			return 1;
529 		}
530 		break;
531 	}
532 	return 0;
533 }
534 
535 static int
536 mkinstr(Instr *i)
537 {
538 	Opclass *oc;
539 	Optab *o;
540 	char *fmt;
541 	int aop;
542 
543 	if((i->op&0x3) != 0x3){
544 		format(i, nil, i->fmt);
545 		return 2;
546 	}
547 	oc = opclass[i->op>>2];
548 	if(oc == 0)
549 		return badinst(i);
550 	fmt = oc->fmt;
551 	if(oc == &opOSYSTEM)
552 		fmt = fmtOSYSTEM[i->func3];
553 	if(oc == &opOOP_FP){
554 		if(i->func7 & 1)
555 			oc = &opOOP_DP;
556 		o = &oc->tab[i->func7>>5];
557 		switch(o->func7){
558 		case 0:
559 			fmt = "f2,fs,fd";
560 		/* fall through */
561 		default:
562 			aop = o->op[(i->func7>>2)&0x7];
563 			if((i->func7&~1) == 0x10){
564 				if(i->func3 == 0 && i->rs1 == i->rs2)
565 					fmt = "fs,fd";
566 				else
567 					aop = 0;
568 			}
569 			break;
570 		case 2:
571 			aop = o->op[i->func3];
572 			break;
573 		case 3:
574 			if(i->func7 & 0x10)
575 				return badinst(i);
576 			aop = o->op[(i->func7>>1)&0x4 | (i->rs2&0x3)];
577 			if(i->func7 & 0x8)
578 				fmt = "s,fd";
579 			else
580 				fmt = "fs,d";
581 			break;
582 		}
583 		if(aop == 0)
584 			return badinst(i);
585 		format(i, anames[aop], fmt);
586 		return 4;
587 	}
588 	o = oc->tab;
589 	while(o->func7 != 0 && (i->func7 != o->func7 || o->op[i->func3] == 0))
590 		o++;
591 	if((aop = o->op[i->func3]) == 0)
592 		return badinst(i);
593 	if(pseudo(i, aop))
594 		return 4;
595 	format(i, anames[aop], fmt);
596 	return 4;
597 }
598 
599 static int
600 riscvdas(Map *map, uvlong pc, char modifier, char *buf, int n)
601 {
602 	Instr i;
603 
604 	USED(modifier);
605 	i.rv64 = 0;
606 	i.curr = buf;
607 	i.end = buf+n;
608 	if(decode(map, pc, &i) < 0)
609 		return -1;
610 	return mkinstr(&i);
611 }
612 
613 static int
614 riscv64das(Map *map, uvlong pc, char modifier, char *buf, int n)
615 {
616 	Instr i;
617 
618 	USED(modifier);
619 	i.rv64 = 1;
620 	i.curr = buf;
621 	i.end = buf+n;
622 	if(decode(map, pc, &i) < 0)
623 		return -1;
624 	return mkinstr(&i);
625 }
626 
627 static int
628 riscvhexinst(Map *map, uvlong pc, char *buf, int n)
629 {
630 	Instr i;
631 
632 	i.curr = buf;
633 	i.end = buf+n;
634 	if(decode(map, pc, &i) < 0)
635 		return -1;
636 	if(i.end-i.curr > 2*i.n)
637 		i.curr = _hexify(buf, i.w, 2*i.n - 1);
638 	*i.curr = 0;
639 	return i.n;
640 }
641 
642 static int
643 riscvinstlen(Map *map, uvlong pc)
644 {
645 	Instr i;
646 
647 	return decode(map, pc, &i);
648 }
649 
650 static char*
651 riscvexcep(Map* m, Rgetter r)
652 {
653 	return "Trap";
654 }
655 
656 /*
657  *	Debugger interface
658  */
659 Machdata riscvmach =
660 {
661 	{0x3a, 0xa0, 0x3d, 0x00},		/* break point */
662 	4,			/* break point size */
663 
664 	leswab,			/* short to local byte order */
665 	leswal,			/* long to local byte order */
666 	leswav,			/* long to local byte order */
667 	risctrace,		/* C traceback */
668 	riscframe,		/* Frame finder */
669 	riscvexcep,		/* print exception */
670 	0,				/* breakpoint fixup */
671 	0,				/* single precision float printer */
672 	0,				/* double precisioin float printer */
673 	0,				/* following addresses */
674 	riscvdas,		/* symbolic disassembly */
675 	riscvhexinst,	/* hex disassembly */
676 	riscvinstlen,	/* instruction size */
677 };
678 
679 Machdata riscv64mach =
680 {
681 	{0x3a, 0xa0, 0x3d, 0x00},		/* break point */
682 	4,			/* break point size */
683 
684 	leswab,			/* short to local byte order */
685 	leswal,			/* long to local byte order */
686 	leswav,			/* long to local byte order */
687 	risctrace,		/* C traceback */
688 	riscframe,		/* Frame finder */
689 	riscvexcep,		/* print exception */
690 	0,				/* breakpoint fixup */
691 	0,				/* single precision float printer */
692 	0,				/* double precisioin float printer */
693 	0,				/* following addresses */
694 	riscv64das,		/* symbolic disassembly */
695 	riscvhexinst,	/* hex disassembly */
696 	riscvinstlen,	/* instruction size */
697 };
698