11 virtual std::string
to_string(insn_t val
) const = 0;
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"
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"
29 class load_address_t
: public arg_t
33 virtual std::string
to_string(insn_t insn
) const
36 s
<< insn
.itype
.imm12
<< '(' << xpr_to_string
[insn
.itype
.rs1
] << ')';
41 class store_address_t
: public arg_t
45 virtual std::string
to_string(insn_t insn
) const
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
] << ')';
55 class amo_address_t
: public arg_t
59 virtual std::string
to_string(insn_t insn
) const
62 s
<< "0(" << xpr_to_string
[insn
.itype
.rs1
] << ')';
67 class xrd_reg_t
: public arg_t
71 virtual std::string
to_string(insn_t insn
) const
73 return xpr_to_string
[insn
.itype
.rd
];
77 class xrs1_reg_t
: public arg_t
81 virtual std::string
to_string(insn_t insn
) const
83 return xpr_to_string
[insn
.itype
.rs1
];
87 class xrs2_reg_t
: public arg_t
91 virtual std::string
to_string(insn_t insn
) const
93 return xpr_to_string
[insn
.rtype
.rs2
];
97 class frd_reg_t
: public arg_t
101 virtual std::string
to_string(insn_t insn
) const
103 return fpr_to_string
[insn
.ftype
.rd
];
107 class frs1_reg_t
: public arg_t
111 virtual std::string
to_string(insn_t insn
) const
113 return fpr_to_string
[insn
.ftype
.rs1
];
117 class frs2_reg_t
: public arg_t
121 virtual std::string
to_string(insn_t insn
) const
123 return fpr_to_string
[insn
.ftype
.rs2
];
127 class frs3_reg_t
: public arg_t
131 virtual std::string
to_string(insn_t insn
) const
133 return fpr_to_string
[insn
.ftype
.rs3
];
137 class pcr_reg_t
: public arg_t
141 virtual std::string
to_string(insn_t insn
) const
144 s
<< "pcr" << insn
.rtype
.rs2
;
149 class imm_t
: public arg_t
153 virtual std::string
to_string(insn_t insn
) const
156 s
<< insn
.itype
.imm12
;
161 class bigimm_t
: public arg_t
165 virtual std::string
to_string(insn_t insn
) const
168 s
<< std::hex
<< "0x" << insn
.ltype
.bigimm
;
173 class branch_target_t
: public arg_t
177 virtual std::string
to_string(insn_t insn
) const
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
);
189 class jump_target_t
: public arg_t
193 virtual std::string
to_string(insn_t insn
) const
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
);
204 // workaround for lack of initializer_list in gcc-4.1
208 disasm_insn_t(const char* name
, uint32_t match
, uint32_t mask
)
210 init(name
, match
, mask
, 0);
212 disasm_insn_t(const char* name
, uint32_t match
, uint32_t mask
,
215 init(name
, match
, mask
, 1, a0
);
217 disasm_insn_t(const char* name
, uint32_t match
, uint32_t mask
,
218 const arg_t
* a0
, const arg_t
* a1
)
220 init(name
, match
, mask
, 2, a0
, a1
);
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
)
225 init(name
, match
, mask
, 3, a0
, a1
, a2
);
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
,
231 init(name
, match
, mask
, 4, a0
, a1
, a2
, a3
);
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
)
237 init(name
, match
, mask
, 5, a0
, a1
, a2
, a3
, a4
);
240 bool operator == (insn_t insn
) const
242 return (insn
.bits
& mask
) == match
;
245 std::string
to_string(insn_t insn
) const
249 for (len
= 0; name
[len
]; len
++)
250 s
<< (name
[len
] == '_' ? '.' : name
[len
]);
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
);
262 uint32_t get_match() const { return match
; }
263 uint32_t get_mask() const { return mask
; }
268 std::vector
<const arg_t
*> args
;
271 void init(const char* name
, uint32_t match
, uint32_t mask
, int n
, ...)
275 for (int i
= 0; i
< n
; i
++)
276 args
.push_back(va_arg(vl
, const arg_t
*));
284 std::string
disassembler::disassemble(insn_t insn
)
286 const disasm_insn_t
* disasm_insn
= lookup(insn
);
287 return disasm_insn
? disasm_insn
->to_string(insn
) : "unknown";
290 disassembler::disassembler()
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
;
310 dummy
.rtype
.rs1
= -1;
311 uint32_t mask_rs1
= dummy
.bits
;
313 dummy
.rtype
.rs2
= -1;
314 uint32_t mask_rs2
= dummy
.bits
;
317 uint32_t mask_rd
= dummy
.bits
;
319 dummy
.itype
.imm12
= -1;
320 uint32_t mask_imm
= dummy
.bits
;
323 uint32_t match_rd_ra
= dummy
.bits
;
326 uint32_t match_rs1_ra
= dummy
.bits
;
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;
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)
374 DEFINE_XAMO(amoadd_w
)
375 DEFINE_XAMO(amoswap_w
)
376 DEFINE_XAMO(amoand_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
)
386 DEFINE_XAMO(amomin_d
)
387 DEFINE_XAMO(amomax_d
)
388 DEFINE_XAMO(amominu_d
)
389 DEFINE_XAMO(amomaxu_d
)
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
);
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
));
418 DEFINE_ITYPE(jalr_c
);
419 DEFINE_ITYPE(jalr_r
);
420 DEFINE_ITYPE(jalr_j
);
422 DEFINE_I0TYPE("li", addi
);
423 DEFINE_I1TYPE("move", addi
);
451 DEFINE_RTYPE(mulhsu
);
467 DEFINE_NOARG(syscall
);
470 DEFINE_NOARG(fence_i
);
472 DEFINE_DTYPE(rdcycle
);
473 DEFINE_DTYPE(rdtime
);
474 DEFINE_DTYPE(rdinstret
);
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
));
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
);
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
);
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
));
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));
554 const disasm_insn_t
* disassembler::lookup(insn_t insn
)
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
];
562 for (size_t j
= 0; j
< chain
[idx
].size(); j
++)
563 if(*chain
[idx
][j
] == insn
)
564 return chain
[idx
][j
];
569 void disassembler::add_insn(disasm_insn_t
* insn
)
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
);
577 disassembler::~disassembler()
579 for (size_t i
= 0; i
< HASH_SIZE
+1; i
++)
580 for (size_t j
= 0; j
< chain
[i
].size(); j
++)