mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-24 06:35:42 +00:00
521 lines
9.7 KiB
C
521 lines
9.7 KiB
C
/*
|
|
* RISC-V Disassembler
|
|
*
|
|
* Copyright (c) 2016-2017 Michael Clark <michaeljclark@mac.com>
|
|
* Copyright (c) 2017-2018 SiFive, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
#ifndef RISCV_DISASSEMBLER_H
|
|
#define RISCV_DISASSEMBLER_H
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <inttypes.h>
|
|
#include <string.h>
|
|
|
|
/* types */
|
|
|
|
typedef uint64_t rv_inst;
|
|
typedef uint16_t rv_opcode;
|
|
|
|
/* enums */
|
|
|
|
typedef enum {
|
|
rv32,
|
|
rv64,
|
|
rv128
|
|
} rv_isa;
|
|
|
|
typedef enum {
|
|
rv_rm_rne = 0,
|
|
rv_rm_rtz = 1,
|
|
rv_rm_rdn = 2,
|
|
rv_rm_rup = 3,
|
|
rv_rm_rmm = 4,
|
|
rv_rm_dyn = 7,
|
|
} rv_rm;
|
|
|
|
typedef enum {
|
|
rv_fence_i = 8,
|
|
rv_fence_o = 4,
|
|
rv_fence_r = 2,
|
|
rv_fence_w = 1,
|
|
} rv_fence;
|
|
|
|
typedef enum {
|
|
rv_ireg_zero,
|
|
rv_ireg_ra,
|
|
rv_ireg_sp,
|
|
rv_ireg_gp,
|
|
rv_ireg_tp,
|
|
rv_ireg_t0,
|
|
rv_ireg_t1,
|
|
rv_ireg_t2,
|
|
rv_ireg_s0,
|
|
rv_ireg_s1,
|
|
rv_ireg_a0,
|
|
rv_ireg_a1,
|
|
rv_ireg_a2,
|
|
rv_ireg_a3,
|
|
rv_ireg_a4,
|
|
rv_ireg_a5,
|
|
rv_ireg_a6,
|
|
rv_ireg_a7,
|
|
rv_ireg_s2,
|
|
rv_ireg_s3,
|
|
rv_ireg_s4,
|
|
rv_ireg_s5,
|
|
rv_ireg_s6,
|
|
rv_ireg_s7,
|
|
rv_ireg_s8,
|
|
rv_ireg_s9,
|
|
rv_ireg_s10,
|
|
rv_ireg_s11,
|
|
rv_ireg_t3,
|
|
rv_ireg_t4,
|
|
rv_ireg_t5,
|
|
rv_ireg_t6,
|
|
} rv_ireg;
|
|
|
|
typedef enum {
|
|
rvc_end,
|
|
rvc_rd_eq_ra,
|
|
rvc_rd_eq_x0,
|
|
rvc_rs1_eq_x0,
|
|
rvc_rs2_eq_x0,
|
|
rvc_rs2_eq_rs1,
|
|
rvc_rs1_eq_ra,
|
|
rvc_imm_eq_zero,
|
|
rvc_imm_eq_n1,
|
|
rvc_imm_eq_p1,
|
|
rvc_csr_eq_0x001,
|
|
rvc_csr_eq_0x002,
|
|
rvc_csr_eq_0x003,
|
|
rvc_csr_eq_0xc00,
|
|
rvc_csr_eq_0xc01,
|
|
rvc_csr_eq_0xc02,
|
|
rvc_csr_eq_0xc80,
|
|
rvc_csr_eq_0xc81,
|
|
rvc_csr_eq_0xc82,
|
|
} rvc_constraint;
|
|
|
|
typedef enum {
|
|
rv_codec_illegal,
|
|
rv_codec_none,
|
|
rv_codec_u,
|
|
rv_codec_uj,
|
|
rv_codec_i,
|
|
rv_codec_i_sh5,
|
|
rv_codec_i_sh6,
|
|
rv_codec_i_sh7,
|
|
rv_codec_i_csr,
|
|
rv_codec_s,
|
|
rv_codec_sb,
|
|
rv_codec_r,
|
|
rv_codec_r_m,
|
|
rv_codec_r4_m,
|
|
rv_codec_r_a,
|
|
rv_codec_r_l,
|
|
rv_codec_r_f,
|
|
rv_codec_cb,
|
|
rv_codec_cb_imm,
|
|
rv_codec_cb_sh5,
|
|
rv_codec_cb_sh6,
|
|
rv_codec_ci,
|
|
rv_codec_ci_sh5,
|
|
rv_codec_ci_sh6,
|
|
rv_codec_ci_16sp,
|
|
rv_codec_ci_lwsp,
|
|
rv_codec_ci_ldsp,
|
|
rv_codec_ci_lqsp,
|
|
rv_codec_ci_li,
|
|
rv_codec_ci_lui,
|
|
rv_codec_ci_none,
|
|
rv_codec_ciw_4spn,
|
|
rv_codec_cj,
|
|
rv_codec_cj_jal,
|
|
rv_codec_cl_lw,
|
|
rv_codec_cl_ld,
|
|
rv_codec_cl_lq,
|
|
rv_codec_cr,
|
|
rv_codec_cr_mv,
|
|
rv_codec_cr_jalr,
|
|
rv_codec_cr_jr,
|
|
rv_codec_cs,
|
|
rv_codec_cs_sw,
|
|
rv_codec_cs_sd,
|
|
rv_codec_cs_sq,
|
|
rv_codec_css_swsp,
|
|
rv_codec_css_sdsp,
|
|
rv_codec_css_sqsp,
|
|
} rv_codec;
|
|
|
|
typedef enum {
|
|
rv_op_illegal,
|
|
rv_op_lui,
|
|
rv_op_auipc,
|
|
rv_op_jal,
|
|
rv_op_jalr,
|
|
rv_op_beq,
|
|
rv_op_bne,
|
|
rv_op_blt,
|
|
rv_op_bge,
|
|
rv_op_bltu,
|
|
rv_op_bgeu,
|
|
rv_op_lb,
|
|
rv_op_lh,
|
|
rv_op_lw,
|
|
rv_op_lbu,
|
|
rv_op_lhu,
|
|
rv_op_sb,
|
|
rv_op_sh,
|
|
rv_op_sw,
|
|
rv_op_addi,
|
|
rv_op_slti,
|
|
rv_op_sltiu,
|
|
rv_op_xori,
|
|
rv_op_ori,
|
|
rv_op_andi,
|
|
rv_op_slli,
|
|
rv_op_srli,
|
|
rv_op_srai,
|
|
rv_op_add,
|
|
rv_op_sub,
|
|
rv_op_sll,
|
|
rv_op_slt,
|
|
rv_op_sltu,
|
|
rv_op_xor,
|
|
rv_op_srl,
|
|
rv_op_sra,
|
|
rv_op_or,
|
|
rv_op_and,
|
|
rv_op_fence,
|
|
rv_op_fence_i,
|
|
rv_op_lwu,
|
|
rv_op_ld,
|
|
rv_op_sd,
|
|
rv_op_addiw,
|
|
rv_op_slliw,
|
|
rv_op_srliw,
|
|
rv_op_sraiw,
|
|
rv_op_addw,
|
|
rv_op_subw,
|
|
rv_op_sllw,
|
|
rv_op_srlw,
|
|
rv_op_sraw,
|
|
rv_op_ldu,
|
|
rv_op_lq,
|
|
rv_op_sq,
|
|
rv_op_addid,
|
|
rv_op_sllid,
|
|
rv_op_srlid,
|
|
rv_op_sraid,
|
|
rv_op_addd,
|
|
rv_op_subd,
|
|
rv_op_slld,
|
|
rv_op_srld,
|
|
rv_op_srad,
|
|
rv_op_mul,
|
|
rv_op_mulh,
|
|
rv_op_mulhsu,
|
|
rv_op_mulhu,
|
|
rv_op_div,
|
|
rv_op_divu,
|
|
rv_op_rem,
|
|
rv_op_remu,
|
|
rv_op_mulw,
|
|
rv_op_divw,
|
|
rv_op_divuw,
|
|
rv_op_remw,
|
|
rv_op_remuw,
|
|
rv_op_muld,
|
|
rv_op_divd,
|
|
rv_op_divud,
|
|
rv_op_remd,
|
|
rv_op_remud,
|
|
rv_op_lr_w,
|
|
rv_op_sc_w,
|
|
rv_op_amoswap_w,
|
|
rv_op_amoadd_w,
|
|
rv_op_amoxor_w,
|
|
rv_op_amoor_w,
|
|
rv_op_amoand_w,
|
|
rv_op_amomin_w,
|
|
rv_op_amomax_w,
|
|
rv_op_amominu_w,
|
|
rv_op_amomaxu_w,
|
|
rv_op_lr_d,
|
|
rv_op_sc_d,
|
|
rv_op_amoswap_d,
|
|
rv_op_amoadd_d,
|
|
rv_op_amoxor_d,
|
|
rv_op_amoor_d,
|
|
rv_op_amoand_d,
|
|
rv_op_amomin_d,
|
|
rv_op_amomax_d,
|
|
rv_op_amominu_d,
|
|
rv_op_amomaxu_d,
|
|
rv_op_lr_q,
|
|
rv_op_sc_q,
|
|
rv_op_amoswap_q,
|
|
rv_op_amoadd_q,
|
|
rv_op_amoxor_q,
|
|
rv_op_amoor_q,
|
|
rv_op_amoand_q,
|
|
rv_op_amomin_q,
|
|
rv_op_amomax_q,
|
|
rv_op_amominu_q,
|
|
rv_op_amomaxu_q,
|
|
rv_op_ecall,
|
|
rv_op_ebreak,
|
|
rv_op_uret,
|
|
rv_op_sret,
|
|
rv_op_hret,
|
|
rv_op_mret,
|
|
rv_op_dret,
|
|
rv_op_sfence_vm,
|
|
rv_op_sfence_vma,
|
|
rv_op_wfi,
|
|
rv_op_csrrw,
|
|
rv_op_csrrs,
|
|
rv_op_csrrc,
|
|
rv_op_csrrwi,
|
|
rv_op_csrrsi,
|
|
rv_op_csrrci,
|
|
rv_op_flw,
|
|
rv_op_fsw,
|
|
rv_op_fmadd_s,
|
|
rv_op_fmsub_s,
|
|
rv_op_fnmsub_s,
|
|
rv_op_fnmadd_s,
|
|
rv_op_fadd_s,
|
|
rv_op_fsub_s,
|
|
rv_op_fmul_s,
|
|
rv_op_fdiv_s,
|
|
rv_op_fsgnj_s,
|
|
rv_op_fsgnjn_s,
|
|
rv_op_fsgnjx_s,
|
|
rv_op_fmin_s,
|
|
rv_op_fmax_s,
|
|
rv_op_fsqrt_s,
|
|
rv_op_fle_s,
|
|
rv_op_flt_s,
|
|
rv_op_feq_s,
|
|
rv_op_fcvt_w_s,
|
|
rv_op_fcvt_wu_s,
|
|
rv_op_fcvt_s_w,
|
|
rv_op_fcvt_s_wu,
|
|
rv_op_fmv_x_s,
|
|
rv_op_fclass_s,
|
|
rv_op_fmv_s_x,
|
|
rv_op_fcvt_l_s,
|
|
rv_op_fcvt_lu_s,
|
|
rv_op_fcvt_s_l,
|
|
rv_op_fcvt_s_lu,
|
|
rv_op_fld,
|
|
rv_op_fsd,
|
|
rv_op_fmadd_d,
|
|
rv_op_fmsub_d,
|
|
rv_op_fnmsub_d,
|
|
rv_op_fnmadd_d,
|
|
rv_op_fadd_d,
|
|
rv_op_fsub_d,
|
|
rv_op_fmul_d,
|
|
rv_op_fdiv_d,
|
|
rv_op_fsgnj_d,
|
|
rv_op_fsgnjn_d,
|
|
rv_op_fsgnjx_d,
|
|
rv_op_fmin_d,
|
|
rv_op_fmax_d,
|
|
rv_op_fcvt_s_d,
|
|
rv_op_fcvt_d_s,
|
|
rv_op_fsqrt_d,
|
|
rv_op_fle_d,
|
|
rv_op_flt_d,
|
|
rv_op_feq_d,
|
|
rv_op_fcvt_w_d,
|
|
rv_op_fcvt_wu_d,
|
|
rv_op_fcvt_d_w,
|
|
rv_op_fcvt_d_wu,
|
|
rv_op_fclass_d,
|
|
rv_op_fcvt_l_d,
|
|
rv_op_fcvt_lu_d,
|
|
rv_op_fmv_x_d,
|
|
rv_op_fcvt_d_l,
|
|
rv_op_fcvt_d_lu,
|
|
rv_op_fmv_d_x,
|
|
rv_op_flq,
|
|
rv_op_fsq,
|
|
rv_op_fmadd_q,
|
|
rv_op_fmsub_q,
|
|
rv_op_fnmsub_q,
|
|
rv_op_fnmadd_q,
|
|
rv_op_fadd_q,
|
|
rv_op_fsub_q,
|
|
rv_op_fmul_q,
|
|
rv_op_fdiv_q,
|
|
rv_op_fsgnj_q,
|
|
rv_op_fsgnjn_q,
|
|
rv_op_fsgnjx_q,
|
|
rv_op_fmin_q,
|
|
rv_op_fmax_q,
|
|
rv_op_fcvt_s_q,
|
|
rv_op_fcvt_q_s,
|
|
rv_op_fcvt_d_q,
|
|
rv_op_fcvt_q_d,
|
|
rv_op_fsqrt_q,
|
|
rv_op_fle_q,
|
|
rv_op_flt_q,
|
|
rv_op_feq_q,
|
|
rv_op_fcvt_w_q,
|
|
rv_op_fcvt_wu_q,
|
|
rv_op_fcvt_q_w,
|
|
rv_op_fcvt_q_wu,
|
|
rv_op_fclass_q,
|
|
rv_op_fcvt_l_q,
|
|
rv_op_fcvt_lu_q,
|
|
rv_op_fcvt_q_l,
|
|
rv_op_fcvt_q_lu,
|
|
rv_op_fmv_x_q,
|
|
rv_op_fmv_q_x,
|
|
rv_op_c_addi4spn,
|
|
rv_op_c_fld,
|
|
rv_op_c_lw,
|
|
rv_op_c_flw,
|
|
rv_op_c_fsd,
|
|
rv_op_c_sw,
|
|
rv_op_c_fsw,
|
|
rv_op_c_nop,
|
|
rv_op_c_addi,
|
|
rv_op_c_jal,
|
|
rv_op_c_li,
|
|
rv_op_c_addi16sp,
|
|
rv_op_c_lui,
|
|
rv_op_c_srli,
|
|
rv_op_c_srai,
|
|
rv_op_c_andi,
|
|
rv_op_c_sub,
|
|
rv_op_c_xor,
|
|
rv_op_c_or,
|
|
rv_op_c_and,
|
|
rv_op_c_subw,
|
|
rv_op_c_addw,
|
|
rv_op_c_j,
|
|
rv_op_c_beqz,
|
|
rv_op_c_bnez,
|
|
rv_op_c_slli,
|
|
rv_op_c_fldsp,
|
|
rv_op_c_lwsp,
|
|
rv_op_c_flwsp,
|
|
rv_op_c_jr,
|
|
rv_op_c_mv,
|
|
rv_op_c_ebreak,
|
|
rv_op_c_jalr,
|
|
rv_op_c_add,
|
|
rv_op_c_fsdsp,
|
|
rv_op_c_swsp,
|
|
rv_op_c_fswsp,
|
|
rv_op_c_ld,
|
|
rv_op_c_sd,
|
|
rv_op_c_addiw,
|
|
rv_op_c_ldsp,
|
|
rv_op_c_sdsp,
|
|
rv_op_c_lq,
|
|
rv_op_c_sq,
|
|
rv_op_c_lqsp,
|
|
rv_op_c_sqsp,
|
|
rv_op_nop,
|
|
rv_op_mv,
|
|
rv_op_not,
|
|
rv_op_neg,
|
|
rv_op_negw,
|
|
rv_op_sext_w,
|
|
rv_op_seqz,
|
|
rv_op_snez,
|
|
rv_op_sltz,
|
|
rv_op_sgtz,
|
|
rv_op_fmv_s,
|
|
rv_op_fabs_s,
|
|
rv_op_fneg_s,
|
|
rv_op_fmv_d,
|
|
rv_op_fabs_d,
|
|
rv_op_fneg_d,
|
|
rv_op_fmv_q,
|
|
rv_op_fabs_q,
|
|
rv_op_fneg_q,
|
|
rv_op_beqz,
|
|
rv_op_bnez,
|
|
rv_op_blez,
|
|
rv_op_bgez,
|
|
rv_op_bltz,
|
|
rv_op_bgtz,
|
|
rv_op_ble,
|
|
rv_op_bleu,
|
|
rv_op_bgt,
|
|
rv_op_bgtu,
|
|
rv_op_j,
|
|
rv_op_ret,
|
|
rv_op_jr,
|
|
rv_op_rdcycle,
|
|
rv_op_rdtime,
|
|
rv_op_rdinstret,
|
|
rv_op_rdcycleh,
|
|
rv_op_rdtimeh,
|
|
rv_op_rdinstreth,
|
|
rv_op_frcsr,
|
|
rv_op_frrm,
|
|
rv_op_frflags,
|
|
rv_op_fscsr,
|
|
rv_op_fsrm,
|
|
rv_op_fsflags,
|
|
rv_op_fsrmi,
|
|
rv_op_fsflagsi,
|
|
} rv_op;
|
|
|
|
/* structures */
|
|
|
|
typedef struct {
|
|
uint64_t pc;
|
|
uint64_t inst;
|
|
int32_t imm;
|
|
uint16_t op;
|
|
uint8_t codec;
|
|
uint8_t rd;
|
|
uint8_t rs1;
|
|
uint8_t rs2;
|
|
uint8_t rs3;
|
|
uint8_t rm;
|
|
uint8_t pred;
|
|
uint8_t succ;
|
|
uint8_t aq;
|
|
uint8_t rl;
|
|
} rv_decode;
|
|
|
|
/* functions */
|
|
|
|
size_t inst_length(rv_inst inst);
|
|
void inst_fetch(const uint8_t *data, rv_inst *instp, size_t *length);
|
|
void disasm_inst(char *buf, size_t buflen, rv_isa isa, uint64_t pc, rv_inst inst);
|
|
|
|
#endif
|