@@ -228,6 +228,16 @@ module snitch_icache
228228 logic [NR_FETCH_PORTS - 1 : 0 ] in_cache_ready, in_bypass_ready;
229229 logic [NR_FETCH_PORTS - 1 : 0 ][FETCH_DW - 1 : 0 ] in_cache_data, in_bypass_data;
230230 logic [NR_FETCH_PORTS - 1 : 0 ] in_cache_error, in_bypass_error;
231+ logic [NR_FETCH_PORTS - 1 : 0 ] l0_flush_ready;
232+ logic handler_idle;
233+
234+ logic flush_req;
235+ logic flush_busy_d, flush_busy_q;
236+ logic flush_shared_done_d, flush_shared_done_q;
237+ logic flush_wait_drop_d, flush_wait_drop_q;
238+ logic flush_l0_fire, flush_l0_pending;
239+ logic flush_req_valid_lookup, flush_req_ready_lookup, flush_fire_lookup;
240+ logic l0_flush_ready_all, shared_cache_idle;
231241
232242 for (genvar i = 0 ; i < NR_FETCH_PORTS ; i++ ) begin : gen_prefetcher
233243 prefetch_req_t local_prefetch_req;
@@ -258,7 +268,9 @@ module snitch_icache
258268 ) i_snitch_icache_l0 (
259269 .clk_i (clk_d2_i),
260270 .rst_ni,
261- .flush_valid_i (flush_valid_i[i]),
271+ .flush_pending_i (flush_l0_pending),
272+ .flush_valid_i (flush_l0_fire),
273+ .flush_ready_o (l0_flush_ready[i]),
262274 .enable_prefetching_i,
263275 .enable_branch_pred_i,
264276 .icache_events_o (icache_l0_events_o[i]),
@@ -516,30 +528,62 @@ module snitch_icache
516528 logic write_valid;
517529 logic write_ready;
518530
519- logic flush_valid, flush_ready;
520- logic flush_valid_lookup, flush_ready_lookup;
531+ logic flush_ready_lookup_unused;
532+
533+ assign flush_req = | flush_valid_i;
534+ assign l0_flush_ready_all = & l0_flush_ready;
535+ // Hold the L0s in a "flush pending" state immediately so they stop creating new work while
536+ // the shared cache and any already-issued responses drain.
537+ assign flush_l0_pending = flush_busy_q | (flush_req & ~ flush_wait_drop_q);
538+ // Only invalidate the L0s after the shared cache has flushed and every port has drained its
539+ // old responses, so no pre-flush traffic can repopulate an L0 afterwards.
540+ assign flush_l0_fire = flush_busy_q & flush_shared_done_q & l0_flush_ready_all;
541+ assign flush_ready_o = { CFG .NR_FETCH_PORTS { flush_l0_fire}} ;
542+ assign shared_cache_idle = ~ (| prefetch_req_valid) & ~ prefetch_lookup_req_valid &
543+ ~ lookup_valid & ~ handler_req_valid & handler_idle;
544+ assign flush_fire_lookup = flush_req_valid_lookup & shared_cache_idle;
545+
546+ always_comb begin
547+ flush_busy_d = flush_busy_q;
548+ flush_shared_done_d = flush_shared_done_q;
549+ flush_wait_drop_d = flush_wait_drop_q;
550+
551+ if (flush_wait_drop_q) begin
552+ if (! flush_req) flush_wait_drop_d = 1'b0 ;
553+ end else if (! flush_busy_q) begin
554+ if (flush_req) begin
555+ flush_busy_d = 1'b1 ;
556+ flush_shared_done_d = 1'b0 ;
557+ end
558+ end else begin
559+ if (! flush_shared_done_q && flush_req_ready_lookup) flush_shared_done_d = 1'b1 ;
560+ if (flush_l0_fire) begin
561+ flush_busy_d = 1'b0 ;
562+ flush_wait_drop_d = 1'b1 ;
563+ end
564+ end
565+ end
521566
522- assign flush_ready_o = { CFG .NR_FETCH_PORTS { flush_ready}} ;
523- assign flush_valid = | flush_valid_i;
567+ `FF (flush_busy_q, flush_busy_d, '0 , clk_d2_i, rst_ni)
568+ `FF (flush_shared_done_q, flush_shared_done_d, '0 , clk_d2_i, rst_ni)
569+ `FF (flush_wait_drop_q, flush_wait_drop_d, '0 , clk_d2_i, rst_ni)
524570
525- // We need to propagate the handshake into the other
571+ // We need to propagate the shared-cache flush request into the other
526572 // clock domain in case we operate w/ different clocks.
527573 if (ISO_CROSSING ) begin : gen_flush_crossing
528- isochronous_spill_register i_isochronous_4phase_handshake (
574+ isochronous_4phase_handshake i_isochronous_4phase_handshake (
529575 .src_clk_i (clk_d2_i),
530576 .src_rst_ni (rst_ni),
531- .src_valid_i (flush_valid),
532- .src_ready_o (flush_ready),
533- .src_data_i ('0 ),
577+ .src_valid_i (flush_busy_q & ~ flush_shared_done_q),
578+ .src_ready_o (flush_req_ready_lookup),
534579 .dst_clk_i (clk_i),
535580 .dst_rst_ni (rst_ni),
536- .dst_valid_o (flush_valid_lookup),
537- .dst_ready_i (flush_ready_lookup),
538- .dst_data_o ( /* Unused */ )
581+ .dst_valid_o (flush_req_valid_lookup),
582+ .dst_ready_i (shared_cache_idle)
539583 );
540584 end else begin : gen_no_flush_crossing
541- assign flush_valid_lookup = flush_valid ;
542- assign flush_ready = flush_ready_lookup ;
585+ assign flush_req_valid_lookup = flush_busy_q & ~ flush_shared_done_q ;
586+ assign flush_req_ready_lookup = shared_cache_idle ;
543587 end
544588
545589 if (SERIAL_LOOKUP ) begin : gen_serial_lookup
@@ -553,8 +597,8 @@ module snitch_icache
553597 .clk_i,
554598 .rst_ni,
555599
556- .flush_valid_i (flush_valid_lookup ),
557- .flush_ready_o (flush_ready_lookup ),
600+ .flush_valid_i (flush_fire_lookup ),
601+ .flush_ready_o (flush_ready_lookup_unused ),
558602 .icache_events_o (icache_l1_events_o),
559603
560604 .in_addr_i (prefetch_lookup_req.addr),
@@ -596,8 +640,8 @@ module snitch_icache
596640 .clk_i,
597641 .rst_ni,
598642
599- .flush_valid_i (flush_valid_lookup ),
600- .flush_ready_o (flush_ready_lookup ),
643+ .flush_valid_i (flush_fire_lookup ),
644+ .flush_ready_o (flush_ready_lookup_unused ),
601645 .icache_events_o (icache_l1_events_o),
602646
603647 .in_addr_i (prefetch_lookup_req.addr),
@@ -651,6 +695,7 @@ module snitch_icache
651695 .in_rsp_id_o (prefetch_lookup_rsp.id),
652696 .in_rsp_valid_o (prefetch_lookup_rsp_valid),
653697 .in_rsp_ready_i (prefetch_lookup_rsp_ready),
698+ .idle_o (handler_idle),
654699
655700 .write_addr_o (write_addr),
656701 .write_way_o (write_way),
0 commit comments