[rtl] Add branch prediction signals to icache

These changes correspond to similar changes in the prefetch buffer to
support branch prediction. A registered version of fill_ext_done was
required to prevent a combinational loop from branch_i in to valid_o
out.

Multiplexing priorities for fifo_addr have been swapped to match
fetch_addr_d in the same module and all similar multiplexing in the
icache (prioritize incoming branch_i over branch_mispredict_i). Note
however that it is not expected that these conditions will actually
occur together, and an assertion has been added to check that.

Signed-off-by: Tom Roberts <tomroberts@lowrisc.org>
This commit is contained in:
Tom Roberts 2020-11-12 11:47:45 +00:00 committed by Tom Roberts
parent 64ee9a930d
commit 8db89a9dfc
6 changed files with 172 additions and 108 deletions

View file

@ -25,32 +25,34 @@ module tb #(parameter bit ICacheECC = 1'b0);
ibex_icache #(
.ICacheECC (ICacheECC)
) dut (
.clk_i (clk),
.rst_ni (rst_n),
.clk_i (clk),
.rst_ni (rst_n),
// Connect icache <-> core interface
.req_i (core_if.req),
.branch_i (core_if.branch),
.branch_spec_i (core_if.branch_spec),
.addr_i (core_if.branch_addr),
.ready_i (core_if.ready),
.valid_o (core_if.valid),
.rdata_o (core_if.rdata),
.addr_o (core_if.addr),
.err_o (core_if.err),
.err_plus2_o (core_if.err_plus2),
.icache_enable_i (core_if.enable),
.icache_inval_i (core_if.invalidate),
.busy_o (core_if.busy),
.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),
.addr_i (core_if.branch_addr),
.ready_i (core_if.ready),
.valid_o (core_if.valid),
.rdata_o (core_if.rdata),
.addr_o (core_if.addr),
.err_o (core_if.err),
.err_plus2_o (core_if.err_plus2),
.icache_enable_i (core_if.enable),
.icache_inval_i (core_if.invalidate),
.busy_o (core_if.busy),
// Connect icache <-> instruction bus interface
.instr_req_o (mem_if.req),
.instr_gnt_i (mem_if.gnt),
.instr_addr_o (mem_if.addr),
.instr_rdata_i (mem_if.rdata),
.instr_err_i (mem_if.err),
.instr_pmp_err_i (mem_if.pmp_err),
.instr_rvalid_i (mem_if.rvalid)
.instr_req_o (mem_if.req),
.instr_gnt_i (mem_if.gnt),
.instr_addr_o (mem_if.addr),
.instr_rdata_i (mem_if.rdata),
.instr_err_i (mem_if.err),
.instr_pmp_err_i (mem_if.pmp_err),
.instr_rvalid_i (mem_if.rvalid)
);
// If the ICacheECC parameter is set in the DUT, generate another interface for each tag ram and

View file

