@@ -26,15 +26,17 @@ module snitch_icache import snitch_icache_pkg::*; #(
2626 parameter int unsigned FILL_AW = - 1 ,
2727 // / Fill interface data width. Power of two; >= 8.
2828 parameter int unsigned FILL_DW = - 1 ,
29+ // / Instruction SPM size in kB. If > 0, bypasses L1 entirely
30+ parameter int unsigned InstrSpmSize = 0 ,
2931 // / Allow fetches to have priority over prefetches for L0 to L1
3032 parameter bit FETCH_PRIORITY = 1'b0 ,
3133 // / Merge L0-L1 fetches if requesting the same address
3234 parameter bit MERGE_FETCHES = 1'b0 ,
33- // / Serialize the L1 lookup (parallel tag/data lookup by default)
35+ // / Serialize the L1 lookup (parallel tag/data lookup by default) - UNUSED when InstrSpmSize > 0
3436 parameter bit SERIAL_LOOKUP = 0 ,
35- // / Replace the L1 tag banks with latch-based SCM.
37+ // / Replace the L1 tag banks with latch-based SCM. - UNUSED when InstrSpmSize > 0
3638 parameter bit L1_TAG_SCM = 0 ,
37- // / Number of pending response beats for the L1 cache.
39+ // / Number of pending response beats for the L1 cache. - UNUSED when InstrSpmSize > 0
3840 parameter int unsigned NUM_AXI_OUTSTANDING = 2 ,
3941 // / This reduces area impact at the cost of
4042 // / increased hassle of having latches in
@@ -78,6 +80,7 @@ module snitch_icache import snitch_icache_pkg::*; #(
7880 input sram_cfg_data_t sram_cfg_data_i,
7981 input sram_cfg_tag_t sram_cfg_tag_i,
8082
83+ // AXI master interface (for L0 prefetchers when InstrSpmSize > 0, or L1 refill otherwise)
8184 output axi_req_t axi_req_o,
8285 input axi_rsp_t axi_rsp_i
8386);
@@ -479,6 +482,102 @@ module snitch_icache import snitch_icache_pkg::*; #(
479482 end
480483 assign prefetch_lookup_rsp_ready = | prefetch_rsp_ready;
481484
485+ // ==============================================
486+ // L0 Prefetcher Backend: SPM mode vs L1 mode
487+ // ==============================================
488+
489+ if (InstrSpmSize > 0 ) begin : gen_spm_mode
490+ // SPM mode: L0 prefetchers access instruction SPM via AXI (cacheable)
491+ // Bypass path still active for non-cacheable bootrom accesses
492+ // No L1 cache instantiated
493+
494+ miss_refill_req_t spm_req;
495+ logic spm_req_valid, spm_req_ready;
496+
497+ // Build SPM request (cacheable path)
498+ assign spm_req.addr = prefetch_lookup_req.addr;
499+ assign spm_req.id = prefetch_lookup_req.id[CFG .PENDING_IW - 1 : 0 ];
500+ assign spm_req.bypass = 1'b0 ;
501+
502+ // Store full ID for response reconstruction
503+ logic [CFG .ID_WIDTH - 1 : 0 ] spm_id_q;
504+ logic spm_id_valid;
505+
506+ `FF (spm_id_q, prefetch_lookup_req.id, '0 )
507+ `FF (spm_id_valid, spm_req_valid && spm_req_ready && ! spm_req.bypass, 1'b0 )
508+
509+ // Arbitrate between cacheable (SPM) and non-cacheable (bootrom) requests
510+ stream_arbiter # (
511+ .DATA_T ( miss_refill_req_t ),
512+ .N_INP ( 2 )
513+ ) i_stream_arbiter_spm_bypass (
514+ .clk_i,
515+ .rst_ni,
516+ .inp_data_i ( { bypass_req_q, spm_req} ),
517+ .inp_valid_i ( { bypass_req_valid_q, spm_req_valid} ),
518+ .inp_ready_o ( { bypass_req_ready_q, spm_req_ready} ),
519+ .oup_data_o ( refill_req ),
520+ .oup_valid_o ( refill_req_valid ),
521+ .oup_ready_i ( refill_req_ready )
522+ );
523+
524+ assign spm_req_valid = prefetch_lookup_req_valid;
525+ assign prefetch_lookup_req_ready = spm_req_ready;
526+
527+ // Use refill module to handle AXI transactions for both paths
528+ snitch_icache_refill # (
529+ .CFG ( CFG ),
530+ .axi_req_t ( axi_req_t ),
531+ .axi_rsp_t ( axi_rsp_t )
532+ ) i_refill (
533+ .clk_i,
534+ .rst_ni,
535+
536+ .in_req_addr_i ( refill_req.addr ),
537+ .in_req_id_i ( refill_req.id ),
538+ .in_req_bypass_i ( refill_req.bypass ),
539+ .in_req_valid_i ( refill_req_valid ),
540+ .in_req_ready_o ( refill_req_ready ),
541+
542+ .in_rsp_data_o ( refill_rsp.data ),
543+ .in_rsp_error_o ( refill_rsp.error ),
544+ .in_rsp_id_o ( refill_rsp.id ),
545+ .in_rsp_bypass_o ( refill_rsp.bypass ),
546+ .in_rsp_valid_o ( refill_rsp_valid ),
547+ .in_rsp_ready_i ( refill_rsp_ready ),
548+
549+ .axi_req_o ( axi_req_o ),
550+ .axi_rsp_i ( axi_rsp_i )
551+ );
552+
553+ // Demux responses back to cacheable (L0) and bypass paths
554+ stream_demux # (
555+ .N_OUP ( 2 )
556+ ) i_stream_demux_spm_bypass (
557+ .inp_valid_i ( refill_rsp_valid ),
558+ .inp_ready_o ( refill_rsp_ready ),
559+
560+ .oup_sel_i ( refill_rsp.bypass ),
561+
562+ .oup_valid_o ( { bypass_rsp_valid, prefetch_lookup_rsp_valid} ),
563+ .oup_ready_i ( { bypass_rsp_ready, prefetch_lookup_rsp_ready} )
564+ );
565+
566+ // Route responses - restore full ID for SPM responses
567+ assign prefetch_lookup_rsp.data = refill_rsp.data;
568+ assign prefetch_lookup_rsp.error = refill_rsp.error;
569+ assign prefetch_lookup_rsp.id = spm_id_valid ? spm_id_q : '0 ;
570+ assign bypass_rsp = refill_rsp;
571+
572+ // Tie off events and flush
573+ assign icache_l1_events_o = '0 ;
574+ logic flush_valid;
575+ assign flush_valid = | flush_valid_i;
576+ assign flush_ready_o = { CFG .NR_FETCH_PORTS { flush_valid}} ; // Immediate ack
577+
578+ end else begin : gen_l1_mode
579+ // L1 cache mode: Full lookup, handler, and refill logic
580+
482581 // / Tag lookup
483582
484583 // The lookup module contains the actual cache RAMs and performs lookups.
@@ -703,6 +802,8 @@ module snitch_icache import snitch_icache_pkg::*; #(
703802 .axi_rsp_i (axi_rsp_i)
704803 );
705804
805+ end // gen_l1_mode
806+
706807endmodule
707808
708809// Translate register interface to refill requests.
0 commit comments