[rtl] Extend BT ALU to be used for all jumps

- Create separate operand muxes for the branch/jump target ALU
- Complete jump instructions in one cycle when BT ALU configured

Signed-off-by: Tom Roberts <tomroberts@lowrisc.org>
This commit is contained in:
Tom Roberts 2020-03-24 13:42:19 +00:00 committed by Tom Roberts
parent e70213d0ef
commit 624ef41462
6 changed files with 146 additions and 84 deletions

View file

@ -133,7 +133,7 @@ module ibex_core #(
logic [31:0] lsu_addr_last;
// Jump and branch target and decision (EX->IF)
logic [31:0] jump_target_ex;
logic [31:0] branch_target_ex;
logic branch_decision;
// Core busy signals
@ -166,8 +166,8 @@ module ibex_core #(
logic [31:0] alu_operand_a_ex;
logic [31:0] alu_operand_b_ex;
jt_mux_sel_e jt_mux_sel_ex;
logic [11:0] bt_operand_imm_ex;
logic [31:0] bt_a_operand;
logic [31:0] bt_b_operand;
logic [31:0] alu_adder_result_ex; // Used to forward computed address to LSU
logic [31:0] result_ex;
@ -386,8 +386,8 @@ module ibex_core #(
.icache_enable_i ( icache_enable ),
.icache_inval_i ( icache_inval ),
// jump targets
.jump_target_ex_i ( jump_target_ex ),
// branch targets
.branch_target_ex_i ( branch_target_ex ),
// CSRs
.csr_mepc_i ( csr_mepc ), // exception return address
@ -463,8 +463,8 @@ module ibex_core #(
.alu_operand_a_ex_o ( alu_operand_a_ex ),
.alu_operand_b_ex_o ( alu_operand_b_ex ),
.jt_mux_sel_ex_o ( jt_mux_sel_ex ),
.bt_operand_imm_o ( bt_operand_imm_ex ),
.bt_a_operand_o ( bt_a_operand ),
.bt_b_operand_o ( bt_b_operand ),
.mult_en_ex_o ( mult_en_ex ),
.div_en_ex_o ( div_en_ex ),
@ -571,9 +571,8 @@ module ibex_core #(
.alu_operand_b_i ( alu_operand_b_ex ),
// Branch target ALU signal from ID stage
.jt_mux_sel_i ( jt_mux_sel_ex ),
.bt_operand_imm_i ( bt_operand_imm_ex ),
.pc_id_i ( pc_id ),
.bt_a_operand_i ( bt_a_operand ),
.bt_b_operand_i ( bt_b_operand ),
// Multipler/Divider signal from ID stage
.multdiv_operator_i ( multdiv_operator_ex ),
@ -589,7 +588,7 @@ module ibex_core #(
.alu_adder_result_ex_o ( alu_adder_result_ex ), // to LSU
.result_ex_o ( result_ex ), // to ID
.jump_target_o ( jump_target_ex ), // to IF
.branch_target_o ( branch_target_ex ), // to IF
.branch_decision_o ( branch_decision ), // to ID
.ex_valid_o ( ex_valid )

View file

