Skip to content

Commit

Permalink
Proj 294 monitor invalidation collision in cache ctrl (#36)
Browse files Browse the repository at this point in the history
* Add colliding_clean logic to cache_ctrl

* Add scoreboard updates to match RTL changes in PROJ-294

* Add comment and assertion in cache_ctrl
  • Loading branch information
maxbjurling authored Nov 20, 2023
1 parent 237af71 commit 0d62603
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 82 deletions.
87 changes: 57 additions & 30 deletions core/cache_subsystem/cache_ctrl.sv
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ module cache_ctrl import ariane_pkg::*; import std_cache_pkg::*; #(
input logic mshr_addr_matches_i,
input logic mshr_index_matches_i,
// to/from snoop controller
input logic snoop_invalidate_i,
input logic [63:0] snoop_invalidate_addr_i,
input readshared_done_t readshared_done_i,
output logic updating_cache_o
);
Expand Down Expand Up @@ -92,6 +94,8 @@ module cache_ctrl import ariane_pkg::*; import std_cache_pkg::*; #(
logic [DCACHE_SET_ASSOC-1:0] shared_way_d, shared_way_q;
logic colliding_read_d, colliding_read_q;
logic sample_readshared_d, sample_readshared_q;
logic colliding_clean_d, colliding_clean_q;


mem_req_t mem_req_d, mem_req_q;

Expand Down Expand Up @@ -145,6 +149,7 @@ module cache_ctrl import ariane_pkg::*; import std_cache_pkg::*; #(

sample_readshared_d = sample_readshared_q;
colliding_read_d = colliding_read_q;
colliding_clean_d = colliding_clean_q;

case (state_q)

Expand Down Expand Up @@ -333,42 +338,62 @@ module cache_ctrl import ariane_pkg::*; import std_cache_pkg::*; #(

// ~> we are here as we need a second round of memory access for a store
STORE_REQ: begin
if (snoop_invalidate_i && !colliding_clean_q) begin
colliding_clean_d = (snoop_invalidate_addr_i[DCACHE_TAG_WIDTH+DCACHE_INDEX_WIDTH-1:DCACHE_BYTE_OFFSET] == {mem_req_q.tag, mem_req_q.index[DCACHE_INDEX_WIDTH-1:DCACHE_BYTE_OFFSET]});
end

// check if the MSHR still doesn't match
mshr_addr_o = {mem_req_q.tag, mem_req_q.index};

// We need to re-check for MSHR aliasing here as the store requires at least
// two memory look-ups on a single-ported SRAM and therefore is non-atomic
if (!mshr_index_matches_i) begin
updating_cache_o = 1'b1;
// store data, write dirty bit
req_o = hit_way_q;
addr_o = mem_req_q.index;
we_o = 1'b1;

// set the correct byte enable
be_o.data[cl_offset>>3 +: 8] = mem_req_q.be;
for (int unsigned i = 0; i < DCACHE_SET_ASSOC; i++) begin
if (hit_way_q[i]) be_o.vldrty[i] = '{valid: 1, shared: 1, dirty: be_o.data};
end
data_o.data[cl_offset +: 64] = mem_req_q.wdata;
// ~> change the state
data_o.dirty[cl_offset>>3 +: 8] = mem_req_q.be;
data_o.valid = 1'b1;
data_o.shared = 1'b0;

