RISC-V 的BRANCH 模块用来处理指令条件跳转部分。这个模块将之前ITCM读取的指令,译码模块分离出来的条件跳转信息进行处理。在处理过程中,包括对32个通用寄存器的赋值,对pc 指针的更改等等。
相关参考文章:
RISC-V 教学教案
RISC-V cpu 架构:

这个模块集中处理:
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 将不需要关心这个值;