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