// got a grant ~> this is finished if there has not been a colliding readshared request during a makeunique+write, otherwise redo a CleanUnique
if (gnt_i) begin
if (colliding_read_q) begin
colliding_read_d = 1'b0;
state_d = MAKE_UNIQUE;
if (mshr_index_matches_i) begin
// We need to re-check for MSHR aliasing here as the store requires at least
// two memory look-ups on a single-ported SRAM and therefore is non-atomic
state_d = WAIT_MSHR;
end else begin
if (colliding_clean_q) begin
// Cache was invalidated while waiting for access. Restart request.
// Note: there is no need to check colliding_clean_d too since it will only be high when the
// snoop controller is updating the cache -> gnt_i will be low
req_o = '1;
addr_o = mem_req_q.index;
if (gnt_i) begin
state_d = WAIT_TAG_SAVED;
colliding_clean_d = 1'b0;
colliding_read_d = 1'b0;
end
else begin
req_port_o.data_gnt = 1'b1;
state_d = IDLE;
end else begin
if (colliding_read_q) begin
// there has been a colliding readshared request during a makeunique+write; redo CleanUnique
colliding_read_d = 1'b0;
colliding_clean_d = 1'b0;
state_d = MAKE_UNIQUE;
end else begin
updating_cache_o = 1'b1;
// store data, write dirty bit
req_o = hit_way_q;
addr_o = mem_req_q.index;
we_o = 1'b1;
// set the correct byte enable
be_o.data[cl_offset>>3 +: 8] = mem_req_q.be;
for (int unsigned i = 0; i < DCACHE_SET_ASSOC; i++) begin
if (hit_way_q[i]) be_o.vldrty[i] = '{valid: 1, shared: 1, dirty: be_o.data};
end
data_o.data[cl_offset +: 64] = mem_req_q.wdata;
// ~> change the state
data_o.dirty[cl_offset>>3 +: 8] = mem_req_q.be;
data_o.valid = 1'b1;
data_o.shared = 1'b0;
// got a grant ~> this is finished
if (gnt_i) begin
req_port_o.data_gnt = 1'b1;
state_d = IDLE;
colliding_read_d = 1'b0;
colliding_clean_d = 1'b0;
a_colliding_clean : assert (!colliding_clean_d) else $error("Unexpected colliding_clean_d");
a_colliding_read : assert (!colliding_read_d) else $error("Unexpected colliding_read_d");
end
end
end
end else begin
state_d = WAIT_MSHR;
end
end // case: STORE_REQ

Expand Down Expand Up @@ -499,13 +524,15 @@ module cache_ctrl import ariane_pkg::*; import std_cache_pkg::*; #(
hit_way_q <= '0;
shared_way_q <= '0;
colliding_read_q <= 1'b0;
colliding_clean_q <= 1'b0;
sample_readshared_q <= 1'b0;
end else begin
state_q <= state_d;
mem_req_q <= mem_req_d;
hit_way_q <= hit_way_d;
shared_way_q <= shared_way_d;
colliding_read_q <= colliding_read_d;
colliding_clean_q <= colliding_clean_d;
sample_readshared_q <= sample_readshared_d;
end
end
Expand Down
2 changes: 2 additions & 0 deletions core/cache_subsystem/std_nbdcache.sv
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ import std_cache_pkg::*;
.mshr_addr_matches_i ( mshr_addr_matches [i-1] ),
.mshr_index_matches_i ( mshr_index_matches[i-1] ),

.snoop_invalidate_i ( invalidate ),
.snoop_invalidate_addr_i ( invalidate_addr ),
.readshared_done_i ( readshared_done ),
.updating_cache_o ( updating_cache [i] ),
.*
Expand Down
107 changes: 55 additions & 52 deletions corev_apu/tb/tb_std_cache_subsystem/hdl/tb_std_cache_subsystem_pkg.sv
Original file line number Diff line number Diff line change
Expand Up @@ -1696,6 +1696,13 @@ package tb_std_cache_subsystem_pkg;
$error("%s.update_cache_from_req:: Timeout while waiting for grant for dcache req : %s", name, req.print_me());
break;
end
if (hit && !isHit(addr_v)) begin
$display("%t ns %s.update_cache_from_req: hit status changed from hit to miss, calling do_miss for req : %s", $time, name, req.print_me());
hit = 0;
req.insert_readback = 0;
do_miss(req);
end

end
$display("%t ns %s.update_cache_from_req: got grant for dcache req : %s", $time, name, req.print_me());
dut_way = one_hot_to_bin(gnt_vif.get_way(.use_be(req_t.prio==0)));
Expand Down Expand Up @@ -2046,17 +2053,53 @@ package tb_std_cache_subsystem_pkg;
ace_ac_beat_t ac = new();
msg.update_cache = 1'b1;

