From 8f0efe79bb75d6db5ada8d5edaec0e004afcf29d Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 6 Feb 2024 14:51:32 +0100 Subject: [PATCH 01/17] Create wrapper for PULP cluster --- Bender.yml | 3 + src/pulp_icache_wrap.sv | 238 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 241 insertions(+) create mode 100644 src/pulp_icache_wrap.sv diff --git a/Bender.yml b/Bender.yml index 5656b6e..94d996e 100644 --- a/Bender.yml +++ b/Bender.yml @@ -36,6 +36,9 @@ sources: # Level 3 - src/snitch_icache.sv - src/snitch_read_only_cache.sv + - target: pulp + files: + - src/pulp_icache_wrap.sv - target: test files: - test/snitch_icache_l0_tb.sv diff --git a/src/pulp_icache_wrap.sv b/src/pulp_icache_wrap.sv new file mode 100644 index 0000000..5fcec5c --- /dev/null +++ b/src/pulp_icache_wrap.sv @@ -0,0 +1,238 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +`include "common_cells/registers.svh" + +/// Porting from hier-icache: +/// Unsupported: different line width, banks in L1, L0 not fully associative +/// [SH_FETCH_DATA_WIDTH == Cache line width] +/// [SH_NB_BANKS == 1] +/// [PRI_NB_WAYS == L0_LINE_COUNT] -> here fully associative +/// [SH_CACHE_LINE == PRI_CACHE_LINE] +/// NumFetchPorts = NB_CORES +/// L0_LINE_COUNT = PRI_CACHE_SIZE/(bytes per line) +/// LINE_WIDTH = X_CACHE_LINE * DATA_WIDTH -> Use >= 32*NB_CORES for optimal performance +/// LINE_COUNT = SH_CACHE_SIZE/(bytes per line) +/// SET_COUNT = SH_NB_WAYS +/// FetchAddrWidth = FETCH_ADDR_WIDTH +/// FetchDataWidth = PRI_FETCH_DATA_WIDTH +/// AxiAddrWidth = AXI_ADDR +/// AxiDataWidth = AXI_DATA +module pulp_icache_wrap #( + /// Number of request (fetch) ports + parameter int NumFetchPorts = -1, + /// L0 Cache Line Count + parameter int L0_LINE_COUNT = -1, + /// Cache Line Width + /// For optimal performance, use >= 32*NumFetchPorts to allow execution of 32-bit instructions + /// for each core before requiring another L0-L1 fetch. + parameter int LINE_WIDTH = -1, + /// The number of cache lines per set. Power of two; >= 2. + parameter int LINE_COUNT = -1, + /// The set associativity of the cache. Power of two; >= 1. + parameter int SET_COUNT = 1, + /// Fetch interface address width. Same as FILL_AW; >= 1. + parameter int FetchAddrWidth = -1, + /// Fetch interface data width. Power of two; >= 8. + parameter int FetchDataWidth = -1, + /// Fill interface address width. Same as FETCH_AW; >= 1. + parameter int AxiAddrWidth = -1, + /// Fill interface data width. Power of two; >= 8. + parameter int AxiDataWidth = -1, + /// Configuration input types for memory cuts used in implementation. + parameter type sram_cfg_data_t = logic, + parameter type sram_cfg_tag_t = logic, + + parameter type axi_req_t = logic, + parameter type axi_rsp_t = logic +) ( + input logic clk_i, + input logic rst_ni, + + // Processor interface + input logic [NumFetchPorts-1:0] fetch_req_i, + input logic [NumFetchPorts-1:0][FetchAddrWidth-1:0] fetch_addr_i, + output logic [NumFetchPorts-1:0] fetch_gnt_o, + output logic [NumFetchPorts-1:0] fetch_rvalid_o, + output logic [NumFetchPorts-1:0][FetchDataWidth-1:0] fetch_rdata_o, + output logic [NumFetchPorts-1:0] fetch_rerror_o, + + input logic enable_prefetching_i, + output snitch_icache_pkg::icache_events_t [NumFetchPorts-1:0] icache_events_o, + input logic [NumFetchPorts-1:0] flush_valid_i, + output logic [NumFetchPorts-1:0] flush_ready_o, + + // SRAM configs + input sram_cfg_data_t sram_cfg_data_i, + input sram_cfg_tag_t sram_cfg_tag_i, + + // AXI interface + output axi_req_t axi_req_o, + input axi_rsp_t axi_rsp_i +); + localparam int unsigned AdapterType = 1; + + logic [NumFetchPorts-1:0] fetch_valid, fetch_ready, fetch_rerror; + logic [NumFetchPorts-1:0][FetchAddrWidth-1:0] fetch_addr; + logic [NumFetchPorts-1:0][FetchDataWidth-1:0] fetch_rdata; + + for (genvar i = 0; i < NumFetchPorts; i++) begin : gen_adapter + if (AdapterType == 0) begin : gen_response_cut + + // Reuquires the core to keep data applied steady while req is high, may not be guaranteed... + spill_register #( + .T (logic [FetchDataWidth-1+1:0]), + .Bypass(1'b0) + ) i_spill_reg ( + .clk_i, + .rst_ni, + .valid_i ( fetch_ready [i] ), + .ready_o ( /* Unconnected as always ready */ ), + .data_i ( {fetch_rdata [i], fetch_rerror [i]} ), + .valid_o ( fetch_rvalid_o[i] ), + .ready_i ( '1 ), + .data_o ( {fetch_rdata_o[i], fetch_rerror_o[i]} ) + ); + + assign fetch_addr[i] = fetch_addr_i[i]; + assign fetch_valid[i] = fetch_req_i[i]; + assign fetch_gnt_o[i] = fetch_ready[i]; + + end else if (AdapterType == 1) begin : gen_request_cut + + logic gnt; + + assign fetch_gnt_o[i] = gnt & fetch_req_i[i]; + + spill_register #( + .T (logic [FetchAddrWidth-1:0]), + .Bypass(1'b0) + ) i_spill_reg ( + .clk_i, + .rst_ni, + .valid_i ( fetch_req_i [i] ), + .ready_o ( gnt ), + .data_i ( fetch_addr_i[i] ), + .valid_o ( fetch_valid [i] ), + .ready_i ( fetch_ready [i] ), + .data_o ( fetch_addr [i] ) + ); + + assign fetch_rdata_o [i] = fetch_rdata [i]; + assign fetch_rerror_o[i] = fetch_rerror[i]; + assign fetch_rvalid_o[i] = fetch_ready [i] & fetch_valid[i]; + + end else begin : gen_flexible_cut + // This can still be improved, there is still an extra stall cycle sometimes AFAIK... + + logic stalled_d, stalled_q; + + logic spill_valid, spill_ready; + logic [FetchAddrWidth-1:0] spill_addr; + + spill_register #( + .T (logic [FetchAddrWidth-1:0]), + .Bypass(1'b0) + ) i_req_spill_reg ( + .clk_i, + .rst_ni, + .valid_i ( fetch_req_i [i] ), + .ready_o ( fetch_gnt_o [i] ), + .data_i ( fetch_addr_i[i] ), + .valid_o ( spill_valid ), + .ready_i ( spill_ready ), + .data_o ( spill_addr ) + ); + + always_comb begin + // Keep steady state + stalled_d = stalled_q; + + // If already stalled + if (stalled_q) begin + // only revert back to unstalled state with sufficient gap + if (!spill_valid && !fetch_req_i[i]) + stalled_d = 1'b0; + end else begin + if (fetch_req_i[i] && !fetch_ready[i]) + stalled_d = 1'b1; + end + end + `FF(stalled_q, stalled_d, '0) + + assign fetch_valid[i] = stalled_q ? spill_valid : fetch_req_i[i]; + assign fetch_addr [i] = stalled_q ? spill_addr : fetch_addr_i[i]; + + logic spill_rvalid; + logic spill_rerror; + logic [FetchDataWidth-1:0] spill_rdata; + + spill_register #( + .T (logic [FetchDataWidth-1+1:0]), + .Bypass(1'b0) + ) i_rsp_spill_reg ( + .clk_i, + .rst_ni, + .valid_i ( fetch_ready [i] ), + .ready_o ( /* Unconnected as always ready */ ), + .data_i ( {fetch_rdata[i], fetch_rerror[i]} ), + .valid_o ( spill_rvalid ), + .ready_i ( '1 ), + .data_o ( {spill_rdata , spill_rerror } ) + ); + + assign fetch_rvalid_o[i] = stalled_q ? fetch_ready[i] : spill_rvalid; + assign fetch_rdata_o [i] = stalled_q ? fetch_rdata [i] : spill_rdata; + assign fetch_rerror_o[i] = stalled_q ? fetch_rerror[i] : spill_rerror; + + end + end + + snitch_icache #( + .NR_FETCH_PORTS ( NumFetchPorts ), + .L0_LINE_COUNT ( L0_LINE_COUNT ), + .LINE_WIDTH ( LINE_WIDTH ), + .LINE_COUNT ( LINE_COUNT ), + .SET_COUNT ( SET_COUNT ), + .FETCH_AW ( FetchAddrWidth ), + .FETCH_DW ( FetchDataWidth ), + .FILL_AW ( AxiAddrWidth ), + .FILL_DW ( AxiDataWidth ), + .FETCH_PRIORITY ( 1 ), + .L1_TAG_SCM ( 1 ), + .SERIAL_LOOKUP ( 1 ), + .NUM_AXI_OUTSTANDING( 4 ), + .EARLY_LATCH ( 0 ), + .ISO_CROSSING ( 0 ), + .sram_cfg_data_t ( sram_cfg_data_t ), + .sram_cfg_tag_t ( sram_cfg_tag_t ), + .axi_req_t ( axi_req_t ), + .axi_rsp_t ( axi_rsp_t ) + ) i_snitch_icache ( + .clk_i, + .clk_d2_i ( clk_i ), + .rst_ni, + + .enable_prefetching_i, + .icache_events_o, + .flush_valid_i, + .flush_ready_o, + + .inst_addr_i ( fetch_addr ), + .inst_data_o ( fetch_rdata ), + .inst_cacheable_i ( {NumFetchPorts{1'b1}} ), + .inst_valid_i ( fetch_valid ), + .inst_ready_o ( fetch_ready ), + .inst_error_o ( fetch_rerror ), + + .sram_cfg_data_i, + .sram_cfg_tag_i, + + .axi_req_o, + .axi_rsp_i + ); + +endmodule From 9918069e2a430274c51764fc95496b4ef30731ee Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 20 Feb 2024 18:00:41 +0100 Subject: [PATCH 02/17] Flatten ID for req path --- src/snitch_axi_to_cache.sv | 60 ++++++++-------- src/snitch_icache.sv | 47 ++++++------ src/snitch_icache_handler.sv | 104 +++++++++++++-------------- src/snitch_icache_l0.sv | 22 +++--- src/snitch_icache_lookup_parallel.sv | 40 +++++------ src/snitch_icache_lookup_serial.sv | 68 +++++++++--------- src/snitch_icache_pkg.sv | 3 +- src/snitch_read_only_cache.sv | 79 ++++++++++---------- test/snitch_icache_l0_tb.sv | 3 +- 9 files changed, 211 insertions(+), 215 deletions(-) diff --git a/src/snitch_axi_to_cache.sv b/src/snitch_axi_to_cache.sv index c1379a8..1099862 100644 --- a/src/snitch_axi_to_cache.sv +++ b/src/snitch_axi_to_cache.sv @@ -21,22 +21,22 @@ module snitch_axi_to_cache #( parameter type resp_t = logic, parameter snitch_icache_pkg::config_t CFG = '0 )( - input logic clk_i, - input logic rst_ni, + input logic clk_i, + input logic rst_ni, // Cache request - output logic [CFG.FETCH_AW-1:0] req_addr_o, - output logic [CFG.ID_WIDTH_REQ-1:0] req_id_o, - output logic req_valid_o, - input logic req_ready_i, + output logic [CFG.FETCH_AW-1:0] req_addr_o, + output logic [CFG.ID_WIDTH-1:0] req_id_o, + output logic req_valid_o, + input logic req_ready_i, // Cache response - input logic [CFG.LINE_WIDTH-1:0] rsp_data_i, - input logic rsp_error_i, - input logic [CFG.ID_WIDTH_RESP-1:0] rsp_id_i, - input logic rsp_valid_i, - output logic rsp_ready_o, + input logic [CFG.LINE_WIDTH-1:0] rsp_data_i, + input logic rsp_error_i, + input logic [CFG.ID_WIDTH-1:0] rsp_id_i, + input logic rsp_valid_i, + output logic rsp_ready_o, // AXI - input req_t slv_req_i, - output resp_t slv_rsp_o + input req_t slv_req_i, + output resp_t slv_rsp_o ); import cf_math_pkg::idx_width; @@ -44,13 +44,13 @@ module snitch_axi_to_cache #( // AXI-word offset within cache line localparam int unsigned WordOffset = idx_width(CFG.LINE_WIDTH/CFG.FETCH_DW); - typedef logic [WordOffset-1:0] offset_t; - typedef logic [CFG.ID_WIDTH_REQ-1:0] id_t; + typedef logic [WordOffset-1:0] offset_t; + typedef logic [$clog2(CFG.ID_WIDTH)-1:0] id_t; typedef struct packed { - logic [CFG.FETCH_AW-1:0] addr; - logic [CFG.ID_WIDTH_REQ-1:0] id; - axi_pkg::len_t len; - axi_pkg::burst_t burst; + logic [CFG.FETCH_AW-1:0] addr; + logic [CFG.ID_WIDTH-1:0] id; + axi_pkg::len_t len; + axi_pkg::burst_t burst; } chan_t; // AR Channel @@ -91,9 +91,9 @@ module snitch_axi_to_cache #( // Store counters axi_burst_splitter_table #( - .MaxTrans ( MaxTrans ), - .IdWidth ( CFG.ID_WIDTH_REQ ), - .offset_t ( offset_t ) + .MaxTrans ( MaxTrans ), + .IdWidth ( $clog2(CFG.ID_WIDTH) ), + .offset_t ( offset_t ) ) i_axi_burst_splitter_table ( .clk_i, .rst_ni, @@ -114,7 +114,7 @@ module snitch_axi_to_cache #( ); assign req_addr_o = ax_o.addr; - assign req_id_o = ax_o.id; + assign req_id_o = 'b1 << ax_o.id; typedef enum logic {Idle, Busy} ar_state_e; ar_state_e ar_state_d, ar_state_q; @@ -192,9 +192,9 @@ module snitch_axi_to_cache #( // -------------------------------------------------- // Cut path typedef struct packed { - logic [CFG.LINE_WIDTH-1:0] data; - logic error; - logic [CFG.ID_WIDTH_RESP-1:0] id; + logic [CFG.LINE_WIDTH-1:0] data; + logic error; + logic [CFG.ID_WIDTH-1:0] id; } rsp_in_t; logic rsp_valid_q, rsp_ready_q; @@ -226,15 +226,15 @@ module snitch_axi_to_cache #( // rsp_error_i --> [forward] --> rsp_in_q.error logic rsp_valid, rsp_ready; logic rsp_id_onehot, rsp_id_empty; - logic [CFG.ID_WIDTH_RESP-1:0] rsp_id_mask, rsp_id_masked; + logic [CFG.ID_WIDTH-1:0] rsp_id_mask, rsp_id_masked; assign rsp_ready_q = (rsp_id_onehot | rsp_id_empty) & rsp_ready; assign rsp_valid = rsp_valid_q; // And not empty? assign rsp_id_masked = rsp_in_q.id & ~rsp_id_mask; lzc #( - .WIDTH ( CFG.ID_WIDTH_RESP ), - .MODE ( 0 ) + .WIDTH ( CFG.ID_WIDTH ), + .MODE ( 0 ) ) i_lzc ( .in_i ( rsp_id_masked ), .cnt_o ( rsp_id ), @@ -242,7 +242,7 @@ module snitch_axi_to_cache #( ); cc_onehot #( - .Width ( CFG.ID_WIDTH_RESP ) + .Width ( CFG.ID_WIDTH ) ) i_onehot ( .d_i ( rsp_id_masked ), .is_onehot_o ( rsp_id_onehot ) diff --git a/src/snitch_icache.sv b/src/snitch_icache.sv index 408d660..c935100 100644 --- a/src/snitch_icache.sv +++ b/src/snitch_icache.sv @@ -106,8 +106,7 @@ module snitch_icache #( L0_TAG_WIDTH: FETCH_AW - $clog2(LINE_WIDTH/8), L0_EARLY_TAG_WIDTH: (L0_EARLY_TAG_WIDTH == -1) ? FETCH_AW - $clog2(LINE_WIDTH/8) : L0_EARLY_TAG_WIDTH, - ID_WIDTH_REQ: $clog2(NR_FETCH_PORTS) + 1, - ID_WIDTH_RESP: 2*NR_FETCH_PORTS, + ID_WIDTH: 2*NR_FETCH_PORTS, PENDING_IW: $clog2(NUM_AXI_OUTSTANDING) }; @@ -152,14 +151,14 @@ module snitch_icache #( // `req` channel, the prefetcher issues another low-priority request for the // next cache line. typedef struct packed { - logic [CFG.FETCH_AW-1:0] addr; - logic [CFG.ID_WIDTH_REQ-1:0] id; + logic [CFG.FETCH_AW-1:0] addr; + logic [CFG.ID_WIDTH-1:0] id; } prefetch_req_t; typedef struct packed { - logic [CFG.LINE_WIDTH-1:0] data; - logic error; - logic [CFG.ID_WIDTH_RESP-1:0] id; + logic [CFG.LINE_WIDTH-1:0] data; + logic error; + logic [CFG.ID_WIDTH-1:0] id; } prefetch_resp_t; prefetch_req_t [NR_FETCH_PORTS-1:0] prefetch_req ; @@ -360,7 +359,7 @@ module snitch_icache #( for (genvar i = 0; i < NR_FETCH_PORTS; i++) begin : gen_prio // prioritize fetches over prefetches - assign prefetch_req_priority[i] = ~prefetch_req[i].id[0]; + assign prefetch_req_priority[i] = prefetch_req[i].id[2*i]; assign prefetch_req_ready[i] = prefetch_req_priority[i] ? prefetch_req_ready_fetch[i] : prefetch_req_ready_pre[i]; @@ -442,22 +441,22 @@ module snitch_icache #( /// Tag lookup // The lookup module contains the actual cache RAMs and performs lookups. - logic [CFG.FETCH_AW-1:0] lookup_addr ; - logic [CFG.ID_WIDTH_REQ-1:0] lookup_id ; - logic [CFG.SET_ALIGN-1:0] lookup_set ; - logic lookup_hit ; - logic [CFG.LINE_WIDTH-1:0] lookup_data ; - logic lookup_error ; - logic lookup_valid ; - logic lookup_ready ; - - logic [CFG.COUNT_ALIGN-1:0] write_addr ; - logic [CFG.SET_ALIGN-1:0] write_set ; - logic [CFG.LINE_WIDTH-1:0] write_data ; - logic [CFG.TAG_WIDTH-1:0] write_tag ; - logic write_error ; - logic write_valid ; - logic write_ready ; + logic [CFG.FETCH_AW-1:0] lookup_addr ; + logic [CFG.ID_WIDTH-1:0] lookup_id ; + logic [CFG.SET_ALIGN-1:0] lookup_set ; + logic lookup_hit ; + logic [CFG.LINE_WIDTH-1:0] lookup_data ; + logic lookup_error ; + logic lookup_valid ; + logic lookup_ready ; + + logic [CFG.COUNT_ALIGN-1:0] write_addr ; + logic [CFG.SET_ALIGN-1:0] write_set ; + logic [CFG.LINE_WIDTH-1:0] write_data ; + logic [CFG.TAG_WIDTH-1:0] write_tag ; + logic write_error ; + logic write_valid ; + logic write_ready ; logic flush_valid, flush_ready; logic flush_valid_lookup, flush_ready_lookup; diff --git a/src/snitch_icache_handler.sv b/src/snitch_icache_handler.sv index ed21b39..54a2e6b 100644 --- a/src/snitch_icache_handler.sv +++ b/src/snitch_icache_handler.sv @@ -12,39 +12,39 @@ module snitch_icache_handler #( input logic clk_i, input logic rst_ni, - input logic [CFG.FETCH_AW-1:0] in_req_addr_i, - input logic [CFG.ID_WIDTH_REQ-1:0] in_req_id_i, - input logic [CFG.SET_ALIGN-1:0] in_req_set_i, - input logic in_req_hit_i, - input logic [CFG.LINE_WIDTH-1:0] in_req_data_i, - input logic in_req_error_i, - input logic in_req_valid_i, - output logic in_req_ready_o, - - output logic [CFG.LINE_WIDTH-1:0] in_rsp_data_o, - output logic in_rsp_error_o, - output logic [CFG.ID_WIDTH_RESP-1:0] in_rsp_id_o, - output logic in_rsp_valid_o, - input logic in_rsp_ready_i, - - output logic [CFG.COUNT_ALIGN-1:0] write_addr_o, - output logic [CFG.SET_ALIGN-1:0] write_set_o, - output logic [CFG.LINE_WIDTH-1:0] write_data_o, - output logic [CFG.TAG_WIDTH-1:0] write_tag_o, - output logic write_error_o, - output logic write_valid_o, - input logic write_ready_i, - - output logic [CFG.FETCH_AW-1:0] out_req_addr_o, - output logic [CFG.PENDING_IW-1:0] out_req_id_o, - output logic out_req_valid_o, - input logic out_req_ready_i, - - input logic [CFG.LINE_WIDTH-1:0] out_rsp_data_i, - input logic out_rsp_error_i, - input logic [CFG.PENDING_IW-1:0] out_rsp_id_i, - input logic out_rsp_valid_i, - output logic out_rsp_ready_o + input logic [CFG.FETCH_AW-1:0] in_req_addr_i, + input logic [CFG.ID_WIDTH-1:0] in_req_id_i, + input logic [CFG.SET_ALIGN-1:0] in_req_set_i, + input logic in_req_hit_i, + input logic [CFG.LINE_WIDTH-1:0] in_req_data_i, + input logic in_req_error_i, + input logic in_req_valid_i, + output logic in_req_ready_o, + + output logic [CFG.LINE_WIDTH-1:0] in_rsp_data_o, + output logic in_rsp_error_o, + output logic [CFG.ID_WIDTH-1:0] in_rsp_id_o, + output logic in_rsp_valid_o, + input logic in_rsp_ready_i, + + output logic [CFG.COUNT_ALIGN-1:0] write_addr_o, + output logic [CFG.SET_ALIGN-1:0] write_set_o, + output logic [CFG.LINE_WIDTH-1:0] write_data_o, + output logic [CFG.TAG_WIDTH-1:0] write_tag_o, + output logic write_error_o, + output logic write_valid_o, + input logic write_ready_i, + + output logic [CFG.FETCH_AW-1:0] out_req_addr_o, + output logic [CFG.PENDING_IW-1:0] out_req_id_o, + output logic out_req_valid_o, + input logic out_req_ready_i, + + input logic [CFG.LINE_WIDTH-1:0] out_rsp_data_i, + input logic out_rsp_error_i, + input logic [CFG.PENDING_IW-1:0] out_rsp_id_i, + input logic out_rsp_valid_i, + output logic out_rsp_ready_o ); `ifndef SYNTHESIS @@ -59,22 +59,22 @@ module snitch_icache_handler #( typedef struct packed { logic valid; logic [CFG.FETCH_AW-1:0] addr; - logic [CFG.ID_WIDTH_RESP-1:0] idmask; // mask of incoming ids + logic [CFG.ID_WIDTH-1:0] idmask; // mask of incoming ids } pending_t; pending_t pending_q [CFG.PENDING_COUNT]; logic [CFG.PENDING_COUNT-1:0] pending_clr; logic [CFG.PENDING_COUNT-1:0] pending_set; - logic [CFG.PENDING_IW-1:0] push_index; - logic push_init; // reset the idmask instead of or'ing - logic [CFG.FETCH_AW-1:0] push_addr; - logic [CFG.ID_WIDTH_RESP-1:0] push_idmask; - logic push_enable; + logic [CFG.PENDING_IW-1:0] push_index; + logic push_init; // reset the idmask instead of or'ing + logic [CFG.FETCH_AW-1:0] push_addr; + logic [CFG.ID_WIDTH-1:0] push_idmask; + logic push_enable; - logic [CFG.PENDING_IW-1:0] pop_index; - logic [CFG.FETCH_AW-1:0] pop_addr; - logic [CFG.ID_WIDTH_RESP-1:0] pop_idmask; - logic pop_enable; + logic [CFG.PENDING_IW-1:0] pop_index; + logic [CFG.FETCH_AW-1:0] pop_addr; + logic [CFG.ID_WIDTH-1:0] pop_idmask; + logic pop_enable; typedef struct packed { logic sel; @@ -159,7 +159,7 @@ module snitch_icache_handler #( // Guarantee ordering // Check if there is a miss in flight from this ID. In that case, stall all // further requests to guarantee correct ordering of requests. - logic [CFG.ID_WIDTH_RESP-1:0] miss_in_flight_d, miss_in_flight_q; + logic [CFG.ID_WIDTH-1:0] miss_in_flight_d, miss_in_flight_q; if (CFG.GUARANTEE_ORDERING) begin : g_miss_in_flight_table always_comb begin : p_miss_in_flight @@ -184,22 +184,22 @@ module snitch_icache_handler #( // progress which cover the request. If not, a new refill request is issued // and the next free entry in the table allocated. Otherwise the existing // table entry is updated. - logic [CFG.ID_WIDTH_RESP-1:0] hit_id; - logic [CFG.LINE_WIDTH-1:0] hit_data; - logic hit_error; - logic hit_valid; - logic hit_ready; + logic [CFG.ID_WIDTH-1:0] hit_id; + logic [CFG.LINE_WIDTH-1:0] hit_data; + logic hit_error; + logic hit_valid; + logic hit_ready; always_comb begin : p_miss_handler hit_valid = 0; - hit_id = 'b1 << in_req_id_i; + hit_id = in_req_id_i; hit_data = in_req_data_i; hit_error = in_req_error_i; push_index = free_id; push_init = 0; push_addr = in_req_addr_i; - push_idmask = 'b1 << in_req_id_i; + push_idmask = in_req_id_i; push_enable = 0; in_req_ready_o = 1; @@ -210,7 +210,7 @@ module snitch_icache_handler #( if (in_req_valid_i) begin // Miss already in flight. Stall to preserve ordering - if (miss_in_flight_q[in_req_id_i]) begin + if (|(miss_in_flight_q & in_req_id_i)) begin in_req_ready_o = 0; // The cache lookup was a hit. end else if (in_req_hit_i) begin diff --git a/src/snitch_icache_l0.sv b/src/snitch_icache_l0.sv index e2346a8..3c1027d 100644 --- a/src/snitch_icache_l0.sv +++ b/src/snitch_icache_l0.sv @@ -26,16 +26,16 @@ module snitch_icache_l0 import snitch_icache_pkg::*; #( output logic in_ready_o, output logic in_error_o, - output logic [CFG.FETCH_AW-1:0] out_req_addr_o, - output logic [CFG.ID_WIDTH_REQ-1:0] out_req_id_o, - output logic out_req_valid_o, - input logic out_req_ready_i, - - input logic [CFG.LINE_WIDTH-1:0] out_rsp_data_i, - input logic out_rsp_error_i, - input logic [CFG.ID_WIDTH_RESP-1:0] out_rsp_id_i, - input logic out_rsp_valid_i, - output logic out_rsp_ready_o + output logic [CFG.FETCH_AW-1:0] out_req_addr_o, + output logic [CFG.ID_WIDTH-1:0] out_req_id_o, + output logic out_req_valid_o, + input logic out_req_ready_i, + + input logic [CFG.LINE_WIDTH-1:0] out_rsp_data_i, + input logic out_rsp_error_i, + input logic [CFG.ID_WIDTH-1:0] out_rsp_id_i, + input logic out_rsp_valid_i, + output logic out_rsp_ready_o ); typedef logic [CFG.FETCH_AW-1:0] addr_t; @@ -262,7 +262,7 @@ module snitch_icache_l0 import snitch_icache_pkg::*; #( assign in_error_o = '0; assign out_req_addr_o = out_req.addr; - assign out_req_id_o = {L0_ID, out_req.is_prefetch}; + assign out_req_id_o = 'b1 << {L0_ID, out_req.is_prefetch}; // Priority arbitrate requests. always_comb begin diff --git a/src/snitch_icache_lookup_parallel.sv b/src/snitch_icache_lookup_parallel.sv index efcbf3f..26b5d61 100644 --- a/src/snitch_icache_lookup_parallel.sv +++ b/src/snitch_icache_lookup_parallel.sv @@ -17,27 +17,27 @@ module snitch_icache_lookup_parallel #( input logic flush_valid_i, output logic flush_ready_o, - input logic [CFG.FETCH_AW-1:0] in_addr_i, - input logic [CFG.ID_WIDTH_REQ-1:0] in_id_i, - input logic in_valid_i, - output logic in_ready_o, + input logic [CFG.FETCH_AW-1:0] in_addr_i, + input logic [CFG.ID_WIDTH-1:0] in_id_i, + input logic in_valid_i, + output logic in_ready_o, - output logic [CFG.FETCH_AW-1:0] out_addr_o, - output logic [CFG.ID_WIDTH_REQ-1:0] out_id_o, - output logic [CFG.SET_ALIGN-1:0] out_set_o, - output logic out_hit_o, - output logic [CFG.LINE_WIDTH-1:0] out_data_o, - output logic out_error_o, - output logic out_valid_o, - input logic out_ready_i, + output logic [CFG.FETCH_AW-1:0] out_addr_o, + output logic [CFG.ID_WIDTH-1:0] out_id_o, + output logic [CFG.SET_ALIGN-1:0] out_set_o, + output logic out_hit_o, + output logic [CFG.LINE_WIDTH-1:0] out_data_o, + output logic out_error_o, + output logic out_valid_o, + input logic out_ready_i, - input logic [CFG.COUNT_ALIGN-1:0] write_addr_i, - input logic [CFG.SET_ALIGN-1:0] write_set_i, - input logic [CFG.LINE_WIDTH-1:0] write_data_i, - input logic [CFG.TAG_WIDTH-1:0] write_tag_i, - input logic write_error_i, - input logic write_valid_i, - output logic write_ready_o, + input logic [CFG.COUNT_ALIGN-1:0] write_addr_i, + input logic [CFG.SET_ALIGN-1:0] write_set_i, + input logic [CFG.LINE_WIDTH-1:0] write_data_i, + input logic [CFG.TAG_WIDTH-1:0] write_tag_i, + input logic write_error_i, + input logic write_valid_i, + output logic write_ready_o, input sram_cfg_data_t sram_cfg_data_i, input sram_cfg_tag_t sram_cfg_tag_i @@ -119,7 +119,7 @@ module snitch_icache_lookup_parallel #( // looked up tag and data. logic valid_q; logic [CFG.FETCH_AW-1:0] addr_q; - logic [CFG.ID_WIDTH_REQ-1:0] id_q; + logic [CFG.ID_WIDTH-1:0] id_q; always_ff @(posedge clk_i or negedge rst_ni) begin if (!rst_ni) begin diff --git a/src/snitch_icache_lookup_serial.sv b/src/snitch_icache_lookup_serial.sv index 6a0ad9c..7690e3d 100644 --- a/src/snitch_icache_lookup_serial.sv +++ b/src/snitch_icache_lookup_serial.sv @@ -13,33 +13,33 @@ module snitch_icache_lookup_serial #( parameter type sram_cfg_data_t = logic, parameter type sram_cfg_tag_t = logic )( - input logic clk_i, - input logic rst_ni, - - input logic flush_valid_i, - output logic flush_ready_o, - - input logic [CFG.FETCH_AW-1:0] in_addr_i, - input logic [CFG.ID_WIDTH_REQ-1:0] in_id_i, - input logic in_valid_i, - output logic in_ready_o, - - output logic [CFG.FETCH_AW-1:0] out_addr_o, - output logic [CFG.ID_WIDTH_REQ-1:0] out_id_o, - output logic [CFG.SET_ALIGN-1:0] out_set_o, - output logic out_hit_o, - output logic [CFG.LINE_WIDTH-1:0] out_data_o, - output logic out_error_o, - output logic out_valid_o, - input logic out_ready_i, - - input logic [CFG.COUNT_ALIGN-1:0] write_addr_i, - input logic [CFG.SET_ALIGN-1:0] write_set_i, - input logic [CFG.LINE_WIDTH-1:0] write_data_i, - input logic [CFG.TAG_WIDTH-1:0] write_tag_i, - input logic write_error_i, - input logic write_valid_i, - output logic write_ready_o, + input logic clk_i, + input logic rst_ni, + + input logic flush_valid_i, + output logic flush_ready_o, + + input logic [CFG.FETCH_AW-1:0] in_addr_i, + input logic [CFG.ID_WIDTH-1:0] in_id_i, + input logic in_valid_i, + output logic in_ready_o, + + output logic [CFG.FETCH_AW-1:0] out_addr_o, + output logic [CFG.ID_WIDTH-1:0] out_id_o, + output logic [CFG.SET_ALIGN-1:0] out_set_o, + output logic out_hit_o, + output logic [CFG.LINE_WIDTH-1:0] out_data_o, + output logic out_error_o, + output logic out_valid_o, + input logic out_ready_i, + + input logic [CFG.COUNT_ALIGN-1:0] write_addr_i, + input logic [CFG.SET_ALIGN-1:0] write_set_i, + input logic [CFG.LINE_WIDTH-1:0] write_data_i, + input logic [CFG.TAG_WIDTH-1:0] write_tag_i, + input logic write_error_i, + input logic write_valid_i, + output logic write_ready_o, input sram_cfg_data_t sram_cfg_data_i, input sram_cfg_tag_t sram_cfg_tag_i @@ -71,8 +71,8 @@ module snitch_icache_lookup_serial #( // Tag stage // -------------------------------------------------- typedef struct packed { - logic [CFG.FETCH_AW-1:0] addr; - logic [CFG.ID_WIDTH_REQ-1:0] id; + logic [CFG.FETCH_AW-1:0] addr; + logic [CFG.ID_WIDTH-1:0] id; } tag_req_t; typedef struct packed { @@ -223,11 +223,11 @@ module snitch_icache_lookup_serial #( // -------------------------------------------------- typedef struct packed { - logic [CFG.FETCH_AW-1:0] addr; - logic [CFG.ID_WIDTH_REQ-1:0] id; - logic [CFG.SET_ALIGN-1:0] cset; - logic hit; - logic error; + logic [CFG.FETCH_AW-1:0] addr; + logic [CFG.ID_WIDTH-1:0] id; + logic [CFG.SET_ALIGN-1:0] cset; + logic hit; + logic error; } data_req_t; typedef logic [CFG.LINE_WIDTH-1:0] data_rsp_t; diff --git a/src/snitch_icache_pkg.sv b/src/snitch_icache_pkg.sv index 4014bd1..17cfa37 100644 --- a/src/snitch_icache_pkg.sv +++ b/src/snitch_icache_pkg.sv @@ -40,8 +40,7 @@ package snitch_icache_pkg; int unsigned TAG_WIDTH; int unsigned L0_TAG_WIDTH; int unsigned L0_EARLY_TAG_WIDTH; - int unsigned ID_WIDTH_REQ; - int unsigned ID_WIDTH_RESP; + int unsigned ID_WIDTH; int unsigned PENDING_IW; // refill ID width } config_t; diff --git a/src/snitch_read_only_cache.sv b/src/snitch_read_only_cache.sv index 369fe0b..9142abc 100644 --- a/src/snitch_read_only_cache.sv +++ b/src/snitch_read_only_cache.sv @@ -211,50 +211,49 @@ module snitch_read_only_cache #( COUNT_ALIGN: cf_math_pkg::idx_width(LineCount), SET_ALIGN: cf_math_pkg::idx_width(SetCount), TAG_WIDTH: AxiAddrWidth - $clog2(LineWidth/8) - $clog2(LineCount) + 1, - ID_WIDTH_REQ: AxiIdWidth, - ID_WIDTH_RESP: 2**AxiIdWidth, + ID_WIDTH: 2**AxiIdWidth, PENDING_IW: $clog2(PendingCount), default: 0 }; - logic [CFG.FETCH_AW-1:0] in_addr; - logic [CFG.ID_WIDTH_REQ-1:0] in_id; - logic in_valid; - logic in_ready; - - logic [CFG.LINE_WIDTH-1:0] in_rsp_data; - logic in_rsp_error; - logic [CFG.ID_WIDTH_RESP-1:0] in_rsp_id; - logic in_rsp_valid; - logic in_rsp_ready; - - logic [CFG.FETCH_AW-1:0] lookup_addr; - logic [CFG.ID_WIDTH_REQ-1:0] lookup_id; - logic [CFG.SET_ALIGN-1:0] lookup_set; - logic lookup_hit; - logic [CFG.LINE_WIDTH-1:0] lookup_data; - logic lookup_error; - logic lookup_valid; - logic lookup_ready; - - logic handler_req_valid; - logic handler_req_ready; - logic [CFG.FETCH_AW-1:0] handler_req_addr; - logic [CFG.PENDING_IW-1:0] handler_req_id; - - logic [CFG.LINE_WIDTH-1:0] handler_rsp_data; - logic handler_rsp_error; - logic [CFG.PENDING_IW-1:0] handler_rsp_id; - logic handler_rsp_valid; - logic handler_rsp_ready; - - logic [CFG.COUNT_ALIGN-1:0] write_addr; - logic [CFG.SET_ALIGN-1:0] write_set; - logic [CFG.LINE_WIDTH-1:0] write_data; - logic [CFG.TAG_WIDTH-1:0] write_tag; - logic write_error; - logic write_valid; - logic write_ready; + logic [CFG.FETCH_AW-1:0] in_addr; + logic [CFG.ID_WIDTH-1:0] in_id; + logic in_valid; + logic in_ready; + + logic [CFG.LINE_WIDTH-1:0] in_rsp_data; + logic in_rsp_error; + logic [CFG.ID_WIDTH-1:0] in_rsp_id; + logic in_rsp_valid; + logic in_rsp_ready; + + logic [CFG.FETCH_AW-1:0] lookup_addr; + logic [CFG.ID_WIDTH-1:0] lookup_id; + logic [CFG.SET_ALIGN-1:0] lookup_set; + logic lookup_hit; + logic [CFG.LINE_WIDTH-1:0] lookup_data; + logic lookup_error; + logic lookup_valid; + logic lookup_ready; + + logic handler_req_valid; + logic handler_req_ready; + logic [CFG.FETCH_AW-1:0] handler_req_addr; + logic [CFG.PENDING_IW-1:0] handler_req_id; + + logic [CFG.LINE_WIDTH-1:0] handler_rsp_data; + logic handler_rsp_error; + logic [CFG.PENDING_IW-1:0] handler_rsp_id; + logic handler_rsp_valid; + logic handler_rsp_ready; + + logic [CFG.COUNT_ALIGN-1:0] write_addr; + logic [CFG.SET_ALIGN-1:0] write_set; + logic [CFG.LINE_WIDTH-1:0] write_data; + logic [CFG.TAG_WIDTH-1:0] write_tag; + logic write_error; + logic write_valid; + logic write_ready; // The axi_to_cache module converts AXI requests to cache requests and // reconstructs AXI responses from the cache's responses diff --git a/test/snitch_icache_l0_tb.sv b/test/snitch_icache_l0_tb.sv index 45a6552..080ad6f 100644 --- a/test/snitch_icache_l0_tb.sv +++ b/test/snitch_icache_l0_tb.sv @@ -101,8 +101,7 @@ module snitch_icache_l0_tb #( L0_TAG_WIDTH: FETCH_AW - $clog2(LINE_WIDTH/8), L0_EARLY_TAG_WIDTH: (L0_EARLY_TAG_WIDTH == -1) ? FETCH_AW - $clog2(LINE_WIDTH/8) : L0_EARLY_TAG_WIDTH, - ID_WIDTH_REQ: $clog2(NR_FETCH_PORTS) + 1, - ID_WIDTH_RESP: 2*NR_FETCH_PORTS, + ID_WIDTH: 2*NR_FETCH_PORTS, PENDING_IW: $clog2(2) }; From 7c5d4acd9a342d8006def75348996d77bd23ffef Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 25 Mar 2024 17:12:15 +0100 Subject: [PATCH 03/17] Merge fetches to L1 if requesting same address --- src/snitch_icache.sv | 51 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/src/snitch_icache.sv b/src/snitch_icache.sv index c935100..59749b1 100644 --- a/src/snitch_icache.sv +++ b/src/snitch_icache.sv @@ -345,6 +345,9 @@ module snitch_icache #( .dst_data_o ( bypass_rsp_q ) ); + logic [NR_FETCH_PORTS-1:0] prefetch_req_ready_tmp; + prefetch_req_t prefetch_lookup_req_tmp; + /// Arbitrate cache port // 1. Request Side if (FETCH_PRIORITY) begin : gen_fetch_priority @@ -353,29 +356,43 @@ module snitch_icache #( logic [NR_FETCH_PORTS-1:0] prefetch_req_ready_pre, prefetch_req_ready_fetch; prefetch_req_t prefetch_lookup_req_pre, prefetch_lookup_req_fetch; logic prefetch_lookup_req_valid_pre, prefetch_lookup_req_valid_fetch; - logic prefetch_lookup_req_ready_pre, prefetch_lookup_req_ready_fetch; logic lock_pre_d, lock_pre_q; + logic prefetch_filtered_ready, fetch_filtered_ready; for (genvar i = 0; i < NR_FETCH_PORTS; i++) begin : gen_prio // prioritize fetches over prefetches assign prefetch_req_priority[i] = prefetch_req[i].id[2*i]; - assign prefetch_req_ready[i] = prefetch_req_priority[i] ? prefetch_req_ready_fetch[i] : - prefetch_req_ready_pre[i]; + assign prefetch_req_ready_tmp[i] = prefetch_req_priority[i] ? prefetch_req_ready_fetch[i] : + prefetch_req_ready_pre[i]; end assign prefetch_lookup_req_valid = prefetch_lookup_req_valid_pre | prefetch_lookup_req_valid_fetch; - assign prefetch_lookup_req = prefetch_lookup_req_valid_fetch && !lock_pre_q ? - prefetch_lookup_req_fetch : - prefetch_lookup_req_pre; + assign prefetch_lookup_req_tmp = prefetch_lookup_req_valid_fetch && !lock_pre_q ? + prefetch_lookup_req_fetch : + prefetch_lookup_req_pre; assign lock_pre_d = (lock_pre_q | (~prefetch_lookup_req_valid_fetch & prefetch_lookup_req_valid_pre )) & ~prefetch_lookup_req_ready; + // Suppress ready if fetch is valid and if the prefetcher is not locked + // If merge fetches, still give ready if addresses match + assign prefetch_filtered_ready = (prefetch_lookup_req_valid_fetch && !lock_pre_q) && + !(MERGE_FETCHES && + prefetch_lookup_req_pre.addr == prefetch_lookup_req_fetch.addr) + ? 1'b0 : prefetch_lookup_req_ready; + + // Suppress ready if locked to prefetcher + // If merge fetches, still give ready if addresses match + assign fetch_filtered_ready = lock_pre_q && + !(MERGE_FETCHES && + prefetch_lookup_req_pre.addr == prefetch_lookup_req_fetch.addr) + ? 1'b0 : prefetch_lookup_req_ready; + // prefetch arbiter - low priority stream_arbiter #( .DATA_T ( prefetch_req_t ), @@ -388,8 +405,7 @@ module snitch_icache #( .inp_ready_o ( prefetch_req_ready_pre ), .oup_data_o ( prefetch_lookup_req_pre ), .oup_valid_o ( prefetch_lookup_req_valid_pre ), - .oup_ready_i ( prefetch_lookup_req_valid_fetch && !lock_pre_q ? - 1'b0 : prefetch_lookup_req_ready ) + .oup_ready_i ( prefetch_filtered_ready ) ); // fetch arbiter - high priority @@ -404,7 +420,7 @@ module snitch_icache #( .inp_ready_o ( prefetch_req_ready_fetch ), .oup_data_o ( prefetch_lookup_req_fetch ), .oup_valid_o ( prefetch_lookup_req_valid_fetch ), - .oup_ready_i ( lock_pre_q ? 1'b0 : prefetch_lookup_req_ready ) + .oup_ready_i ( fetch_filtered_ready ) ); `FF(lock_pre_q, lock_pre_d, '0) @@ -419,14 +435,27 @@ module snitch_icache #( .rst_ni, .inp_data_i ( prefetch_req ), .inp_valid_i ( prefetch_req_valid ), - .inp_ready_o ( prefetch_req_ready ), - .oup_data_o ( prefetch_lookup_req ), + .inp_ready_o ( prefetch_req_ready_tmp ), + .oup_data_o ( prefetch_lookup_req_tmp ), .oup_valid_o ( prefetch_lookup_req_valid ), .oup_ready_i ( prefetch_lookup_req_ready ) ); end + for (genvar i = 0; i < NR_FETCH_PORTS; i++) begin : gen_prefetch_req_ready + assign prefetch_req_ready[i] = prefetch_req_ready_tmp[i] | + (prefetch_lookup_req_ready & + prefetch_req[i].addr == prefetch_lookup_req.addr); + end + always_comb begin + prefetch_lookup_req = prefetch_lookup_req_tmp; + for (int i = 0; i < NR_FETCH_PORTS; i++) begin + prefetch_lookup_req.id |= prefetch_req_ready[i] && prefetch_req_valid[i] ? + prefetch_req[i].id : '0; + end + end + // 2. Response Side // This breaks if the pre-fetcher would not alway be ready // which is the case for the moment From 677b19aeeb5ca55fe791e9de8150f94e46821001 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 25 Mar 2024 17:09:00 +0100 Subject: [PATCH 04/17] Add multi-accept RR arbiter --- Bender.yml | 1 + src/multi_accept_rr_arb.sv | 95 ++++++++++++++++++++++++++++++++++++++ src/snitch_icache.sv | 21 +++++---- 3 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 src/multi_accept_rr_arb.sv diff --git a/Bender.yml b/Bender.yml index 94d996e..6bdfef8 100644 --- a/Bender.yml +++ b/Bender.yml @@ -24,6 +24,7 @@ sources: # Level 0 - src/snitch_icache_pkg.sv - src/riscv_instr_branch.sv + - src/multi_accept_rr_arb.sv # Level 1 - src/snitch_axi_to_cache.sv - src/snitch_icache_l0.sv diff --git a/src/multi_accept_rr_arb.sv b/src/multi_accept_rr_arb.sv new file mode 100644 index 0000000..181a648 --- /dev/null +++ b/src/multi_accept_rr_arb.sv @@ -0,0 +1,95 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +module multi_accept_rr_arb #( + parameter type data_t = logic, + parameter int unsigned NumInp = 0 +) ( + input logic clk_i, + input logic rst_ni, + input logic flush_i, + + input data_t [NumInp-1:0] inp_data_i, + input logic [NumInp-1:0] inp_valid_i, + output logic [NumInp-1:0] inp_ready_o, + + output data_t oup_data_o, + output logic oup_valid_o, + input logic oup_ready_i +); + + // lock arbiter decision in case we got at least one req and no acknowledge + logic lock_d, lock_q; + logic [NumInp-1:0] req_d, req_q; + + assign lock_d = oup_valid_o & ~oup_ready_i; + assign req_d = (lock_q) ? req_q : inp_valid_i; + + always_ff @(posedge clk_i or negedge rst_ni) begin : p_lock_reg + if (!rst_ni) begin + lock_q <= '0; + end else begin + if (flush_i) begin + lock_q <= '0; + end else begin + lock_q <= lock_d; + end + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin : p_req_regs + if (!rst_ni) begin + req_q <= '0; + end else begin + if (flush_i) begin + req_q <= '0; + end else begin + req_q <= req_d; + end + end + end + + localparam int unsigned IdxWidth = (NumInp > 32'd1) ? unsigned'($clog2(NumInp)) : 32'd1; + logic [IdxWidth-1:0] idx; + + `ifndef SYNTHESIS + `ifndef COMMON_CELLS_ASSERTS_OFF + lock: assert property( + @(posedge clk_i) disable iff (!rst_ni || flush_i) + oup_valid_o && (!oup_ready_i && !flush_i) |=> idx == $past(idx)) else + $fatal (1, "Lock implies same arbiter decision in next cycle if output is not ready."); + + lock_req: assume property( + @(posedge clk_i) disable iff (!rst_ni || flush_i) + lock_d |=> inp_valid_i[idx] == req_q[idx]) else + $fatal (1, "It is disallowed to deassert the selected unserved request signals."); + `endif + `endif + + + + + rr_arb_tree #( + .NumIn (NumInp), + .DataType (data_t), + .ExtPrio (1'b0), + .AxiVldRdy (1'b1), + .LockIn (1'b0) + ) i_arbiter ( + .clk_i, + .rst_ni, + .flush_i, + .rr_i ('0), + .req_i (req_d), + .gnt_o (inp_ready_o), + .data_i (inp_data_i), + .gnt_i (oup_ready_i), + .req_o (oup_valid_o), + .data_o (oup_data_o), + .idx_o (idx) + ); + +endmodule diff --git a/src/snitch_icache.sv b/src/snitch_icache.sv index 59749b1..0978a9b 100644 --- a/src/snitch_icache.sv +++ b/src/snitch_icache.sv @@ -394,12 +394,13 @@ module snitch_icache #( ? 1'b0 : prefetch_lookup_req_ready; // prefetch arbiter - low priority - stream_arbiter #( - .DATA_T ( prefetch_req_t ), - .N_INP ( NR_FETCH_PORTS ) + multi_accept_rr_arb #( + .data_t ( prefetch_req_t ), + .NumInp ( NR_FETCH_PORTS ) ) i_stream_arbiter_pre ( .clk_i, .rst_ni, + .flush_i ( '0 ), .inp_data_i ( prefetch_req ), .inp_valid_i ( prefetch_req_valid & ~prefetch_req_priority ), .inp_ready_o ( prefetch_req_ready_pre ), @@ -409,12 +410,13 @@ module snitch_icache #( ); // fetch arbiter - high priority - stream_arbiter #( - .DATA_T ( prefetch_req_t ), - .N_INP ( NR_FETCH_PORTS ) + multi_accept_rr_arb #( + .data_t ( prefetch_req_t ), + .NumInp ( NR_FETCH_PORTS ) ) i_stream_arbiter_fetch ( .clk_i, .rst_ni, + .flush_i ( '0 ), .inp_data_i ( prefetch_req ), .inp_valid_i ( prefetch_req_valid & prefetch_req_priority ), .inp_ready_o ( prefetch_req_ready_fetch ), @@ -427,12 +429,13 @@ module snitch_icache #( end else begin : gen_standard_fetch - stream_arbiter #( - .DATA_T ( prefetch_req_t ), - .N_INP ( NR_FETCH_PORTS ) + multi_accept_rr_arb #( + .data_t ( prefetch_req_t ), + .NumInp ( NR_FETCH_PORTS ) ) i_stream_arbiter ( .clk_i, .rst_ni, + .flush_i ( '0 ), .inp_data_i ( prefetch_req ), .inp_valid_i ( prefetch_req_valid ), .inp_ready_o ( prefetch_req_ready_tmp ), From 851912cad177cb8fcb90eff188402cf724b6fd0d Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 25 Mar 2024 12:20:46 +0100 Subject: [PATCH 05/17] Add parameter to enable fetch merging --- src/pulp_icache_wrap.sv | 1 + src/snitch_icache.sv | 27 +++++++++++++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/pulp_icache_wrap.sv b/src/pulp_icache_wrap.sv index 5fcec5c..6d4e23a 100644 --- a/src/pulp_icache_wrap.sv +++ b/src/pulp_icache_wrap.sv @@ -202,6 +202,7 @@ module pulp_icache_wrap #( .FILL_AW ( AxiAddrWidth ), .FILL_DW ( AxiDataWidth ), .FETCH_PRIORITY ( 1 ), + .MERGE_FETCHES ( 1 ), .L1_TAG_SCM ( 1 ), .SERIAL_LOOKUP ( 1 ), .NUM_AXI_OUTSTANDING( 4 ), diff --git a/src/snitch_icache.sv b/src/snitch_icache.sv index 0978a9b..e64d7fe 100644 --- a/src/snitch_icache.sv +++ b/src/snitch_icache.sv @@ -28,6 +28,8 @@ module snitch_icache #( parameter int unsigned FILL_DW = -1, /// Allow fetches to have priority over prefetches for L0 to L1 parameter bit FETCH_PRIORITY = 1'b0, + /// Merge L0-L1 fetches if requesting the same address + parameter bit MERGE_FETCHES = 1'b0, /// Serialize the L1 lookup (parallel tag/data lookup by default) parameter bit SERIAL_LOOKUP = 0, /// Replace the L1 tag banks with latch-based SCM. @@ -446,17 +448,22 @@ module snitch_icache #( end - for (genvar i = 0; i < NR_FETCH_PORTS; i++) begin : gen_prefetch_req_ready - assign prefetch_req_ready[i] = prefetch_req_ready_tmp[i] | - (prefetch_lookup_req_ready & - prefetch_req[i].addr == prefetch_lookup_req.addr); - end - always_comb begin - prefetch_lookup_req = prefetch_lookup_req_tmp; - for (int i = 0; i < NR_FETCH_PORTS; i++) begin - prefetch_lookup_req.id |= prefetch_req_ready[i] && prefetch_req_valid[i] ? - prefetch_req[i].id : '0; + if (MERGE_FETCHES) begin : gen_merge_fetches + for (genvar i = 0; i < NR_FETCH_PORTS; i++) begin : gen_prefetch_req_ready + assign prefetch_req_ready[i] = prefetch_req_ready_tmp[i] | + (prefetch_lookup_req_ready & + prefetch_req[i].addr == prefetch_lookup_req.addr); + end + always_comb begin + prefetch_lookup_req = prefetch_lookup_req_tmp; + for (int i = 0; i < NR_FETCH_PORTS; i++) begin + prefetch_lookup_req.id |= prefetch_req_ready[i] && prefetch_req_valid[i] ? + prefetch_req[i].id : '0; + end end + end else begin : gen_no_merge_fetches + assign prefetch_req_ready = prefetch_req_ready_tmp; + assign prefetch_lookup_req = prefetch_lookup_req_tmp; end // 2. Response Side From dc8debfe13facd5087a155b47825fdebb3bd7b5f Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 21 Mar 2024 18:20:46 +0100 Subject: [PATCH 06/17] Update formatting --- src/snitch_icache.sv | 138 ++++++++++++++++++++-------------------- src/snitch_icache_l0.sv | 16 ++--- 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/src/snitch_icache.sv b/src/snitch_icache.sv index e64d7fe..09df052 100644 --- a/src/snitch_icache.sv +++ b/src/snitch_icache.sv @@ -235,25 +235,25 @@ module snitch_icache #( ) i_snitch_icache_l0 ( .clk_i ( clk_d2_i ), .rst_ni, - .flush_valid_i ( flush_valid_i[i] ), + .flush_valid_i ( flush_valid_i [i] ), .enable_prefetching_i, - .icache_events_o ( icache_events_o [i] ), - .in_addr_i ( inst_addr_i [i] ), - .in_data_o ( in_cache_data [i] ), - .in_error_o ( in_cache_error [i] ), - .in_valid_i ( in_cache_valid [i] ), - .in_ready_o ( in_cache_ready [i] ), - - .out_req_addr_o ( local_prefetch_req.addr ), - .out_req_id_o ( local_prefetch_req.id ), + .icache_events_o ( icache_events_o [i] ), + .in_addr_i ( inst_addr_i [i] ), + .in_data_o ( in_cache_data [i] ), + .in_error_o ( in_cache_error [i] ), + .in_valid_i ( in_cache_valid [i] ), + .in_ready_o ( in_cache_ready [i] ), + + .out_req_addr_o ( local_prefetch_req.addr ), + .out_req_id_o ( local_prefetch_req.id ), .out_req_valid_o ( local_prefetch_req_valid ), .out_req_ready_i ( local_prefetch_req_ready ), - .out_rsp_data_i ( local_prefetch_rsp.data ), - .out_rsp_error_i ( local_prefetch_rsp.error ), - .out_rsp_id_i ( local_prefetch_rsp.id ), - .out_rsp_valid_i ( local_prefetch_rsp_valid ), - .out_rsp_ready_o ( local_prefetch_rsp_ready ) + .out_rsp_data_i ( local_prefetch_rsp.data ), + .out_rsp_error_i ( local_prefetch_rsp.error ), + .out_rsp_id_i ( local_prefetch_rsp.id ), + .out_rsp_valid_i ( local_prefetch_rsp_valid ), + .out_rsp_ready_o ( local_prefetch_rsp_ready ) ); isochronous_spill_register #( @@ -526,37 +526,37 @@ module snitch_icache #( if (SERIAL_LOOKUP) begin : gen_serial_lookup snitch_icache_lookup_serial #( - .CFG (CFG), - .sram_cfg_tag_t (sram_cfg_tag_t), - .sram_cfg_data_t (sram_cfg_data_t) + .CFG ( CFG ), + .sram_cfg_tag_t ( sram_cfg_tag_t ), + .sram_cfg_data_t ( sram_cfg_data_t ) ) i_lookup ( .clk_i, .rst_ni, - .flush_valid_i (flush_valid_lookup ), - .flush_ready_o (flush_ready_lookup ), - - .in_addr_i ( prefetch_lookup_req.addr ), - .in_id_i ( prefetch_lookup_req.id ), - .in_valid_i ( prefetch_lookup_req_valid ), - .in_ready_o ( prefetch_lookup_req_ready ), - - .out_addr_o ( lookup_addr ), - .out_id_o ( lookup_id ), - .out_set_o ( lookup_set ), - .out_hit_o ( lookup_hit ), - .out_data_o ( lookup_data ), - .out_error_o ( lookup_error ), - .out_valid_o ( lookup_valid ), - .out_ready_i ( lookup_ready ), - - .write_addr_i ( write_addr ), - .write_set_i ( write_set ), - .write_data_i ( write_data ), - .write_tag_i ( write_tag ), - .write_error_i ( write_error ), - .write_valid_i ( write_valid ), - .write_ready_o ( write_ready ), + .flush_valid_i ( flush_valid_lookup ), + .flush_ready_o ( flush_ready_lookup ), + + .in_addr_i ( prefetch_lookup_req.addr ), + .in_id_i ( prefetch_lookup_req.id ), + .in_valid_i ( prefetch_lookup_req_valid ), + .in_ready_o ( prefetch_lookup_req_ready ), + + .out_addr_o ( lookup_addr ), + .out_id_o ( lookup_id ), + .out_set_o ( lookup_set ), + .out_hit_o ( lookup_hit ), + .out_data_o ( lookup_data ), + .out_error_o ( lookup_error ), + .out_valid_o ( lookup_valid ), + .out_ready_i ( lookup_ready ), + + .write_addr_i ( write_addr ), + .write_set_i ( write_set ), + .write_data_i ( write_data ), + .write_tag_i ( write_tag ), + .write_error_i ( write_error ), + .write_valid_i ( write_valid ), + .write_ready_o ( write_ready ), .sram_cfg_tag_i, .sram_cfg_data_i @@ -564,37 +564,37 @@ module snitch_icache #( end else begin : gen_parallel_lookup snitch_icache_lookup_parallel #( - .CFG (CFG), - .sram_cfg_tag_t (sram_cfg_tag_t), - .sram_cfg_data_t (sram_cfg_data_t) + .CFG ( CFG ), + .sram_cfg_tag_t ( sram_cfg_tag_t ), + .sram_cfg_data_t ( sram_cfg_data_t ) ) i_lookup ( .clk_i, .rst_ni, - .flush_valid_i (flush_valid_lookup ), - .flush_ready_o (flush_ready_lookup ), - - .in_addr_i ( prefetch_lookup_req.addr ), - .in_id_i ( prefetch_lookup_req.id ), - .in_valid_i ( prefetch_lookup_req_valid ), - .in_ready_o ( prefetch_lookup_req_ready ), - - .out_addr_o ( lookup_addr ), - .out_id_o ( lookup_id ), - .out_set_o ( lookup_set ), - .out_hit_o ( lookup_hit ), - .out_data_o ( lookup_data ), - .out_error_o ( lookup_error ), - .out_valid_o ( lookup_valid ), - .out_ready_i ( lookup_ready ), - - .write_addr_i ( write_addr ), - .write_set_i ( write_set ), - .write_data_i ( write_data ), - .write_tag_i ( write_tag ), - .write_error_i ( write_error ), - .write_valid_i ( write_valid ), - .write_ready_o ( write_ready ), + .flush_valid_i ( flush_valid_lookup ), + .flush_ready_o ( flush_ready_lookup ), + + .in_addr_i ( prefetch_lookup_req.addr ), + .in_id_i ( prefetch_lookup_req.id ), + .in_valid_i ( prefetch_lookup_req_valid ), + .in_ready_o ( prefetch_lookup_req_ready ), + + .out_addr_o ( lookup_addr ), + .out_id_o ( lookup_id ), + .out_set_o ( lookup_set ), + .out_hit_o ( lookup_hit ), + .out_data_o ( lookup_data ), + .out_error_o ( lookup_error ), + .out_valid_o ( lookup_valid ), + .out_ready_i ( lookup_ready ), + + .write_addr_i ( write_addr ), + .write_set_i ( write_set ), + .write_data_i ( write_data ), + .write_tag_i ( write_tag ), + .write_error_i ( write_error ), + .write_valid_i ( write_valid ), + .write_ready_o ( write_ready ), .sram_cfg_tag_i, .sram_cfg_data_i diff --git a/src/snitch_icache_l0.sv b/src/snitch_icache_l0.sv index 3c1027d..43a9250 100644 --- a/src/snitch_icache_l0.sv +++ b/src/snitch_icache_l0.sv @@ -17,14 +17,14 @@ module snitch_icache_l0 import snitch_icache_pkg::*; #( input logic rst_ni, input logic flush_valid_i, - input logic enable_prefetching_i, - output icache_events_t icache_events_o, - - input logic [CFG.FETCH_AW-1:0] in_addr_i, - input logic in_valid_i, - output logic [CFG.FETCH_DW-1:0] in_data_o, - output logic in_ready_o, - output logic in_error_o, + input logic enable_prefetching_i, + output icache_l0_events_t icache_events_o, + + input logic [CFG.FETCH_AW-1:0] in_addr_i, + input logic in_valid_i, + output logic [CFG.FETCH_DW-1:0] in_data_o, + output logic in_ready_o, + output logic in_error_o, output logic [CFG.FETCH_AW-1:0] out_req_addr_o, output logic [CFG.ID_WIDTH-1:0] out_req_id_o, From 6d61fd43c4f7c8f1a81682bd844ac78a12e35e63 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 21 Mar 2024 18:22:01 +0100 Subject: [PATCH 07/17] Rename l0 events struct --- src/snitch_icache.sv | 8 ++++---- src/snitch_icache_pkg.sv | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/snitch_icache.sv b/src/snitch_icache.sv index 09df052..304cc6c 100644 --- a/src/snitch_icache.sv +++ b/src/snitch_icache.sv @@ -7,7 +7,7 @@ `include "common_cells/registers.svh" -module snitch_icache #( +module snitch_icache import snitch_icache_pkg::*; #( /// Number of request (fetch) ports parameter int unsigned NR_FETCH_PORTS = -1, /// L0 Cache Line Count @@ -61,8 +61,8 @@ module snitch_icache #( input logic clk_d2_i, input logic rst_ni, - input logic enable_prefetching_i, - output snitch_icache_pkg::icache_events_t [NR_FETCH_PORTS-1:0] icache_events_o, + input logic enable_prefetching_i, + output icache_l0_events_t [NR_FETCH_PORTS-1:0] icache_l0_events_o, input logic [NR_FETCH_PORTS-1:0] flush_valid_i, output logic [NR_FETCH_PORTS-1:0] flush_ready_o, @@ -237,7 +237,7 @@ module snitch_icache #( .rst_ni, .flush_valid_i ( flush_valid_i [i] ), .enable_prefetching_i, - .icache_events_o ( icache_events_o [i] ), + .icache_events_o ( icache_l0_events_o [i] ), .in_addr_i ( inst_addr_i [i] ), .in_data_o ( in_cache_data [i] ), .in_error_o ( in_cache_error [i] ), diff --git a/src/snitch_icache_pkg.sv b/src/snitch_icache_pkg.sv index 17cfa37..aba42a0 100644 --- a/src/snitch_icache_pkg.sv +++ b/src/snitch_icache_pkg.sv @@ -12,7 +12,7 @@ package snitch_icache_pkg; logic l0_prefetch; logic l0_double_hit; logic l0_stall; - } icache_events_t; + } icache_l0_events_t; typedef struct packed { // Parameters passed to the root module. From c58c0ef7510adb29a65bf949a1fb2dd43329859c Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 21 Mar 2024 18:22:35 +0100 Subject: [PATCH 08/17] Add l1 events --- src/pulp_icache_wrap.sv | 6 ++++-- src/snitch_icache.sv | 3 +++ src/snitch_icache_lookup_parallel.sv | 16 ++++++++++++++-- src/snitch_icache_lookup_serial.sv | 16 ++++++++++++++-- src/snitch_icache_pkg.sv | 7 +++++++ src/snitch_read_only_cache.sv | 7 +++++-- test/snitch_read_only_cache_tb.sv | 5 ++++- 7 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/pulp_icache_wrap.sv b/src/pulp_icache_wrap.sv index 6d4e23a..6c470f5 100644 --- a/src/pulp_icache_wrap.sv +++ b/src/pulp_icache_wrap.sv @@ -61,7 +61,8 @@ module pulp_icache_wrap #( output logic [NumFetchPorts-1:0] fetch_rerror_o, input logic enable_prefetching_i, - output snitch_icache_pkg::icache_events_t [NumFetchPorts-1:0] icache_events_o, + output snitch_icache_pkg::icache_l0_events_t [NumFetchPorts-1:0] icache_l0_events_o, + output snitch_icache_pkg::icache_l1_events_t icache_l1_events_o, input logic [NumFetchPorts-1:0] flush_valid_i, output logic [NumFetchPorts-1:0] flush_ready_o, @@ -218,7 +219,8 @@ module pulp_icache_wrap #( .rst_ni, .enable_prefetching_i, - .icache_events_o, + .icache_l0_events_o, + .icache_l1_events_o, .flush_valid_i, .flush_ready_o, diff --git a/src/snitch_icache.sv b/src/snitch_icache.sv index 304cc6c..88ccdc3 100644 --- a/src/snitch_icache.sv +++ b/src/snitch_icache.sv @@ -63,6 +63,7 @@ module snitch_icache import snitch_icache_pkg::*; #( input logic enable_prefetching_i, output icache_l0_events_t [NR_FETCH_PORTS-1:0] icache_l0_events_o, + output icache_l1_events_t icache_l1_events_o, input logic [NR_FETCH_PORTS-1:0] flush_valid_i, output logic [NR_FETCH_PORTS-1:0] flush_ready_o, @@ -535,6 +536,7 @@ module snitch_icache import snitch_icache_pkg::*; #( .flush_valid_i ( flush_valid_lookup ), .flush_ready_o ( flush_ready_lookup ), + .icache_events_o ( icache_l1_events_o ), .in_addr_i ( prefetch_lookup_req.addr ), .in_id_i ( prefetch_lookup_req.id ), @@ -573,6 +575,7 @@ module snitch_icache import snitch_icache_pkg::*; #( .flush_valid_i ( flush_valid_lookup ), .flush_ready_o ( flush_ready_lookup ), + .icache_events_o ( icache_l1_events_o ), .in_addr_i ( prefetch_lookup_req.addr ), .in_id_i ( prefetch_lookup_req.id ), diff --git a/src/snitch_icache_lookup_parallel.sv b/src/snitch_icache_lookup_parallel.sv index 26b5d61..4a8fa46 100644 --- a/src/snitch_icache_lookup_parallel.sv +++ b/src/snitch_icache_lookup_parallel.sv @@ -5,8 +5,8 @@ // Fabian Schuiki /// An actual cache lookup. -module snitch_icache_lookup_parallel #( - parameter snitch_icache_pkg::config_t CFG = '0, +module snitch_icache_lookup_parallel import snitch_icache_pkg::*; #( + parameter config_t CFG = '0, /// Configuration input types for SRAMs used in implementation. parameter type sram_cfg_data_t = logic, parameter type sram_cfg_tag_t = logic @@ -16,6 +16,7 @@ module snitch_icache_lookup_parallel #( input logic flush_valid_i, output logic flush_ready_o, + output icache_l1_events_t icache_events_o, input logic [CFG.FETCH_AW-1:0] in_addr_i, input logic [CFG.ID_WIDTH-1:0] in_id_i, @@ -250,6 +251,17 @@ module snitch_icache_lookup_parallel #( assign out_error_o = data_q.error; assign out_valid_o = buffer_valid; + // ------------------ + // Performance Events + // ------------------ + always_comb begin + icache_events_o = '0; + icache_events_o.l1_miss = valid_q & ~data_d.hit; + icache_events_o.l1_hit = valid_q & data_d.hit; + icache_events_o.l1_stall = in_valid_i & ~in_ready_o; + icache_events_o.l1_handler_stall = out_valid_o & ~out_ready_i; + end + // Assertions `include "common_cells/assertions.svh" `ASSERT(i_rsp_buffer_ready, (valid_q |-> buffer_ready), clk_i, !rst_ni) diff --git a/src/snitch_icache_lookup_serial.sv b/src/snitch_icache_lookup_serial.sv index 7690e3d..7584e3e 100644 --- a/src/snitch_icache_lookup_serial.sv +++ b/src/snitch_icache_lookup_serial.sv @@ -7,8 +7,8 @@ `include "common_cells/registers.svh" /// An actual cache lookup. -module snitch_icache_lookup_serial #( - parameter snitch_icache_pkg::config_t CFG = '0, +module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( + parameter config_t CFG = '0, /// Configuration input types for SRAMs used in implementation. parameter type sram_cfg_data_t = logic, parameter type sram_cfg_tag_t = logic @@ -18,6 +18,7 @@ module snitch_icache_lookup_serial #( input logic flush_valid_i, output logic flush_ready_o, + output icache_l1_events_t icache_events_o, input logic [CFG.FETCH_AW-1:0] in_addr_i, input logic [CFG.ID_WIDTH-1:0] in_id_i, @@ -325,4 +326,15 @@ module snitch_icache_lookup_serial #( assign out_valid_o = data_valid; assign data_ready = out_ready_i; + // ------------------ + // Performance Events + // ------------------ + always_comb begin + icache_events_o = '0; + icache_events_o.l1_miss = req_handshake & ~tag_rsp_s.hit; + icache_events_o.l1_hit = req_handshake & tag_rsp_s.hit; + icache_events_o.l1_stall = in_valid_i & ~in_ready_o; + icache_events_o.l1_handler_stall = out_valid_o & ~out_ready_i; + end + endmodule diff --git a/src/snitch_icache_pkg.sv b/src/snitch_icache_pkg.sv index aba42a0..738f222 100644 --- a/src/snitch_icache_pkg.sv +++ b/src/snitch_icache_pkg.sv @@ -14,6 +14,13 @@ package snitch_icache_pkg; logic l0_stall; } icache_l0_events_t; + typedef struct packed { + logic l1_miss; + logic l1_hit; + logic l1_stall; + logic l1_handler_stall; + } icache_l1_events_t; + typedef struct packed { // Parameters passed to the root module. int unsigned NR_FETCH_PORTS; diff --git a/src/snitch_read_only_cache.sv b/src/snitch_read_only_cache.sv index 9142abc..ecb1daa 100644 --- a/src/snitch_read_only_cache.sv +++ b/src/snitch_read_only_cache.sv @@ -8,7 +8,7 @@ /// Serve read memory requests from a read-only cache. /// The cacheable region can be runtime configured. All writes and read /// requests outside the configured regions will be forwarded. -module snitch_read_only_cache #( +module snitch_read_only_cache import snitch_icache_pkg::*; #( /// Cache Line Width parameter int unsigned LineWidth = -1, /// The number of cache lines per set. Power of two; >= 2. @@ -39,6 +39,7 @@ module snitch_read_only_cache #( input logic enable_i, input logic flush_valid_i, output logic flush_ready_o, + output icache_l1_events_t icache_events_o, input logic [NrAddrRules-1:0][AxiAddrWidth-1:0] start_addr_i, input logic [NrAddrRules-1:0][AxiAddrWidth-1:0] end_addr_i, input slv_req_t axi_slv_req_i, @@ -191,7 +192,7 @@ module snitch_read_only_cache #( // Cache Logic // -------------------------------------------------- localparam int unsigned PendingCount = MaxTrans; - localparam snitch_icache_pkg::config_t CFG = '{ + localparam config_t CFG = '{ LINE_WIDTH: LineWidth, LINE_COUNT: LineCount, SET_COUNT: SetCount, @@ -293,6 +294,7 @@ module snitch_read_only_cache #( .flush_valid_i ( flush_valid_i ), .flush_ready_o ( flush_ready_o ), + .icache_events_o, .in_addr_i ( in_addr ), .in_id_i ( in_id ), @@ -330,6 +332,7 @@ module snitch_read_only_cache #( .flush_valid_i ( flush_valid_i ), .flush_ready_o ( flush_ready_o ), + .icache_events_o, .in_addr_i ( in_addr ), .in_id_i ( in_id ), diff --git a/test/snitch_read_only_cache_tb.sv b/test/snitch_read_only_cache_tb.sv index 1f3687e..a3835c8 100644 --- a/test/snitch_read_only_cache_tb.sv +++ b/test/snitch_read_only_cache_tb.sv @@ -379,12 +379,15 @@ module snitch_read_only_cache_tb #( .enable_i ( 1'b1 ), .flush_valid_i ( 1'b0 ), .flush_ready_o ( /*unused*/ ), + .icache_events_o ( ), .start_addr_i ( {CachedRegionStart} ), .end_addr_i ( {CachedRegionEnd} ), .axi_slv_req_i ( axi_mst_req ), .axi_slv_rsp_o ( axi_mst_resp ), .axi_mst_req_o ( axi_slv_req ), - .axi_mst_rsp_i ( axi_slv_resp ) + .axi_mst_rsp_i ( axi_slv_resp ), + .sram_cfg_data_i('0), + .sram_cfg_tag_i ('0) ); task static cycle_start; From 6a6d9a014b05580cee4a41cbf98ab47216016b01 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 20 Feb 2024 19:48:55 +0100 Subject: [PATCH 09/17] Add plru tree to L0 --- src/snitch_icache.sv | 1 + src/snitch_icache_l0.sv | 53 +++++++++++++++++++++++++---------- src/snitch_icache_pkg.sv | 1 + src/snitch_read_only_cache.sv | 1 + test/snitch_icache_l0_tb.sv | 1 + 5 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/snitch_icache.sv b/src/snitch_icache.sv index 88ccdc3..6a52eb4 100644 --- a/src/snitch_icache.sv +++ b/src/snitch_icache.sv @@ -99,6 +99,7 @@ module snitch_icache import snitch_icache_pkg::*; #( EARLY_LATCH: EARLY_LATCH, BUFFER_LOOKUP: 0, GUARANTEE_ORDERING: 0, + L0_PLRU: 1, FETCH_ALIGN: $clog2(FETCH_DW/8), FILL_ALIGN: $clog2(FILL_DW/8), diff --git a/src/snitch_icache_l0.sv b/src/snitch_icache_l0.sv index 43a9250..7e1fa92 100644 --- a/src/snitch_icache_l0.sv +++ b/src/snitch_icache_l0.sv @@ -197,21 +197,46 @@ 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; + + 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 + + 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 end end + + `FF(cnt_q, cnt_d, '0) + end always_comb begin : flush @@ -226,8 +251,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 // ------------- diff --git a/src/snitch_icache_pkg.sv b/src/snitch_icache_pkg.sv index 738f222..8fffbc3 100644 --- a/src/snitch_icache_pkg.sv +++ b/src/snitch_icache_pkg.sv @@ -37,6 +37,7 @@ package snitch_icache_pkg; bit EARLY_LATCH; bit BUFFER_LOOKUP; bit GUARANTEE_ORDERING; + bit L0_PLRU; // Derived values. int unsigned FETCH_ALIGN; diff --git a/src/snitch_read_only_cache.sv b/src/snitch_read_only_cache.sv index ecb1daa..478bc51 100644 --- a/src/snitch_read_only_cache.sv +++ b/src/snitch_read_only_cache.sv @@ -205,6 +205,7 @@ 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 FETCH_ALIGN: $clog2(AxiDataWidth/8), FILL_ALIGN: $clog2(AxiDataWidth/8), diff --git a/test/snitch_icache_l0_tb.sv b/test/snitch_icache_l0_tb.sv index 080ad6f..7475a30 100644 --- a/test/snitch_icache_l0_tb.sv +++ b/test/snitch_icache_l0_tb.sv @@ -91,6 +91,7 @@ module snitch_icache_l0_tb #( EARLY_LATCH: EARLY_LATCH, BUFFER_LOOKUP: BUFFER_LOOKUP, GUARANTEE_ORDERING: GUARANTEE_ORDERING, + L0_PLRU: 1'b1, FETCH_ALIGN: $clog2(FETCH_DW/8), FILL_ALIGN: $clog2(FILL_DW/8), From c8520bcd66e6892930ded3618b8712f012d6fc13 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Wed, 21 Feb 2024 12:03:36 +0100 Subject: [PATCH 10/17] Add PLRU eviction to L1 Current addition is directly with FFs in the handler, not re-using tag storage. --- src/snitch_icache.sv | 1 + src/snitch_icache_handler.sv | 63 +++++++++++++++++++++++++++++------ src/snitch_icache_pkg.sv | 1 + src/snitch_read_only_cache.sv | 1 + test/snitch_icache_l0_tb.sv | 1 + 5 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/snitch_icache.sv b/src/snitch_icache.sv index 6a52eb4..8d2f0b4 100644 --- a/src/snitch_icache.sv +++ b/src/snitch_icache.sv @@ -100,6 +100,7 @@ module snitch_icache import snitch_icache_pkg::*; #( BUFFER_LOOKUP: 0, GUARANTEE_ORDERING: 0, L0_PLRU: 1, + L1_PLRU: 1, FETCH_ALIGN: $clog2(FETCH_DW/8), FILL_ALIGN: $clog2(FILL_DW/8), diff --git a/src/snitch_icache_handler.sv b/src/snitch_icache_handler.sv index 54a2e6b..3675317 100644 --- a/src/snitch_icache_handler.sv +++ b/src/snitch_icache_handler.sv @@ -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.SET_COUNT-1:0] used_masks; + logic [CFG.LINE_COUNT-1:0][CFG.SET_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.SET_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.SET_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 diff --git a/src/snitch_icache_pkg.sv b/src/snitch_icache_pkg.sv index 8fffbc3..b018b3c 100644 --- a/src/snitch_icache_pkg.sv +++ b/src/snitch_icache_pkg.sv @@ -38,6 +38,7 @@ package snitch_icache_pkg; bit BUFFER_LOOKUP; bit GUARANTEE_ORDERING; bit L0_PLRU; + bit L1_PLRU; // Derived values. int unsigned FETCH_ALIGN; diff --git a/src/snitch_read_only_cache.sv b/src/snitch_read_only_cache.sv index 478bc51..3a7cce9 100644 --- a/src/snitch_read_only_cache.sv +++ b/src/snitch_read_only_cache.sv @@ -206,6 +206,7 @@ module snitch_read_only_cache import snitch_icache_pkg::*; #( 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), diff --git a/test/snitch_icache_l0_tb.sv b/test/snitch_icache_l0_tb.sv index 7475a30..2075421 100644 --- a/test/snitch_icache_l0_tb.sv +++ b/test/snitch_icache_l0_tb.sv @@ -92,6 +92,7 @@ module snitch_icache_l0_tb #( 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), From 229ed4ff412024a8c41cc8817e532f92beeb2c4a Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 26 Mar 2024 17:39:27 +0100 Subject: [PATCH 11/17] Allow early_tag_width == tag_width --- src/snitch_icache.sv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/snitch_icache.sv b/src/snitch_icache.sv index 8d2f0b4..5195ed6 100644 --- a/src/snitch_icache.sv +++ b/src/snitch_icache.sv @@ -127,7 +127,7 @@ module snitch_icache import snitch_icache_pkg::*; #( assert(FETCH_DW > 0); assert(FILL_AW > 0); assert(FILL_DW > 0); - assert(CFG.L0_EARLY_TAG_WIDTH < CFG.L0_TAG_WIDTH); + assert(CFG.L0_EARLY_TAG_WIDTH <= CFG.L0_TAG_WIDTH); assert(FETCH_AW == FILL_AW); assert(2**$clog2(LINE_WIDTH) == LINE_WIDTH) else $fatal(1, "Cache LINE_WIDTH %0d is not a power of two", LINE_WIDTH); From f0e2ed8c210621db275a23c2cd8ed29f26c2733c Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 25 Apr 2024 15:18:29 +0200 Subject: [PATCH 12/17] Add control register file --- .github/workflows/lint.yml | 3 + Bender.yml | 10 +- Makefile | 11 +- src/ctrl_unit/cluster_icache_ctrl.hjson | 138 ++ src/ctrl_unit/cluster_icache_ctrl_reg_pkg.sv | 272 +++ src/ctrl_unit/cluster_icache_ctrl_reg_top.sv | 2116 ++++++++++++++++++ src/ctrl_unit/cluster_icache_ctrl_unit.sv | 96 + 7 files changed, 2642 insertions(+), 4 deletions(-) create mode 100644 src/ctrl_unit/cluster_icache_ctrl.hjson create mode 100644 src/ctrl_unit/cluster_icache_ctrl_reg_pkg.sv create mode 100644 src/ctrl_unit/cluster_icache_ctrl_reg_top.sv create mode 100644 src/ctrl_unit/cluster_icache_ctrl_unit.sv diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 2b6f1c2..bb2a297 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -23,6 +23,9 @@ jobs: paths: | ./src ./test + exclude_paths: | + ./src/ctrl_unit/cluster_icache_ctrl_reg_top.sv + ./src/ctrl_unit/cluster_icache_ctrl_reg_pkg.sv github_token: ${{ secrets.GITHUB_TOKEN }} fail_on_error: true reviewdog_reporter: github-check diff --git a/Bender.yml b/Bender.yml index 6bdfef8..985466d 100644 --- a/Bender.yml +++ b/Bender.yml @@ -16,6 +16,7 @@ dependencies: tech_cells_generic: { git: "https://github.com/pulp-platform/tech_cells_generic.git", version: 0.2.11 } axi: { git: "https://github.com/pulp-platform/axi.git", version: 0.39.1 } scm: { git: "https://github.com/pulp-platform/scm.git", version: 1.1.0 } + register_interface: { git: "https://github.com/pulp-platform/register_interface.git", version: 0.4.4 } sources: # Source files grouped in levels. Files in level 0 have no dependencies on files in this @@ -37,9 +38,12 @@ sources: # Level 3 - src/snitch_icache.sv - src/snitch_read_only_cache.sv - - target: pulp - files: - - src/pulp_icache_wrap.sv + # Level 4 + - src/pulp_icache_wrap.sv + - files: # ctrl_unit + - src/ctrl_unit/cluster_icache_ctrl_reg_pkg.sv + - src/ctrl_unit/cluster_icache_ctrl_reg_top.sv + - src/ctrl_unit/cluster_icache_ctrl_unit.sv - target: test files: - test/snitch_icache_l0_tb.sv diff --git a/Makefile b/Makefile index db20e27..46df7eb 100644 --- a/Makefile +++ b/Makefile @@ -9,13 +9,22 @@ VLOG_FLAGS += -svinputport=compat VLOG_FLAGS += -suppress 2583 VLOG_FLAGS += +cover=sbecft +CTRL_UNIT_DIR = src/ctrl_unit +CTRL_UNIT = $(CTRL_UNIT_DIR)/cluster_icache_ctrl + Bender.lock: $(BENDER) update .bender: $(BENDER) checkout -compile.tcl: .bender +.PHONY: gen_hw +gen_hw: .bender $(CTRL_UNIT)_reg_top.sv + +$(CTRL_UNIT)_reg_top.sv: .bender $(CTRL_UNIT).hjson + python $(shell $(BENDER) path register_interface)/vendor/lowrisc_opentitan/util/regtool.py $(CTRL_UNIT).hjson -t $(CTRL_UNIT_DIR) -r + +compile.tcl: .bender Bender.yml Bender.lock $(BENDER) script vsim -t test \ --vlog-arg="$(VLOG_FLAGS)" \ > compile.tcl diff --git a/src/ctrl_unit/cluster_icache_ctrl.hjson b/src/ctrl_unit/cluster_icache_ctrl.hjson new file mode 100644 index 0000000..5286d71 --- /dev/null +++ b/src/ctrl_unit/cluster_icache_ctrl.hjson @@ -0,0 +1,138 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +{ + name: "cluster_icache_ctrl", + clock_primary: "clk_i", + reset_primary: "rst_ni", + bus_interfaces: [ + { protocol: "reg_iface", + direction: "device" + } + ], + + param_list: [ + { name: "NumCores", + desc: "Number of cores", + default: "8" + }, + { name: "NumAvailableCounters", + desc: "Number of available counters", + default: "44" // NumL1Events + NumCores * NumL0Events + }, + ], + + regwidth: "32", + registers: [ + { name: "enable", + desc: "", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "0", + name: "enable", + desc: "", + resval: 0x1 + } + ] + }, + { name: "flush", + desc: "Flush all levels of the cache", + swaccess: "rw", + hwaccess: "hrw", + hwqe: "true", + hwext: "true", + fields: [ + { bits: "0", + name: "flush", + desc: "", + resval: 0x0 + } + ] + }, + { name: "flush_l1_only", + desc: "not yet functional", + swaccess: "rw", + hwaccess: "hrw", + hwext: "true", + hwqe: "true", + fields: [ + { bits: "0", + name: "flush", + desc: "", + resval: 0x0 + } + ] + }, + { name: "sel_flush_icache", + desc: "flush specified L0 banks (and currently the complete L1)", + swaccess: "rw", + hwaccess: "hrw", + hwext: "true", + hwqe: "true", + fields: [ + { bits: "NumCores-1:0", + name: "flush", + desc: "", + resval: 0x0000_0000 + } + ] + }, + { name: "clear_counters", + desc: "Clear all performance counters", + swaccess: "rw", + hwaccess: "hrw", + hwqe: "true", + hwext: "true", + fields: [ + { bits: "0", + name: "clear", + desc: "", + resval: 0x0 + } + ] + }, + { name: "enable_counters", + desc: "Enable performance counters", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "0", + name: "enable", + desc: "", + resval: 0x1 + } + ] + }, + { skipto: "0x1C" }, + { name: "enable_prefetch", + desc: "Enable prefetching", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "0", + name: "enable", + desc: "", + resval: 0x1 + } + ] + }, + { multireg: { + name: "counters", + desc: "Performance counters", + count: "NumAvailableCounters", + cname: "id", + swaccess: "rw0c", + hwaccess: "hrw", + fields: [ + { bits: "31:0", + name: "counter", + desc: "", + resval: 0x0000_0000 + } + ] + } + }, + ], +} diff --git a/src/ctrl_unit/cluster_icache_ctrl_reg_pkg.sv b/src/ctrl_unit/cluster_icache_ctrl_reg_pkg.sv new file mode 100644 index 0000000..8df9fbe --- /dev/null +++ b/src/ctrl_unit/cluster_icache_ctrl_reg_pkg.sv @@ -0,0 +1,272 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Package auto-generated by `reggen` containing data structure + +package cluster_icache_ctrl_reg_pkg; + + // Param list + parameter int NumCores = 8; + parameter int NumAvailableCounters = 44; + + // Address widths within the block + parameter int BlockAw = 8; + + //////////////////////////// + // Typedefs for registers // + //////////////////////////// + + typedef struct packed { + logic q; + } cluster_icache_ctrl_reg2hw_enable_reg_t; + + typedef struct packed { + logic q; + logic qe; + } cluster_icache_ctrl_reg2hw_flush_reg_t; + + typedef struct packed { + logic q; + logic qe; + } cluster_icache_ctrl_reg2hw_flush_l1_only_reg_t; + + typedef struct packed { + logic [7:0] q; + logic qe; + } cluster_icache_ctrl_reg2hw_sel_flush_icache_reg_t; + + typedef struct packed { + logic q; + logic qe; + } cluster_icache_ctrl_reg2hw_clear_counters_reg_t; + + typedef struct packed { + logic q; + } cluster_icache_ctrl_reg2hw_enable_counters_reg_t; + + typedef struct packed { + logic q; + } cluster_icache_ctrl_reg2hw_enable_prefetch_reg_t; + + typedef struct packed { + logic [31:0] q; + } cluster_icache_ctrl_reg2hw_counters_mreg_t; + + typedef struct packed { + logic d; + } cluster_icache_ctrl_hw2reg_flush_reg_t; + + typedef struct packed { + logic d; + } cluster_icache_ctrl_hw2reg_flush_l1_only_reg_t; + + typedef struct packed { + logic [7:0] d; + } cluster_icache_ctrl_hw2reg_sel_flush_icache_reg_t; + + typedef struct packed { + logic d; + } cluster_icache_ctrl_hw2reg_clear_counters_reg_t; + + typedef struct packed { + logic [31:0] d; + logic de; + } cluster_icache_ctrl_hw2reg_counters_mreg_t; + + // Register -> HW type + typedef struct packed { + cluster_icache_ctrl_reg2hw_enable_reg_t enable; // [1425:1425] + cluster_icache_ctrl_reg2hw_flush_reg_t flush; // [1424:1423] + cluster_icache_ctrl_reg2hw_flush_l1_only_reg_t flush_l1_only; // [1422:1421] + cluster_icache_ctrl_reg2hw_sel_flush_icache_reg_t sel_flush_icache; // [1420:1412] + cluster_icache_ctrl_reg2hw_clear_counters_reg_t clear_counters; // [1411:1410] + cluster_icache_ctrl_reg2hw_enable_counters_reg_t enable_counters; // [1409:1409] + cluster_icache_ctrl_reg2hw_enable_prefetch_reg_t enable_prefetch; // [1408:1408] + cluster_icache_ctrl_reg2hw_counters_mreg_t [43:0] counters; // [1407:0] + } cluster_icache_ctrl_reg2hw_t; + + // HW -> register type + typedef struct packed { + cluster_icache_ctrl_hw2reg_flush_reg_t flush; // [1462:1462] + cluster_icache_ctrl_hw2reg_flush_l1_only_reg_t flush_l1_only; // [1461:1461] + cluster_icache_ctrl_hw2reg_sel_flush_icache_reg_t sel_flush_icache; // [1460:1453] + cluster_icache_ctrl_hw2reg_clear_counters_reg_t clear_counters; // [1452:1452] + cluster_icache_ctrl_hw2reg_counters_mreg_t [43:0] counters; // [1451:0] + } cluster_icache_ctrl_hw2reg_t; + + // Register offsets + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_ENABLE_OFFSET = 8'h 0; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_FLUSH_OFFSET = 8'h 4; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_FLUSH_L1_ONLY_OFFSET = 8'h 8; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_SEL_FLUSH_ICACHE_OFFSET = 8'h c; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_CLEAR_COUNTERS_OFFSET = 8'h 10; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_ENABLE_COUNTERS_OFFSET = 8'h 14; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_ENABLE_PREFETCH_OFFSET = 8'h 1c; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_0_OFFSET = 8'h 20; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_1_OFFSET = 8'h 24; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_2_OFFSET = 8'h 28; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_3_OFFSET = 8'h 2c; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_4_OFFSET = 8'h 30; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_5_OFFSET = 8'h 34; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_6_OFFSET = 8'h 38; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_7_OFFSET = 8'h 3c; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_8_OFFSET = 8'h 40; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_9_OFFSET = 8'h 44; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_10_OFFSET = 8'h 48; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_11_OFFSET = 8'h 4c; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_12_OFFSET = 8'h 50; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_13_OFFSET = 8'h 54; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_14_OFFSET = 8'h 58; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_15_OFFSET = 8'h 5c; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_16_OFFSET = 8'h 60; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_17_OFFSET = 8'h 64; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_18_OFFSET = 8'h 68; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_19_OFFSET = 8'h 6c; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_20_OFFSET = 8'h 70; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_21_OFFSET = 8'h 74; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_22_OFFSET = 8'h 78; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_23_OFFSET = 8'h 7c; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_24_OFFSET = 8'h 80; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_25_OFFSET = 8'h 84; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_26_OFFSET = 8'h 88; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_27_OFFSET = 8'h 8c; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_28_OFFSET = 8'h 90; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_29_OFFSET = 8'h 94; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_30_OFFSET = 8'h 98; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_31_OFFSET = 8'h 9c; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_32_OFFSET = 8'h a0; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_33_OFFSET = 8'h a4; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_34_OFFSET = 8'h a8; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_35_OFFSET = 8'h ac; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_36_OFFSET = 8'h b0; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_37_OFFSET = 8'h b4; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_38_OFFSET = 8'h b8; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_39_OFFSET = 8'h bc; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_40_OFFSET = 8'h c0; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_41_OFFSET = 8'h c4; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_42_OFFSET = 8'h c8; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_43_OFFSET = 8'h cc; + + // Reset values for hwext registers and their fields + parameter logic [0:0] CLUSTER_ICACHE_CTRL_FLUSH_RESVAL = 1'h 0; + parameter logic [0:0] CLUSTER_ICACHE_CTRL_FLUSH_FLUSH_RESVAL = 1'h 0; + parameter logic [0:0] CLUSTER_ICACHE_CTRL_FLUSH_L1_ONLY_RESVAL = 1'h 0; + parameter logic [0:0] CLUSTER_ICACHE_CTRL_FLUSH_L1_ONLY_FLUSH_RESVAL = 1'h 0; + parameter logic [7:0] CLUSTER_ICACHE_CTRL_SEL_FLUSH_ICACHE_RESVAL = 8'h 0; + parameter logic [7:0] CLUSTER_ICACHE_CTRL_SEL_FLUSH_ICACHE_FLUSH_RESVAL = 8'h 0; + parameter logic [0:0] CLUSTER_ICACHE_CTRL_CLEAR_COUNTERS_RESVAL = 1'h 0; + parameter logic [0:0] CLUSTER_ICACHE_CTRL_CLEAR_COUNTERS_CLEAR_RESVAL = 1'h 0; + + // Register index + typedef enum int { + CLUSTER_ICACHE_CTRL_ENABLE, + CLUSTER_ICACHE_CTRL_FLUSH, + CLUSTER_ICACHE_CTRL_FLUSH_L1_ONLY, + CLUSTER_ICACHE_CTRL_SEL_FLUSH_ICACHE, + CLUSTER_ICACHE_CTRL_CLEAR_COUNTERS, + CLUSTER_ICACHE_CTRL_ENABLE_COUNTERS, + CLUSTER_ICACHE_CTRL_ENABLE_PREFETCH, + CLUSTER_ICACHE_CTRL_COUNTERS_0, + CLUSTER_ICACHE_CTRL_COUNTERS_1, + CLUSTER_ICACHE_CTRL_COUNTERS_2, + CLUSTER_ICACHE_CTRL_COUNTERS_3, + CLUSTER_ICACHE_CTRL_COUNTERS_4, + CLUSTER_ICACHE_CTRL_COUNTERS_5, + CLUSTER_ICACHE_CTRL_COUNTERS_6, + CLUSTER_ICACHE_CTRL_COUNTERS_7, + CLUSTER_ICACHE_CTRL_COUNTERS_8, + CLUSTER_ICACHE_CTRL_COUNTERS_9, + CLUSTER_ICACHE_CTRL_COUNTERS_10, + CLUSTER_ICACHE_CTRL_COUNTERS_11, + CLUSTER_ICACHE_CTRL_COUNTERS_12, + CLUSTER_ICACHE_CTRL_COUNTERS_13, + CLUSTER_ICACHE_CTRL_COUNTERS_14, + CLUSTER_ICACHE_CTRL_COUNTERS_15, + CLUSTER_ICACHE_CTRL_COUNTERS_16, + CLUSTER_ICACHE_CTRL_COUNTERS_17, + CLUSTER_ICACHE_CTRL_COUNTERS_18, + CLUSTER_ICACHE_CTRL_COUNTERS_19, + CLUSTER_ICACHE_CTRL_COUNTERS_20, + CLUSTER_ICACHE_CTRL_COUNTERS_21, + CLUSTER_ICACHE_CTRL_COUNTERS_22, + CLUSTER_ICACHE_CTRL_COUNTERS_23, + CLUSTER_ICACHE_CTRL_COUNTERS_24, + CLUSTER_ICACHE_CTRL_COUNTERS_25, + CLUSTER_ICACHE_CTRL_COUNTERS_26, + CLUSTER_ICACHE_CTRL_COUNTERS_27, + CLUSTER_ICACHE_CTRL_COUNTERS_28, + CLUSTER_ICACHE_CTRL_COUNTERS_29, + CLUSTER_ICACHE_CTRL_COUNTERS_30, + CLUSTER_ICACHE_CTRL_COUNTERS_31, + CLUSTER_ICACHE_CTRL_COUNTERS_32, + CLUSTER_ICACHE_CTRL_COUNTERS_33, + CLUSTER_ICACHE_CTRL_COUNTERS_34, + CLUSTER_ICACHE_CTRL_COUNTERS_35, + CLUSTER_ICACHE_CTRL_COUNTERS_36, + CLUSTER_ICACHE_CTRL_COUNTERS_37, + CLUSTER_ICACHE_CTRL_COUNTERS_38, + CLUSTER_ICACHE_CTRL_COUNTERS_39, + CLUSTER_ICACHE_CTRL_COUNTERS_40, + CLUSTER_ICACHE_CTRL_COUNTERS_41, + CLUSTER_ICACHE_CTRL_COUNTERS_42, + CLUSTER_ICACHE_CTRL_COUNTERS_43 + } cluster_icache_ctrl_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] CLUSTER_ICACHE_CTRL_PERMIT [51] = '{ + 4'b 0001, // index[ 0] CLUSTER_ICACHE_CTRL_ENABLE + 4'b 0001, // index[ 1] CLUSTER_ICACHE_CTRL_FLUSH + 4'b 0001, // index[ 2] CLUSTER_ICACHE_CTRL_FLUSH_L1_ONLY + 4'b 0001, // index[ 3] CLUSTER_ICACHE_CTRL_SEL_FLUSH_ICACHE + 4'b 0001, // index[ 4] CLUSTER_ICACHE_CTRL_CLEAR_COUNTERS + 4'b 0001, // index[ 5] CLUSTER_ICACHE_CTRL_ENABLE_COUNTERS + 4'b 0001, // index[ 6] CLUSTER_ICACHE_CTRL_ENABLE_PREFETCH + 4'b 1111, // index[ 7] CLUSTER_ICACHE_CTRL_COUNTERS_0 + 4'b 1111, // index[ 8] CLUSTER_ICACHE_CTRL_COUNTERS_1 + 4'b 1111, // index[ 9] CLUSTER_ICACHE_CTRL_COUNTERS_2 + 4'b 1111, // index[10] CLUSTER_ICACHE_CTRL_COUNTERS_3 + 4'b 1111, // index[11] CLUSTER_ICACHE_CTRL_COUNTERS_4 + 4'b 1111, // index[12] CLUSTER_ICACHE_CTRL_COUNTERS_5 + 4'b 1111, // index[13] CLUSTER_ICACHE_CTRL_COUNTERS_6 + 4'b 1111, // index[14] CLUSTER_ICACHE_CTRL_COUNTERS_7 + 4'b 1111, // index[15] CLUSTER_ICACHE_CTRL_COUNTERS_8 + 4'b 1111, // index[16] CLUSTER_ICACHE_CTRL_COUNTERS_9 + 4'b 1111, // index[17] CLUSTER_ICACHE_CTRL_COUNTERS_10 + 4'b 1111, // index[18] CLUSTER_ICACHE_CTRL_COUNTERS_11 + 4'b 1111, // index[19] CLUSTER_ICACHE_CTRL_COUNTERS_12 + 4'b 1111, // index[20] CLUSTER_ICACHE_CTRL_COUNTERS_13 + 4'b 1111, // index[21] CLUSTER_ICACHE_CTRL_COUNTERS_14 + 4'b 1111, // index[22] CLUSTER_ICACHE_CTRL_COUNTERS_15 + 4'b 1111, // index[23] CLUSTER_ICACHE_CTRL_COUNTERS_16 + 4'b 1111, // index[24] CLUSTER_ICACHE_CTRL_COUNTERS_17 + 4'b 1111, // index[25] CLUSTER_ICACHE_CTRL_COUNTERS_18 + 4'b 1111, // index[26] CLUSTER_ICACHE_CTRL_COUNTERS_19 + 4'b 1111, // index[27] CLUSTER_ICACHE_CTRL_COUNTERS_20 + 4'b 1111, // index[28] CLUSTER_ICACHE_CTRL_COUNTERS_21 + 4'b 1111, // index[29] CLUSTER_ICACHE_CTRL_COUNTERS_22 + 4'b 1111, // index[30] CLUSTER_ICACHE_CTRL_COUNTERS_23 + 4'b 1111, // index[31] CLUSTER_ICACHE_CTRL_COUNTERS_24 + 4'b 1111, // index[32] CLUSTER_ICACHE_CTRL_COUNTERS_25 + 4'b 1111, // index[33] CLUSTER_ICACHE_CTRL_COUNTERS_26 + 4'b 1111, // index[34] CLUSTER_ICACHE_CTRL_COUNTERS_27 + 4'b 1111, // index[35] CLUSTER_ICACHE_CTRL_COUNTERS_28 + 4'b 1111, // index[36] CLUSTER_ICACHE_CTRL_COUNTERS_29 + 4'b 1111, // index[37] CLUSTER_ICACHE_CTRL_COUNTERS_30 + 4'b 1111, // index[38] CLUSTER_ICACHE_CTRL_COUNTERS_31 + 4'b 1111, // index[39] CLUSTER_ICACHE_CTRL_COUNTERS_32 + 4'b 1111, // index[40] CLUSTER_ICACHE_CTRL_COUNTERS_33 + 4'b 1111, // index[41] CLUSTER_ICACHE_CTRL_COUNTERS_34 + 4'b 1111, // index[42] CLUSTER_ICACHE_CTRL_COUNTERS_35 + 4'b 1111, // index[43] CLUSTER_ICACHE_CTRL_COUNTERS_36 + 4'b 1111, // index[44] CLUSTER_ICACHE_CTRL_COUNTERS_37 + 4'b 1111, // index[45] CLUSTER_ICACHE_CTRL_COUNTERS_38 + 4'b 1111, // index[46] CLUSTER_ICACHE_CTRL_COUNTERS_39 + 4'b 1111, // index[47] CLUSTER_ICACHE_CTRL_COUNTERS_40 + 4'b 1111, // index[48] CLUSTER_ICACHE_CTRL_COUNTERS_41 + 4'b 1111, // index[49] CLUSTER_ICACHE_CTRL_COUNTERS_42 + 4'b 1111 // index[50] CLUSTER_ICACHE_CTRL_COUNTERS_43 + }; + +endpackage + diff --git a/src/ctrl_unit/cluster_icache_ctrl_reg_top.sv b/src/ctrl_unit/cluster_icache_ctrl_reg_top.sv new file mode 100644 index 0000000..9f9d0ca --- /dev/null +++ b/src/ctrl_unit/cluster_icache_ctrl_reg_top.sv @@ -0,0 +1,2116 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Top module auto-generated by `reggen` + + +`include "common_cells/assertions.svh" + +module cluster_icache_ctrl_reg_top #( + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + parameter int AW = 8 +) ( + input logic clk_i, + input logic rst_ni, + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + // To HW + output cluster_icache_ctrl_reg_pkg::cluster_icache_ctrl_reg2hw_t reg2hw, // Write + input cluster_icache_ctrl_reg_pkg::cluster_icache_ctrl_hw2reg_t hw2reg, // Read + + + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + + import cluster_icache_ctrl_reg_pkg::* ; + + localparam int DW = 32; + localparam int DBW = DW/8; // Byte Width + + // register signals + logic reg_we; + logic reg_re; + logic [BlockAw-1:0] reg_addr; + logic [DW-1:0] reg_wdata; + logic [DBW-1:0] reg_be; + logic [DW-1:0] reg_rdata; + logic reg_error; + + logic addrmiss, wr_err; + + logic [DW-1:0] reg_rdata_next; + + // Below register interface can be changed + reg_req_t reg_intf_req; + reg_rsp_t reg_intf_rsp; + + + assign reg_intf_req = reg_req_i; + assign reg_rsp_o = reg_intf_rsp; + + + assign reg_we = reg_intf_req.valid & reg_intf_req.write; + assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; + assign reg_addr = reg_intf_req.addr[BlockAw-1:0]; + assign reg_wdata = reg_intf_req.wdata; + assign reg_be = reg_intf_req.wstrb; + assign reg_intf_rsp.rdata = reg_rdata; + assign reg_intf_rsp.error = reg_error; + assign reg_intf_rsp.ready = 1'b1; + + assign reg_rdata = reg_rdata_next ; + assign reg_error = (devmode_i & addrmiss) | wr_err; + + + // Define SW related signals + // Format: __{wd|we|qs} + // or _{wd|we|qs} if field == 1 or 0 + logic enable_qs; + logic enable_wd; + logic enable_we; + logic flush_qs; + logic flush_wd; + logic flush_we; + logic flush_re; + logic flush_l1_only_qs; + logic flush_l1_only_wd; + logic flush_l1_only_we; + logic flush_l1_only_re; + logic [7:0] sel_flush_icache_qs; + logic [7:0] sel_flush_icache_wd; + logic sel_flush_icache_we; + logic sel_flush_icache_re; + logic clear_counters_qs; + logic clear_counters_wd; + logic clear_counters_we; + logic clear_counters_re; + logic enable_counters_qs; + logic enable_counters_wd; + logic enable_counters_we; + logic enable_prefetch_qs; + logic enable_prefetch_wd; + logic enable_prefetch_we; + logic [31:0] counters_0_qs; + logic [31:0] counters_0_wd; + logic counters_0_we; + logic [31:0] counters_1_qs; + logic [31:0] counters_1_wd; + logic counters_1_we; + logic [31:0] counters_2_qs; + logic [31:0] counters_2_wd; + logic counters_2_we; + logic [31:0] counters_3_qs; + logic [31:0] counters_3_wd; + logic counters_3_we; + logic [31:0] counters_4_qs; + logic [31:0] counters_4_wd; + logic counters_4_we; + logic [31:0] counters_5_qs; + logic [31:0] counters_5_wd; + logic counters_5_we; + logic [31:0] counters_6_qs; + logic [31:0] counters_6_wd; + logic counters_6_we; + logic [31:0] counters_7_qs; + logic [31:0] counters_7_wd; + logic counters_7_we; + logic [31:0] counters_8_qs; + logic [31:0] counters_8_wd; + logic counters_8_we; + logic [31:0] counters_9_qs; + logic [31:0] counters_9_wd; + logic counters_9_we; + logic [31:0] counters_10_qs; + logic [31:0] counters_10_wd; + logic counters_10_we; + logic [31:0] counters_11_qs; + logic [31:0] counters_11_wd; + logic counters_11_we; + logic [31:0] counters_12_qs; + logic [31:0] counters_12_wd; + logic counters_12_we; + logic [31:0] counters_13_qs; + logic [31:0] counters_13_wd; + logic counters_13_we; + logic [31:0] counters_14_qs; + logic [31:0] counters_14_wd; + logic counters_14_we; + logic [31:0] counters_15_qs; + logic [31:0] counters_15_wd; + logic counters_15_we; + logic [31:0] counters_16_qs; + logic [31:0] counters_16_wd; + logic counters_16_we; + logic [31:0] counters_17_qs; + logic [31:0] counters_17_wd; + logic counters_17_we; + logic [31:0] counters_18_qs; + logic [31:0] counters_18_wd; + logic counters_18_we; + logic [31:0] counters_19_qs; + logic [31:0] counters_19_wd; + logic counters_19_we; + logic [31:0] counters_20_qs; + logic [31:0] counters_20_wd; + logic counters_20_we; + logic [31:0] counters_21_qs; + logic [31:0] counters_21_wd; + logic counters_21_we; + logic [31:0] counters_22_qs; + logic [31:0] counters_22_wd; + logic counters_22_we; + logic [31:0] counters_23_qs; + logic [31:0] counters_23_wd; + logic counters_23_we; + logic [31:0] counters_24_qs; + logic [31:0] counters_24_wd; + logic counters_24_we; + logic [31:0] counters_25_qs; + logic [31:0] counters_25_wd; + logic counters_25_we; + logic [31:0] counters_26_qs; + logic [31:0] counters_26_wd; + logic counters_26_we; + logic [31:0] counters_27_qs; + logic [31:0] counters_27_wd; + logic counters_27_we; + logic [31:0] counters_28_qs; + logic [31:0] counters_28_wd; + logic counters_28_we; + logic [31:0] counters_29_qs; + logic [31:0] counters_29_wd; + logic counters_29_we; + logic [31:0] counters_30_qs; + logic [31:0] counters_30_wd; + logic counters_30_we; + logic [31:0] counters_31_qs; + logic [31:0] counters_31_wd; + logic counters_31_we; + logic [31:0] counters_32_qs; + logic [31:0] counters_32_wd; + logic counters_32_we; + logic [31:0] counters_33_qs; + logic [31:0] counters_33_wd; + logic counters_33_we; + logic [31:0] counters_34_qs; + logic [31:0] counters_34_wd; + logic counters_34_we; + logic [31:0] counters_35_qs; + logic [31:0] counters_35_wd; + logic counters_35_we; + logic [31:0] counters_36_qs; + logic [31:0] counters_36_wd; + logic counters_36_we; + logic [31:0] counters_37_qs; + logic [31:0] counters_37_wd; + logic counters_37_we; + logic [31:0] counters_38_qs; + logic [31:0] counters_38_wd; + logic counters_38_we; + logic [31:0] counters_39_qs; + logic [31:0] counters_39_wd; + logic counters_39_we; + logic [31:0] counters_40_qs; + logic [31:0] counters_40_wd; + logic counters_40_we; + logic [31:0] counters_41_qs; + logic [31:0] counters_41_wd; + logic counters_41_we; + logic [31:0] counters_42_qs; + logic [31:0] counters_42_wd; + logic counters_42_we; + logic [31:0] counters_43_qs; + logic [31:0] counters_43_wd; + logic counters_43_we; + + // Register instances + // R[enable]: V(False) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h1) + ) u_enable ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (enable_we), + .wd (enable_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.enable.q ), + + // to register interface (read) + .qs (enable_qs) + ); + + + // R[flush]: V(True) + + prim_subreg_ext #( + .DW (1) + ) u_flush ( + .re (flush_re), + .we (flush_we), + .wd (flush_wd), + .d (hw2reg.flush.d), + .qre (), + .qe (reg2hw.flush.qe), + .q (reg2hw.flush.q ), + .qs (flush_qs) + ); + + + // R[flush_l1_only]: V(True) + + prim_subreg_ext #( + .DW (1) + ) u_flush_l1_only ( + .re (flush_l1_only_re), + .we (flush_l1_only_we), + .wd (flush_l1_only_wd), + .d (hw2reg.flush_l1_only.d), + .qre (), + .qe (reg2hw.flush_l1_only.qe), + .q (reg2hw.flush_l1_only.q ), + .qs (flush_l1_only_qs) + ); + + + // R[sel_flush_icache]: V(True) + + prim_subreg_ext #( + .DW (8) + ) u_sel_flush_icache ( + .re (sel_flush_icache_re), + .we (sel_flush_icache_we), + .wd (sel_flush_icache_wd), + .d (hw2reg.sel_flush_icache.d), + .qre (), + .qe (reg2hw.sel_flush_icache.qe), + .q (reg2hw.sel_flush_icache.q ), + .qs (sel_flush_icache_qs) + ); + + + // R[clear_counters]: V(True) + + prim_subreg_ext #( + .DW (1) + ) u_clear_counters ( + .re (clear_counters_re), + .we (clear_counters_we), + .wd (clear_counters_wd), + .d (hw2reg.clear_counters.d), + .qre (), + .qe (reg2hw.clear_counters.qe), + .q (reg2hw.clear_counters.q ), + .qs (clear_counters_qs) + ); + + + // R[enable_counters]: V(False) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h1) + ) u_enable_counters ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (enable_counters_we), + .wd (enable_counters_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.enable_counters.q ), + + // to register interface (read) + .qs (enable_counters_qs) + ); + + + // R[enable_prefetch]: V(False) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h1) + ) u_enable_prefetch ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (enable_prefetch_we), + .wd (enable_prefetch_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.enable_prefetch.q ), + + // to register interface (read) + .qs (enable_prefetch_qs) + ); + + + + // Subregister 0 of Multireg counters + // R[counters_0]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_0 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_0_we), + .wd (counters_0_wd), + + // from internal hardware + .de (hw2reg.counters[0].de), + .d (hw2reg.counters[0].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[0].q ), + + // to register interface (read) + .qs (counters_0_qs) + ); + + // Subregister 1 of Multireg counters + // R[counters_1]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_1 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_1_we), + .wd (counters_1_wd), + + // from internal hardware + .de (hw2reg.counters[1].de), + .d (hw2reg.counters[1].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[1].q ), + + // to register interface (read) + .qs (counters_1_qs) + ); + + // Subregister 2 of Multireg counters + // R[counters_2]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_2 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_2_we), + .wd (counters_2_wd), + + // from internal hardware + .de (hw2reg.counters[2].de), + .d (hw2reg.counters[2].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[2].q ), + + // to register interface (read) + .qs (counters_2_qs) + ); + + // Subregister 3 of Multireg counters + // R[counters_3]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_3 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_3_we), + .wd (counters_3_wd), + + // from internal hardware + .de (hw2reg.counters[3].de), + .d (hw2reg.counters[3].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[3].q ), + + // to register interface (read) + .qs (counters_3_qs) + ); + + // Subregister 4 of Multireg counters + // R[counters_4]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_4 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_4_we), + .wd (counters_4_wd), + + // from internal hardware + .de (hw2reg.counters[4].de), + .d (hw2reg.counters[4].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[4].q ), + + // to register interface (read) + .qs (counters_4_qs) + ); + + // Subregister 5 of Multireg counters + // R[counters_5]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_5 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_5_we), + .wd (counters_5_wd), + + // from internal hardware + .de (hw2reg.counters[5].de), + .d (hw2reg.counters[5].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[5].q ), + + // to register interface (read) + .qs (counters_5_qs) + ); + + // Subregister 6 of Multireg counters + // R[counters_6]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_6 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_6_we), + .wd (counters_6_wd), + + // from internal hardware + .de (hw2reg.counters[6].de), + .d (hw2reg.counters[6].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[6].q ), + + // to register interface (read) + .qs (counters_6_qs) + ); + + // Subregister 7 of Multireg counters + // R[counters_7]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_7 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_7_we), + .wd (counters_7_wd), + + // from internal hardware + .de (hw2reg.counters[7].de), + .d (hw2reg.counters[7].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[7].q ), + + // to register interface (read) + .qs (counters_7_qs) + ); + + // Subregister 8 of Multireg counters + // R[counters_8]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_8 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_8_we), + .wd (counters_8_wd), + + // from internal hardware + .de (hw2reg.counters[8].de), + .d (hw2reg.counters[8].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[8].q ), + + // to register interface (read) + .qs (counters_8_qs) + ); + + // Subregister 9 of Multireg counters + // R[counters_9]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_9 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_9_we), + .wd (counters_9_wd), + + // from internal hardware + .de (hw2reg.counters[9].de), + .d (hw2reg.counters[9].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[9].q ), + + // to register interface (read) + .qs (counters_9_qs) + ); + + // Subregister 10 of Multireg counters + // R[counters_10]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_10 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_10_we), + .wd (counters_10_wd), + + // from internal hardware + .de (hw2reg.counters[10].de), + .d (hw2reg.counters[10].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[10].q ), + + // to register interface (read) + .qs (counters_10_qs) + ); + + // Subregister 11 of Multireg counters + // R[counters_11]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_11 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_11_we), + .wd (counters_11_wd), + + // from internal hardware + .de (hw2reg.counters[11].de), + .d (hw2reg.counters[11].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[11].q ), + + // to register interface (read) + .qs (counters_11_qs) + ); + + // Subregister 12 of Multireg counters + // R[counters_12]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_12 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_12_we), + .wd (counters_12_wd), + + // from internal hardware + .de (hw2reg.counters[12].de), + .d (hw2reg.counters[12].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[12].q ), + + // to register interface (read) + .qs (counters_12_qs) + ); + + // Subregister 13 of Multireg counters + // R[counters_13]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_13 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_13_we), + .wd (counters_13_wd), + + // from internal hardware + .de (hw2reg.counters[13].de), + .d (hw2reg.counters[13].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[13].q ), + + // to register interface (read) + .qs (counters_13_qs) + ); + + // Subregister 14 of Multireg counters + // R[counters_14]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_14 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_14_we), + .wd (counters_14_wd), + + // from internal hardware + .de (hw2reg.counters[14].de), + .d (hw2reg.counters[14].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[14].q ), + + // to register interface (read) + .qs (counters_14_qs) + ); + + // Subregister 15 of Multireg counters + // R[counters_15]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_15 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_15_we), + .wd (counters_15_wd), + + // from internal hardware + .de (hw2reg.counters[15].de), + .d (hw2reg.counters[15].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[15].q ), + + // to register interface (read) + .qs (counters_15_qs) + ); + + // Subregister 16 of Multireg counters + // R[counters_16]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_16 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_16_we), + .wd (counters_16_wd), + + // from internal hardware + .de (hw2reg.counters[16].de), + .d (hw2reg.counters[16].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[16].q ), + + // to register interface (read) + .qs (counters_16_qs) + ); + + // Subregister 17 of Multireg counters + // R[counters_17]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_17 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_17_we), + .wd (counters_17_wd), + + // from internal hardware + .de (hw2reg.counters[17].de), + .d (hw2reg.counters[17].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[17].q ), + + // to register interface (read) + .qs (counters_17_qs) + ); + + // Subregister 18 of Multireg counters + // R[counters_18]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_18 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_18_we), + .wd (counters_18_wd), + + // from internal hardware + .de (hw2reg.counters[18].de), + .d (hw2reg.counters[18].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[18].q ), + + // to register interface (read) + .qs (counters_18_qs) + ); + + // Subregister 19 of Multireg counters + // R[counters_19]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_19 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_19_we), + .wd (counters_19_wd), + + // from internal hardware + .de (hw2reg.counters[19].de), + .d (hw2reg.counters[19].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[19].q ), + + // to register interface (read) + .qs (counters_19_qs) + ); + + // Subregister 20 of Multireg counters + // R[counters_20]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_20 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_20_we), + .wd (counters_20_wd), + + // from internal hardware + .de (hw2reg.counters[20].de), + .d (hw2reg.counters[20].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[20].q ), + + // to register interface (read) + .qs (counters_20_qs) + ); + + // Subregister 21 of Multireg counters + // R[counters_21]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_21 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_21_we), + .wd (counters_21_wd), + + // from internal hardware + .de (hw2reg.counters[21].de), + .d (hw2reg.counters[21].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[21].q ), + + // to register interface (read) + .qs (counters_21_qs) + ); + + // Subregister 22 of Multireg counters + // R[counters_22]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_22 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_22_we), + .wd (counters_22_wd), + + // from internal hardware + .de (hw2reg.counters[22].de), + .d (hw2reg.counters[22].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[22].q ), + + // to register interface (read) + .qs (counters_22_qs) + ); + + // Subregister 23 of Multireg counters + // R[counters_23]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_23 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_23_we), + .wd (counters_23_wd), + + // from internal hardware + .de (hw2reg.counters[23].de), + .d (hw2reg.counters[23].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[23].q ), + + // to register interface (read) + .qs (counters_23_qs) + ); + + // Subregister 24 of Multireg counters + // R[counters_24]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_24 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_24_we), + .wd (counters_24_wd), + + // from internal hardware + .de (hw2reg.counters[24].de), + .d (hw2reg.counters[24].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[24].q ), + + // to register interface (read) + .qs (counters_24_qs) + ); + + // Subregister 25 of Multireg counters + // R[counters_25]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_25 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_25_we), + .wd (counters_25_wd), + + // from internal hardware + .de (hw2reg.counters[25].de), + .d (hw2reg.counters[25].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[25].q ), + + // to register interface (read) + .qs (counters_25_qs) + ); + + // Subregister 26 of Multireg counters + // R[counters_26]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_26 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_26_we), + .wd (counters_26_wd), + + // from internal hardware + .de (hw2reg.counters[26].de), + .d (hw2reg.counters[26].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[26].q ), + + // to register interface (read) + .qs (counters_26_qs) + ); + + // Subregister 27 of Multireg counters + // R[counters_27]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_27 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_27_we), + .wd (counters_27_wd), + + // from internal hardware + .de (hw2reg.counters[27].de), + .d (hw2reg.counters[27].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[27].q ), + + // to register interface (read) + .qs (counters_27_qs) + ); + + // Subregister 28 of Multireg counters + // R[counters_28]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_28 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_28_we), + .wd (counters_28_wd), + + // from internal hardware + .de (hw2reg.counters[28].de), + .d (hw2reg.counters[28].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[28].q ), + + // to register interface (read) + .qs (counters_28_qs) + ); + + // Subregister 29 of Multireg counters + // R[counters_29]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_29 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_29_we), + .wd (counters_29_wd), + + // from internal hardware + .de (hw2reg.counters[29].de), + .d (hw2reg.counters[29].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[29].q ), + + // to register interface (read) + .qs (counters_29_qs) + ); + + // Subregister 30 of Multireg counters + // R[counters_30]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_30 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_30_we), + .wd (counters_30_wd), + + // from internal hardware + .de (hw2reg.counters[30].de), + .d (hw2reg.counters[30].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[30].q ), + + // to register interface (read) + .qs (counters_30_qs) + ); + + // Subregister 31 of Multireg counters + // R[counters_31]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_31 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_31_we), + .wd (counters_31_wd), + + // from internal hardware + .de (hw2reg.counters[31].de), + .d (hw2reg.counters[31].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[31].q ), + + // to register interface (read) + .qs (counters_31_qs) + ); + + // Subregister 32 of Multireg counters + // R[counters_32]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_32 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_32_we), + .wd (counters_32_wd), + + // from internal hardware + .de (hw2reg.counters[32].de), + .d (hw2reg.counters[32].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[32].q ), + + // to register interface (read) + .qs (counters_32_qs) + ); + + // Subregister 33 of Multireg counters + // R[counters_33]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_33 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_33_we), + .wd (counters_33_wd), + + // from internal hardware + .de (hw2reg.counters[33].de), + .d (hw2reg.counters[33].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[33].q ), + + // to register interface (read) + .qs (counters_33_qs) + ); + + // Subregister 34 of Multireg counters + // R[counters_34]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_34 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_34_we), + .wd (counters_34_wd), + + // from internal hardware + .de (hw2reg.counters[34].de), + .d (hw2reg.counters[34].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[34].q ), + + // to register interface (read) + .qs (counters_34_qs) + ); + + // Subregister 35 of Multireg counters + // R[counters_35]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_35 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_35_we), + .wd (counters_35_wd), + + // from internal hardware + .de (hw2reg.counters[35].de), + .d (hw2reg.counters[35].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[35].q ), + + // to register interface (read) + .qs (counters_35_qs) + ); + + // Subregister 36 of Multireg counters + // R[counters_36]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_36 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_36_we), + .wd (counters_36_wd), + + // from internal hardware + .de (hw2reg.counters[36].de), + .d (hw2reg.counters[36].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[36].q ), + + // to register interface (read) + .qs (counters_36_qs) + ); + + // Subregister 37 of Multireg counters + // R[counters_37]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_37 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_37_we), + .wd (counters_37_wd), + + // from internal hardware + .de (hw2reg.counters[37].de), + .d (hw2reg.counters[37].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[37].q ), + + // to register interface (read) + .qs (counters_37_qs) + ); + + // Subregister 38 of Multireg counters + // R[counters_38]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_38 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_38_we), + .wd (counters_38_wd), + + // from internal hardware + .de (hw2reg.counters[38].de), + .d (hw2reg.counters[38].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[38].q ), + + // to register interface (read) + .qs (counters_38_qs) + ); + + // Subregister 39 of Multireg counters + // R[counters_39]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_39 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_39_we), + .wd (counters_39_wd), + + // from internal hardware + .de (hw2reg.counters[39].de), + .d (hw2reg.counters[39].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[39].q ), + + // to register interface (read) + .qs (counters_39_qs) + ); + + // Subregister 40 of Multireg counters + // R[counters_40]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_40 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_40_we), + .wd (counters_40_wd), + + // from internal hardware + .de (hw2reg.counters[40].de), + .d (hw2reg.counters[40].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[40].q ), + + // to register interface (read) + .qs (counters_40_qs) + ); + + // Subregister 41 of Multireg counters + // R[counters_41]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_41 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_41_we), + .wd (counters_41_wd), + + // from internal hardware + .de (hw2reg.counters[41].de), + .d (hw2reg.counters[41].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[41].q ), + + // to register interface (read) + .qs (counters_41_qs) + ); + + // Subregister 42 of Multireg counters + // R[counters_42]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_42 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_42_we), + .wd (counters_42_wd), + + // from internal hardware + .de (hw2reg.counters[42].de), + .d (hw2reg.counters[42].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[42].q ), + + // to register interface (read) + .qs (counters_42_qs) + ); + + // Subregister 43 of Multireg counters + // R[counters_43]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_43 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_43_we), + .wd (counters_43_wd), + + // from internal hardware + .de (hw2reg.counters[43].de), + .d (hw2reg.counters[43].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[43].q ), + + // to register interface (read) + .qs (counters_43_qs) + ); + + + + + logic [50:0] addr_hit; + always_comb begin + addr_hit = '0; + addr_hit[ 0] = (reg_addr == CLUSTER_ICACHE_CTRL_ENABLE_OFFSET); + addr_hit[ 1] = (reg_addr == CLUSTER_ICACHE_CTRL_FLUSH_OFFSET); + addr_hit[ 2] = (reg_addr == CLUSTER_ICACHE_CTRL_FLUSH_L1_ONLY_OFFSET); + addr_hit[ 3] = (reg_addr == CLUSTER_ICACHE_CTRL_SEL_FLUSH_ICACHE_OFFSET); + addr_hit[ 4] = (reg_addr == CLUSTER_ICACHE_CTRL_CLEAR_COUNTERS_OFFSET); + addr_hit[ 5] = (reg_addr == CLUSTER_ICACHE_CTRL_ENABLE_COUNTERS_OFFSET); + addr_hit[ 6] = (reg_addr == CLUSTER_ICACHE_CTRL_ENABLE_PREFETCH_OFFSET); + addr_hit[ 7] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_0_OFFSET); + addr_hit[ 8] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_1_OFFSET); + addr_hit[ 9] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_2_OFFSET); + addr_hit[10] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_3_OFFSET); + addr_hit[11] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_4_OFFSET); + addr_hit[12] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_5_OFFSET); + addr_hit[13] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_6_OFFSET); + addr_hit[14] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_7_OFFSET); + addr_hit[15] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_8_OFFSET); + addr_hit[16] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_9_OFFSET); + addr_hit[17] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_10_OFFSET); + addr_hit[18] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_11_OFFSET); + addr_hit[19] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_12_OFFSET); + addr_hit[20] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_13_OFFSET); + addr_hit[21] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_14_OFFSET); + addr_hit[22] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_15_OFFSET); + addr_hit[23] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_16_OFFSET); + addr_hit[24] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_17_OFFSET); + addr_hit[25] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_18_OFFSET); + addr_hit[26] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_19_OFFSET); + addr_hit[27] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_20_OFFSET); + addr_hit[28] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_21_OFFSET); + addr_hit[29] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_22_OFFSET); + addr_hit[30] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_23_OFFSET); + addr_hit[31] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_24_OFFSET); + addr_hit[32] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_25_OFFSET); + addr_hit[33] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_26_OFFSET); + addr_hit[34] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_27_OFFSET); + addr_hit[35] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_28_OFFSET); + addr_hit[36] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_29_OFFSET); + addr_hit[37] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_30_OFFSET); + addr_hit[38] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_31_OFFSET); + addr_hit[39] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_32_OFFSET); + addr_hit[40] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_33_OFFSET); + addr_hit[41] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_34_OFFSET); + addr_hit[42] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_35_OFFSET); + addr_hit[43] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_36_OFFSET); + addr_hit[44] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_37_OFFSET); + addr_hit[45] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_38_OFFSET); + addr_hit[46] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_39_OFFSET); + addr_hit[47] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_40_OFFSET); + addr_hit[48] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_41_OFFSET); + addr_hit[49] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_42_OFFSET); + addr_hit[50] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_43_OFFSET); + end + + assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; + + // Check sub-word write is permitted + always_comb begin + wr_err = (reg_we & + ((addr_hit[ 0] & (|(CLUSTER_ICACHE_CTRL_PERMIT[ 0] & ~reg_be))) | + (addr_hit[ 1] & (|(CLUSTER_ICACHE_CTRL_PERMIT[ 1] & ~reg_be))) | + (addr_hit[ 2] & (|(CLUSTER_ICACHE_CTRL_PERMIT[ 2] & ~reg_be))) | + (addr_hit[ 3] & (|(CLUSTER_ICACHE_CTRL_PERMIT[ 3] & ~reg_be))) | + (addr_hit[ 4] & (|(CLUSTER_ICACHE_CTRL_PERMIT[ 4] & ~reg_be))) | + (addr_hit[ 5] & (|(CLUSTER_ICACHE_CTRL_PERMIT[ 5] & ~reg_be))) | + (addr_hit[ 6] & (|(CLUSTER_ICACHE_CTRL_PERMIT[ 6] & ~reg_be))) | + (addr_hit[ 7] & (|(CLUSTER_ICACHE_CTRL_PERMIT[ 7] & ~reg_be))) | + (addr_hit[ 8] & (|(CLUSTER_ICACHE_CTRL_PERMIT[ 8] & ~reg_be))) | + (addr_hit[ 9] & (|(CLUSTER_ICACHE_CTRL_PERMIT[ 9] & ~reg_be))) | + (addr_hit[10] & (|(CLUSTER_ICACHE_CTRL_PERMIT[10] & ~reg_be))) | + (addr_hit[11] & (|(CLUSTER_ICACHE_CTRL_PERMIT[11] & ~reg_be))) | + (addr_hit[12] & (|(CLUSTER_ICACHE_CTRL_PERMIT[12] & ~reg_be))) | + (addr_hit[13] & (|(CLUSTER_ICACHE_CTRL_PERMIT[13] & ~reg_be))) | + (addr_hit[14] & (|(CLUSTER_ICACHE_CTRL_PERMIT[14] & ~reg_be))) | + (addr_hit[15] & (|(CLUSTER_ICACHE_CTRL_PERMIT[15] & ~reg_be))) | + (addr_hit[16] & (|(CLUSTER_ICACHE_CTRL_PERMIT[16] & ~reg_be))) | + (addr_hit[17] & (|(CLUSTER_ICACHE_CTRL_PERMIT[17] & ~reg_be))) | + (addr_hit[18] & (|(CLUSTER_ICACHE_CTRL_PERMIT[18] & ~reg_be))) | + (addr_hit[19] & (|(CLUSTER_ICACHE_CTRL_PERMIT[19] & ~reg_be))) | + (addr_hit[20] & (|(CLUSTER_ICACHE_CTRL_PERMIT[20] & ~reg_be))) | + (addr_hit[21] & (|(CLUSTER_ICACHE_CTRL_PERMIT[21] & ~reg_be))) | + (addr_hit[22] & (|(CLUSTER_ICACHE_CTRL_PERMIT[22] & ~reg_be))) | + (addr_hit[23] & (|(CLUSTER_ICACHE_CTRL_PERMIT[23] & ~reg_be))) | + (addr_hit[24] & (|(CLUSTER_ICACHE_CTRL_PERMIT[24] & ~reg_be))) | + (addr_hit[25] & (|(CLUSTER_ICACHE_CTRL_PERMIT[25] & ~reg_be))) | + (addr_hit[26] & (|(CLUSTER_ICACHE_CTRL_PERMIT[26] & ~reg_be))) | + (addr_hit[27] & (|(CLUSTER_ICACHE_CTRL_PERMIT[27] & ~reg_be))) | + (addr_hit[28] & (|(CLUSTER_ICACHE_CTRL_PERMIT[28] & ~reg_be))) | + (addr_hit[29] & (|(CLUSTER_ICACHE_CTRL_PERMIT[29] & ~reg_be))) | + (addr_hit[30] & (|(CLUSTER_ICACHE_CTRL_PERMIT[30] & ~reg_be))) | + (addr_hit[31] & (|(CLUSTER_ICACHE_CTRL_PERMIT[31] & ~reg_be))) | + (addr_hit[32] & (|(CLUSTER_ICACHE_CTRL_PERMIT[32] & ~reg_be))) | + (addr_hit[33] & (|(CLUSTER_ICACHE_CTRL_PERMIT[33] & ~reg_be))) | + (addr_hit[34] & (|(CLUSTER_ICACHE_CTRL_PERMIT[34] & ~reg_be))) | + (addr_hit[35] & (|(CLUSTER_ICACHE_CTRL_PERMIT[35] & ~reg_be))) | + (addr_hit[36] & (|(CLUSTER_ICACHE_CTRL_PERMIT[36] & ~reg_be))) | + (addr_hit[37] & (|(CLUSTER_ICACHE_CTRL_PERMIT[37] & ~reg_be))) | + (addr_hit[38] & (|(CLUSTER_ICACHE_CTRL_PERMIT[38] & ~reg_be))) | + (addr_hit[39] & (|(CLUSTER_ICACHE_CTRL_PERMIT[39] & ~reg_be))) | + (addr_hit[40] & (|(CLUSTER_ICACHE_CTRL_PERMIT[40] & ~reg_be))) | + (addr_hit[41] & (|(CLUSTER_ICACHE_CTRL_PERMIT[41] & ~reg_be))) | + (addr_hit[42] & (|(CLUSTER_ICACHE_CTRL_PERMIT[42] & ~reg_be))) | + (addr_hit[43] & (|(CLUSTER_ICACHE_CTRL_PERMIT[43] & ~reg_be))) | + (addr_hit[44] & (|(CLUSTER_ICACHE_CTRL_PERMIT[44] & ~reg_be))) | + (addr_hit[45] & (|(CLUSTER_ICACHE_CTRL_PERMIT[45] & ~reg_be))) | + (addr_hit[46] & (|(CLUSTER_ICACHE_CTRL_PERMIT[46] & ~reg_be))) | + (addr_hit[47] & (|(CLUSTER_ICACHE_CTRL_PERMIT[47] & ~reg_be))) | + (addr_hit[48] & (|(CLUSTER_ICACHE_CTRL_PERMIT[48] & ~reg_be))) | + (addr_hit[49] & (|(CLUSTER_ICACHE_CTRL_PERMIT[49] & ~reg_be))) | + (addr_hit[50] & (|(CLUSTER_ICACHE_CTRL_PERMIT[50] & ~reg_be))))); + end + + assign enable_we = addr_hit[0] & reg_we & !reg_error; + assign enable_wd = reg_wdata[0]; + + assign flush_we = addr_hit[1] & reg_we & !reg_error; + assign flush_wd = reg_wdata[0]; + assign flush_re = addr_hit[1] & reg_re & !reg_error; + + assign flush_l1_only_we = addr_hit[2] & reg_we & !reg_error; + assign flush_l1_only_wd = reg_wdata[0]; + assign flush_l1_only_re = addr_hit[2] & reg_re & !reg_error; + + assign sel_flush_icache_we = addr_hit[3] & reg_we & !reg_error; + assign sel_flush_icache_wd = reg_wdata[7:0]; + assign sel_flush_icache_re = addr_hit[3] & reg_re & !reg_error; + + assign clear_counters_we = addr_hit[4] & reg_we & !reg_error; + assign clear_counters_wd = reg_wdata[0]; + assign clear_counters_re = addr_hit[4] & reg_re & !reg_error; + + assign enable_counters_we = addr_hit[5] & reg_we & !reg_error; + assign enable_counters_wd = reg_wdata[0]; + + assign enable_prefetch_we = addr_hit[6] & reg_we & !reg_error; + assign enable_prefetch_wd = reg_wdata[0]; + + assign counters_0_we = addr_hit[7] & reg_we & !reg_error; + assign counters_0_wd = reg_wdata[31:0]; + + assign counters_1_we = addr_hit[8] & reg_we & !reg_error; + assign counters_1_wd = reg_wdata[31:0]; + + assign counters_2_we = addr_hit[9] & reg_we & !reg_error; + assign counters_2_wd = reg_wdata[31:0]; + + assign counters_3_we = addr_hit[10] & reg_we & !reg_error; + assign counters_3_wd = reg_wdata[31:0]; + + assign counters_4_we = addr_hit[11] & reg_we & !reg_error; + assign counters_4_wd = reg_wdata[31:0]; + + assign counters_5_we = addr_hit[12] & reg_we & !reg_error; + assign counters_5_wd = reg_wdata[31:0]; + + assign counters_6_we = addr_hit[13] & reg_we & !reg_error; + assign counters_6_wd = reg_wdata[31:0]; + + assign counters_7_we = addr_hit[14] & reg_we & !reg_error; + assign counters_7_wd = reg_wdata[31:0]; + + assign counters_8_we = addr_hit[15] & reg_we & !reg_error; + assign counters_8_wd = reg_wdata[31:0]; + + assign counters_9_we = addr_hit[16] & reg_we & !reg_error; + assign counters_9_wd = reg_wdata[31:0]; + + assign counters_10_we = addr_hit[17] & reg_we & !reg_error; + assign counters_10_wd = reg_wdata[31:0]; + + assign counters_11_we = addr_hit[18] & reg_we & !reg_error; + assign counters_11_wd = reg_wdata[31:0]; + + assign counters_12_we = addr_hit[19] & reg_we & !reg_error; + assign counters_12_wd = reg_wdata[31:0]; + + assign counters_13_we = addr_hit[20] & reg_we & !reg_error; + assign counters_13_wd = reg_wdata[31:0]; + + assign counters_14_we = addr_hit[21] & reg_we & !reg_error; + assign counters_14_wd = reg_wdata[31:0]; + + assign counters_15_we = addr_hit[22] & reg_we & !reg_error; + assign counters_15_wd = reg_wdata[31:0]; + + assign counters_16_we = addr_hit[23] & reg_we & !reg_error; + assign counters_16_wd = reg_wdata[31:0]; + + assign counters_17_we = addr_hit[24] & reg_we & !reg_error; + assign counters_17_wd = reg_wdata[31:0]; + + assign counters_18_we = addr_hit[25] & reg_we & !reg_error; + assign counters_18_wd = reg_wdata[31:0]; + + assign counters_19_we = addr_hit[26] & reg_we & !reg_error; + assign counters_19_wd = reg_wdata[31:0]; + + assign counters_20_we = addr_hit[27] & reg_we & !reg_error; + assign counters_20_wd = reg_wdata[31:0]; + + assign counters_21_we = addr_hit[28] & reg_we & !reg_error; + assign counters_21_wd = reg_wdata[31:0]; + + assign counters_22_we = addr_hit[29] & reg_we & !reg_error; + assign counters_22_wd = reg_wdata[31:0]; + + assign counters_23_we = addr_hit[30] & reg_we & !reg_error; + assign counters_23_wd = reg_wdata[31:0]; + + assign counters_24_we = addr_hit[31] & reg_we & !reg_error; + assign counters_24_wd = reg_wdata[31:0]; + + assign counters_25_we = addr_hit[32] & reg_we & !reg_error; + assign counters_25_wd = reg_wdata[31:0]; + + assign counters_26_we = addr_hit[33] & reg_we & !reg_error; + assign counters_26_wd = reg_wdata[31:0]; + + assign counters_27_we = addr_hit[34] & reg_we & !reg_error; + assign counters_27_wd = reg_wdata[31:0]; + + assign counters_28_we = addr_hit[35] & reg_we & !reg_error; + assign counters_28_wd = reg_wdata[31:0]; + + assign counters_29_we = addr_hit[36] & reg_we & !reg_error; + assign counters_29_wd = reg_wdata[31:0]; + + assign counters_30_we = addr_hit[37] & reg_we & !reg_error; + assign counters_30_wd = reg_wdata[31:0]; + + assign counters_31_we = addr_hit[38] & reg_we & !reg_error; + assign counters_31_wd = reg_wdata[31:0]; + + assign counters_32_we = addr_hit[39] & reg_we & !reg_error; + assign counters_32_wd = reg_wdata[31:0]; + + assign counters_33_we = addr_hit[40] & reg_we & !reg_error; + assign counters_33_wd = reg_wdata[31:0]; + + assign counters_34_we = addr_hit[41] & reg_we & !reg_error; + assign counters_34_wd = reg_wdata[31:0]; + + assign counters_35_we = addr_hit[42] & reg_we & !reg_error; + assign counters_35_wd = reg_wdata[31:0]; + + assign counters_36_we = addr_hit[43] & reg_we & !reg_error; + assign counters_36_wd = reg_wdata[31:0]; + + assign counters_37_we = addr_hit[44] & reg_we & !reg_error; + assign counters_37_wd = reg_wdata[31:0]; + + assign counters_38_we = addr_hit[45] & reg_we & !reg_error; + assign counters_38_wd = reg_wdata[31:0]; + + assign counters_39_we = addr_hit[46] & reg_we & !reg_error; + assign counters_39_wd = reg_wdata[31:0]; + + assign counters_40_we = addr_hit[47] & reg_we & !reg_error; + assign counters_40_wd = reg_wdata[31:0]; + + assign counters_41_we = addr_hit[48] & reg_we & !reg_error; + assign counters_41_wd = reg_wdata[31:0]; + + assign counters_42_we = addr_hit[49] & reg_we & !reg_error; + assign counters_42_wd = reg_wdata[31:0]; + + assign counters_43_we = addr_hit[50] & reg_we & !reg_error; + assign counters_43_wd = reg_wdata[31:0]; + + // Read data return + always_comb begin + reg_rdata_next = '0; + unique case (1'b1) + addr_hit[0]: begin + reg_rdata_next[0] = enable_qs; + end + + addr_hit[1]: begin + reg_rdata_next[0] = flush_qs; + end + + addr_hit[2]: begin + reg_rdata_next[0] = flush_l1_only_qs; + end + + addr_hit[3]: begin + reg_rdata_next[7:0] = sel_flush_icache_qs; + end + + addr_hit[4]: begin + reg_rdata_next[0] = clear_counters_qs; + end + + addr_hit[5]: begin + reg_rdata_next[0] = enable_counters_qs; + end + + addr_hit[6]: begin + reg_rdata_next[0] = enable_prefetch_qs; + end + + addr_hit[7]: begin + reg_rdata_next[31:0] = counters_0_qs; + end + + addr_hit[8]: begin + reg_rdata_next[31:0] = counters_1_qs; + end + + addr_hit[9]: begin + reg_rdata_next[31:0] = counters_2_qs; + end + + addr_hit[10]: begin + reg_rdata_next[31:0] = counters_3_qs; + end + + addr_hit[11]: begin + reg_rdata_next[31:0] = counters_4_qs; + end + + addr_hit[12]: begin + reg_rdata_next[31:0] = counters_5_qs; + end + + addr_hit[13]: begin + reg_rdata_next[31:0] = counters_6_qs; + end + + addr_hit[14]: begin + reg_rdata_next[31:0] = counters_7_qs; + end + + addr_hit[15]: begin + reg_rdata_next[31:0] = counters_8_qs; + end + + addr_hit[16]: begin + reg_rdata_next[31:0] = counters_9_qs; + end + + addr_hit[17]: begin + reg_rdata_next[31:0] = counters_10_qs; + end + + addr_hit[18]: begin + reg_rdata_next[31:0] = counters_11_qs; + end + + addr_hit[19]: begin + reg_rdata_next[31:0] = counters_12_qs; + end + + addr_hit[20]: begin + reg_rdata_next[31:0] = counters_13_qs; + end + + addr_hit[21]: begin + reg_rdata_next[31:0] = counters_14_qs; + end + + addr_hit[22]: begin + reg_rdata_next[31:0] = counters_15_qs; + end + + addr_hit[23]: begin + reg_rdata_next[31:0] = counters_16_qs; + end + + addr_hit[24]: begin + reg_rdata_next[31:0] = counters_17_qs; + end + + addr_hit[25]: begin + reg_rdata_next[31:0] = counters_18_qs; + end + + addr_hit[26]: begin + reg_rdata_next[31:0] = counters_19_qs; + end + + addr_hit[27]: begin + reg_rdata_next[31:0] = counters_20_qs; + end + + addr_hit[28]: begin + reg_rdata_next[31:0] = counters_21_qs; + end + + addr_hit[29]: begin + reg_rdata_next[31:0] = counters_22_qs; + end + + addr_hit[30]: begin + reg_rdata_next[31:0] = counters_23_qs; + end + + addr_hit[31]: begin + reg_rdata_next[31:0] = counters_24_qs; + end + + addr_hit[32]: begin + reg_rdata_next[31:0] = counters_25_qs; + end + + addr_hit[33]: begin + reg_rdata_next[31:0] = counters_26_qs; + end + + addr_hit[34]: begin + reg_rdata_next[31:0] = counters_27_qs; + end + + addr_hit[35]: begin + reg_rdata_next[31:0] = counters_28_qs; + end + + addr_hit[36]: begin + reg_rdata_next[31:0] = counters_29_qs; + end + + addr_hit[37]: begin + reg_rdata_next[31:0] = counters_30_qs; + end + + addr_hit[38]: begin + reg_rdata_next[31:0] = counters_31_qs; + end + + addr_hit[39]: begin + reg_rdata_next[31:0] = counters_32_qs; + end + + addr_hit[40]: begin + reg_rdata_next[31:0] = counters_33_qs; + end + + addr_hit[41]: begin + reg_rdata_next[31:0] = counters_34_qs; + end + + addr_hit[42]: begin + reg_rdata_next[31:0] = counters_35_qs; + end + + addr_hit[43]: begin + reg_rdata_next[31:0] = counters_36_qs; + end + + addr_hit[44]: begin + reg_rdata_next[31:0] = counters_37_qs; + end + + addr_hit[45]: begin + reg_rdata_next[31:0] = counters_38_qs; + end + + addr_hit[46]: begin + reg_rdata_next[31:0] = counters_39_qs; + end + + addr_hit[47]: begin + reg_rdata_next[31:0] = counters_40_qs; + end + + addr_hit[48]: begin + reg_rdata_next[31:0] = counters_41_qs; + end + + addr_hit[49]: begin + reg_rdata_next[31:0] = counters_42_qs; + end + + addr_hit[50]: begin + reg_rdata_next[31:0] = counters_43_qs; + end + + default: begin + reg_rdata_next = '1; + end + endcase + end + + // Unused signal tieoff + + // wdata / byte enable are not always fully used + // add a blanket unused statement to handle lint waivers + logic unused_wdata; + logic unused_be; + assign unused_wdata = ^reg_wdata; + assign unused_be = ^reg_be; + + // Assertions for Register Interface + `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) + +endmodule + +module cluster_icache_ctrl_reg_top_intf +#( + parameter int AW = 8, + localparam int DW = 32 +) ( + input logic clk_i, + input logic rst_ni, + REG_BUS.in regbus_slave, + // To HW + output cluster_icache_ctrl_reg_pkg::cluster_icache_ctrl_reg2hw_t reg2hw, // Write + input cluster_icache_ctrl_reg_pkg::cluster_icache_ctrl_hw2reg_t hw2reg, // Read + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + localparam int unsigned STRB_WIDTH = DW/8; + +`include "register_interface/typedef.svh" +`include "register_interface/assign.svh" + + // Define structs for reg_bus + typedef logic [AW-1:0] addr_t; + typedef logic [DW-1:0] data_t; + typedef logic [STRB_WIDTH-1:0] strb_t; + `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t) + + reg_bus_req_t s_reg_req; + reg_bus_rsp_t s_reg_rsp; + + // Assign SV interface to structs + `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave) + `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp) + + + + cluster_icache_ctrl_reg_top #( + .reg_req_t(reg_bus_req_t), + .reg_rsp_t(reg_bus_rsp_t), + .AW(AW) + ) i_regs ( + .clk_i, + .rst_ni, + .reg_req_i(s_reg_req), + .reg_rsp_o(s_reg_rsp), + .reg2hw, // Write + .hw2reg, // Read + .devmode_i + ); + +endmodule + + diff --git a/src/ctrl_unit/cluster_icache_ctrl_unit.sv b/src/ctrl_unit/cluster_icache_ctrl_unit.sv new file mode 100644 index 0000000..3c2061a --- /dev/null +++ b/src/ctrl_unit/cluster_icache_ctrl_unit.sv @@ -0,0 +1,96 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +module cluster_icache_ctrl_unit import snitch_icache_pkg::*; #( + parameter int unsigned NR_FETCH_PORTS = -1, + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic +) ( + input logic clk_i, + input logic rst_ni, + + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + + output logic enable_prefetching_o, + output logic [NR_FETCH_PORTS-1:0] flush_valid_o, + input logic [NR_FETCH_PORTS-1:0] flush_ready_i, + + input icache_l0_events_t [NR_FETCH_PORTS-1:0] l0_events_i, + input icache_l1_events_t l1_events_i +); + + import cluster_icache_ctrl_reg_pkg::*; + + initial begin + assert(5 == $bits(icache_l0_events_t)); + assert(4 == $bits(icache_l1_events_t)); + assert(NumAvailableCounters >= 4 + NR_FETCH_PORTS*5); + assert(NR_FETCH_PORTS <= NumCores); + end + + cluster_icache_ctrl_reg2hw_t reg2hw; + cluster_icache_ctrl_hw2reg_t hw2reg; + + cluster_icache_ctrl_reg_top #( + .reg_req_t(reg_req_t), + .reg_rsp_t(reg_rsp_t) + ) i_regs ( + .clk_i, + .rst_ni, + + .reg_req_i, + .reg_rsp_o, + + .reg2hw (reg2hw), + .hw2reg (hw2reg), + .devmode_i (1'b0) + ); + + cluster_icache_ctrl_hw2reg_counters_mreg_t [NumAvailableCounters-1:0] counters_reg; + + always_comb begin : gen_counters_reg + // set up defaults - increment but not active + for (int unsigned i = 0; i < NumAvailableCounters; i++) begin + counters_reg[i].d = reg2hw.counters[i].q + 1; + counters_reg[i].de = '0; + end + + // Activate increment counters + counters_reg[0].de = reg2hw.enable_counters.q & l1_events_i.l1_miss; + counters_reg[1].de = reg2hw.enable_counters.q & l1_events_i.l1_hit; + counters_reg[2].de = reg2hw.enable_counters.q & l1_events_i.l1_stall; + counters_reg[3].de = reg2hw.enable_counters.q & l1_events_i.l1_handler_stall; + + for (int unsigned i = 0; i < NR_FETCH_PORTS; i++) begin + counters_reg[4 + i*5 + 0].de = reg2hw.enable_counters.q & l0_events_i[i].l0_miss; + counters_reg[4 + i*5 + 1].de = reg2hw.enable_counters.q & l0_events_i[i].l0_hit; + counters_reg[4 + i*5 + 2].de = reg2hw.enable_counters.q & l0_events_i[i].l0_prefetch; + counters_reg[4 + i*5 + 3].de = reg2hw.enable_counters.q & l0_events_i[i].l0_double_hit; + counters_reg[4 + i*5 + 4].de = reg2hw.enable_counters.q & l0_events_i[i].l0_stall; + end + + // Clear on global clear signal + if (reg2hw.clear_counters.q) begin + for (int unsigned i = 0; i < NumAvailableCounters; i++) begin + counters_reg[i].d = '0; + counters_reg[i].de = '1; + end + end + end + + assign enable_prefetching_o = reg2hw.enable_prefetch.q; + assign flush_valid_o = ({NR_FETCH_PORTS{reg2hw.flush.q}} & {NR_FETCH_PORTS{reg2hw.flush.qe}}) | + (reg2hw.sel_flush_icache.q[NR_FETCH_PORTS-1:0] & + {NR_FETCH_PORTS{reg2hw.sel_flush_icache.qe}}); + + assign hw2reg.flush.d = ~|flush_ready_i; + assign hw2reg.flush_l1_only.d = '0; + assign hw2reg.sel_flush_icache.d = ~flush_ready_i; + assign hw2reg.clear_counters.d = '0; + assign hw2reg.counters = counters_reg; + +endmodule From ceb81b24e67e14b48e5682861d4e9cbd960a9364 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 8 Feb 2024 11:51:27 +0100 Subject: [PATCH 13/17] Add initial L1 parity protection --- src/pulp_icache_wrap.sv | 3 + src/snitch_icache.sv | 3 + src/snitch_icache_handler.sv | 4 +- src/snitch_icache_lookup_serial.sv | 200 +++++++++++++++++++++++------ src/snitch_icache_pkg.sv | 1 + 5 files changed, 173 insertions(+), 38 deletions(-) diff --git a/src/pulp_icache_wrap.sv b/src/pulp_icache_wrap.sv index 6c470f5..86d93ff 100644 --- a/src/pulp_icache_wrap.sv +++ b/src/pulp_icache_wrap.sv @@ -34,6 +34,8 @@ module pulp_icache_wrap #( parameter int LINE_COUNT = -1, /// The set associativity of the cache. Power of two; >= 1. parameter int SET_COUNT = 1, + /// Error detection + parameter int unsigned L1DataParityWidth = 0, /// Fetch interface address width. Same as FILL_AW; >= 1. parameter int FetchAddrWidth = -1, /// Fetch interface data width. Power of two; >= 8. @@ -204,6 +206,7 @@ module pulp_icache_wrap #( .FILL_DW ( AxiDataWidth ), .FETCH_PRIORITY ( 1 ), .MERGE_FETCHES ( 1 ), + .L1_DATA_PARITY_BITS( L1DataParityWidth ), .L1_TAG_SCM ( 1 ), .SERIAL_LOOKUP ( 1 ), .NUM_AXI_OUTSTANDING( 4 ), diff --git a/src/snitch_icache.sv b/src/snitch_icache.sv index 5195ed6..5a7ba85 100644 --- a/src/snitch_icache.sv +++ b/src/snitch_icache.sv @@ -30,6 +30,8 @@ module snitch_icache import snitch_icache_pkg::*; #( parameter bit FETCH_PRIORITY = 1'b0, /// Merge L0-L1 fetches if requesting the same address parameter bit MERGE_FETCHES = 1'b0, + /// Extra parity bits to add to a line for L1 reliability. + parameter int unsigned L1_DATA_PARITY_BITS = 0, /// Serialize the L1 lookup (parallel tag/data lookup by default) parameter bit SERIAL_LOOKUP = 0, /// Replace the L1 tag banks with latch-based SCM. @@ -95,6 +97,7 @@ module snitch_icache import snitch_icache_pkg::*; #( FETCH_DW: FETCH_DW, FILL_AW: FILL_AW, FILL_DW: FILL_DW, + L1_DATA_PARITY_BITS: L1_DATA_PARITY_BITS, L1_TAG_SCM: L1_TAG_SCM, EARLY_LATCH: EARLY_LATCH, BUFFER_LOOKUP: 0, diff --git a/src/snitch_icache_handler.sv b/src/snitch_icache_handler.sv index 3675317..2bbe0e1 100644 --- a/src/snitch_icache_handler.sv +++ b/src/snitch_icache_handler.sv @@ -218,8 +218,8 @@ module snitch_icache_handler #( in_req_ready_o = hit_ready; // The cache lookup was a miss, but there is already a pending - // refill that covers the line. - end else if (pending) begin + // refill that covers the line and the lookup accepted the request. + end else if (pending && !(write_valid_o && !write_ready_i)) begin push_index = pending_id; push_enable = 1; diff --git a/src/snitch_icache_lookup_serial.sv b/src/snitch_icache_lookup_serial.sv index 7584e3e..4bd25f5 100644 --- a/src/snitch_icache_lookup_serial.sv +++ b/src/snitch_icache_lookup_serial.sv @@ -47,6 +47,7 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( ); localparam int unsigned DataAddrWidth = $clog2(CFG.SET_COUNT) + CFG.COUNT_ALIGN; + localparam int unsigned TagParity = (CFG.L1_DATA_PARITY_BITS > 0) ? 1 : 0; `ifndef SYNTHESIS initial assert(CFG != '0); @@ -82,13 +83,20 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( logic error; } tag_rsp_t; + typedef struct packed { + logic [ CFG.FETCH_AW-1:0] addr; + logic [CFG.SET_ALIGN-1:0] cset; + logic parity_error; + } tag_inv_req_t; + logic req_valid, req_ready; logic req_handshake; - logic [CFG.COUNT_ALIGN-1:0] tag_addr; - logic [CFG.SET_COUNT-1:0] tag_enable; - logic [CFG.TAG_WIDTH+1:0] tag_wdata, tag_rdata [CFG.SET_COUNT]; - logic tag_write; + logic [CFG.COUNT_ALIGN-1:0] tag_addr; + logic [CFG.SET_COUNT-1:0] tag_enable; + logic [CFG.TAG_WIDTH+1:0] tag_wdata; + logic [CFG.TAG_WIDTH+1+TagParity:0] tag_wdata_prot, tag_rdata [CFG.SET_COUNT]; + logic tag_write; tag_req_t tag_req_d, tag_req_q; tag_rsp_t tag_rsp_s, tag_rsp_d, tag_rsp_q, tag_rsp; @@ -97,15 +105,43 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( logic [CFG.TAG_WIDTH-1:0] required_tag; logic [CFG.SET_COUNT-1:0] line_hit; + logic [CFG.SET_COUNT-1:0] tag_parity_error_d, tag_parity_error_q; + logic faulty_hit_valid, faulty_hit_ready, faulty_hit_d, faulty_hit_q; logic [DataAddrWidth-1:0] lookup_addr; logic [DataAddrWidth-1:0] write_addr; + tag_inv_req_t data_parity_inv_d, data_parity_inv_q; + logic data_fault_valid, data_fault_ready; + // Connect input requests to tag stage assign tag_req_d.addr = in_addr_i; assign tag_req_d.id = in_id_i; // Multiplex read and write access to the tag banks onto one port, prioritizing write accesses + + logic tag_parity_bit; + if (TagParity > 0) begin : gen_tag_parity + always_comb begin + tag_parity_bit = ^write_tag_i; + if (init_phase) begin + tag_parity_bit = 1'b0; + end else if (data_fault_valid) begin + tag_parity_bit = 1'b1; + end else if (write_valid_i) begin + tag_parity_bit = ^write_tag_i; + end else if (faulty_hit_valid) begin + tag_parity_bit = 1'b1; + end else if (in_valid_i) begin + // read phase: write tag not used + end + end + end else begin : gen_no_tag_parity + assign tag_parity_bit = '0; + end + + assign data_fault_valid = (CFG.L1_DATA_PARITY_BITS > 0) ? data_parity_inv_q : '0; + always_comb begin tag_addr = in_addr_i[CFG.LINE_ALIGN +: CFG.COUNT_ALIGN]; tag_enable = '0; @@ -116,17 +152,34 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( in_ready_o = 1'b0; req_valid = 1'b0; + data_fault_ready = 1'b0; + faulty_hit_ready = 1'b0; + if (init_phase) begin - tag_addr = init_count_q; - tag_enable = '1; - tag_wdata = '0; - tag_write = 1'b1; + tag_addr = init_count_q; + tag_enable = '1; + tag_wdata[CFG.TAG_WIDTH+1:0] = '0; + tag_write = 1'b1; + end else if (data_fault_valid) begin // Only if data has parity + tag_addr = data_parity_inv_q.addr >> CFG.LINE_ALIGN; + tag_enable = $unsigned(1 << data_parity_inv_q.cset); + tag_wdata[CFG.TAG_WIDTH+1:0] = '0; + tag_write = 1'b1; + data_fault_ready = 1'b1; end else if (write_valid_i) begin // Write a refill request tag_addr = write_addr_i; tag_enable = $unsigned(1 << write_set_i); tag_write = 1'b1; write_ready_o = 1'b1; + end else if (faulty_hit_valid) begin // Only if tag has parity + // we need to set second bit (valid) of write data of the previous adress to 0 + // we do not accept read requests and we do not store data in the pipeline. + tag_addr = tag_req_q >> CFG.LINE_ALIGN; // buffered version of in_addr_i + tag_enable = tag_parity_error_q; // which set must be written (faulty one) + tag_wdata[CFG.TAG_WIDTH+1:0] = '0; + tag_write = 1'b0; + faulty_hit_ready = 1'b1; end else if (in_valid_i) begin // Check cache tag_enable = '1; @@ -136,12 +189,14 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( end end + assign tag_wdata_prot = {tag_parity_bit, tag_wdata}; + // Instantiate the tag sets. if (CFG.L1_TAG_SCM) begin : gen_scm for (genvar i = 0; i < CFG.SET_COUNT; i++) begin : g_sets register_file_1r_1w #( - .ADDR_WIDTH ($clog2(CFG.LINE_COUNT)), - .DATA_WIDTH (CFG.TAG_WIDTH+2 ) + .ADDR_WIDTH ($clog2(CFG.LINE_COUNT) ), + .DATA_WIDTH (CFG.TAG_WIDTH+2+TagParity) ) i_tag ( .clk ( clk_i ), .ReadEnable ( tag_enable[i] && !tag_write ), @@ -149,20 +204,21 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( .ReadData ( tag_rdata[i] ), .WriteEnable ( tag_enable[i] && tag_write ), .WriteAddr ( tag_addr ), - .WriteData ( tag_wdata ) + .WriteData ( tag_wdata_prot ) ); end end else begin : gen_sram - logic [CFG.SET_COUNT*(CFG.TAG_WIDTH+2)-1:0] tag_rdata_flat; + logic [CFG.SET_COUNT*(CFG.TAG_WIDTH+2+TagParity)-1:0] tag_rdata_flat; for (genvar i = 0; i < CFG.SET_COUNT; i++) begin : g_sets_rdata - assign tag_rdata[i] = tag_rdata_flat[i*(CFG.TAG_WIDTH+2)+:CFG.TAG_WIDTH+2]; + assign tag_rdata[i] = tag_rdata_flat[i*(CFG.TAG_WIDTH+2+TagParity) +: + CFG.TAG_WIDTH+2+TagParity]; end tc_sram_impl #( - .DataWidth ( (CFG.TAG_WIDTH+2) * CFG.SET_COUNT ), - .ByteWidth ( CFG.TAG_WIDTH+2 ), - .NumWords ( CFG.LINE_COUNT ), - .NumPorts ( 1 ), - .impl_in_t ( sram_cfg_tag_t ) + .DataWidth ( (CFG.TAG_WIDTH+2+TagParity) * CFG.SET_COUNT ), + .ByteWidth ( CFG.TAG_WIDTH+2+TagParity ), + .NumWords ( CFG.LINE_COUNT ), + .NumPorts ( 1 ), + .impl_in_t ( sram_cfg_tag_t ) ) i_tag ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -171,12 +227,23 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( .req_i ( |tag_enable ), .we_i ( tag_write ), .addr_i ( tag_addr ), - .wdata_i ( {CFG.SET_COUNT{tag_wdata}} ), + .wdata_i ( {CFG.SET_COUNT{tag_wdata_prot}} ), .be_i ( tag_enable ), .rdata_o ( tag_rdata_flat ) ); end + // compute tag parity bit the cycle before reading the tag and buffer it + logic exp_tag_parity_bit_d, exp_tag_parity_bit_q; + + if (TagParity>0) begin : gen_tag_parity_bit + assign exp_tag_parity_bit_d = ^(tag_req_d.addr >> (CFG.LINE_ALIGN + CFG.COUNT_ALIGN)); + `FFL(exp_tag_parity_bit_q, exp_tag_parity_bit_d, req_valid && req_ready, '0, clk_i, rst_ni); + end else begin : gen_no_tag_parity_bit + assign exp_tag_parity_bit_d = '0; + assign exp_tag_parity_bit_q = '0; + end + // Determine which set hit logic [CFG.SET_COUNT-1:0] errors; assign required_tag = tag_req_q.addr[CFG.FETCH_AW-1:CFG.LINE_ALIGN + CFG.COUNT_ALIGN]; @@ -185,9 +252,20 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( tag_rdata[i][CFG.TAG_WIDTH-1:0] == required_tag; // check valid bit and tag assign errors[i] = tag_rdata[i][CFG.TAG_WIDTH] && line_hit[i]; // check error bit end - assign tag_rsp_s.hit = |line_hit; assign tag_rsp_s.error = |errors; + if (TagParity>0) begin : gen_tag_parity_error + for (genvar i = 0; i < CFG.SET_COUNT; i++) begin : gen_tag_parity_error_individual + assign tag_parity_error_d[i] = ~((tag_rdata[i][CFG.TAG_WIDTH+2] == exp_tag_parity_bit_q)); + end + assign tag_rsp_s.hit = |(line_hit & ~tag_parity_error_d); + assign faulty_hit_d = |(line_hit & tag_parity_error_d); + end else begin : gen_no_tag_parity_error + assign tag_rsp_s.hit = |line_hit; + assign tag_parity_error_d = '0; + assign faulty_hit_d = '0; + end + lzc #(.WIDTH(CFG.SET_COUNT)) i_lzc ( .in_i ( line_hit ), .cnt_o ( tag_rsp_s.cset ), @@ -197,6 +275,17 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( // Buffer the metadata on a valid handshake. Stall on write (implicit in req_valid/ready) `FFL(tag_req_q, tag_req_d, req_valid && req_ready, '0, clk_i, rst_ni) `FF(tag_valid, req_valid ? 1'b1 : tag_ready ? 1'b0 : tag_valid, '0, clk_i, rst_ni) + if (TagParity>0) begin : gen_tag_parity_error_ff + // save faulty sets and clear when upstream invalidated them + `FFL(tag_parity_error_q, tag_parity_error_d, req_valid && req_ready, '0, clk_i, rst_ni) + `FFL(faulty_hit_q, (faulty_hit_ready && !(req_valid && req_ready)) ? 1'b0 : faulty_hit_d, + req_valid && req_ready || faulty_hit_ready, '0, clk_i, rst_ni) + end else begin : gen_no_tag_parity_error_ff + assign tag_parity_error_q = '0; + assign faulty_hit_q = '0; + end + assign faulty_hit_valid = faulty_hit_q; + // Ready if buffer is empy or downstream is reading. Stall on write assign req_ready = (!tag_valid || tag_ready) && !tag_write; @@ -214,7 +303,7 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( tag_rsp_d = tag_rsp_s; end // Override the hit if the write that stalled us invalidated the data - if (lookup_addr == write_addr && write_valid_i) begin + if ((lookup_addr == write_addr) && write_valid_i && write_ready_o) begin tag_rsp_d.hit = 1'b0; end end @@ -233,14 +322,15 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( typedef logic [CFG.LINE_WIDTH-1:0] data_rsp_t; - logic [DataAddrWidth-1:0] data_addr; - logic data_enable; - data_rsp_t data_wdata, data_rdata; - logic data_write; + logic [DataAddrWidth-1:0] data_addr; + logic data_enable; + logic [CFG.LINE_WIDTH+CFG.L1_DATA_PARITY_BITS-1:0] data_wdata, data_rdata; + logic data_write; - data_req_t data_req_d, data_req_q; - data_rsp_t data_rsp_q; - logic data_valid, data_ready; + data_req_t data_req_d, data_req_q; + data_rsp_t data_rsp_q; + logic data_valid, data_ready; + logic hit_invalid, hit_invalid_q; logic refill_hit_d, refill_hit_q; data_rsp_t refill_wdata_q, proper_rdata; @@ -257,15 +347,25 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( assign lookup_addr = {tag_rsp.cset, tag_req_q.addr[CFG.LINE_ALIGN +: CFG.COUNT_ALIGN]}; assign write_addr = {write_set_i, write_addr_i}; + localparam int unsigned LineParitySplit = CFG.LINE_WIDTH/CFG.L1_DATA_PARITY_BITS; + if (CFG.L1_DATA_PARITY_BITS>0) begin : gen_wdata_parity + for (genvar i = 0; i < CFG.L1_DATA_PARITY_BITS; i++) begin : gen_wdata_parity_individual + assign data_wdata[CFG.LINE_WIDTH+CFG.L1_DATA_PARITY_BITS-1-i] = + ~^write_data_i[CFG.LINE_WIDTH-LineParitySplit*i-1 -: LineParitySplit]; + end + end + for (genvar i = 0; i < CFG.LINE_WIDTH; i++) begin : gen_wdata_individual + assign data_wdata[i] = write_data_i[i]; + end + // Data bank port mux always_comb begin // Default read request data_addr = lookup_addr; data_enable = tag_valid && tag_rsp.hit; // Only read data on hit - data_wdata = write_data_i; data_write = 1'b0; - // Write takes priority - if (!init_phase && write_valid_i) begin + // Write takes priority (except with invalidation due to parity error) + if (!init_phase && write_valid_i && !data_fault_valid) begin data_addr = write_addr; data_enable = 1'b1; data_write = 1'b1; @@ -273,10 +373,10 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( end tc_sram_impl #( - .DataWidth ( CFG.LINE_WIDTH ), - .NumWords ( CFG.LINE_COUNT * CFG.SET_COUNT ), - .NumPorts ( 1 ), - .impl_in_t ( sram_cfg_data_t ) + .DataWidth ( CFG.LINE_WIDTH + CFG.L1_DATA_PARITY_BITS ), + .NumWords ( CFG.LINE_COUNT * CFG.SET_COUNT ), + .NumPorts ( 1 ), + .impl_in_t ( sram_cfg_data_t ) ) i_data ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -290,6 +390,23 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( .rdata_o ( data_rdata ) ); + // Parity check + if (CFG.L1_DATA_PARITY_BITS>0) begin : gen_data_parity_error + logic [CFG.L1_DATA_PARITY_BITS-1:0] data_parity_error; + + for (genvar i = 0; i < CFG.L1_DATA_PARITY_BITS; i++) begin : gen_data_parity_error_individual + assign data_parity_error[i] = + data_rdata[CFG.LINE_WIDTH + CFG.L1_DATA_PARITY_BITS -1 - i] == + ^data_rdata[CFG.LINE_WIDTH-LineParitySplit*i-1 -: LineParitySplit]; + end + + assign data_parity_inv_d.parity_error = |data_parity_error; + assign data_parity_inv_d.addr = data_req_q.addr; + assign data_parity_inv_d.cset = data_req_q.id; + end else begin : gen_no_data_parity_error + assign data_parity_inv_d = '0; + end + // Buffer the metadata on a valid handshake. Stall on write (implicit in tag_ready) `FFL(data_req_q, data_req_d, tag_valid && tag_ready, '0, clk_i, rst_ni) `FF(data_valid, (tag_valid && (!data_write || refill_hit_d)) ? @@ -317,11 +434,22 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( `FFL(write_set_q, write_set_i, refill_hit_d, '0, clk_i, rst_ni) `FFL(write_error_q, write_error_i, refill_hit_d, '0, clk_i, rst_ni) + // Buffer the metadata when there is faulty data for the invalidation procedure + if (CFG.L1_DATA_PARITY_BITS > 0) begin : gen_data_parity_error_ff + `FFL(data_parity_inv_q, (data_fault_ready && !tag_handshake) ? '0 : data_parity_inv_d, + tag_handshake || data_fault_ready, '0, clk_i, rst_ni) + `FFL(hit_invalid_q, data_parity_inv_d.parity_error, tag_handshake, '0, clk_i, rst_ni) + end else begin : gen_no_data_parity_error_ff + assign data_parity_inv_q = '0; + assign hit_invalid_q = '0; + end + assign hit_invalid = tag_handshake ? data_parity_inv_d.parity_error : hit_invalid_q; + // Generate the remaining output signals. assign out_addr_o = data_req_q.addr; assign out_id_o = data_req_q.id; assign out_set_o = refill_hit_q && !data_req_q.hit ? write_set_q : data_req_q.cset; - assign out_hit_o = refill_hit_q || data_req_q.hit; + assign out_hit_o = refill_hit_q || data_req_q.hit && !hit_invalid; assign out_error_o = refill_hit_q && !data_req_q.hit ? write_error_q : data_req_q.error; assign out_valid_o = data_valid; assign data_ready = out_ready_i; diff --git a/src/snitch_icache_pkg.sv b/src/snitch_icache_pkg.sv index b018b3c..8623300 100644 --- a/src/snitch_icache_pkg.sv +++ b/src/snitch_icache_pkg.sv @@ -33,6 +33,7 @@ package snitch_icache_pkg; int unsigned FETCH_DW; int unsigned FILL_AW; int unsigned FILL_DW; + int unsigned L1_DATA_PARITY_BITS; bit L1_TAG_SCM; bit EARLY_LATCH; bit BUFFER_LOOKUP; From 8b0b1751eba85abb270952943697552bc265fb7a Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Thu, 25 Apr 2024 15:44:39 +0200 Subject: [PATCH 14/17] Add L1 error count registers --- src/ctrl_unit/cluster_icache_ctrl.hjson | 10 ++- src/ctrl_unit/cluster_icache_ctrl_reg_pkg.sv | 42 ++++++---- src/ctrl_unit/cluster_icache_ctrl_reg_top.sv | 82 +++++++++++++++++++- src/ctrl_unit/cluster_icache_ctrl_unit.sv | 23 ++++-- src/snitch_icache_lookup_parallel.sv | 2 + src/snitch_icache_lookup_serial.sv | 2 + src/snitch_icache_pkg.sv | 2 + 7 files changed, 135 insertions(+), 28 deletions(-) diff --git a/src/ctrl_unit/cluster_icache_ctrl.hjson b/src/ctrl_unit/cluster_icache_ctrl.hjson index 5286d71..fe8adb6 100644 --- a/src/ctrl_unit/cluster_icache_ctrl.hjson +++ b/src/ctrl_unit/cluster_icache_ctrl.hjson @@ -17,9 +17,17 @@ desc: "Number of cores", default: "8" }, + { name: "NumL0Events", + desc: "Number of L0 events", + default: "5" + }, + { name: "NumL1Events", + desc: "Number of L1 events", + default: "6" + }, { name: "NumAvailableCounters", desc: "Number of available counters", - default: "44" // NumL1Events + NumCores * NumL0Events + default: "46" // NumL1Events + NumCores * NumL0Events }, ], diff --git a/src/ctrl_unit/cluster_icache_ctrl_reg_pkg.sv b/src/ctrl_unit/cluster_icache_ctrl_reg_pkg.sv index 8df9fbe..4370993 100644 --- a/src/ctrl_unit/cluster_icache_ctrl_reg_pkg.sv +++ b/src/ctrl_unit/cluster_icache_ctrl_reg_pkg.sv @@ -8,7 +8,9 @@ package cluster_icache_ctrl_reg_pkg; // Param list parameter int NumCores = 8; - parameter int NumAvailableCounters = 44; + parameter int NumL0Events = 5; + parameter int NumL1Events = 6; + parameter int NumAvailableCounters = 46; // Address widths within the block parameter int BlockAw = 8; @@ -76,23 +78,23 @@ package cluster_icache_ctrl_reg_pkg; // Register -> HW type typedef struct packed { - cluster_icache_ctrl_reg2hw_enable_reg_t enable; // [1425:1425] - cluster_icache_ctrl_reg2hw_flush_reg_t flush; // [1424:1423] - cluster_icache_ctrl_reg2hw_flush_l1_only_reg_t flush_l1_only; // [1422:1421] - cluster_icache_ctrl_reg2hw_sel_flush_icache_reg_t sel_flush_icache; // [1420:1412] - cluster_icache_ctrl_reg2hw_clear_counters_reg_t clear_counters; // [1411:1410] - cluster_icache_ctrl_reg2hw_enable_counters_reg_t enable_counters; // [1409:1409] - cluster_icache_ctrl_reg2hw_enable_prefetch_reg_t enable_prefetch; // [1408:1408] - cluster_icache_ctrl_reg2hw_counters_mreg_t [43:0] counters; // [1407:0] + cluster_icache_ctrl_reg2hw_enable_reg_t enable; // [1489:1489] + cluster_icache_ctrl_reg2hw_flush_reg_t flush; // [1488:1487] + cluster_icache_ctrl_reg2hw_flush_l1_only_reg_t flush_l1_only; // [1486:1485] + cluster_icache_ctrl_reg2hw_sel_flush_icache_reg_t sel_flush_icache; // [1484:1476] + cluster_icache_ctrl_reg2hw_clear_counters_reg_t clear_counters; // [1475:1474] + cluster_icache_ctrl_reg2hw_enable_counters_reg_t enable_counters; // [1473:1473] + cluster_icache_ctrl_reg2hw_enable_prefetch_reg_t enable_prefetch; // [1472:1472] + cluster_icache_ctrl_reg2hw_counters_mreg_t [45:0] counters; // [1471:0] } cluster_icache_ctrl_reg2hw_t; // HW -> register type typedef struct packed { - cluster_icache_ctrl_hw2reg_flush_reg_t flush; // [1462:1462] - cluster_icache_ctrl_hw2reg_flush_l1_only_reg_t flush_l1_only; // [1461:1461] - cluster_icache_ctrl_hw2reg_sel_flush_icache_reg_t sel_flush_icache; // [1460:1453] - cluster_icache_ctrl_hw2reg_clear_counters_reg_t clear_counters; // [1452:1452] - cluster_icache_ctrl_hw2reg_counters_mreg_t [43:0] counters; // [1451:0] + cluster_icache_ctrl_hw2reg_flush_reg_t flush; // [1528:1528] + cluster_icache_ctrl_hw2reg_flush_l1_only_reg_t flush_l1_only; // [1527:1527] + cluster_icache_ctrl_hw2reg_sel_flush_icache_reg_t sel_flush_icache; // [1526:1519] + cluster_icache_ctrl_hw2reg_clear_counters_reg_t clear_counters; // [1518:1518] + cluster_icache_ctrl_hw2reg_counters_mreg_t [45:0] counters; // [1517:0] } cluster_icache_ctrl_hw2reg_t; // Register offsets @@ -147,6 +149,8 @@ package cluster_icache_ctrl_reg_pkg; parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_41_OFFSET = 8'h c4; parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_42_OFFSET = 8'h c8; parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_43_OFFSET = 8'h cc; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_44_OFFSET = 8'h d0; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_COUNTERS_45_OFFSET = 8'h d4; // Reset values for hwext registers and their fields parameter logic [0:0] CLUSTER_ICACHE_CTRL_FLUSH_RESVAL = 1'h 0; @@ -210,11 +214,13 @@ package cluster_icache_ctrl_reg_pkg; CLUSTER_ICACHE_CTRL_COUNTERS_40, CLUSTER_ICACHE_CTRL_COUNTERS_41, CLUSTER_ICACHE_CTRL_COUNTERS_42, - CLUSTER_ICACHE_CTRL_COUNTERS_43 + CLUSTER_ICACHE_CTRL_COUNTERS_43, + CLUSTER_ICACHE_CTRL_COUNTERS_44, + CLUSTER_ICACHE_CTRL_COUNTERS_45 } cluster_icache_ctrl_id_e; // Register width information to check illegal writes - parameter logic [3:0] CLUSTER_ICACHE_CTRL_PERMIT [51] = '{ + parameter logic [3:0] CLUSTER_ICACHE_CTRL_PERMIT [53] = '{ 4'b 0001, // index[ 0] CLUSTER_ICACHE_CTRL_ENABLE 4'b 0001, // index[ 1] CLUSTER_ICACHE_CTRL_FLUSH 4'b 0001, // index[ 2] CLUSTER_ICACHE_CTRL_FLUSH_L1_ONLY @@ -265,7 +271,9 @@ package cluster_icache_ctrl_reg_pkg; 4'b 1111, // index[47] CLUSTER_ICACHE_CTRL_COUNTERS_40 4'b 1111, // index[48] CLUSTER_ICACHE_CTRL_COUNTERS_41 4'b 1111, // index[49] CLUSTER_ICACHE_CTRL_COUNTERS_42 - 4'b 1111 // index[50] CLUSTER_ICACHE_CTRL_COUNTERS_43 + 4'b 1111, // index[50] CLUSTER_ICACHE_CTRL_COUNTERS_43 + 4'b 1111, // index[51] CLUSTER_ICACHE_CTRL_COUNTERS_44 + 4'b 1111 // index[52] CLUSTER_ICACHE_CTRL_COUNTERS_45 }; endpackage diff --git a/src/ctrl_unit/cluster_icache_ctrl_reg_top.sv b/src/ctrl_unit/cluster_icache_ctrl_reg_top.sv index 9f9d0ca..305ac0b 100644 --- a/src/ctrl_unit/cluster_icache_ctrl_reg_top.sv +++ b/src/ctrl_unit/cluster_icache_ctrl_reg_top.sv @@ -225,6 +225,12 @@ module cluster_icache_ctrl_reg_top #( logic [31:0] counters_43_qs; logic [31:0] counters_43_wd; logic counters_43_we; + logic [31:0] counters_44_qs; + logic [31:0] counters_44_wd; + logic counters_44_we; + logic [31:0] counters_45_qs; + logic [31:0] counters_45_wd; + logic counters_45_we; // Register instances // R[enable]: V(False) @@ -1561,10 +1567,64 @@ module cluster_icache_ctrl_reg_top #( .qs (counters_43_qs) ); + // Subregister 44 of Multireg counters + // R[counters_44]: V(False) + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_44 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_44_we), + .wd (counters_44_wd), + + // from internal hardware + .de (hw2reg.counters[44].de), + .d (hw2reg.counters[44].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[44].q ), + + // to register interface (read) + .qs (counters_44_qs) + ); + + // Subregister 45 of Multireg counters + // R[counters_45]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_45 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + // from register interface + .we (counters_45_we), + .wd (counters_45_wd), + + // from internal hardware + .de (hw2reg.counters[45].de), + .d (hw2reg.counters[45].d ), - logic [50:0] addr_hit; + // to internal hardware + .qe (), + .q (reg2hw.counters[45].q ), + + // to register interface (read) + .qs (counters_45_qs) + ); + + + + + logic [52:0] addr_hit; always_comb begin addr_hit = '0; addr_hit[ 0] = (reg_addr == CLUSTER_ICACHE_CTRL_ENABLE_OFFSET); @@ -1618,6 +1678,8 @@ module cluster_icache_ctrl_reg_top #( addr_hit[48] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_41_OFFSET); addr_hit[49] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_42_OFFSET); addr_hit[50] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_43_OFFSET); + addr_hit[51] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_44_OFFSET); + addr_hit[52] = (reg_addr == CLUSTER_ICACHE_CTRL_COUNTERS_45_OFFSET); end assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; @@ -1675,7 +1737,9 @@ module cluster_icache_ctrl_reg_top #( (addr_hit[47] & (|(CLUSTER_ICACHE_CTRL_PERMIT[47] & ~reg_be))) | (addr_hit[48] & (|(CLUSTER_ICACHE_CTRL_PERMIT[48] & ~reg_be))) | (addr_hit[49] & (|(CLUSTER_ICACHE_CTRL_PERMIT[49] & ~reg_be))) | - (addr_hit[50] & (|(CLUSTER_ICACHE_CTRL_PERMIT[50] & ~reg_be))))); + (addr_hit[50] & (|(CLUSTER_ICACHE_CTRL_PERMIT[50] & ~reg_be))) | + (addr_hit[51] & (|(CLUSTER_ICACHE_CTRL_PERMIT[51] & ~reg_be))) | + (addr_hit[52] & (|(CLUSTER_ICACHE_CTRL_PERMIT[52] & ~reg_be))))); end assign enable_we = addr_hit[0] & reg_we & !reg_error; @@ -1835,6 +1899,12 @@ module cluster_icache_ctrl_reg_top #( assign counters_43_we = addr_hit[50] & reg_we & !reg_error; assign counters_43_wd = reg_wdata[31:0]; + assign counters_44_we = addr_hit[51] & reg_we & !reg_error; + assign counters_44_wd = reg_wdata[31:0]; + + assign counters_45_we = addr_hit[52] & reg_we & !reg_error; + assign counters_45_wd = reg_wdata[31:0]; + // Read data return always_comb begin reg_rdata_next = '0; @@ -2043,6 +2113,14 @@ module cluster_icache_ctrl_reg_top #( reg_rdata_next[31:0] = counters_43_qs; end + addr_hit[51]: begin + reg_rdata_next[31:0] = counters_44_qs; + end + + addr_hit[52]: begin + reg_rdata_next[31:0] = counters_45_qs; + end + default: begin reg_rdata_next = '1; end diff --git a/src/ctrl_unit/cluster_icache_ctrl_unit.sv b/src/ctrl_unit/cluster_icache_ctrl_unit.sv index 3c2061a..341ca06 100644 --- a/src/ctrl_unit/cluster_icache_ctrl_unit.sv +++ b/src/ctrl_unit/cluster_icache_ctrl_unit.sv @@ -26,9 +26,9 @@ module cluster_icache_ctrl_unit import snitch_icache_pkg::*; #( import cluster_icache_ctrl_reg_pkg::*; initial begin - assert(5 == $bits(icache_l0_events_t)); - assert(4 == $bits(icache_l1_events_t)); - assert(NumAvailableCounters >= 4 + NR_FETCH_PORTS*5); + assert(NumL0Events == $bits(icache_l0_events_t)); + assert(NumL1Events == $bits(icache_l1_events_t)); + assert(NumAvailableCounters >= NumL1Events + NR_FETCH_PORTS*NumL0Events); assert(NR_FETCH_PORTS <= NumCores); end @@ -64,13 +64,20 @@ module cluster_icache_ctrl_unit import snitch_icache_pkg::*; #( counters_reg[1].de = reg2hw.enable_counters.q & l1_events_i.l1_hit; counters_reg[2].de = reg2hw.enable_counters.q & l1_events_i.l1_stall; counters_reg[3].de = reg2hw.enable_counters.q & l1_events_i.l1_handler_stall; + counters_reg[5].de = reg2hw.enable_counters.q & l1_events_i.l1_tag_parity_error; + counters_reg[6].de = reg2hw.enable_counters.q & l1_events_i.l1_data_parity_error; for (int unsigned i = 0; i < NR_FETCH_PORTS; i++) begin - counters_reg[4 + i*5 + 0].de = reg2hw.enable_counters.q & l0_events_i[i].l0_miss; - counters_reg[4 + i*5 + 1].de = reg2hw.enable_counters.q & l0_events_i[i].l0_hit; - counters_reg[4 + i*5 + 2].de = reg2hw.enable_counters.q & l0_events_i[i].l0_prefetch; - counters_reg[4 + i*5 + 3].de = reg2hw.enable_counters.q & l0_events_i[i].l0_double_hit; - counters_reg[4 + i*5 + 4].de = reg2hw.enable_counters.q & l0_events_i[i].l0_stall; + counters_reg[NumL1Events + i*NumL0Events + 0].de = reg2hw.enable_counters.q & + l0_events_i[i].l0_miss; + counters_reg[NumL1Events + i*NumL0Events + 1].de = reg2hw.enable_counters.q & + l0_events_i[i].l0_hit; + counters_reg[NumL1Events + i*NumL0Events + 2].de = reg2hw.enable_counters.q & + l0_events_i[i].l0_prefetch; + counters_reg[NumL1Events + i*NumL0Events + 3].de = reg2hw.enable_counters.q & + l0_events_i[i].l0_double_hit; + counters_reg[NumL1Events + i*NumL0Events + 4].de = reg2hw.enable_counters.q & + l0_events_i[i].l0_stall; end // Clear on global clear signal diff --git a/src/snitch_icache_lookup_parallel.sv b/src/snitch_icache_lookup_parallel.sv index 4a8fa46..1a2eb11 100644 --- a/src/snitch_icache_lookup_parallel.sv +++ b/src/snitch_icache_lookup_parallel.sv @@ -260,6 +260,8 @@ module snitch_icache_lookup_parallel import snitch_icache_pkg::*; #( icache_events_o.l1_hit = valid_q & data_d.hit; icache_events_o.l1_stall = in_valid_i & ~in_ready_o; icache_events_o.l1_handler_stall = out_valid_o & ~out_ready_i; + icache_events_o.l1_tag_parity_error = '0; + icache_events_o.l1_data_parity_error = '0; end // Assertions diff --git a/src/snitch_icache_lookup_serial.sv b/src/snitch_icache_lookup_serial.sv index 4bd25f5..31314c6 100644 --- a/src/snitch_icache_lookup_serial.sv +++ b/src/snitch_icache_lookup_serial.sv @@ -463,6 +463,8 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( icache_events_o.l1_hit = req_handshake & tag_rsp_s.hit; icache_events_o.l1_stall = in_valid_i & ~in_ready_o; icache_events_o.l1_handler_stall = out_valid_o & ~out_ready_i; + icache_events_o.l1_tag_parity_error = req_handshake & faulty_hit_d; + icache_events_o.l1_data_parity_error = tag_handshake & data_parity_inv_d.parity_error; end endmodule diff --git a/src/snitch_icache_pkg.sv b/src/snitch_icache_pkg.sv index 8623300..0c090a5 100644 --- a/src/snitch_icache_pkg.sv +++ b/src/snitch_icache_pkg.sv @@ -19,6 +19,8 @@ package snitch_icache_pkg; logic l1_hit; logic l1_stall; logic l1_handler_stall; + logic l1_tag_parity_error; + logic l1_data_parity_error; } icache_l1_events_t; typedef struct packed { From 269f6fd23aeaeb9cd18f16377ca1095688aa337d Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Tue, 30 Apr 2024 14:55:35 +0200 Subject: [PATCH 15/17] Fix L0 testbench --- test/snitch_icache_l0_tb.sv | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/test/snitch_icache_l0_tb.sv b/test/snitch_icache_l0_tb.sv index 2075421..6f4a296 100644 --- a/test/snitch_icache_l0_tb.sv +++ b/test/snitch_icache_l0_tb.sv @@ -87,6 +87,7 @@ module snitch_icache_l0_tb #( FETCH_DW: FETCH_DW, FILL_AW: FILL_AW, FILL_DW: FILL_DW, + L1_DATA_PARITY_BITS: 0, L1_TAG_SCM: 1'b0, EARLY_LATCH: EARLY_LATCH, BUFFER_LOOKUP: BUFFER_LOOKUP, @@ -107,8 +108,7 @@ module snitch_icache_l0_tb #( PENDING_IW: $clog2(2) }; - localparam int unsigned IdWidthReq = $clog2(NR_FETCH_PORTS) + 1; - localparam int unsigned IdWidthResp = 2*NR_FETCH_PORTS; + localparam int unsigned IdWidth = 2*NR_FETCH_PORTS; logic clk, rst; logic dut_flush_valid; @@ -121,12 +121,12 @@ module snitch_icache_l0_tb #( typedef struct packed { logic [LINE_WIDTH-1:0] data; logic error; - logic [IdWidthResp-1:0] id; + logic [IdWidth-1:0] id; } dut_in_t; typedef struct packed { addr_t addr; - logic [IdWidthReq-1:0] id; + logic [IdWidth-1:0] id; } dut_out_t; typedef stream_test::stream_driver #( @@ -285,13 +285,27 @@ module snitch_icache_l0_tb #( `ASSERT(RequestProgress, dut_valid |-> ##[0:RequestTimeout] dut_ready, clk, rst) // Response Drivers - mailbox #(dut_out_t) addr_mbx [2]; + mailbox #(dut_out_t) addr_mbx [IdWidth]; semaphore response_lock = new (1); + function automatic logic [$clog2(IdWidth)-1:0] onehot2bin (input logic [IdWidth-1:0] onehot); + logic [$clog2(IdWidth)-1:0] bin; + for (int i = 0; i < IdWidth; i++) begin + logic [IdWidth-1:0] tmp_mask; + for (int j = 0; j < IdWidth; j++) begin + logic [IdWidth-1:0] tmp_i; + tmp_i = j; + tmp_mask[j] = tmp_i[i]; + end + bin[i] = |(tmp_mask & onehot); + end + return bin; + endfunction + initial begin automatic int unsigned stall_cycles; - automatic dut_out_t dut_out; - for (int i = 0; i < 2**IdWidthReq; i++) + automatic dut_out_t dut_out_loc; + for (int i = 0; i < IdWidth; i++) addr_mbx [i] = new(); out_driver.reset_out(); @(negedge rst); @@ -299,8 +313,8 @@ module snitch_icache_l0_tb #( forever begin stall_cycles = $urandom_range(0, 5); repeat (stall_cycles) @(posedge clk); - out_driver.recv(dut_out); - addr_mbx[dut_out.id].put(dut_out); + out_driver.recv(dut_out_loc); + addr_mbx[onehot2bin(dut_out_loc.id)].put(dut_out_loc); // $info("Requesting from Address: %h, ID: %d", dut_out.addr, dut_out.id); end end From b3b0c474eb5baa2fdeece65369805206398ab63b Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Fri, 10 May 2024 17:04:05 +0200 Subject: [PATCH 16/17] Add ctrl_reg variant without L0 statistics --- Bender.yml | 4 + Makefile | 6 +- .../cluster_icache_ctrl_perfctr.hjson | 146 ++++ .../cluster_icache_ctrl_perfctr_reg_pkg.sv | 160 +++++ .../cluster_icache_ctrl_perfctr_reg_top.sv | 634 ++++++++++++++++++ .../cluster_icache_ctrl_perfctr_unit.sv | 103 +++ 6 files changed, 1052 insertions(+), 1 deletion(-) create mode 100644 src/ctrl_unit/cluster_icache_ctrl_perfctr.hjson create mode 100644 src/ctrl_unit/cluster_icache_ctrl_perfctr_reg_pkg.sv create mode 100644 src/ctrl_unit/cluster_icache_ctrl_perfctr_reg_top.sv create mode 100644 src/ctrl_unit/cluster_icache_ctrl_perfctr_unit.sv diff --git a/Bender.yml b/Bender.yml index 985466d..ade436b 100644 --- a/Bender.yml +++ b/Bender.yml @@ -44,6 +44,10 @@ sources: - src/ctrl_unit/cluster_icache_ctrl_reg_pkg.sv - src/ctrl_unit/cluster_icache_ctrl_reg_top.sv - src/ctrl_unit/cluster_icache_ctrl_unit.sv + - files: # ctrl_unit + - src/ctrl_unit/cluster_icache_ctrl_perfctr_reg_pkg.sv + - src/ctrl_unit/cluster_icache_ctrl_perfctr_reg_top.sv + - src/ctrl_unit/cluster_icache_ctrl_perfctr_unit.sv - target: test files: - test/snitch_icache_l0_tb.sv diff --git a/Makefile b/Makefile index 46df7eb..bfee175 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ VLOG_FLAGS += +cover=sbecft CTRL_UNIT_DIR = src/ctrl_unit CTRL_UNIT = $(CTRL_UNIT_DIR)/cluster_icache_ctrl +CTRL_UNIT_PERF = $(CTRL_UNIT_DIR)/cluster_icache_ctrl_perfctr Bender.lock: $(BENDER) update @@ -19,11 +20,14 @@ Bender.lock: $(BENDER) checkout .PHONY: gen_hw -gen_hw: .bender $(CTRL_UNIT)_reg_top.sv +gen_hw: .bender $(CTRL_UNIT)_reg_top.sv $(CTRL_UNIT_PERF)_reg_top.sv $(CTRL_UNIT)_reg_top.sv: .bender $(CTRL_UNIT).hjson python $(shell $(BENDER) path register_interface)/vendor/lowrisc_opentitan/util/regtool.py $(CTRL_UNIT).hjson -t $(CTRL_UNIT_DIR) -r +$(CTRL_UNIT_PERF)_reg_top.sv: .bender $(CTRL_UNIT_PERF).hjson + python $(shell $(BENDER) path register_interface)/vendor/lowrisc_opentitan/util/regtool.py $(CTRL_UNIT_PERF).hjson -t $(CTRL_UNIT_DIR) -r + compile.tcl: .bender Bender.yml Bender.lock $(BENDER) script vsim -t test \ --vlog-arg="$(VLOG_FLAGS)" \ diff --git a/src/ctrl_unit/cluster_icache_ctrl_perfctr.hjson b/src/ctrl_unit/cluster_icache_ctrl_perfctr.hjson new file mode 100644 index 0000000..709e98e --- /dev/null +++ b/src/ctrl_unit/cluster_icache_ctrl_perfctr.hjson @@ -0,0 +1,146 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +{ + name: "cluster_icache_ctrl_perfctr", + clock_primary: "clk_i", + reset_primary: "rst_ni", + bus_interfaces: [ + { protocol: "reg_iface", + direction: "device" + } + ], + + param_list: [ + { name: "NumCores", + desc: "Number of cores", + default: "8" + }, + { name: "NumL0Events", + desc: "Number of L0 events", + default: "5" // Use performance counters for L0 events + }, + { name: "NumL1Events", + desc: "Number of L1 events", + default: "6" + }, + { name: "NumAvailableCounters", + desc: "Number of available counters", + default: "6" // NumL1Events + }, + ], + + regwidth: "32", + registers: [ + { name: "enable", + desc: "", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "0", + name: "enable", + desc: "", + resval: 0x1 + } + ] + }, + { name: "flush", + desc: "Flush all levels of the cache", + swaccess: "rw", + hwaccess: "hrw", + hwqe: "true", + hwext: "true", + fields: [ + { bits: "0", + name: "flush", + desc: "", + resval: 0x0 + } + ] + }, + { name: "flush_l1_only", + desc: "not yet functional", + swaccess: "rw", + hwaccess: "hrw", + hwext: "true", + hwqe: "true", + fields: [ + { bits: "0", + name: "flush", + desc: "", + resval: 0x0 + } + ] + }, + { name: "sel_flush_icache", + desc: "flush specified L0 banks (and currently the complete L1)", + swaccess: "rw", + hwaccess: "hrw", + hwext: "true", + hwqe: "true", + fields: [ + { bits: "NumCores-1:0", + name: "flush", + desc: "", + resval: 0x0000_0000 + } + ] + }, + { name: "clear_counters", + desc: "Clear all performance counters", + swaccess: "rw", + hwaccess: "hrw", + hwqe: "true", + hwext: "true", + fields: [ + { bits: "0", + name: "clear", + desc: "", + resval: 0x0 + } + ] + }, + { name: "enable_counters", + desc: "Enable performance counters", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "0", + name: "enable", + desc: "", + resval: 0x1 + } + ] + }, + { skipto: "0x1C" }, + { name: "enable_prefetch", + desc: "Enable prefetching", + swaccess: "rw", + hwaccess: "hro", + fields: [ + { bits: "0", + name: "enable", + desc: "", + resval: 0x1 + } + ] + }, + { multireg: { + name: "counters", + desc: "Performance counters", + count: "NumAvailableCounters", + cname: "id", + swaccess: "rw0c", + hwaccess: "hrw", + fields: [ + { bits: "31:0", + name: "counter", + desc: "", + resval: 0x0000_0000 + } + ] + } + }, + ], +} diff --git a/src/ctrl_unit/cluster_icache_ctrl_perfctr_reg_pkg.sv b/src/ctrl_unit/cluster_icache_ctrl_perfctr_reg_pkg.sv new file mode 100644 index 0000000..3cb16c0 --- /dev/null +++ b/src/ctrl_unit/cluster_icache_ctrl_perfctr_reg_pkg.sv @@ -0,0 +1,160 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Package auto-generated by `reggen` containing data structure + +package cluster_icache_ctrl_perfctr_reg_pkg; + + // Param list + parameter int NumCores = 8; + parameter int NumL0Events = 5; + parameter int NumL1Events = 6; + parameter int NumAvailableCounters = 6; + + // Address widths within the block + parameter int BlockAw = 6; + + //////////////////////////// + // Typedefs for registers // + //////////////////////////// + + typedef struct packed { + logic q; + } cluster_icache_ctrl_perfctr_reg2hw_enable_reg_t; + + typedef struct packed { + logic q; + logic qe; + } cluster_icache_ctrl_perfctr_reg2hw_flush_reg_t; + + typedef struct packed { + logic q; + logic qe; + } cluster_icache_ctrl_perfctr_reg2hw_flush_l1_only_reg_t; + + typedef struct packed { + logic [7:0] q; + logic qe; + } cluster_icache_ctrl_perfctr_reg2hw_sel_flush_icache_reg_t; + + typedef struct packed { + logic q; + logic qe; + } cluster_icache_ctrl_perfctr_reg2hw_clear_counters_reg_t; + + typedef struct packed { + logic q; + } cluster_icache_ctrl_perfctr_reg2hw_enable_counters_reg_t; + + typedef struct packed { + logic q; + } cluster_icache_ctrl_perfctr_reg2hw_enable_prefetch_reg_t; + + typedef struct packed { + logic [31:0] q; + } cluster_icache_ctrl_perfctr_reg2hw_counters_mreg_t; + + typedef struct packed { + logic d; + } cluster_icache_ctrl_perfctr_hw2reg_flush_reg_t; + + typedef struct packed { + logic d; + } cluster_icache_ctrl_perfctr_hw2reg_flush_l1_only_reg_t; + + typedef struct packed { + logic [7:0] d; + } cluster_icache_ctrl_perfctr_hw2reg_sel_flush_icache_reg_t; + + typedef struct packed { + logic d; + } cluster_icache_ctrl_perfctr_hw2reg_clear_counters_reg_t; + + typedef struct packed { + logic [31:0] d; + logic de; + } cluster_icache_ctrl_perfctr_hw2reg_counters_mreg_t; + + // Register -> HW type + typedef struct packed { + cluster_icache_ctrl_perfctr_reg2hw_enable_reg_t enable; // [209:209] + cluster_icache_ctrl_perfctr_reg2hw_flush_reg_t flush; // [208:207] + cluster_icache_ctrl_perfctr_reg2hw_flush_l1_only_reg_t flush_l1_only; // [206:205] + cluster_icache_ctrl_perfctr_reg2hw_sel_flush_icache_reg_t sel_flush_icache; // [204:196] + cluster_icache_ctrl_perfctr_reg2hw_clear_counters_reg_t clear_counters; // [195:194] + cluster_icache_ctrl_perfctr_reg2hw_enable_counters_reg_t enable_counters; // [193:193] + cluster_icache_ctrl_perfctr_reg2hw_enable_prefetch_reg_t enable_prefetch; // [192:192] + cluster_icache_ctrl_perfctr_reg2hw_counters_mreg_t [5:0] counters; // [191:0] + } cluster_icache_ctrl_perfctr_reg2hw_t; + + // HW -> register type + typedef struct packed { + cluster_icache_ctrl_perfctr_hw2reg_flush_reg_t flush; // [208:208] + cluster_icache_ctrl_perfctr_hw2reg_flush_l1_only_reg_t flush_l1_only; // [207:207] + cluster_icache_ctrl_perfctr_hw2reg_sel_flush_icache_reg_t sel_flush_icache; // [206:199] + cluster_icache_ctrl_perfctr_hw2reg_clear_counters_reg_t clear_counters; // [198:198] + cluster_icache_ctrl_perfctr_hw2reg_counters_mreg_t [5:0] counters; // [197:0] + } cluster_icache_ctrl_perfctr_hw2reg_t; + + // Register offsets + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_PERFCTR_ENABLE_OFFSET = 6'h 0; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_PERFCTR_FLUSH_OFFSET = 6'h 4; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_PERFCTR_FLUSH_L1_ONLY_OFFSET = 6'h 8; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_PERFCTR_SEL_FLUSH_ICACHE_OFFSET = 6'h c; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_PERFCTR_CLEAR_COUNTERS_OFFSET = 6'h 10; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_PERFCTR_ENABLE_COUNTERS_OFFSET = 6'h 14; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_PERFCTR_ENABLE_PREFETCH_OFFSET = 6'h 1c; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_0_OFFSET = 6'h 20; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_1_OFFSET = 6'h 24; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_2_OFFSET = 6'h 28; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_3_OFFSET = 6'h 2c; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_4_OFFSET = 6'h 30; + parameter logic [BlockAw-1:0] CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_5_OFFSET = 6'h 34; + + // Reset values for hwext registers and their fields + parameter logic [0:0] CLUSTER_ICACHE_CTRL_PERFCTR_FLUSH_RESVAL = 1'h 0; + parameter logic [0:0] CLUSTER_ICACHE_CTRL_PERFCTR_FLUSH_FLUSH_RESVAL = 1'h 0; + parameter logic [0:0] CLUSTER_ICACHE_CTRL_PERFCTR_FLUSH_L1_ONLY_RESVAL = 1'h 0; + parameter logic [0:0] CLUSTER_ICACHE_CTRL_PERFCTR_FLUSH_L1_ONLY_FLUSH_RESVAL = 1'h 0; + parameter logic [7:0] CLUSTER_ICACHE_CTRL_PERFCTR_SEL_FLUSH_ICACHE_RESVAL = 8'h 0; + parameter logic [7:0] CLUSTER_ICACHE_CTRL_PERFCTR_SEL_FLUSH_ICACHE_FLUSH_RESVAL = 8'h 0; + parameter logic [0:0] CLUSTER_ICACHE_CTRL_PERFCTR_CLEAR_COUNTERS_RESVAL = 1'h 0; + parameter logic [0:0] CLUSTER_ICACHE_CTRL_PERFCTR_CLEAR_COUNTERS_CLEAR_RESVAL = 1'h 0; + + // Register index + typedef enum int { + CLUSTER_ICACHE_CTRL_PERFCTR_ENABLE, + CLUSTER_ICACHE_CTRL_PERFCTR_FLUSH, + CLUSTER_ICACHE_CTRL_PERFCTR_FLUSH_L1_ONLY, + CLUSTER_ICACHE_CTRL_PERFCTR_SEL_FLUSH_ICACHE, + CLUSTER_ICACHE_CTRL_PERFCTR_CLEAR_COUNTERS, + CLUSTER_ICACHE_CTRL_PERFCTR_ENABLE_COUNTERS, + CLUSTER_ICACHE_CTRL_PERFCTR_ENABLE_PREFETCH, + CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_0, + CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_1, + CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_2, + CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_3, + CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_4, + CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_5 + } cluster_icache_ctrl_perfctr_id_e; + + // Register width information to check illegal writes + parameter logic [3:0] CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT [13] = '{ + 4'b 0001, // index[ 0] CLUSTER_ICACHE_CTRL_PERFCTR_ENABLE + 4'b 0001, // index[ 1] CLUSTER_ICACHE_CTRL_PERFCTR_FLUSH + 4'b 0001, // index[ 2] CLUSTER_ICACHE_CTRL_PERFCTR_FLUSH_L1_ONLY + 4'b 0001, // index[ 3] CLUSTER_ICACHE_CTRL_PERFCTR_SEL_FLUSH_ICACHE + 4'b 0001, // index[ 4] CLUSTER_ICACHE_CTRL_PERFCTR_CLEAR_COUNTERS + 4'b 0001, // index[ 5] CLUSTER_ICACHE_CTRL_PERFCTR_ENABLE_COUNTERS + 4'b 0001, // index[ 6] CLUSTER_ICACHE_CTRL_PERFCTR_ENABLE_PREFETCH + 4'b 1111, // index[ 7] CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_0 + 4'b 1111, // index[ 8] CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_1 + 4'b 1111, // index[ 9] CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_2 + 4'b 1111, // index[10] CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_3 + 4'b 1111, // index[11] CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_4 + 4'b 1111 // index[12] CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_5 + }; + +endpackage + diff --git a/src/ctrl_unit/cluster_icache_ctrl_perfctr_reg_top.sv b/src/ctrl_unit/cluster_icache_ctrl_perfctr_reg_top.sv new file mode 100644 index 0000000..4bbfa58 --- /dev/null +++ b/src/ctrl_unit/cluster_icache_ctrl_perfctr_reg_top.sv @@ -0,0 +1,634 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// Register Top module auto-generated by `reggen` + + +`include "common_cells/assertions.svh" + +module cluster_icache_ctrl_perfctr_reg_top #( + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic, + parameter int AW = 6 +) ( + input logic clk_i, + input logic rst_ni, + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + // To HW + output cluster_icache_ctrl_perfctr_reg_pkg::cluster_icache_ctrl_perfctr_reg2hw_t reg2hw, // Write + input cluster_icache_ctrl_perfctr_reg_pkg::cluster_icache_ctrl_perfctr_hw2reg_t hw2reg, // Read + + + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + + import cluster_icache_ctrl_perfctr_reg_pkg::* ; + + localparam int DW = 32; + localparam int DBW = DW/8; // Byte Width + + // register signals + logic reg_we; + logic reg_re; + logic [BlockAw-1:0] reg_addr; + logic [DW-1:0] reg_wdata; + logic [DBW-1:0] reg_be; + logic [DW-1:0] reg_rdata; + logic reg_error; + + logic addrmiss, wr_err; + + logic [DW-1:0] reg_rdata_next; + + // Below register interface can be changed + reg_req_t reg_intf_req; + reg_rsp_t reg_intf_rsp; + + + assign reg_intf_req = reg_req_i; + assign reg_rsp_o = reg_intf_rsp; + + + assign reg_we = reg_intf_req.valid & reg_intf_req.write; + assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; + assign reg_addr = reg_intf_req.addr[BlockAw-1:0]; + assign reg_wdata = reg_intf_req.wdata; + assign reg_be = reg_intf_req.wstrb; + assign reg_intf_rsp.rdata = reg_rdata; + assign reg_intf_rsp.error = reg_error; + assign reg_intf_rsp.ready = 1'b1; + + assign reg_rdata = reg_rdata_next ; + assign reg_error = (devmode_i & addrmiss) | wr_err; + + + // Define SW related signals + // Format: __{wd|we|qs} + // or _{wd|we|qs} if field == 1 or 0 + logic enable_qs; + logic enable_wd; + logic enable_we; + logic flush_qs; + logic flush_wd; + logic flush_we; + logic flush_re; + logic flush_l1_only_qs; + logic flush_l1_only_wd; + logic flush_l1_only_we; + logic flush_l1_only_re; + logic [7:0] sel_flush_icache_qs; + logic [7:0] sel_flush_icache_wd; + logic sel_flush_icache_we; + logic sel_flush_icache_re; + logic clear_counters_qs; + logic clear_counters_wd; + logic clear_counters_we; + logic clear_counters_re; + logic enable_counters_qs; + logic enable_counters_wd; + logic enable_counters_we; + logic enable_prefetch_qs; + logic enable_prefetch_wd; + logic enable_prefetch_we; + logic [31:0] counters_0_qs; + logic [31:0] counters_0_wd; + logic counters_0_we; + logic [31:0] counters_1_qs; + logic [31:0] counters_1_wd; + logic counters_1_we; + logic [31:0] counters_2_qs; + logic [31:0] counters_2_wd; + logic counters_2_we; + logic [31:0] counters_3_qs; + logic [31:0] counters_3_wd; + logic counters_3_we; + logic [31:0] counters_4_qs; + logic [31:0] counters_4_wd; + logic counters_4_we; + logic [31:0] counters_5_qs; + logic [31:0] counters_5_wd; + logic counters_5_we; + + // Register instances + // R[enable]: V(False) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h1) + ) u_enable ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (enable_we), + .wd (enable_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.enable.q ), + + // to register interface (read) + .qs (enable_qs) + ); + + + // R[flush]: V(True) + + prim_subreg_ext #( + .DW (1) + ) u_flush ( + .re (flush_re), + .we (flush_we), + .wd (flush_wd), + .d (hw2reg.flush.d), + .qre (), + .qe (reg2hw.flush.qe), + .q (reg2hw.flush.q ), + .qs (flush_qs) + ); + + + // R[flush_l1_only]: V(True) + + prim_subreg_ext #( + .DW (1) + ) u_flush_l1_only ( + .re (flush_l1_only_re), + .we (flush_l1_only_we), + .wd (flush_l1_only_wd), + .d (hw2reg.flush_l1_only.d), + .qre (), + .qe (reg2hw.flush_l1_only.qe), + .q (reg2hw.flush_l1_only.q ), + .qs (flush_l1_only_qs) + ); + + + // R[sel_flush_icache]: V(True) + + prim_subreg_ext #( + .DW (8) + ) u_sel_flush_icache ( + .re (sel_flush_icache_re), + .we (sel_flush_icache_we), + .wd (sel_flush_icache_wd), + .d (hw2reg.sel_flush_icache.d), + .qre (), + .qe (reg2hw.sel_flush_icache.qe), + .q (reg2hw.sel_flush_icache.q ), + .qs (sel_flush_icache_qs) + ); + + + // R[clear_counters]: V(True) + + prim_subreg_ext #( + .DW (1) + ) u_clear_counters ( + .re (clear_counters_re), + .we (clear_counters_we), + .wd (clear_counters_wd), + .d (hw2reg.clear_counters.d), + .qre (), + .qe (reg2hw.clear_counters.qe), + .q (reg2hw.clear_counters.q ), + .qs (clear_counters_qs) + ); + + + // R[enable_counters]: V(False) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h1) + ) u_enable_counters ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (enable_counters_we), + .wd (enable_counters_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.enable_counters.q ), + + // to register interface (read) + .qs (enable_counters_qs) + ); + + + // R[enable_prefetch]: V(False) + + prim_subreg #( + .DW (1), + .SWACCESS("RW"), + .RESVAL (1'h1) + ) u_enable_prefetch ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (enable_prefetch_we), + .wd (enable_prefetch_wd), + + // from internal hardware + .de (1'b0), + .d ('0 ), + + // to internal hardware + .qe (), + .q (reg2hw.enable_prefetch.q ), + + // to register interface (read) + .qs (enable_prefetch_qs) + ); + + + + // Subregister 0 of Multireg counters + // R[counters_0]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_0 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_0_we), + .wd (counters_0_wd), + + // from internal hardware + .de (hw2reg.counters[0].de), + .d (hw2reg.counters[0].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[0].q ), + + // to register interface (read) + .qs (counters_0_qs) + ); + + // Subregister 1 of Multireg counters + // R[counters_1]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_1 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_1_we), + .wd (counters_1_wd), + + // from internal hardware + .de (hw2reg.counters[1].de), + .d (hw2reg.counters[1].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[1].q ), + + // to register interface (read) + .qs (counters_1_qs) + ); + + // Subregister 2 of Multireg counters + // R[counters_2]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_2 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_2_we), + .wd (counters_2_wd), + + // from internal hardware + .de (hw2reg.counters[2].de), + .d (hw2reg.counters[2].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[2].q ), + + // to register interface (read) + .qs (counters_2_qs) + ); + + // Subregister 3 of Multireg counters + // R[counters_3]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_3 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_3_we), + .wd (counters_3_wd), + + // from internal hardware + .de (hw2reg.counters[3].de), + .d (hw2reg.counters[3].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[3].q ), + + // to register interface (read) + .qs (counters_3_qs) + ); + + // Subregister 4 of Multireg counters + // R[counters_4]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_4 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_4_we), + .wd (counters_4_wd), + + // from internal hardware + .de (hw2reg.counters[4].de), + .d (hw2reg.counters[4].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[4].q ), + + // to register interface (read) + .qs (counters_4_qs) + ); + + // Subregister 5 of Multireg counters + // R[counters_5]: V(False) + + prim_subreg #( + .DW (32), + .SWACCESS("W0C"), + .RESVAL (32'h0) + ) u_counters_5 ( + .clk_i (clk_i ), + .rst_ni (rst_ni ), + + // from register interface + .we (counters_5_we), + .wd (counters_5_wd), + + // from internal hardware + .de (hw2reg.counters[5].de), + .d (hw2reg.counters[5].d ), + + // to internal hardware + .qe (), + .q (reg2hw.counters[5].q ), + + // to register interface (read) + .qs (counters_5_qs) + ); + + + + + logic [12:0] addr_hit; + always_comb begin + addr_hit = '0; + addr_hit[ 0] = (reg_addr == CLUSTER_ICACHE_CTRL_PERFCTR_ENABLE_OFFSET); + addr_hit[ 1] = (reg_addr == CLUSTER_ICACHE_CTRL_PERFCTR_FLUSH_OFFSET); + addr_hit[ 2] = (reg_addr == CLUSTER_ICACHE_CTRL_PERFCTR_FLUSH_L1_ONLY_OFFSET); + addr_hit[ 3] = (reg_addr == CLUSTER_ICACHE_CTRL_PERFCTR_SEL_FLUSH_ICACHE_OFFSET); + addr_hit[ 4] = (reg_addr == CLUSTER_ICACHE_CTRL_PERFCTR_CLEAR_COUNTERS_OFFSET); + addr_hit[ 5] = (reg_addr == CLUSTER_ICACHE_CTRL_PERFCTR_ENABLE_COUNTERS_OFFSET); + addr_hit[ 6] = (reg_addr == CLUSTER_ICACHE_CTRL_PERFCTR_ENABLE_PREFETCH_OFFSET); + addr_hit[ 7] = (reg_addr == CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_0_OFFSET); + addr_hit[ 8] = (reg_addr == CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_1_OFFSET); + addr_hit[ 9] = (reg_addr == CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_2_OFFSET); + addr_hit[10] = (reg_addr == CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_3_OFFSET); + addr_hit[11] = (reg_addr == CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_4_OFFSET); + addr_hit[12] = (reg_addr == CLUSTER_ICACHE_CTRL_PERFCTR_COUNTERS_5_OFFSET); + end + + assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; + + // Check sub-word write is permitted + always_comb begin + wr_err = (reg_we & + ((addr_hit[ 0] & (|(CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT[ 0] & ~reg_be))) | + (addr_hit[ 1] & (|(CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT[ 1] & ~reg_be))) | + (addr_hit[ 2] & (|(CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT[ 2] & ~reg_be))) | + (addr_hit[ 3] & (|(CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT[ 3] & ~reg_be))) | + (addr_hit[ 4] & (|(CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT[ 4] & ~reg_be))) | + (addr_hit[ 5] & (|(CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT[ 5] & ~reg_be))) | + (addr_hit[ 6] & (|(CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT[ 6] & ~reg_be))) | + (addr_hit[ 7] & (|(CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT[ 7] & ~reg_be))) | + (addr_hit[ 8] & (|(CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT[ 8] & ~reg_be))) | + (addr_hit[ 9] & (|(CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT[ 9] & ~reg_be))) | + (addr_hit[10] & (|(CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT[10] & ~reg_be))) | + (addr_hit[11] & (|(CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT[11] & ~reg_be))) | + (addr_hit[12] & (|(CLUSTER_ICACHE_CTRL_PERFCTR_PERMIT[12] & ~reg_be))))); + end + + assign enable_we = addr_hit[0] & reg_we & !reg_error; + assign enable_wd = reg_wdata[0]; + + assign flush_we = addr_hit[1] & reg_we & !reg_error; + assign flush_wd = reg_wdata[0]; + assign flush_re = addr_hit[1] & reg_re & !reg_error; + + assign flush_l1_only_we = addr_hit[2] & reg_we & !reg_error; + assign flush_l1_only_wd = reg_wdata[0]; + assign flush_l1_only_re = addr_hit[2] & reg_re & !reg_error; + + assign sel_flush_icache_we = addr_hit[3] & reg_we & !reg_error; + assign sel_flush_icache_wd = reg_wdata[7:0]; + assign sel_flush_icache_re = addr_hit[3] & reg_re & !reg_error; + + assign clear_counters_we = addr_hit[4] & reg_we & !reg_error; + assign clear_counters_wd = reg_wdata[0]; + assign clear_counters_re = addr_hit[4] & reg_re & !reg_error; + + assign enable_counters_we = addr_hit[5] & reg_we & !reg_error; + assign enable_counters_wd = reg_wdata[0]; + + assign enable_prefetch_we = addr_hit[6] & reg_we & !reg_error; + assign enable_prefetch_wd = reg_wdata[0]; + + assign counters_0_we = addr_hit[7] & reg_we & !reg_error; + assign counters_0_wd = reg_wdata[31:0]; + + assign counters_1_we = addr_hit[8] & reg_we & !reg_error; + assign counters_1_wd = reg_wdata[31:0]; + + assign counters_2_we = addr_hit[9] & reg_we & !reg_error; + assign counters_2_wd = reg_wdata[31:0]; + + assign counters_3_we = addr_hit[10] & reg_we & !reg_error; + assign counters_3_wd = reg_wdata[31:0]; + + assign counters_4_we = addr_hit[11] & reg_we & !reg_error; + assign counters_4_wd = reg_wdata[31:0]; + + assign counters_5_we = addr_hit[12] & reg_we & !reg_error; + assign counters_5_wd = reg_wdata[31:0]; + + // Read data return + always_comb begin + reg_rdata_next = '0; + unique case (1'b1) + addr_hit[0]: begin + reg_rdata_next[0] = enable_qs; + end + + addr_hit[1]: begin + reg_rdata_next[0] = flush_qs; + end + + addr_hit[2]: begin + reg_rdata_next[0] = flush_l1_only_qs; + end + + addr_hit[3]: begin + reg_rdata_next[7:0] = sel_flush_icache_qs; + end + + addr_hit[4]: begin + reg_rdata_next[0] = clear_counters_qs; + end + + addr_hit[5]: begin + reg_rdata_next[0] = enable_counters_qs; + end + + addr_hit[6]: begin + reg_rdata_next[0] = enable_prefetch_qs; + end + + addr_hit[7]: begin + reg_rdata_next[31:0] = counters_0_qs; + end + + addr_hit[8]: begin + reg_rdata_next[31:0] = counters_1_qs; + end + + addr_hit[9]: begin + reg_rdata_next[31:0] = counters_2_qs; + end + + addr_hit[10]: begin + reg_rdata_next[31:0] = counters_3_qs; + end + + addr_hit[11]: begin + reg_rdata_next[31:0] = counters_4_qs; + end + + addr_hit[12]: begin + reg_rdata_next[31:0] = counters_5_qs; + end + + default: begin + reg_rdata_next = '1; + end + endcase + end + + // Unused signal tieoff + + // wdata / byte enable are not always fully used + // add a blanket unused statement to handle lint waivers + logic unused_wdata; + logic unused_be; + assign unused_wdata = ^reg_wdata; + assign unused_be = ^reg_be; + + // Assertions for Register Interface + `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) + +endmodule + +module cluster_icache_ctrl_perfctr_reg_top_intf +#( + parameter int AW = 6, + localparam int DW = 32 +) ( + input logic clk_i, + input logic rst_ni, + REG_BUS.in regbus_slave, + // To HW + output cluster_icache_ctrl_perfctr_reg_pkg::cluster_icache_ctrl_perfctr_reg2hw_t reg2hw, // Write + input cluster_icache_ctrl_perfctr_reg_pkg::cluster_icache_ctrl_perfctr_hw2reg_t hw2reg, // Read + // Config + input devmode_i // If 1, explicit error return for unmapped register access +); + localparam int unsigned STRB_WIDTH = DW/8; + +`include "register_interface/typedef.svh" +`include "register_interface/assign.svh" + + // Define structs for reg_bus + typedef logic [AW-1:0] addr_t; + typedef logic [DW-1:0] data_t; + typedef logic [STRB_WIDTH-1:0] strb_t; + `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t) + + reg_bus_req_t s_reg_req; + reg_bus_rsp_t s_reg_rsp; + + // Assign SV interface to structs + `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave) + `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp) + + + + cluster_icache_ctrl_perfctr_reg_top #( + .reg_req_t(reg_bus_req_t), + .reg_rsp_t(reg_bus_rsp_t), + .AW(AW) + ) i_regs ( + .clk_i, + .rst_ni, + .reg_req_i(s_reg_req), + .reg_rsp_o(s_reg_rsp), + .reg2hw, // Write + .hw2reg, // Read + .devmode_i + ); + +endmodule + + diff --git a/src/ctrl_unit/cluster_icache_ctrl_perfctr_unit.sv b/src/ctrl_unit/cluster_icache_ctrl_perfctr_unit.sv new file mode 100644 index 0000000..cf73473 --- /dev/null +++ b/src/ctrl_unit/cluster_icache_ctrl_perfctr_unit.sv @@ -0,0 +1,103 @@ +// Copyright 2024 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Michael Rogenmoser + +module cluster_icache_ctrl_perfctr_unit import snitch_icache_pkg::*; #( + parameter int unsigned NR_FETCH_PORTS = -1, + parameter type reg_req_t = logic, + parameter type reg_rsp_t = logic +) ( + input logic clk_i, + input logic rst_ni, + + input reg_req_t reg_req_i, + output reg_rsp_t reg_rsp_o, + + output logic enable_prefetching_o, + output logic [NR_FETCH_PORTS-1:0] flush_valid_o, + input logic [NR_FETCH_PORTS-1:0] flush_ready_i, + + // input icache_l0_events_t [NR_FETCH_PORTS-1:0] l0_events_i, + input icache_l1_events_t l1_events_i +); + + import cluster_icache_ctrl_perfctr_reg_pkg::*; + + initial begin + // assert(NumL0Events == $bits(icache_l0_events_t)); + assert(NumL1Events == $bits(icache_l1_events_t)); + assert(NumAvailableCounters >= NumL1Events); + assert(NR_FETCH_PORTS <= NumCores); + end + + cluster_icache_ctrl_perfctr_reg2hw_t reg2hw; + cluster_icache_ctrl_perfctr_hw2reg_t hw2reg; + + cluster_icache_ctrl_perfctr_reg_top #( + .reg_req_t(reg_req_t), + .reg_rsp_t(reg_rsp_t) + ) i_regs ( + .clk_i, + .rst_ni, + + .reg_req_i, + .reg_rsp_o, + + .reg2hw (reg2hw), + .hw2reg (hw2reg), + .devmode_i (1'b0) + ); + + cluster_icache_ctrl_perfctr_hw2reg_counters_mreg_t [NumAvailableCounters-1:0] counters_reg; + + always_comb begin : gen_counters_reg + // set up defaults - increment but not active + for (int unsigned i = 0; i < NumAvailableCounters; i++) begin + counters_reg[i].d = reg2hw.counters[i].q + 1; + counters_reg[i].de = '0; + end + + // Activate increment counters + counters_reg[0].de = reg2hw.enable_counters.q & l1_events_i.l1_miss; + counters_reg[1].de = reg2hw.enable_counters.q & l1_events_i.l1_hit; + counters_reg[2].de = reg2hw.enable_counters.q & l1_events_i.l1_stall; + counters_reg[3].de = reg2hw.enable_counters.q & l1_events_i.l1_handler_stall; + counters_reg[5].de = reg2hw.enable_counters.q & l1_events_i.l1_tag_parity_error; + counters_reg[6].de = reg2hw.enable_counters.q & l1_events_i.l1_data_parity_error; + + // for (int unsigned i = 0; i < NR_FETCH_PORTS; i++) begin + // counters_reg[NumL1Events + i*NumL0Events + 0].de = reg2hw.enable_counters.q & + // l0_events_i[i].l0_miss; + // counters_reg[NumL1Events + i*NumL0Events + 1].de = reg2hw.enable_counters.q & + // l0_events_i[i].l0_hit; + // counters_reg[NumL1Events + i*NumL0Events + 2].de = reg2hw.enable_counters.q & + // l0_events_i[i].l0_prefetch; + // counters_reg[NumL1Events + i*NumL0Events + 3].de = reg2hw.enable_counters.q & + // l0_events_i[i].l0_double_hit; + // counters_reg[NumL1Events + i*NumL0Events + 4].de = reg2hw.enable_counters.q & + // l0_events_i[i].l0_stall; + // end + + // Clear on global clear signal + if (reg2hw.clear_counters.q) begin + for (int unsigned i = 0; i < NumAvailableCounters; i++) begin + counters_reg[i].d = '0; + counters_reg[i].de = '1; + end + end + end + + assign enable_prefetching_o = reg2hw.enable_prefetch.q; + assign flush_valid_o = ({NR_FETCH_PORTS{reg2hw.flush.q}} & {NR_FETCH_PORTS{reg2hw.flush.qe}}) | + (reg2hw.sel_flush_icache.q[NR_FETCH_PORTS-1:0] & + {NR_FETCH_PORTS{reg2hw.sel_flush_icache.qe}}); + + assign hw2reg.flush.d = ~|flush_ready_i; + assign hw2reg.flush_l1_only.d = '0; + assign hw2reg.sel_flush_icache.d = ~flush_ready_i; + assign hw2reg.clear_counters.d = '0; + assign hw2reg.counters = counters_reg; + +endmodule From 672d2d506073020080a5d20e9e27a458249927c1 Mon Sep 17 00:00:00 2001 From: Yvan Tortorella Date: Sun, 9 Jun 2024 14:57:46 +0200 Subject: [PATCH 17/17] Allow reset connection in SCM if FPGA target is exported. --- src/snitch_icache_lookup_serial.sv | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/snitch_icache_lookup_serial.sv b/src/snitch_icache_lookup_serial.sv index 31314c6..bce7747 100644 --- a/src/snitch_icache_lookup_serial.sv +++ b/src/snitch_icache_lookup_serial.sv @@ -199,6 +199,9 @@ module snitch_icache_lookup_serial import snitch_icache_pkg::*; #( .DATA_WIDTH (CFG.TAG_WIDTH+2+TagParity) ) i_tag ( .clk ( clk_i ), + `ifdef TARGET_SCM_USE_FPGA_SCM + .rst_n ( rst_ni ), + `endif .ReadEnable ( tag_enable[i] && !tag_write ), .ReadAddr ( tag_addr ), .ReadData ( tag_rdata[i] ),