88// Simple direct mapped cache
99module instruction_cache # (
1010 // / Width of the Program Counter
11- parameter int unsigned PcWidth = 32 ,
11+ parameter int unsigned PcWidth = 8 ,
1212 // / Number of warps per compute unit
1313 parameter int unsigned NumWarps = 8 ,
1414 // / Number of threads per warp
1515 parameter int unsigned WarpWidth = 32 ,
1616 // / Encoded instruction width
1717 parameter int unsigned EncInstWidth = 4 ,
1818 // / Encoded instructions per cacheline -> Also determines the memory interface width
19- parameter int unsigned CachelineIdxBits = 1 ,
19+ parameter int unsigned CachelineIdxBits = 2 ,
2020 // / Number of cachelines in the instruction cache
21- parameter int unsigned NumCachelines = 2 ,
21+ parameter int unsigned NumCachelines = 8 ,
2222
2323 // / Dependent parameter, do **not** overwrite.
24- parameter int unsigned SubwarpIdWidth = WarpWidth > 1 ? $clog2(WarpWidth) : 1 ,
25- parameter int unsigned WidWidth = NumWarps > 1 ? $clog2(NumWarps) : 1 ,
26- parameter int unsigned CachelineAddrWidth = CachelineIdxBits > 0 ? PcWidth - CachelineIdxBits
27- : PcWidth,
24+ parameter int unsigned SubwarpIdWidth = WarpWidth > 1 ? $clog2(WarpWidth) : 1 ,
25+ parameter int unsigned WidWidth = NumWarps > 1 ? $clog2(NumWarps) : 1 ,
26+ parameter int unsigned CachelineAddrWidth = PcWidth - CachelineIdxBits,
2827 parameter type cache_addr_t = logic [CachelineAddrWidth- 1 : 0 ],
2928 parameter type wid_t = logic [ WidWidth- 1 : 0 ],
3029 parameter type pc_t = logic [ PcWidth- 1 : 0 ],
@@ -468,6 +467,13 @@ module instruction_cache #(
468467 assert property (@ (posedge clk_i) disable iff (! rst_ni)
469468 ! (mem_req_o && mem_ready_i) || (state_d == WAIT_FOR_MEM )
470469 ) else $fatal (1 , " Memory request sent, but did not go to WAIT_FOR_MEM state." );
470+
471+ // If decoder is not ready, the output must stay stable and valid
472+ assert property (@ (posedge clk_i)
473+ ! $past (ic_valid_o && ! dec_ready_i && rst_ni) || ! rst_ni
474+ || (ic_valid_o && $stable ({ ic_pc_o, ic_act_mask_o, ic_warp_id_o,
475+ ic_subwarp_id_o, ic_inst_o} ))
476+ ) else $fatal (1 , " Decoder not ready, but output changed." );
471477 `endif
472478
473479 // #######################################################################################
@@ -509,6 +515,9 @@ module instruction_cache #(
509515 // Check that we can perform memory requests
510516 cover property (@ (posedge clk_i) disable iff (! rst_ni) (mem_req_o && mem_ready_i));
511517 cover property (@ (posedge clk_i) disable iff (! rst_ni) (! mem_req_o && mem_ready_i));
518+ // Check that we can receive memory responses
519+ cover property (@ (posedge clk_i) disable iff (! rst_ni) (mem_valid_i));
520+ cover property (@ (posedge clk_i) disable iff (! rst_ni) (! mem_valid_i));
512521 // Check that we can receive a new instruction
513522 cover property (@ (posedge clk_i) disable iff (! rst_ni) (fe_valid_i && ic_ready_o));
514523 cover property (@ (posedge clk_i) disable iff (! rst_ni) (fe_valid_i && ! ic_ready_o));
@@ -517,23 +526,136 @@ module instruction_cache #(
517526 cover property (@ (posedge clk_i) disable iff (! rst_ni) (! ic_valid_o && dec_ready_i));
518527
519528 // / Memory Latency Model
520- localparam int unsigned FormalMemLatency = 5 ;
521- logic [FormalMemLatency- 1 : 0 ] mem_valid_shift;
529+ localparam int unsigned FormalMemLatency = 3 ;
530+ logic [FormalMemLatency- 1 : 0 ] fv_mem_req_shift;
531+ cache_addr_t [FormalMemLatency- 1 : 0 ] fv_mem_addr_shift;
522532 always_ff @ (posedge clk_i or negedge rst_ni) begin
523533 if (! rst_ni) begin
524- mem_valid_shift <= '0 ;
534+ fv_mem_req_shift <= '0 ;
535+ fv_mem_addr_shift <= '0 ;
525536 end else begin
526- mem_valid_shift <= { mem_valid_shift [FormalMemLatency- 2 : 0 ],
537+ fv_mem_req_shift <= { fv_mem_req_shift [FormalMemLatency- 2 : 0 ],
527538 mem_req_o && mem_ready_i} ;
539+ fv_mem_addr_shift <= { fv_mem_addr_shift[FormalMemLatency- 2 : 0 ],
540+ mem_addr_o} ;
528541 end
529542 end
530543
531544 // Memory valid signal must be delayed version of mem_req_o && mem_ready_i
532545 assume property (@ (posedge clk_i) disable iff (! rst_ni)
533- (mem_valid_i == mem_valid_shift [FormalMemLatency- 1 ]));
546+ (mem_valid_i == fv_mem_req_shift [FormalMemLatency- 1 ]));
534547
535548 // There can only be one active memory request at a time
536- assert property (@ (posedge clk_i) $onehot0 (mem_valid_shift));
549+ assert property (@ (posedge clk_i) $onehot0 (fv_mem_req_shift));
550+
551+ // New request
552+ cache_addr_t f_mem_addr;
553+ cache_data_t f_mem_data;
554+ act_mask_t f_act_mask;
555+ wid_t f_warp_id;
556+ subwarp_id_t f_subwarp_id;
557+
558+ assign f_mem_addr = $anyconst ;
559+ assign f_mem_data = $anyconst ;
560+ assign f_act_mask = $anyconst ;
561+ assign f_warp_id = $anyconst ;
562+ assign f_subwarp_id = $anyconst ;
563+
564+ // Assume that if the fetcher request the instruction with f_pc, we have a request with f_* signals
565+ logic fetcher_request_matches_f_pc;
566+ assign fetcher_request_matches_f_pc =
567+ fe_valid_i && (fe_pc_i[PcWidth- 1 : CachelineIdxBits] == f_mem_addr);
568+ assume property (@ (posedge clk_i) disable iff (! rst_ni)
569+ ! fetcher_request_matches_f_pc || (fe_act_mask_i == f_act_mask)
570+ );
571+ assume property (@ (posedge clk_i) disable iff (! rst_ni)
572+ ! fetcher_request_matches_f_pc || (fe_warp_id_i == f_warp_id)
573+ );
574+ assume property (@ (posedge clk_i) disable iff (! rst_ni)
575+ ! fetcher_request_matches_f_pc || (fe_subwarp_id_i == f_subwarp_id)
576+ );
577+
578+ // Assert that valid cachelines that match the assumed memory address return the correct data
579+ cache_addr_t [NumCachelines- 1 : 0 ] cacheline_addrs;
580+ logic [NumCachelines- 1 : 0 ] cacheline_matches;
581+ for (genvar i = 0 ; i < NumCachelines; i++ ) begin : gen_cacheline_addrs
582+ assign cacheline_addrs[i] = {
583+ i_tag_mem.sram[i],
584+ cache_select_t ' (i)
585+ } ;
586+ assign cacheline_matches[i] = (cacheline_addrs[i] == f_mem_addr) && cache_valids_q[i];
587+
588+ assert property (@ (posedge clk_i) disable iff (! rst_ni)
589+ ! (cacheline_matches[i]) || (f_mem_data == i_inst_mem.sram[i])
590+ ) else $fatal (1 , " Memory data does not match cache data for matching addresses." );
591+ end
592+
593+ logic request_matches_addr;
594+ assign request_matches_addr = mem_valid_i
595+ && (fv_mem_addr_shift[FormalMemLatency- 1 ] == f_mem_addr);
596+ assume property (@ (posedge clk_i) disable iff (! rst_ni)
597+ ! request_matches_addr || (mem_data_i == f_mem_data)
598+ ) else $fatal (1 , " Memory data does not match assumed data." );
599+
600+ // If instruction has the same address as our assumed memory address, the data must match
601+ logic result_matches_mem_addr;
602+ assign result_matches_mem_addr = ic_valid_o
603+ && (ic_pc_o[PcWidth- 1 : CachelineIdxBits] == f_mem_addr);
604+ enc_inst_t result_exp_inst;
605+ assign result_exp_inst = f_mem_data[
606+ ic_pc_o[CachelineIdxBits- 1 : 0 ]
607+ ];
608+ assert property (@ (posedge clk_i) disable iff (! rst_ni)
609+ ! result_matches_mem_addr || (ic_inst_o == result_exp_inst)
610+ ) else $fatal (1 , " Instruction data does not match memory data for matching addresses." );
611+
612+ // Other signals must also match the f_* signals
613+ assert property (@ (posedge clk_i) disable iff (! rst_ni)
614+ ! result_matches_mem_addr || (ic_act_mask_o == f_act_mask)
615+ ) else $fatal (1 , " Active mask does not match assumed data." );
616+ assert property (@ (posedge clk_i) disable iff (! rst_ni)
617+ ! result_matches_mem_addr || (ic_warp_id_o == f_warp_id)
618+ ) else $fatal (1 , " Warp ID does not match assumed data." );
619+ assert property (@ (posedge clk_i) disable iff (! rst_ni)
620+ ! result_matches_mem_addr || (ic_subwarp_id_o == f_subwarp_id)
621+ ) else $fatal (1 , " Subwarp ID does not match assumed data." );
622+
623+ logic active_req_matches_mem_addr;
624+ assign active_req_matches_mem_addr =
625+ (active_req_q.pc[PcWidth- 1 : CachelineIdxBits] == f_mem_addr);
626+
627+ // Cache miss -> data came from memory
628+ assert property (@ (posedge clk_i) disable iff (! rst_ni)
629+ ! (active_req_matches_mem_addr && state_q == WAIT_FOR_DECODER )
630+ || (mem_data_q == f_mem_data)
631+ ) else $fatal (1 , " Stored memory data does not match assumed data." );
632+
633+ // Data in active request must match f_* signals
634+ assert property (@ (posedge clk_i) disable iff (! rst_ni)
635+ ! (active_req_matches_mem_addr && (state_q != IDLE ))
636+ || (active_req_q.act_mask == f_act_mask)
637+ ) else $fatal (1 , " Active mask does not match assumed data on cache miss." );
638+
639+ assert property (@ (posedge clk_i) disable iff (! rst_ni)
640+ ! (active_req_matches_mem_addr && (state_q != IDLE ))
641+ || (active_req_q.warp_id == f_warp_id)
642+ ) else $fatal (1 , " Warp ID does not match assumed data on cache miss." );
643+
644+ assert property (@ (posedge clk_i) disable iff (! rst_ni)
645+ ! (active_req_matches_mem_addr && (state_q != IDLE ))
646+ || (active_req_q.subwarp_id == f_subwarp_id)
647+ ) else $fatal (1 , " Subwarp ID does not match assumed data on cache miss." );
648+
649+ // Cache hit -> data came from cache
650+ logic cache_hit_matches_mem_addr;
651+ assign cache_hit_matches_mem_addr = cache_valid_q
652+ && (cache_tag_q == active_req_q.pc[PcWidth- 1 - : CacheTagBits])
653+ && active_req_matches_mem_addr;
654+
655+ assert property (@ (posedge clk_i) disable iff (! rst_ni)
656+ ! (state_q == HANDLE_INSTR && ic_valid_o && cache_hit_matches_mem_addr)
657+ || (cache_data == f_mem_data)
658+ ) else $fatal (1 , " Cache data does not match assumed data." );
537659 `endif
538660
539661endmodule : instruction_cache
0 commit comments