@ -47,7 +47,8 @@ module ibex_decoder #(
// immediates
output ibex_pkg::imm_a_sel_e imm_a_mux_sel_o, // immediate selection for operand a
output ibex_pkg::imm_b_sel_e imm_b_mux_sel_o, // immediate selection for operand b
output ibex_pkg::jt_mux_sel_e jt_mux_sel_o, // jump target selection
output ibex_pkg::op_a_sel_e bt_a_mux_sel_o, // branch target selection operand a
output ibex_pkg::imm_b_sel_e bt_b_mux_sel_o, // branch target selection operand b
output logic [31:0] imm_i_type_o,
output logic [31:0] imm_s_type_o,
output logic [31:0] imm_b_type_o,
@ -212,8 +213,8 @@ module ibex_decoder #(
jump_in_dec_o = 1'b1;
if (instr_first_cycle_i) begin
// Calculate jump target
rf_we = 1'b0;
// Calculate jump target (and store PC + 4 if BranchTargetALU is configured)
rf_we = BranchTargetALU;
jump_set_o = 1'b1;
end else begin
// Calculate and store PC+4
@ -225,8 +226,8 @@ module ibex_decoder #(
jump_in_dec_o = 1'b1;
if (instr_first_cycle_i) begin
// Calculate jump target
rf_we = 1'b0;
// Calculate jump target (and store PC + 4 if BranchTargetALU is configured)
rf_we = BranchTargetALU;
jump_set_o = 1'b1;
end else begin
// Calculate and store PC+4
@ -548,7 +549,8 @@ module ibex_decoder #(
imm_a_mux_sel_o = IMM_A_ZERO;
imm_b_mux_sel_o = IMM_B_I;
jt_mux_sel_o = JT_ALU;
bt_a_mux_sel_o = OP_A_CURRPC;
bt_b_mux_sel_o = IMM_B_I;
multdiv_sel_o = 1'b0;
@ -562,10 +564,12 @@ module ibex_decoder #(
OPCODE_JAL: begin // Jump and Link
if (BranchTargetALU) begin
jt_mux_sel_o = JT_ALU;
bt_a_mux_sel_o = OP_A_CURRPC;
bt_b_mux_sel_o = IMM_B_J;
end
if (instr_first_cycle_i) begin
// Jumps take two cycles without the BTALU
if (instr_first_cycle_i && !BranchTargetALU) begin
// Calculate jump target
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
@ -582,10 +586,12 @@ module ibex_decoder #(
OPCODE_JALR: begin // Jump and Link Register
if (BranchTargetALU) begin
jt_mux_sel_o = JT_ALU;
bt_a_mux_sel_o = OP_A_REG_A;
bt_b_mux_sel_o = IMM_B_I;
end
if (instr_first_cycle_i) begin
// Jumps take two cycles without the BTALU
if (instr_first_cycle_i && !BranchTargetALU) begin
// Calculate jump target
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_IMM;
@ -617,7 +623,8 @@ module ibex_decoder #(
// target ALU calculates the target (which is controlled in a seperate block below)
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_REG_B;
jt_mux_sel_o = JT_BT_ALU;
bt_a_mux_sel_o = OP_A_CURRPC;
bt_b_mux_sel_o = IMM_B_B;
end else begin
// Without branch target ALU, a branch is a two-stage operation using the Main ALU in both
// stages
@ -757,10 +764,15 @@ module ibex_decoder #(
alu_op_b_mux_sel_o = OP_B_IMM;
end
3'b001: begin
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_INCR_PC;
alu_operator_o = ALU_ADD;
if (BranchTargetALU) begin
bt_a_mux_sel_o = OP_A_CURRPC;
bt_b_mux_sel_o = IMM_B_INCR_PC;
end else begin
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_INCR_PC;
alu_operator_o = ALU_ADD;
end
end
default: ;
endcase

View file

