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