Menu Close

RISC-V ALU模块和branch(2)branch模块

RISC-V 的BRANCH 模块用来处理指令条件跳转部分。这个模块将之前ITCM读取的指令,译码模块分离出来的条件跳转信息进行处理。在处理过程中,包括读取32个通用寄存器的值,对pc 指针的更改等等。

相关参考文章:

RISC-V 教学教案

 

RISC-V cpu 架构:

%title插图%num

%title插图%num

 

这个模块集中处理:

BEQ:    if (rs1 == rs2) pc += sext(offset)

BGE:    if (rs1 ≥s rs2) pc += sext(offset)

BGEU: if (rs1 ≥u rs2) pc += sext(offset)

BLT:     if (rs1 <s rs2) pc += sext(offset)

BLTU:  if (rs1 <u rs2) pc += sext(offset)

BNE:    if (rs1 ≠ rs2) pc += sext(offset)

汇编语言中的编译器在这6条指令的基础上,又增加了相关的 伪指令, 方便用户编写汇编语言。 最后形成的机器码依然只有这6条指令。

相关的文章可以参考:RISC-V 伪指令查找表

 

branch 模块代码:

module exu_BRANCH
(
    input sys_clk,                 // 系统时钟
    input rst_n,

    input i_EXE_vld,               // 执行enable
    input i_BRANCH,                // 译码模块提供的 branch 指令组
    input [ 5: 0 ] i_branch_instr, // 具体branch 指令,包括{rv32i_bgeu,rv32i_bge,rv32i_bltu,rv32i_blt,rv32i_bne,rv32i_beq};

    input [ 31: 0 ] i_rs1_val,     // rs1 通用寄存器
    input [ 31: 0 ] i_rs2_val,     // rs2 通用寄存器

    input [ 31: 0 ] i_PC,          // 当前指令pc
    input [ 31: 0 ] i_B_imm,       // b-type 立即数

    output reg o_B_vld,            // 跳转 pc 有效 branch valid
    output [ 31: 0 ] o_PC          // 准备跳转的pc 值

) ;

wire [ 31: 0 ] op1 = i_rs1_val;
wire [ 31: 0 ] op2 = i_rs2_val;

wire [ 31: 0 ] op_xor = op1 ^ op2;
wire bit_or = |op_xor;

//                         bge               blt
wire [ 33: 0 ] ext_op1 = ({i_branch_instr[4],i_branch_instr[2]} != 0 ) ? {op1[31],op1[31],op1} : {1'b0,1'b0,op1};
//                         bge               blt
wire [ 33: 0 ] ext_op2 = ({i_branch_instr[4],i_branch_instr[2]} != 0 ) ? {op2[31],op2[31],op2} : {1'b0,1'b0,op2};
wire [ 33: 0 ] comp_ext_op2 = ~ext_op2 + 1;

wire [ 33: 0 ] op_sub = ext_op1 + comp_ext_op2; //ext_op1 - ext_op2;

assign o_PC = i_PC + i_B_imm;

//assign o_branch_instr = { rv32i_bgtu, rv32i_bgt, rv32i_bltu, rv32i_blt, rv32i_bne, rv32i_beq };
always @( * )
begin
    o_B_vld <= 1'b0;

    if ( i_EXE_vld & i_BRANCH )
    begin
        case ( i_branch_instr )
        6'b00_0001:
        begin //eq
            if ( !bit_or )
                o_B_vld <= 1'b1;
        end
        6'b00_0010:
        begin //bne
            if ( bit_or )
                o_B_vld <= 1'b1;
        end
        6'b00_0100:
        begin //blt
            if ( op_sub[ 33 ] )
                o_B_vld <= 1'b1;
        end
        6'b00_1000:
        begin //bltu
            if ( op_sub[ 33 ] )
                o_B_vld <= 1'b1;
        end
        6'b01_0000:
        begin //bge
            if ( !op_sub[ 33 ] )
                o_B_vld <= 1'b1;
        end
        6'b10_0000:
        begin //bgeu
            if ( !op_sub[ 33 ] )
                o_B_vld <= 1'b1;
        end
        default: ;
        endcase
    end
end

endmodule

模块端口:

input sys_clk,                             // 系统时钟
input rst_n,

input i_EXE_vld,                      // 执行enable
input i_BRANCH,                     // 译码模块提供的 branch 指令组
input [ 5: 0 ] i_branch_instr, // 具体branch 指令,包括{rv32i_bgeu,rv32i_bge,rv32i_bltu,rv32i_blt,rv32i_bne,rv32i_beq};

input [ 31: 0 ] i_rs1_val,          // rs1 通用寄存器
input [ 31: 0 ] i_rs2_val,          // rs2 通用寄存器

input [ 31: 0 ] i_PC,                   // 当前指令pc
input [ 31: 0 ] i_B_imm,          // b-type 立即数

output reg o_B_vld,                  // 跳转 pc 有效 branch valid
output [ 31: 0 ] o_PC                 // 准备跳转的pc 值

 

操作数1,2 扩展:

//                                           bge                             blt
wire [ 33: 0 ] ext_op1 = ({i_branch_instr[4],i_branch_instr[2]} != 0 ) ? {op1[31],op1[31],op1} : {1’b0,1’b0,op1};
//                                           bge                             blt
wire [ 33: 0 ] ext_op2 = ({i_branch_instr[4],i_branch_instr[2]} != 0 ) ? {op2[31],op2[31],op2} : {1’b0,1’b0,op2};

bge, blt 指令需要进行符号扩展, 其他指令不需要。

负数操作:

wire [ 33: 0 ] comp_ext_op2 = ~ext_op2 + 1;

相当于 comp_ext_op2 = -ext_op2;

减法操作:

wire [ 33: 0 ] op_sub = ext_op1 + comp_ext_op2; //ext_op1 – ext_op2;

异或, 或 操作:

wire [ 31: 0 ] op_xor = op1 ^ op2;
wire bit_or = |op_xor;

这两个操作 最终可实现 op1 == op2 ;   op1 != op2 的操作。 当bit_or == 1’b1 时  op1 不等于 op2;  当 bit_or == 1’b0 时 op1 等于 op2

准备跳转的新pc 值:

assign o_PC = i_PC + i_B_imm;

需要配合o_B_vld 信号, 如果 o_B_vld == 1,  o_PC  是有效的跳转pc ; 如果 o_B_vld == 0,  o_PC   cpu 将不需要关心这个值;

 

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

发表评论

相关链接