@ -17,21 +17,22 @@
module formal_tb #(
// DUT parameters
parameter int unsigned BusWidth = 32,
parameter int unsigned CacheSizeBytes = 4*1024,
parameter bit ICacheECC = 1'b0,
parameter int unsigned LineSize = 64,
parameter int unsigned NumWays = 2,
parameter bit BranchCache = 1'b0,
parameter bit BranchPredictor = 1'b0,
parameter int unsigned BusWidth = 32,
parameter int unsigned CacheSizeBytes = 4*1024,
parameter bit ICacheECC = 1'b0,
parameter int unsigned LineSize = 64,
parameter int unsigned NumWays = 2,
parameter bit BranchCache = 1'b0,
// Internal parameters / localparams
parameter int unsigned ADDR_W = 32,
parameter int unsigned NUM_FB = 4,
parameter int unsigned LINE_W = 3,
parameter int unsigned BUS_BYTES = BusWidth/8,
parameter int unsigned BUS_W = $clog2(BUS_BYTES),
parameter int unsigned LINE_BEATS = 2,
parameter int unsigned LINE_BEATS_W = 1
parameter int unsigned ADDR_W = 32,
parameter int unsigned NUM_FB = 4,
parameter int unsigned LINE_W = 3,
parameter int unsigned BUS_BYTES = BusWidth/8,
parameter int unsigned BUS_W = $clog2(BUS_BYTES),
parameter int unsigned LINE_BEATS = 2,
parameter int unsigned LINE_BEATS_W = 1
) (
// Top-level ports
input logic clk_i,
@ -39,6 +40,8 @@ module formal_tb #(
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] addr_i,
input logic ready_i,
input logic valid_o,
@ -65,7 +68,8 @@ module formal_tb #(
input logic [NUM_FB-1:0] fill_hit_q,
input logic [NUM_FB-1:0][LINE_BEATS_W:0] fill_ext_cnt_q,
input logic [NUM_FB-1:0] fill_ext_hold_q,
input logic [NUM_FB-1:0] fill_ext_done,
input logic [NUM_FB-1:0] fill_ext_done_d,
input logic [NUM_FB-1:0] fill_ext_done_q,
input logic [NUM_FB-1:0][LINE_BEATS_W:0] fill_rvd_cnt_q,
input logic [NUM_FB-1:0] fill_rvd_done,
input logic [NUM_FB-1:0][LINE_BEATS_W:0] fill_out_cnt_q,
@ -122,6 +126,17 @@ module formal_tb #(
end
end
// Reset assumptions
//
// We assume that req_i isn't asserted to the block when in reset (which avoids it making requests
// on the external bus).
`ASSUME_ZERO_IN_RESET(req_i)
// Parameter assumptions
//
// If BranchPredictor = 1'b0, the branch_mispredict_i signal will never go high
`ASSUME(no_mispred_without_branch_pred, `IMPLIES(branch_mispredict_i, BranchPredictor))
// Protocol assumptions
//
// These are assumptions based on the top-level ports. They somewhat mirror the assertions in the
@ -346,7 +361,7 @@ module formal_tb #(
(fill_ext_cnt_q[fb] != '0) &&
fill_older_q[fb][fb2] &&
fill_busy_q[fb2]),
fill_ext_done[fb2]))
fill_ext_done_q[fb2]))
// Similarly, if J is older than I then we should see fill_rvd_done[J] before
// fill_rvd_cnt_q[I] is nonzero.
@ -656,7 +671,7 @@ module formal_tb #(
// for beat b and the memory request was squashed by a PMP error.
//
// The former case is easy (bit b should be set in f_fill_rvd_mask). In the latter case,
// fill_ext_done will be true, fill_ext_cnt_q will be less than LINE_BEATS, and fill_ext_off (the
// fill_ext_done_d will be true, fill_ext_cnt_q will be less than LINE_BEATS, and fill_ext_off (the
// next beat to fetch) will equal b. We define explicit masks for the bits allowed in each case.
logic [NUM_FB-1:0][LINE_BEATS-1:0] f_rvd_err_mask, f_pmp_err_mask, f_err_mask;
always_comb begin
@ -665,7 +680,7 @@ module formal_tb #(
for (int i = 0; i < NUM_FB; i++) begin
f_rvd_err_mask[i] = f_fill_rvd_mask[i];
for (int b = 0; b < LINE_BEATS; b++) begin
f_pmp_err_mask[i][b] = (fill_ext_done[i] &&
f_pmp_err_mask[i][b] = (fill_ext_done_d[i] &&
!fill_ext_cnt_q[i][LINE_BEATS_W] &&
(fill_ext_off[i] == b[LINE_BEATS_W-1:0]));
end

View file

@ -8,18 +8,19 @@
// Using a wildcard (.*) for ports allows the testbench to inspect internal signals of the cache.
formal_tb #(
.BusWidth (BusWidth),
.CacheSizeBytes (CacheSizeBytes),
.ICacheECC (ICacheECC),
.LineSize (LineSize),
.NumWays (NumWays),
.BranchCache (BranchCache),
.BranchPredictor (BranchPredictor),
.BusWidth (BusWidth),
.CacheSizeBytes (CacheSizeBytes),
.ICacheECC (ICacheECC),
.LineSize (LineSize),
.NumWays (NumWays),
.BranchCache (BranchCache),
.ADDR_W (ADDR_W),
.NUM_FB (NUM_FB),
.LINE_W (LINE_W),
.BUS_BYTES (BUS_BYTES),
.BUS_W (BUS_W),
.LINE_BEATS (LINE_BEATS),
.LINE_BEATS_W (LINE_BEATS_W)
.ADDR_W (ADDR_W),
.NUM_FB (NUM_FB),
.LINE_W (LINE_W),
.BUS_BYTES (BUS_BYTES),
.BUS_W (BUS_W),
.LINE_BEATS (LINE_BEATS),
.LINE_BEATS_W (LINE_BEATS_W)
) tb_i (.*);

View file

@ -11,14 +11,15 @@
`include "prim_assert.sv"
module ibex_icache #(
parameter bit BranchPredictor = 1'b0,
// Cache arrangement parameters
parameter int unsigned BusWidth = 32,
parameter int unsigned CacheSizeBytes = 4*1024,
parameter bit ICacheECC = 1'b0,
parameter int unsigned LineSize = 64,
parameter int unsigned NumWays = 2,
parameter int unsigned BusWidth = 32,
parameter int unsigned CacheSizeBytes = 4*1024,
parameter bit ICacheECC = 1'b0,
parameter int unsigned LineSize = 64,
parameter int unsigned NumWays = 2,
// Only cache branch targets
parameter bit BranchCache = 1'b0
parameter bit BranchCache = 1'b0
) (
// Clock and reset
input logic clk_i,
@ -30,6 +31,8 @@ module ibex_icache #(
// 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] addr_i,
// IF stage interface: Pass fetched instructions to the core
@ -77,8 +80,10 @@ module ibex_icache #(
// 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;
// Cache pipelipe IC0 signals
logic branch_suppress;
logic lookup_throttle;
@ -134,7 +139,7 @@ module ibex_icache #(
logic [NUM_FB-1:0] fill_hit_ic1, fill_hit_d, fill_hit_q;
logic [NUM_FB-1:0][LINE_BEATS_W:0] fill_ext_cnt_d, fill_ext_cnt_q;
logic [NUM_FB-1:0] fill_ext_hold_d, fill_ext_hold_q;
logic [NUM_FB-1:0] fill_ext_done;
logic [NUM_FB-1:0] fill_ext_done_d, fill_ext_done_q;
logic [NUM_FB-1:0][LINE_BEATS_W:0] fill_rvd_cnt_d, fill_rvd_cnt_q;
logic [NUM_FB-1:0] fill_rvd_done;
logic [NUM_FB-1:0] fill_ram_done_d, fill_ram_done_q;
@ -175,6 +180,7 @@ module ibex_icache #(
logic output_valid;
logic addr_incr_two;
logic output_addr_en;
logic [ADDR_W-1:1] output_addr_incr;
logic [ADDR_W-1:1] output_addr_d, output_addr_q;
logic [15:0] output_data_lo, output_data_hi;
logic data_valid, output_ready;
@ -194,6 +200,33 @@ module ibex_icache #(
// 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;
always_ff @(posedge clk_i) begin
if (branch_mispredict_addr_en) begin
branch_mispredict_addr_q <= {output_addr_incr, 1'b0};
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:LINE_W],{LINE_W{1'b0}}};
// The prefetch address increments by one cache line for each granted request.
@ -204,9 +237,10 @@ module ibex_icache #(
// line must also be recorded for later use by the fill buffers.
assign prefetch_addr_d =
lookup_grant_ic0 ? (lookup_addr_aligned + {{ADDR_W-LINE_W-1{1'b0}},1'b1,{LINE_W{1'b0}}}) :
addr_i;
branch_i ? addr_i :
branch_mispredict_addr;
assign prefetch_addr_en = branch_i | lookup_grant_ic0;
assign prefetch_addr_en = branch_or_mispredict | lookup_grant_ic0;
always_ff @(posedge clk_i) begin
if (prefetch_addr_en) begin
@ -221,9 +255,11 @@ module ibex_icache #(
// Cache lookup
assign lookup_throttle = (fb_fill_level > FB_THRESHOLD[$clog2(NUM_FB)-1:0]);
assign lookup_req_ic0 = req_i & ~&fill_busy_q & (branch_i | ~lookup_throttle) & ~ecc_write_req;
assign lookup_addr_ic0 = branch_spec_i ? addr_i :
prefetch_addr_q;
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 :
prefetch_addr_q;
assign lookup_index_ic0 = lookup_addr_ic0[INDEX_HI:LINE_W];
// Cache write
@ -516,7 +552,7 @@ module ibex_icache #(
assign fill_new_alloc = lookup_grant_ic0;
// Track whether a speculative external request was made from IC0, and whether it was granted
// Speculative requests are only made for branches, or if the cache is disabled
assign fill_spec_req = (~icache_enable_i | branch_i) & ~|fill_ext_req;
assign fill_spec_req = (~icache_enable_i | branch_or_mispredict) & ~|fill_ext_req;
assign fill_spec_done = fill_spec_req & gnt_not_pmp_err;
assign fill_spec_hold = fill_spec_req & ~gnt_or_pmp_err;
@ -545,7 +581,7 @@ module ibex_icache #(
assign fill_done[fb] = (fill_ram_done_q[fb] | fill_hit_q[fb] | ~fill_cache_q[fb] |
(|fill_err_q[fb])) &
// all data output unless stale due to intervening branch
(fill_out_done[fb] | fill_stale_q[fb] | branch_i) &
(fill_out_done[fb] | fill_stale_q[fb] | branch_or_mispredict) &
// all external requests completed
fill_rvd_done[fb];
@ -554,7 +590,7 @@ module ibex_icache #(
/////////////////////////////////
// Track staleness (requests become stale when a branch intervenes)
assign fill_stale_d[fb] = fill_busy_q[fb] & (branch_i | fill_stale_q[fb]);
assign fill_stale_d[fb] = fill_busy_q[fb] & (branch_or_mispredict | fill_stale_q[fb]);
// Track whether or not this request should allocate to the cache
// Any invalidation or disabling of the cache while the buffer is busy will stop allocation
assign fill_cache_d[fb] = (fill_alloc[fb] & fill_cache_new) |
@ -569,7 +605,7 @@ module ibex_icache #(
///////////////////////////////////////////
// Make an external request
assign fill_ext_req[fb] = fill_busy_q[fb] & ~fill_ext_done[fb];
assign fill_ext_req[fb] = fill_busy_q[fb] & ~fill_ext_done_d[fb];
// Count the number of completed external requests (each line requires LINE_BEATS requests)
// Don't count fake PMP error grants here since they will never receive an rvalid response
@ -581,17 +617,17 @@ module ibex_icache #(
assign fill_ext_hold_d[fb] = (fill_alloc[fb] & fill_spec_hold) |
(fill_ext_arb[fb] & ~gnt_or_pmp_err);
// External requests are completed when the counter is filled or when the request is cancelled
assign fill_ext_done[fb] = (fill_ext_cnt_q[fb][LINE_BEATS_W] |
assign fill_ext_done_d[fb] = (fill_ext_cnt_q[fb][LINE_BEATS_W] |
// external requests are considered complete if the request hit
fill_hit_ic1[fb] | fill_hit_q[fb] |
// external requests will stop once any PMP error is received
fill_err_q[fb][fill_ext_off[fb]] |
// cancel if the line won't be cached and, it is stale
(~fill_cache_q[fb] & (branch_i | fill_stale_q[fb] |
(~fill_cache_q[fb] & (branch_or_mispredict | fill_stale_q[fb] |
// or we're already at the end of the line
fill_ext_beat[fb][LINE_BEATS_W]))) &
// can't cancel while we are waiting for a grant on the bus
~fill_ext_hold_q[fb];
~fill_ext_hold_q[fb] & fill_busy_q[fb];
// Track whether this fill buffer expects to receive beats of data
assign fill_rvd_exp[fb] = fill_busy_q[fb] & ~fill_rvd_done[fb];
// Count the number of rvalid beats received
@ -599,7 +635,8 @@ module ibex_icache #(
(fill_rvd_cnt_q[fb] +
{{LINE_BEATS_W{1'b0}},fill_rvd_arb[fb]});
// External data is complete when all issued external requests have received their data
assign fill_rvd_done[fb] = fill_ext_done[fb] & (fill_rvd_cnt_q[fb] == fill_ext_cnt_q[fb]);
assign fill_rvd_done[fb] = (fill_ext_done_q[fb] & ~fill_ext_hold_q[fb]) &
(fill_rvd_cnt_q[fb] == fill_ext_cnt_q[fb]);
//////////////////////////////////////
// Fill buffer data output tracking //
@ -705,6 +742,7 @@ module ibex_icache #(
fill_hit_q[fb] <= 1'b0;
fill_ext_cnt_q[fb] <= '0;
fill_ext_hold_q[fb] <= 1'b0;
fill_ext_done_q[fb] <= 1'b0;
fill_rvd_cnt_q[fb] <= '0;
fill_ram_done_q[fb] <= 1'b0;
fill_out_cnt_q[fb] <= '0;
@ -716,6 +754,7 @@ module ibex_icache #(
fill_hit_q[fb] <= fill_hit_d[fb];
fill_ext_cnt_q[fb] <= fill_ext_cnt_d[fb];
fill_ext_hold_q[fb] <= fill_ext_hold_d[fb];
fill_ext_done_q[fb] <= fill_ext_done_d[fb];
fill_rvd_cnt_q[fb] <= fill_rvd_cnt_d[fb];
fill_ram_done_q[fb] <= fill_ram_done_d[fb];
fill_out_cnt_q[fb] <= fill_out_cnt_d[fb];
@ -828,7 +867,7 @@ module ibex_icache #(
// External requests //
///////////////////////
assign instr_req = ((~icache_enable_i | branch_i) & lookup_grant_ic0) |
assign instr_req = ((~icache_enable_i | branch_or_mispredict) & lookup_grant_ic0) |
(|fill_ext_req);
assign instr_addr = |fill_ext_req ? fill_ext_req_addr :
@ -893,7 +932,7 @@ module ibex_icache #(
assign skid_valid_d =
// Branches invalidate the skid buffer
branch_i ? 1'b0 :
branch_or_mispredict ? 1'b0 :
// Once valid, the skid buffer stays valid until a compressed instruction realigns the stream
(skid_valid_q ? ~(ready_i & ((skid_data_q[1:0] != 2'b11) | skid_err_q)) :
// The skid buffer becomes valid when:
@ -921,15 +960,20 @@ module ibex_icache #(
output_err | (output_data[17:16] != 2'b11)));
// Update the address on branches and every time an instruction is driven
assign output_addr_en = branch_i | (ready_i & valid_o);
assign output_addr_en = branch_or_mispredict | (ready_i & valid_o);
// Increment the address by two every time a compressed instruction is popped
assign addr_incr_two = output_compressed & ~err_o;
assign output_addr_d = branch_i ? addr_i[31:1] :
(output_addr_q[31:1] +
// Increment address by 4 or 2
{29'd0, ~addr_incr_two, addr_incr_two});
// Next IF stage PC
assign output_addr_incr = (output_addr_q[31:1] +
// Increment address by 4 or 2
{29'd0, ~addr_incr_two, addr_incr_two});
// 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] :
output_addr_incr;
always_ff @(posedge clk_i) begin
if (output_addr_en) begin
@ -963,7 +1007,7 @@ module ibex_icache #(
end
end
assign valid_o = output_valid;
assign valid_o = output_valid & ~branch_mispredict_i;
assign rdata_o = {output_data_hi, (skid_valid_q ? skid_data_q : output_data_lo)};
assign addr_o = {output_addr_q, 1'b0};
assign err_o = (skid_valid_q & skid_err_q) | (~skid_complete_instr & output_err);

View file

@ -184,40 +184,39 @@ module ibex_if_stage #(
if (ICache) begin : gen_icache
// Full I-Cache option
ibex_icache #(
.ICacheECC (ICacheECC)
.BranchPredictor (BranchPredictor),
.ICacheECC (ICacheECC)
) icache_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.req_i ( req_i ),
.req_i ( req_i ),
.branch_i ( branch_req ),
.branch_spec_i ( branch_spec ),
.addr_i ( {fetch_addr_n[31:1], 1'b0} ),
.branch_i ( branch_req ),
.branch_spec_i ( branch_spec ),
.predicted_branch_i ( predicted_branch ),
.branch_mispredict_i ( nt_branch_mispredict_i ),
.addr_i ( {fetch_addr_n[31:1], 1'b0} ),
.ready_i ( fetch_ready ),
.valid_o ( fetch_valid ),
.rdata_o ( fetch_rdata ),
.addr_o ( fetch_addr ),
.err_o ( fetch_err ),
.err_plus2_o ( fetch_err_plus2 ),
.ready_i ( fetch_ready ),
.valid_o ( fetch_valid ),
.rdata_o ( fetch_rdata ),
.addr_o ( fetch_addr ),
.err_o ( fetch_err ),
.err_plus2_o ( fetch_err_plus2 ),
.instr_req_o ( instr_req_o ),
.instr_addr_o ( instr_addr_o ),
.instr_gnt_i ( instr_gnt_i ),
.instr_rvalid_i ( instr_rvalid_i ),
.instr_rdata_i ( instr_rdata_i ),
.instr_err_i ( instr_err_i ),
.instr_pmp_err_i ( instr_pmp_err_i ),
.instr_req_o ( instr_req_o ),
.instr_addr_o ( instr_addr_o ),
.instr_gnt_i ( instr_gnt_i ),
.instr_rvalid_i ( instr_rvalid_i ),
.instr_rdata_i ( instr_rdata_i ),
.instr_err_i ( instr_err_i ),
.instr_pmp_err_i ( instr_pmp_err_i ),
.icache_enable_i ( icache_enable_i ),
.icache_inval_i ( icache_inval_i ),
.busy_o ( prefetch_busy )
.icache_enable_i ( icache_enable_i ),
.icache_inval_i ( icache_inval_i ),
.busy_o ( prefetch_busy )
);
// Branch predictor tie-offs (which are unused when the instruction cache is enabled)
logic unused_nt_branch_mispredict, unused_predicted_branch;
assign unused_nt_branch_mispredict = nt_branch_mispredict_i;
assign unused_predicted_branch = predicted_branch;
end else begin : gen_prefetch_buffer
// prefetch buffer, caches a fixed number of instructions
ibex_prefetch_buffer #(
@ -590,6 +589,9 @@ module ibex_if_stage #(
// following cycle core signal that that branch has mispredicted).
`ASSERT(MispredictSingleCycle,
nt_branch_mispredict_i & ~(fetch_valid & fetch_ready) |=> ~nt_branch_mispredict_i)
// Note that we should never see a mispredict and an incoming branch on the same cycle.
// The mispredict also cancels any predicted branch so overall branch_req must be low.
`ASSERT(NoMispredBranch, nt_branch_mispredict_i |-> ~branch_req)
`endif
end else begin : g_no_branch_predictor_asserts

View file

@ -286,7 +286,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_mispredict_i ? branch_mispredict_addr : addr_i;
assign fifo_addr = branch_i ? addr_i : branch_mispredict_addr;
///////////////
// Registers //