Move NT branch addr calculation to ID stage

This commit is contained in:
Sam Shahrestani 2021-11-13 08:36:42 +11:00 committed by Tom Roberts
parent b66f199151
commit ab4041c439
8 changed files with 36 additions and 106 deletions

View file

@ -8,8 +8,8 @@ module ic_top import ibex_pkg::*; #(parameter bit ICacheECC = 1'b0) (
input logic req_i,
input logic branch_i,
input logic branch_spec_i,
input logic predicted_branch_i,
input logic branch_mispredict_i,
input logic [31:0] mispredict_addr_i,
input logic [31:0] addr_i,
input logic ready_i,
output logic valid_o,
@ -60,8 +60,8 @@ module ic_top import ibex_pkg::*; #(parameter bit ICacheECC = 1'b0) (
.branch_i ( branch_i ),
.branch_spec_i ( branch_spec_i ),
.predicted_branch_i ( predicted_branch_i ),
.branch_mispredict_i ( branch_mispredict_i ),
.mispredict_addr_i ( mispredict_addr_i ),
.addr_i ( addr_i ),
.ready_i ( ready_i ),

View file

@ -32,8 +32,8 @@ module tb #(parameter bit ICacheECC = 1'b0);
.req_i (core_if.req),
.branch_i (core_if.branch),
.branch_spec_i (core_if.branch_spec),
.predicted_branch_i (1'b0),
.branch_mispredict_i (1'b0),
.mispredict_addr_i (32'b0),
.addr_i (core_if.branch_addr),
.ready_i (core_if.ready),
.valid_o (core_if.valid),

View file

@ -187,6 +187,7 @@ module ibex_core import ibex_pkg::*; #(
logic pc_set;
logic pc_set_spec;
logic nt_branch_mispredict;
logic [31:0] nt_branch_addr;
pc_sel_e pc_mux_id; // Mux selector for next PC
exc_pc_sel_e exc_pc_mux_id; // Mux selector for exception PC
exc_cause_e exc_cause; // Exception cause
@ -434,6 +435,7 @@ module ibex_core import ibex_pkg::*; #(
// branch targets
.branch_target_ex_i(branch_target_ex),
.nt_branch_addr_i (nt_branch_addr),
// CSRs
.csr_mepc_i (csr_mepc), // exception return address
@ -499,6 +501,7 @@ module ibex_core import ibex_pkg::*; #(
.pc_set_spec_o (pc_set_spec),
.pc_mux_o (pc_mux_id),
.nt_branch_mispredict_o(nt_branch_mispredict),
.nt_branch_addr_o (nt_branch_addr),
.exc_pc_mux_o (exc_pc_mux_id),
.exc_cause_o (exc_cause),
.icache_inval_o (icache_inval),

View file

@ -33,7 +33,6 @@ module ibex_fetch_fifo #(
output logic out_valid_o,
input logic out_ready_i,
output logic [31:0] out_addr_o,
output logic [31:0] out_addr_next_o,
output logic [31:0] out_rdata_o,
output logic out_err_o,
output logic out_err_plus2_o
@ -166,10 +165,7 @@ module ibex_fetch_fifo #(
end
end
// Output both PC of current instruction and instruction following. PC of instruction following is
// required for the branch predictor. It's used to fetch the instruction following a branch that
// was not-taken but (mis)predicted taken.
assign out_addr_next_o = {instr_addr_next, 1'b0};
// Output PC of current instruction
assign out_addr_o = {instr_addr_q, 1'b0};
// The LSB of the address is unused, since all addresses are halfword aligned

View file

@ -11,7 +11,6 @@
`include "prim_assert.sv"
module ibex_icache import ibex_pkg::*; #(
parameter bit BranchPredictor = 1'b0,
parameter bit ICacheECC = 1'b0,
parameter bit ResetAll = 1'b0,
parameter int unsigned BusSizeECC = BUS_SIZE,
@ -30,8 +29,8 @@ module ibex_icache import ibex_pkg::*; #(
// Set the cache's address counter
input logic branch_i,
input logic branch_spec_i,
input logic predicted_branch_i,
input logic branch_mispredict_i,
input logic [31:0] mispredict_addr_i,
input logic [31:0] addr_i,
// IF stage interface: Pass fetched instructions to the core
@ -76,7 +75,6 @@ module ibex_icache import ibex_pkg::*; #(
// Prefetch signals
logic [ADDR_W-1:0] lookup_addr_aligned;
logic [ADDR_W-1:0] branch_mispredict_addr;
logic [ADDR_W-1:0] prefetch_addr_d, prefetch_addr_q;
logic prefetch_addr_en;
logic branch_or_mispredict;
@ -198,41 +196,6 @@ module ibex_icache import ibex_pkg::*; #(
// Instruction prefetch //
//////////////////////////
if (BranchPredictor) begin : g_branch_predictor
// Where the branch predictor is present record what address followed a predicted branch. If
// that branch is predicted taken but mispredicted (so not-taken) this is used to resume on
// the not-taken code path.
logic [31:0] branch_mispredict_addr_q;
logic branch_mispredict_addr_en;
assign branch_mispredict_addr_en = branch_i & predicted_branch_i;
if (ResetAll) begin : g_branch_misp_ra
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
branch_mispredict_addr_q <= '0;
end else if (branch_mispredict_addr_en) begin
branch_mispredict_addr_q <= {output_addr_incr, 1'b0};
end
end
end else begin : g_branch_misp_nr
always_ff @(posedge clk_i) begin
if (branch_mispredict_addr_en) begin
branch_mispredict_addr_q <= {output_addr_incr, 1'b0};
end
end
end
assign branch_mispredict_addr = branch_mispredict_addr_q;
end else begin : g_no_branch_predictor
logic unused_predicted_branch;
assign unused_predicted_branch = predicted_branch_i;
assign branch_mispredict_addr = '0;
end
assign branch_or_mispredict = branch_i | branch_mispredict_i;
assign lookup_addr_aligned = {lookup_addr_ic0[ADDR_W-1:IC_LINE_W], {IC_LINE_W{1'b0}}};
@ -247,7 +210,7 @@ module ibex_icache import ibex_pkg::*; #(
lookup_grant_ic0 ? (lookup_addr_aligned +
{{ADDR_W-IC_LINE_W-1{1'b0}}, 1'b1, {IC_LINE_W{1'b0}}}) :
branch_i ? addr_i :
branch_mispredict_addr;
mispredict_addr_i;
assign prefetch_addr_en = branch_or_mispredict | lookup_grant_ic0;
@ -277,7 +240,7 @@ module ibex_icache import ibex_pkg::*; #(
assign lookup_req_ic0 = req_i & ~&fill_busy_q & (branch_or_mispredict | ~lookup_throttle) &
~ecc_write_req;
assign lookup_addr_ic0 = branch_spec_i ? addr_i :
branch_mispredict_i ? branch_mispredict_addr :
branch_mispredict_i ? mispredict_addr_i :
prefetch_addr_q;
assign lookup_index_ic0 = lookup_addr_ic0[IC_INDEX_HI:IC_LINE_W];
@ -1068,7 +1031,7 @@ module ibex_icache import ibex_pkg::*; #(
// Redirect the address on branches or mispredicts
assign output_addr_d = branch_i ? addr_i[31:1] :
branch_mispredict_i ? branch_mispredict_addr[31:1] :
branch_mispredict_i ? mispredict_addr_i[31:1] :
output_addr_incr;
if (ResetAll) begin : g_output_addr_ra

View file

@ -54,6 +54,7 @@ module ibex_id_stage #(
output logic pc_set_spec_o,
output ibex_pkg::pc_sel_e pc_mux_o,
output logic nt_branch_mispredict_o,
output logic [31:0] nt_branch_addr_o,
output ibex_pkg::exc_pc_sel_e exc_pc_mux_o,
output ibex_pkg::exc_cause_e exc_cause_o,
@ -738,6 +739,16 @@ module ibex_id_stage #(
`ASSERT(NeverDoubleBranch, branch_set & ~instr_bp_taken_i |=> ~branch_set)
`ASSERT(NeverDoubleJump, jump_set & ~instr_bp_taken_i |=> ~jump_set)
//////////////////////////////
// Branch not-taken address //
//////////////////////////////
if (BranchPredictor) begin : g_calc_nt_addr
assign nt_branch_addr_o = pc_id_i + (instr_is_compressed_i ? 32'd2 : 32'd4);
end else begin : g_n_calc_nt_addr
assign nt_branch_addr_o = 32'd0;
end
///////////////
// ID-EX FSM //
///////////////

View file

@ -82,6 +82,7 @@ module ibex_if_stage import ibex_pkg::*; #(
input pc_sel_e pc_mux_i, // selector for PC multiplexer
input logic nt_branch_mispredict_i, // Not-taken branch in ID/EX was
// mispredicted (predicted taken)
input logic [31:0] nt_branch_addr_i, // Not-taken branch address in ID/EX
input exc_pc_sel_e exc_pc_mux_i, // selects ISR address
input exc_cause_e exc_cause, // selects ISR address for
// vectorized interrupt lines
@ -118,7 +119,6 @@ module ibex_if_stage import ibex_pkg::*; #(
logic prefetch_busy;
logic branch_req;
logic branch_spec;
logic predicted_branch;
logic [31:0] fetch_addr_n;
logic unused_fetch_addr_n0;
@ -200,7 +200,6 @@ module ibex_if_stage import ibex_pkg::*; #(
if (ICache) begin : gen_icache
// Full I-Cache option
ibex_icache #(
.BranchPredictor (BranchPredictor),
.ICacheECC (ICacheECC),
.ResetAll (ResetAll),
.BusSizeECC (BusSizeECC),
@ -214,8 +213,8 @@ module ibex_if_stage import ibex_pkg::*; #(
.branch_i ( branch_req ),
.branch_spec_i ( branch_spec ),
.predicted_branch_i ( predicted_branch ),
.branch_mispredict_i ( nt_branch_mispredict_i ),
.mispredict_addr_i ( nt_branch_addr_i ),
.addr_i ( {fetch_addr_n[31:1], 1'b0} ),
.ready_i ( fetch_ready ),
@ -251,7 +250,6 @@ module ibex_if_stage import ibex_pkg::*; #(
end else begin : gen_prefetch_buffer
// prefetch buffer, caches a fixed number of instructions
ibex_prefetch_buffer #(
.BranchPredictor (BranchPredictor),
.ResetAll (ResetAll)
) prefetch_buffer_i (
.clk_i ( clk_i ),
@ -261,8 +259,8 @@ module ibex_if_stage import ibex_pkg::*; #(
.branch_i ( branch_req ),
.branch_spec_i ( branch_spec ),
.predicted_branch_i ( predicted_branch ),
.branch_mispredict_i ( nt_branch_mispredict_i ),
.mispredict_addr_i ( nt_branch_addr_i ),
.addr_i ( {fetch_addr_n[31:1], 1'b0} ),
.ready_i ( fetch_ready ),
@ -512,7 +510,7 @@ module ibex_if_stage import ibex_pkg::*; #(
// data_gnt_i -> instr_req_o (which needs to be avoided as for some interconnects this will
// result in a combinational loop).
assign instr_skid_en = predicted_branch & ~id_in_ready_i & ~instr_skid_valid_q;
assign instr_skid_en = predict_branch_taken & ~pc_set_i & ~id_in_ready_i & ~instr_skid_valid_q;
assign instr_skid_valid_d = (instr_skid_valid_q & ~id_in_ready_i & ~stall_dummy_instr) |
instr_skid_en;
@ -564,10 +562,7 @@ module ibex_if_stage import ibex_pkg::*; #(
// Do not branch predict on instruction errors.
assign predict_branch_taken = predict_branch_taken_raw & ~instr_skid_valid_q & ~fetch_err;
// pc_set_i takes precendence over branch prediction
assign predicted_branch = predict_branch_taken & ~pc_set_i;
assign if_instr_valid = fetch_valid | instr_skid_valid_q;
assign if_instr_valid = fetch_valid | (instr_skid_valid_q & ~nt_branch_mispredict_i);
assign if_instr_rdata = instr_skid_valid_q ? instr_skid_data_q : fetch_rdata;
assign if_instr_addr = instr_skid_valid_q ? instr_skid_addr_q : fetch_addr;
@ -585,7 +580,6 @@ module ibex_if_stage import ibex_pkg::*; #(
end else begin : g_no_branch_predictor
assign instr_bp_taken_o = 1'b0;
assign predict_branch_taken = 1'b0;
assign predicted_branch = 1'b0;
assign predict_branch_pc = 32'b0;
assign if_instr_valid = fetch_valid;
@ -638,6 +632,11 @@ module ibex_if_stage import ibex_pkg::*; #(
assign next_pc = fetch_addr + (instr_is_compressed_out ? 32'd2 : 32'd4);
logic predicted_branch;
// pc_set_i takes precendence over branch prediction
assign predicted_branch = predict_branch_taken & ~pc_set_i;
always_comb begin
predicted_branch_live_d = predicted_branch_live_q;
mispredicted_d = mispredicted_q;

View file

@ -10,7 +10,6 @@
* paths to the instruction cache.
*/
module ibex_prefetch_buffer #(
parameter bit BranchPredictor = 1'b0,
parameter bit ResetAll = 1'b0
) (
input logic clk_i,
@ -20,8 +19,8 @@ module ibex_prefetch_buffer #(
input logic branch_i,
input logic branch_spec_i,
input logic predicted_branch_i,
input logic branch_mispredict_i,
input logic [31:0] mispredict_addr_i,
input logic [31:0] addr_i,
@ -62,7 +61,6 @@ module ibex_prefetch_buffer #(
logic stored_addr_en;
logic [31:0] fetch_addr_d, fetch_addr_q;
logic fetch_addr_en;
logic [31:0] branch_mispredict_addr;
logic [31:0] instr_addr, instr_addr_w_aligned;
logic instr_or_pmp_err;
@ -74,8 +72,6 @@ module ibex_prefetch_buffer #(
logic valid_raw;
logic [31:0] addr_next;
logic branch_or_mispredict;
////////////////////////////
@ -128,7 +124,6 @@ module ibex_prefetch_buffer #(
.out_ready_i ( ready_i ),
.out_rdata_o ( rdata_o ),
.out_addr_o ( addr_o ),
.out_addr_next_o ( addr_next ),
.out_err_o ( err_o ),
.out_err_plus2_o ( err_plus2_o )
);
@ -198,50 +193,13 @@ module ibex_prefetch_buffer #(
end
end
end
if (BranchPredictor) begin : g_branch_predictor
// Where the branch predictor is present record what address followed a predicted branch. If
// that branch is predicted taken but mispredicted (so not-taken) this is used to resume on
// the not-taken code path.
logic [31:0] branch_mispredict_addr_q;
logic branch_mispredict_addr_en;
assign branch_mispredict_addr_en = branch_i & predicted_branch_i;
if (ResetAll) begin : g_branch_misp_addr_ra
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
branch_mispredict_addr_q <= '0;
end else if (branch_mispredict_addr_en) begin
branch_mispredict_addr_q <= addr_next;
end
end
end else begin : g_branch_misp_addr_nr
always_ff @(posedge clk_i) begin
if (branch_mispredict_addr_en) begin
branch_mispredict_addr_q <= addr_next;
end
end
end
assign branch_mispredict_addr = branch_mispredict_addr_q;
end else begin : g_no_branch_predictor
logic unused_predicted_branch;
logic [31:0] unused_addr_next;
assign unused_predicted_branch = predicted_branch_i;
assign unused_addr_next = addr_next;
assign branch_mispredict_addr = '0;
end
// 2. fetch_addr_q
// Update on a branch or as soon as a request is issued
assign fetch_addr_en = branch_or_mispredict | (valid_new_req & ~valid_req_q);
assign fetch_addr_d = (branch_i ? addr_i :
branch_mispredict_i ? {branch_mispredict_addr[31:2], 2'b00} :
branch_mispredict_i ? {mispredict_addr_i[31:2], 2'b00} :
{fetch_addr_q[31:2], 2'b00}) +
// Current address + 4
{{29{1'b0}},(valid_new_req & ~valid_req_q),2'b00};
@ -265,7 +223,7 @@ module ibex_prefetch_buffer #(
// Address mux
assign instr_addr = valid_req_q ? stored_addr_q :
branch_spec_i ? addr_i :
branch_mispredict_i ? branch_mispredict_addr :
branch_mispredict_i ? mispredict_addr_i :
fetch_addr_q;
assign instr_addr_w_aligned = {instr_addr[31:2], 2'b00};
@ -318,7 +276,7 @@ module ibex_prefetch_buffer #(
// Push a new entry to the FIFO once complete (and not cancelled by a branch)
assign fifo_valid = rvalid_or_pmp_err & ~branch_discard_q[0];
assign fifo_addr = branch_i ? addr_i : branch_mispredict_addr;
assign fifo_addr = branch_i ? addr_i : mispredict_addr_i;
///////////////
// Registers //