In the design of RISC-V FPGA, the core core module of RISC-V includes the instruction decoding module. The main function of this module is to parse the assembly machine code input by ITCM according to the current PC. Including getting the corresponding assembly language command, the required rs1, rs2 registers, the rd register that needs to be stored, etc.
Related reference articles:
RISC-V teaching plan
The structure of the cpu core design framework in RISC-V:
In the vivado project file:
The input of the instr_dec module is machine code in assembly language, and the output is:
RS1_IDX: general register rs1 ID
RS2_IDX: general register rs2 ID
RD_IDX: general register RD ID
instr_group: Include: OP_IMM, OP, LUI, AUIPC, JAL, JALR, BRANCH, LOAD, STORE, CSR, etc.
opimm_instr: Include: SRAI, SRLI, SLLI, ANDI, ORI, XORI, SLTIU, SLTI, ADDI
op_instr: includes: SRA, SUB, SRL, SLL, XOR, OR, AND, SLTU, SLT, ADD
branch_instr: includes: BGTU, BGT, BLTU, BLT, BNE, BEQ
shamt: data displacement width I_imm: I-type immediate data
S_imm: S-type immediate
J_imm: J-type immediate
U_imm: U-type immediate
B_imm: B-type immediate
load_instr: Include: LBU, LB, LHU, LH, LW
store_instr: includes: SB, SH, SW
csr_instr: includes: SCRRCI, CSRRSI, CSRRWI, SCRRC, CSRRS, CSRRW
csr_addr: select one of the 4095 csr registers CSR_imm: csr immediate
decoder module code:
module instr_dec ( input sys_clk, // system clock input [ 31: 0 ] i_instr, // assembly language machine code read from ITCM output RV32I, // decoded output in RV32I format. Currently, we do not support RV32C, RV64 etc. output [ 4: 0 ] o_rs1_idx, // one of the 32 general-purpose registers specified by rs1 in the assembly instruction output [ 4: 0 ] o_rs2_idx, // one of the 32 general-purpose registers specified by rs2 in the assembly instruction output [ 4: 0 ] o_rd_idx, // one of the 32 general-purpose registers specified by rd in the assembly instruction output [ 15: 0 ] o_instr_group, // instruction group, LOAD, STORE, CSR, BRANCH, OP, OP_imm, etc. Instruction grouping output [ 8: 0 ] o_opimm_instr, // each instruction in the opimm instruction, including: SRAI, SRLI, SLLI, ANDI, ORI, XORI, SLTIU, SLTI, ADDI output [ 9: 0 ] o_op_instr, // op Each of the instructions, including: SRA, SUB, SRL, SLL, XOR, OR, AND, SLTU, SLT, ADD output [ 5: 0 ] o_branch_instr, // each instruction in the branch instruction, including: BGTU, BGT, BLTU, BLT, BNE, BEQ output [ 4: 0 ] o_load_instr, // each instruction in the load instruction, including : LBU, LB, LHU, LH, LW output [ 2: 0 ] o_store_instr, // each instruction in the store instruction, including: SB, SH, SW output [ 1: 0 ] o_fence_instr, // each instruction in the fence instruction One instruction, including: fence, fence.i output [ 5: 0 ] o_csr_instr, // Each instruction in CSR instructions, including: SCRRCI, CSRRSI, CSRRWI, SCRRC, CSRRS, CSRRW output [11: 0 ] o_csr_addr, // Select one of the 4095 csr registers CSR_imm: csr immediate output [ 4: 0 ] o_shamt, // data shift width I_imm: I-type immediate output [ 31: 0 ] o_I_imm, // I-type immediate output [ 31: 0 ] o_S_imm, // R-type immediate output [ 31: 0 ] o_B_imm, // S-type immediate output output [ 31: 0 ] o_J_imm, // J-type immediate output [ 31: 0 ] o_U_imm, // U-type immediate output [ 31: 0 ] o_csr_imm, // CSR immediate //output [31:0] o_pc output o_mret, // interrupt return output o_ecall, // request execution environment by raising an environment call exception output o_ebreak, // debug interrupt breakpoint output o_dret, // debug interrupt return output o_wfi // wait for interrupt ); //== ===================================================== ============================ // riscv instruction basic decode OP DECODE wire [ 6: 0 ] opcode = i_instr[ 6: 0 ]; wire [ 2: 0 ] funct3 = i_instr[ 14: 12 ]; wire [ 6: 0 ] funct7 = i_instr[ 31: 25 ]; assign RV32I = ( opcode[ 1: 0 ] == 2'b11 ) && ( opcode[ 4: 2 ] != 3'b111 ); //register index decode assign o_rd_idx = i_instr[ 11: 7 ]; assign o_rs1_idx = i_instr [ 19: 15 ]; assign o_rs2_idx = i_instr[ 24: 20 ]; //================================== ================================================== // decode opcode [6:0] wire LUI = ( opcode[ 6: 0 ] == 7'b011_0111 ); // TYPE U lui wire AUIPC = ( opcode[ 6: 0 ] == 7'b001_0111 ); // TYPE U auipc wire JAL = ( opcode[ 6: 0 ] == 7'b110_1111 ); // TYPE J jal wire JALR = ( opcode[ 6: 0 ] == 7'b110_0111 ); // TYPE I jalr wire BRANCH = ( opcode[ 6: 0 ] == 7'b110_0011 ); // TYPE B wire LOAD = ( opcode[ 6: 0 ] == 7'b000_0011 ); // TYPE I load wire STORE = ( opcode[ 6: 0 ] == 7'b010_0011 ); // YTPE S store wire OP_IMM = ( opcode[ 6: 0 ] == 7'b001_0011 ); // TYPE I operator wire OP = ( opcode[ 6: 0 ] == 7'b011_0011 ); // TYPE R operator wire FENCE = ( opcode[ 6: 0 ] == 7'b000_1111 ); // TYPE I fence wire CSR = ( opcode[ 6: 0 ] == 7'b111_0011 ); // TYPE I csr assign o_instr_group = { FENCE, CSR, STORE, LOAD, BRANCH, JALR, JAL, AUIPC, LUI, OP, OP_IMM }; //========== ===================================================== ================= // funct3 decode wire funct3_0 = ( funct3 == 3'b000 ); wire funct3_1 = ( funct3 == 3'b001 ); wire funct3_2 = ( funct3 == 3'b010 ); wire funct3_3 = ( funct3 == 3'b011 ); wire funct3_4 = ( funct3 == 3'b100 ); wire funct3_5 = ( funct3 == 3'b101 ); wire funct3_6 = ( funct3 == 3'b110 ); wire funct3_7 = ( funct3 == 3'b111 ); // ===================================================== ============================ //funct7 decode wire funct7_0 = ( funct7 == 7'b0 ); wire funct7_20 = ( funct7 == 7'b010_0000 ); //========================================== ======================================= //imm & shamt decode assign o_I_imm = { { 20 { i_instr[ 31 ] } } , i_instr[ 31: 20 ] }; //addi/slti/sltiu/andi/ori/xori, lw/lh/lhu/lb/lbu, JALR, SLLI/SRLi/SRAI assign o_S_imm = { { 20{ i_instr[ 31 ] } }, i_instr[ 31: 25 ], i_instr[ 11: 7 ] }; //s-type instruction, provide imm or store instruction assign o_B_imm = { { 19{ i_instr[ 31 ] } }, i_instr[ 31 ], i_instr[ 7 ], i_instr[ 30: 25 ], i_instr[ 11: 8 ], 1'b0 }; assign o_U_imm = { i_instr[ 31 : 12 ], 12'b0 }; assign o_J_imm = { { 11{ i_instr[ 31 ] } }, i_instr[ 31 ], i_instr[ 19: 12 ], i_instr[ 20 ], i_instr[ 30: 21 ], 1'b0 }; //for JAL, assign o_shamt = i_instr[ 24: 20 ]; assign o_csr_imm = {27'b0,i_instr[19:15]}; //================ ===================================================== ============== // instruction decode for I-type operator 7'b001_0011 wire rv32i_addi = OP_IMM & funct3_0; wire rv32i_slti = OP_IMM & funct3_2; wire rv32i_sltiu = OP_IMM & funct3_3; wire rv32i_xori = OP_IMM & funct3_4; wire rv32i_ori = OP_IMM & funct3_6; wire rv32i_andi = OP_IMM & funct3_7; wire rv32i_slli = OP_IMM & funct3_1 ; wire rv32i_srli = OP_IMM & funct3_5 & funct7_0; wire rv32i_srai = OP_IMM & funct3_5 & funct7_20; assign o_opimm_instr = { rv32i_srai, rv32i_srli, rv32i_slli, rv32i_andi, rv32i_ori, rv32i_xori, rv32i_sltiu, rv32i_slti, rv32i_addi }; //============================================== ===================================== //instruction decode for R-type wire rv32i_add = OP & funct3_0 & funct7_0; wire rv32i_sub = OP & funct3_0 & funct7_20; wire rv32i_sll = OP & funct3_1 & funct7_0; wire rv32i_slt = OP & funct3_2 & funct7_0; wire rv32i_sltu = OP & funct3_3 & funct7_0; wire rv32i_xor = OP & funct3_4 & funct7_0; wire rv32i_srl = OP & funct3_5 & funct7_0; wire rv32i_sra = OP & funct3_5 & funct7_20; wire rv32i_or = OP & funct3_6 & funct7_0; wire rv32i_and = OP & funct3_7 & funct7_0; assign o_op_instr = { rv32i_sra, rv32i_sub, rv32i_srl,
rv32i_sll, rv32i_xor, rv32i_or,
rv32i_and, rv32i_sltu, rv32i_slt,
rv32i_add }; //============================ ===================================================== = //instruction for conditional branch wire rv32i_beq = BRANCH & funct3_0; wire rv32i_bne = BRANCH & funct3_1; wire rv32i_blt = BRANCH & funct3_4; wire rv32i_bltu = BRANCH & funct3_6; wire rv32i_bgt = BRANCH & funct3_5; wire rv32i_bgtu = BRANCH & funct3_7; assign o_branch_instr = { rv32i_bgtu, rv32i_bgt, rv32i_bltu, rv32i_blt, rv32i_bne, rv32i_beq }; //========================== ===================================================== ===== // memory operation load/store wire rv32i_lw = LOAD & funct3_2; wire rv32i_lh = LOAD & funct3_1; wire rv32i_lhu = LOAD & funct3_5; wire rv32i_lb = LOAD & funct3_0; wire rv32i_lbu = LOAD & funct3_4; wire rv32i_sw = STORE & funct3_2; wire rv32i_sh = STORE & funct3_1; wire rv32i_sb = STORE & funct3_0; assign o_load_instr = { rv32i_lbu, rv32i_lb, rv32i_lhu, rv32i_lh, rv32i_lw }; assign o_store_instr = { rv32i_sb, rv2 //==================================================== ============================== //instruction for fence wire rv32i_fence = FENCE & funct3_0; wire rv32i_fence_i = FENCE & funct3_1; assign o_fence_instr = {rv32i_fence_i, rv32i_fence }; //========================================== ========================================= //instruction for csr wire rv32i_csrrw = CSR & funct3_1; wire rv32i_csrrs = CSR & funct3_2; wire rv32i_csrrc = CSR & funct3_3; wire rv32i_csrrwi = CSR & funct3_5; wire rv32i_csrrsi = CSR & funct3_6; wire rv32i_csrrci = CSR & funct3_7; assign o_csr_instr = { rv32i_csrrci, rv32i_csrrsi, rv32i_csrrwi, rv32i_csrrc, rv32i_csrrs , rv32i_csrrw}; assign o_csr_addr = i_instr[ 31: 20 ]; //========================================== ========================================== // System Instructions assign o_ecall = CSR & funct3_0 & (i_instr[31:20] == 12'b0000_0000_0000); assign o_ebreak = CSR & funct3_0 & (i_instr[31:20] == 12'b0000_0000_0001); assign o_mret = CSR & funct3_0 & (i_instr[31:20] == 12'b0011_0000_0010); assign o_dret = CSR & funct3_0 & (i_instr[31:20] == 12'b0111_1011_0010); assign o_wfi = CSR & funct3_0 & (i_instr[31:20] == 12'b0001_0000_0101); endmodule
1) Find the lowest 7 bits of the assembly instruction machine code and
get the opcode :
wire[ 6: 0 ] opcode = i_instr[ 6: 0 ];
assign RV32I = ( opcode[ 1: 0 ] == 2'b11 ) && ( opcode[ 4: 2 ] != 3'b111 );
if opcode is lowest 2 bits are 11, and the lowest 5 bits cannot be 111111,
then the current instruction bit is the RV32i instruction.
wire LUI = ( opcode[ 6: 0 ] == 7’b011_0111 ); // TYPE U lui
wire AUIPC = ( opcode[ 6: 0 ] == 7’b001_0111 ); // TYPE U auipc
wire JAL = ( opcode[ 6: 0 ] == 7’b110_1111 ); // TYPE J jal
wire JALR = ( opcode[ 6: 0 ] == 7’b110_0111 ); // TYPE I jalr
wire BRANCH = ( opcode[ 6: 0 ] == 7’b110_0011 ); // TYPE B
wire LOAD = ( opcode[ 6: 0 ] == 7’b000_0011 ); // TYPE I load
wire STORE = ( opcode[ 6: 0 ] == 7’b010_0011 ); // YTPE S store
wire OP_IMM = ( opcode[ 6: 0 ] == 7’b001_0011 ); // TYPE I operator
wire OP = ( opcode[ 6: 0 ] == 7’b011_0011 ); // TYPE R operator
wire FENCE = ( opcode[ 6: 0 ] == 7’b000_1111 ); // TYPE I fence
wire CSR = ( opcode[ 6: 0 ] == 7’b111_0011 ); // TYPE I csr
If it is an RV32I instruction, first decode which class of instruction it is.
2) Decode funct3 and funct7. funct3 is mainly used to specify the specific
assembly instruction in the current class; funct7 is a supplement when
funct3 is not enough. Only 8 instructions can be specified.
wire [ 2: 0 ] funct3 = i_instr[ 14: 12 ];
wire [ 6: 0 ] funct7 = i_instr[ 31: 25 ];
assign o_rd_idx = i_instr[ 11: 7 ];
assign o_rs1_idx = i_instr[ 19: 15 ];
assign o_rs2_idx = i_instr[ 24: 20 ];
3) Splicing the immediate data in different instructions,
according to the assembly instructions, what the cpu does here is the
corresponding decoding
assign o_I_imm = { { 20{ i_instr[ 31 ] } } , i_instr[ 31: 20 ] }; //addi/slti/sltiu/andi/ori/xori, lw/lh/lhu/lb/lbu, JALR, SLLI/ SRLi/SRAI
assign o_S_imm = { { 20{ i_instr[ 31 ] } }, i_instr[ 31: 25 ], i_instr[ 11: 7 ] }; //s-type instruction, provide imm or store instruction
assign o_B_imm = { { 19{ i_instr[ 31 ] } }, i_instr[ 31 ], i_instr[ 7 ], i_instr[ 30: 25 ], i_instr[ 11: 8 ], 1’b0 };
assign o_U_imm = { i_instr[ 31: 12 ], 12’b0 };
assign o_J_imm = { { 11{ i_instr[ 31 ] } }, i_instr[ 31 ], i_instr[ 19: 12 ], i_instr[ 20 ], i_instr[ 30: 21 ], 1’b0 }; //for JAL,
assign o_shamt = i_instr[ 24: 20 ];
assign o_csr_imm = {27’b0,i_instr[19:15]};
4) Determine the final instruction :
According to the categories decoded by opcode, the specific instructions decoded by funct3 and funct7, and finally determine that the current machine code is the instruction in the instruction set.