[rtl/icache] Move various parameters into the pkg

No functional change. These parameters are effectively fixed. Moving
them to the pkg eases top-level wiring of RAM signals.

Signed-off-by: Tom Roberts <tomroberts@lowrisc.org>
This commit is contained in:
Tom Roberts 2021-03-24 09:55:31 +00:00 committed by Tom Roberts
parent a799a92e5e
commit b106001d82
4 changed files with 245 additions and 237 deletions

View file

@ -60,7 +60,7 @@ module tb #(parameter bit ICacheECC = 1'b0);
// each data ram, binding them into the RAMs themselves. ECC tests can use these to insert errors
// into memory lookups.
generate if (dut.ICacheECC) begin : gen_ecc
for (genvar w = 0; w < dut.NumWays; w++) begin : gen_ecc_ifs
for (genvar w = 0; w < ibex_pkg::IC_NUM_WAYS; w++) begin : gen_ecc_ifs
bind dut.gen_rams[w].tag_bank.gen_badbit.u_impl_badbit ibex_icache_ecc_if tag_bank_if (.*);
bind dut.gen_rams[w].data_bank.gen_badbit.u_impl_badbit ibex_icache_ecc_if data_bank_if (.*);
@ -93,7 +93,7 @@ module tb #(parameter bit ICacheECC = 1'b0);
// Record the number of (ECC) ways in the config database. The top-level environment's config
// will use this to decide how many agents to create.
uvm_config_db#(int unsigned)::set(null, "*", "num_ecc_ways", dut.ICacheECC ? dut.NumWays : 0);
uvm_config_db#(int unsigned)::set(null, "*", "num_ecc_ways", dut.ICacheECC ? ibex_pkg::IC_NUM_WAYS : 0);
$timeformat(-12, 0, " ps", 12);
run_test();

View file

@ -10,6 +10,7 @@ filesets:
- lowrisc:prim:secded
- lowrisc:prim:ram_1p
- lowrisc:prim:assert
- lowrisc:ibex:ibex_pkg
files:
- rtl/ibex_icache.sv
file_type: systemVerilogSource

View file

