From 2dcaaf61d846d8e29a01108f2f5879176a86ffd9 Mon Sep 17 00:00:00 2001 From: Yang Hau Date: Fri, 18 Oct 2024 00:05:04 +0200 Subject: [PATCH] Add decoder for RVV instructions --- src/decode.c | 181 +++++++++++++++++++++++++++++++++++++++- src/decode.h | 28 +++++++ src/emulate.c | 3 + src/feature.h | 5 ++ src/rv32_constopt.c | 25 ++++++ src/rv32_rvv_template.c | 24 ++++++ 6 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 src/rv32_rvv_template.c diff --git a/src/decode.c b/src/decode.c index c434b0fa..a33e1366 100644 --- a/src/decode.c +++ b/src/decode.c @@ -118,6 +118,16 @@ static inline uint32_t decode_r4type_rs3(const uint32_t insn) } #endif +#if RV32_HAS(EXT_RVV) +/* decode RVV vm field + * vm = inst[25] + */ +static inline uint32_t decode_rvv_vm(const uint32_t insn) +{ + return (insn >> 25) & 0x1; +} +#endif + #if RV32_HAS(EXT_C) enum { /* clang-format off */ @@ -1791,6 +1801,165 @@ static inline bool op_cfsw(rv_insn_t *ir, const uint32_t insn) #define op_cflwsp OP_UNIMP #endif /* RV32_HAS(EXT_C) && RV32_HAS(EXT_F) */ +static inline bool op_ivv(rv_insn_t *ir, const uint32_t insn) { +#define MASK 0xfc00707f +#define MATCH_VADD_VI 0x3057 +#define MATCH_VAND_VI 0x24003057 +#define MATCH_VMADC_VI 0x46003057 +#define MATCH_VMSEQ_VI 0x60003057 +#define MATCH_VMSGT_VI 0x7c003057 +#define MATCH_VMSGTU_VI 0x78003057 +#define MATCH_VMSLE_VI 0x74003057 +#define MATCH_VMSLEU_VI 0x70003057 +#define MATCH_VMSNE_VI 0x64003057 +#define MATCH_VOR_VI 0x28003057 +#define MATCH_VRGATHER_VI 0x30003057 +#define MATCH_VRSUB_VI 0xc003057 +#define MATCH_VSADD_VI 0x84003057 +#define MATCH_VSADDU_VI 0x80003057 +#define MATCH_VSLIDEDOWN_VI 0x3c003057 +#define MATCH_VSLIDEUP_VI 0x38003057 +#define MATCH_VSLL_VI 0x94003057 +#define MATCH_VSRA_VI 0xa4003057 +#define MATCH_VSRL_VI 0xa0003057 +#define MATCH_VSSRA_VI 0xac003057 +#define MATCH_VSSRL_VI 0xa8003057 +#define MATCH_VXOR_VI 0x2c003057 + + ir->rs1 = decode_rs1(insn); + ir->rs2 = decode_rs2(insn); + ir->vm = decode_rvv_vm(insn); + switch (insn & MASK) { + case MATCH_VADD_VI: + ir->opcode = rv_insn_vadd_vi; + break; + case MATCH_VAND_VI: + ir->opcode = rv_insn_vand_vi; + break; + case MATCH_VMADC_VI: + ir->opcode = rv_insn_vmadc_vi; + break; + case MATCH_VMSEQ_VI: + ir->opcode = rv_insn_vmseq_vi; + break; + case MATCH_VMSGT_VI: + ir->opcode = rv_insn_vmsgt_vi; + break; + case MATCH_VMSGTU_VI: + ir->opcode = rv_insn_vmsgtu_vi; + break; + case MATCH_VMSLE_VI: + ir->opcode = rv_insn_vmsle_vi; + break; + case MATCH_VMSLEU_VI: + ir->opcode = rv_insn_vmsleu_vi; + break; + case MATCH_VMSNE_VI: + ir->opcode = rv_insn_vmsne_vi; + break; + case MATCH_VOR_VI: + ir->opcode = rv_insn_vor_vi; + break; + case MATCH_VRGATHER_VI: + ir->opcode = rv_insn_vrgather_vi; + break; + case MATCH_VRSUB_VI: + ir->opcode = rv_insn_vrsub_vi; + break; + case MATCH_VSADD_VI: + ir->opcode = rv_insn_vsadd_vi; + break; + case MATCH_VSADDU_VI: + ir->opcode = rv_insn_vsaddu_vi; + break; + case MATCH_VSLIDEDOWN_VI: + ir->opcode = rv_insn_vslidedown_vi; + break; + case MATCH_VSLIDEUP_VI: + ir->opcode = rv_insn_vslideup_vi; + break; + case MATCH_VSLL_VI: + ir->opcode = rv_insn_vsll_vi; + break; + case MATCH_VSRA_VI: + ir->opcode = rv_insn_vsra_vi; + break; + case MATCH_VSRL_VI: + ir->opcode = rv_insn_vsrl_vi; + break; + case MATCH_VSSRA_VI: + ir->opcode = rv_insn_vssra_vi; + break; + case MATCH_VSSRL_VI: + ir->opcode = rv_insn_vssrl_vi; + break; + case MATCH_VXOR_VI: + ir->opcode = rv_insn_vxor_vi; + break; + default: + return false; + } +} + +static inline bool op_fvv(rv_insn_t *ir, const uint32_t insn) {} +static inline bool op_mvv(rv_insn_t *ir, const uint32_t insn) {} +static inline bool op_ivi(rv_insn_t *ir, const uint32_t insn) {} +static inline bool op_ivx(rv_insn_t *ir, const uint32_t insn) {} +static inline bool op_fvf(rv_insn_t *ir, const uint32_t insn) {} +static inline bool op_mvx(rv_insn_t *ir, const uint32_t insn) {} + +/* OP: RVV + * opcode is 0x57 + * 31 26 25 24 20 19 15 14 12 11 7 6 0 + * funct6 | vm | vs2 | vs1 | 0 0 0 (funct3) | vd |1010111| OP-V (OPIVV) + * funct6 | vm | vs2 | vs1 | 0 0 1 (funct3) | vd/rd |1010111| OP-V (OPFVV) + * funct6 | vm | vs2 | vs1 | 0 1 0 (funct3) | vd/rd |1010111| OP-V (OPMVV) + * funct6 | vm | vs2 | imm[4:0] | 0 1 1 (funct3) | vd |1010111| OP-V (OPIVI) + * funct6 | vm | vs2 | rs1 | 1 0 0 (funct3) | vd |1010111| OP-V (OPIVX) + * funct6 | vm | vs2 | rs1 | 1 0 1 (funct3) | vd |1010111| OP-V (OPFVF) + * funct6 | vm | vs2 | rs1 | 1 1 0 (funct3) | vd/rd |1010111| OP-V (OPMVX) + * 6 1 5 5 3 5 7 + * + * Where 'vm' is the bit indicates whether masking is enabled + * see https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#531-mask-encoding + * + * reference: + * https://github.com/riscv/riscv-isa-manual/blob/main/src/images/wavedrom/valu-format.edn + * https://github.com/riscv/riscv-isa-manual/blob/main/src/images/wavedrom/v-inst-table.edn + * https://observablehq.com/@drom/risc-v-v + * + * funct3 + * | 0 | 0 | 0 | OPIVV | vector-vector | N/A + * | 0 | 0 | 1 | OPFVV | vector-vector | N/A + * | 0 | 1 | 0 | OPMVV | vector-vector | N/A + * | 0 | 1 | 1 | OPIVI | vector-immediate | `imm[4:0]` + * | 1 | 0 | 0 | OPIVX | vector-scalar | GPR `x` register `rs1` + * | 1 | 0 | 1 | OPFVF | vector-scalar | FP `f` register `rs1` + * | 1 | 1 | 0 | OPMVX | vector-scalar | GPR `x` register `rs1` + */ +static inline bool op_v(rv_insn_t *ir, const uint32_t insn) +{ + uint32_t funct3_mask = 0x7000; + switch (insn & funct3_mask) { + case 0: + return op_ivv(ir, insn); + case 1: + return op_fvv(ir, insn); + case 2: + return op_mvv(ir, insn); + case 3: + return op_ivi(ir, insn); + case 4: + return op_ivx(ir, insn); + case 5: + return op_fvf(ir, insn); + case 6: + return op_mvx(ir, insn); + default: + return false; + } +} + /* handler for all unimplemented opcodes */ static inline bool op_unimp(rv_insn_t *ir UNUSED, uint32_t insn UNUSED) { @@ -1800,18 +1969,28 @@ static inline bool op_unimp(rv_insn_t *ir UNUSED, uint32_t insn UNUSED) /* RV32 decode handler type */ typedef bool (*decode_t)(rv_insn_t *ir, uint32_t insn); +#if RV32_HAS(EXT_RVV) +#define MASK_OPCODE_RVV 0x57 +#endif /* decode RISC-V instruction */ bool rv_decode(rv_insn_t *ir, uint32_t insn) { assert(ir); +#if RV32_HAS(EXT_RVV) + if (insn & MASK_OPCODE_RVV) { + return op_v(ir, insn); + } +#endif + #define OP_UNIMP op_unimp #define OP(insn) op_##insn /* RV32 base opcode map */ /* clang-format off */ static const decode_t rv_jump_table[] = { - // 000 001 010 011 100 101 110 111 + // insn[4:2] + // 000 001 010 011 100 101 110 111 // insn[6:5] OP(load), OP(load_fp), OP(unimp), OP(misc_mem), OP(op_imm), OP(auipc), OP(unimp), OP(unimp), // 00 OP(store), OP(store_fp), OP(unimp), OP(amo), OP(op), OP(lui), OP(unimp), OP(unimp), // 01 OP(madd), OP(msub), OP(nmsub), OP(nmadd), OP(op_fp), OP(unimp), OP(unimp), OP(unimp), // 10 diff --git a/src/decode.h b/src/decode.h index 6af8ef2e..13226059 100644 --- a/src/decode.h +++ b/src/decode.h @@ -149,6 +149,30 @@ enum op_field { _(fcvtswu, 0, 4, 0, ENC(rs1, rs2, rd)) \ _(fmvwx, 0, 4, 0, ENC(rs1, rs2, rd)) \ ) \ + IIF(RV32_HAS(EXT_RVV))( \ + _(vadd_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vand_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vmadc_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vmseq_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vmsgt_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vmsgtu_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vmsle_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vmsleu_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vmsne_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vor_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vrgather_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vrsub_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vsadd_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vsaddu_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vslidedown_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vslideup_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vsll_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vsra_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vsrl_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vssra_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vssrl_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + _(vxor_vi, 0, 4, 0, ENC(r1, r2, rd)) \ + ) \ /* RV32C Standard Extension */ \ IIF(RV32_HAS(EXT_C))( \ _(caddi4spn, 0, 2, 1, ENC(rd)) \ @@ -294,6 +318,7 @@ typedef struct rv_insn { int32_t imm; uint8_t rs3; }; + // uses as both scalar registers and vector registers uint8_t rd, rs1, rs2; /* store IR list */ uint8_t opcode; @@ -315,6 +340,9 @@ typedef struct rv_insn { uint8_t rm; #endif +#if RV32_HAS(EXT_RVV) + uint8_t vm; +#endif /* fuse operation */ int32_t imm2; opcode_fuse_t *fuse; diff --git a/src/emulate.c b/src/emulate.c index a8856afb..f28d822b 100644 --- a/src/emulate.c +++ b/src/emulate.c @@ -414,6 +414,9 @@ static bool has_loops = false; } #include "rv32_template.c" +#if RV32_HAS(EXT_RVV) +#include "rv32_rvv_template.c" +#endif #undef RVOP /* multiple LUI */ diff --git a/src/feature.h b/src/feature.h index ee27936a..f387c935 100644 --- a/src/feature.h +++ b/src/feature.h @@ -37,6 +37,11 @@ #define RV32_FEATURE_Zifencei 1 #endif +#define RV32_FEATURE_EXT_RVV 1 +#ifndef RV32_FEATURE_EXT_RVV +// #define RV32_FEATURE_EXT_RVV 1 +#endif + /* Experimental SDL oriented system calls */ #ifndef RV32_FEATURE_SDL #define RV32_FEATURE_SDL 1 diff --git a/src/rv32_constopt.c b/src/rv32_constopt.c index 9ae5a4e3..012f843b 100644 --- a/src/rv32_constopt.c +++ b/src/rv32_constopt.c @@ -1037,3 +1037,28 @@ CONSTOPT(cflw, {}) /* C.FSW */ CONSTOPT(cfsw, {}) #endif + +#if RV32_HAS(EXT_RVV) +CONSTOPT(vadd_vi, {}) +CONSTOPT(vand_vi, {}) +CONSTOPT(vmadc_vi, {}) +CONSTOPT(vmseq_vi, {}) +CONSTOPT(vmsgt_vi, {}) +CONSTOPT(vmsgtu_vi, {}) +CONSTOPT(vmsle_vi, {}) +CONSTOPT(vmsleu_vi, {}) +CONSTOPT(vmsne_vi, {}) +CONSTOPT(vor_vi, {}) +CONSTOPT(vrgather_vi, {}) +CONSTOPT(vrsub_vi, {}) +CONSTOPT(vsadd_vi, {}) +CONSTOPT(vsaddu_vi, {}) +CONSTOPT(vslidedown_vi, {}) +CONSTOPT(vslideup_vi, {}) +CONSTOPT(vsll_vi, {}) +CONSTOPT(vsra_vi, {}) +CONSTOPT(vsrl_vi, {}) +CONSTOPT(vssra_vi, {}) +CONSTOPT(vssrl_vi, {}) +CONSTOPT(vxor_vi, {}) +#endif diff --git a/src/rv32_rvv_template.c b/src/rv32_rvv_template.c new file mode 100644 index 00000000..6e13fce2 --- /dev/null +++ b/src/rv32_rvv_template.c @@ -0,0 +1,24 @@ +/* RV32 RVV Instruction Set */ + +RVOP(vadd_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vand_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vmadc_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vmseq_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vmsgt_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vmsgtu_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vmsle_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vmsleu_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vmsne_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vor_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vrgather_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vrsub_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vsadd_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vsaddu_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vslidedown_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vslideup_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vsll_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vsra_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vsrl_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vssra_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vssrl_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */})) +RVOP(vxor_vi, { rv->X[rv_reg_zero] = 0; }, GEN({/* no operation */}))