Remove dependence on binutils
[riscv-isa-sim.git] / riscv / disasm.cc
1 #include "disasm.h"
2 #include <string>
3 #include <vector>
4 #include <cstdarg>
5 #include <sstream>
6
7 class arg_t
8 {
9 public:
10 virtual std::string to_string(insn_t val) const = 0;
11 virtual ~arg_t() {}
12 };
13
14 static const char* xpr_to_string[] = {
15 "zero", "ra", "v0", "v1", "a0", "a1", "a2", "a3",
16 "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
17 "t4", "t5", "t6", "t7", "s0", "s1", "s2", "s3",
18 "s4", "s5", "s6", "s7", "s8", "s9", "sp", "tp"
19 };
20
21 static const char* fpr_to_string[] = {
22 "ft0", "ft1", "fv0", "fv1", "fa0", "fa1", "fa2", "fa3",
23 "fa4", "fa5", "fa6", "fa7", "ft0", "ft1", "ft2", "ft3",
24 "ft4", "ft5", "ft6", "ft7", "fs0", "fs1", "fs2", "fs3",
25 "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", "ft10", "ft11"
26 };
27
28 class load_address_t : public arg_t
29 {
30 public:
31 virtual std::string to_string(insn_t insn) const
32 {
33 std::stringstream s;
34 s << insn.itype.imm12 << '(' << xpr_to_string[insn.itype.rs1] << ')';
35 return s.str();
36 }
37 };
38
39 class store_address_t : public arg_t
40 {
41 public:
42 virtual std::string to_string(insn_t insn) const
43 {
44 std::stringstream s;
45 int32_t imm = (int32_t)insn.btype.immlo;
46 imm |= insn.btype.immhi << IMMLO_BITS;
47 s << imm << '(' << xpr_to_string[insn.itype.rs1] << ')';
48 return s.str();
49 }
50 };
51
52 class amo_address_t : public arg_t
53 {
54 public:
55 virtual std::string to_string(insn_t insn) const
56 {
57 std::stringstream s;
58 s << "0(" << xpr_to_string[insn.itype.rs1] << ')';
59 return s.str();
60 }
61 };
62
63 class xrd_reg_t : public arg_t
64 {
65 public:
66 virtual std::string to_string(insn_t insn) const
67 {
68 return xpr_to_string[insn.itype.rd];
69 }
70 };
71
72 class xrs1_reg_t : public arg_t
73 {
74 public:
75 virtual std::string to_string(insn_t insn) const
76 {
77 return xpr_to_string[insn.itype.rs1];
78 }
79 };
80
81 class xrs2_reg_t : public arg_t
82 {
83 public:
84 virtual std::string to_string(insn_t insn) const
85 {
86 return xpr_to_string[insn.rtype.rs2];
87 }
88 };
89
90 class frd_reg_t : public arg_t
91 {
92 public:
93 virtual std::string to_string(insn_t insn) const
94 {
95 return fpr_to_string[insn.ftype.rd];
96 }
97 };
98
99 class frs1_reg_t : public arg_t
100 {
101 public:
102 virtual std::string to_string(insn_t insn) const
103 {
104 return fpr_to_string[insn.ftype.rs1];
105 }
106 };
107
108 class frs2_reg_t : public arg_t
109 {
110 public:
111 virtual std::string to_string(insn_t insn) const
112 {
113 return fpr_to_string[insn.ftype.rs2];
114 }
115 };
116
117 class frs3_reg_t : public arg_t
118 {
119 public:
120 virtual std::string to_string(insn_t insn) const
121 {
122 return fpr_to_string[insn.ftype.rs3];
123 }
124 };
125
126 class pcr_reg_t : public arg_t
127 {
128 public:
129 virtual std::string to_string(insn_t insn) const
130 {
131 std::stringstream s;
132 s << "pcr" << insn.rtype.rs2;
133 return s.str();
134 }
135 };
136
137 class imm_t : public arg_t
138 {
139 public:
140 virtual std::string to_string(insn_t insn) const
141 {
142 std::stringstream s;
143 s << insn.itype.imm12;
144 return s.str();
145 }
146 };
147
148 class bigimm_t : public arg_t
149 {
150 public:
151 virtual std::string to_string(insn_t insn) const
152 {
153 std::stringstream s;
154 s << std::hex << "0x" << insn.ltype.bigimm;
155 return s.str();
156 }
157 };
158
159 class branch_target_t : public arg_t
160 {
161 public:
162 virtual std::string to_string(insn_t insn) const
163 {
164 std::stringstream s;
165 int32_t target = (int32_t)insn.btype.immlo;
166 target |= insn.btype.immhi << IMMLO_BITS;
167 target <<= BRANCH_ALIGN_BITS;
168 char sign = target >= 0 ? '+' : '-';
169 s << "pc " << sign << std::hex << " 0x" << abs(target);
170 return s.str();
171 }
172 };
173
174 class jump_target_t : public arg_t
175 {
176 public:
177 virtual std::string to_string(insn_t insn) const
178 {
179 std::stringstream s;
180 int32_t target = (int32_t)insn.jtype.target;
181 target <<= JUMP_ALIGN_BITS;
182 char sign = target >= 0 ? '+' : '-';
183 s << "pc " << sign << std::hex << " 0x" << abs(target);
184 return s.str();
185 }
186 };
187
188 // workaround for lack of initializer_list in gcc-4.1
189 class disasm_insn_t
190 {
191 public:
192 disasm_insn_t(const char* name, uint32_t match, uint32_t mask)
193 {
194 init(name, match, mask, 0);
195 }
196 disasm_insn_t(const char* name, uint32_t match, uint32_t mask,
197 const arg_t* a0)
198 {
199 init(name, match, mask, 1, a0);
200 }
201 disasm_insn_t(const char* name, uint32_t match, uint32_t mask,
202 const arg_t* a0, const arg_t* a1)
203 {
204 init(name, match, mask, 2, a0, a1);
205 }
206 disasm_insn_t(const char* name, uint32_t match, uint32_t mask,
207 const arg_t* a0, const arg_t* a1, const arg_t* a2)
208 {
209 init(name, match, mask, 3, a0, a1, a2);
210 }
211 disasm_insn_t(const char* name, uint32_t match, uint32_t mask,
212 const arg_t* a0, const arg_t* a1, const arg_t* a2,
213 const arg_t* a3)
214 {
215 init(name, match, mask, 4, a0, a1, a2, a3);
216 }
217 disasm_insn_t(const char* name, uint32_t match, uint32_t mask,
218 const arg_t* a0, const arg_t* a1, const arg_t* a2,
219 const arg_t* a3, const arg_t* a4)
220 {
221 init(name, match, mask, 5, a0, a1, a2, a3, a4);
222 }
223
224 bool operator == (insn_t insn) const
225 {
226 return (insn.bits & mask) == match;
227 }
228
229 std::string to_string(insn_t insn) const
230 {
231 std::stringstream s;
232 int len;
233 for (len = 0; name[len]; len++)
234 s << (name[len] == '_' ? '.' : name[len]);
235
236 if (args.size())
237 {
238 s << std::string(std::max(1, 8 - len), ' ');
239 for (size_t i = 0; i < args.size()-1; i++)
240 s << args[i]->to_string(insn) << ", ";
241 s << args[args.size()-1]->to_string(insn);
242 }
243 return s.str();
244 }
245
246 uint32_t get_match() const { return match; }
247 uint32_t get_mask() const { return mask; }
248
249 private:
250 uint32_t match;
251 uint32_t mask;
252 std::vector<const arg_t*> args;
253 const char* name;
254
255 void init(const char* name, uint32_t match, uint32_t mask, int n, ...)
256 {
257 va_list vl;
258 va_start(vl, n);
259 for (int i = 0; i < n; i++)
260 args.push_back(va_arg(vl, const arg_t*));
261 va_end(vl);
262 this->match = match;
263 this->mask = mask;
264 this->name = name;
265 }
266 };
267
268 std::string disassembler::disassemble(insn_t insn)
269 {
270 const disasm_insn_t* disasm_insn = lookup(insn);
271 return disasm_insn ? disasm_insn->to_string(insn) : "unknown";
272 }
273
274 disassembler::disassembler()
275 {
276 static const xrd_reg_t _xrd_reg, *xrd_reg = &_xrd_reg;
277 static const xrs1_reg_t _xrs1_reg, *xrs1_reg = &_xrs1_reg;
278 static const load_address_t _load_address, *load_address = &_load_address;
279 static const store_address_t _store_address, *store_address = &_store_address;
280 static const amo_address_t _amo_address, *amo_address = &_amo_address;
281 static const xrs2_reg_t _xrs2_reg, *xrs2_reg = &_xrs2_reg;
282 static const frd_reg_t _frd_reg, *frd_reg = &_frd_reg;
283 static const frs1_reg_t _frs1_reg, *frs1_reg = &_frs1_reg;
284 static const frs2_reg_t _frs2_reg, *frs2_reg = &_frs2_reg;
285 static const frs3_reg_t _frs3_reg, *frs3_reg = &_frs3_reg;
286 static const pcr_reg_t _pcr_reg, *pcr_reg = &_pcr_reg;
287 static const imm_t _imm, *imm = &_imm;
288 static const bigimm_t _bigimm, *bigimm = &_bigimm;
289 static const branch_target_t _branch_target, *branch_target = &_branch_target;
290 static const jump_target_t _jump_target, *jump_target = &_jump_target;
291
292 insn_t dummy;
293 dummy.bits = 0;
294 dummy.rtype.rs1 = -1;
295 uint32_t mask_rs1 = dummy.bits;
296 dummy.bits = 0;
297 dummy.rtype.rs2 = -1;
298 uint32_t mask_rs2 = dummy.bits;
299 dummy.bits = 0;
300 dummy.rtype.rd = -1;
301 uint32_t mask_rd = dummy.bits;
302 dummy.bits = 0;
303 dummy.itype.imm12 = -1;
304 uint32_t mask_imm = dummy.bits;
305 dummy.bits = 0;
306 dummy.itype.rd = 1;
307 uint32_t match_rd_ra = dummy.bits;
308 dummy.bits = 0;
309 dummy.itype.rs1 = 1;
310 uint32_t match_rs1_ra = dummy.bits;
311
312 #define DECLARE_INSN(code, match, mask) \
313 const uint32_t __attribute__((unused)) match_##code = match; \
314 const uint32_t __attribute__((unused)) mask_##code = mask;
315 #include "opcodes.h"
316 #undef DECLARE_INSN
317
318 // explicit per-instruction disassembly
319 #define DISASM_INSN(name, code, extra, ...) \
320 add_insn(new disasm_insn_t(name, match_##code, mask_##code | (extra), __VA_ARGS__));
321 #define DEFINE_NOARG(code) \
322 add_insn(new disasm_insn_t(#code, match_##code, mask_##code));
323 #define DEFINE_DTYPE(code) DISASM_INSN(#code, code, 0, xrd_reg)
324 #define DEFINE_RTYPE(code) DISASM_INSN(#code, code, 0, xrd_reg, xrs1_reg, xrs2_reg)
325 #define DEFINE_ITYPE(code) DISASM_INSN(#code, code, 0, xrd_reg, xrs1_reg, imm)
326 #define DEFINE_I0TYPE(name, code) DISASM_INSN(name, code, mask_rs1, xrd_reg, imm)
327 #define DEFINE_I1TYPE(name, code) DISASM_INSN(name, code, mask_imm, xrd_reg, xrs1_reg)
328 #define DEFINE_I2TYPE(name, code) DISASM_INSN(name, code, mask_rd | mask_imm, xrs1_reg)
329 #define DEFINE_LTYPE(code) DISASM_INSN(#code, code, 0, xrd_reg, bigimm)
330 #define DEFINE_BTYPE(code) DISASM_INSN(#code, code, 0, xrs1_reg, xrs2_reg, branch_target)
331 #define DEFINE_B0TYPE(name, code) DISASM_INSN(name, code, mask_rs1 | mask_rs2, branch_target)
332 #define DEFINE_B1TYPE(name, code) DISASM_INSN(name, code, mask_rs2, xrs1_reg, branch_target)
333 #define DEFINE_JTYPE(code) DISASM_INSN(#code, code, 0, jump_target)
334 #define DEFINE_XLOAD(code) DISASM_INSN(#code, code, 0, xrd_reg, load_address)
335 #define DEFINE_XSTORE(code) DISASM_INSN(#code, code, 0, xrs2_reg, store_address)
336 #define DEFINE_XAMO(code) DISASM_INSN(#code, code, 0, xrd_reg, xrs2_reg, amo_address)
337 #define DEFINE_FLOAD(code) DISASM_INSN(#code, code, 0, frd_reg, load_address)
338 #define DEFINE_FSTORE(code) DISASM_INSN(#code, code, 0, frs2_reg, store_address)
339 #define DEFINE_FRTYPE(code) DISASM_INSN(#code, code, 0, frd_reg, frs1_reg, frs2_reg)
340 #define DEFINE_FR1TYPE(code) DISASM_INSN(#code, code, 0, frd_reg, frs1_reg)
341 #define DEFINE_FR3TYPE(code) DISASM_INSN(#code, code, 0, frd_reg, frs1_reg, frs2_reg, frs3_reg)
342 #define DEFINE_FXTYPE(code) DISASM_INSN(#code, code, 0, xrd_reg, frs1_reg)
343 #define DEFINE_XFTYPE(code) DISASM_INSN(#code, code, 0, frd_reg, xrs1_reg)
344
345 DEFINE_XLOAD(lb)
346 DEFINE_XLOAD(lbu)
347 DEFINE_XLOAD(lh)
348 DEFINE_XLOAD(lhu)
349 DEFINE_XLOAD(lw)
350 DEFINE_XLOAD(lwu)
351 DEFINE_XLOAD(ld)
352
353 DEFINE_XSTORE(sb)
354 DEFINE_XSTORE(sh)
355 DEFINE_XSTORE(sw)
356 DEFINE_XSTORE(sd)
357
358 DEFINE_XAMO(amoadd_w)
359 DEFINE_XAMO(amoswap_w)
360 DEFINE_XAMO(amoand_w)
361 DEFINE_XAMO(amoor_w)
362 DEFINE_XAMO(amomin_w)
363 DEFINE_XAMO(amomax_w)
364 DEFINE_XAMO(amominu_w)
365 DEFINE_XAMO(amomaxu_w)
366 DEFINE_XAMO(amoadd_d)
367 DEFINE_XAMO(amoswap_d)
368 DEFINE_XAMO(amoand_d)
369 DEFINE_XAMO(amoor_d)
370 DEFINE_XAMO(amomin_d)
371 DEFINE_XAMO(amomax_d)
372 DEFINE_XAMO(amominu_d)
373 DEFINE_XAMO(amomaxu_d)
374
375 DEFINE_FLOAD(flw)
376 DEFINE_FLOAD(fld)
377
378 DEFINE_FSTORE(fsw)
379 DEFINE_FSTORE(fsd)
380
381 DEFINE_JTYPE(j);
382 DEFINE_JTYPE(jal);
383
384 DEFINE_B0TYPE("b", beq);
385 DEFINE_B1TYPE("beqz", beq);
386 DEFINE_B1TYPE("bnez", bne);
387 DEFINE_B1TYPE("bltz", blt);
388 DEFINE_B1TYPE("bgez", bge);
389 DEFINE_BTYPE(beq)
390 DEFINE_BTYPE(bne)
391 DEFINE_BTYPE(blt)
392 DEFINE_BTYPE(bge)
393 DEFINE_BTYPE(bltu)
394 DEFINE_BTYPE(bgeu)
395
396 DEFINE_LTYPE(lui);
397
398 DEFINE_I2TYPE("jr", jalr_j);
399 add_insn(new disasm_insn_t("jalr", match_jalr_c | match_rd_ra, mask_jalr_c | mask_rd | mask_imm, xrs1_reg));
400 add_insn(new disasm_insn_t("ret", match_jalr_r | match_rs1_ra, mask_jalr_r | mask_rd | mask_rs1 | mask_imm));
401 DEFINE_DTYPE(rdnpc);
402 DEFINE_ITYPE(jalr_c);
403 DEFINE_ITYPE(jalr_r);
404 DEFINE_ITYPE(jalr_j);
405
406 DEFINE_I0TYPE("li", addi);
407 DEFINE_I1TYPE("move", addi);
408 DEFINE_ITYPE(addi);
409 DEFINE_ITYPE(slli);
410 DEFINE_ITYPE(slti);
411 DEFINE_ITYPE(sltiu);
412 DEFINE_ITYPE(xori);
413 DEFINE_ITYPE(srli);
414 DEFINE_ITYPE(srai);
415 DEFINE_ITYPE(ori);
416 DEFINE_ITYPE(andi);
417 DEFINE_ITYPE(addiw);
418 DEFINE_ITYPE(slliw);
419 DEFINE_ITYPE(srliw);
420 DEFINE_ITYPE(sraiw);
421
422 DEFINE_RTYPE(add);
423 DEFINE_RTYPE(sub);
424 DEFINE_RTYPE(sll);
425 DEFINE_RTYPE(slt);
426 DEFINE_RTYPE(sltiu);
427 DEFINE_RTYPE(xor);
428 DEFINE_RTYPE(srl);
429 DEFINE_RTYPE(sra);
430 DEFINE_RTYPE(or);
431 DEFINE_RTYPE(and);
432 DEFINE_RTYPE(mul);
433 DEFINE_RTYPE(mulh);
434 DEFINE_RTYPE(mulhu);
435 DEFINE_RTYPE(mulhsu);
436 DEFINE_RTYPE(div);
437 DEFINE_RTYPE(divu);
438 DEFINE_RTYPE(rem);
439 DEFINE_RTYPE(remu);
440 DEFINE_RTYPE(addw);
441 DEFINE_RTYPE(subw);
442 DEFINE_RTYPE(sllw);
443 DEFINE_RTYPE(srlw);
444 DEFINE_RTYPE(sraw);
445 DEFINE_RTYPE(mulw);
446 DEFINE_RTYPE(divw);
447 DEFINE_RTYPE(divuw);
448 DEFINE_RTYPE(remw);
449 DEFINE_RTYPE(remuw);
450
451 DEFINE_NOARG(syscall);
452 DEFINE_NOARG(break);
453 DEFINE_NOARG(fence);
454 DEFINE_NOARG(fence_i);
455
456 DEFINE_DTYPE(rdcycle);
457 DEFINE_DTYPE(rdtime);
458 DEFINE_DTYPE(rdinstret);
459
460 add_insn(new disasm_insn_t("mtpcr", match_mtpcr, mask_mtpcr, xrs1_reg, pcr_reg));
461 add_insn(new disasm_insn_t("mfpcr", match_mfpcr, mask_mfpcr, xrd_reg, pcr_reg));
462 DEFINE_NOARG(cflush)
463 DEFINE_NOARG(eret)
464 DEFINE_DTYPE(ei)
465 DEFINE_DTYPE(di)
466
467 DEFINE_FRTYPE(fadd_s);
468 DEFINE_FRTYPE(fsub_s);
469 DEFINE_FRTYPE(fmul_s);
470 DEFINE_FRTYPE(fdiv_s);
471 DEFINE_FR1TYPE(fsqrt_s);
472 DEFINE_FRTYPE(fmin_s);
473 DEFINE_FRTYPE(fmax_s);
474 DEFINE_FR3TYPE(fmadd_s);
475 DEFINE_FR3TYPE(fmsub_s);
476 DEFINE_FR3TYPE(fnmadd_s);
477 DEFINE_FR3TYPE(fnmsub_s);
478 DEFINE_FRTYPE(fsgnj_s);
479 DEFINE_FRTYPE(fsgnjn_s);
480 DEFINE_FRTYPE(fsgnjx_s);
481 DEFINE_FR1TYPE(fcvt_s_d);
482 DEFINE_XFTYPE(fcvt_s_l);
483 DEFINE_XFTYPE(fcvt_s_lu);
484 DEFINE_XFTYPE(fcvt_s_w);
485 DEFINE_XFTYPE(fcvt_s_wu);
486 DEFINE_XFTYPE(fcvt_s_wu);
487 DEFINE_XFTYPE(mxtf_s);
488 DEFINE_FXTYPE(fcvt_l_s);
489 DEFINE_FXTYPE(fcvt_lu_s);
490 DEFINE_FXTYPE(fcvt_w_s);
491 DEFINE_FXTYPE(fcvt_wu_s);
492 DEFINE_FXTYPE(mftx_s);
493 DEFINE_FXTYPE(feq_s);
494 DEFINE_FXTYPE(flt_s);
495 DEFINE_FXTYPE(fle_s);
496
497 DEFINE_FRTYPE(fadd_d);
498 DEFINE_FRTYPE(fsub_d);
499 DEFINE_FRTYPE(fmul_d);
500 DEFINE_FRTYPE(fdiv_d);
501 DEFINE_FR1TYPE(fsqrt_d);
502 DEFINE_FRTYPE(fmin_d);
503 DEFINE_FRTYPE(fmax_d);
504 DEFINE_FR3TYPE(fmadd_d);
505 DEFINE_FR3TYPE(fmsub_d);
506 DEFINE_FR3TYPE(fnmadd_d);
507 DEFINE_FR3TYPE(fnmsub_d);
508 DEFINE_FRTYPE(fsgnj_d);
509 DEFINE_FRTYPE(fsgnjn_d);
510 DEFINE_FRTYPE(fsgnjx_d);
511 DEFINE_FR1TYPE(fcvt_d_s);
512 DEFINE_XFTYPE(fcvt_d_l);
513 DEFINE_XFTYPE(fcvt_d_lu);
514 DEFINE_XFTYPE(fcvt_d_w);
515 DEFINE_XFTYPE(fcvt_d_wu);
516 DEFINE_XFTYPE(fcvt_d_wu);
517 DEFINE_XFTYPE(mxtf_d);
518 DEFINE_FXTYPE(fcvt_l_d);
519 DEFINE_FXTYPE(fcvt_lu_d);
520 DEFINE_FXTYPE(fcvt_w_d);
521 DEFINE_FXTYPE(fcvt_wu_d);
522 DEFINE_FXTYPE(mftx_d);
523 DEFINE_FXTYPE(feq_d);
524 DEFINE_FXTYPE(flt_d);
525 DEFINE_FXTYPE(fle_d);
526
527 add_insn(new disasm_insn_t("mtfsr", match_mtfsr, mask_mtfsr | mask_rd, xrs1_reg));
528 add_insn(new disasm_insn_t("mtfsr", match_mtfsr, mask_mtfsr, xrd_reg, xrs1_reg));
529 DEFINE_DTYPE(mffsr);
530
531 // provide a default disassembly for all instructions as a fallback
532 #define DECLARE_INSN(code, match, mask) \
533 add_insn(new disasm_insn_t(#code " (args unknown)", match, mask));
534 #include "opcodes.h"
535 #undef DECLARE_INSN
536 }
537
538 const disasm_insn_t* disassembler::lookup(insn_t insn)
539 {
540 size_t idx = insn.bits % HASH_SIZE;
541 for (size_t j = 0; j < chain[idx].size(); j++)
542 if(*chain[idx][j] == insn)
543 return chain[idx][j];
544
545 idx = HASH_SIZE;
546 for (size_t j = 0; j < chain[idx].size(); j++)
547 if(*chain[idx][j] == insn)
548 return chain[idx][j];
549
550 return NULL;
551 }
552
553 void disassembler::add_insn(disasm_insn_t* insn)
554 {
555 size_t idx = HASH_SIZE;
556 if (insn->get_mask() % HASH_SIZE == HASH_SIZE - 1)
557 idx = insn->get_match() % HASH_SIZE;
558 chain[idx].push_back(insn);
559 }
560
561 disassembler::~disassembler()
562 {
563 for (size_t i = 0; i < HASH_SIZE+1; i++)
564 for (size_t j = 0; j < chain[i].size(); j++)
565 delete chain[i][j];
566 }