From 5eb17afc18f106f8b784e9406c856993ef4704a5 Mon Sep 17 00:00:00 2001 From: Michael Rogenmoser Date: Mon, 18 Mar 2024 23:23:48 +0100 Subject: [PATCH] treewide: Replace `snitch_icache` with `cluster_icache` dependency (#112) --- .github/CODEOWNERS | 1 - .gitlab-ci.yml | 1 - Bender.yml | 18 +- hw/snitch_cluster/src/snitch_hive.sv | 5 +- hw/snitch_icache/.gitignore | 6 - hw/snitch_icache/doc/index.md | 14 - hw/snitch_icache/src/snitch_icache.sv | 690 ------------------ hw/snitch_icache/src/snitch_icache_handler.sv | 344 --------- hw/snitch_icache/src/snitch_icache_l0.sv | 413 ----------- hw/snitch_icache/src/snitch_icache_lfsr.sv | 121 --- hw/snitch_icache/src/snitch_icache_lookup.sv | 257 ------- hw/snitch_icache/src/snitch_icache_pkg.sv | 47 -- hw/snitch_icache/src/snitch_icache_refill.sv | 140 ---- hw/snitch_icache/test/snitch_icache_l0_tb.sv | 380 ---------- hw/snitch_icache/util/compile.sh | 20 - hw/snitch_icache/util/run_vsim.sh | 19 - 16 files changed, 5 insertions(+), 2471 deletions(-) delete mode 100644 hw/snitch_icache/.gitignore delete mode 100644 hw/snitch_icache/doc/index.md delete mode 100644 hw/snitch_icache/src/snitch_icache.sv delete mode 100644 hw/snitch_icache/src/snitch_icache_handler.sv delete mode 100644 hw/snitch_icache/src/snitch_icache_l0.sv delete mode 100644 hw/snitch_icache/src/snitch_icache_lfsr.sv delete mode 100644 hw/snitch_icache/src/snitch_icache_lookup.sv delete mode 100644 hw/snitch_icache/src/snitch_icache_pkg.sv delete mode 100644 hw/snitch_icache/src/snitch_icache_refill.sv delete mode 100644 hw/snitch_icache/test/snitch_icache_l0_tb.sv delete mode 100755 hw/snitch_icache/util/compile.sh delete mode 100755 hw/snitch_icache/util/run_vsim.sh diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 26e4ee4ff..70ea7fe02 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -6,6 +6,5 @@ hw/snitch_cluster @paulsc96 @lucabertaccini hw/snitch_dma @paulsc96 @thommythomaso -hw/snitch_icache @paulsc96 @SamuelRiedel sw @colluca @fischeti @viv-eth diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 075f7d4b0..122763b8e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -68,7 +68,6 @@ snitch-ip-tests: - IP: - mem_interface - snitch_cluster - - snitch_icache - tcdm_interface script: - cd hw/$IP diff --git a/Bender.yml b/Bender.yml index 84dad47e8..61539826f 100644 --- a/Bender.yml +++ b/Bender.yml @@ -26,6 +26,7 @@ dependencies: register_interface: { git: https://github.com/pulp-platform/register_interface, version: 0.4.2 } tech_cells_generic: { git: https://github.com/pulp-platform/tech_cells_generic, version: 0.2.11 } riscv-dbg: { git: https://github.com/pulp-platform/riscv-dbg, version: 0.8.0 } + cluster_icache: { git: https://github.com/pulp-platform/cluster_icache.git, version: 0.1.0 } vendor_package: - name: musl @@ -197,23 +198,6 @@ sources: # Level 2: - hw/snitch_dma/src/axi_dma_tc_snitch_fe.sv - # snitch_icache - - files: - # Level 0 - - hw/snitch_icache/src/snitch_icache_pkg.sv - # Level 1 - - hw/snitch_icache/src/snitch_icache_l0.sv - - hw/snitch_icache/src/snitch_icache_refill.sv - - hw/snitch_icache/src/snitch_icache_lfsr.sv - - hw/snitch_icache/src/snitch_icache_lookup.sv - # Level 2 - - hw/snitch_icache/src/snitch_icache_handler.sv - # Level 3 - - hw/snitch_icache/src/snitch_icache.sv - - target: test - files: - - hw/snitch_icache/test/snitch_icache_l0_tb.sv - # snitch_ipu - files: # Level 0 diff --git a/hw/snitch_cluster/src/snitch_hive.sv b/hw/snitch_cluster/src/snitch_hive.sv index c9f284769..fbb5f6910 100644 --- a/hw/snitch_cluster/src/snitch_hive.sv +++ b/hw/snitch_cluster/src/snitch_hive.sv @@ -92,7 +92,10 @@ module snitch_hive #( .FETCH_DW ( 32 ), .FILL_AW ( AddrWidth ), .FILL_DW ( WideDataWidth ), - .EARLY_LATCH ( 0 ), + .SERIAL_LOOKUP ( 0 ), + .L1_TAG_SCM ( 0 ), + .NUM_AXI_OUTSTANDING( 2 ), + .EARLY_LATCH ( 0 ), .L0_EARLY_TAG_WIDTH ( snitch_pkg::PageShift - $clog2(ICacheLineWidth/8) ), .ISO_CROSSING ( IsoCrossing ), .sram_cfg_tag_t ( sram_cfg_t ), diff --git a/hw/snitch_icache/.gitignore b/hw/snitch_icache/.gitignore deleted file mode 100644 index 640d5abdb..000000000 --- a/hw/snitch_icache/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -compile.tcl -transcript -*.log -*.lock -work -Bender.lock diff --git a/hw/snitch_icache/doc/index.md b/hw/snitch_icache/doc/index.md deleted file mode 100644 index fd759a77d..000000000 --- a/hw/snitch_icache/doc/index.md +++ /dev/null @@ -1,14 +0,0 @@ -# Snitch Instruction Cache - -This folder contains components for the Snitch instruction cache. The -instruction cache consists of a private L0 cache, usually made out of latches or -flip-flops. The L0 cache is small is used to serve requests in the same cycle as -it has been requested (the L0 sits in the core's only pipeline stage). - -## Testbench - -- The L0 cache used in Snitch: Core instruction requests are randomly generated - (except for branches and jumps which are taken). Refill (cache lines) are - randomly generated making sure that instructions are RISC-V aligned (end in - `2'b11`) and sometimes inferring ctrl flow changes. Requests are changing - periodically to avoid infinite looping. diff --git a/hw/snitch_icache/src/snitch_icache.sv b/hw/snitch_icache/src/snitch_icache.sv deleted file mode 100644 index b0b1d7421..000000000 --- a/hw/snitch_icache/src/snitch_icache.sv +++ /dev/null @@ -1,690 +0,0 @@ -// Copyright 2020 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - -// Fabian Schuiki -// Florian Zaruba - -`include "common_cells/registers.svh" - -module snitch_icache #( - /// Number of request (fetch) ports - parameter int NR_FETCH_PORTS = -1, - /// L0 Cache Line Count - parameter int L0_LINE_COUNT = -1, - /// Cache Line Width - 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 FETCH_AW = -1, - /// Fetch interface data width. Power of two; >= 8. - parameter int FETCH_DW = -1, - /// Fill interface address width. Same as FETCH_AW; >= 1. - parameter int FILL_AW = -1, - /// Fill interface data width. Power of two; >= 8. - parameter int FILL_DW = -1, - /// This reduces area impact at the cost of - /// increased hassle of having latches in - /// the design. - /// i_snitch_icache/gen_prefetcher*i_snitch_icache_l0/data*/Q - parameter bit EARLY_LATCH = 0, - /// Tag width of the data determining logic, this can reduce the - /// the critical path into the L0 cache when small. The trade-off - /// is a higher miss-rate in case the smaller tag matches more - /// tags. The tag must be smaller than the necessary L0 tag. - /// If configured to `-1` the entire tag is used, effectively - /// disabling this feature. - parameter int L0_EARLY_TAG_WIDTH = -1, - /// Operate L0 cache in slower clock-domain - parameter bit ISO_CROSSING = 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 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 [NR_FETCH_PORTS-1:0] flush_valid_i, - output logic [NR_FETCH_PORTS-1:0] flush_ready_o, - - input logic [NR_FETCH_PORTS-1:0][FETCH_AW-1:0] inst_addr_i, - output logic [NR_FETCH_PORTS-1:0][FETCH_DW-1:0] inst_data_o, - input logic [NR_FETCH_PORTS-1:0] inst_cacheable_i, - input logic [NR_FETCH_PORTS-1:0] inst_valid_i, - output logic [NR_FETCH_PORTS-1:0] inst_ready_o, - output logic [NR_FETCH_PORTS-1:0] inst_error_o, - - input sram_cfg_data_t sram_cfg_data_i, - input sram_cfg_tag_t sram_cfg_tag_i, - - output axi_req_t axi_req_o, - input axi_rsp_t axi_rsp_i -); - - // Bundle the parameters up into a proper configuration struct that we can - // pass to submodules. - localparam int PendingCount = 2; - localparam snitch_icache_pkg::config_t CFG = '{ - NR_FETCH_PORTS: NR_FETCH_PORTS, - LINE_WIDTH: LINE_WIDTH, - LINE_COUNT: LINE_COUNT, - L0_LINE_COUNT: L0_LINE_COUNT, - SET_COUNT: SET_COUNT, - PENDING_COUNT: PendingCount, - FETCH_AW: FETCH_AW, - FETCH_DW: FETCH_DW, - FILL_AW: FILL_AW, - FILL_DW: FILL_DW, - EARLY_LATCH: EARLY_LATCH, - BUFFER_LOOKUP: 0, - GUARANTEE_ORDERING: 0, - - FETCH_ALIGN: $clog2(FETCH_DW/8), - FILL_ALIGN: $clog2(FILL_DW/8), - LINE_ALIGN: $clog2(LINE_WIDTH/8), - COUNT_ALIGN: $clog2(LINE_COUNT), - SET_ALIGN: $clog2(SET_COUNT), - TAG_WIDTH: FETCH_AW - $clog2(LINE_WIDTH/8) - $clog2(LINE_COUNT) + 1, - 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, - PENDING_IW: $clog2(PendingCount) - }; - - // pragma translate_off - `ifndef VERILATOR - // Check invariants. - initial begin - assert(L0_LINE_COUNT > 0); - assert(LINE_WIDTH > 0); - assert(LINE_COUNT > 1); - assert(SET_COUNT >= 2) else $warning("Only >= 2 sets are supported"); - assert(FETCH_AW > 0); - assert(FETCH_DW > 0); - assert(FILL_AW > 0); - assert(FILL_DW > 0); - 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); - assert(2**$clog2(LINE_COUNT) == LINE_COUNT) - else $fatal(1, "Cache LINE_COUNT %0d is not a power of two", LINE_COUNT); - // NOTE(fschuiki): I think the following is not needed - // assert(2**$clog2(SET_COUNT) == SET_COUNT) else $fatal(1, "Cache SET_COUNT %0d is not a power of two", SET_COUNT); - assert(2**$clog2(FETCH_DW) == FETCH_DW) - else $fatal(1, "Cache FETCH_DW %0d is not a power of two", FETCH_DW); - assert(2**$clog2(FILL_DW) == FILL_DW) - else $fatal(1, "Cache FILL_DW %0d is not a power of two", FILL_DW); - end - `endif - // pragma translate_on - - // Instantiate the optional early cache, or bypass it. - logic [NR_FETCH_PORTS-1:0][FETCH_AW-1:0] early_addr; - logic [NR_FETCH_PORTS-1:0][LINE_WIDTH-1:0] early_data; - logic [NR_FETCH_PORTS-1:0] early_valid; - logic [NR_FETCH_PORTS-1:0] early_ready; - logic [NR_FETCH_PORTS-1:0] early_error; - - // The prefetch module is responsible for taking the 1-channel valid/ready - // transaction from the early cache and translate it into a 2-channel - // transaction. Once the actual incoming request has been accepted on the - // `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; - } prefetch_req_t; - - typedef struct packed { - logic [CFG.LINE_WIDTH-1:0] data; - logic error; - logic [CFG.ID_WIDTH_RESP-1:0] id; - } prefetch_resp_t; - - prefetch_req_t [NR_FETCH_PORTS-1:0] prefetch_req ; - logic [NR_FETCH_PORTS-1:0] prefetch_req_valid ; - logic [NR_FETCH_PORTS-1:0] prefetch_req_ready ; - - prefetch_req_t prefetch_lookup_req ; - logic prefetch_lookup_req_valid ; - logic prefetch_lookup_req_ready ; - - prefetch_resp_t [NR_FETCH_PORTS-1:0] prefetch_rsp ; - logic [NR_FETCH_PORTS-1:0] prefetch_rsp_valid ; - logic [NR_FETCH_PORTS-1:0] prefetch_rsp_ready ; - - prefetch_resp_t prefetch_lookup_rsp ; - logic prefetch_lookup_rsp_valid ; - logic prefetch_lookup_rsp_ready ; - - typedef struct packed { - logic [CFG.FETCH_AW-1:0] addr; - logic [CFG.PENDING_IW-1:0] id; - logic bypass; - } miss_refill_req_t; - miss_refill_req_t handler_req, bypass_req, bypass_req_q, refill_req; - logic handler_req_valid, bypass_req_valid, bypass_req_valid_q, refill_req_valid; - logic handler_req_ready, bypass_req_ready, bypass_req_ready_q, refill_req_ready; - - typedef struct packed { - logic [CFG.LINE_WIDTH-1:0] data; - logic error; - logic [CFG.PENDING_IW-1:0] id; - logic bypass; - } miss_refill_rsp_t; - miss_refill_rsp_t handler_rsp, bypass_rsp, bypass_rsp_q, refill_rsp; - logic handler_rsp_valid, bypass_rsp_valid, bypass_rsp_valid_q, refill_rsp_valid; - logic handler_rsp_ready, bypass_rsp_ready, bypass_rsp_ready_q, refill_rsp_ready; - - logic [NR_FETCH_PORTS-1:0][FETCH_DW-1:0] bypass_data; - logic [NR_FETCH_PORTS-1:0] bypass_error; - logic [NR_FETCH_PORTS-1:0] bypass_valid; - logic [NR_FETCH_PORTS-1:0] bypass_ready; - logic [NR_FETCH_PORTS-1:0][FETCH_AW-1:0] bypass_addr; - - // logic [NR_FETCH_PORTS-1:0] - logic [NR_FETCH_PORTS-1:0] in_cache_valid, in_bypass_valid; - logic [NR_FETCH_PORTS-1:0] in_cache_ready, in_bypass_ready; - logic [NR_FETCH_PORTS-1:0] [FETCH_DW-1:0] in_cache_data, in_bypass_data; - logic [NR_FETCH_PORTS-1:0] in_cache_error, in_bypass_error; - for (genvar i = 0; i < NR_FETCH_PORTS; i++) begin : gen_prefetcher - prefetch_req_t local_prefetch_req; - logic local_prefetch_req_valid; - logic local_prefetch_req_ready; - prefetch_resp_t local_prefetch_rsp; - logic local_prefetch_rsp_valid; - logic local_prefetch_rsp_ready; - - assign in_cache_valid[i] = inst_cacheable_i[i] & inst_valid_i[i]; - assign in_bypass_valid[i] = ~inst_cacheable_i[i] & inst_valid_i[i]; - assign inst_ready_o[i] = (inst_cacheable_i[i] & in_cache_ready [i]) - | (~inst_cacheable_i[i] & in_bypass_ready [i]); - // multiplex results - assign {inst_error_o[i], inst_data_o[i]} = - ({($bits(in_cache_data[i])+1){inst_cacheable_i[i]}} - & {in_cache_error [i], in_cache_data[i]}) - | (~{($bits(in_cache_data[i])+1){inst_cacheable_i[i]}} - & {in_bypass_error[i], in_bypass_data[i]}); - - snitch_icache_l0 #( - .CFG ( CFG ), - .L0_ID ( i ) - ) i_snitch_icache_l0 ( - .clk_i ( clk_d2_i ), - .rst_ni, - .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 ), - .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 ) - ); - - isochronous_spill_register #( - .T ( prefetch_req_t ), - .Bypass ( !ISO_CROSSING ) - ) i_spill_register_prefetch_req ( - .src_clk_i ( clk_d2_i ), - .src_rst_ni ( rst_ni ), - .src_valid_i ( local_prefetch_req_valid ), - .src_ready_o ( local_prefetch_req_ready ), - .src_data_i ( local_prefetch_req ), - .dst_clk_i ( clk_i ), - .dst_rst_ni ( rst_ni ), - .dst_valid_o ( prefetch_req_valid [i] ), - .dst_ready_i ( prefetch_req_ready [i] ), - .dst_data_o ( prefetch_req [i] ) - ); - - isochronous_spill_register #( - .T ( prefetch_resp_t ), - .Bypass ( !ISO_CROSSING ) - ) i_spill_register_prefetch_resp ( - .src_clk_i ( clk_i ), - .src_rst_ni ( rst_ni ), - .src_valid_i ( prefetch_rsp_valid [i] ), - .src_ready_o ( prefetch_rsp_ready [i] ), - .src_data_i ( prefetch_rsp [i] ), - .dst_clk_i ( clk_d2_i ), - .dst_rst_ni ( rst_ni ), - .dst_valid_o ( local_prefetch_rsp_valid ), - .dst_ready_i ( local_prefetch_rsp_ready ), - .dst_data_o ( local_prefetch_rsp ) - ); - - end - - l0_to_bypass #( - .CFG ( CFG ) - ) i_l0_to_bypass ( - .clk_i ( clk_d2_i ), - .rst_ni, - - .in_valid_i ( in_bypass_valid ), - .in_ready_o ( in_bypass_ready ), - .in_addr_i ( inst_addr_i ), - .in_data_o ( in_bypass_data ), - .in_error_o ( in_bypass_error ), - - .refill_req_addr_o ( bypass_req.addr ), - .refill_req_bypass_o ( bypass_req.bypass ), - .refill_req_valid_o ( bypass_req_valid ), - .refill_req_ready_i ( bypass_req_ready ), - - .refill_rsp_data_i ( bypass_rsp_q.data ), - .refill_rsp_error_i ( bypass_rsp_q.error ), - .refill_rsp_valid_i ( bypass_rsp_valid_q ), - .refill_rsp_ready_o ( bypass_rsp_ready_q ) - ); - - assign bypass_req.id = '0; - - isochronous_spill_register #( - .T ( miss_refill_req_t ), - .Bypass ( !ISO_CROSSING ) - ) i_spill_register_bypass_req ( - .src_clk_i ( clk_d2_i ), - .src_rst_ni ( rst_ni ), - .src_valid_i ( bypass_req_valid ), - .src_ready_o ( bypass_req_ready ), - .src_data_i ( bypass_req ), - .dst_clk_i ( clk_i ), - .dst_rst_ni ( rst_ni ), - .dst_valid_o ( bypass_req_valid_q ), - .dst_ready_i ( bypass_req_ready_q ), - .dst_data_o ( bypass_req_q ) - ); - - isochronous_spill_register #( - .T ( miss_refill_rsp_t ), - .Bypass ( !ISO_CROSSING ) - ) i_spill_register_bypass_resp ( - .src_clk_i ( clk_i ), - .src_rst_ni ( rst_ni ), - .src_valid_i ( bypass_rsp_valid ), - .src_ready_o ( bypass_rsp_ready ), - .src_data_i ( bypass_rsp ), - .dst_clk_i ( clk_d2_i ), - .dst_rst_ni ( rst_ni ), - .dst_valid_o ( bypass_rsp_valid_q ), - .dst_ready_i ( bypass_rsp_ready_q ), - .dst_data_o ( bypass_rsp_q ) - ); - - /// Arbitrate cache port - // 1. Request Side - stream_arbiter #( - .DATA_T ( prefetch_req_t ), - .N_INP ( NR_FETCH_PORTS ) - ) i_stream_arbiter ( - .clk_i, - .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 ), - .oup_valid_o ( prefetch_lookup_req_valid ), - .oup_ready_i ( prefetch_lookup_req_ready ) - ); - - // 2. Response Side - // This breaks if the pre-fetcher would not alway be ready - // which is the case for the moment - for (genvar i = 0; i < NR_FETCH_PORTS; i++) begin : gen_resp - assign prefetch_rsp[i] = prefetch_lookup_rsp; - // check if one of the ID bits is set - assign prefetch_rsp_valid[i] = - ((|((prefetch_rsp[i].id >> 2*i) & 2'b11)) & prefetch_lookup_rsp_valid); - end - assign prefetch_lookup_rsp_ready = |prefetch_rsp_ready; - - /// 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 flush_valid, flush_ready; - logic flush_valid_lookup, flush_ready_lookup; - - assign flush_ready_o = {CFG.NR_FETCH_PORTS{flush_ready}}; - assign flush_valid = |flush_valid_i; - - // We need to propagate the handshake into the other - // clock domain in case we operate w/ different clocks. - if (ISO_CROSSING) begin : gen_flush_crossing - isochronous_4phase_handshake - i_isochronous_4phase_handshake ( - .src_clk_i ( clk_d2_i ), - .src_rst_ni ( rst_ni ), - .src_valid_i ( flush_valid ), - .src_ready_o ( flush_ready ), - .dst_clk_i ( clk_i ), - .dst_rst_ni ( rst_ni ), - .dst_valid_o ( flush_valid_lookup ), - .dst_ready_i ( flush_ready_lookup ) - ); - end else begin : gen_no_flush_crossing - assign flush_valid_lookup = flush_valid; - assign flush_ready = flush_ready_lookup; - end - - snitch_icache_lookup #( - .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 ), - - .sram_cfg_tag_i, - .sram_cfg_data_i - ); - - // The miss handler module deals with the result of the lookup. It also - // keeps track of the pending refills and ensures that no redundant memory - // requests are made. Upon refill completion, it sends a new tag/data item - // to the lookup module and the received data to the prefetch module. - snitch_icache_handler #(CFG) i_handler ( - .clk_i, - .rst_ni, - - .in_req_addr_i ( lookup_addr ), - .in_req_id_i ( lookup_id ), - .in_req_set_i ( lookup_set ), - .in_req_hit_i ( lookup_hit ), - .in_req_data_i ( lookup_data ), - .in_req_error_i ( lookup_error ), - .in_req_valid_i ( lookup_valid ), - .in_req_ready_o ( lookup_ready ), - - .in_rsp_data_o ( prefetch_lookup_rsp.data ), - .in_rsp_error_o ( prefetch_lookup_rsp.error ), - .in_rsp_id_o ( prefetch_lookup_rsp.id ), - .in_rsp_valid_o ( prefetch_lookup_rsp_valid ), - .in_rsp_ready_i ( prefetch_lookup_rsp_ready ), - - .write_addr_o ( write_addr ), - .write_set_o ( write_set ), - .write_data_o ( write_data ), - .write_tag_o ( write_tag ), - .write_error_o ( write_error ), - .write_valid_o ( write_valid ), - .write_ready_i ( write_ready ), - - .out_req_addr_o ( handler_req.addr ), - .out_req_id_o ( handler_req.id ), - .out_req_valid_o ( handler_req_valid ), - .out_req_ready_i ( handler_req_ready ), - - .out_rsp_data_i ( handler_rsp.data ), - .out_rsp_error_i ( handler_rsp.error ), - .out_rsp_id_i ( handler_rsp.id ), - .out_rsp_valid_i ( handler_rsp_valid ), - .out_rsp_ready_o ( handler_rsp_ready ) - ); - assign handler_req.bypass = 1'b0; - // Arbitrate between bypass and cache-refills - stream_arbiter #( - .DATA_T ( miss_refill_req_t ), - .N_INP ( 2 ) - ) i_stream_arbiter_miss_refill ( - .clk_i, - .rst_ni, - .inp_data_i ( {bypass_req_q, handler_req} ), - .inp_valid_i ( {bypass_req_valid_q, handler_req_valid} ), - .inp_ready_o ( {bypass_req_ready_q, handler_req_ready} ), - .oup_data_o ( refill_req ), - .oup_valid_o ( refill_req_valid ), - .oup_ready_i ( refill_req_ready ) - ); - // Response path muxing - stream_demux #( - .N_OUP ( 2 ) - ) i_stream_demux_miss_refill ( - .inp_valid_i ( refill_rsp_valid ), - .inp_ready_o ( refill_rsp_ready ), - - .oup_sel_i ( refill_rsp.bypass ), - - .oup_valid_o ( {{bypass_rsp_valid, handler_rsp_valid}} ), - .oup_ready_i ( {{bypass_rsp_ready, handler_rsp_ready}} ) - ); - - assign handler_rsp = refill_rsp; - assign bypass_rsp = refill_rsp; - - // Instantiate the cache refill module which emits AXI transactions. - snitch_icache_refill #( - .CFG(CFG), - .axi_req_t (axi_req_t), - .axi_rsp_t (axi_rsp_t) - ) i_refill ( - .clk_i, - .rst_ni, - - .in_req_addr_i ( refill_req.addr ), - .in_req_id_i ( refill_req.id ), - .in_req_bypass_i ( refill_req.bypass ), - .in_req_valid_i ( refill_req_valid ), - .in_req_ready_o ( refill_req_ready ), - - .in_rsp_data_o ( refill_rsp.data ), - .in_rsp_error_o ( refill_rsp.error ), - .in_rsp_id_o ( refill_rsp.id ), - .in_rsp_bypass_o ( refill_rsp.bypass ), - .in_rsp_valid_o ( refill_rsp_valid ), - .in_rsp_ready_i ( refill_rsp_ready ), - .axi_req_o (axi_req_o), - .axi_rsp_i (axi_rsp_i) - ); - -endmodule - -// Translate register interface to refill requests. -// Used for bypassable accesses. -module l0_to_bypass #( - parameter snitch_icache_pkg::config_t CFG = '0 -) ( - input logic clk_i, - input logic rst_ni, - - input logic [CFG.NR_FETCH_PORTS-1:0] in_valid_i, - output logic [CFG.NR_FETCH_PORTS-1:0] in_ready_o, - input logic [CFG.NR_FETCH_PORTS-1:0][CFG.FETCH_AW-1:0] in_addr_i, - output logic [CFG.NR_FETCH_PORTS-1:0][CFG.FETCH_DW-1:0] in_data_o, - output logic [CFG.NR_FETCH_PORTS-1:0] in_error_o, - - output logic [CFG.FETCH_AW-1:0] refill_req_addr_o, - output logic refill_req_bypass_o, - output logic refill_req_valid_o, - input logic refill_req_ready_i, - - input logic [CFG.LINE_WIDTH-1:0] refill_rsp_data_i, - input logic refill_rsp_error_i, - input logic refill_rsp_valid_i, - output logic refill_rsp_ready_o -); - - assign refill_req_bypass_o = 1'b1; - - logic [CFG.NR_FETCH_PORTS-1:0] in_valid; - logic [CFG.NR_FETCH_PORTS-1:0] in_ready; - - typedef enum logic [1:0] { - Idle, RequestData, WaitResponse, PresentResponse - } state_e; - state_e [CFG.NR_FETCH_PORTS-1:0] state_d , state_q; - - // Mask address so that it is aligned to the cache-line width. - logic [CFG.NR_FETCH_PORTS-1:0][CFG.FETCH_AW-1:0] in_addr_masked; - for (genvar i = 0; i < CFG.NR_FETCH_PORTS; i++) begin : gen_masked_addr - assign in_addr_masked[i] = in_addr_i[i] >> CFG.LINE_ALIGN << CFG.LINE_ALIGN; - end - stream_arbiter #( - .DATA_T ( logic [CFG.FETCH_AW-1:0] ), - .N_INP ( CFG.NR_FETCH_PORTS ) - ) i_stream_arbiter ( - .clk_i, - .rst_ni, - .inp_data_i ( in_addr_masked ), - .inp_valid_i ( in_valid ), - .inp_ready_o ( in_ready ), - .oup_data_o ( refill_req_addr_o ), - .oup_valid_o ( refill_req_valid_o ), - .oup_ready_i ( refill_req_ready_i ) - ); - - localparam int unsigned NrFetchPortsBin = - CFG.NR_FETCH_PORTS == 1 ? 1 : $clog2(CFG.NR_FETCH_PORTS); - - logic [CFG.NR_FETCH_PORTS-1:0] rsp_fifo_mux; - logic [NrFetchPortsBin-1:0] onehot_mux; - logic [CFG.NR_FETCH_PORTS-1:0] rsp_fifo_pop; - logic rsp_fifo_full; - - logic [CFG.NR_FETCH_PORTS-1:0] rsp_valid; - logic [CFG.NR_FETCH_PORTS-1:0] rsp_ready; - - fifo_v3 #( - .DATA_WIDTH ( CFG.NR_FETCH_PORTS ), - .DEPTH ( 4 ) - ) rsp_fifo ( - .clk_i, - .rst_ni, - .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), - .full_o ( rsp_fifo_full ), - .empty_o ( ), - .usage_o ( ), - .data_i ( {in_valid & in_ready} ), - .push_i ( |{in_valid & in_ready}), - .data_o ( rsp_fifo_mux ), - .pop_i ( |rsp_fifo_pop ) - ); - - - onehot_to_bin #( - .ONEHOT_WIDTH (CFG.NR_FETCH_PORTS) - ) i_onehot_to_bin ( - .onehot (rsp_fifo_mux), - .bin (onehot_mux) - ); - - assign rsp_ready = '1; - - stream_demux #( - .N_OUP ( CFG.NR_FETCH_PORTS ) - ) i_stream_mux_miss_refill ( - .inp_valid_i ( refill_rsp_valid_i ), - .inp_ready_o ( refill_rsp_ready_o ), - .oup_sel_i ( onehot_mux ), - .oup_valid_o ( rsp_valid ), - .oup_ready_i ( rsp_ready ) - ); - - for (genvar i = 0; i < CFG.NR_FETCH_PORTS; i++) begin : gen_bypass_request - always_comb begin - state_d[i] = state_q[i]; - in_ready_o[i] = 1'b0; - rsp_fifo_pop[i] = 1'b0; - in_valid[i] = 1'b0; - unique case (state_q[i]) - // latch data when idle - Idle: if (in_valid_i[i]) state_d[i] = RequestData; - RequestData: begin - // check that there is still space for the response to be accepted. - if (!rsp_fifo_full) begin - in_valid[i] = 1'b1; - if (in_ready[i]) state_d[i] = WaitResponse; - end - end - WaitResponse: begin - if (rsp_valid[i]) begin - rsp_fifo_pop[i] = 1'b1; - state_d[i] = PresentResponse; - end - end - // The response will be served from the register and is valid for one cycle. - PresentResponse: begin - state_d[i] = Idle; - in_ready_o[i] = 1'b1; - end - default:; - endcase - end - logic [CFG.FILL_DW-1:0] fill_rsp_data; - assign fill_rsp_data = - refill_rsp_data_i >> (in_addr_i[i][CFG.LINE_ALIGN-1:CFG.FETCH_ALIGN] * CFG.FETCH_DW); - `FFLNR({in_data_o[i], in_error_o[i]}, {fill_rsp_data[CFG.FETCH_DW-1:0], refill_rsp_error_i}, - rsp_valid[i], clk_i) - end - - `FF(state_q, state_d, '{default: Idle}) - -endmodule diff --git a/hw/snitch_icache/src/snitch_icache_handler.sv b/hw/snitch_icache/src/snitch_icache_handler.sv deleted file mode 100644 index 55b862db1..000000000 --- a/hw/snitch_icache/src/snitch_icache_handler.sv +++ /dev/null @@ -1,344 +0,0 @@ -// Copyright 2020 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - -// Fabian Schuiki - -`include "common_cells/registers.svh" - -module snitch_icache_handler #( - parameter snitch_icache_pkg::config_t CFG = '0 -)( - 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 -); - - `ifndef SYNTHESIS - initial assert(CFG != '0); - `endif - - // The table of pending refills holds the metadata of all refills that are - // currently in flight. The table has a push and a pop interfaces. The push - // interface is used to mark entries as valid and update the mask of request - // IDs that the refill will serve. The pop interface is used to read a value - // from the table and clear its valid flag. - typedef struct packed { - logic valid; - logic [CFG.FETCH_AW-1:0] addr; - logic [CFG.ID_WIDTH_RESP-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] pop_index; - logic [CFG.FETCH_AW-1:0] pop_addr; - logic [CFG.ID_WIDTH_RESP-1:0] pop_idmask; - logic pop_enable; - - for (genvar i = 0; i < CFG.PENDING_COUNT; i++) begin : g_pending_row - always_ff @(posedge clk_i, negedge rst_ni) begin - if (!rst_ni) - pending_q[i].valid <= 0; - else if (pending_set[i] || pending_clr[i]) - pending_q[i].valid <= pending_set[i] && ~pending_clr[i]; - end - - always_ff @(posedge clk_i, negedge rst_ni) begin - if (!rst_ni) begin - pending_q[i].addr <= '0; - pending_q[i].idmask <= '0; - end else if (pending_set[i]) begin - pending_q[i].addr <= push_addr; - pending_q[i].idmask <= push_init ? push_idmask : push_idmask | pending_q[i].idmask; - end - end - end - - // The bypass logic ensures that if a table entry is pushed and popped at - // the same time, the pop is updated with the push information and the push - // discarded. - always_comb begin : p_pushpop_bypass - pending_set = push_enable ? 'b1 << push_index : '0; - pending_clr = pop_enable ? 'b1 << pop_index : '0; - pop_addr = pending_q[pop_index].addr; - pop_idmask = pending_q[pop_index].idmask; - if (push_enable && pop_enable && push_index == pop_index) begin - pop_addr = push_addr; - pop_idmask |= push_idmask; - end - end - - // Determine the first available entry in the pending table, if any is free. - logic [CFG.PENDING_COUNT-1:0] free_entries; - logic free; - logic [CFG.PENDING_IW-1:0] free_id; - - always_comb begin : p_free_id - for (int i = 0; i < CFG.PENDING_COUNT; i++) - free_entries[i] = ~pending_q[i].valid; - free = |free_entries; - end - - lzc #(.WIDTH(CFG.PENDING_COUNT)) i_lzc_free ( - .in_i ( free_entries ), - .cnt_o ( free_id ), - .empty_o ( ) - ); - - // Determine if the address of the incoming request coincides with any of - // the entries in the pending table. - logic [CFG.PENDING_COUNT-1:0] pending_matches; - logic pending; - logic [CFG.PENDING_IW-1:0] pending_id; - - always_comb begin : p_pending_id - for (int i = 0; i < CFG.PENDING_COUNT; i++) - pending_matches[i] = pending_q[i].valid && pending_q[i].addr == in_req_addr_i; - pending = |pending_matches; - end - - lzc #(.WIDTH(CFG.PENDING_COUNT)) i_lzc_pending ( - .in_i ( pending_matches ), - .cnt_o ( pending_id ), - .empty_o ( ) - ); - - // Gurarntee 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; - - if (CFG.GUARANTEE_ORDERING) begin : g_miss_in_flight_table - always_comb begin : p_miss_in_flight - miss_in_flight_d = miss_in_flight_q; - if (push_enable) begin - miss_in_flight_d |= push_idmask; - end - if (in_rsp_valid_o && in_rsp_ready_i) begin - miss_in_flight_d &= ~in_rsp_id_o; - end - end - - `FF(miss_in_flight_q, miss_in_flight_d, '0, clk_i, rst_ni) - end else begin : g_tie_off_miss_in_flight - assign miss_in_flight_d = '0; - assign miss_in_flight_q = '0; - end - - // The miss handler checks if the access into the cache was a hit. If yes, - // the data is forwarded to the response handler. Otherwise the table of - // pending refills is consulted to check if any refills are currently in - // 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; - - always_comb begin : p_miss_handler - hit_valid = 0; - hit_id = 'b1 << 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_enable = 0; - - in_req_ready_o = 1; - - out_req_addr_o = in_req_addr_i; - out_req_id_o = free_id; - out_req_valid_o = 0; - - if (in_req_valid_i) begin - // Miss already in flight. Stall to preserve ordering - 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 - hit_valid = 1; - 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 - push_index = pending_id; - push_enable = 1; - - // The cache lookup was a miss, there is no pending refill, but - // there are available entries in the table. - end else if (free) begin - out_req_addr_o = in_req_addr_i; - out_req_id_o = free_id; - out_req_valid_o = 1; - in_req_ready_o = out_req_ready_i; - push_index = free_id; - push_init = 1; - push_enable = out_req_ready_i; - - // The cache lookup was a miss, there is no pending refill, and - // there is no room in the table for a new refill at the moment. - end else begin - in_req_ready_o = 0; - end - 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 ) - ); - - // The response handler deals with incoming refill responses. It queries and - // clears the corresponding entry in the pending table, stores the data in - // the cache via the `write` port, and returns the data to the appropriate - // fetch ports via the `in_rsp` port. It also mixes the data of a cache hit - // into the response stream. - logic write_served_q; - logic in_rsp_served_q; - logic rsp_valid, rsp_ready; - - typedef struct packed { - logic sel; - logic lock; - } arb_t; - arb_t arb_q, arb_d; - - always_ff @(posedge clk_i, negedge rst_ni) begin - if (!rst_ni) - arb_q <= '0; - else - arb_q <= arb_d; - end - - always_comb begin : p_response_handler - pop_index = out_rsp_id_i; - pop_enable = 0; - - write_addr_o = pop_addr >> CFG.LINE_ALIGN; - write_set_o = evict_index; - write_data_o = out_rsp_data_i; - write_tag_o = pop_addr >> (CFG.LINE_ALIGN + CFG.COUNT_ALIGN); - write_error_o = out_rsp_error_i; - write_valid_o = 0; - - in_rsp_data_o = out_rsp_data_i; - in_rsp_error_o = out_rsp_error_i; - in_rsp_id_o = pop_idmask; - in_rsp_valid_o = 0; - - hit_ready = 1; - out_rsp_ready_o = 1; - evict_enable = 0; - rsp_valid = 0; - rsp_ready = 1; - - arb_d = arb_q; - if (!arb_q.lock) begin - if (hit_valid) begin - arb_d.sel = 0; - arb_d.lock = 1; - end else if (out_rsp_valid_i) begin - arb_d.sel = 1; - arb_d.lock = 1; - end else begin - arb_d.sel = 0; - arb_d.lock = 0; - end - end - - // Cache hit data is pending. - if (arb_d.sel == 0) begin - if (hit_valid) begin - out_rsp_ready_o = 0; - in_rsp_data_o = hit_data; - in_rsp_error_o = 0; - in_rsp_id_o = hit_id; - in_rsp_valid_o = 1; - hit_ready = in_rsp_ready_i; - end else hit_ready = 1; - if (hit_ready) arb_d.lock = 0; - - // No cache hit is pending, but response data is available. - end else if (arb_d.sel == 1) begin - if (out_rsp_valid_i) begin - hit_ready = 0; - rsp_valid = 1; - rsp_ready = (in_rsp_ready_i || in_rsp_served_q) - && (write_ready_i || write_served_q); - write_valid_o = 1 && ~write_served_q; - in_rsp_valid_o = 1 && ~in_rsp_served_q; - pop_enable = rsp_ready; - out_rsp_ready_o = rsp_ready; - evict_enable = rsp_ready; - end else rsp_ready = 1; - if (rsp_ready) arb_d.lock = 0; - end - end - - always_ff @(posedge clk_i, negedge rst_ni) begin - if (!rst_ni) begin - write_served_q <= 0; - in_rsp_served_q <= 0; - end else begin - write_served_q <= rsp_valid & ~rsp_ready & (write_served_q | write_ready_i); - in_rsp_served_q <= rsp_valid & ~rsp_ready & (in_rsp_served_q | in_rsp_ready_i); - end - end - -endmodule diff --git a/hw/snitch_icache/src/snitch_icache_l0.sv b/hw/snitch_icache/src/snitch_icache_l0.sv deleted file mode 100644 index 1995c8491..000000000 --- a/hw/snitch_icache/src/snitch_icache_l0.sv +++ /dev/null @@ -1,413 +0,0 @@ -// Copyright 2020 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - -// Fabian Schuiki -// Florian Zaruba - -`include "common_cells/registers.svh" -`include "common_cells/assertions.svh" - -/// A simple single-line cache private to each port. -module snitch_icache_l0 import snitch_icache_pkg::*; #( - parameter config_t CFG = '0, - parameter int unsigned L0_ID = 0 -) ( - input logic clk_i, - 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, - - 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 -); - - typedef logic [CFG.FETCH_AW-1:0] addr_t; - typedef struct packed { - logic [CFG.L0_TAG_WIDTH-1:0] tag; - logic vld; - } tag_t; - - logic [CFG.L0_TAG_WIDTH-1:0] addr_tag, addr_tag_prefetch; - - tag_t [CFG.L0_LINE_COUNT-1:0] tag; - logic [CFG.L0_LINE_COUNT-1:0][CFG.LINE_WIDTH-1:0] data; - - logic [CFG.L0_LINE_COUNT-1:0] hit, hit_early, hit_prefetch; - logic hit_early_is_onehot; - logic hit_any; - logic hit_prefetch_any; - logic miss; - - logic [CFG.L0_LINE_COUNT-1:0] evict_strb; - logic [CFG.L0_LINE_COUNT-1:0] flush_strb; - logic [CFG.L0_LINE_COUNT-1:0] validate_strb; - - typedef struct packed { - logic vld; - logic [CFG.FETCH_AW-1:0] addr; - } prefetch_req_t; - - logic latch_prefetch, last_cycle_was_prefetch_q; - prefetch_req_t prefetcher_out; - // As we have different flipflops (resetable vs non-resetable) we need to - // split that struct into two distinct signals to avoid multi-driven warnings - // in Verilator. - logic prefetch_req_vld_q, prefetch_req_vld_d; - logic [CFG.FETCH_AW-1:0] prefetch_req_addr_q, prefetch_req_addr_d; - - // Holds the onehot signal for the line being refilled at the moment - logic [CFG.L0_LINE_COUNT-1:0] pending_line_refill_q; - logic pending_refill_q, pending_refill_d; - - logic evict_req; - logic last_cycle_was_miss_q; - - `FF(last_cycle_was_miss_q, miss, '0) - `FF(last_cycle_was_prefetch_q, latch_prefetch, '0) - - logic evict_because_miss, evict_because_prefetch; - - typedef struct packed { - logic is_prefetch; - logic [CFG.FETCH_AW-1:0] addr; - } req_t; - - req_t refill, prefetch; - logic refill_valid, prefetch_valid; - logic refill_ready, prefetch_ready; - req_t out_req; - - assign evict_because_miss = miss & ~last_cycle_was_miss_q; - assign evict_because_prefetch = latch_prefetch & ~last_cycle_was_prefetch_q; - - assign evict_req = evict_because_miss | evict_because_prefetch; - - assign addr_tag = in_addr_i >> CFG.LINE_ALIGN; - - // ------------ - // Tag Compare - // ------------ - for (genvar i = 0; i < CFG.L0_LINE_COUNT; i++) begin : gen_cmp_fetch - assign hit_early[i] = tag[i].vld & - (tag[i].tag[CFG.L0_EARLY_TAG_WIDTH-1:0] == addr_tag[CFG.L0_EARLY_TAG_WIDTH-1:0]); - // The two signals calculate the same. - if (CFG.L0_TAG_WIDTH == CFG.L0_EARLY_TAG_WIDTH) begin : gen_hit_assign - assign hit[i] = hit_early[i]; - // Compare the rest of the tag. - end else begin : gen_hit - assign hit[i] = hit_early[i] & - (tag[i].tag[CFG.L0_TAG_WIDTH-1:CFG.L0_EARLY_TAG_WIDTH] - == addr_tag[CFG.L0_TAG_WIDTH-1:CFG.L0_EARLY_TAG_WIDTH]); - end - assign hit_prefetch[i] = tag[i].vld & (tag[i].tag == addr_tag_prefetch); - end - - assign hit_any = |hit; - assign hit_prefetch_any = |hit_prefetch; - assign miss = ~hit_any & in_valid_i & ~pending_refill_q; - - for (genvar i = 0; i < CFG.L0_LINE_COUNT; i++) begin : gen_array - // Tag Array - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - tag[i].vld <= 0; - tag[i].tag <= 0; - end else begin - if (evict_strb[i]) begin - tag[i].vld <= 1'b0; - tag[i].tag <= evict_because_prefetch ? addr_tag_prefetch : addr_tag; - end else if (validate_strb[i]) begin - tag[i].vld <= 1'b1; - end - if (flush_strb[i]) begin - tag[i].vld <= 1'b0; - end - end - end - if (CFG.EARLY_LATCH) begin : gen_latch - // Data Array - always_latch begin - if (clk_i && validate_strb[i]) begin - data[i] <= out_rsp_data_i; - end - end - end else begin : gen_ff - `FFLNR(data[i], out_rsp_data_i, validate_strb[i], clk_i) - end - end - - // ---- - // HIT - // ---- - // we hit in the cache and there was a unique hit. - assign in_ready_o = hit_any; - - logic [CFG.LINE_WIDTH-1:0] ins_data; - always_comb begin : data_muxer - ins_data = '0; - for (int unsigned i = 0; i < CFG.L0_LINE_COUNT; i++) begin - ins_data |= {CFG.LINE_WIDTH{hit[i]}} & data[i]; - end - in_data_o = ins_data >> (in_addr_i[CFG.LINE_ALIGN-1:CFG.FETCH_ALIGN] * CFG.FETCH_DW); - end - - // Check whether we had an early multi-hit (e.g., the portion of the tag matched - // multiple entries in the tag array) - if (CFG.L0_TAG_WIDTH != CFG.L0_EARLY_TAG_WIDTH) begin : gen_multihit_detection - cc_onehot #( - .Width (CFG.L0_LINE_COUNT) - ) i_onehot_hit_early ( - .d_i (hit_early), - .is_onehot_o (hit_early_is_onehot) - ); - end else begin : gen_no_multihit_detection - assign hit_early_is_onehot = 1'b1; - end - - // ------- - // 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; - end - end - end - - always_comb begin : flush - flush_strb = '0; - // Check whether we encountered a multi-hit condition and - // evict the offending entry. - if (hit_any && !hit_early_is_onehot) begin - // We want to evict all entries which hit with the early tag - // but didn't hit in the final comparison. - flush_strb = ~hit & hit_early; - end - if (flush_valid_i) flush_strb = '1; - end - - `FF(cnt_q, cnt_d, '0) - - // ------------- - // Miss Handling - // ------------- - assign refill.addr = addr_tag << CFG.LINE_ALIGN; - assign refill.is_prefetch = 1'b0; - assign refill_valid = miss; - - `FFLNR(pending_line_refill_q, evict_strb, evict_req, clk_i) - `FF(pending_refill_q, pending_refill_d, '0) - - always_comb begin - pending_refill_d = pending_refill_q; - // re-set condition - if (pending_refill_q) begin - if (out_rsp_valid_i & out_rsp_ready_o) begin - pending_refill_d = 1'b0; - end - // set condition - end else begin - if (refill_valid && refill_ready) begin - pending_refill_d = 1'b1; - end - if (latch_prefetch) begin - pending_refill_d = 1'b1; - end - end - end - - assign validate_strb = out_rsp_valid_i ? pending_line_refill_q : '0; - assign out_rsp_ready_o = 1'b1; - - assign in_error_o = '0; - - assign out_req_addr_o = out_req.addr; - assign out_req_id_o = {L0_ID, out_req.is_prefetch}; - - // Priority arbitrate requests. - always_comb begin - out_req = prefetch; - out_req_valid_o = prefetch_valid; - prefetch_ready = out_req_ready_i; - refill_ready = 1'b0; - - if (refill_valid) begin - out_req_valid_o = refill_valid; - out_req = refill; - refill_ready = out_req_ready_i; - prefetch_ready = 1'b0; - end - end - - // ------------- - // Pre-fetching - // ------------- - // Generate a prefetch request if the cache hits and we haven't - // pre-fetched the line yet and there is no other refill in progress. - assign prefetcher_out.vld = enable_prefetching_i & - hit_any & ~hit_prefetch_any & - hit_early_is_onehot & ~pending_refill_q; - - localparam int unsigned FetchPkts = CFG.LINE_WIDTH/32; - logic [FetchPkts-1:0] is_branch_taken; - logic [FetchPkts-1:0] is_jal; - logic [FetchPkts-1:0] mask; - // make sure that we only look at the packets which are of interest to - assign mask = '1 << in_addr_i[CFG.LINE_ALIGN-1:2]; - - // Instruction aware pre-fetching - for (genvar i = 0; i < FetchPkts; i++) begin : gen_pre_decode - // iterate over the fetch packets (32 bits per instruction) - always_comb begin - is_branch_taken[i] = 1'b0; - is_jal[i] = 1'b0; - unique casez (ins_data[i*32+:32]) - // static prediction - riscv_instr::BEQ, - riscv_instr::BNE, - riscv_instr::BLT, - riscv_instr::BGE, - riscv_instr::BLTU, - riscv_instr::BGEU: begin - // look at the sign bit of the immediate field - // backward branches (immediate negative) taken - // forward branches not taken - is_branch_taken[i] = ins_data[i*32+31]; - end - riscv_instr::JAL: begin - is_jal[i] = 1'b1; - end - // we can't do anything about the JALR case as we don't - // know the destination. - default:; - endcase - end - end - - logic [$clog2(FetchPkts)-1:0] taken_idx; - logic no_prefetch; - logic [$clog2(CFG.LINE_WIDTH)-1:0] ins_idx; - assign ins_idx = 32*taken_idx; - // Find first taken branch - lzc #( - .WIDTH(FetchPkts), - .MODE(0) - ) i_lzc_branch ( - // look at branches and jals - .in_i (mask & (is_branch_taken | is_jal)), - .cnt_o (taken_idx), - .empty_o (no_prefetch) - ); - - addr_t base_addr, offset, uj_imm, sb_imm; - logic [CFG.LINE_ALIGN-1:0] base_offset; - assign base_offset = taken_idx << 2; - assign uj_imm = - $signed({ins_data[ins_idx+31], ins_data[ins_idx+12+:8], - ins_data[ins_idx+20], ins_data[ins_idx+21+:10], 1'b0}); - assign sb_imm = - $signed({ins_data[ins_idx+31], ins_data[ins_idx+7], - ins_data[ins_idx+25+:6], ins_data[ins_idx+8+:4], 1'b0}); - - // next address calculation - always_comb begin - // default is next line predictor - base_addr = no_prefetch ? in_addr_i : {in_addr_i >> CFG.LINE_ALIGN, base_offset}; - offset = (1 << CFG.LINE_ALIGN); - // If the cache-line contains a taken branch, compute the pre-fetch address with the jump's offset. - unique case ({is_branch_taken[taken_idx] & ~no_prefetch, is_jal[taken_idx] & ~no_prefetch}) - // JAL: UJ Immediate - 2'b01: offset = uj_imm; - // Branch: // SB Immediate - 2'b10: offset = sb_imm; - default:; - endcase - end - - assign prefetcher_out.addr = ($signed(base_addr) + offset) >> CFG.LINE_ALIGN << CFG.LINE_ALIGN; - - // check whether cache-line we want to pre-fetch is already present - assign addr_tag_prefetch = prefetcher_out.addr >> CFG.LINE_ALIGN; - - assign latch_prefetch = prefetcher_out.vld & ~prefetch_req_vld_q; - - always_comb begin - prefetch_req_vld_d = prefetch_req_vld_q; - prefetch_req_addr_d = prefetch_req_addr_q; - - if (prefetch_ready) prefetch_req_vld_d = 1'b0; - - if (latch_prefetch) begin - prefetch_req_vld_d = 1'b1; - prefetch_req_addr_d = prefetcher_out.addr; - end - end - - assign prefetch.is_prefetch = 1'b1; - assign prefetch.addr = prefetch_req_addr_q; - assign prefetch_valid = prefetch_req_vld_q; - - `FF(prefetch_req_vld_q, prefetch_req_vld_d, '0) - `FFNR(prefetch_req_addr_q, prefetch_req_addr_d, clk_i) - - // ------------------ - // Performance Events - // ------------------ - always_comb begin - icache_events_o = '0; - icache_events_o.l0_miss = miss; - icache_events_o.l0_hit = hit_any & in_valid_i; - icache_events_o.l0_prefetch = prefetcher_out.vld; - icache_events_o.l0_double_hit = hit_any & ~hit_early_is_onehot & in_valid_i; - icache_events_o.l0_stall = !in_ready_o & in_valid_i; - end - - // ---------- - // Assertions - // ---------- - `ASSERT(HitOnehot, $onehot0(hit)) - // make sure only one signal is high and the conditions are mutual exclusive - `ASSERT(ExclusiveEvict, $onehot0({evict_because_miss, evict_because_prefetch})) - // request must be stable - `ASSERT(InstReqStable, in_valid_i && !in_ready_o |=> in_valid_i) - `ASSERT(InstReqDataStable, in_valid_i && !in_ready_o |=> $stable(in_addr_i)) - - `ASSERT(RefillReqStable, out_req_valid_o && !out_req_ready_i |=> out_req_valid_o) - `ASSERT(RefillReqDataStable, - out_req_valid_o && !out_req_ready_i |=> $stable(out_req_addr_o) && $stable(out_req_id_o)) - - `ASSERT(RefillRspStable, out_rsp_valid_i && !out_rsp_ready_o |=> out_rsp_valid_i) - `ASSERT(RefillRspDataStable, - out_rsp_valid_i && !out_rsp_ready_o - |=> $stable(out_rsp_data_i) && $stable(out_rsp_error_i) && $stable(out_rsp_id_i)) - // make sure we observe a double hit condition - `COVER(HitEarlyNotOnehot, hit |-> $onehot(hit_early)) - -endmodule diff --git a/hw/snitch_icache/src/snitch_icache_lfsr.sv b/hw/snitch_icache/src/snitch_icache_lfsr.sv deleted file mode 100644 index 1568b1e68..000000000 --- a/hw/snitch_icache/src/snitch_icache_lfsr.sv +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2020 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - -// Fabian Schuiki - -/// A linear feedback shift register. -/// -/// The register provides a maximum length sequence for N <= 32. For larger N, -/// multiple LFSR are instantiated. Note that the generated sequence is forced -/// to include the value 0, making it length 2**N instead of the usual 2**N-1. -module snitch_icache_lfsr #( - parameter int N = -1 -)( - input logic clk_i, - input logic rst_ni, - output logic [N-1:0] value_o, - input logic enable_i -); - - `ifndef SYNTHESIS - initial assert(N > 0); - `endif - - if (N > 32) begin : g_split - - localparam int N0 = N/2; - localparam int N1 = N-N0; - - snitch_icache_lfsr #(N0) i_lo ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .value_o ( value_o[N0-1:0] ), - .enable_i ( enable_i ) - ); - - snitch_icache_lfsr #(N1) i_hi ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .value_o ( value_o[N-1:N0] ), - .enable_i ( enable_i && value_o[N0-1:0] == 0 ) - ); - - end else if (N == 1) begin : g_toggle - - logic q; - - always_ff @(posedge clk_i, negedge rst_ni) begin - if (!rst_ni) - q <= 0; - else if (enable_i) - q <= ~q; - end - - assign value_o = q; - - end else begin : g_impl - - logic [N-1:0] q, d, taps; - - assign value_o = q; - - always_ff @(posedge clk_i, negedge rst_ni) begin - if (!rst_ni) - q <= 0; - else if (enable_i) - q <= d; - end - - always_comb begin - if (q == '0) begin - d = '1; - end else begin - d = {1'b0, q[N-1:1]}; - if (q[0]) d ^= taps; - if (d == '1) d = '0; - end - end - - // A lookup table for the taps. - always_comb begin - taps = 1 << (N-1); - case (N) - 2: taps = $unsigned( 1<< 1 | 1<< 0 ); - 3: taps = $unsigned( 1<< 2 | 1<< 1 ); - 4: taps = $unsigned( 1<< 3 | 1<< 2 ); - 5: taps = $unsigned( 1<< 4 | 1<< 2 ); - 6: taps = $unsigned( 1<< 5 | 1<< 4 ); - 7: taps = $unsigned( 1<< 6 | 1<< 5 ); - 8: taps = $unsigned( 1<< 7 | 1<< 5 | 1<< 4 | 1<< 3 ); - 9: taps = $unsigned( 1<< 8 | 1<< 4 ); - 10: taps = $unsigned( 1<< 9 | 1<< 6 ); - 11: taps = $unsigned( 1<<10 | 1<< 8 ); - 12: taps = $unsigned( 1<<11 | 1<<10 | 1<< 9 | 1<< 3 ); - 13: taps = $unsigned( 1<<12 | 1<<11 | 1<<10 | 1<< 7 ); - 14: taps = $unsigned( 1<<13 | 1<<12 | 1<<11 | 1<< 1 ); - 15: taps = $unsigned( 1<<14 | 1<<13 ); - 16: taps = $unsigned( 1<<15 | 1<<14 | 1<<12 | 1<< 3 ); - 17: taps = $unsigned( 1<<16 | 1<<13 ); - 18: taps = $unsigned( 1<<17 | 1<<10 ); - 19: taps = $unsigned( 1<<18 | 1<<17 | 1<<16 | 1<<13 ); - 20: taps = $unsigned( 1<<19 | 1<<16 ); - 21: taps = $unsigned( 1<<20 | 1<<18 ); - 22: taps = $unsigned( 1<<21 | 1<<20 ); - 23: taps = $unsigned( 1<<22 | 1<<17 ); - 24: taps = $unsigned( 1<<23 | 1<<22 | 1<<21 | 1<<16 ); - 25: taps = $unsigned( 1<<24 | 1<<21 ); - 26: taps = $unsigned( 1<<25 | 1<< 5 | 1<< 1 | 1<< 0 ); - 27: taps = $unsigned( 1<<26 | 1<< 4 | 1<< 1 | 1<< 0 ); - 28: taps = $unsigned( 1<<27 | 1<<24 ); - 29: taps = $unsigned( 1<<28 | 1<<26 ); - 30: taps = $unsigned( 1<<29 | 1<< 5 | 1<< 3 | 1<< 0 ); - 31: taps = $unsigned( 1<<30 | 1<<27 ); - 32: taps = $unsigned( 1<<31 | 1<<21 | 1<< 1 | 1<< 0 ); - default: taps = 1 << (N-1); - endcase; - end - - end - -endmodule diff --git a/hw/snitch_icache/src/snitch_icache_lookup.sv b/hw/snitch_icache/src/snitch_icache_lookup.sv deleted file mode 100644 index fdcfd5c5f..000000000 --- a/hw/snitch_icache/src/snitch_icache_lookup.sv +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright 2020 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - -// Fabian Schuiki - -/// An actual cache lookup. -module snitch_icache_lookup #( - parameter snitch_icache_pkg::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 -)( - 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 sram_cfg_data_t sram_cfg_data_i, - input sram_cfg_tag_t sram_cfg_tag_i -); - - `ifndef SYNTHESIS - initial assert(CFG != '0); - `endif - - // Multiplex read and write access to the RAMs onto one port, prioritizing - // write accesses. - logic [CFG.COUNT_ALIGN-1:0] ram_addr ; - logic [CFG.SET_COUNT-1:0] ram_enable ; - logic [CFG.LINE_WIDTH-1:0] ram_wdata, ram_rdata [CFG.SET_COUNT] ; - logic [CFG.TAG_WIDTH+1:0] ram_wtag, ram_rtag [CFG.SET_COUNT] ; - logic ram_write ; - logic ram_write_q; - logic [CFG.COUNT_ALIGN:0] init_count_q; - - typedef struct packed { - logic [CFG.SET_ALIGN-1:0] cset; - logic hit; - logic [CFG.LINE_WIDTH-1:0] data; - logic error; - } out_buffer_t; - - out_buffer_t data_d, data_q; - logic buffer_ready; - logic buffer_valid; - - always_comb begin : p_portmux - write_ready_o = 0; - in_ready_o = 0; - - ram_addr = in_addr_i >> CFG.LINE_ALIGN; - ram_wdata = write_data_i; - ram_wtag = {1'b1, write_error_i, write_tag_i}; - ram_enable = '0; - ram_write = 1'b0; - - if (init_count_q != $unsigned(CFG.LINE_COUNT)) begin - ram_addr = init_count_q; - ram_enable = '1; - ram_write = 1'b1; - ram_wdata = '0; - ram_wtag = '0; - end else if (write_valid_i) begin - ram_addr = write_addr_i; - ram_enable = CFG.SET_COUNT > 1 ? $unsigned(1 << write_set_i) : 1'b1; - ram_write = 1'b1; - write_ready_o = 1'b1; - end else if (out_ready_i) begin - ram_enable = in_valid_i ? '1 : '0; - in_ready_o = 1'b1; - end - end - - // We are always ready to flush - assign flush_ready_o = 1'b1; - - always_ff @(posedge clk_i, negedge rst_ni) begin - if (!rst_ni) - init_count_q <= '0; - else if (init_count_q != $unsigned(CFG.LINE_COUNT)) - init_count_q <= init_count_q + 1; - else if (flush_valid_i) - init_count_q <= '0; - end - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - ram_write_q <= 0; - end else begin - ram_write_q <= ram_write; - end - end - - // The address register keeps track of additional metadata alongside the - // 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; - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - valid_q <= 0; - end else begin - if (CFG.BUFFER_LOOKUP) begin - valid_q <= in_valid_i && in_ready_o; - end else if ((in_valid_i && in_ready_o) || out_ready_i) begin - valid_q <= in_valid_i && in_ready_o; - end - end - end - - always_ff @(posedge clk_i, negedge rst_ni) begin - if (!rst_ni) begin - addr_q <= '0; - id_q <= '0; - end else if (in_valid_i && in_ready_o) begin - addr_q <= in_addr_i; - id_q <= in_id_i; - end - end - - // Instantiate the RAM sets. - for (genvar i = 0; i < CFG.SET_COUNT; i++) begin : g_sets - tc_sram_impl #( - .NumWords (CFG.LINE_COUNT), - .DataWidth (CFG.TAG_WIDTH+2), - .ByteWidth (8), - .NumPorts (1), - .Latency (1), - .impl_in_t (sram_cfg_tag_t) - ) i_tag ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .impl_i (sram_cfg_tag_i), - .impl_o ( ), - .req_i (ram_enable[i]), - .we_i (ram_write), - .addr_i (ram_addr), - .wdata_i (ram_wtag), - .be_i ('1), - .rdata_o (ram_rtag[i]) - ); - - tc_sram_impl #( - .NumWords (CFG.LINE_COUNT), - .DataWidth (CFG.LINE_WIDTH), - .ByteWidth (8), - .NumPorts (1), - .Latency (1), - .impl_in_t (sram_cfg_data_t) - ) i_data ( - .clk_i (clk_i), - .rst_ni (rst_ni), - .impl_i (sram_cfg_data_i), - .impl_o ( ), - .req_i (ram_enable[i]), - .we_i (ram_write), - .addr_i (ram_addr), - .wdata_i (ram_wdata), - .be_i ('1), - .rdata_o (ram_rdata[i]) - ); - end - - // Determine which RAM line hit, and multiplex that data to the output. - logic [CFG.TAG_WIDTH-1:0] required_tag; - logic [CFG.SET_COUNT-1:0] line_hit; - - always_comb begin - automatic logic [CFG.SET_COUNT-1:0] errors; - required_tag = addr_q >> (CFG.LINE_ALIGN + CFG.COUNT_ALIGN); - for (int i = 0; i < CFG.SET_COUNT; i++) begin - line_hit[i] = ram_rtag[i][CFG.TAG_WIDTH+1] && - ram_rtag[i][CFG.TAG_WIDTH-1:0] == required_tag; - errors[i] = ram_rtag[i][CFG.TAG_WIDTH] && line_hit[i]; - end - data_d.hit = |line_hit & ~ram_write_q; // Don't let refills trigger "valid" lookups - data_d.error = |errors; - end - - always_comb begin - for (int i = 0; i < CFG.LINE_WIDTH; i++) begin - automatic logic [CFG.SET_COUNT-1:0] masked; - for (int j = 0; j < CFG.SET_COUNT; j++) - masked[j] = ram_rdata[j][i] & line_hit[j]; - data_d.data[i] = |masked; - end - end - - lzc #(.WIDTH(CFG.SET_COUNT)) i_lzc ( - .in_i ( line_hit ), - .cnt_o ( data_d.cset ), - .empty_o ( ) - ); - - // Buffer response in case we are stalled - if (CFG.BUFFER_LOOKUP) begin : gen_buffer - fall_through_register #( - .T ( out_buffer_t ) - ) i_rsp_buffer ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .clr_i ( 1'b0 ), - .testmode_i ( 1'b0 ), - // Input port - .valid_i ( valid_q ), - .ready_o ( buffer_ready ), - .data_i ( data_d ), - // Output port - .valid_o ( buffer_valid ), - .ready_i ( out_ready_i ), - .data_o ( data_q ) - ); - end else begin : gen_connection - assign data_q = data_d; - assign buffer_valid = valid_q; - assign buffer_ready = 1'b1; - end - - // Generate the output signals. - assign out_addr_o = addr_q; - assign out_id_o = id_q; - assign out_set_o = data_q.cset; - assign out_hit_o = data_q.hit; - assign out_data_o = data_q.data; - assign out_error_o = data_q.error; - assign out_valid_o = buffer_valid; - - // Assertions - `include "common_cells/assertions.svh" - `ASSERT(i_rsp_buffer_ready, (valid_q |-> buffer_ready), clk_i, !rst_ni) - -endmodule diff --git a/hw/snitch_icache/src/snitch_icache_pkg.sv b/hw/snitch_icache/src/snitch_icache_pkg.sv deleted file mode 100644 index 6a14a7d82..000000000 --- a/hw/snitch_icache/src/snitch_icache_pkg.sv +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2020 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - -// Fabian Schuiki - -package snitch_icache_pkg; - - typedef struct packed { - logic l0_miss; - logic l0_hit; - logic l0_prefetch; - logic l0_double_hit; - logic l0_stall; - } icache_events_t; - - typedef struct packed { - // Parameters passed to the root module. - int NR_FETCH_PORTS; - int LINE_WIDTH; - int LINE_COUNT; - int SET_COUNT; - int PENDING_COUNT; - int L0_LINE_COUNT; - int FETCH_AW; - int FETCH_DW; - int FILL_AW; - int FILL_DW; - bit EARLY_LATCH; - bit BUFFER_LOOKUP; - bit GUARANTEE_ORDERING; - - // Derived values. - int FETCH_ALIGN; - int FILL_ALIGN; - int LINE_ALIGN; - int COUNT_ALIGN; - int SET_ALIGN; - int TAG_WIDTH; - int L0_TAG_WIDTH; - int L0_EARLY_TAG_WIDTH; - int ID_WIDTH_REQ; - int ID_WIDTH_RESP; - int PENDING_IW; // refill ID width - } config_t; - -endpackage diff --git a/hw/snitch_icache/src/snitch_icache_refill.sv b/hw/snitch_icache/src/snitch_icache_refill.sv deleted file mode 100644 index e133d8302..000000000 --- a/hw/snitch_icache/src/snitch_icache_refill.sv +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2020 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - -// Fabian Schuiki - -/// A refiller for cache lines. -module snitch_icache_refill #( - parameter snitch_icache_pkg::config_t CFG = '0, - parameter type axi_req_t = logic, - parameter type axi_rsp_t = logic -) ( - input logic clk_i, - input logic rst_ni, - - input logic [CFG.FETCH_AW-1:0] in_req_addr_i, - input logic [CFG.PENDING_IW-1:0] in_req_id_i, - input logic in_req_bypass_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.PENDING_IW-1:0] in_rsp_id_o, - output logic in_rsp_bypass_o, - output logic in_rsp_valid_o, - input logic in_rsp_ready_i, - - output axi_req_t axi_req_o, - input axi_rsp_t axi_rsp_i -); - - `ifndef SYNTHESIS - initial assert(CFG != '0); - `endif - - // How many response beats are necessary to refill one cache line. - localparam int unsigned BeatsPerRefill = - CFG.LINE_WIDTH >= CFG.FILL_DW ? CFG.LINE_WIDTH/CFG.FILL_DW : 1; - - // The response queue holds metadata for the issued requests in order. - logic queue_full; - logic queue_push; - logic queue_pop; - - localparam int unsigned TransactionQueueDepth = 4; - - fifo_v3 #( - .DEPTH ( TransactionQueueDepth ), - .DATA_WIDTH ( CFG.PENDING_IW+1 ) - ) i_fifo_id_queue ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), - .full_o ( queue_full ), - .empty_o ( ), - .usage_o ( ), - .data_i ( {in_req_bypass_i, in_req_id_i} ), - .push_i ( queue_push ), - .data_o ( {in_rsp_bypass_o, in_rsp_id_o} ), - .pop_i ( queue_pop ) - ); - - // Accept incoming requests, push the ID into the queue, and issue the - // corresponding request. - assign in_req_ready_o = axi_rsp_i.ar_ready & ~queue_full; - assign queue_push = axi_req_o.ar_valid & axi_rsp_i.ar_ready; - - // Assemble incoming responses if the cache line is wider than the bus data width. - logic [CFG.LINE_WIDTH-1:0] response_data; - - if (CFG.LINE_WIDTH > CFG.FILL_DW) begin : g_data_concat - always_ff @(posedge clk_i, negedge rst_ni) begin - if (!rst_ni) begin - response_data[CFG.LINE_WIDTH-CFG.FILL_DW-1:0] <= '0; - end else if (axi_rsp_i.r_valid && axi_req_o.r_ready) begin - response_data[CFG.LINE_WIDTH-CFG.FILL_DW-1:0] - <= response_data[CFG.LINE_WIDTH-1:CFG.FILL_DW]; - end - end - assign response_data[CFG.LINE_WIDTH-1:CFG.LINE_WIDTH-CFG.FILL_DW] = axi_rsp_i.r.data; - end else if (CFG.LINE_WIDTH < CFG.FILL_DW) begin : g_data_slice - localparam int unsigned AddrQueueDepth = CFG.FILL_ALIGN-CFG.LINE_ALIGN; - logic [AddrQueueDepth-1:0] addr_offset; - fifo_v3 #( - .DEPTH ( TransactionQueueDepth ), - .DATA_WIDTH ( AddrQueueDepth ) - ) i_fifo_addr_offset ( - .clk_i ( clk_i ), - .rst_ni ( rst_ni ), - .flush_i ( 1'b0 ), - .testmode_i ( 1'b0 ), - .full_o ( ), // the queue has the same size as the `id_queue` - .empty_o ( ), - .usage_o ( ), - .data_i ( in_req_addr_i[CFG.FILL_ALIGN-1:CFG.LINE_ALIGN] ), - .push_i ( queue_push ), - .data_o ( addr_offset ), - .pop_i ( queue_pop ) - ); - assign response_data = - axi_rsp_i.r.data >> (addr_offset * CFG.LINE_WIDTH); - end else begin : g_data_passthrough - assign response_data = axi_rsp_i.r.data; - end - - // Accept response beats. Upon the last beat, pop the ID off the queue - // and return the response. - always_comb begin : p_response - // Tie-off unused ports - axi_req_o = '0; - axi_req_o.b_ready = 1'b1; - axi_req_o.ar.addr = in_req_addr_i; - axi_req_o.ar.size = $clog2(CFG.FILL_DW/8); - axi_req_o.ar.burst = axi_pkg::BURST_INCR; - axi_req_o.ar.len = $unsigned(BeatsPerRefill-1); - axi_req_o.ar.cache = axi_pkg::CACHE_MODIFIABLE; - axi_req_o.ar_valid = in_req_valid_i & ~queue_full; - - in_rsp_data_o = response_data; - in_rsp_error_o = axi_rsp_i.r.resp[1]; - in_rsp_valid_o = 0; - queue_pop = 0; - axi_req_o.r_ready = 0; - - if (axi_rsp_i.r_valid) begin - if (!axi_rsp_i.r.last) begin - axi_req_o.r_ready = 1; - end else begin - in_rsp_valid_o = 1; - if (in_rsp_ready_i) begin - axi_req_o.r_ready = 1; - queue_pop = 1; - end - end - end - end - -endmodule diff --git a/hw/snitch_icache/test/snitch_icache_l0_tb.sv b/hw/snitch_icache/test/snitch_icache_l0_tb.sv deleted file mode 100644 index f53d76843..000000000 --- a/hw/snitch_icache/test/snitch_icache_l0_tb.sv +++ /dev/null @@ -1,380 +0,0 @@ -// Copyright 2020 ETH Zurich and University of Bologna. -// Solderpad Hardware License, Version 0.51, see LICENSE for details. -// SPDX-License-Identifier: SHL-0.51 - -// Author: Florian Zaruba - -class icache_request #( - parameter int unsigned AddrWidth = 48 -); - rand logic [AddrWidth-1:0] addr; - rand bit flush; - - constraint flush_c { - flush dist { 1 := 2, 0 := 200}; - } - - constraint addr_c { - addr[1:0] == 0; - } -endclass - -class riscv_inst; - rand logic [31:0] inst; - rand bit ctrl_flow; - constraint inst_c { - ctrl_flow dist { 1 := 3, 0 := 10}; - inst[1:0] == 2'b11; - if (ctrl_flow) { - inst[6:0] inside { - riscv_instr::BEQ[6:0], - riscv_instr::JAL[6:0] - }; - // we don't support compressed instructions, make sure - // that we only emit aligned jump targets. - if (inst[6:0] == riscv_instr::BEQ[6:0]) { - inst[8] == 0; - } - if (inst[6:0] == riscv_instr::JAL[6:0]) { - inst[21] == 0; - } - // make sure that we don't emit control flow instructions - } else { - !(inst[6:0] inside { - riscv_instr::BEQ[6:0], - riscv_instr::JAL[6:0] - }); - } - } -endclass - -`include "common_cells/assertions.svh" - -module snitch_icache_l0_tb import snitch_pkg::*; #( - parameter int unsigned AddrWidth = 48, - parameter type addr_t = logic [AddrWidth-1:0], - parameter int NR_FETCH_PORTS = 1, - parameter int L0_LINE_COUNT = 8, - parameter int LINE_WIDTH = 128, - parameter int LINE_COUNT = 0, - parameter int SET_COUNT = 1, - parameter int FETCH_AW = AddrWidth, - parameter int FETCH_DW = 32, - parameter int FILL_AW = AddrWidth, - parameter int FILL_DW = 64, - parameter int L0_EARLY_TAG_WIDTH = 8, - parameter bit EARLY_LATCH = 0, - parameter bit BUFFER_LOOKUP = 0, - parameter bit GUARANTEE_ORDERING = 0 -); - - localparam time ClkPeriod = 10ns; - localparam time TA = 2ns; - localparam time TT = 8ns; - localparam bit DEBUG = 1'b0; - - // backing memory - logic [LINE_WIDTH-1:0] memory [logic [AddrWidth-1:0]]; - - localparam snitch_icache_pkg::config_t CFG = '{ - NR_FETCH_PORTS: NR_FETCH_PORTS, - LINE_WIDTH: LINE_WIDTH, - LINE_COUNT: LINE_COUNT, - L0_LINE_COUNT: L0_LINE_COUNT, - SET_COUNT: SET_COUNT, - PENDING_COUNT: 2, - FETCH_AW: FETCH_AW, - FETCH_DW: FETCH_DW, - FILL_AW: FILL_AW, - FILL_DW: FILL_DW, - EARLY_LATCH: EARLY_LATCH, - BUFFER_LOOKUP: BUFFER_LOOKUP, - GUARANTEE_ORDERING: GUARANTEE_ORDERING, - - FETCH_ALIGN: $clog2(FETCH_DW/8), - FILL_ALIGN: $clog2(FILL_DW/8), - LINE_ALIGN: $clog2(LINE_WIDTH/8), - COUNT_ALIGN: $clog2(LINE_COUNT), - SET_ALIGN: $clog2(SET_COUNT), - TAG_WIDTH: FETCH_AW - $clog2(LINE_WIDTH/8) - $clog2(LINE_COUNT) + 1, - 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, - PENDING_IW: $clog2(2) - }; - - localparam int unsigned IdWidthReq = $clog2(NR_FETCH_PORTS) + 1; - localparam int unsigned IdWidthResp = 2*NR_FETCH_PORTS; - - logic clk, rst; - logic dut_flush_valid; - addr_t dut_addr; - logic dut_valid; - logic [31:0] dut_data; - logic dut_ready; - logic dut_error; - - typedef struct packed { - logic [LINE_WIDTH-1:0] data; - logic error; - logic [IdWidthResp-1:0] id; - } dut_in_t; - - typedef struct packed { - addr_t addr; - logic [IdWidthReq-1:0] id; - } dut_out_t; - - typedef stream_test::stream_driver #( - .payload_t (dut_in_t), - .TA (TA), - .TT (TT) - ) stream_driver_in_t; - - typedef stream_test::stream_driver #( - .payload_t (dut_out_t), - .TA (TA), - .TT (TT) - ) stream_driver_out_t; - - STREAM_DV #( - .payload_t (dut_in_t) - ) dut_in ( - .clk_i (clk) - ); - - STREAM_DV #( - .payload_t (dut_out_t) - ) dut_out ( - .clk_i (clk) - ); - - stream_driver_in_t in_driver = new(dut_in); - stream_driver_out_t out_driver = new(dut_out); - - snitch_icache_l0 #( - .CFG (CFG), - .L0_ID ( 0 ) - ) dut ( - .clk_i (clk), - .rst_ni (~rst), - .enable_prefetching_i (1'b1), - .icache_events_o (), - .flush_valid_i (dut_flush_valid), - .in_addr_i (dut_addr), - .in_valid_i (dut_valid), - .in_data_o (dut_data), - .in_ready_o (dut_ready), - .in_error_o (dut_error), - - .out_req_addr_o (dut_out.data.addr), - .out_req_id_o (dut_out.data.id), - .out_req_valid_o (dut_out.valid), - .out_req_ready_i (dut_out.ready), - - .out_rsp_data_i (dut_in.data.data), - .out_rsp_error_i (dut_in.data.error), - .out_rsp_id_i (dut_in.data.id), - .out_rsp_valid_i (dut_in.valid), - .out_rsp_ready_o (dut_in.ready) - ); - - task static cycle_start; - #TT; - endtask - - task static cycle_end; - @(posedge clk); - endtask - - task static reset; - dut_flush_valid = '0; - dut_addr = '0; - dut_valid = '0; - endtask - - /// Drive DUT request side. - task static send_req ( - /// Request instruction at address - input addr_t addr, - /// Flush the L0 cache. - input logic flush, - /// Obtain the instructions. - output logic [31:0] data - ); - dut_valid <= #TA ~flush; - dut_addr <= #TA addr; - dut_flush_valid <= #TA flush; - cycle_start(); - while (!flush && dut_ready != 1) begin cycle_end(); cycle_start(); end - data <= dut_data; - cycle_end(); - dut_valid <= 0; - dut_addr <= 0; - dut_flush_valid <= 0; - endtask - - localparam int NrDirectedRequests = 100_000; - // Request Port - initial begin - automatic int unsigned stall_cycles; - automatic logic [31:0] data; - automatic logic [31:0] golden; - automatic addr_t addr, immediate; - automatic icache_request #(.AddrWidth (AddrWidth)) req = new; - automatic int requests = 0; - reset(); - @(negedge rst); - req.addr = 0; - req.flush = 0; - forever begin - stall_cycles = $urandom_range(0, 3); - if (requests == 0) $info("Starting Directed Sequence of %d Requests", NrDirectedRequests); - if (requests == NrDirectedRequests) $info("Starting Randomized Sequence"); - // Send request - send_req(req.addr, req.flush, data); - repeat (stall_cycles) @(posedge clk); - // Check Response - if (!req.flush) begin - addr = req.addr >> CFG.LINE_ALIGN << CFG.LINE_ALIGN; - assert(memory.exists(addr)) else $fatal(1, "Address has not been allocated."); - golden = memory[addr][req.addr[CFG.LINE_ALIGN-1:0]*8+:32]; - assert(golden === data) else $fatal(1, "Got: %h Expected: %h", data, golden); - end - // Next request preparation - // Directed Sequence - if (requests < NrDirectedRequests) begin - // Re-randomize requests every 100 cycles - // to pull out of loops. - if (requests % 100 == 0) begin - assert(std::randomize(addr)); - req.addr = addr >> 2 <<2; - req.flush = 1; - end else req.flush = 0; - casez (data) - riscv_instr::BEQ, - riscv_instr::BNE, - riscv_instr::BLT, - riscv_instr::BGE, - riscv_instr::BLTU, - riscv_instr::BGEU: begin - if (data[31]) immediate = $signed({data[31], data[7], data[30:25], data[11:8], 1'b0}); - else immediate = 4; - end - riscv_instr::JAL: begin - immediate = $signed({data[20], data[19:12], data[20], data[30:21], 1'b0}); - end - default: immediate = 4; - endcase - req.addr += immediate; - // Random Sequence - end else begin - assert(req.randomize()); - end - requests++; - if (requests > 2*NrDirectedRequests) $finish(); - end - end - - localparam int unsigned RequestTimeout = 100; - // make sure that we eventually make progress (i.e., a timeout) - `ASSERT(RequestProgress, dut_valid |-> ##[0:RequestTimeout] dut_ready, clk, rst) - - // Response Drivers - mailbox #(dut_out_t) addr_mbx [2]; - semaphore response_lock = new (1); - - initial begin - automatic int unsigned stall_cycles; - automatic dut_out_t dut_out; - for (int i = 0; i < 2**IdWidthReq; i++) - addr_mbx [i] = new(); - out_driver.reset_out(); - @(negedge rst); - repeat (5) @(posedge clk); - 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); - // $info("Requesting from Address: %h, ID: %d", dut_out.addr, dut_out.id); - end - end - - initial begin - in_driver.reset_in(); - @(negedge rst); - repeat (5) @(posedge clk); - - // I couldn't find any better way to describing this than - // manual unrolling. Ugly as fuck. - fork - forever begin - automatic int unsigned stall_cycles; - automatic dut_out_t dut_out; - automatic dut_in_t send_data; - automatic riscv_inst rand_data = new; - automatic addr_t addr; - addr_mbx[0].get(dut_out); - stall_cycles = $urandom_range(1, 10); - repeat (stall_cycles) @(posedge clk); - - send_data.error = 1'b0; - send_data.id = 0; - addr = dut_out.addr >> CFG.LINE_ALIGN << CFG.LINE_ALIGN; - if (!memory.exists(dut_out.addr)) begin - for (int i = 0; i < CFG.LINE_WIDTH/32; i++) begin - assert(rand_data.randomize()); - memory[addr][i*32+:32] = rand_data.inst; - end - end - if (DEBUG) $info("Response for Address: %h, ID: 0, Data: %h", dut_out.addr, memory[addr]); - send_data.data = memory[addr]; - response_lock.get(); - in_driver.send(send_data); - response_lock.put(); - end - forever begin - automatic int unsigned stall_cycles; - automatic dut_out_t dut_out; - automatic dut_in_t send_data; - automatic riscv_inst rand_data = new; - automatic addr_t addr; - addr_mbx[1].get(dut_out); - stall_cycles = $urandom_range(1, 10); - repeat (stall_cycles) @(posedge clk); - - send_data.error = 1'b0; - send_data.id = 1; - addr = dut_out.addr >> CFG.LINE_ALIGN << CFG.LINE_ALIGN; - if (!memory.exists(dut_out.addr)) begin - for (int i = 0; i < CFG.LINE_WIDTH/32; i++) begin - assert(rand_data.randomize()); - memory[addr][i*32+:32] = rand_data.inst; - end - end - if (DEBUG) $info("Response for Address: %h, ID: 1, Data: %h", dut_out.addr, memory[addr]); - send_data.data = memory[addr]; - response_lock.get(); - in_driver.send(send_data); - response_lock.put(); - end - join_none - end - - // Clock generation. - initial begin - rst = 1; - repeat (3) begin - #(ClkPeriod/2) clk = 0; - #(ClkPeriod/2) clk = 1; - end - rst = 0; - forever begin - #(ClkPeriod/2) clk = 0; - #(ClkPeriod/2) clk = 1; - end - end -endmodule diff --git a/hw/snitch_icache/util/compile.sh b/hw/snitch_icache/util/compile.sh deleted file mode 100755 index 1a3678cfa..000000000 --- a/hw/snitch_icache/util/compile.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# Copyright 2020 ETH Zurich and University of Bologna. -# Solderpad Hardware License, Version 0.51, see LICENSE for details. -# SPDX-License-Identifier: SHL-0.51 -# -# Fabian Schuiki -# Andreas Kurth - -set -e - -[ ! -z "$VSIM" ] || VSIM=vsim - -$BENDER script vsim -t test \ - --vlog-arg="-svinputport=compat" \ - --vlog-arg="-override_timescale 1ns/1ps" \ - --vlog-arg="-suppress 2583" \ - --vlog-arg="+cover=sbecft" \ - > compile.tcl -echo 'return 0' >> compile.tcl -$QUESTA_SEPP $VSIM -c -do 'exit -code [source compile.tcl]' diff --git a/hw/snitch_icache/util/run_vsim.sh b/hw/snitch_icache/util/run_vsim.sh deleted file mode 100755 index 42cc47f94..000000000 --- a/hw/snitch_icache/util/run_vsim.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# Copyright 2020 ETH Zurich and University of Bologna. -# Solderpad Hardware License, Version 0.51, see LICENSE for details. -# SPDX-License-Identifier: SHL-0.51 -# -# Fabian Schuiki -# Andreas Kurth - -set -e -ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) - -[ ! -z "$VSIM" ] || VSIM=vsim - -call_vsim() { - echo "log -r /*; run -all" | $QUESTA_SEPP $VSIM -c -coverage -voptargs='+acc +cover=sbecft' "$@" | tee vsim.log 2>&1 - grep "Errors: 0," vsim.log -} - -call_vsim snitch_icache_l0_tb