Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PLRU eviction to L0 and L1 #9

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/snitch_icache.sv
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ module snitch_icache import snitch_icache_pkg::*; #(
EARLY_LATCH: EARLY_LATCH,
BUFFER_LOOKUP: 0,
GUARANTEE_ORDERING: 0,
L0_PLRU: 1,
L1_PLRU: 1,

FETCH_ALIGN: $clog2(FETCH_DW/8),
FILL_ALIGN: $clog2(FILL_DW/8),
Expand Down
63 changes: 53 additions & 10 deletions src/snitch_icache_handler.sv
Original file line number Diff line number Diff line change
Expand Up @@ -242,19 +242,62 @@ module snitch_icache_handler #(
end
end

// The cache line eviction LFSR is responsible for picking a cache line for
// replacement at random. Note that we assume that the entire cache is full,
// so no empty cache lines are available. This is the common case since we
// do not support flushing of the cache.
logic [CFG.SET_ALIGN-1:0] evict_index;
logic evict_enable;

snitch_icache_lfsr #(CFG.SET_ALIGN) i_evict_lfsr (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.value_o ( evict_index ),
.enable_i ( evict_enable )
);
if ( CFG.L1_PLRU ) begin : gen_plru

logic [CFG.LINE_COUNT-1:0][CFG.WAY_COUNT-1:0] used_masks;
logic [CFG.LINE_COUNT-1:0][CFG.WAY_COUNT-1:0] evict_masks;

always_comb begin
used_masks = '0;
if (in_req_valid_i && in_req_hit_i) begin
// hit update
used_masks[in_req_addr_i >> CFG.LINE_ALIGN][in_req_set_i] = 1'b1;
end else if (write_valid_o) begin
// refill update
used_masks[write_addr_o][write_set_o] = 1'b1;
end
end

for (genvar i = 0; i < CFG.LINE_COUNT; i++) begin : gen_plru_tree

plru_tree #(
.ENTRIES ( CFG.WAY_COUNT )
) i_plru_tree (
.clk_i,
.rst_ni,

.used_i ( used_masks [i] ),
.plru_o ( evict_masks[i] )
);

end

onehot_to_bin #(
.ONEHOT_WIDTH ( CFG.WAY_COUNT )
) i_evict_mask_to_index (
.onehot ( evict_masks[write_addr_o] ),
.bin ( evict_index )
);

end else begin : gen_lfsr

// The cache line eviction LFSR is responsible for picking a cache line for
// replacement at random. Note that we assume that the entire cache is full,
// so no empty cache lines are available. This is the common case since we
// do not support flushing of the cache.
snitch_icache_lfsr #(
.N (CFG.SET_ALIGN)
) i_evict_lfsr (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.value_o ( evict_index ),
.enable_i ( evict_enable )
);

end

// The response handler deals with incoming refill responses. It queries and
// clears the corresponding entry in the pending table, stores the data in
Expand Down
63 changes: 46 additions & 17 deletions src/snitch_icache_l0.sv
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ module snitch_icache_l0 import snitch_icache_pkg::*; #(
logic [CFG.L0_LINE_COUNT-1:0] evict_strb;
logic [CFG.L0_LINE_COUNT-1:0] flush_strb;
logic [CFG.L0_LINE_COUNT-1:0] validate_strb;
logic [CFG.L0_LINE_COUNT-1:0] next_evict;

