| /* |
| * QEMU RISC-V Disassembler |
| * |
| * Copyright (c) 2016-2017 Michael Clark <michaeljclark@mac.com> |
| * Copyright (c) 2017-2018 SiFive, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms and conditions of the GNU General Public License, |
| * version 2 or later, as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| * You should have received a copy of the GNU General Public License along with |
| * this program. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include "qemu/osdep.h" |
| #include "qemu/bitops.h" |
| #include "disas/dis-asm.h" |
| #include "target/riscv/cpu_cfg.h" |
| #include "disas/riscv.h" |
| |
| /* Vendor extensions */ |
| #include "disas/riscv-xthead.h" |
| #include "disas/riscv-xventana.h" |
| #include "disas/riscv-xlrbr.h" |
| |
| /* register names */ |
| |
| static const char rv_ireg_name_sym[32][5] = { |
| "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", |
| "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", |
| "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", |
| "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", |
| }; |
| |
| static const char rv_freg_name_sym[32][5] = { |
| "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7", |
| "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", |
| "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", |
| "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11", |
| }; |
| |
| static const char rv_vreg_name_sym[32][4] = { |
| "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", |
| "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", |
| "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", |
| "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" |
| }; |
| |
| /* The FLI.[HSDQ] numeric constants (0.0 for symbolic constants). |
| * The constants use the hex floating-point literal representation |
| * that is printed when using the printf %a format specifier, |
| * which matches the output that is generated by the disassembler. |
| */ |
| static const char rv_fli_name_const[32][9] = |
| { |
| "0x1p+0", "min", "0x1p-16", "0x1p-15", |
| "0x1p-8", "0x1p-7", "0x1p-4", "0x1p-3", |
| "0x1p-2", "0x1.4p-2", "0x1.8p-2", "0x1.cp-2", |
| "0x1p-1", "0x1.4p-1", "0x1.8p-1", "0x1.cp-1", |
| "0x1p+0", "0x1.4p+0", "0x1.8p+0", "0x1.cp+0", |
| "0x1p+1", "0x1.4p+1", "0x1.8p+1", "0x1p+2", |
| "0x1p+3", "0x1p+4", "0x1p+7", "0x1p+8", |
| "0x1p+15", "0x1p+16", "inf", "nan" |
| }; |
| |
| /* pseudo-instruction constraints */ |
| |
| static const rvc_constraint rvcc_jal_ra[] = { rvc_rd_eq_ra, rvc_end }; |
| static const rvc_constraint rvcc_jalr_ra[] = { rvc_rd_eq_ra, rvc_imm_eq_zero, |
| rvc_end }; |
| static const rvc_constraint rvcc_nop[] = { rvc_rd_eq_x0, rvc_rs1_eq_x0, |
| rvc_end }; |
| static const rvc_constraint rvcc_mv[] = { rvc_imm_eq_zero, rvc_end }; |
| static const rvc_constraint rvcc_not[] = { rvc_imm_eq_n1, rvc_end }; |
| static const rvc_constraint rvcc_neg[] = { rvc_rs1_eq_x0, rvc_end }; |
| static const rvc_constraint rvcc_negw[] = { rvc_rs1_eq_x0, rvc_end }; |
| static const rvc_constraint rvcc_sext_w[] = { rvc_imm_eq_zero, rvc_end }; |
| static const rvc_constraint rvcc_seqz[] = { rvc_imm_eq_p1, rvc_end }; |
| static const rvc_constraint rvcc_snez[] = { rvc_rs1_eq_x0, rvc_end }; |
| static const rvc_constraint rvcc_sltz[] = { rvc_rs2_eq_x0, rvc_end }; |
| static const rvc_constraint rvcc_sgtz[] = { rvc_rs1_eq_x0, rvc_end }; |
| static const rvc_constraint rvcc_fmv_s[] = { rvc_rs2_eq_rs1, rvc_end }; |
| static const rvc_constraint rvcc_fabs_s[] = { rvc_rs2_eq_rs1, rvc_end }; |
| static const rvc_constraint rvcc_fneg_s[] = { rvc_rs2_eq_rs1, rvc_end }; |
| static const rvc_constraint rvcc_fmv_d[] = { rvc_rs2_eq_rs1, rvc_end }; |
| static const rvc_constraint rvcc_fabs_d[] = { rvc_rs2_eq_rs1, rvc_end }; |
| static const rvc_constraint rvcc_fneg_d[] = { rvc_rs2_eq_rs1, rvc_end }; |
| static const rvc_constraint rvcc_fmv_q[] = { rvc_rs2_eq_rs1, rvc_end }; |
| static const rvc_constraint rvcc_fabs_q[] = { rvc_rs2_eq_rs1, rvc_end }; |
| static const rvc_constraint rvcc_fneg_q[] = { rvc_rs2_eq_rs1, rvc_end }; |
| static const rvc_constraint rvcc_beqz[] = { rvc_rs2_eq_x0, rvc_end }; |
| static const rvc_constraint rvcc_bnez[] = { rvc_rs2_eq_x0, rvc_end }; |
| static const rvc_constraint rvcc_blez[] = { rvc_rs1_eq_x0, rvc_end }; |
| static const rvc_constraint rvcc_bgez[] = { rvc_rs2_eq_x0, rvc_end }; |
| static const rvc_constraint rvcc_bltz[] = { rvc_rs2_eq_x0, rvc_end }; |
| static const rvc_constraint rvcc_bgtz[] = { rvc_rs1_eq_x0, rvc_end }; |
| static const rvc_constraint rvcc_j[] = { rvc_rd_eq_x0, rvc_end }; |
| static const rvc_constraint rvcc_ret[] = { rvc_rs1_eq_ra, rvc_end }; |
| static const rvc_constraint rvcc_jr[] = { rvc_rd_eq_x0, rvc_imm_eq_zero, |
| rvc_end }; |
| static const rvc_constraint rvcc_true[] = { rvc_end }; |
| |
| /* pseudo-instruction metadata */ |
| |
| /* Forward declare the all the opcodes so that we may link them. */ |
| #define OP(N, ...) static const rv_opcode_data op_##N; |
| #include "riscv-op.c.inc" |
| #undef OP |
| |
| static const rv_comp_data rvcp_jal[] = { |
| { &op_j, rvcc_j }, |
| { &op_jal_ra, rvcc_jal_ra }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_jalr[] = { |
| { &op_jr, rvcc_jr }, |
| { &op_jalr_ra, rvcc_jalr_ra }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_jr[] = { |
| { &op_ret, rvcc_ret }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_beq[] = { |
| { &op_beqz, rvcc_beqz }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_bne[] = { |
| { &op_bnez, rvcc_bnez }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_blt[] = { |
| { &op_bltz, rvcc_bltz }, |
| { &op_bgtz, rvcc_bgtz }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_bge[] = { |
| { &op_blez, rvcc_blez }, |
| { &op_bgez, rvcc_bgez }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_addi[] = { |
| { &op_mv, rvcc_mv }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_mv[] = { |
| { &op_nop, rvcc_nop }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_sltiu[] = { |
| { &op_seqz, rvcc_seqz }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_xori[] = { |
| { &op_not, rvcc_not }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_sub[] = { |
| { &op_neg, rvcc_neg }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_slt[] = { |
| { &op_sltz, rvcc_sltz }, |
| { &op_sgtz, rvcc_sgtz }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_sltu[] = { |
| { &op_snez, rvcc_snez }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_addiw[] = { |
| { &op_sext_w, rvcc_sext_w }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_subw[] = { |
| { &op_negw, rvcc_negw }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_fsgnj_s[] = { |
| { &op_fmv_s, rvcc_fmv_s }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_fsgnjn_s[] = { |
| { &op_fneg_s, rvcc_fneg_s }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_fsgnjx_s[] = { |
| { &op_fabs_s, rvcc_fabs_s }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_fsgnj_d[] = { |
| { &op_fmv_d, rvcc_fmv_d }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_fsgnjn_d[] = { |
| { &op_fneg_d, rvcc_fneg_d }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_fsgnjx_d[] = { |
| { &op_fabs_d, rvcc_fabs_d }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_fsgnj_q[] = { |
| { &op_fmv_q, rvcc_fmv_q }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_fsgnjn_q[] = { |
| { &op_fneg_q, rvcc_fneg_q }, |
| { }, |
| }; |
| |
| static const rv_comp_data rvcp_fsgnjx_q[] = { |
| { &op_fabs_q, rvcc_fabs_q }, |
| { }, |
| }; |
| |
| /* Convert compressed insns into normal insns via pseudo expansion. */ |
| #define DECOMP(X) &(const rv_comp_data){ &X, rvcc_true } |
| |
| /* operand extractors */ |
| |
| static uint32_t operand_rd(rv_inst inst) |
| { |
| return extract32(inst, 7, 5); |
| } |
| |
| static uint32_t operand_rs1(rv_inst inst) |
| { |
| return extract32(inst, 15, 5); |
| } |
| |
| static uint32_t operand_rs2(rv_inst inst) |
| { |
| return extract32(inst, 20, 5); |
| } |
| |
| static uint32_t operand_rs3(rv_inst inst) |
| { |
| return extract32(inst, 27, 5); |
| } |
| |
| static uint32_t operand_aq(rv_inst inst) |
| { |
| return extract32(inst, 26, 1); |
| } |
| |
| static uint32_t operand_rl(rv_inst inst) |
| { |
| return extract32(inst, 25, 1); |
| } |
| |
| static uint32_t operand_pred(rv_inst inst) |
| { |
| return extract32(inst, 24, 4); |
| } |
| |
| static uint32_t operand_succ(rv_inst inst) |
| { |
| return extract32(inst, 20, 4); |
| } |
| |
| static uint32_t operand_rm(rv_inst inst) |
| { |
| return extract32(inst, 12, 3); |
| } |
| |
| static uint32_t operand_shamt5(rv_inst inst) |
| { |
| return extract32(inst, 20, 5); |
| } |
| |
| static uint32_t operand_shamt6(rv_inst inst) |
| { |
| return extract32(inst, 20, 6); |
| } |
| |
| static uint32_t operand_shamt7(rv_inst inst) |
| { |
| return extract32(inst, 20, 7); |
| } |
| |
| static uint32_t operand_crdq(rv_inst inst) |
| { |
| return extract32(inst, 2, 3); |
| } |
| |
| static uint32_t operand_crs1q(rv_inst inst) |
| { |
| return extract32(inst, 7, 3); |
| } |
| |
| static uint32_t operand_crs1rdq(rv_inst inst) |
| { |
| return extract32(inst, 7, 3); |
| } |
| |
| static uint32_t operand_crs2q(rv_inst inst) |
| { |
| return extract32(inst, 2, 3); |
| } |
| |
| static uint32_t calculate_xreg(uint32_t sreg) |
| { |
| return sreg < 2 ? sreg + 8 : sreg + 16; |
| } |
| |
| static uint32_t operand_sreg1(rv_inst inst) |
| { |
| return calculate_xreg(extract32(inst, 7, 3)); |
| } |
| |
| static uint32_t operand_sreg2(rv_inst inst) |
| { |
| return calculate_xreg(extract32(inst, 2, 3)); |
| } |
| |
| static uint32_t operand_crd(rv_inst inst) |
| { |
| return extract32(inst, 7, 5); |
| } |
| |
| static uint32_t operand_crs1(rv_inst inst) |
| { |
| return extract32(inst, 7, 5); |
| } |
| |
| static uint32_t operand_crs1rd(rv_inst inst) |
| { |
| return extract32(inst, 7, 5); |
| } |
| |
| static uint32_t operand_crs2(rv_inst inst) |
| { |
| return extract32(inst, 2, 5); |
| } |
| |
| static uint32_t operand_cimmsh5(rv_inst inst) |
| { |
| return extract32(inst, 2, 5); |
| } |
| |
| static uint32_t operand_csr12(rv_inst inst) |
| { |
| return extract32(inst, 20, 12); |
| } |
| |
| static int32_t operand_imm12(rv_inst inst) |
| { |
| return sextract32(inst, 20, 12); |
| } |
| |
| static int32_t operand_imm20(rv_inst inst) |
| { |
| return sextract32(inst, 12, 20) << 12; |
| } |
| |
| static int32_t operand_jimm20(rv_inst inst) |
| { |
| return sextract32(inst, 31, 1) << 20 | |
| extract32(inst, 21, 10) << 1 | |
| extract32(inst, 20, 1) << 11 | |
| extract32(inst, 12, 8) << 12; |
| } |
| |
| static int32_t operand_simm12(rv_inst inst) |
| { |
| return sextract32(inst, 25, 7) << 5 | |
| extract32(inst, 7, 5); |
| } |
| |
| static int32_t operand_sbimm12(rv_inst inst) |
| { |
| return sextract32(inst, 31, 1) << 12 | |
| extract32(inst, 25, 6) << 5 | |
| extract32(inst, 8, 4) << 1 | |
| extract32(inst, 7, 1) << 11; |
| } |
| |
| static uint32_t operand_cimmshl6(rv_inst inst, rv_isa isa) |
| { |
| int imm = extract32(inst, 12, 1) << 5 | |
| extract32(inst, 2, 5); |
| if (isa == rv128) { |
| imm = imm ? imm : 64; |
| } |
| return imm; |
| } |
| |
| static uint32_t operand_cimmshr6(rv_inst inst, rv_isa isa) |
| { |
| int imm = extract32(inst, 12, 1) << 5 | |
| extract32(inst, 2, 5); |
| if (isa == rv128) { |
| imm = imm | (imm & 32) << 1; |
| imm = imm ? imm : 64; |
| } |
| return imm; |
| } |
| |
| static int32_t operand_cimmi(rv_inst inst) |
| { |
| return sextract32(inst, 12, 1) << 5 | |
| extract32(inst, 2, 5); |
| } |
| |
| static int32_t operand_cimmui(rv_inst inst) |
| { |
| return sextract32(inst, 12, 1) << 17 | |
| extract32(inst, 2, 5) << 12; |
| } |
| |
| static uint32_t operand_cimmlwsp(rv_inst inst) |
| { |
| return extract32(inst, 12, 1) << 5 | |
| extract32(inst, 4, 3) << 2 | |
| extract32(inst, 2, 2) << 6; |
| } |
| |
| static uint32_t operand_cimmldsp(rv_inst inst) |
| { |
| return extract32(inst, 12, 1) << 5 | |
| extract32(inst, 5, 2) << 3 | |
| extract32(inst, 2, 3) << 6; |
| } |
| |
| static uint32_t operand_cimmlqsp(rv_inst inst) |
| { |
| return extract32(inst, 12, 1) << 5 | |
| extract32(inst, 6, 1) << 4 | |
| extract32(inst, 2, 4) << 6; |
| } |
| |
| static int32_t operand_cimm16sp(rv_inst inst) |
| { |
| return sextract32(inst, 12, 1) << 9 | |
| extract32(inst, 6, 1) << 4 | |
| extract32(inst, 5, 1) << 6 | |
| extract32(inst, 3, 2) << 7 | |
| extract32(inst, 2, 1) << 5; |
| } |
| |
| static int32_t operand_cimmj(rv_inst inst) |
| { |
| return sextract32(inst, 12, 1) << 11 | |
| extract32(inst, 11, 1) << 4 | |
| extract32(inst, 9, 2) << 8 | |
| extract32(inst, 8, 1) << 10 | |
| extract32(inst, 7, 1) << 6 | |
| extract32(inst, 6, 1) << 7 | |
| extract32(inst, 3, 3) << 1 | |
| extract32(inst, 2, 1) << 5; |
| } |
| |
| static int32_t operand_cimmb(rv_inst inst) |
| { |
| return sextract32(inst, 12, 1) << 8 | |
| extract32(inst, 10, 2) << 3 | |
| extract32(inst, 5, 2) << 6 | |
| extract32(inst, 3, 2) << 1 | |
| extract32(inst, 2, 1) << 5; |
| } |
| |
| static uint32_t operand_cimmswsp(rv_inst inst) |
| { |
| return extract32(inst, 9, 4) << 2 | |
| extract32(inst, 7, 2) << 6; |
| } |
| |
| static uint32_t operand_cimmsdsp(rv_inst inst) |
| { |
| return extract32(inst, 10, 3) << 3 | |
| extract32(inst, 7, 3) << 6; |
| } |
| |
| static uint32_t operand_cimmsqsp(rv_inst inst) |
| { |
| return extract32(inst, 11, 2) << 4 | |
| extract32(inst, 7, 4) << 6; |
| } |
| |
| static uint32_t operand_cimm4spn(rv_inst inst) |
| { |
| return extract32(inst, 11, 2) << 4 | |
| extract32(inst, 7, 4) << 6 | |
| extract32(inst, 6, 1) << 2 | |
| extract32(inst, 5, 1) << 3; |
| } |
| |
| static uint32_t operand_cimmw(rv_inst inst) |
| { |
| return extract32(inst, 10, 3) << 3 | |
| extract32(inst, 6, 1) << 2 | |
| extract32(inst, 5, 1) << 6; |
| } |
| |
| static uint32_t operand_cimmd(rv_inst inst) |
| { |
| return extract32(inst, 10, 3) << 3 | |
| extract32(inst, 5, 2) << 6; |
| } |
| |
| static uint32_t operand_cimmq(rv_inst inst) |
| { |
| return extract32(inst, 11, 2) << 4 | |
| extract32(inst, 10, 1) << 8 | |
| extract32(inst, 5, 2) << 6; |
| } |
| |
| static int32_t operand_vimm(rv_inst inst) |
| { |
| return sextract32(inst, 15, 5); |
| } |
| |
| static uint32_t operand_vuimm(rv_inst inst) |
| { |
| return extract32(inst, 15, 5); |
| } |
| |
| static uint32_t operand_vzimm11(rv_inst inst) |
| { |
| return extract32(inst, 20, 11); |
| } |
| |
| static uint32_t operand_vzimm10(rv_inst inst) |
| { |
| return extract32(inst, 20, 10); |
| } |
| |
| static uint32_t operand_vzimm6(rv_inst inst) |
| { |
| return extract32(inst, 26, 1) << 5 | |
| extract32(inst, 15, 5); |
| } |
| |
| static uint32_t operand_bs(rv_inst inst) |
| { |
| return extract32(inst, 30, 2); |
| } |
| |
| static uint32_t operand_rnum(rv_inst inst) |
| { |
| return extract32(inst, 20, 4); |
| } |
| |
| static uint32_t operand_vm(rv_inst inst) |
| { |
| return extract32(inst, 25, 1); |
| } |
| |
| static uint32_t operand_uimm_c_lb(rv_inst inst) |
| { |
| return extract32(inst, 5, 1) << 1 | |
| extract32(inst, 6, 1); |
| } |
| |
| static uint32_t operand_uimm_c_lh(rv_inst inst) |
| { |
| return extract32(inst, 5, 1) << 1; |
| } |
| |
| static uint32_t operand_zcmp_spimm(rv_inst inst) |
| { |
| return extract32(inst, 2, 2) << 4; |
| } |
| |
| static uint32_t operand_zcmp_rlist(rv_inst inst) |
| { |
| return extract32(inst, 4, 4); |
| } |
| |
| static uint32_t operand_imm6(rv_inst inst) |
| { |
| return extract32(inst, 20, 6); |
| } |
| |
| static uint32_t operand_imm2(rv_inst inst) |
| { |
| return extract32(inst, 25, 2); |
| } |
| |
| static uint32_t operand_immh(rv_inst inst) |
| { |
| return extract32(inst, 26, 6); |
| } |
| |
| static uint32_t operand_imml(rv_inst inst) |
| { |
| return extract32(inst, 20, 6); |
| } |
| |
| static uint32_t calculate_stack_adj(rv_isa isa, uint32_t rlist, uint32_t spimm) |
| { |
| int xlen_bytes_log2 = isa == rv64 ? 3 : 2; |
| int regs = rlist == 15 ? 13 : rlist - 3; |
| uint32_t stack_adj_base = ROUND_UP(regs << xlen_bytes_log2, 16); |
| return stack_adj_base + spimm; |
| } |
| |
| static uint32_t operand_zcmp_stack_adj(rv_inst inst, rv_isa isa) |
| { |
| return calculate_stack_adj(isa, operand_zcmp_rlist(inst), |
| operand_zcmp_spimm(inst)); |
| } |
| |
| static uint32_t operand_tbl_index(rv_inst inst) |
| { |
| return extract32(inst, 2, 8); |
| } |
| |
| static uint32_t operand_lpl(rv_inst inst) |
| { |
| return extract32(inst, 12, 20); |
| } |
| |
| static uint32_t operand_cmop_imm(rv_inst inst) |
| { |
| return extract32(inst, 8, 3) * 2 + 1; |
| } |
| |
| static uint32_t operand_mop_r_imm(rv_inst inst) |
| { |
| return (extract32(inst, 30, 1) << 4) | |
| (extract32(inst, 26, 2) << 2) | |
| extract32(inst, 20, 2); |
| } |
| |
| static uint32_t operand_mop_rr_imm(rv_inst inst) |
| { |
| return (extract32(inst, 30, 1) << 2) | extract32(inst, 26, 2); |
| } |
| |
| /* instruction metadata */ |
| |
| #define OP(N, ...) static const rv_opcode_data op_##N = { __VA_ARGS__ }; |
| #include "riscv-op.c.inc" |
| #undef OP |
| |
| /* CSR names */ |
| |
| static const char *csr_name(int csrno) |
| { |
| switch (csrno) { |
| case 0x0000: return "ustatus"; |
| case 0x0001: return "fflags"; |
| case 0x0002: return "frm"; |
| case 0x0003: return "fcsr"; |
| case 0x0004: return "uie"; |
| case 0x0005: return "utvec"; |
| case 0x0008: return "vstart"; |
| case 0x0009: return "vxsat"; |
| case 0x000a: return "vxrm"; |
| case 0x000f: return "vcsr"; |
| case 0x0011: return "ssp"; |
| case 0x0015: return "seed"; |
| case 0x0017: return "jvt"; |
| case 0x0040: return "uscratch"; |
| case 0x0041: return "uepc"; |
| case 0x0042: return "ucause"; |
| case 0x0043: return "utval"; |
| case 0x0044: return "uip"; |
| case 0x0100: return "sstatus"; |
| case 0x0104: return "sie"; |
| case 0x0105: return "stvec"; |
| case 0x0106: return "scounteren"; |
| case 0x0140: return "sscratch"; |
| case 0x0141: return "sepc"; |
| case 0x0142: return "scause"; |
| case 0x0143: return "stval"; |
| case 0x0144: return "sip"; |
| case 0x0180: return "satp"; |
| case 0x0200: return "hstatus"; |
| case 0x0202: return "hedeleg"; |
| case 0x0203: return "hideleg"; |
| case 0x0204: return "hie"; |
| case 0x0205: return "htvec"; |
| case 0x0240: return "hscratch"; |
| case 0x0241: return "hepc"; |
| case 0x0242: return "hcause"; |
| case 0x0243: return "hbadaddr"; |
| case 0x0244: return "hip"; |
| case 0x0300: return "mstatus"; |
| case 0x0301: return "misa"; |
| case 0x0302: return "medeleg"; |
| case 0x0303: return "mideleg"; |
| case 0x0304: return "mie"; |
| case 0x0305: return "mtvec"; |
| case 0x0306: return "mcounteren"; |
| case 0x0320: return "mucounteren"; |
| case 0x0321: return "mscounteren"; |
| case 0x0322: return "mhcounteren"; |
| case 0x0323: return "mhpmevent3"; |
| case 0x0324: return "mhpmevent4"; |
| case 0x0325: return "mhpmevent5"; |
| case 0x0326: return "mhpmevent6"; |
| case 0x0327: return "mhpmevent7"; |
| case 0x0328: return "mhpmevent8"; |
| case 0x0329: return "mhpmevent9"; |
| case 0x032a: return "mhpmevent10"; |
| case 0x032b: return "mhpmevent11"; |
| case 0x032c: return "mhpmevent12"; |
| case 0x032d: return "mhpmevent13"; |
| case 0x032e: return "mhpmevent14"; |
| case 0x032f: return "mhpmevent15"; |
| case 0x0330: return "mhpmevent16"; |
| case 0x0331: return "mhpmevent17"; |
| case 0x0332: return "mhpmevent18"; |
| case 0x0333: return "mhpmevent19"; |
| case 0x0334: return "mhpmevent20"; |
| case 0x0335: return "mhpmevent21"; |
| case 0x0336: return "mhpmevent22"; |
| case 0x0337: return "mhpmevent23"; |
| case 0x0338: return "mhpmevent24"; |
| case 0x0339: return "mhpmevent25"; |
| case 0x033a: return "mhpmevent26"; |
| case 0x033b: return "mhpmevent27"; |
| case 0x033c: return "mhpmevent28"; |
| case 0x033d: return "mhpmevent29"; |
| case 0x033e: return "mhpmevent30"; |
| case 0x033f: return "mhpmevent31"; |
| case 0x0340: return "mscratch"; |
| case 0x0341: return "mepc"; |
| case 0x0342: return "mcause"; |
| case 0x0343: return "mtval"; |
| case 0x0344: return "mip"; |
| case 0x0380: return "mbase"; |
| case 0x0381: return "mbound"; |
| case 0x0382: return "mibase"; |
| case 0x0383: return "mibound"; |
| case 0x0384: return "mdbase"; |
| case 0x0385: return "mdbound"; |
| case 0x03a0: return "pmpcfg0"; |
| case 0x03a1: return "pmpcfg1"; |
| case 0x03a2: return "pmpcfg2"; |
| case 0x03a3: return "pmpcfg3"; |
| case 0x03a4: return "pmpcfg4"; |
| case 0x03a5: return "pmpcfg5"; |
| case 0x03a6: return "pmpcfg6"; |
| case 0x03a7: return "pmpcfg7"; |
| case 0x03a8: return "pmpcfg8"; |
| case 0x03a9: return "pmpcfg9"; |
| case 0x03aa: return "pmpcfg10"; |
| case 0x03ab: return "pmpcfg11"; |
| case 0x03ac: return "pmpcfg12"; |
| case 0x03ad: return "pmpcfg13"; |
| case 0x03ae: return "pmpcfg14"; |
| case 0x03af: return "pmpcfg15"; |
| case 0x03b0: return "pmpaddr0"; |
| case 0x03b1: return "pmpaddr1"; |
| case 0x03b2: return "pmpaddr2"; |
| case 0x03b3: return "pmpaddr3"; |
| case 0x03b4: return "pmpaddr4"; |
| case 0x03b5: return "pmpaddr5"; |
| case 0x03b6: return "pmpaddr6"; |
| case 0x03b7: return "pmpaddr7"; |
| case 0x03b8: return "pmpaddr8"; |
| case 0x03b9: return "pmpaddr9"; |
| case 0x03ba: return "pmpaddr10"; |
| case 0x03bb: return "pmpaddr11"; |
| case 0x03bc: return "pmpaddr12"; |
| case 0x03bd: return "pmpaddr13"; |
| case 0x03be: return "pmpaddr14"; |
| case 0x03bf: return "pmpaddr15"; |
| case 0x03c0: return "pmpaddr16"; |
| case 0x03c1: return "pmpaddr17"; |
| case 0x03c2: return "pmpaddr18"; |
| case 0x03c3: return "pmpaddr19"; |
| case 0x03c4: return "pmpaddr20"; |
| case 0x03c5: return "pmpaddr21"; |
| case 0x03c6: return "pmpaddr22"; |
| case 0x03c7: return "pmpaddr23"; |
| case 0x03c8: return "pmpaddr24"; |
| case 0x03c9: return "pmpaddr25"; |
| case 0x03ca: return "pmpaddr26"; |
| case 0x03cb: return "pmpaddr27"; |
| case 0x03cc: return "pmpaddr28"; |
| case 0x03cd: return "pmpaddr29"; |
| case 0x03ce: return "pmpaddr30"; |
| case 0x03cf: return "pmpaddr31"; |
| case 0x03d0: return "pmpaddr32"; |
| case 0x03d1: return "pmpaddr33"; |
| case 0x03d2: return "pmpaddr34"; |
| case 0x03d3: return "pmpaddr35"; |
| case 0x03d4: return "pmpaddr36"; |
| case 0x03d5: return "pmpaddr37"; |
| case 0x03d6: return "pmpaddr38"; |
| case 0x03d7: return "pmpaddr39"; |
| case 0x03d8: return "pmpaddr40"; |
| case 0x03d9: return "pmpaddr41"; |
| case 0x03da: return "pmpaddr42"; |
| case 0x03db: return "pmpaddr43"; |
| case 0x03dc: return "pmpaddr44"; |
| case 0x03dd: return "pmpaddr45"; |
| case 0x03de: return "pmpaddr46"; |
| case 0x03df: return "pmpaddr47"; |
| case 0x03e0: return "pmpaddr48"; |
| case 0x03e1: return "pmpaddr49"; |
| case 0x03e2: return "pmpaddr50"; |
| case 0x03e3: return "pmpaddr51"; |
| case 0x03e4: return "pmpaddr52"; |
| case 0x03e5: return "pmpaddr53"; |
| case 0x03e6: return "pmpaddr54"; |
| case 0x03e7: return "pmpaddr55"; |
| case 0x03e8: return "pmpaddr56"; |
| case 0x03e9: return "pmpaddr57"; |
| case 0x03ea: return "pmpaddr58"; |
| case 0x03eb: return "pmpaddr59"; |
| case 0x03ec: return "pmpaddr60"; |
| case 0x03ed: return "pmpaddr61"; |
| case 0x03ee: return "pmpaddr62"; |
| case 0x03ef: return "pmpaddr63"; |
| case 0x0780: return "mtohost"; |
| case 0x0781: return "mfromhost"; |
| case 0x0782: return "mreset"; |
| case 0x0783: return "mipi"; |
| case 0x0784: return "miobase"; |
| case 0x07a0: return "tselect"; |
| case 0x07a1: return "tdata1"; |
| case 0x07a2: return "tdata2"; |
| case 0x07a3: return "tdata3"; |
| case 0x07a4: return "tinfo"; |
| case 0x07b0: return "dcsr"; |
| case 0x07b1: return "dpc"; |
| case 0x07b2: return "dscratch0"; |
| case 0x07b3: return "dscratch1"; |
| case 0x0b00: return "mcycle"; |
| case 0x0b01: return "mtime"; |
| case 0x0b02: return "minstret"; |
| case 0x0b03: return "mhpmcounter3"; |
| case 0x0b04: return "mhpmcounter4"; |
| case 0x0b05: return "mhpmcounter5"; |
| case 0x0b06: return "mhpmcounter6"; |
| case 0x0b07: return "mhpmcounter7"; |
| case 0x0b08: return "mhpmcounter8"; |
| case 0x0b09: return "mhpmcounter9"; |
| case 0x0b0a: return "mhpmcounter10"; |
| case 0x0b0b: return "mhpmcounter11"; |
| case 0x0b0c: return "mhpmcounter12"; |
| case 0x0b0d: return "mhpmcounter13"; |
| case 0x0b0e: return "mhpmcounter14"; |
| case 0x0b0f: return "mhpmcounter15"; |
| case 0x0b10: return "mhpmcounter16"; |
| case 0x0b11: return "mhpmcounter17"; |
| case 0x0b12: return "mhpmcounter18"; |
| case 0x0b13: return "mhpmcounter19"; |
| case 0x0b14: return "mhpmcounter20"; |
| case 0x0b15: return "mhpmcounter21"; |
| case 0x0b16: return "mhpmcounter22"; |
| case 0x0b17: return "mhpmcounter23"; |
| case 0x0b18: return "mhpmcounter24"; |
| case 0x0b19: return "mhpmcounter25"; |
| case 0x0b1a: return "mhpmcounter26"; |
| case 0x0b1b: return "mhpmcounter27"; |
| case 0x0b1c: return "mhpmcounter28"; |
| case 0x0b1d: return "mhpmcounter29"; |
| case 0x0b1e: return "mhpmcounter30"; |
| case 0x0b1f: return "mhpmcounter31"; |
| case 0x0b80: return "mcycleh"; |
| case 0x0b81: return "mtimeh"; |
| case 0x0b82: return "minstreth"; |
| case 0x0b83: return "mhpmcounter3h"; |
| case 0x0b84: return "mhpmcounter4h"; |
| case 0x0b85: return "mhpmcounter5h"; |
| case 0x0b86: return "mhpmcounter6h"; |
| case 0x0b87: return "mhpmcounter7h"; |
| case 0x0b88: return "mhpmcounter8h"; |
| case 0x0b89: return "mhpmcounter9h"; |
| case 0x0b8a: return "mhpmcounter10h"; |
| case 0x0b8b: return "mhpmcounter11h"; |
| case 0x0b8c: return "mhpmcounter12h"; |
| case 0x0b8d: return "mhpmcounter13h"; |
| case 0x0b8e: return "mhpmcounter14h"; |
| case 0x0b8f: return "mhpmcounter15h"; |
| case 0x0b90: return "mhpmcounter16h"; |
| case 0x0b91: return "mhpmcounter17h"; |
| case 0x0b92: return "mhpmcounter18h"; |
| case 0x0b93: return "mhpmcounter19h"; |
| case 0x0b94: return "mhpmcounter20h"; |
| case 0x0b95: return "mhpmcounter21h"; |
| case 0x0b96: return "mhpmcounter22h"; |
| case 0x0b97: return "mhpmcounter23h"; |
| case 0x0b98: return "mhpmcounter24h"; |
| case 0x0b99: return "mhpmcounter25h"; |
| case 0x0b9a: return "mhpmcounter26h"; |
| case 0x0b9b: return "mhpmcounter27h"; |
| case 0x0b9c: return "mhpmcounter28h"; |
| case 0x0b9d: return "mhpmcounter29h"; |
| case 0x0b9e: return "mhpmcounter30h"; |
| case 0x0b9f: return "mhpmcounter31h"; |
| case 0x0c00: return "cycle"; |
| case 0x0c01: return "time"; |
| case 0x0c02: return "instret"; |
| case 0x0c20: return "vl"; |
| case 0x0c21: return "vtype"; |
| case 0x0c22: return "vlenb"; |
| case 0x0c80: return "cycleh"; |
| case 0x0c81: return "timeh"; |
| case 0x0c82: return "instreth"; |
| case 0x0d00: return "scycle"; |
| case 0x0d01: return "stime"; |
| case 0x0d02: return "sinstret"; |
| case 0x0d80: return "scycleh"; |
| case 0x0d81: return "stimeh"; |
| case 0x0d82: return "sinstreth"; |
| case 0x0e00: return "hcycle"; |
| case 0x0e01: return "htime"; |
| case 0x0e02: return "hinstret"; |
| case 0x0e80: return "hcycleh"; |
| case 0x0e81: return "htimeh"; |
| case 0x0e82: return "hinstreth"; |
| case 0x0f11: return "mvendorid"; |
| case 0x0f12: return "marchid"; |
| case 0x0f13: return "mimpid"; |
| case 0x0f14: return "mhartid"; |
| default: return NULL; |
| } |
| } |
| |
| /* decode opcode */ |
| |
| static const rv_opcode_data *decode_inst_opcode(rv_decode *dec, rv_isa isa) |
| { |
| rv_inst inst = dec->inst; |
| |
| switch ((inst >> 0) & 0b11) { |
| case 0: |
| switch ((inst >> 13) & 0b111) { |
| case 0: |
| if ((inst >> 5) & 0xff) { |
| return &op_c_addi4spn; |
| } |
| break; |
| case 1: |
| if (isa == rv128) { |
| return &op_c_lq; |
| } |
| return &op_c_fld; |
| case 2: return &op_c_lw; |
| case 3: |
| if (isa == rv32) { |
| return &op_c_flw; |
| } |
| return &op_c_ld; |
| case 4: |
| switch ((inst >> 10) & 0b111) { |
| case 0: return &op_c_lbu; |
| case 1: |
| if (((inst >> 6) & 1) == 0) { |
| return &op_c_lhu; |
| } |
| return &op_c_lh; |
| case 2: return &op_c_sb; |
| case 3: |
| if (((inst >> 6) & 1) == 0) { |
| return &op_c_sh; |
| } |
| break; |
| } |
| break; |
| case 5: |
| if (isa == rv128) { |
| return &op_c_sq; |
| } |
| return &op_c_fsd; |
| case 6: return &op_c_sw; |
| case 7: |
| if (isa == rv32) { |
| return &op_c_fsw; |
| } |
| return &op_c_sd; |
| } |
| break; |
| case 1: |
| switch ((inst >> 13) & 0b111) { |
| case 0: |
| return &op_c_addi; /* or unspecified HINT */ |
| case 1: |
| if (isa == rv32) { |
| return &op_c_jal; |
| } |
| return &op_c_addiw; |
| case 2: return &op_c_li; |
| case 3: |
| if (dec->cfg |
| && dec->cfg->ext_zcmop |
| && ((inst >> 2) & 0b111111) == 0b100000 |
| && ((inst >> 11) & 0b11) == 0) { |
| if (dec->cfg->ext_zicfiss) { |
| switch (operand_cmop_imm(inst)) { |
| case 1: return &op_c_sspush; |
| case 5: return &op_c_sspopchk; |
| } |
| } |
| return &op_c_mop; |
| } |
| if (inst & ((1 << 12) | (0x1f << 2))) { |
| switch ((inst >> 7) & 0b11111) { |
| case 2: return &op_c_addi16sp; |
| default: return &op_c_lui; |
| } |
| } |
| break; |
| case 4: |
| switch ((inst >> 10) & 0b11) { |
| case 0: |
| /* For rv32, shamt[5]=1 is designated for custom extensions. */ |
| if (isa != rv32 || (inst & 0x1000) == 0) { |
| return &op_c_srli; /* or unspecified HINT */ |
| } |
| break; |
| case 1: |
| /* For rv32, shamt[5]=1 is designated for custom extensions. */ |
| if (isa != rv32 || (inst & 0x1000) == 0) { |
| return &op_c_srai; /* or unspecified HINT */ |
| } |
| break; |
| case 2: return &op_c_andi; |
| case 3: |
| switch (((inst >> 10) & 0b100) | ((inst >> 5) & 0b011)) { |
| case 0: return &op_c_sub; |
| case 1: return &op_c_xor; |
| case 2: return &op_c_or; |
| case 3: return &op_c_and; |
| case 4: |
| if (isa != rv32) { |
| return &op_c_subw; |
| } |
| break; |
| case 5: |
| if (isa != rv32) { |
| return &op_c_addw; |
| } |
| break; |
| case 6: return &op_c_mul; |
| case 7: |
| switch ((inst >> 2) & 0b111) { |
| case 0: return &op_c_zext_b; |
| case 1: return &op_c_sext_b; |
| case 2: return &op_c_zext_h; |
| case 3: return &op_c_sext_h; |
| case 4: return &op_c_zext_w; |
| case 5: return &op_c_not; |
| } |
| break; |
| } |
| break; |
| } |
| break; |
| case 5: return &op_c_j; |
| case 6: return &op_c_beqz; |
| case 7: return &op_c_bnez; |
| } |
| break; |
| case 2: |
| switch ((inst >> 13) & 0b111) { |
| case 0: |
| if (isa != rv32 || (inst & 0x1000) == 0) { |
| return &op_c_slli; /* or unspecified HINT */ |
| } |
| break; |
| case 1: |
| if (isa == rv128) { |
| return &op_c_lqsp; |
| } |
| return &op_c_fldsp; |
| case 2: return &op_c_lwsp; |
| case 3: |
| if (isa == rv32) { |
| return &op_c_flwsp; |
| } |
| return &op_c_ldsp; |
| case 4: |
| switch ((inst >> 12) & 0b1) { |
| case 0: |
| switch ((inst >> 2) & 0b11111) { |
| case 0: return &op_c_jr; |
| default: return &op_c_mv; |
| } |
| break; |
| case 1: |
| switch ((inst >> 2) & 0b11111) { |
| case 0: |
| switch ((inst >> 7) & 0b11111) { |
| case 0: return &op_c_ebreak; |
| default: return &op_c_jalr; |
| } |
| break; |
| default: return &op_c_add; |
| } |
| break; |
| } |
| break; |
| case 5: |
| if (isa == rv128) { |
| return &op_c_sqsp; |
| } |
| if (dec->cfg) { |
| if (dec->cfg->ext_zcmp && ((inst >> 12) & 0b01)) { |
| switch ((inst >> 8) & 0b01111) { |
| case 8: |
| if (((inst >> 4) & 0b01111) >= 4) { |
| return &op_cm_push; |
| } |
| break; |
| case 10: |
| if (((inst >> 4) & 0b01111) >= 4) { |
| return &op_cm_pop; |
| } |
| break; |
| case 12: |
| if (((inst >> 4) & 0b01111) >= 4) { |
| return &op_cm_popretz; |
| } |
| break; |
| case 14: |
| if (((inst >> 4) & 0b01111) >= 4) { |
| return &op_cm_popret; |
| } |
| break; |
| } |
| } |
| switch ((inst >> 10) & 0b011) { |
| case 0: |
| if (!dec->cfg->ext_zcmt) { |
| break; |
| } |
| if (((inst >> 2) & 0xFF) >= 32) { |
| return &op_cm_jalt; |
| } |
| return &op_cm_jt; |
| case 3: |
| if (!dec->cfg->ext_zcmp) { |
| break; |
| } |
| switch ((inst >> 5) & 0b011) { |
| case 1: return &op_cm_mvsa01; |
| case 3: return &op_cm_mva01s; |
| } |
| break; |
| } |
| } |
| return &op_c_fsdsp; |
| case 6: return &op_c_swsp; |
| case 7: |
| if (isa == rv32) { |
| return &op_c_fswsp; |
| } |
| return &op_c_sdsp; |
| } |
| break; |
| case 3: |
| switch ((inst >> 2) & 0b11111) { |
| case 0: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_lb; |
| case 1: return &op_lh; |
| case 2: return &op_lw; |
| case 3: return &op_ld; |
| case 4: return &op_lbu; |
| case 5: return &op_lhu; |
| case 6: return &op_lwu; |
| case 7: return &op_ldu; |
| } |
| break; |
| case 1: |
| switch ((inst >> 12) & 0b111) { |
| case 0: |
| switch ((inst >> 20) & 0b111111111111) { |
| case 40: return &op_vl1re8_v; |
| case 552: return &op_vl2re8_v; |
| case 1576: return &op_vl4re8_v; |
| case 3624: return &op_vl8re8_v; |
| } |
| switch ((inst >> 26) & 0b111) { |
| case 0: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_vle8_v; |
| case 11: return &op_vlm_v; |
| case 16: return &op_vle8ff_v; |
| } |
| break; |
| case 1: return &op_vluxei8_v; |
| case 2: return &op_vlse8_v; |
| case 3: return &op_vloxei8_v; |
| } |
| break; |
| case 1: return &op_flh; |
| case 2: return &op_flw; |
| case 3: return &op_fld; |
| case 4: return &op_flq; |
| case 5: |
| switch ((inst >> 20) & 0b111111111111) { |
| case 40: return &op_vl1re16_v; |
| case 552: return &op_vl2re16_v; |
| case 1576: return &op_vl4re16_v; |
| case 3624: return &op_vl8re16_v; |
| } |
| switch ((inst >> 26) & 0b111) { |
| case 0: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_vle16_v; |
| case 16: return &op_vle16ff_v; |
| } |
| break; |
| case 1: return &op_vluxei16_v; |
| case 2: return &op_vlse16_v; |
| case 3: return &op_vloxei16_v; |
| } |
| break; |
| case 6: |
| switch ((inst >> 20) & 0b111111111111) { |
| case 40: return &op_vl1re32_v; |
| case 552: return &op_vl2re32_v; |
| case 1576: return &op_vl4re32_v; |
| case 3624: return &op_vl8re32_v; |
| } |
| switch ((inst >> 26) & 0b111) { |
| case 0: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_vle32_v; |
| case 16: return &op_vle32ff_v; |
| } |
| break; |
| case 1: return &op_vluxei32_v; |
| case 2: return &op_vlse32_v; |
| case 3: return &op_vloxei32_v; |
| } |
| break; |
| case 7: |
| switch ((inst >> 20) & 0b111111111111) { |
| case 40: return &op_vl1re64_v; |
| case 552: return &op_vl2re64_v; |
| case 1576: return &op_vl4re64_v; |
| case 3624: return &op_vl8re64_v; |
| } |
| switch ((inst >> 26) & 0b111) { |
| case 0: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_vle64_v; |
| case 16: return &op_vle64ff_v; |
| } |
| break; |
| case 1: return &op_vluxei64_v; |
| case 2: return &op_vlse64_v; |
| case 3: return &op_vloxei64_v; |
| } |
| break; |
| } |
| break; |
| case 3: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_fence; |
| case 1: return &op_fence_i; |
| case 2: |
| /* |
| * 'lq' shares the "(...) 010 ..... 0001111" opcode space |
| * with 'cbo' insns. Check the next 5 bits to select |
| * what we want: |
| * |
| * cbo_inval 0000000 00000 ..... 010 00000 0001111 |
| * cbo_clean 0000000 00001 ..... 010 00000 0001111 |
| * cbo_flush 0000000 00010 ..... 010 00000 0001111 |
| * cbo_zero 0000000 00100 ..... 010 00000 0001111 |
| * |
| * Anything that doesn't match these will default to 'lq'. |
| */ |
| switch ((inst >> 17) & 0b11111) { |
| case 0: return &op_cbo_inval; |
| case 1: return &op_cbo_clean; |
| case 2: return &op_cbo_flush; |
| case 4: return &op_cbo_zero; |
| default: return &op_lq; |
| } |
| } |
| break; |
| case 4: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_addi; |
| case 1: |
| switch ((inst >> 27) & 0b11111) { |
| case 0b00000: return &op_slli; |
| case 0b00001: |
| switch ((inst >> 20) & 0b1111111) { |
| case 0b0001111: return &op_zip; |
| } |
| break; |
| case 0b00010: |
| switch ((inst >> 20) & 0b1111111) { |
| case 0b0000000: return &op_sha256sum0; |
| case 0b0000001: return &op_sha256sum1; |
| case 0b0000010: return &op_sha256sig0; |
| case 0b0000011: return &op_sha256sig1; |
| case 0b0000100: return &op_sha512sum0; |
| case 0b0000101: return &op_sha512sum1; |
| case 0b0000110: return &op_sha512sig0; |
| case 0b0000111: return &op_sha512sig1; |
| case 0b0001000: return &op_sm3p0; |
| case 0b0001001: return &op_sm3p1; |
| } |
| break; |
| case 0b00101: return &op_bseti; |
| case 0b00110: |
| switch ((inst >> 20) & 0b1111111) { |
| case 0b0000000: return &op_aes64im; |
| default: |
| if (((inst >> 24) & 0b0111) == 0b001) { |
| return &op_aes64ks1i; |
| } |
| break; |
| } |
| break; |
| case 0b01001: return &op_bclri; |
| case 0b01101: return &op_binvi; |
| case 0b01100: |
| switch ((inst >> 20) & 0b1111111) { |
| case 0b0000000: return &op_clz; |
| case 0b0000001: return &op_ctz; |
| case 0b0000010: return &op_cpop; |
| /* 0b0000011 */ |
| case 0b0000100: return &op_sext_b; |
| case 0b0000101: return &op_sext_h; |
| } |
| break; |
| } |
| break; |
| case 2: return &op_slti; |
| case 3: return &op_sltiu; |
| case 4: return &op_xori; |
| case 5: |
| switch ((inst >> 27) & 0b11111) { |
| case 0b00000: return &op_srli; |
| case 0b00001: |
| switch ((inst >> 20) & 0b1111111) { |
| case 0b0001111: return &op_unzip; |
| } |
| break; |
| case 0b00101: return &op_orc_b; |
| case 0b01000: return &op_srai; |
| case 0b01001: return &op_bexti; |
| case 0b01100: return &op_rori; |
| case 0b01101: |
| switch ((inst >> 20) & 0b1111111) { |
| case 0b0011000: |
| if (isa == rv32) { |
| return &op_rev8; |
| } |
| break; |
| case 0b0111000: |
| if (isa == rv64) { |
| return &op_rev8; |
| } |
| break; |
| case 0b0000111: return &op_brev8; |
| } |
| break; |
| } |
| break; |
| case 6: return &op_ori; |
| case 7: return &op_andi; |
| } |
| break; |
| case 5: |
| if (dec->cfg && dec->cfg->ext_zicfilp && |
| (((inst >> 7) & 0b11111) == 0b00000)) { |
| return &op_lpad; |
| } |
| return &op_auipc; |
| case 6: |
| /* OP-IMM-32 */ |
| if (isa == rv32) { |
| break; |
| } |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_addiw; |
| case 1: |
| switch ((inst >> 26) & 0b111111) { |
| case 0: return &op_slliw; |
| case 2: return &op_slli_uw; |
| case 24: |
| switch ((inst >> 20) & 0b11111) { |
| case 0b00000: return &op_clzw; |
| case 0b00001: return &op_ctzw; |
| case 0b00010: return &op_cpopw; |
| } |
| break; |
| } |
| break; |
| case 5: |
| switch ((inst >> 25) & 0b1111111) { |
| case 0: return &op_srliw; |
| case 32: return &op_sraiw; |
| case 48: return &op_roriw; |
| } |
| break; |
| } |
| break; |
| case 8: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_sb; |
| case 1: return &op_sh; |
| case 2: return &op_sw; |
| case 3: return &op_sd; |
| case 4: return &op_sq; |
| } |
| break; |
| case 9: |
| switch ((inst >> 12) & 0b111) { |
| case 0: |
| switch ((inst >> 20) & 0b111111111111) { |
| case 40: return &op_vs1r_v; |
| case 552: return &op_vs2r_v; |
| case 1576: return &op_vs4r_v; |
| case 3624: return &op_vs8r_v; |
| } |
| switch ((inst >> 26) & 0b111) { |
| case 0: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_vse8_v; |
| case 11: return &op_vsm_v; |
| } |
| break; |
| case 1: return &op_vsuxei8_v; |
| case 2: return &op_vsse8_v; |
| case 3: return &op_vsoxei8_v; |
| } |
| break; |
| case 1: return &op_fsh; |
| case 2: return &op_fsw; |
| case 3: return &op_fsd; |
| case 4: return &op_fsq; |
| case 5: |
| switch ((inst >> 26) & 0b111) { |
| case 0: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_vse16_v; |
| } |
| break; |
| case 1: return &op_vsuxei16_v; |
| case 2: return &op_vsse16_v; |
| case 3: return &op_vsoxei16_v; |
| } |
| break; |
| case 6: |
| switch ((inst >> 26) & 0b111) { |
| case 0: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_vse32_v; |
| } |
| break; |
| case 1: return &op_vsuxei32_v; |
| case 2: return &op_vsse32_v; |
| case 3: return &op_vsoxei32_v; |
| } |
| break; |
| case 7: |
| switch ((inst >> 26) & 0b111) { |
| case 0: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_vse64_v; |
| } |
| break; |
| case 1: return &op_vsuxei64_v; |
| case 2: return &op_vsse64_v; |
| case 3: return &op_vsoxei64_v; |
| } |
| break; |
| } |
| break; |
| case 11: |
| switch (((inst >> 24) & 0b11111000) | |
| ((inst >> 12) & 0b00000111)) { |
| case 0: return &op_amoadd_b; |
| case 1: return &op_amoadd_h; |
| case 2: return &op_amoadd_w; |
| case 3: return &op_amoadd_d; |
| case 4: return &op_amoadd_q; |
| case 8: return &op_amoswap_b; |
| case 9: return &op_amoswap_h; |
| case 10: return &op_amoswap_w; |
| case 11: return &op_amoswap_d; |
| case 12: return &op_amoswap_q; |
| case 18: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_lr_w; |
| } |
| break; |
| case 19: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_lr_d; |
| } |
| break; |
| case 20: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_lr_q; |
| } |
| break; |
| case 26: return &op_sc_w; |
| case 27: return &op_sc_d; |
| case 28: return &op_sc_q; |
| case 32: return &op_amoxor_b; |
| case 33: return &op_amoxor_h; |
| case 34: return &op_amoxor_w; |
| case 35: return &op_amoxor_d; |
| case 36: return &op_amoxor_q; |
| case 40: return &op_amocas_b; |
| case 41: return &op_amocas_h; |
| case 42: return &op_amocas_w; |
| case 43: return &op_amocas_d; |
| case 44: return &op_amocas_q; |
| case 64: return &op_amoor_b; |
| case 65: return &op_amoor_h; |
| case 66: return &op_amoor_w; |
| case 67: return &op_amoor_d; |
| case 68: return &op_amoor_q; |
| case 74: return &op_ssamoswap_w; |
| case 75: return &op_ssamoswap_d; |
| case 96: return &op_amoand_b; |
| case 97: return &op_amoand_h; |
| case 98: return &op_amoand_w; |
| case 99: return &op_amoand_d; |
| case 100: return &op_amoand_q; |
| case 128: return &op_amomin_b; |
| case 129: return &op_amomin_h; |
| case 130: return &op_amomin_w; |
| case 131: return &op_amomin_d; |
| case 132: return &op_amomin_q; |
| case 160: return &op_amomax_b; |
| case 161: return &op_amomax_h; |
| case 162: return &op_amomax_w; |
| case 163: return &op_amomax_d; |
| case 164: return &op_amomax_q; |
| case 192: return &op_amominu_b; |
| case 193: return &op_amominu_h; |
| case 194: return &op_amominu_w; |
| case 195: return &op_amominu_d; |
| case 196: return &op_amominu_q; |
| case 224: return &op_amomaxu_b; |
| case 225: return &op_amomaxu_h; |
| case 226: return &op_amomaxu_w; |
| case 227: return &op_amomaxu_d; |
| case 228: return &op_amomaxu_q; |
| } |
| break; |
| case 12: |
| switch (((inst >> 22) & 0b1111111000) | |
| ((inst >> 12) & 0b0000000111)) { |
| case 0: return &op_add; |
| case 1: return &op_sll; |
| case 2: return &op_slt; |
| case 3: return &op_sltu; |
| case 4: return &op_xor; |
| case 5: return &op_srl; |
| case 6: return &op_or; |
| case 7: return &op_and; |
| case 8: return &op_mul; |
| case 9: return &op_mulh; |
| case 10: return &op_mulhsu; |
| case 11: return &op_mulhu; |
| case 12: return &op_div; |
| case 13: return &op_divu; |
| case 14: return &op_rem; |
| case 15: return &op_remu; |
| case 36: |
| if (isa == rv32 && !((inst >> 20) & 0b11111)) { |
| return &op_zext_h; |
| } |
| return &op_pack; |
| case 39: return &op_packh; |
| case 41: return &op_clmul; |
| case 42: return &op_clmulr; |
| case 43: return &op_clmulh; |
| case 44: return &op_min; |
| case 45: return &op_minu; |
| case 46: return &op_max; |
| case 47: return &op_maxu; |
| case 075: return &op_czero_eqz; |
| case 077: return &op_czero_nez; |
| case 130: return &op_sh1add; |
| case 132: return &op_sh2add; |
| case 134: return &op_sh3add; |
| case 161: return &op_bset; |
| case 162: return &op_xperm4; |
| case 164: return &op_xperm8; |
| case 200: return &op_aes64es; |
| case 216: return &op_aes64esm; |
| case 232: return &op_aes64ds; |
| case 248: return &op_aes64dsm; |
| case 256: return &op_sub; |
| case 260: return &op_xnor; |
| case 261: return &op_sra; |
| case 262: return &op_orn; |
| case 263: return &op_andn; |
| case 289: return &op_bclr; |
| case 293: return &op_bext; |
| case 320: return &op_sha512sum0r; |
| case 328: return &op_sha512sum1r; |
| case 336: return &op_sha512sig0l; |
| case 344: return &op_sha512sig1l; |
| case 368: return &op_sha512sig0h; |
| case 376: return &op_sha512sig1h; |
| case 385: return &op_rol; |
| case 389: return &op_ror; |
| case 417: return &op_binv; |
| case 504: return &op_aes64ks2; |
| } |
| switch ((inst >> 25) & 0b0011111) { |
| case 17: return &op_aes32esi; |
| case 19: return &op_aes32esmi; |
| case 21: return &op_aes32dsi; |
| case 23: return &op_aes32dsmi; |
| case 24: return &op_sm4ed; |
| case 26: return &op_sm4ks; |
| } |
| break; |
| case 13: return &op_lui; |
| case 14: |
| /* OP-32 */ |
| if (isa == rv32) { |
| break; |
| } |
| switch (((inst >> 22) & 0b1111111000) | |
| ((inst >> 12) & 0b0000000111)) { |
| case 0: return &op_addw; |
| case 1: return &op_sllw; |
| case 5: return &op_srlw; |
| case 8: return &op_mulw; |
| case 12: return &op_divw; |
| case 13: return &op_divuw; |
| case 14: return &op_remw; |
| case 15: return &op_remuw; |
| case 32: return &op_add_uw; |
| case 36: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_zext_h; |
| default: return &op_packw; |
| } |
| break; |
| case 130: return &op_sh1add_uw; |
| case 132: return &op_sh2add_uw; |
| case 134: return &op_sh3add_uw; |
| case 256: return &op_subw; |
| case 261: return &op_sraw; |
| case 385: return &op_rolw; |
| case 389: return &op_rorw; |
| } |
| break; |
| case 16: |
| switch ((inst >> 25) & 0b11) { |
| case 0: return &op_fmadd_s; |
| case 1: return &op_fmadd_d; |
| case 3: return &op_fmadd_q; |
| } |
| break; |
| case 17: |
| switch ((inst >> 25) & 0b11) { |
| case 0: return &op_fmsub_s; |
| case 1: return &op_fmsub_d; |
| case 3: return &op_fmsub_q; |
| } |
| break; |
| case 18: |
| switch ((inst >> 25) & 0b11) { |
| case 0: return &op_fnmsub_s; |
| case 1: return &op_fnmsub_d; |
| case 3: return &op_fnmsub_q; |
| } |
| break; |
| case 19: |
| switch ((inst >> 25) & 0b11) { |
| case 0: return &op_fnmadd_s; |
| case 1: return &op_fnmadd_d; |
| case 3: return &op_fnmadd_q; |
| } |
| break; |
| case 20: |
| switch ((inst >> 25) & 0b1111111) { |
| case 0: return &op_fadd_s; |
| case 1: return &op_fadd_d; |
| case 3: return &op_fadd_q; |
| case 4: return &op_fsub_s; |
| case 5: return &op_fsub_d; |
| case 7: return &op_fsub_q; |
| case 8: return &op_fmul_s; |
| case 9: return &op_fmul_d; |
| case 11: return &op_fmul_q; |
| case 12: return &op_fdiv_s; |
| case 13: return &op_fdiv_d; |
| case 15: return &op_fdiv_q; |
| case 16: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_fsgnj_s; |
| case 1: return &op_fsgnjn_s; |
| case 2: return &op_fsgnjx_s; |
| } |
| break; |
| case 17: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_fsgnj_d; |
| case 1: return &op_fsgnjn_d; |
| case 2: return &op_fsgnjx_d; |
| } |
| break; |
| case 19: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_fsgnj_q; |
| case 1: return &op_fsgnjn_q; |
| case 2: return &op_fsgnjx_q; |
| } |
| break; |
| case 20: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_fmin_s; |
| case 1: return &op_fmax_s; |
| case 2: return &op_fminm_s; |
| case 3: return &op_fmaxm_s; |
| } |
| break; |
| case 21: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_fmin_d; |
| case 1: return &op_fmax_d; |
| case 2: return &op_fminm_d; |
| case 3: return &op_fmaxm_d; |
| } |
| break; |
| case 22: |
| switch (((inst >> 12) & 0b111)) { |
| case 2: return &op_fminm_h; |
| case 3: return &op_fmaxm_h; |
| } |
| break; |
| case 23: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_fmin_q; |
| case 1: return &op_fmax_q; |
| case 2: return &op_fminm_q; |
| case 3: return &op_fmaxm_q; |
| } |
| break; |
| case 32: |
| switch ((inst >> 20) & 0b11111) { |
| case 1: return &op_fcvt_s_d; |
| case 3: return &op_fcvt_s_q; |
| case 4: return &op_fround_s; |
| case 5: return &op_froundnx_s; |
| case 6: return &op_fcvt_s_bf16; |
| } |
| break; |
| case 33: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_fcvt_d_s; |
| case 3: return &op_fcvt_d_q; |
| case 4: return &op_fround_d; |
| case 5: return &op_froundnx_d; |
| } |
| break; |
| case 34: |
| switch (((inst >> 20) & 0b11111)) { |
| case 4: return &op_fround_h; |
| case 5: return &op_froundnx_h; |
| case 8: return &op_fcvt_bf16_s; |
| } |
| break; |
| case 35: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_fcvt_q_s; |
| case 1: return &op_fcvt_q_d; |
| case 4: return &op_fround_q; |
| case 5: return &op_froundnx_q; |
| } |
| break; |
| case 44: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_fsqrt_s; |
| } |
| break; |
| case 45: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_fsqrt_d; |
| } |
| break; |
| case 47: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_fsqrt_q; |
| } |
| break; |
| case 80: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_fle_s; |
| case 1: return &op_flt_s; |
| case 2: return &op_feq_s; |
| case 4: return &op_fleq_s; |
| case 5: return &op_fltq_s; |
| } |
| break; |
| case 81: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_fle_d; |
| case 1: return &op_flt_d; |
| case 2: return &op_feq_d; |
| case 4: return &op_fleq_d; |
| case 5: return &op_fltq_d; |
| } |
| break; |
| case 82: |
| switch (((inst >> 12) & 0b111)) { |
| case 4: return &op_fleq_h; |
| case 5: return &op_fltq_h; |
| } |
| break; |
| case 83: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_fle_q; |
| case 1: return &op_flt_q; |
| case 2: return &op_feq_q; |
| case 4: return &op_fleq_q; |
| case 5: return &op_fltq_q; |
| } |
| break; |
| case 89: |
| switch (((inst >> 12) & 0b111)) { |
| case 0: return &op_fmvp_d_x; |
| } |
| break; |
| case 91: |
| switch (((inst >> 12) & 0b111)) { |
| case 0: return &op_fmvp_q_x; |
| } |
| break; |
| case 96: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_fcvt_w_s; |
| case 1: return &op_fcvt_wu_s; |
| case 2: return &op_fcvt_l_s; |
| case 3: return &op_fcvt_lu_s; |
| } |
| break; |
| case 97: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_fcvt_w_d; |
| case 1: return &op_fcvt_wu_d; |
| case 2: return &op_fcvt_l_d; |
| case 3: return &op_fcvt_lu_d; |
| case 8: return &op_fcvtmod_w_d; |
| } |
| break; |
| case 99: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_fcvt_w_q; |
| case 1: return &op_fcvt_wu_q; |
| case 2: return &op_fcvt_l_q; |
| case 3: return &op_fcvt_lu_q; |
| } |
| break; |
| case 104: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_fcvt_s_w; |
| case 1: return &op_fcvt_s_wu; |
| case 2: return &op_fcvt_s_l; |
| case 3: return &op_fcvt_s_lu; |
| } |
| break; |
| case 105: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_fcvt_d_w; |
| case 1: return &op_fcvt_d_wu; |
| case 2: return &op_fcvt_d_l; |
| case 3: return &op_fcvt_d_lu; |
| } |
| break; |
| case 107: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: return &op_fcvt_q_w; |
| case 1: return &op_fcvt_q_wu; |
| case 2: return &op_fcvt_q_l; |
| case 3: return &op_fcvt_q_lu; |
| } |
| break; |
| case 112: |
| switch (((inst >> 17) & 0b11111000) | |
| ((inst >> 12) & 0b00000111)) { |
| case 0: return &op_fmv_x_s; |
| case 1: return &op_fclass_s; |
| } |
| break; |
| case 113: |
| switch (((inst >> 17) & 0b11111000) | |
| ((inst >> 12) & 0b00000111)) { |
| case 0: return &op_fmv_x_d; |
| case 1: return &op_fclass_d; |
| case 8: return &op_fmvh_x_d; |
| } |
| break; |
| case 114: |
| switch (((inst >> 17) & 0b11111000) | |
| ((inst >> 12) & 0b00000111)) { |
| case 0: return &op_fmv_x_h; |
| } |
| break; |
| case 115: |
| switch (((inst >> 17) & 0b11111000) | |
| ((inst >> 12) & 0b00000111)) { |
| case 0: return &op_fmv_x_q; |
| case 1: return &op_fclass_q; |
| case 8: return &op_fmvh_x_q; |
| } |
| break; |
| case 120: |
| switch (((inst >> 17) & 0b11111000) | |
| ((inst >> 12) & 0b00000111)) { |
| case 0: return &op_fmv_s_x; |
| case 8: return &op_fli_s; |
| } |
| break; |
| case 121: |
| switch (((inst >> 17) & 0b11111000) | |
| ((inst >> 12) & 0b00000111)) { |
| case 0: return &op_fmv_d_x; |
| case 8: return &op_fli_d; |
| } |
| break; |
| case 122: |
| switch (((inst >> 17) & 0b11111000) | |
| ((inst >> 12) & 0b00000111)) { |
| case 0: return &op_fmv_h_x; |
| case 8: return &op_fli_h; |
| } |
| break; |
| case 123: |
| switch (((inst >> 17) & 0b11111000) | |
| ((inst >> 12) & 0b00000111)) { |
| case 0: return &op_fmv_q_x; |
| case 8: return &op_fli_q; |
| } |
| break; |
| } |
| break; |
| case 21: |
| switch ((inst >> 12) & 0b111) { |
| case 0: |
| switch ((inst >> 26) & 0b111111) { |
| case 0: return &op_vadd_vv; |
| case 1: return &op_vandn_vv; |
| case 2: return &op_vsub_vv; |
| case 4: return &op_vminu_vv; |
| case 5: return &op_vmin_vv; |
| case 6: return &op_vmaxu_vv; |
| case 7: return &op_vmax_vv; |
| case 9: return &op_vand_vv; |
| case 10: return &op_vor_vv; |
| case 11: return &op_vxor_vv; |
| case 12: return &op_vrgather_vv; |
| case 14: return &op_vrgatherei16_vv; |
| case 16: |
| if (((inst >> 25) & 1) == 0) { |
| return &op_vadc_vvm; |
| } |
| break; |
| case 17: return &op_vmadc_vvm; |
| case 18: |
| if (((inst >> 25) & 1) == 0) { |
| return &op_vsbc_vvm; |
| } |
| break; |
| case 19: return &op_vmsbc_vvm; |
| case 20: return &op_vror_vv; |
| case 21: return &op_vrol_vv; |
| case 23: |
| if (((inst >> 20) & 0b111111) == 32) { |
| return &op_vmv_v_v; |
| } else if (((inst >> 25) & 1) == 0) { |
| return &op_vmerge_vvm; |
| } |
| break; |
| case 24: return &op_vmseq_vv; |
| case 25: return &op_vmsne_vv; |
| case 26: return &op_vmsltu_vv; |
| case 27: return &op_vmslt_vv; |
| case 28: return &op_vmsleu_vv; |
| case 29: return &op_vmsle_vv; |
| case 32: return &op_vsaddu_vv; |
| case 33: return &op_vsadd_vv; |
| case 34: return &op_vssubu_vv; |
| case 35: return &op_vssub_vv; |
| case 37: return &op_vsll_vv; |
| case 39: return &op_vsmul_vv; |
| case 40: return &op_vsrl_vv; |
| case 41: return &op_vsra_vv; |
| case 42: return &op_vssrl_vv; |
| case 43: return &op_vssra_vv; |
| case 44: return &op_vnsrl_wv; |
| case 45: return &op_vnsra_wv; |
| case 46: return &op_vnclipu_wv; |
| case 47: return &op_vnclip_wv; |
| case 48: return &op_vwredsumu_vs; |
| case 49: return &op_vwredsum_vs; |
| case 53: return &op_vwsll_vv; |
| } |
| break; |
| case 1: |
| switch ((inst >> 26) & 0b111111) { |
| case 0: return &op_vfadd_vv; |
| case 1: return &op_vfredusum_vs; |
| case 2: return &op_vfsub_vv; |
| case 3: return &op_vfredosum_vs; |
| case 4: return &op_vfmin_vv; |
| case 5: return &op_vfredmin_vs; |
| case 6: return &op_vfmax_vv; |
| case 7: return &op_vfredmax_vs; |
| case 8: return &op_vfsgnj_vv; |
| case 9: return &op_vfsgnjn_vv; |
| case 10: return &op_vfsgnjx_vv; |
| case 16: |
| switch ((inst >> 15) & 0b11111) { |
| case 0: |
| if ((inst >> 25) & 1) { |
| return &op_vfmv_f_s; |
| } |
| } |
| break; |
| case 18: |
| switch ((inst >> 15) & 0b11111) { |
| case 0: return &op_vfcvt_xu_f_v; |
| case 1: return &op_vfcvt_x_f_v; |
| case 2: return &op_vfcvt_f_xu_v; |
| case 3: return &op_vfcvt_f_x_v; |
| case 6: return &op_vfcvt_rtz_xu_f_v; |
| case 7: return &op_vfcvt_rtz_x_f_v; |
| case 8: return &op_vfwcvt_xu_f_v; |
| case 9: return &op_vfwcvt_x_f_v; |
| case 10: return &op_vfwcvt_f_xu_v; |
| case 11: return &op_vfwcvt_f_x_v; |
| case 12: return &op_vfwcvt_f_f_v; |
| case 13: return &op_vfwcvtbf16_f_f_v; |
| case 14: return &op_vfwcvt_rtz_xu_f_v; |
| case 15: return &op_vfwcvt_rtz_x_f_v; |
| case 16: return &op_vfncvt_xu_f_w; |
| case 17: return &op_vfncvt_x_f_w; |
| case 18: return &op_vfncvt_f_xu_w; |
| case 19: return &op_vfncvt_f_x_w; |
| case 20: return &op_vfncvt_f_f_w; |
| case 21: return &op_vfncvt_rod_f_f_w; |
| case 22: return &op_vfncvt_rtz_xu_f_w; |
| case 23: return &op_vfncvt_rtz_x_f_w; |
| case 29: return &op_vfncvtbf16_f_f_w; |
| } |
| break; |
| case 19: |
| switch ((inst >> 15) & 0b11111) { |
| case 0: return &op_vfsqrt_v; |
| case 4: return &op_vfrsqrt7_v; |
| case 5: return &op_vfrec7_v; |
| case 16: return &op_vfclass_v; |
| } |
| break; |
| case 24: return &op_vmfeq_vv; |
| case 25: return &op_vmfle_vv; |
| case 27: return &op_vmflt_vv; |
| case 28: return &op_vmfne_vv; |
| case 32: return &op_vfdiv_vv; |
| case 36: return &op_vfmul_vv; |
| case 40: return &op_vfmadd_vv; |
| case 41: return &op_vfnmadd_vv; |
| case 42: return &op_vfmsub_vv; |
| case 43: return &op_vfnmsub_vv; |
| case 44: return &op_vfmacc_vv; |
| case 45: return &op_vfnmacc_vv; |
| case 46: return &op_vfmsac_vv; |
| case 47: return &op_vfnmsac_vv; |
| case 48: return &op_vfwadd_vv; |
| case 49: return &op_vfwredusum_vs; |
| case 50: return &op_vfwsub_vv; |
| case 51: return &op_vfwredosum_vs; |
| case 52: return &op_vfwadd_wv; |
| case 54: return &op_vfwsub_wv; |
| case 56: return &op_vfwmul_vv; |
| case 59: return &op_vfwmaccbf16_vv; |
| case 60: return &op_vfwmacc_vv; |
| case 61: return &op_vfwnmacc_vv; |
| case 62: return &op_vfwmsac_vv; |
| case 63: return &op_vfwnmsac_vv; |
| } |
| break; |
| case 2: |
| switch ((inst >> 26) & 0b111111) { |
| case 0: return &op_vredsum_vs; |
| case 1: return &op_vredand_vs; |
| case 2: return &op_vredor_vs; |
| case 3: return &op_vredxor_vs; |
| case 4: return &op_vredminu_vs; |
| case 5: return &op_vredmin_vs; |
| case 6: return &op_vredmaxu_vs; |
| case 7: return &op_vredmax_vs; |
| case 8: return &op_vaaddu_vv; |
| case 9: return &op_vaadd_vv; |
| case 10: return &op_vasubu_vv; |
| case 11: return &op_vasub_vv; |
| case 12: return &op_vclmul_vv; |
| case 13: return &op_vclmulh_vv; |
| case 16: |
| switch ((inst >> 15) & 0b11111) { |
| case 0: |
| if ((inst >> 25) & 1) { |
| return &op_vmv_x_s; |
| } |
| break; |
| case 16: return &op_vcpop_m; |
| case 17: return &op_vfirst_m; |
| } |
| break; |
| case 18: |
| switch ((inst >> 15) & 0b11111) { |
| case 2: return &op_vzext_vf8; |
| case 3: return &op_vsext_vf8; |
| case 4: return &op_vzext_vf4; |
| case 5: return &op_vsext_vf4; |
| case 6: return &op_vzext_vf2; |
| case 7: return &op_vsext_vf2; |
| case 8: return &op_vbrev8_v; |
| case 9: return &op_vrev8_v; |
| case 10: return &op_vbrev_v; |
| case 12: return &op_vclz_v; |
| case 13: return &op_vctz_v; |
| case 14: return &op_vcpop_v; |
| } |
| break; |
| case 20: |
| switch ((inst >> 15) & 0b11111) { |
| case 1: return &op_vmsbf_m; break; |
| case 2: return &op_vmsof_m; |
| case 3: return &op_vmsif_m; |
| case 16: return &op_viota_m; |
| case 17: |
| if (((inst >> 20) & 0b11111) == 0) { |
| return &op_vid_v; |
| } |
| break; |
| } |
| break; |
| case 23: |
| if ((inst >> 25) & 1) { |
| return &op_vcompress_vm; |
| } |
| break; |
| case 24: |
| if ((inst >> 25) & 1) { |
| return &op_vmandn_mm; |
| } |
| break; |
| case 25: |
| if ((inst >> 25) & 1) { |
| return &op_vmand_mm; |
| } |
| break; |
| case 26: |
| if ((inst >> 25) & 1) { |
| return &op_vmor_mm; |
| } |
| break; |
| case 27: |
| if ((inst >> 25) & 1) { |
| return &op_vmxor_mm; |
| } |
| break; |
| case 28: |
| if ((inst >> 25) & 1) { |
| return &op_vmorn_mm; |
| } |
| break; |
| case 29: |
| if ((inst >> 25) & 1) { |
| return &op_vmnand_mm; |
| } |
| break; |
| case 30: |
| if ((inst >> 25) & 1) { |
| return &op_vmnor_mm; |
| } |
| break; |
| case 31: |
| if ((inst >> 25) & 1) { |
| return &op_vmxnor_mm; |
| } |
| break; |
| case 32: return &op_vdivu_vv; |
| case 33: return &op_vdiv_vv; |
| case 34: return &op_vremu_vv; |
| case 35: return &op_vrem_vv; |
| case 36: return &op_vmulhu_vv; |
| case 37: return &op_vmul_vv; |
| case 38: return &op_vmulhsu_vv; |
| case 39: return &op_vmulh_vv; |
| case 41: return &op_vmadd_vv; |
| case 43: return &op_vnmsub_vv; |
| case 45: return &op_vmacc_vv; |
| case 47: return &op_vnmsac_vv; |
| case 48: return &op_vwaddu_vv; |
| case 49: return &op_vwadd_vv; |
| case 50: return &op_vwsubu_vv; |
| case 51: return &op_vwsub_vv; |
| case 52: return &op_vwaddu_wv; |
| case 53: return &op_vwadd_wv; |
| case 54: return &op_vwsubu_wv; |
| case 55: return &op_vwsub_wv; |
| case 56: return &op_vwmulu_vv; |
| case 58: return &op_vwmulsu_vv; |
| case 59: return &op_vwmul_vv; |
| case 60: return &op_vwmaccu_vv; |
| case 61: return &op_vwmacc_vv; |
| case 63: return &op_vwmaccsu_vv; |
| } |
| break; |
| case 3: |
| switch ((inst >> 26) & 0b111111) { |
| case 0: return &op_vadd_vi; |
| case 3: return &op_vrsub_vi; |
| case 9: return &op_vand_vi; |
| case 10: return &op_vor_vi; |
| case 11: return &op_vxor_vi; |
| case 12: return &op_vrgather_vi; |
| case 14: return &op_vslideup_vi; |
| case 15: return &op_vslidedown_vi; |
| case 16: |
| if (((inst >> 25) & 1) == 0) { |
| return &op_vadc_vim; |
| } |
| break; |
| case 17: return &op_vmadc_vim; |
| case 20: case 21: return &op_vror_vi; |
| case 23: |
| if (((inst >> 20) & 0b111111) == 32) { |
| return &op_vmv_v_i; |
| } else if (((inst >> 25) & 1) == 0) { |
| return &op_vmerge_vim; |
| } |
| break; |
| case 24: return &op_vmseq_vi; |
| case 25: return &op_vmsne_vi; |
| case 28: return &op_vmsleu_vi; |
| case 29: return &op_vmsle_vi; |
| case 30: return &op_vmsgtu_vi; |
| case 31: return &op_vmsgt_vi; |
| case 32: return &op_vsaddu_vi; |
| case 33: return &op_vsadd_vi; |
| case 37: return &op_vsll_vi; |
| case 39: |
| switch ((inst >> 15) & 0b11111) { |
| case 0: return &op_vmv1r_v; |
| case 1: return &op_vmv2r_v; |
| case 3: return &op_vmv4r_v; |
| case 7: return &op_vmv8r_v; |
| } |
| break; |
| case 40: return &op_vsrl_vi; |
| case 41: return &op_vsra_vi; |
| case 42: return &op_vssrl_vi; |
| case 43: return &op_vssra_vi; |
| case 44: return &op_vnsrl_wi; |
| case 45: return &op_vnsra_wi; |
| case 46: return &op_vnclipu_wi; |
| case 47: return &op_vnclip_wi; |
| case 53: return &op_vwsll_vi; |
| } |
| break; |
| case 4: |
| switch ((inst >> 26) & 0b111111) { |
| case 0: return &op_vadd_vx; |
| case 1: return &op_vandn_vx; |
| case 2: return &op_vsub_vx; |
| case 3: return &op_vrsub_vx; |
| case 4: return &op_vminu_vx; |
| case 5: return &op_vmin_vx; |
| case 6: return &op_vmaxu_vx; |
| case 7: return &op_vmax_vx; |
| case 9: return &op_vand_vx; |
| case 10: return &op_vor_vx; |
| case 11: return &op_vxor_vx; |
| case 12: return &op_vrgather_vx; |
| case 14: return &op_vslideup_vx; |
| case 15: return &op_vslidedown_vx; |
| case 16: |
| if (((inst >> 25) & 1) == 0) { |
| return &op_vadc_vxm; |
| } |
| break; |
| case 17: return &op_vmadc_vxm; |
| case 18: |
| if (((inst >> 25) & 1) == 0) { |
| return &op_vsbc_vxm; |
| } |
| break; |
| case 19: return &op_vmsbc_vxm; |
| case 20: return &op_vror_vx; |
| case 21: return &op_vrol_vx; |
| case 23: |
| if (((inst >> 20) & 0b111111) == 32) { |
| return &op_vmv_v_x; |
| } else if (((inst >> 25) & 1) == 0) { |
| return &op_vmerge_vxm; |
| } |
| break; |
| case 24: return &op_vmseq_vx; |
| case 25: return &op_vmsne_vx; |
| case 26: return &op_vmsltu_vx; |
| case 27: return &op_vmslt_vx; |
| case 28: return &op_vmsleu_vx; |
| case 29: return &op_vmsle_vx; |
| case 30: return &op_vmsgtu_vx; |
| case 31: return &op_vmsgt_vx; |
| case 32: return &op_vsaddu_vx; |
| case 33: return &op_vsadd_vx; |
| case 34: return &op_vssubu_vx; |
| case 35: return &op_vssub_vx; |
| case 37: return &op_vsll_vx; |
| case 39: return &op_vsmul_vx; |
| case 40: return &op_vsrl_vx; |
| case 41: return &op_vsra_vx; |
| case 42: return &op_vssrl_vx; |
| case 43: return &op_vssra_vx; |
| case 44: return &op_vnsrl_wx; |
| case 45: return &op_vnsra_wx; |
| case 46: return &op_vnclipu_wx; |
| case 47: return &op_vnclip_wx; |
| case 53: return &op_vwsll_vx; |
| } |
| break; |
| case 5: |
| switch ((inst >> 26) & 0b111111) { |
| case 0: return &op_vfadd_vf; |
| case 2: return &op_vfsub_vf; |
| case 4: return &op_vfmin_vf; |
| case 6: return &op_vfmax_vf; |
| case 8: return &op_vfsgnj_vf; |
| case 9: return &op_vfsgnjn_vf; |
| case 10: return &op_vfsgnjx_vf; |
| case 14: return &op_vfslide1up_vf; |
| case 15: return &op_vfslide1down_vf; |
| case 16: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: |
| if ((inst >> 25) & 1) { |
| return &op_vfmv_s_f; |
| } |
| } |
| break; |
| case 23: |
| if (((inst >> 25) & 1) == 0) { |
| return &op_vfmerge_vfm; |
| } else if (((inst >> 20) & 0b111111) == 32) { |
| return &op_vfmv_v_f; |
| } |
| break; |
| case 24: return &op_vmfeq_vf; |
| case 25: return &op_vmfle_vf; |
| case 27: return &op_vmflt_vf; |
| case 28: return &op_vmfne_vf; |
| case 29: return &op_vmfgt_vf; |
| case 31: return &op_vmfge_vf; |
| case 32: return &op_vfdiv_vf; |
| case 33: return &op_vfrdiv_vf; |
| case 36: return &op_vfmul_vf; |
| case 39: return &op_vfrsub_vf; |
| case 40: return &op_vfmadd_vf; |
| case 41: return &op_vfnmadd_vf; |
| case 42: return &op_vfmsub_vf; |
| case 43: return &op_vfnmsub_vf; |
| case 44: return &op_vfmacc_vf; |
| case 45: return &op_vfnmacc_vf; |
| case 46: return &op_vfmsac_vf; |
| case 47: return &op_vfnmsac_vf; |
| case 48: return &op_vfwadd_vf; |
| case 50: return &op_vfwsub_vf; |
| case 52: return &op_vfwadd_wf; |
| case 54: return &op_vfwsub_wf; |
| case 56: return &op_vfwmul_vf; |
| case 59: return &op_vfwmaccbf16_vf; |
| case 60: return &op_vfwmacc_vf; |
| case 61: return &op_vfwnmacc_vf; |
| case 62: return &op_vfwmsac_vf; |
| case 63: return &op_vfwnmsac_vf; |
| } |
| break; |
| case 6: |
| switch ((inst >> 26) & 0b111111) { |
| case 8: return &op_vaaddu_vx; |
| case 9: return &op_vaadd_vx; |
| case 10: return &op_vasubu_vx; |
| case 11: return &op_vasub_vx; |
| case 12: return &op_vclmul_vx; |
| case 13: return &op_vclmulh_vx; |
| case 14: return &op_vslide1up_vx; |
| case 15: return &op_vslide1down_vx; |
| case 16: |
| switch ((inst >> 20) & 0b11111) { |
| case 0: |
| if ((inst >> 25) & 1) { |
| return &op_vmv_s_x; |
| } |
| } |
| break; |
| case 32: return &op_vdivu_vx; |
| case 33: return &op_vdiv_vx; |
| case 34: return &op_vremu_vx; |
| case 35: return &op_vrem_vx; |
| case 36: return &op_vmulhu_vx; |
| case 37: return &op_vmul_vx; |
| case 38: return &op_vmulhsu_vx; |
| case 39: return &op_vmulh_vx; |
| case 41: return &op_vmadd_vx; |
| case 43: return &op_vnmsub_vx; |
| case 45: return &op_vmacc_vx; |
| case 47: return &op_vnmsac_vx; |
| case 48: return &op_vwaddu_vx; |
| case 49: return &op_vwadd_vx; |
| case 50: return &op_vwsubu_vx; |
| case 51: return &op_vwsub_vx; |
| case 52: return &op_vwaddu_wx; |
| case 53: return &op_vwadd_wx; |
| case 54: return &op_vwsubu_wx; |
| case 55: return &op_vwsub_wx; |
| case 56: return &op_vwmulu_vx; |
| case 58: return &op_vwmulsu_vx; |
| case 59: return &op_vwmul_vx; |
| case 60: return &op_vwmaccu_vx; |
| case 61: return &op_vwmacc_vx; |
| case 62: return &op_vwmaccus_vx; |
| case 63: return &op_vwmaccsu_vx; |
| } |
| break; |
| case 7: |
| if (((inst >> 31) & 1) == 0) { |
| return &op_vsetvli; |
| } else if ((inst >> 30) & 1) { |
| return &op_vsetivli; |
| } else if (((inst >> 25) & 0b11111) == 0) { |
| return &op_vsetvl; |
| } |
| break; |
| } |
| break; |
| case 22: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_addid; |
| case 1: |
| switch ((inst >> 26) & 0b111111) { |
| case 0: return &op_sllid; |
| } |
| break; |
| case 5: |
| switch ((inst >> 26) & 0b111111) { |
| case 0: return &op_srlid; |
| case 16: return &op_sraid; |
| } |
| break; |
| } |
| break; |
| case 24: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_beq; |
| case 1: return &op_bne; |
| case 4: return &op_blt; |
| case 5: return &op_bge; |
| case 6: return &op_bltu; |
| case 7: return &op_bgeu; |
| } |
| break; |
| case 25: |
| switch ((inst >> 12) & 0b111) { |
| case 0: return &op_jalr; |
| } |
| break; |
| case 27: return &op_jal; |
| case 28: |
| switch ((inst >> 12) & 0b111) { |
| case 0: |
| switch (((inst >> 20) & 0b111111100000) | |
| ((inst >> 7) & 0b000000011111)) { |
| case 0: |
| switch ((inst >> 15) & 0b1111111111) { |
| case 0: return &op_ecall; |
| case 32: return &op_ebreak; |
| case 64: return &op_uret; |
| case 416: return &op_wrs_nto; |
| case 928: return &op_wrs_sto; |
| } |
| break; |
| case 256: |
| switch ((inst >> 20) & 0b11111) { |
| case 2: |
| switch ((inst >> 15) & 0b11111) { |
| case 0: return &op_sret; |
| } |
| break; |
| case 4: return &op_sfence_vm; |
| case 5: |
| switch ((inst >> 15) & 0b11111) { |
| case 0: return &op_wfi; |
| } |
| break; |
| } |
| break; |
| case 288: return &op_sfence_vma; |
| case 512: |
| switch ((inst >> 15) & 0b1111111111) { |
| case 64: return &op_hret; |
| } |
| break; |
| case 768: |
| switch ((inst >> 15) & 0b1111111111) { |
| case 64: return &op_mret; |
| } |
| break; |
| case 1792: |
| switch ((inst >> 15) & 0b1111111111) { |
| case 64: return &op_mnret; |
| } |
| break; |
| case 1952: |
| switch ((inst >> 15) & 0b1111111111) { |
| case 576: return &op_dret; |
| } |
| break; |
| } |
| break; |
| case 1: |
| switch (operand_csr12(inst)) { |
| case 1: return &op_fsflags; |
| case 2: return &op_fsrm; |
| case 3: return &op_fscsr; |
| default: return &op_csrrw; |
| } |
| break; |
| case 2: |
| return &op_csrrs; |
| if (operand_rs1(inst) == 0) { |
| switch (operand_csr12(inst)) { |
| case 0x001: return &op_frflags; |
| case 0x002: return &op_frrm; |
| case 0x003: return &op_frcsr; |
| case 0xc00: return &op_rdcycle; |
| case 0xc01: return &op_rdtime; |
| case 0xc02: return &op_rdinstret; |
| case 0xc80: return &op_rdcycleh; |
| case 0xc81: return &op_rdtimeh; |
| case 0xc82: return &op_rdinstreth; |
| } |
| } |
| break; |
| case 3: return &op_csrrc; |
| case 4: |
| if (dec->cfg && dec->cfg->ext_zimop) { |
| if (((inst >> 22) & 0b1011001111) == 0b1000000111) { |
| if (dec->cfg->ext_zicfiss |
| && operand_mop_r_imm(inst) == 28) { |
| switch (operand_rs1(inst)) { |
| case 0: |
| return &op_ssrdp; |
| case 1: |
| case 5: |
| if (operand_rd(inst) == 0) { |
| return &op_sspopchk; |
| } |
| } |
| } |
| return &op_mop_r; |
| } |
| if (((inst >> 25) & 0b1011001) == 0b1000001) { |
| if (dec->cfg->ext_zicfiss |
| && operand_mop_rr_imm(inst) == 7 |
| && operand_rd(inst) == 0 |
| && operand_rs1(inst) == 0) { |
| switch (operand_rs2(inst)) { |
| case 1: |
| case 5: |
| return &op_sspush; |
| } |
| } |
| return &op_mop_rr; |
| } |
| } |
| break; |
| case 5: |
| switch (operand_csr12(inst)) { |
| case 1: return &op_fsflagsi; |
| case 2: return &op_fsrmi; |
| default: return &op_csrrwi; |
| } |
| break; |
| case 6: return &op_csrrsi; |
| case 7: return &op_csrrci; |
| } |
| break; |
| case 29: |
| if (((inst >> 25) & 1) == 1 && ((inst >> 12) & 0b111) == 2) { |
| switch ((inst >> 26) & 0b111111) { |
| case 32: return &op_vsm3me_vv; |
| case 33: return &op_vsm4k_vi; |
| case 34: return &op_vaeskf1_vi; |
| case 40: |
| switch ((inst >> 15) & 0b11111) { |
| case 0: return &op_vaesdm_vv; |
| case 1: return &op_vaesdf_vv; |
| case 2: return &op_vaesem_vv; |
| case 3: return &op_vaesef_vv; |
| case 16: return &op_vsm4r_vv; |
| case 17: return &op_vgmul_vv; |
| } |
| break; |
| case 41: |
| switch ((inst >> 15) & 0b11111) { |
| case 0: return &op_vaesdm_vs; |
| case 1: return &op_vaesdf_vs; |
| case 2: return &op_vaesem_vs; |
| case 3: return &op_vaesef_vs; |
| case 7: return &op_vaesz_vs; |
| case 16: return &op_vsm4r_vs; |
| } |
| break; |
| case 42: return &op_vaeskf2_vi; |
| case 43: return &op_vsm3c_vi; |
| case 44: return &op_vghsh_vv; |
| case 45: return &op_vsha2ms_vv; |
| case 46: return &op_vsha2ch_vv; |
| case 47: return &op_vsha2cl_vv; |
| } |
| } |
| break; |
| case 30: |
| switch (((inst >> 22) & 0b1111111000) | |
| ((inst >> 12) & 0b0000000111)) { |
| case 0: return &op_addd; |
| case 1: return &op_slld; |
| case 5: return &op_srld; |
| case 8: return &op_muld; |
| case 12: return &op_divd; |
| case 13: return &op_divud; |
| case 14: return &op_remd; |
| case 15: return &op_remud; |
| case 256: return &op_subd; |
| case 261: return &op_srad; |
| } |
| break; |
| } |
| break; |
| } |
| |
| return NULL; |
| } |
| |
| /* decode operands */ |
| |
| static void decode_inst_operands(rv_decode *dec, rv_isa isa, |
| const rv_opcode_data *op) |
| { |
| rv_inst inst = dec->inst; |
| |
| switch (op->codec) { |
| case rv_codec_none: |
| dec->rd = dec->rs1 = dec->rs2 = rv_ireg_zero; |
| dec->imm = 0; |
| break; |
| case rv_codec_u: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_imm20(inst); |
| break; |
| case rv_codec_uj: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_jimm20(inst); |
| break; |
| case rv_codec_i: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_imm12(inst); |
| break; |
| case rv_codec_i_sh5: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_shamt5(inst); |
| break; |
| case rv_codec_i_sh6: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_shamt6(inst); |
| break; |
| case rv_codec_i_sh7: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_shamt7(inst); |
| break; |
| case rv_codec_i_csr: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_csr12(inst); |
| break; |
| case rv_codec_s: |
| dec->rd = rv_ireg_zero; |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = operand_rs2(inst); |
| dec->imm = operand_simm12(inst); |
| break; |
| case rv_codec_sb: |
| dec->rd = rv_ireg_zero; |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = operand_rs2(inst); |
| dec->imm = operand_sbimm12(inst); |
| break; |
| case rv_codec_r: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = operand_rs2(inst); |
| dec->imm = 0; |
| break; |
| case rv_codec_r_m: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = operand_rs2(inst); |
| dec->imm = 0; |
| dec->rm = operand_rm(inst); |
| break; |
| case rv_codec_r4_m: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = operand_rs2(inst); |
| dec->rs3 = operand_rs3(inst); |
| dec->imm = 0; |
| dec->rm = operand_rm(inst); |
| break; |
| case rv_codec_r_a: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = operand_rs2(inst); |
| dec->imm = 0; |
| dec->aq = operand_aq(inst); |
| dec->rl = operand_rl(inst); |
| break; |
| case rv_codec_r_l: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = 0; |
| dec->aq = operand_aq(inst); |
| dec->rl = operand_rl(inst); |
| break; |
| case rv_codec_r_f: |
| dec->rd = dec->rs1 = dec->rs2 = rv_ireg_zero; |
| dec->pred = operand_pred(inst); |
| dec->succ = operand_succ(inst); |
| dec->imm = 0; |
| break; |
| case rv_codec_cb: |
| dec->rd = rv_ireg_zero; |
| dec->rs1 = operand_crs1q(inst) + 8; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmb(inst); |
| break; |
| case rv_codec_cb_imm: |
| dec->rd = dec->rs1 = operand_crs1rdq(inst) + 8; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmi(inst); |
| break; |
| case rv_codec_cb_sh5: |
| dec->rd = dec->rs1 = operand_crs1rdq(inst) + 8; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmsh5(inst); |
| break; |
| case rv_codec_cb_sh6: |
| dec->rd = dec->rs1 = operand_crs1rdq(inst) + 8; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmshr6(inst, isa); |
| break; |
| case rv_codec_ci: |
| dec->rd = dec->rs1 = operand_crs1rd(inst); |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmi(inst); |
| break; |
| case rv_codec_ci_sh5: |
| dec->rd = dec->rs1 = operand_crs1rd(inst); |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmsh5(inst); |
| break; |
| case rv_codec_ci_sh6: |
| dec->rd = dec->rs1 = operand_crs1rd(inst); |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmshl6(inst, isa); |
| break; |
| case rv_codec_ci_16sp: |
| dec->rd = rv_ireg_sp; |
| dec->rs1 = rv_ireg_sp; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimm16sp(inst); |
| break; |
| case rv_codec_ci_lwsp: |
| dec->rd = operand_crd(inst); |
| dec->rs1 = rv_ireg_sp; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmlwsp(inst); |
| break; |
| case rv_codec_ci_ldsp: |
| dec->rd = operand_crd(inst); |
| dec->rs1 = rv_ireg_sp; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmldsp(inst); |
| break; |
| case rv_codec_ci_lqsp: |
| dec->rd = operand_crd(inst); |
| dec->rs1 = rv_ireg_sp; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmlqsp(inst); |
| break; |
| case rv_codec_ci_li: |
| dec->rd = operand_crd(inst); |
| dec->rs1 = rv_ireg_zero; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmi(inst); |
| break; |
| case rv_codec_ci_lui: |
| dec->rd = operand_crd(inst); |
| dec->rs1 = rv_ireg_zero; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmui(inst); |
| break; |
| case rv_codec_ci_none: |
| dec->rd = dec->rs1 = dec->rs2 = rv_ireg_zero; |
| dec->imm = 0; |
| break; |
| case rv_codec_ciw_4spn: |
| dec->rd = operand_crdq(inst) + 8; |
| dec->rs1 = rv_ireg_sp; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimm4spn(inst); |
| break; |
| case rv_codec_cj: |
| dec->rd = dec->rs1 = dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmj(inst); |
| break; |
| case rv_codec_cj_jal: |
| dec->rd = rv_ireg_ra; |
| dec->rs1 = dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmj(inst); |
| break; |
| case rv_codec_cl_lw: |
| dec->rd = operand_crdq(inst) + 8; |
| dec->rs1 = operand_crs1q(inst) + 8; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmw(inst); |
| break; |
| case rv_codec_cl_ld: |
| dec->rd = operand_crdq(inst) + 8; |
| dec->rs1 = operand_crs1q(inst) + 8; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmd(inst); |
| break; |
| case rv_codec_cl_lq: |
| dec->rd = operand_crdq(inst) + 8; |
| dec->rs1 = operand_crs1q(inst) + 8; |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = operand_cimmq(inst); |
| break; |
| case rv_codec_cr: |
| dec->rd = dec->rs1 = operand_crs1rd(inst); |
| dec->rs2 = operand_crs2(inst); |
| dec->imm = 0; |
| break; |
| case rv_codec_cr_mv: |
| dec->rd = operand_crd(inst); |
| dec->rs1 = operand_crs2(inst); |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = 0; |
| break; |
| case rv_codec_cr_jalr: |
| dec->rd = rv_ireg_ra; |
| dec->rs1 = operand_crs1(inst); |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = 0; |
| break; |
| case rv_codec_cr_jr: |
| dec->rd = rv_ireg_zero; |
| dec->rs1 = operand_crs1(inst); |
| dec->rs2 = rv_ireg_zero; |
| dec->imm = 0; |
| break; |
| case rv_codec_cs: |
| dec->rd = dec->rs1 = operand_crs1rdq(inst) + 8; |
| dec->rs2 = operand_crs2q(inst) + 8; |
| dec->imm = 0; |
| break; |
| case rv_codec_cs_sw: |
| dec->rd = rv_ireg_zero; |
| dec->rs1 = operand_crs1q(inst) + 8; |
| dec->rs2 = operand_crs2q(inst) + 8; |
| dec->imm = operand_cimmw(inst); |
| break; |
| case rv_codec_cs_sd: |
| dec->rd = rv_ireg_zero; |
| dec->rs1 = operand_crs1q(inst) + 8; |
| dec->rs2 = operand_crs2q(inst) + 8; |
| dec->imm = operand_cimmd(inst); |
| break; |
| case rv_codec_cs_sq: |
| dec->rd = rv_ireg_zero; |
| dec->rs1 = operand_crs1q(inst) + 8; |
| dec->rs2 = operand_crs2q(inst) + 8; |
| dec->imm = operand_cimmq(inst); |
| break; |
| case rv_codec_css_swsp: |
| dec->rd = rv_ireg_zero; |
| dec->rs1 = rv_ireg_sp; |
| dec->rs2 = operand_crs2(inst); |
| dec->imm = operand_cimmswsp(inst); |
| break; |
| case rv_codec_css_sdsp: |
| dec->rd = rv_ireg_zero; |
| dec->rs1 = rv_ireg_sp; |
| dec->rs2 = operand_crs2(inst); |
| dec->imm = operand_cimmsdsp(inst); |
| break; |
| case rv_codec_css_sqsp: |
| dec->rd = rv_ireg_zero; |
| dec->rs1 = rv_ireg_sp; |
| dec->rs2 = operand_crs2(inst); |
| dec->imm = operand_cimmsqsp(inst); |
| break; |
| case rv_codec_k_bs: |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = operand_rs2(inst); |
| dec->bs = operand_bs(inst); |
| break; |
| case rv_codec_k_rnum: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rnum = operand_rnum(inst); |
| break; |
| case rv_codec_v_r: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = operand_rs2(inst); |
| dec->vm = operand_vm(inst); |
| break; |
| case rv_codec_v_ldst: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->vm = operand_vm(inst); |
| break; |
| case rv_codec_v_i: |
| dec->rd = operand_rd(inst); |
| dec->rs2 = operand_rs2(inst); |
| dec->imm = operand_vimm(inst); |
| dec->vm = operand_vm(inst); |
| break; |
| case rv_codec_v_i_u: |
| dec->rd = operand_rd(inst); |
| dec->rs2 = operand_rs2(inst); |
| dec->imm = operand_vuimm(inst); |
| dec->vm = operand_vm(inst); |
| break; |
| case rv_codec_vror_vi: |
| dec->rd = operand_rd(inst); |
| dec->rs2 = operand_rs2(inst); |
| dec->imm = operand_vzimm6(inst); |
| dec->vm = operand_vm(inst); |
| break; |
| case rv_codec_vsetvli: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->vzimm = operand_vzimm11(inst); |
| break; |
| case rv_codec_vsetivli: |
| dec->rd = operand_rd(inst); |
| dec->imm = extract32(inst, 15, 5); |
| dec->vzimm = operand_vzimm10(inst); |
| break; |
| case rv_codec_zcb_lb: |
| dec->rs1 = operand_crs1q(inst) + 8; |
| dec->rs2 = operand_crs2q(inst) + 8; |
| dec->imm = operand_uimm_c_lb(inst); |
| break; |
| case rv_codec_zcb_lh: |
| dec->rs1 = operand_crs1q(inst) + 8; |
| dec->rs2 = operand_crs2q(inst) + 8; |
| dec->imm = operand_uimm_c_lh(inst); |
| break; |
| case rv_codec_zcb_ext: |
| dec->rd = operand_crs1q(inst) + 8; |
| break; |
| case rv_codec_zcb_mul: |
| dec->rd = operand_crs1rdq(inst) + 8; |
| dec->rs2 = operand_crs2q(inst) + 8; |
| break; |
| case rv_codec_zcmp_cm_pushpop: |
| dec->imm = operand_zcmp_stack_adj(inst, isa); |
| dec->rlist = operand_zcmp_rlist(inst); |
| break; |
| case rv_codec_zcmp_cm_mv: |
| dec->rd = operand_sreg1(inst); |
| dec->rs2 = operand_sreg2(inst); |
| break; |
| case rv_codec_zcmt_jt: |
| dec->imm = operand_tbl_index(inst); |
| break; |
| case rv_codec_fli: |
| dec->rd = operand_rd(inst); |
| dec->imm = operand_rs1(inst); |
| break; |
| case rv_codec_r2_imm5: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->imm = operand_rs2(inst); |
| break; |
| case rv_codec_r2: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| break; |
| case rv_codec_r2_imm6: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->imm = operand_imm6(inst); |
| break; |
| case rv_codec_r_imm2: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = operand_rs2(inst); |
| dec->imm = operand_imm2(inst); |
| break; |
| case rv_codec_r2_immhl: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->imm = operand_immh(inst); |
| dec->imm1 = operand_imml(inst); |
| break; |
| case rv_codec_r2_imm2_imm5: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->imm = sextract32(operand_rs2(inst), 0, 5); |
| dec->imm1 = operand_imm2(inst); |
| break; |
| case rv_codec_lp: |
| dec->imm = operand_lpl(inst); |
| break; |
| case rv_codec_cmop: |
| dec->imm = operand_cmop_imm(inst); |
| break; |
| case rv_codec_cmop_ss: |
| dec->rd = rv_ireg_zero; |
| dec->rs1 = dec->rs2 = operand_crs1(inst); |
| dec->imm = 0; |
| break; |
| case rv_codec_mop_r: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->imm = operand_mop_r_imm(inst); |
| break; |
| case rv_codec_mop_rr: |
| dec->rd = operand_rd(inst); |
| dec->rs1 = operand_rs1(inst); |
| dec->rs2 = operand_rs2(inst); |
| dec->imm = operand_mop_rr_imm(inst); |
| break; |
| default: |
| g_assert_not_reached(); |
| } |
| } |
| |
| /* check constraint */ |
| |
| static bool check_constraints(rv_decode *dec, const rvc_constraint *c) |
| { |
| int32_t imm = dec->imm; |
| uint8_t rd = dec->rd, rs1 = dec->rs1, rs2 = dec->rs2; |
| while (*c != rvc_end) { |
| switch (*c) { |
| case rvc_rd_eq_ra: |
| if (!(rd == 1)) { |
| return false; |
| } |
| break; |
| case rvc_rd_eq_x0: |
| if (!(rd == 0)) { |
| return false; |
| } |
| break; |
| case rvc_rs1_eq_x0: |
| if (!(rs1 == 0)) { |
| return false; |
| } |
| break; |
| case rvc_rs2_eq_x0: |
| if (!(rs2 == 0)) { |
| return false; |
| } |
| break; |
| case rvc_rs2_eq_rs1: |
| if (!(rs2 == rs1)) { |
| return false; |
| } |
| break; |
| case rvc_rs1_eq_ra: |
| if (!(rs1 == 1)) { |
| return false; |
| } |
| break; |
| case rvc_imm_eq_zero: |
| if (!(imm == 0)) { |
| return false; |
| } |
| break; |
| case rvc_imm_eq_n1: |
| if (!(imm == -1)) { |
| return false; |
| } |
| break; |
| case rvc_imm_eq_p1: |
| if (!(imm == 1)) { |
| return false; |
| } |
| break; |
| default: break; |
| } |
| c++; |
| } |
| return true; |
| } |
| |
| /* Same as insn_len() from target/riscv/internals.h */ |
| static size_t inst_length(rv_inst inst) |
| { |
| return (inst & 3) == 3 ? 4 : 2; |
| } |
| |
| /* format instruction */ |
| |
| static GString *format_inst(size_t tab, rv_decode *dec, |
| const rv_opcode_data *op) |
| { |
| GString *buf = g_string_sized_new(64); |
| const char *fmt = op->format; |
| |
| while (*fmt) { |
| switch (*fmt) { |
| case 'O': |
| g_string_append(buf, op->name); |
| break; |
| case '(': |
| case '.': |
| case ',': |
| case ')': |
| case '-': |
| g_string_append_c(buf, *fmt); |
| break; |
| case 'b': |
| g_string_append_printf(buf, "%d", dec->bs); |
| break; |
| case 'n': |
| g_string_append_printf(buf, "%d", dec->rnum); |
| break; |
| case '0': |
| g_string_append(buf, rv_ireg_name_sym[dec->rd]); |
| break; |
| case '1': |
| g_string_append(buf, rv_ireg_name_sym[dec->rs1]); |
| break; |
| case '2': |
| g_string_append(buf, rv_ireg_name_sym[dec->rs2]); |
| break; |
| case '3': |
| if (dec->cfg && dec->cfg->ext_zfinx) { |
| g_string_append(buf, rv_ireg_name_sym[dec->rd]); |
| } else { |
| g_string_append(buf, rv_freg_name_sym[dec->rd]); |
| } |
| break; |
| case '4': |
| if (dec->cfg && dec->cfg->ext_zfinx) { |
| g_string_append(buf, rv_ireg_name_sym[dec->rs1]); |
| } else { |
| g_string_append(buf, rv_freg_name_sym[dec->rs1]); |
| } |
| break; |
| case '5': |
| if (dec->cfg && dec->cfg->ext_zfinx) { |
| g_string_append(buf, rv_ireg_name_sym[dec->rs2]); |
| } else { |
| g_string_append(buf, rv_freg_name_sym[dec->rs2]); |
| } |
| break; |
| case '6': |
| if (dec->cfg && dec->cfg->ext_zfinx) { |
| g_string_append(buf, rv_ireg_name_sym[dec->rs3]); |
| } else { |
| g_string_append(buf, rv_freg_name_sym[dec->rs3]); |
| } |
| break; |
| case '7': |
| g_string_append_printf(buf, "%d", dec->rs1); |
| break; |
| case 'i': |
| g_string_append_printf(buf, "%d", dec->imm); |
| break; |
| case 'u': |
| g_string_append_printf(buf, "%u", ((uint32_t)dec->imm & 0b111111)); |
| break; |
| case 'j': |
| g_string_append_printf(buf, "%d", dec->imm1); |
| break; |
| case 'o': |
| g_string_append_printf(buf, "%d", dec->imm); |
| while (buf->len < tab * 2) { |
| g_string_append_c(buf, ' '); |
| } |
| g_string_append_printf(buf, "# 0x%" PRIx64, dec->pc + dec->imm); |
| break; |
| case 'U': |
| fmt++; |
| g_string_append_printf(buf, "%d", dec->imm >> 12); |
| if (*fmt == 'o') { |
| while (buf->len < tab * 2) { |
| g_string_append_c(buf, ' '); |
| } |
| g_string_append_printf(buf, "# 0x%" PRIx64, dec->pc + dec->imm); |
| } |
| break; |
| case 'c': { |
| const char *name = csr_name(dec->imm & 0xfff); |
| if (name) { |
| g_string_append(buf, name); |
| } else { |
| g_string_append_printf(buf, "0x%03x", dec->imm & 0xfff); |
| } |
| break; |
| } |
| case 'r': |
| switch (dec->rm) { |
| case rv_rm_rne: |
| g_string_append(buf, "rne"); |
| break; |
| case rv_rm_rtz: |
| g_string_append(buf, "rtz"); |
| break; |
| case rv_rm_rdn: |
| g_string_append(buf, "rdn"); |
| break; |
| case rv_rm_rup: |
| g_string_append(buf, "rup"); |
| break; |
| case rv_rm_rmm: |
| g_string_append(buf, "rmm"); |
| break; |
| case rv_rm_dyn: |
| g_string_append(buf, "dyn"); |
| break; |
| default: |
| g_string_append(buf, "inv"); |
| break; |
| } |
| break; |
| case 'p': |
| if (dec->pred & rv_fence_i) { |
| g_string_append_c(buf, 'i'); |
| } |
| if (dec->pred & rv_fence_o) { |
| g_string_append_c(buf, 'o'); |
| } |
| if (dec->pred & rv_fence_r) { |
| g_string_append_c(buf, 'r'); |
| } |
| if (dec->pred & rv_fence_w) { |
| g_string_append_c(buf, 'w'); |
| } |
| break; |
| case 's': |
| if (dec->succ & rv_fence_i) { |
| g_string_append_c(buf, 'i'); |
| } |
| if (dec->succ & rv_fence_o) { |
| g_string_append_c(buf, 'o'); |
| } |
| if (dec->succ & rv_fence_r) { |
| g_string_append_c(buf, 'r'); |
| } |
| if (dec->succ & rv_fence_w) { |
| g_string_append_c(buf, 'w'); |
| } |
| break; |
| case '\t': |
| while (buf->len < tab) { |
| g_string_append_c(buf, ' '); |
| } |
| break; |
| case 'A': |
| if (dec->aq) { |
| g_string_append(buf, ".aq"); |
| } |
| break; |
| case 'R': |
| if (dec->rl) { |
| g_string_append(buf, ".rl"); |
| } |
| break; |
| case 'l': |
| g_string_append(buf, ",v0"); |
| break; |
| case 'm': |
| if (dec->vm == 0) { |
| g_string_append(buf, ",v0.t"); |
| } |
| break; |
| case 'D': |
| g_string_append(buf, rv_vreg_name_sym[dec->rd]); |
| break; |
| case 'E': |
| g_string_append(buf, rv_vreg_name_sym[dec->rs1]); |
| break; |
| case 'F': |
| g_string_append(buf, rv_vreg_name_sym[dec->rs2]); |
| break; |
| case 'G': |
| g_string_append(buf, rv_vreg_name_sym[dec->rs3]); |
| break; |
| case 'v': { |
| const int sew = 1 << (((dec->vzimm >> 3) & 0b111) + 3); |
| const int lmul = dec->vzimm & 0b11; |
| const int flmul = (dec->vzimm >> 2) & 1; |
| const char *vta = (dec->vzimm >> 6) & 1 ? "ta" : "tu"; |
| const char *vma = (dec->vzimm >> 7) & 1 ? "ma" : "mu"; |
| |
| g_string_append_printf(buf, "e%d,m", sew); |
| if (flmul) { |
| switch (lmul) { |
| case 3: |
| g_string_append(buf, "f2"); |
| break; |
| case 2: |
| g_string_append(buf, "f4"); |
| break; |
| case 1: |
| g_string_append(buf, "f8"); |
| break; |
| } |
| } else { |
| g_string_append_printf(buf, "%d", 1 << lmul); |
| } |
| g_string_append_c(buf, ','); |
| g_string_append(buf, vta); |
| g_string_append_c(buf, ','); |
| g_string_append(buf, vma); |
| break; |
| } |
| case 'x': { |
| switch (dec->rlist) { |
| case 4: |
| g_string_append(buf, "{ra}"); |
| break; |
| case 5: |
| g_string_append(buf, "{ra, s0}"); |
| break; |
| case 15: |
| g_string_append(buf, "{ra, s0-s11}"); |
| break; |
| default: |
| g_string_append_printf(buf, "{ra, s0-s%d}", dec->rlist - 5); |
| break; |
| } |
| break; |
| } |
| case 'h': |
| g_string_append(buf, rv_fli_name_const[dec->imm]); |
| break; |
| default: |
| break; |
| } |
| fmt++; |
| } |
| |
| return buf; |
| } |
| |
| /* lift instruction to pseudo-instruction */ |
| |
| static const rv_opcode_data *decode_inst_lift_pseudo(rv_decode *dec, |
| const rv_opcode_data *op) |
| { |
| const rv_comp_data *comp_data = op->pseudo; |
| if (comp_data) { |
| while (comp_data->constraints) { |
| if (check_constraints(dec, comp_data->constraints)) { |
| assert(op != comp_data->op); |
| return decode_inst_lift_pseudo(dec, comp_data->op); |
| } |
| comp_data++; |
| } |
| } |
| return op; |
| } |
| |
| /* disassemble instruction */ |
| |
| static GString *disasm_inst(rv_isa isa, uint64_t pc, rv_inst inst, |
| const RISCVCPUConfig *cfg) |
| { |
| rv_decode dec = { |
| .pc = pc, |
| .inst = inst, |
| .cfg = cfg, |
| }; |
| const rv_opcode_data *op = decode_inst_opcode(&dec, isa); |
| |
| if (!op && cfg) { |
| static const struct { |
| bool (*guard_func)(const RISCVCPUConfig *); |
| const rv_opcode_data *(*decode_func)(rv_decode *, rv_isa); |
| } decoders[] = { |
| { has_xtheadba_p, decode_xtheadba }, |
| { has_xtheadbb_p, decode_xtheadbb }, |
| { has_xtheadbs_p, decode_xtheadbs }, |
| { has_xtheadcmo_p, decode_xtheadcmo }, |
| { has_xtheadcondmov_p, decode_xtheadcondmov }, |
| { has_xtheadfmemidx_p, decode_xtheadfmemidx }, |
| { has_xtheadfmv_p, decode_xtheadfmv }, |
| { has_xtheadmac_p, decode_xtheadmac }, |
| { has_xtheadmemidx_p, decode_xtheadmemidx }, |
| { has_xtheadmempair_p, decode_xtheadmempair }, |
| { has_xtheadsync_p, decode_xtheadsync }, |
| { has_XVentanaCondOps_p, decode_xventanacondops }, |
| { has_xlrbr_p, decode_xlrbr }, |
| }; |
| |
| for (size_t i = 0; i < ARRAY_SIZE(decoders); i++) { |
| if (decoders[i].guard_func(cfg)) { |
| op = decoders[i].decode_func(&dec, isa); |
| if (op) { |
| break; |
| } |
| } |
| } |
| } |
| |
| if (op) { |
| decode_inst_operands(&dec, isa, op); |
| op = decode_inst_lift_pseudo(&dec, op); |
| } else { |
| op = &op_illegal; |
| } |
| |
| return format_inst(24, &dec, op); |
| } |
| |
| #define INST_FMT_2 "%04x " |
| #define INST_FMT_4 "%08x " |
| |
| static int |
| print_insn_riscv(bfd_vma memaddr, struct disassemble_info *info, rv_isa isa) |
| { |
| bfd_byte packet[2]; |
| rv_inst inst = 0; |
| size_t len = 2; |
| bfd_vma n; |
| int status; |
| |
| /* Instructions are made of 2-byte packets in little-endian order */ |
| for (n = 0; n < len; n += 2) { |
| status = (*info->read_memory_func)(memaddr + n, packet, 2, info); |
| if (status != 0) { |
| /* Don't fail just because we fell off the end. */ |
| if (n > 0) { |
| break; |
| } |
| (*info->memory_error_func)(status, memaddr, info); |
| return status; |
| } |
| inst |= ((rv_inst) bfd_getl16(packet)) << (8 * n); |
| if (n == 0) { |
| len = inst_length(inst); |
| } |
| } |
| |
| if (info->show_opcodes) { |
| switch (len) { |
| case 2: |
| (*info->fprintf_func)(info->stream, INST_FMT_2, inst); |
| break; |
| case 4: |
| (*info->fprintf_func)(info->stream, INST_FMT_4, inst); |
| break; |
| default: |
| g_assert_not_reached(); |
| } |
| } |
| |
| g_autoptr(GString) str = |
| disasm_inst(isa, memaddr, inst, |
| (const RISCVCPUConfig *)info->target_info); |
| (*info->fprintf_func)(info->stream, "%s", str->str); |
| |
| return len; |
| } |
| |
| int print_insn_riscv32(bfd_vma memaddr, struct disassemble_info *info) |
| { |
| return print_insn_riscv(memaddr, info, rv32); |
| } |
| |
| int print_insn_riscv64(bfd_vma memaddr, struct disassemble_info *info) |
| { |
| return print_insn_riscv(memaddr, info, rv64); |
| } |
| |
| int print_insn_riscv128(bfd_vma memaddr, struct disassemble_info *info) |
| { |
| return print_insn_riscv(memaddr, info, rv128); |
| } |