RISC-V FPGA 设计中, RISC-V 的核心核心模块中包括指令译码模块。 这个模块的主要功能是:根据当前的PC,对ITCM 输入的汇编机器码进行解析。包括得到相应的汇编语言命令,需要的rs1,rs2寄存器,需要存储的rd 寄存器等
相关参考文章:
RISC-V 教学教案
RISC-V 中cpu 核心设计框架组成结构:

在vivado 工程文件中:
instr_dec 模块 输入为汇编语言的机器码, 输出为:
RS1_IDX: 通用寄存器rs1 ID
RS2_IDX: 通用寄存器rs2 ID
RD_IDX: 通用寄存器RD ID
instr_group: 包括:OP_IMM, OP, LUI, AUIPC, JAL, JALR, BRANCH, LOAD, STORE, CSR, 等等
opimm_instr: 包括:SRAI, SRLI, SLLI, ANDI, ORI, XORI, SLTIU, SLTI, ADDI
op_instr: 包括:SRA, SUB, SRL, SLL, XOR, OR, AND, SLTU, SLT, ADD
branch_instr: 包括:BGTU, BGT, BLTU, BLT, BNE, BEQ
shamt: 数据位移宽度 I_imm: I-type 立即数
S_imm: S-type 立即数
J_imm: J-type 立即数
U_imm: U-type 立即数
B_imm: B-type 立即数
load_instr: 包括:LBU, LB, LHU, LH, LW
store_instr: 包括:SB, SH, SW
csr_instr: 包括:SCRRCI, CSRRSI, CSRRWI, SCRRC, CSRRS, CSRRW
csr_addr: 选择4095 个csr 寄存器中的一个 CSR_imm: csr 立即数
decoder 模块代码:
|
1 |
module instr_dec<br />(<br />input sys_clk, // 系统时钟<br />input [ 31: 0 ] i_instr, // 从ITCM 中读取的汇编语言机器码<br /><br />output RV32I, // 译码输出的RV32I 格式. 目前,我们不支持RV32C, RV64等<br /><br />output [ 4: 0 ] o_rs1_idx, // 汇编指令中rs1 所指定的32个通用寄存器中的一个<br />output [ 4: 0 ] o_rs2_idx, // 汇编指令中rs2 所指定的32个通用寄存器中的一个<br />output [ 4: 0 ] o_rd_idx, // 汇编指令中rd 所指定的32个通用寄存器中的一个<br /><br />output [ 15: 0 ] o_instr_group, // 指令组,将LOAD,STORE,CSR,BRANCH,OP,OP_imm 等等 指令分组<br /><br />output [ 8: 0 ] o_opimm_instr, // opimm 指令中的每一条指令,包括:SRAI, SRLI, SLLI, ANDI, ORI, XORI, SLTIU, SLTI, ADDI<br />output [ 9: 0 ] o_op_instr, // op 指令中的每一条指令,包括:SRA, SUB, SRL, SLL, XOR, OR, AND, SLTU, SLT, ADD<br />output [ 5: 0 ] o_branch_instr, // branch 指令中的每一条指令,包括:BGTU, BGT, BLTU, BLT, BNE, BEQ<br />output [ 4: 0 ] o_load_instr, // load 指令中的每一条指令,包括:LBU, LB, LHU, LH, LW<br />output [ 2: 0 ] o_store_instr, // store 指令中的每一条指令,包括:SB, SH, SW<br />output [ 1: 0 ] o_fence_instr, // fence 指令中的每一条指令,包括:fence, fence.i<br /><br />output [ 5: 0 ] o_csr_instr, // CSR 指令中的每一条指令,包括:SCRRCI, CSRRSI, CSRRWI, SCRRC, CSRRS, CSRRW<br />output [11: 0 ] o_csr_addr, // 选择4095 个csr 寄存器中的一个 CSR_imm: csr 立即数<br /><br />output [ 4: 0 ] o_shamt, // 数据位移宽度 I_imm: I-type 立即数<br />output [ 31: 0 ] o_I_imm, // I-type immediate<br />output [ 31: 0 ] o_S_imm, // R-type immediate<br />output [ 31: 0 ] o_B_imm, // S-type immediate<br />output [ 31: 0 ] o_J_imm, // J-type immediate<br />output [ 31: 0 ] o_U_imm, // U-type immediate<br />output [ 31: 0 ] o_csr_imm, // CSR 立即数<br />//output [31:0] o_pc<br />output o_mret, // 中断返回<br />output o_ecall, // 通过引发环境调用异常来请求执行环境<br />output o_ebreak, // 调试中断断点<br />output o_dret, // 调试中断 返回<br />output o_wfi // 等待中断<br /><br />);<br /><br />//===============================================================================<br />// riscv instruction basic decode OP DECODE <br />wire [ 6: 0 ] opcode = i_instr[ 6: 0 ];<br />wire [ 2: 0 ] funct3 = i_instr[ 14: 12 ];<br />wire [ 6: 0 ] funct7 = i_instr[ 31: 25 ];<br /><br />assign RV32I = ( opcode[ 1: 0 ] == 2'b11 ) && ( opcode[ 4: 2 ] != 3'b111 );<br /><br />//register index decode<br />assign o_rd_idx = i_instr[ 11: 7 ];<br />assign o_rs1_idx = i_instr[ 19: 15 ];<br />assign o_rs2_idx = i_instr[ 24: 20 ];<br />//===============================================================================<br />// decode opcode [6:0]<br />wire LUI = ( opcode[ 6: 0 ] == 7'b011_0111 ); // TYPE U lui<br />wire AUIPC = ( opcode[ 6: 0 ] == 7'b001_0111 ); // TYPE U auipc<br /><br />wire JAL = ( opcode[ 6: 0 ] == 7'b110_1111 ); // TYPE J jal<br />wire JALR = ( opcode[ 6: 0 ] == 7'b110_0111 ); // TYPE I jalr<br /><br />wire BRANCH = ( opcode[ 6: 0 ] == 7'b110_0011 ); // TYPE B<br /><br />wire LOAD = ( opcode[ 6: 0 ] == 7'b000_0011 ); // TYPE I load<br />wire STORE = ( opcode[ 6: 0 ] == 7'b010_0011 ); // YTPE S store<br /><br />wire OP_IMM = ( opcode[ 6: 0 ] == 7'b001_0011 ); // TYPE I operator<br />wire OP = ( opcode[ 6: 0 ] == 7'b011_0011 ); // TYPE R operator<br /><br />wire FENCE = ( opcode[ 6: 0 ] == 7'b000_1111 ); // TYPE I fence<br />wire CSR = ( opcode[ 6: 0 ] == 7'b111_0011 ); // TYPE I csr<br /><br /><br /><br /><br />assign o_instr_group = { FENCE, CSR, STORE, LOAD, BRANCH, JALR, JAL, AUIPC, LUI, OP, OP_IMM };<br /><br />//===============================================================================<br />// funct3 decode<br />wire funct3_0 = ( funct3 == 3'b000 );<br />wire funct3_1 = ( funct3 == 3'b001 );<br />wire funct3_2 = ( funct3 == 3'b010 );<br />wire funct3_3 = ( funct3 == 3'b011 );<br />wire funct3_4 = ( funct3 == 3'b100 );<br />wire funct3_5 = ( funct3 == 3'b101 );<br />wire funct3_6 = ( funct3 == 3'b110 );<br />wire funct3_7 = ( funct3 == 3'b111 );<br />//===============================================================================<br />//funct7 decode<br />wire funct7_0 = ( funct7 == 7'b0 );<br />wire funct7_20 = ( funct7 == 7'b010_0000 );<br />//===============================================================================<br />//imm & shamt decode<br /><br />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<br /><br />assign o_S_imm = { { 20{ i_instr[ 31 ] } }, i_instr[ 31: 25 ], i_instr[ 11: 7 ] }; //s-type instruction, provide imm or store instruction<br /><br />assign o_B_imm = { { 19{ i_instr[ 31 ] } }, i_instr[ 31 ], i_instr[ 7 ], i_instr[ 30: 25 ], i_instr[ 11: 8 ], 1'b0 };<br /><br />assign o_U_imm = { i_instr[ 31: 12 ], 12'b0 };<br /><br />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,<br /><br />assign o_shamt = i_instr[ 24: 20 ];<br /><br />assign o_csr_imm = {27'b0,i_instr[19:15]};<br /><br />//===============================================================================<br />// instruction decode for I-type operator 7'b001_0011<br />wire rv32i_addi = OP_IMM & funct3_0;<br />wire rv32i_slti = OP_IMM & funct3_2;<br />wire rv32i_sltiu = OP_IMM & funct3_3;<br />wire rv32i_xori = OP_IMM & funct3_4;<br />wire rv32i_ori = OP_IMM & funct3_6;<br />wire rv32i_andi = OP_IMM & funct3_7;<br /><br />wire rv32i_slli = OP_IMM & funct3_1 ;<br />wire rv32i_srli = OP_IMM & funct3_5 & funct7_0;<br />wire rv32i_srai = OP_IMM & funct3_5 & funct7_20;<br /><br />assign o_opimm_instr = { rv32i_srai, rv32i_srli, rv32i_slli,<br />rv32i_andi, rv32i_ori, rv32i_xori,<br />rv32i_sltiu, rv32i_slti, rv32i_addi };<br /><br />//===============================================================================<br />//instruction decode for R-type<br /><br />wire rv32i_add = OP & funct3_0 & funct7_0;<br />wire rv32i_sub = OP & funct3_0 & funct7_20;<br /><br />wire rv32i_sll = OP & funct3_1 & funct7_0;<br /><br />wire rv32i_slt = OP & funct3_2 & funct7_0;<br />wire rv32i_sltu = OP & funct3_3 & funct7_0;<br />wire rv32i_xor = OP & funct3_4 & funct7_0;<br /><br />wire rv32i_srl = OP & funct3_5 & funct7_0;<br />wire rv32i_sra = OP & funct3_5 & funct7_20;<br /><br />wire rv32i_or = OP & funct3_6 & funct7_0;<br />wire rv32i_and = OP & funct3_7 & funct7_0;<br /><br />assign o_op_instr = { rv32i_sra, rv32i_sub, rv32i_srl,<br />rv32i_sll, rv32i_xor, rv32i_or,<br />rv32i_and, rv32i_sltu, rv32i_slt,<br />rv32i_add };<br />//===============================================================================<br />//instruction for conditional branch<br />wire rv32i_beq = BRANCH & funct3_0;<br />wire rv32i_bne = BRANCH & funct3_1;<br />wire rv32i_blt = BRANCH & funct3_4;<br />wire rv32i_bltu = BRANCH & funct3_6;<br />wire rv32i_bgt = BRANCH & funct3_5;<br />wire rv32i_bgtu = BRANCH & funct3_7;<br /><br />assign o_branch_instr = { rv32i_bgtu, rv32i_bgt, rv32i_bltu,<br />rv32i_blt, rv32i_bne, rv32i_beq };<br /><br />//===============================================================================<br />// memory operation load/store<br />wire rv32i_lw = LOAD & funct3_2;<br />wire rv32i_lh = LOAD & funct3_1;<br />wire rv32i_lhu = LOAD & funct3_5;<br />wire rv32i_lb = LOAD & funct3_0;<br />wire rv32i_lbu = LOAD & funct3_4;<br /><br />wire rv32i_sw = STORE & funct3_2;<br />wire rv32i_sh = STORE & funct3_1;<br />wire rv32i_sb = STORE & funct3_0;<br /><br /><br />assign o_load_instr = { rv32i_lbu, rv32i_lb, rv32i_lhu, rv32i_lh, rv32i_lw };<br />assign o_store_instr = { rv32i_sb, rv32i_sh, rv32i_sw };<br /><br />//===============================================================================<br />//instruction for fence<br />wire rv32i_fence = FENCE & funct3_0;<br />wire rv32i_fence_i = FENCE & funct3_1;<br /><br />assign o_fence_instr = {rv32i_fence_i, rv32i_fence };<br /><br />//===============================================================================<br />//instruction for csr<br /><br />wire rv32i_csrrw = CSR & funct3_1;<br />wire rv32i_csrrs = CSR & funct3_2;<br />wire rv32i_csrrc = CSR & funct3_3;<br />wire rv32i_csrrwi = CSR & funct3_5;<br />wire rv32i_csrrsi = CSR & funct3_6;<br />wire rv32i_csrrci = CSR & funct3_7;<br /><br />assign o_csr_instr = { rv32i_csrrci, rv32i_csrrsi, rv32i_csrrwi, <br />rv32i_csrrc, rv32i_csrrs, rv32i_csrrw};<br /><br /><br />assign o_csr_addr = i_instr[ 31: 20 ];<br />//===============================================================================<br />// System Instructions<br />assign o_ecall = CSR & funct3_0 & (i_instr[31:20] == 12'b0000_0000_0000);<br />assign o_ebreak = CSR & funct3_0 & (i_instr[31:20] == 12'b0000_0000_0001);<br />assign o_mret = CSR & funct3_0 & (i_instr[31:20] == 12'b0011_0000_0010);<br />assign o_dret = CSR & funct3_0 & (i_instr[31:20] == 12'b0111_1011_0010);<br />assign o_wfi = CSR & funct3_0 & (i_instr[31:20] == 12'b0001_0000_0101);<br /><br /><br />endmodule |
|
1 |
|
1 |
|
1 |
1)查找汇编指令机器码最低7位,<strong>得到opcode</strong>:<br /><span style="color: #0000ff;">wire [ 6: 0 ] opcode = i_instr[ 6: 0 ];</span> <br /><span style="color: #0000ff;">assign RV32I = ( opcode[ 1: 0 ] == 2'b11 ) && ( opcode[ 4: 2 ] != 3'b111 );<br /></span>如果opcode 最低2位为 11, 并且最低5位 不能是 111111 , 那么当前指令位RV32i 指令。<br /><br /> |
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
如果是RV32I 指令, 先译码出是哪一个类指令。
|
1 |
<br />2)<strong>将funct3,funct7 译码出来</strong>, funct3 主要用来指定当前类中具体那一条汇编指令; funct7 是当funct3 不够用时的一种补充,比如:某一类指令中由9条指令,但funct3 最多只能指定8条指令。 <br />wire [ 2: 0 ] funct3 = i_instr[ 14: 12 ]; <br />wire [ 6: 0 ] funct7 = i_instr[ 31: 25 ]; <br /><br />assign o_rd_idx = i_instr[ 11: 7 ]; <br />assign o_rs1_idx = i_instr[ 19: 15 ]; <br />assign o_rs2_idx = i_instr[ 24: 20 ];<br /><br />3) <strong>拼接 不同指令中的立即数</strong>, 根据汇编指令, cpu 这里做的是相对应的解码 |
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)确定最终指令: 根据opcode 译码出来的大类, funct3,funct7 译码出来的具体指令, 最终确定当前的机器码是指令集当中的那一条指令。