typedef struct packed {
logic vld;
Expand Down Expand Up @@ -201,21 +202,49 @@ module snitch_icache_l0 import snitch_icache_pkg::*; #(
// -------
// Evictor
// -------
logic [$clog2(CFG.L0_LINE_COUNT)-1:0] cnt_d, cnt_q;

always_comb begin : evictor
evict_strb = '0;
cnt_d = cnt_q;

// Round-Robin
if (evict_req) begin
evict_strb = 1 << cnt_q;
cnt_d = cnt_q + 1;
if (evict_strb == hit_early) begin
evict_strb = 1 << cnt_d;
cnt_d = cnt_q + 2;

if (CFG.L0_PLRU) begin : gen_plru

logic [CFG.L0_LINE_COUNT-1:0] hit_plru;
logic [CFG.L0_LINE_COUNT-1:0] evict_plru;

// Update plru on hit and on miss eviction, prefetch only once fetch hits
assign hit_plru = hit | (evict_because_miss ? evict_strb : '0);
assign evict_strb = evict_req ? evict_plru : '0;
assign next_evict = evict_plru;

plru_tree #(
.ENTRIES(CFG.L0_LINE_COUNT)
) i_plru_tree (
.clk_i,
.rst_ni,
.used_i ( hit_plru ),
.plru_o ( evict_plru )
);

end else begin : gen_round_robin

assign next_evict = '0;

logic [$clog2(CFG.L0_LINE_COUNT)-1:0] cnt_d, cnt_q;

always_comb begin : evictor
evict_strb = '0;
cnt_d = cnt_q;

// Round-Robin
if (evict_req) begin
evict_strb = 1 << cnt_q;
cnt_d = cnt_q + 1;
if (evict_strb == hit_early) begin
evict_strb = 1 << cnt_d;
cnt_d = cnt_q + 2;
end
Comment on lines +239 to +242
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure to never evict the currently used cache line: pulp-platform/snitch#69

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a check to prevent the prefetch if the current line is being fetched (on the last commit on the branch), however I did not synthesize thus don't know the full timing implications.

end
end

`FF(cnt_q, cnt_d, '0)

end

always_comb begin : flush
Expand All @@ -230,8 +259,6 @@ module snitch_icache_l0 import snitch_icache_pkg::*; #(
if (flush_valid_i) flush_strb = '1;
end

`FF(cnt_q, cnt_d, '0)

// -------------
// Miss Handling
// -------------
Expand Down Expand Up @@ -287,10 +314,12 @@ module snitch_icache_l0 import snitch_icache_pkg::*; #(
// Pre-fetching
// -------------
// Generate a prefetch request if the cache hits and we haven't
// pre-fetched the line yet and there is no other refill in progress.
// pre-fetched the line yet and there is no other refill in progress
// and the current hit won't be evicted.
assign prefetcher_out.vld = enable_prefetching_i &
hit_any & ~hit_prefetch_any &
hit_early_is_onehot & ~pending_refill_q;
hit_early_is_onehot & ~pending_refill_q &
~|(next_evict & hit_early);

localparam int unsigned FetchPkts = CFG.LINE_WIDTH/32;
logic [FetchPkts-1:0] is_branch_taken;
Expand Down
2 changes: 2 additions & 0 deletions src/snitch_icache_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ package snitch_icache_pkg;
bit EARLY_LATCH;
bit BUFFER_LOOKUP;
bit GUARANTEE_ORDERING;
bit L0_PLRU;
bit L1_PLRU;

// Derived values.
int unsigned FETCH_ALIGN;
Expand Down
2 changes: 2 additions & 0 deletions src/snitch_read_only_cache.sv
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ module snitch_read_only_cache import snitch_icache_pkg::*; #(
EARLY_LATCH: 0, // Unused here
BUFFER_LOOKUP: 1, // Mandatory here
GUARANTEE_ORDERING: 1, // Mandatory here
L0_PLRU: 0, // Unused here
L1_PLRU: 1,

FETCH_ALIGN: $clog2(AxiDataWidth/8),
FILL_ALIGN: $clog2(AxiDataWidth/8),
Expand Down
2 changes: 2 additions & 0 deletions test/snitch_icache_l0_tb.sv
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ module snitch_icache_l0_tb #(
EARLY_LATCH: EARLY_LATCH,
BUFFER_LOOKUP: BUFFER_LOOKUP,
GUARANTEE_ORDERING: GUARANTEE_ORDERING,
L0_PLRU: 1'b1,
L1_PLRU: 1'b1,

FETCH_ALIGN: $clog2(FETCH_DW/8),
FILL_ALIGN: $clog2(FILL_DW/8),
Expand Down
Loading