Menu Close

RISC-V ALU and Branch Module(2)Branch Module

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:

fii_riscv_branch

 

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;

 

Posted in FPGA, RISC-V, RISC-V Textbook, Textbook and Training Project

Related Articles

Leave a Reply

Your email address will not be published.

Leave the field below empty!