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