if (redo_hit == 1'b1) begin
// The timing is a bit different when redoing hit - compensate for it here
@(posedge sram_vif.clk);
end

while (gnt_vif.req[msg.prio] && (!gnt_vif.rd_gnt[msg.prio])) begin
$display("%t ns %s.do_hit: wait for cache grant for message : %s", $time, name, msg.print_me());
@(posedge sram_vif.clk); // skip cycles without grant
// wait for possible MSHR match
while (gnt_vif.mshr_match[msg.port_idx]) begin
mshr_match = 1;
if (cnt == 0 || verbosity > 0) begin
$display("%t ns %s.do_hit: wait for MSHR match for message : %s", $time, name, msg.print_me());
end
@(posedge sram_vif.clk);
cnt++;
if (cnt > cache_msg_timeout) begin
$error("%s : Timeout while waiting for cache grant for message : %s", name, msg.print_me());
$error("%s.do_hit : Timeout while waiting for MSHR match for message : %s", name, msg.print_me());
break;
end
if (!gnt_vif.mshr_match[msg.port_idx]) begin
// if there was an MHSR match we need to get cache grant again
$display("%t ns %s.do_hit: MSHR match ended, wait for cache grant for message : %s", $time, name, msg.print_me());
while (!gnt_vif.rd_gnt[msg.prio]) begin
@(posedge sram_vif.clk); // skip cycles without grant
cnt++;
if (cnt > cache_msg_timeout) begin
$error("%s : Timeout while waiting for cache grant for message : %s", name, msg.print_me());
break;
end
end
$display("%t ns %s.do_hit: got cache grant for message : %s", $time, name, msg.print_me());
@(posedge sram_vif.clk); // wait one more cycle before reading cache status
end
end

if (mshr_match) begin
$display("%t ns %s.do_hit: MSHR match ended and got grant for message : %s", $time, name, msg.print_me());
end else begin
while (gnt_vif.req[msg.prio] && (!gnt_vif.rd_gnt[msg.prio])) begin
$display("%t ns %s.do_hit: wait for cache grant for message : %s", $time, name, msg.print_me());
@(posedge sram_vif.clk); // skip cycles without grant
cnt++;
if (cnt > cache_msg_timeout) begin
$error("%s : Timeout while waiting for cache grant for message : %s", name, msg.print_me());
break;
end
end
$display("%t ns %s.do_hit: got cache grant for message : %s", $time, name, msg.print_me());
end
$display("%t ns %s.do_hit: got cache grant for message : %s", $time, name, msg.print_me());

// empty snoop mailbox
while (ac_mbx_int.try_get(ac));
Expand Down Expand Up @@ -2357,6 +2400,7 @@ package tb_std_cache_subsystem_pkg;
join_any
disable fork;


if (isHit(addr_v) || msg.redo_hit) begin
$display("%t ns %s.do_miss: Calling hit routine for message : %s", $time, name, msg.print_me());
do_hit(msg);
Expand Down Expand Up @@ -2497,60 +2541,19 @@ package tb_std_cache_subsystem_pkg;
logic mshr_match = 0;
int cnt = 0;

// wait for possible MSHR match
while (gnt_vif.mshr_match[msg.port_idx]) begin
if (cnt == 0 || verbosity > 0) begin
$display("%t ns %s.check_cache_msg: wait for MSHR match for message : %s", $time, name, msg.print_me());
end
@(posedge sram_vif.clk);
cnt++;
if (cnt > cache_msg_timeout) begin
$error("%s.check_cache_msg : Timeout while waiting for MSHR match for message : %s", name, msg.print_me());
break;
end

if (!gnt_vif.mshr_match[msg.port_idx]) begin
// if there was an MHSR match we need to get cache grant again
$display("%t ns %s.check_cache_msg: MSHR match ended, wait for cache grant for message : %s", $time, name, msg.print_me());
while (!gnt_vif.rd_gnt[msg.prio]) begin
@(posedge sram_vif.clk); // skip cycles without grant
cnt++;
if (cnt > cache_msg_timeout) begin
$error("%s : Timeout while waiting for cache grant for message : %s", name, msg.print_me());
break;
end
end
$display("%t ns %s.check_cache_msg: got cache grant for message : %s", $time, name, msg.print_me());
@(posedge sram_vif.clk); // wait one more cycle before reading cache status
end
end
if (cnt > 0) begin
$display("%t ns %s.check_cache_msg: MSHR match ended and got grant for message : %s", $time, name, msg.print_me());
end

// go to hit or miss routine
if (isHit(addr_v)) begin
do_hit(msg);
end else begin
do_miss(msg);
end

fork
begin
// send to cache update
$display("%t ns %s Sending message to cache update : %s", $time, name, msg.print_me());
req_to_cache_update.put(msg);
end
begin
// if a new hit() round is requested, do this here and
while (msg.redo_hit == 1) begin
do_hit(msg);
// update cache (again) after a new hit() round
$display("%t ns %s Sending message to cache update : %s", $time, name, msg.print_me());
req_to_cache_update.put(msg);
end
end
join
while (msg.redo_hit == 1) begin
// call hit routine again if requested
do_hit(msg);
end
$display("%t ns %s Sending message to cache update : %s", $time, name, msg.print_me());
req_to_cache_update.put(msg);

end

Expand Down

0 comments on commit 0d62603

Please sign in to comment.