Menu Close

RISC-V32个寄存器和译码模块(4)指令译码器

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

相关参考文章:

RISC-V 教学教案

 

RISC-V  中cpu 核心设计框架组成结构:  

fii_riscv_decorder

在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 模块代码:

module instr_dec
(
input sys_clk, // 系统时钟
input [ 31: 0 ] i_instr, // 从ITCM 中读取的汇编语言机器码

output RV32I, // 译码输出的RV32I 格式. 目前,我们不支持RV32C, RV64等

output [ 4: 0 ] o_rs1_idx, // 汇编指令中rs1 所指定的32个通用寄存器中的一个
output [ 4: 0 ] o_rs2_idx, // 汇编指令中rs2 所指定的32个通用寄存器中的一个
output [ 4: 0 ] o_rd_idx, // 汇编指令中rd 所指定的32个通用寄存器中的一个

output [ 15: 0 ] o_instr_group, // 指令组,将LOAD,STORE,CSR,BRANCH,OP,OP_imm 等等 指令分组

output [ 8: 0 ] o_opimm_instr, // opimm 指令中的每一条指令,包括:SRAI, SRLI, SLLI, ANDI, ORI, XORI, SLTIU, SLTI, ADDI
output [ 9: 0 ] o_op_instr, // op 指令中的每一条指令,包括:SRA, SUB, SRL, SLL, XOR, OR, AND, SLTU, SLT, ADD
output [ 5: 0 ] o_branch_instr, // branch 指令中的每一条指令,包括:BGTU, BGT, BLTU, BLT, BNE, BEQ
output [ 4: 0 ] o_load_instr, // load 指令中的每一条指令,包括:LBU, LB, LHU, LH, LW
output [ 2: 0 ] o_store_instr, // store 指令中的每一条指令,包括:SB, SH, SW
output [ 1: 0 ] o_fence_instr, // fence 指令中的每一条指令,包括:fence, fence.i

output [ 5: 0 ] o_csr_instr, // CSR 指令中的每一条指令,包括:SCRRCI, CSRRSI, CSRRWI, SCRRC, CSRRS, CSRRW
output [11: 0 ] o_csr_addr, // 选择4095 个csr 寄存器中的一个 CSR_imm: csr 立即数

output [ 4: 0 ] o_shamt, // 数据位移宽度 I_imm: I-type 立即数
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 [ 31: 0 ] o_J_imm, // J-type immediate
output [ 31: 0 ] o_U_imm, // U-type immediate
output [ 31: 0 ] o_csr_imm, // CSR 立即数
//output [31:0] o_pc
output o_mret, // 中断返回
output o_ecall, // 通过引发环境调用异常来请求执行环境
output o_ebreak, // 调试中断断点
output o_dret, // 调试中断 返回
output o_wfi // 等待中断

);

//===============================================================================
// 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, rv32i_sh, rv32i_sw };

//===============================================================================
//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)查找汇编指令机器码最低7位,得到opcode:
wire [ 6: 0 ] opcode = i_instr[ 6: 0 ];
assign RV32I = ( opcode[ 1: 0 ] == 2'b11 ) && ( opcode[ 4: 2 ] != 3'b111 );
如果opcode 最低2位为 11, 并且最低5位 不能是 111111 , 那么当前指令位RV32i 指令。

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 指令, 先译码出是哪一个类指令。


2)将funct3,funct7 译码出来, funct3 主要用来指定当前类中具体那一条汇编指令; funct7 是当funct3 不够用时的一种补充,比如:某一类指令中由9条指令,但funct3 最多只能指定8条指令。
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) 拼接 不同指令中的立即数, 根据汇编指令, 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 译码出来的具体指令, 最终确定当前的机器码是指令集当中的那一条指令。

Posted in FPGA, FPGA 教材教案, IC, RISC-V, RISC-V IPcore设计, RISC-V 教材教案, 教材与教案, 文章

发表回复

相关链接