mirror of
				https://github.com/RetroDECK/Duckstation.git
				synced 2025-04-10 19:15:14 +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
 | 