@ -12,192 +12,177 @@
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,
// Only cache branch targets
parameter bit BranchCache = 1'b0
) (
// Clock and reset
input logic clk_i,
input logic rst_ni,
input logic clk_i,
input logic rst_ni,
// Signal that the core would like instructions
input logic req_i,
input logic req_i,
// 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,
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
input logic ready_i,
output logic valid_o,
output logic [31:0] rdata_o,
output logic [31:0] addr_o,
output logic err_o,
output logic err_plus2_o,
input logic ready_i,
output logic valid_o,
output logic [31:0] rdata_o,
output logic [31:0] addr_o,
output logic err_o,
output logic err_plus2_o,
// Instruction memory / interconnect interface: Fetch instruction data from memory
output logic instr_req_o,
input logic instr_gnt_i,
output logic [31:0] instr_addr_o,
input logic [BusWidth-1:0] instr_rdata_i,
input logic instr_err_i,
input logic instr_pmp_err_i,
input logic instr_rvalid_i,
output logic instr_req_o,
input logic instr_gnt_i,
output logic [31:0] instr_addr_o,
input logic [ibex_pkg::BUS_WIDTH-1:0] instr_rdata_i,
input logic instr_err_i,
input logic instr_pmp_err_i,
input logic instr_rvalid_i,
// Cache status
input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_i,
input logic icache_enable_i,
input logic icache_inval_i,
output logic busy_o
input prim_ram_1p_pkg::ram_1p_cfg_t ram_cfg_i,
input logic icache_enable_i,
input logic icache_inval_i,
output logic busy_o
);
// Local constants
localparam int unsigned ADDR_W = 32;
import ibex_pkg::*;
// Number of fill buffers (must be >= 2)
localparam int unsigned NUM_FB = 4;
localparam int unsigned NUM_FB = 4;
// Request throttling threshold
localparam int unsigned FB_THRESHOLD = NUM_FB - 2;
localparam int unsigned FB_THRESHOLD = NUM_FB - 2;
// Derived parameters
localparam int unsigned LINE_SIZE_BYTES = LineSize/8;
localparam int unsigned LINE_W = $clog2(LINE_SIZE_BYTES);
localparam int unsigned BUS_SIZE_ECC = ICacheECC ? (BusWidth + 7) : BusWidth;
localparam int unsigned BUS_BYTES = BusWidth/8;
localparam int unsigned BUS_W = $clog2(BUS_BYTES);
localparam int unsigned LINE_BEATS = LINE_SIZE_BYTES / BUS_BYTES;
localparam int unsigned LINE_BEATS_W = $clog2(LINE_BEATS);
localparam int unsigned NUM_LINES = CacheSizeBytes / NumWays / LINE_SIZE_BYTES;
localparam int unsigned LINE_SIZE_ECC = BUS_SIZE_ECC * LINE_BEATS;
localparam int unsigned INDEX_W = $clog2(NUM_LINES);
localparam int unsigned INDEX_HI = INDEX_W + LINE_W - 1;
localparam int unsigned TAG_SIZE = ADDR_W - INDEX_W - LINE_W + 1; // 1 valid bit
localparam int unsigned TAG_SIZE_ECC = ICacheECC ? (TAG_SIZE + 6) : TAG_SIZE;
localparam int unsigned OUTPUT_BEATS = (BUS_BYTES / 2); // number of halfwords
localparam int unsigned BUS_SIZE_ECC = ICacheECC ? (BUS_WIDTH + 7) : BUS_WIDTH;
localparam int unsigned LINE_SIZE_ECC = BUS_SIZE_ECC * IC_LINE_BEATS;
localparam int unsigned TAG_SIZE_ECC = ICacheECC ? (IC_TAG_SIZE + 6) : IC_TAG_SIZE;
// 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;
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;
logic lookup_req_ic0;
logic [ADDR_W-1:0] lookup_addr_ic0;
logic [INDEX_W-1:0] lookup_index_ic0;
logic fill_req_ic0;
logic [INDEX_W-1:0] fill_index_ic0;
logic [TAG_SIZE-1:0] fill_tag_ic0;
logic [LineSize-1:0] fill_wdata_ic0;
logic lookup_grant_ic0;
logic lookup_actual_ic0;
logic fill_grant_ic0;
logic tag_req_ic0;
logic [INDEX_W-1:0] tag_index_ic0;
logic [NumWays-1:0] tag_banks_ic0;
logic tag_write_ic0;
logic [TAG_SIZE_ECC-1:0] tag_wdata_ic0;
logic data_req_ic0;
logic [INDEX_W-1:0] data_index_ic0;
logic [NumWays-1:0] data_banks_ic0;
logic data_write_ic0;
logic [LINE_SIZE_ECC-1:0] data_wdata_ic0;
logic branch_suppress;
logic lookup_throttle;
logic lookup_req_ic0;
logic [ADDR_W-1:0] lookup_addr_ic0;
logic [IC_INDEX_W-1:0] lookup_index_ic0;
logic fill_req_ic0;
logic [IC_INDEX_W-1:0] fill_index_ic0;
logic [IC_TAG_SIZE-1:0] fill_tag_ic0;
logic [IC_LINE_SIZE-1:0] fill_wdata_ic0;
logic lookup_grant_ic0;
logic lookup_actual_ic0;
logic fill_grant_ic0;
logic tag_req_ic0;
logic [IC_INDEX_W-1:0] tag_index_ic0;
logic [IC_NUM_WAYS-1:0] tag_banks_ic0;
logic tag_write_ic0;
logic [TAG_SIZE_ECC-1:0] tag_wdata_ic0;
logic data_req_ic0;
logic [IC_INDEX_W-1:0] data_index_ic0;
logic [IC_NUM_WAYS-1:0] data_banks_ic0;
logic data_write_ic0;
logic [LINE_SIZE_ECC-1:0] data_wdata_ic0;
// Cache pipelipe IC1 signals
logic [TAG_SIZE_ECC-1:0] tag_rdata_ic1 [NumWays];
logic [LINE_SIZE_ECC-1:0] data_rdata_ic1 [NumWays];
logic [LINE_SIZE_ECC-1:0] hit_data_ecc_ic1;
logic [LineSize-1:0] hit_data_ic1;
logic lookup_valid_ic1;
logic [ADDR_W-1:INDEX_HI+1] lookup_addr_ic1;
logic [NumWays-1:0] tag_match_ic1;
logic tag_hit_ic1;
logic [NumWays-1:0] tag_invalid_ic1;
logic [NumWays-1:0] lowest_invalid_way_ic1;
logic [NumWays-1:0] round_robin_way_ic1, round_robin_way_q;
logic [NumWays-1:0] sel_way_ic1;
logic ecc_err_ic1;
logic ecc_write_req;
logic [NumWays-1:0] ecc_write_ways;
logic [INDEX_W-1:0] ecc_write_index;
logic [TAG_SIZE_ECC-1:0] tag_rdata_ic1 [IC_NUM_WAYS];
logic [LINE_SIZE_ECC-1:0] data_rdata_ic1 [IC_NUM_WAYS];
logic [LINE_SIZE_ECC-1:0] hit_data_ecc_ic1;
logic [IC_LINE_SIZE-1:0] hit_data_ic1;
logic lookup_valid_ic1;
logic [ADDR_W-1:IC_INDEX_HI+1] lookup_addr_ic1;
logic [IC_NUM_WAYS-1:0] tag_match_ic1;
logic tag_hit_ic1;
logic [IC_NUM_WAYS-1:0] tag_invalid_ic1;
logic [IC_NUM_WAYS-1:0] lowest_invalid_way_ic1;
logic [IC_NUM_WAYS-1:0] round_robin_way_ic1, round_robin_way_q;
logic [IC_NUM_WAYS-1:0] sel_way_ic1;
logic ecc_err_ic1;
logic ecc_write_req;
logic [IC_NUM_WAYS-1:0] ecc_write_ways;
logic [IC_INDEX_W-1:0] ecc_write_index;
// Fill buffer signals
logic gnt_or_pmp_err, gnt_not_pmp_err;
logic [$clog2(NUM_FB)-1:0] fb_fill_level;
logic fill_cache_new;
logic fill_new_alloc;
logic fill_spec_req, fill_spec_done, fill_spec_hold;
logic [NUM_FB-1:0][NUM_FB-1:0] fill_older_d, fill_older_q;
logic [NUM_FB-1:0] fill_alloc_sel, fill_alloc;
logic [NUM_FB-1:0] fill_busy_d, fill_busy_q;
logic [NUM_FB-1:0] fill_done;
logic [NUM_FB-1:0] fill_in_ic1;
logic [NUM_FB-1:0] fill_stale_d, fill_stale_q;
logic [NUM_FB-1:0] fill_cache_d, fill_cache_q;
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_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;
logic [NUM_FB-1:0] fill_out_grant;
logic [NUM_FB-1:0][LINE_BEATS_W:0] fill_out_cnt_d, fill_out_cnt_q;
logic [NUM_FB-1:0] fill_out_done;
logic [NUM_FB-1:0] fill_ext_req, fill_rvd_exp, fill_ram_req, fill_out_req;
logic [NUM_FB-1:0] fill_data_sel, fill_data_reg, fill_data_hit, fill_data_rvd;
logic [NUM_FB-1:0][LINE_BEATS_W-1:0] fill_ext_off, fill_rvd_off;
logic [NUM_FB-1:0][LINE_BEATS_W:0] fill_ext_beat, fill_rvd_beat;
logic [NUM_FB-1:0] fill_ext_arb, fill_ram_arb, fill_out_arb;
logic [NUM_FB-1:0] fill_rvd_arb;
logic [NUM_FB-1:0] fill_entry_en;
logic [NUM_FB-1:0] fill_addr_en;
logic [NUM_FB-1:0] fill_way_en;
logic [NUM_FB-1:0][LINE_BEATS-1:0] fill_data_en;
logic [NUM_FB-1:0][LINE_BEATS-1:0] fill_err_d, fill_err_q;
logic [ADDR_W-1:0] fill_addr_q [NUM_FB];
logic [NumWays-1:0] fill_way_q [NUM_FB];
logic [LineSize-1:0] fill_data_d [NUM_FB];
logic [LineSize-1:0] fill_data_q [NUM_FB];
logic [ADDR_W-1:BUS_W] fill_ext_req_addr;
logic [ADDR_W-1:0] fill_ram_req_addr;
logic [NumWays-1:0] fill_ram_req_way;
logic [LineSize-1:0] fill_ram_req_data;
logic [LineSize-1:0] fill_out_data;
logic [LINE_BEATS-1:0] fill_out_err;
logic gnt_or_pmp_err, gnt_not_pmp_err;
logic [$clog2(NUM_FB)-1:0] fb_fill_level;
logic fill_cache_new;
logic fill_new_alloc;
logic fill_spec_req, fill_spec_done, fill_spec_hold;
logic [NUM_FB-1:0][NUM_FB-1:0] fill_older_d, fill_older_q;
logic [NUM_FB-1:0] fill_alloc_sel, fill_alloc;
logic [NUM_FB-1:0] fill_busy_d, fill_busy_q;
logic [NUM_FB-1:0] fill_done;
logic [NUM_FB-1:0] fill_in_ic1;
logic [NUM_FB-1:0] fill_stale_d, fill_stale_q;
logic [NUM_FB-1:0] fill_cache_d, fill_cache_q;
logic [NUM_FB-1:0] fill_hit_ic1, fill_hit_d, fill_hit_q;
logic [NUM_FB-1:0][IC_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_d, fill_ext_done_q;
logic [NUM_FB-1:0][IC_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;
logic [NUM_FB-1:0] fill_out_grant;
logic [NUM_FB-1:0][IC_LINE_BEATS_W:0] fill_out_cnt_d, fill_out_cnt_q;
logic [NUM_FB-1:0] fill_out_done;
logic [NUM_FB-1:0] fill_ext_req, fill_rvd_exp, fill_ram_req, fill_out_req;
logic [NUM_FB-1:0] fill_data_sel, fill_data_reg, fill_data_hit, fill_data_rvd;
logic [NUM_FB-1:0][IC_LINE_BEATS_W-1:0] fill_ext_off, fill_rvd_off;
logic [NUM_FB-1:0][IC_LINE_BEATS_W:0] fill_ext_beat, fill_rvd_beat;
logic [NUM_FB-1:0] fill_ext_arb, fill_ram_arb, fill_out_arb;
logic [NUM_FB-1:0] fill_rvd_arb;
logic [NUM_FB-1:0] fill_entry_en;
logic [NUM_FB-1:0] fill_addr_en;
logic [NUM_FB-1:0] fill_way_en;
logic [NUM_FB-1:0][IC_LINE_BEATS-1:0] fill_data_en;
logic [NUM_FB-1:0][IC_LINE_BEATS-1:0] fill_err_d, fill_err_q;
logic [ADDR_W-1:0] fill_addr_q [NUM_FB];
logic [IC_NUM_WAYS-1:0] fill_way_q [NUM_FB];
logic [IC_LINE_SIZE-1:0] fill_data_d [NUM_FB];
logic [IC_LINE_SIZE-1:0] fill_data_q [NUM_FB];
logic [ADDR_W-1:BUS_W] fill_ext_req_addr;
logic [ADDR_W-1:0] fill_ram_req_addr;
logic [IC_NUM_WAYS-1:0] fill_ram_req_way;
logic [IC_LINE_SIZE-1:0] fill_ram_req_data;
logic [IC_LINE_SIZE-1:0] fill_out_data;
logic [IC_LINE_BEATS-1:0] fill_out_err;
// External req signals
logic instr_req;
logic [ADDR_W-1:BUS_W] instr_addr;
logic instr_req;
logic [ADDR_W-1:BUS_W] instr_addr;
// Data output signals
logic skid_complete_instr;
logic skid_ready;
logic output_compressed;
logic skid_valid_d, skid_valid_q, skid_en;
logic [15:0] skid_data_d, skid_data_q;
logic skid_err_q;
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;
logic [LineSize-1:0] line_data;
logic [LINE_BEATS-1:0] line_err;
logic [31:0] line_data_muxed;
logic line_err_muxed;
logic [31:0] output_data;
logic output_err;
logic skid_complete_instr;
logic skid_ready;
logic output_compressed;
logic skid_valid_d, skid_valid_q, skid_en;
logic [15:0] skid_data_d, skid_data_q;
logic skid_err_q;
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;
logic [IC_LINE_SIZE-1:0] line_data;
logic [IC_LINE_BEATS-1:0] line_err;
logic [31:0] line_data_muxed;
logic line_err_muxed;
logic [31:0] output_data;
logic output_err;
// Invalidations
logic start_inval, inval_done;
logic reset_inval_q;
logic inval_prog_d, inval_prog_q;
logic [INDEX_W-1:0] inval_index_d, inval_index_q;
logic start_inval, inval_done;
logic reset_inval_q;
logic inval_prog_d, inval_prog_q;
logic [IC_INDEX_W-1:0] inval_index_d, inval_index_q;
//////////////////////////
// Instruction prefetch //
@ -230,7 +215,7 @@ module ibex_icache #(
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}}};
assign lookup_addr_aligned = {lookup_addr_ic0[ADDR_W-1:IC_LINE_W], {IC_LINE_W{1'b0}}};
// The prefetch address increments by one cache line for each granted request.
// This address is also updated if there is a branch that is not granted, since the target
@ -239,7 +224,8 @@ module ibex_icache #(
// The captured branch target address is not forced to be aligned since the offset in the cache
// 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}}}) :
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;
@ -263,12 +249,13 @@ module ibex_icache #(
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];
assign lookup_index_ic0 = lookup_addr_ic0[IC_INDEX_HI:IC_LINE_W];
// Cache write
assign fill_req_ic0 = (|fill_ram_req);
assign fill_index_ic0 = fill_ram_req_addr[INDEX_HI:LINE_W];
assign fill_tag_ic0 = {(~inval_prog_q & ~ecc_write_req),fill_ram_req_addr[ADDR_W-1:INDEX_HI+1]};
assign fill_index_ic0 = fill_ram_req_addr[IC_INDEX_HI:IC_LINE_W];
assign fill_tag_ic0 = {(~inval_prog_q & ~ecc_write_req),
fill_ram_req_addr[ADDR_W-1:IC_INDEX_HI+1]};
assign fill_wdata_ic0 = fill_ram_req_data;
// Suppress a new lookup on a not-taken branch (as the address will be incorrect)
@ -289,7 +276,7 @@ module ibex_icache #(
lookup_index_ic0;
assign tag_banks_ic0 = ecc_write_req ? ecc_write_ways :
fill_grant_ic0 ? fill_ram_req_way :
{NumWays{1'b1}};
{IC_NUM_WAYS{1'b1}};
assign tag_write_ic0 = fill_grant_ic0 | inval_prog_q | ecc_write_req;
// Dataram
@ -303,24 +290,24 @@ module ibex_icache #(
// Tagram ECC
// Reuse the same ecc encoding module for larger cache sizes by padding with zeros
logic [21:0] tag_ecc_input_padded;
logic [27:0] tag_ecc_output_padded;
logic [22-TAG_SIZE:0] tag_ecc_output_unused;
logic [21:0] tag_ecc_input_padded;
logic [27:0] tag_ecc_output_padded;
logic [22-IC_TAG_SIZE:0] tag_ecc_output_unused;
assign tag_ecc_input_padded = {{22-TAG_SIZE{1'b0}},fill_tag_ic0};
assign tag_ecc_output_unused = tag_ecc_output_padded[21:TAG_SIZE-1];
assign tag_ecc_input_padded = {{22-IC_TAG_SIZE{1'b0}},fill_tag_ic0};
assign tag_ecc_output_unused = tag_ecc_output_padded[21:IC_TAG_SIZE-1];
prim_secded_28_22_enc tag_ecc_enc (
.in (tag_ecc_input_padded),
.out (tag_ecc_output_padded)
);
assign tag_wdata_ic0 = {tag_ecc_output_padded[27:22],tag_ecc_output_padded[TAG_SIZE-1:0]};
assign tag_wdata_ic0 = {tag_ecc_output_padded[27:22],tag_ecc_output_padded[IC_TAG_SIZE-1:0]};
// Dataram ECC
for (genvar bank = 0; bank < LINE_BEATS; bank ++) begin : gen_ecc_banks
for (genvar bank = 0; bank < IC_LINE_BEATS; bank++) begin : gen_ecc_banks
prim_secded_39_32_enc data_ecc_enc (
.in (fill_wdata_ic0[bank*BusWidth+:BusWidth]),
.in (fill_wdata_ic0[bank*BUS_WIDTH+:BUS_WIDTH]),
.out (data_wdata_ic0[bank*BUS_SIZE_ECC+:BUS_SIZE_ECC])
);
end
@ -334,11 +321,11 @@ module ibex_icache #(
// IC0 -> IC1 //
////////////////
for (genvar way = 0; way < NumWays; way++) begin : gen_rams
for (genvar way = 0; way < IC_NUM_WAYS; way++) begin : gen_rams
// Tag RAM instantiation
prim_ram_1p #(
.Width (TAG_SIZE_ECC),
.Depth (NUM_LINES),
.Depth (IC_NUM_LINES),
.DataBitsPerMask (TAG_SIZE_ECC)
) tag_bank (
.clk_i (clk_i),
@ -353,7 +340,7 @@ module ibex_icache #(
// Data RAM instantiation
prim_ram_1p #(
.Width (LINE_SIZE_ECC),
.Depth (NUM_LINES),
.Depth (IC_NUM_LINES),
.DataBitsPerMask (LINE_SIZE_ECC)
) data_bank (
.clk_i (clk_i),
@ -377,7 +364,7 @@ module ibex_icache #(
always_ff @(posedge clk_i) begin
if (lookup_grant_ic0) begin
lookup_addr_ic1 <= lookup_addr_ic0[ADDR_W-1:INDEX_HI+1];
lookup_addr_ic1 <= lookup_addr_ic0[ADDR_W-1:IC_INDEX_HI+1];
fill_in_ic1 <= fill_alloc_sel;
end
end
@ -387,10 +374,10 @@ module ibex_icache #(
////////////////////////
// Tag matching
for (genvar way = 0; way < NumWays; way++) begin : gen_tag_match
assign tag_match_ic1[way] = (tag_rdata_ic1[way][TAG_SIZE-1:0] ==
{1'b1,lookup_addr_ic1[ADDR_W-1:INDEX_HI+1]});
assign tag_invalid_ic1[way] = ~tag_rdata_ic1[way][TAG_SIZE-1];
for (genvar way = 0; way < IC_NUM_WAYS; way++) begin : gen_tag_match
assign tag_match_ic1[way] = (tag_rdata_ic1[way][IC_TAG_SIZE-1:0] ==
{1'b1,lookup_addr_ic1[ADDR_W-1:IC_INDEX_HI+1]});
assign tag_invalid_ic1[way] = ~tag_rdata_ic1[way][IC_TAG_SIZE-1];
end
assign tag_hit_ic1 = |tag_match_ic1;
@ -398,7 +385,7 @@ module ibex_icache #(
// Hit data mux
always_comb begin
hit_data_ecc_ic1 = 'b0;
for (int way = 0; way < NumWays; way++) begin
for (int way = 0; way < IC_NUM_WAYS; way++) begin
if (tag_match_ic1[way]) begin
hit_data_ecc_ic1 |= data_rdata_ic1[way];
end
@ -409,15 +396,15 @@ module ibex_icache #(
// 1 first invalid way
// 2 global round-robin (pseudorandom) way
assign lowest_invalid_way_ic1[0] = tag_invalid_ic1[0];
assign round_robin_way_ic1[0] = round_robin_way_q[NumWays-1];
for (genvar way = 1; way < NumWays; way++) begin : gen_lowest_way
assign round_robin_way_ic1[0] = round_robin_way_q[IC_NUM_WAYS-1];
for (genvar way = 1; way < IC_NUM_WAYS; way++) begin : gen_lowest_way
assign lowest_invalid_way_ic1[way] = tag_invalid_ic1[way] & ~|tag_invalid_ic1[way-1:0];
assign round_robin_way_ic1[way] = round_robin_way_q[way-1];
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
round_robin_way_q <= {{NumWays-1{1'b0}},1'b1};
round_robin_way_q <= {{IC_NUM_WAYS-1{1'b0}}, 1'b1};
end else if (lookup_valid_ic1) begin
round_robin_way_q <= round_robin_way_ic1;
end
@ -428,21 +415,21 @@ module ibex_icache #(
// ECC checking logic
if (ICacheECC) begin : gen_data_ecc_checking
logic [NumWays-1:0] tag_err_ic1;
logic [LINE_BEATS*2-1:0] data_err_ic1;
logic ecc_correction_write_d, ecc_correction_write_q;
logic [NumWays-1:0] ecc_correction_ways_d, ecc_correction_ways_q;
logic [INDEX_W-1:0] lookup_index_ic1, ecc_correction_index_q;
logic [IC_NUM_WAYS-1:0] tag_err_ic1;
logic [IC_LINE_BEATS*2-1:0] data_err_ic1;
logic ecc_correction_write_d, ecc_correction_write_q;
logic [IC_NUM_WAYS-1:0] ecc_correction_ways_d, ecc_correction_ways_q;
logic [IC_INDEX_W-1:0] lookup_index_ic1, ecc_correction_index_q;
// Tag ECC checking
for (genvar way = 0; way < NumWays; way++) begin : gen_tag_ecc
for (genvar way = 0; way < IC_NUM_WAYS; way++) begin : gen_tag_ecc
logic [1:0] tag_err_bank_ic1;
logic [27:0] tag_rdata_padded_ic1;
// Expand the tag rdata with extra padding if the tag size is less than the maximum
assign tag_rdata_padded_ic1 = {tag_rdata_ic1[way][TAG_SIZE_ECC-1-:6],
{22-TAG_SIZE{1'b0}},
tag_rdata_ic1[way][TAG_SIZE-1:0]};
{22-IC_TAG_SIZE{1'b0}},
tag_rdata_ic1[way][IC_TAG_SIZE-1:0]};
prim_secded_28_22_dec data_ecc_dec (
.in (tag_rdata_padded_ic1),
@ -455,7 +442,7 @@ module ibex_icache #(
// Data ECC checking
// Note - could generate for all ways and mux after
for (genvar bank = 0; bank < LINE_BEATS; bank++) begin : gen_ecc_banks
for (genvar bank = 0; bank < IC_LINE_BEATS; bank++) begin : gen_ecc_banks
prim_secded_39_32_dec data_ecc_dec (
.in (hit_data_ecc_ic1[bank*BUS_SIZE_ECC+:BUS_SIZE_ECC]),
.d_o (),
@ -463,7 +450,8 @@ module ibex_icache #(
.err_o (data_err_ic1[bank*2+:2])
);
assign hit_data_ic1[bank*BusWidth+:BusWidth] = hit_data_ecc_ic1[bank*BUS_SIZE_ECC+:BusWidth];
assign hit_data_ic1[bank*BUS_WIDTH+:BUS_WIDTH] =
hit_data_ecc_ic1[bank*BUS_SIZE_ECC+:BUS_WIDTH];
end
@ -473,8 +461,8 @@ module ibex_icache #(
// All ways will be invalidated on a tag error to prevent X-propagation from data_err_ic1 on
// spurious hits. Also prevents the same line being allocated twice when there was a true
// hit and a spurious hit.
assign ecc_correction_ways_d = {NumWays{|tag_err_ic1}} |
(tag_match_ic1 & {NumWays{|data_err_ic1}});
assign ecc_correction_ways_d = {IC_NUM_WAYS{|tag_err_ic1}} |
(tag_match_ic1 & {IC_NUM_WAYS{|data_err_ic1}});
assign ecc_correction_write_d = ecc_err_ic1;
always_ff @(posedge clk_i or negedge rst_ni) begin
@ -488,7 +476,7 @@ module ibex_icache #(
// The index is required in IC1 only when ECC is configured so is registered here
always_ff @(posedge clk_i) begin
if (lookup_grant_ic0) begin
lookup_index_ic1 <= lookup_addr_ic0[INDEX_HI-:INDEX_W];
lookup_index_ic1 <= lookup_addr_ic0[IC_INDEX_HI-:IC_INDEX_W];
end
end
@ -620,17 +608,17 @@ module ibex_icache #(
// Make an external request
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)
// Count the number of completed external requests (each line requires IC_LINE_BEATS requests)
// Don't count fake PMP error grants here since they will never receive an rvalid response
assign fill_ext_cnt_d[fb] = fill_alloc[fb] ?
{{LINE_BEATS_W{1'b0}},fill_spec_done} :
(fill_ext_cnt_q[fb] + {{LINE_BEATS_W{1'b0}},
{{IC_LINE_BEATS_W{1'b0}},fill_spec_done} :
(fill_ext_cnt_q[fb] + {{IC_LINE_BEATS_W{1'b0}},
fill_ext_arb[fb] & gnt_not_pmp_err});
// External request must be held until granted
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_d[fb] = (fill_ext_cnt_q[fb][LINE_BEATS_W] |
assign fill_ext_done_d[fb] = (fill_ext_cnt_q[fb][IC_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
@ -638,7 +626,7 @@ module ibex_icache #(
// cancel if the line won't be cached and, it is stale
(~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]))) &
fill_ext_beat[fb][IC_LINE_BEATS_W]))) &
// can't cancel while we are waiting for a grant on the bus
~fill_ext_hold_q[fb] & fill_busy_q[fb];
// Track whether this fill buffer expects to receive beats of data
@ -646,7 +634,7 @@ module ibex_icache #(
// Count the number of rvalid beats received
assign fill_rvd_cnt_d[fb] = fill_alloc[fb] ? '0 :
(fill_rvd_cnt_q[fb] +
{{LINE_BEATS_W{1'b0}},fill_rvd_arb[fb]});
{{IC_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_q[fb] & ~fill_ext_hold_q[fb]) &
(fill_rvd_cnt_q[fb] == fill_ext_cnt_q[fb]);
@ -664,25 +652,25 @@ module ibex_icache #(
// - Data is available from the bus this cycle (fill_rvd_arb)
assign fill_out_req[fb] = fill_busy_q[fb] & ~fill_stale_q[fb] & ~fill_out_done[fb] &
(fill_hit_ic1[fb] | fill_hit_q[fb] |
(fill_err_q[fb][fill_out_cnt_q[fb][LINE_BEATS_W-1:0]]) |
(fill_err_q[fb][fill_out_cnt_q[fb][IC_LINE_BEATS_W-1:0]]) |
(fill_rvd_beat[fb] > fill_out_cnt_q[fb]) | fill_rvd_arb[fb]);
// Calculate when a beat of data is output. Any ECC error squashes the output that cycle.
assign fill_out_grant[fb] = fill_out_arb[fb] & output_ready;
// Count the beats of data output to the IF stage
assign fill_out_cnt_d[fb] = fill_alloc[fb] ? {1'b0,lookup_addr_ic0[LINE_W-1:BUS_W]} :
assign fill_out_cnt_d[fb] = fill_alloc[fb] ? {1'b0,lookup_addr_ic0[IC_LINE_W-1:BUS_W]} :
(fill_out_cnt_q[fb] +
{{LINE_BEATS_W{1'b0}},fill_out_grant[fb]});
{{IC_LINE_BEATS_W{1'b0}},fill_out_grant[fb]});
// Data output complete when the counter fills
assign fill_out_done[fb] = fill_out_cnt_q[fb][LINE_BEATS_W];
assign fill_out_done[fb] = fill_out_cnt_q[fb][IC_LINE_BEATS_W];
//////////////////////////////////////
// Fill buffer ram request tracking //
//////////////////////////////////////
// make a fill request once all data beats received
assign fill_ram_req[fb] = fill_busy_q[fb] & fill_rvd_cnt_q[fb][LINE_BEATS_W] &
assign fill_ram_req[fb] = fill_busy_q[fb] & fill_rvd_cnt_q[fb][IC_LINE_BEATS_W] &
// unless the request hit, was non-allocating or got an error
~fill_hit_q[fb] & fill_cache_q[fb] & ~|fill_err_q[fb] &
// or the request was already completed
@ -697,12 +685,12 @@ module ibex_icache #(
// When we branch into the middle of a line, the output count will not start from zero. This
// beat count is used to know which incoming rdata beats are relevant.
assign fill_ext_beat[fb] = {1'b0,fill_addr_q[fb][LINE_W-1:BUS_W]} +
fill_ext_cnt_q[fb][LINE_BEATS_W:0];
assign fill_ext_off[fb] = fill_ext_beat[fb][LINE_BEATS_W-1:0];
assign fill_rvd_beat[fb] = {1'b0,fill_addr_q[fb][LINE_W-1:BUS_W]} +
fill_rvd_cnt_q[fb][LINE_BEATS_W:0];
assign fill_rvd_off[fb] = fill_rvd_beat[fb][LINE_BEATS_W-1:0];
assign fill_ext_beat[fb] = {1'b0,fill_addr_q[fb][IC_LINE_W-1:BUS_W]} +
fill_ext_cnt_q[fb][IC_LINE_BEATS_W:0];
assign fill_ext_off[fb] = fill_ext_beat[fb][IC_LINE_BEATS_W-1:0];
assign fill_rvd_beat[fb] = {1'b0,fill_addr_q[fb][IC_LINE_W-1:BUS_W]} +
fill_rvd_cnt_q[fb][IC_LINE_BEATS_W:0];
assign fill_rvd_off[fb] = fill_rvd_beat[fb][IC_LINE_BEATS_W-1:0];
/////////////////////////////
// Fill buffer arbitration //
@ -796,19 +784,20 @@ module ibex_icache #(
// Data either comes from the cache or the bus. If there was an ECC error, we must take
// the incoming bus data since the cache hit data is corrupted.
assign fill_data_d[fb] = fill_hit_ic1[fb] ? hit_data_ic1 :
{LINE_BEATS{instr_rdata_i}};
{IC_LINE_BEATS{instr_rdata_i}};
for (genvar b = 0; b < LINE_BEATS; b++) begin : gen_data_buf
for (genvar b = 0; b < IC_LINE_BEATS; b++) begin : gen_data_buf
// Error tracking (per beat)
// Either a PMP error on a speculative request,
assign fill_err_d[fb][b] = (instr_pmp_err_i & fill_alloc[fb] & fill_spec_req &
(lookup_addr_ic0[LINE_W-1:BUS_W] == b[LINE_BEATS_W-1:0])) |
(lookup_addr_ic0[IC_LINE_W-1:BUS_W] ==
b[IC_LINE_BEATS_W-1:0])) |
// a PMP error on a fill buffer ext req
(instr_pmp_err_i & fill_ext_arb[fb] &
(fill_ext_off[fb] == b[LINE_BEATS_W-1:0])) |
(fill_ext_off[fb] == b[IC_LINE_BEATS_W-1:0])) |
// Or a data error with instr_rvalid_i
(fill_rvd_arb[fb] & instr_err_i &
(fill_rvd_off[fb] == b[LINE_BEATS_W-1:0])) |
(fill_rvd_off[fb] == b[IC_LINE_BEATS_W-1:0])) |
// Hold the error once recorded
(fill_busy_q[fb] & fill_err_q[fb][b]);
@ -824,11 +813,11 @@ module ibex_icache #(
// Ignore incoming rvalid data when we already have cache hit data
assign fill_data_en[fb][b] = fill_hit_ic1[fb] |
(fill_rvd_arb[fb] & ~fill_hit_q[fb] &
(fill_rvd_off[fb] == b[LINE_BEATS_W-1:0]));
(fill_rvd_off[fb] == b[IC_LINE_BEATS_W-1:0]));
always_ff @(posedge clk_i) begin
if (fill_data_en[fb][b]) begin
fill_data_q[fb][b*BusWidth+:BusWidth] <= fill_data_d[fb][b*BusWidth+:BusWidth];
fill_data_q[fb][b*BUS_WIDTH+:BUS_WIDTH] <= fill_data_d[fb][b*BUS_WIDTH+:BUS_WIDTH];
end
end
@ -844,7 +833,7 @@ module ibex_icache #(
fill_ext_req_addr = '0;
for (int i = 0; i < NUM_FB; i++) begin
if (fill_ext_arb[i]) begin
fill_ext_req_addr |= {fill_addr_q[i][ADDR_W-1:LINE_W], fill_ext_off[i]};
fill_ext_req_addr |= {fill_addr_q[i][ADDR_W-1:IC_LINE_W], fill_ext_off[i]};
end
end
end
@ -871,7 +860,7 @@ module ibex_icache #(
if (fill_data_reg[i]) begin
fill_out_data |= fill_data_q[i];
// Ignore any speculative errors accumulated on cache hits
fill_out_err |= (fill_err_q[i] & ~{LINE_BEATS{fill_hit_q[i]}});
fill_out_err |= (fill_err_q[i] & ~{IC_LINE_BEATS{fill_hit_q[i]}});
end
end
end
@ -895,16 +884,16 @@ module ibex_icache #(
// Mux between line-width data sources
assign line_data = |fill_data_hit ? hit_data_ic1 : fill_out_data;
assign line_err = |fill_data_hit ? {LINE_BEATS{1'b0}} : fill_out_err;
assign line_err = |fill_data_hit ? {IC_LINE_BEATS{1'b0}} : fill_out_err;
// Mux the relevant beat of line data, based on the output address
always_comb begin
line_data_muxed = '0;
line_err_muxed = 1'b0;
for (int i = 0; i < LINE_BEATS; i++) begin
for (int i = 0; i < IC_LINE_BEATS; i++) begin
// When data has been skidded, the output address is behind by one
if ((output_addr_q[LINE_W-1:BUS_W] + {{LINE_BEATS_W-1{1'b0}},skid_valid_q}) ==
i[LINE_BEATS_W-1:0]) begin
if ((output_addr_q[IC_LINE_W-1:BUS_W] + {{IC_LINE_BEATS_W-1{1'b0}},skid_valid_q}) ==
i[IC_LINE_BEATS_W-1:0]) begin
line_data_muxed |= line_data[i*32+:32];
line_err_muxed |= line_err[i];
end
@ -994,14 +983,14 @@ module ibex_icache #(
end
end
// Mux the data from BusWidth to halfword
// Mux the data from BUS_WIDTH to halfword
// This muxing realigns data when instruction words are split across BUS_W e.g.
// word 1 |----|*h1*|
// word 0 |*h0*|----| --> |*h1*|*h0*|
// 31 15 0 31 15 0
always_comb begin
output_data_lo = '0;
for (int i = 0; i < OUTPUT_BEATS; i++) begin
for (int i = 0; i < IC_OUTPUT_BEATS; i++) begin
if (output_addr_q[BUS_W-1:1] == i[BUS_W-2:0]) begin
output_data_lo |= output_data[i*16+:16];
end
@ -1010,7 +999,7 @@ module ibex_icache #(
always_comb begin
output_data_hi = '0;
for (int i = 0; i < OUTPUT_BEATS-1; i++) begin
for (int i = 0; i < IC_OUTPUT_BEATS-1; i++) begin
if (output_addr_q[BUS_W-1:1] == i[BUS_W-2:0]) begin
output_data_hi |= output_data[(i+1)*16+:16];
end
@ -1038,7 +1027,7 @@ module ibex_icache #(
assign inval_prog_d = start_inval | (inval_prog_q & ~inval_done);
assign inval_done = &inval_index_q;
assign inval_index_d = start_inval ? '0 :
(inval_index_q + {{INDEX_W-1{1'b0}},1'b1});
(inval_index_q + {{IC_INDEX_W-1{1'b0}},1'b1});
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
@ -1068,11 +1057,11 @@ module ibex_icache #(
// Assertions //
////////////////
`ASSERT_INIT(size_param_legal, (LineSize > 32))
`ASSERT_INIT(size_param_legal, (IC_LINE_SIZE > 32))
// ECC primitives will need to be changed for different sizes
`ASSERT_INIT(ecc_tag_param_legal, (TAG_SIZE <= 27))
`ASSERT_INIT(ecc_data_param_legal, !ICacheECC || (BusWidth == 32))
`ASSERT_INIT(ecc_tag_param_legal, (IC_TAG_SIZE <= 27))
`ASSERT_INIT(ecc_data_param_legal, !ICacheECC || (BUS_WIDTH == 32))
// Lookups in the tag ram should always give a known result
`ASSERT_KNOWN(TagHitKnown, lookup_valid_ic1 & tag_hit_ic1)

View file

@ -311,6 +311,24 @@ typedef enum logic [2:0] {
DBG_CAUSE_STEP = 3'h4
} dbg_cause_e;
// ICache constants
parameter int unsigned ADDR_W = 32;
parameter int unsigned BUS_SIZE = 32;
parameter int unsigned BUS_BYTES = BUS_SIZE/8;
parameter int unsigned BUS_W = $clog2(BUS_BYTES);
parameter int unsigned IC_SIZE_BYTES = 4096;
parameter int unsigned IC_NUM_WAYS = 2;
parameter int unsigned IC_LINE_SIZE = 64;
parameter int unsigned IC_LINE_BYTES = IC_LINE_SIZE/8;
parameter int unsigned IC_LINE_W = $clog2(IC_LINE_BYTES);
parameter int unsigned IC_NUM_LINES = IC_SIZE_BYTES / IC_NUM_WAYS / IC_LINE_BYTES;
parameter int unsigned IC_LINE_BEATS = IC_LINE_BYTES / BUS_BYTES;
parameter int unsigned IC_LINE_BEATS_W = $clog2(IC_LINE_BEATS);
parameter int unsigned IC_INDEX_W = $clog2(IC_NUM_LINES);
parameter int unsigned IC_INDEX_HI = IC_INDEX_W + IC_LINE_W - 1;
parameter int unsigned IC_TAG_SIZE = ADDR_W - IC_INDEX_W - IC_LINE_W + 1; // 1 valid bit
parameter int unsigned IC_OUTPUT_BEATS = (BUS_BYTES / 2); // number of halfwords
// PMP constants
parameter int unsigned PMP_MAX_REGIONS = 16;
parameter int unsigned PMP_CFG_W = 8;