@ -23,9 +23,8 @@ module ibex_ex_block #(
// Branch Target ALU
// All of these signals are unusued when BranchTargetALU == 0
input ibex_pkg::jt_mux_sel_e jt_mux_sel_i,
input logic [11:0] bt_operand_imm_i,
input logic [31:0] pc_id_i,
input logic [31:0] bt_a_operand_i,
input logic [31:0] bt_b_operand_i,
// Multiplier/Divider
input ibex_pkg::md_op_e multdiv_operator_i,
@ -40,7 +39,7 @@ module ibex_ex_block #(
// Outputs
output logic [31:0] alu_adder_result_ex_o, // to LSU
output logic [31:0] result_ex_o,
output logic [31:0] jump_target_o, // to IF
output logic [31:0] branch_target_o, // to IF
output logic branch_decision_o, // to ID
output logic ex_valid_o // EX has valid output
@ -74,21 +73,20 @@ module ibex_ex_block #(
if (BranchTargetALU) begin : g_branch_target_alu
logic [32:0] bt_alu_result;
logic unused_bt_carry;
assign bt_alu_result = {{19{bt_operand_imm_i[11]}}, bt_operand_imm_i, 1'b0} + pc_id_i;
assign bt_alu_result = bt_a_operand_i + bt_b_operand_i;
assign jump_target_o = (jt_mux_sel_i == JT_ALU) ? alu_adder_result_ex_o : bt_alu_result[31:0];
assign unused_bt_carry = bt_alu_result[32];
assign branch_target_o = bt_alu_result[31:0];
end else begin : g_no_branch_target_alu
// Unused jt_mux_sel_i/bt_operand_imm_i/pc_id_i signals causes lint errors, this avoids them
ibex_pkg::jt_mux_sel_e unused_jt_mux_sel;
logic [11:0] unused_bt_operand_imm;
logic [31:0] unused_pc_id;
// Unused bt_operand signals cause lint errors, this avoids them
logic [31:0] unused_bt_a_operand, unused_bt_b_operand;
assign unused_jt_mux_sel = jt_mux_sel_i;
assign unused_bt_operand_imm = bt_operand_imm_i;
assign unused_pc_id = pc_id_i;
assign unused_bt_a_operand = bt_a_operand_i;
assign unused_bt_b_operand = bt_b_operand_i;
assign jump_target_o = alu_adder_result_ex_o;
assign branch_target_o = alu_adder_result_ex_o;
end
/////////

View file

@ -67,8 +67,8 @@ module ibex_id_stage #(
output logic [31:0] alu_operand_b_ex_o,
// Branch target ALU
output ibex_pkg::jt_mux_sel_e jt_mux_sel_ex_o,
output logic [11:0] bt_operand_imm_o,
output logic [31:0] bt_a_operand_o,
output logic [31:0] bt_b_operand_o,
// MUL, DIV
output logic mult_en_ex_o,
@ -224,6 +224,9 @@ module ibex_id_stage #(
op_a_sel_e alu_op_a_mux_sel, alu_op_a_mux_sel_dec;
op_b_sel_e alu_op_b_mux_sel, alu_op_b_mux_sel_dec;
op_a_sel_e bt_a_mux_sel;
imm_b_sel_e bt_b_mux_sel;
imm_a_sel_e imm_a_mux_sel;
imm_b_sel_e imm_b_mux_sel, imm_b_mux_sel_dec;
@ -258,13 +261,13 @@ module ibex_id_stage #(
assign imm_b_mux_sel = lsu_addr_incr_req_i ? IMM_B_INCR_ADDR : imm_b_mux_sel_dec;
///////////////////
// Operand A MUX //
// Operand MUXES //
///////////////////
// Immediate MUX for Operand A
// Main ALU immediate MUX for Operand A
assign imm_a = (imm_a_mux_sel == IMM_A_Z) ? zimm_rs1_type : '0;
// ALU MUX for Operand A
// Main ALU MUX for Operand A
always_comb begin : alu_operand_a_mux
unique case (alu_op_a_mux_sel)
OP_A_REG_A: alu_operand_a = rf_rdata_a_fwd;
@ -275,22 +278,60 @@ module ibex_id_stage #(
endcase
end
///////////////////
// Operand B MUX //
///////////////////
if (BranchTargetALU) begin : g_btalu_muxes
// Branch target ALU operand A mux
always_comb begin : bt_operand_a_mux
unique case (bt_a_mux_sel)
OP_A_REG_A: bt_a_operand_o = rf_rdata_a_fwd;
OP_A_CURRPC: bt_a_operand_o = pc_id_i;
default: bt_a_operand_o = pc_id_i;
endcase
end
// Immediate MUX for Operand B
always_comb begin : immediate_b_mux
unique case (imm_b_mux_sel)
IMM_B_I: imm_b = imm_i_type;
IMM_B_S: imm_b = imm_s_type;
IMM_B_B: imm_b = imm_b_type;
IMM_B_U: imm_b = imm_u_type;
IMM_B_J: imm_b = imm_j_type;
IMM_B_INCR_PC: imm_b = instr_is_compressed_i ? 32'h2 : 32'h4;
IMM_B_INCR_ADDR: imm_b = 32'h4;
default: imm_b = 32'h4;
endcase
// Branch target ALU operand B mux
always_comb begin : bt_immediate_b_mux
unique case (bt_b_mux_sel)
IMM_B_I: bt_b_operand_o = imm_i_type;
IMM_B_B: bt_b_operand_o = imm_b_type;
IMM_B_J: bt_b_operand_o = imm_j_type;
IMM_B_INCR_PC: bt_b_operand_o = instr_is_compressed_i ? 32'h2 : 32'h4;
default: bt_b_operand_o = instr_is_compressed_i ? 32'h2 : 32'h4;
endcase
end
// Reduced main ALU immediate MUX for Operand B
always_comb begin : immediate_b_mux
unique case (imm_b_mux_sel)
IMM_B_I: imm_b = imm_i_type;
IMM_B_S: imm_b = imm_s_type;
IMM_B_U: imm_b = imm_u_type;
IMM_B_INCR_PC: imm_b = instr_is_compressed_i ? 32'h2 : 32'h4;
IMM_B_INCR_ADDR: imm_b = 32'h4;
default: imm_b = 32'h4;
endcase
end
end else begin : g_nobtalu
op_a_sel_e unused_a_mux_sel;
imm_b_sel_e unused_b_mux_sel;
assign unused_a_mux_sel = bt_a_mux_sel;
assign unused_b_mux_sel = bt_b_mux_sel;
assign bt_a_operand_o = '0;
assign bt_b_operand_o = '0;
// Full main ALU immediate MUX for Operand B
always_comb begin : immediate_b_mux
unique case (imm_b_mux_sel)
IMM_B_I: imm_b = imm_i_type;
IMM_B_S: imm_b = imm_s_type;
IMM_B_B: imm_b = imm_b_type;
IMM_B_U: imm_b = imm_u_type;
IMM_B_J: imm_b = imm_j_type;
IMM_B_INCR_PC: imm_b = instr_is_compressed_i ? 32'h2 : 32'h4;
IMM_B_INCR_ADDR: imm_b = 32'h4;
default: imm_b = 32'h4;
endcase
end
end
// ALU MUX for Operand B
@ -343,7 +384,8 @@ module ibex_id_stage #(
// immediates
.imm_a_mux_sel_o ( imm_a_mux_sel ),
.imm_b_mux_sel_o ( imm_b_mux_sel_dec ),
.jt_mux_sel_o ( jt_mux_sel_ex_o ),
.bt_a_mux_sel_o ( bt_a_mux_sel ),
.bt_b_mux_sel_o ( bt_b_mux_sel ),
.imm_i_type_o ( imm_i_type ),
.imm_s_type_o ( imm_s_type ),
@ -529,14 +571,6 @@ module ibex_id_stage #(
assign alu_operand_a_ex_o = alu_operand_a;
assign alu_operand_b_ex_o = alu_operand_b;
if (BranchTargetALU) begin : g_bt_operand_imm
// Branch target ALU sign-extends and inserts bottom 0 bit so only want the
// 'raw' B-type immediate bits.
assign bt_operand_imm_o = imm_b_type[12:1];
end else begin : g_no_bt_operand_imm
assign bt_operand_imm_o = '0;
end
assign mult_en_ex_o = mult_en_id;
assign div_en_ex_o = div_en_id;
assign multdiv_sel_ex_o = multdiv_sel_dec;
@ -637,8 +671,9 @@ module ibex_id_stage #(
end
jump_in_dec: begin
// uncond branch operation
id_fsm_d = MULTI_CYCLE;
stall_jump = 1'b1;
// BTALU means jumps only need one cycle
id_fsm_d = BranchTargetALU ? FIRST_CYCLE : MULTI_CYCLE;
stall_jump = ~BranchTargetALU;
end
default: begin
id_fsm_d = FIRST_CYCLE;
@ -853,14 +888,38 @@ module ibex_id_stage #(
// Selectors must be known/valid.
`ASSERT_KNOWN(IbexAluOpMuxSelKnown, alu_op_a_mux_sel, clk_i, !rst_ni)
`ASSERT(IbexImmBMuxSelValid, imm_b_mux_sel inside {
`ASSERT(IbexAluAOpMuxSelValid, alu_op_a_mux_sel inside {
OP_A_REG_A,
OP_A_FWD,
OP_A_CURRPC,
OP_A_IMM})
if (BranchTargetALU) begin : g_btalu_assertions
`ASSERT(IbexImmBMuxSelValid, imm_b_mux_sel inside {
IMM_B_I,
IMM_B_S,
IMM_B_U,
IMM_B_INCR_PC,
IMM_B_INCR_ADDR})
end else begin : g_nobtalu_assertions
`ASSERT(IbexImmBMuxSelValid, imm_b_mux_sel inside {
IMM_B_I,
IMM_B_S,
IMM_B_B,
IMM_B_U,
IMM_B_J,
IMM_B_INCR_PC,
IMM_B_INCR_ADDR})
end
`ASSERT_KNOWN(IbexBTAluAOpMuxSelKnown, bt_a_mux_sel, clk_i, !rst_ni)
`ASSERT(IbexBTAluAOpMuxSelValid, bt_a_mux_sel inside {
OP_A_REG_A,
OP_A_CURRPC})
`ASSERT_KNOWN(IbexBTAluBOpMuxSelKnown, bt_b_mux_sel, clk_i, !rst_ni)
`ASSERT(IbexBTAluBOpMuxSelValid, bt_b_mux_sel inside {
IMM_B_I,
IMM_B_S,
IMM_B_B,
IMM_B_U,
IMM_B_J,
IMM_B_INCR_PC,
IMM_B_INCR_ADDR})
IMM_B_INCR_PC})
`ASSERT(IbexRegfileWdataSelValid, rf_wdata_sel inside {
RF_WD_EX,
RF_WD_CSR})

View file

@ -62,7 +62,7 @@ module ibex_if_stage #(
input logic icache_inval_i,
// jump and branch target
input logic [31:0] jump_target_ex_i, // jump target address
input logic [31:0] branch_target_ex_i, // branch/jump target address
// CSRs
input logic [31:0] csr_mepc_i, // PC to restore after handling
@ -128,7 +128,7 @@ module ibex_if_stage #(
always_comb begin : fetch_addr_mux
unique case (pc_mux_i)
PC_BOOT: fetch_addr_n = { boot_addr_i[31:8], 8'h80 };
PC_JUMP: fetch_addr_n = jump_target_ex_i;
PC_JUMP: fetch_addr_n = branch_target_ex_i;
PC_EXC: fetch_addr_n = exc_pc; // set PC to exception handler
PC_ERET: fetch_addr_n = csr_mepc_i; // restore PC when returning from EXC
PC_DRET: fetch_addr_n = csr_depc_i;

View file

@ -142,12 +142,6 @@ typedef enum logic [2:0] {
IMM_B_INCR_ADDR
} imm_b_sel_e;
// Only used when BranchTargetALU == 1
typedef enum logic {
JT_ALU, // Jump target from main ALU
JT_BT_ALU // Jump target from specialised branch ALU
} jt_mux_sel_e;
// Regfile write data selection
typedef enum logic {
RF_WD_EX,