Skip to content

Commit

Permalink
Add decoder for RVV instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
howjmay committed Oct 20, 2024
1 parent a00c49f commit 2dcaaf6
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 1 deletion.
181 changes: 180 additions & 1 deletion src/decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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)
{
Expand All @@ -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
Expand Down
28 changes: 28 additions & 0 deletions src/decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)) \
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions src/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
5 changes: 5 additions & 0 deletions src/feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions src/rv32_constopt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
24 changes: 24 additions & 0 deletions src/rv32_rvv_template.c
Original file line number Diff line number Diff line change
@@ -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 */}))

0 comments on commit 2dcaaf6

Please sign in to comment.