The BRANCH module of RISC-V is used to handle the conditional jump part of the instruction. This module processes the instructions read by ITCM and the conditional jump information separated by the decoding module. During processing, including assignments to 32 general-purpose registers, changes to the pc pointer, and so on.
Related reference articles:
RISC-V teaching plan
RISC-V cpu architecture:
This module centrally handles:
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)
These six instructions, the compiler in the assembly language adds related pseudo-instructions on the basis of the six instructions, which is convenient for the user to write the assembly language. The final machine code is still only these 6 instructions.
Related articles can refer to: RISC-V Instruction Set Manual
branch module code:
module exu_BRANCH ( input sys_clk, // system clock input rst_n, input i_EXE_vld, // execute enable input i_BRANCH, // branch instruction group provided by decoding module input [ 5: 0 ] i_branch_instr, // specific branch instructions, including {rv32i_bgeu,rv32i_bge,rv32i_bltu,rv32i_blt,rv32i_bne,rv32i_beq}; input [ 31: 0 ] i_rs1_val, // rs1 general purpose register input [ 31: 0 ] i_rs2_val, // rs2 general purpose register input [ 31: 0 ] i_PC, // current command pc input [ 31: 0 ] i_B_imm, // b-type immediate output reg o_B_vld, // jump pc is valid branch valid output [ 31: 0 ] o_PC // pc value ready to jump ) ; 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
Module port:
input sys_clk , // system clock
input rst_n ,
input i_EXE_vld , // execute enable
input i_BRANCH , // branch instruction group input provided by decoding module
[ 5: 0 ] i_branch_instr , // specific branch instructions, including {rv32i_bgeu,rv32i_bge,rv32i_bltu,rv32i_blt,rv32i_bne,rv32i_beq};
input [ 31: 0 ] i_rs1_val , // rs1 general purpose register
input [ 31: 0 ] i_rs2_val , // rs2 general purpose register
input [ 31: 0 ] i_PC , // current command pc
input [ 31: 0 ] i_B_imm , // b-type immediate data
output reg o_B_vld , // jump pc valid branch valid
output [ 31: 0 ] o_PC // pc value ready to jump
Operands 1, 2 expansion:
// 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};
The bge and blt instructions require sign extension, and other instructions do not.
Negative operation:
wire [ 33: 0 ] comp_ext_op2 = ~ext_op2 + 1;
Equivalent to comp_ext_op2 = -ext_op2;
Subtraction operation:
wire [ 33: 0 ] op_sub = ext_op1 + comp_ext_op2; //ext_op1 – ext_op2;
XOR, OR operation:
wire [ 31: 0 ] op_xor = op1 ^ op2;
wire bit_or = |op_xor;
These two operations finally achieve the operation of op1 == op2 ; op1 != op2 . When bit_or == 1’b1, op1 is not equal to op2; when bit_or == 1’b0, op1 is equal to op2
New pc value ready to jump:
assign o_PC = i_PC + i_B_imm;
Need to cooperate with o_B_vld signal, if o_B_vld == 1, o_PC is a valid jump pc; if o_B_vld == 0, o_PC cpu will not need to care about this value;