Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add decoder for RVV instructions #501

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 219 additions & 1 deletion src/decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <stdlib.h>

#include "decode.h"
#include "encoding.h"
#include "riscv_private.h"

/* decode rd field
Expand Down Expand Up @@ -118,6 +119,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 @@ -1971,6 +1982,204 @@ 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 for VALU and VCFG
*
* VALU format:
* 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
*
* VMEM format:
*
* 31 29 28 27 26 25 24 20 19 15 14 12 11 7 6 0
* nf | mew| mop | vm | lumop | rs1 | width | vd |0000111| VL*
* unit-stride nf | mew| mop | vm | rs2 | rs1 | width | vd
* |0000111| VLS* strided nf | mew| mop | vm | vs2 | rs1 | width | vd
* |0000111| VLX* indexed 3 1 2 1 5 5 3 5 7
*
* VCFG format:
*
* 31 30 25 24 20 19 15 14 12 11 7 6 0
* 0 | zimm[10:0] | rs1 | 1 1 1 | rd |1010111| vsetvli
* 1 | 1| zimm[ 9:0] | uimm[4:0]| 1 1 1 | rd |1010111| vsetivli
* 1 | 000000 | rs2 | rs1 | 1 1 1 | rd |1010111| vsetvl
* 1 6 5 5 3 5 7
*
* 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) >> 7) {
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;
}

if ((insn & MASK_VSETVLI) == MATCH_VSETVLI) {
// vsetvli
ir->rd = (insn >> 7) & 0x1f;
ir->rs1 = (insn >> 15) & 0x1f;
ir->zimm = (insn >> 20) & 0x7ff;
} else if ((insn & MASK_VSETIVLI) == MATCH_VSETIVLI) {
// vsetivli
ir->rd = (insn >> 7) & 0x1f;
ir->uimm = (insn >> 15) & 0x1f;
ir->zimm = (insn >> 20) & 0x3ff; // zimm[9:0]

} else if ((insn & MASK_VSETVL) == MATCH_VSETVL) {
// vsetvl
ir->rd = (insn >> 7) & 0x1f;
ir->rs1 = (insn >> 15) & 0x1f;
ir->rs2 = (insn >> 20) & 0x1f;
}
}

/* handler for all unimplemented opcodes */
static inline bool op_unimp(rv_insn_t *ir UNUSED, uint32_t insn UNUSED)
{
Expand All @@ -1985,13 +2194,22 @@ bool rv_decode(rv_insn_t *ir, uint32_t insn)
{
assert(ir);

#if RV32_HAS(EXT_RVV)
#define MASK_OPCODE_RVV 0x57
#define MASK_OPCODE_RVV_VMEM 0x57
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
30 changes: 30 additions & 0 deletions src/decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,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 @@ -340,6 +364,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 @@ -361,6 +386,11 @@ typedef struct rv_insn {
uint8_t rm;
#endif

#if RV32_HAS(EXT_RVV)
uint8_t vm;
uint8_t zimm;
uint8_t uimm;
#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 @@ -401,6 +401,9 @@ static uint32_t peripheral_update_ctr = 64;
}

#include "rv32_template.c"
#if RV32_HAS(EXT_RVV)
#include "rv32_vector.c"
#endif
#undef RVOP

/* multiple LUI */
Expand Down
Loading
Loading