From c8d518a546b17fbad482a7b3aeb11e3928131a70 Mon Sep 17 00:00:00 2001 From: Cesar Fuguet Date: Sun, 8 Oct 2023 23:49:07 +0200 Subject: [PATCH] vendor: import the HPDcache sources into the vendor subtree Signed-off-by: Cesar Fuguet --- Makefile | 2 + core/Flist.cva6 | 1 + vendor/openhwgroup/cvhpdcache/.gitignore | 6 + vendor/openhwgroup/cvhpdcache/CHANGELOG.md | 80 + vendor/openhwgroup/cvhpdcache/CODEOWNERS | 2 + vendor/openhwgroup/cvhpdcache/LICENSE | 97 + vendor/openhwgroup/cvhpdcache/README.md | 45 + .../docs/hpdcache_spec_document/.gitignore | 3 + .../docs/hpdcache_spec_document/Makefile | 122 + .../docs/hpdcache_spec_document/latexmkrc | 2 + .../release/hpdcache_spec-1.0.0-draft.pdf | Bin 0 -> 568647 bytes .../source/hpdcache_spec.bib | 67 + .../source/hpdcache_spec.tex | 3404 ++++++++++++++++ .../source/hpdcache_spec_changelog.tex | 35 + .../source/hpdcache_spec_preamble.tex | 351 ++ .../images/exported/wave_back_to_back.svg | 4 + .../exported/wave_ready_before_valid.svg | 4 + .../images/exported/wave_ready_when_valid.svg | 4 + .../exported/wave_valid_before_ready.svg | 4 + .../source/images/hpdcache_core.svg | 3436 +++++++++++++++++ .../images/hpdcache_data_ram_organization.svg | 2344 +++++++++++ ...pdcache_request_address_data_alignment.svg | 2016 ++++++++++ .../images/hpdcache_request_arbiter.svg | 428 ++ .../source/images/wave_back_to_back.json | 10 + .../images/wave_ready_before_valid.json | 10 + .../source/images/wave_ready_when_valid.json | 10 + .../images/wave_valid_before_ready.json | 10 + .../supplement/download_wavedrom.sh | 22 + .../docs/hpdcache_spec_document/version | 1 + .../openhwgroup/cvhpdcache/rtl/hpdcache.Flist | 64 + .../cvhpdcache/rtl/hpdcache_cva6.Flist | 35 + .../rtl/include/hpdcache_typedef.svh | 62 + .../rtl/src/common/hpdcache_data_downsize.sv | 187 + .../rtl/src/common/hpdcache_data_upsize.sv | 189 + .../rtl/src/common/hpdcache_demux.sv | 69 + .../rtl/src/common/hpdcache_fifo_reg.sv | 144 + .../rtl/src/common/hpdcache_fxarb.sv | 85 + .../cvhpdcache/rtl/src/common/hpdcache_mux.sv | 79 + .../src/common/hpdcache_prio_1hot_encoder.sv | 43 + .../hpdcache_regbank_wbyteenable_1rw.sv | 63 + .../src/common/hpdcache_regbank_wmask_1rw.sv | 61 + .../rtl/src/common/hpdcache_rrarb.sv | 121 + .../rtl/src/common/hpdcache_sram.sv | 56 + .../src/common/hpdcache_sram_wbyteenable.sv | 58 + .../rtl/src/common/hpdcache_sram_wmask.sv | 58 + .../common/macros/behav/hpdcache_sram_1rw.sv | 60 + .../behav/hpdcache_sram_wbyteenable_1rw.sv | 63 + .../macros/behav/hpdcache_sram_wmask_1rw.sv | 61 + .../cvhpdcache/rtl/src/hpdcache.sv | 658 ++++ .../cvhpdcache/rtl/src/hpdcache.vlt | 29 + .../cvhpdcache/rtl/src/hpdcache_amo.sv | 67 + .../cvhpdcache/rtl/src/hpdcache_cmo.sv | 250 ++ .../rtl/src/hpdcache_core_arbiter.sv | 171 + .../cvhpdcache/rtl/src/hpdcache_ctrl.sv | 760 ++++ .../cvhpdcache/rtl/src/hpdcache_ctrl_pe.sv | 620 +++ .../cvhpdcache/rtl/src/hpdcache_memarray.sv | 120 + .../cvhpdcache/rtl/src/hpdcache_memctrl.sv | 656 ++++ .../rtl/src/hpdcache_miss_handler.sv | 673 ++++ .../cvhpdcache/rtl/src/hpdcache_mshr.sv | 385 ++ .../rtl/src/hpdcache_mshr_to_cache_set.sv | 105 + .../cvhpdcache/rtl/src/hpdcache_pkg.sv | 613 +++ .../cvhpdcache/rtl/src/hpdcache_plru.sv | 138 + .../cvhpdcache/rtl/src/hpdcache_rtab.sv | 666 ++++ .../cvhpdcache/rtl/src/hpdcache_uncached.sv | 965 +++++ .../cvhpdcache/rtl/src/hpdcache_wbuf.sv | 685 ++++ .../rtl/src/hpdcache_wbuf_wrapper.sv | 227 ++ .../rtl/src/hwpf_stride/hwpf_stride.sv | 374 ++ .../rtl/src/hwpf_stride/hwpf_stride_arb.sv | 117 + .../rtl/src/hwpf_stride/hwpf_stride_pkg.sv | 68 + .../src/hwpf_stride/hwpf_stride_snooper.sv | 38 + .../src/hwpf_stride/hwpf_stride_wrapper.sv | 265 ++ .../cva6/cva6_hpdcache_cmo_if_adapter.sv | 186 + .../target/cva6/cva6_hpdcache_if_adapter.sv | 217 ++ .../target/cva6/cva6_hpdcache_params_pkg.sv | 182 + .../target/cva6/cva6_hpdcache_subsystem.sv | 601 +++ .../cva6_hpdcache_subsystem_axi_arbiter.sv | 593 +++ .../src/target/generic/hpdcache_params_pkg.sv | 180 + .../utils/hpdcache_mem_req_read_arbiter.sv | 103 + .../utils/hpdcache_mem_req_write_arbiter.sv | 193 + .../rtl/src/utils/hpdcache_mem_resp_demux.sv | 108 + .../rtl/src/utils/hpdcache_mem_to_axi_read.sv | 95 + .../src/utils/hpdcache_mem_to_axi_write.sv | 148 + vendor/openhwgroup_cvhpdcache.lock.hjson | 14 + vendor/openhwgroup_cvhpdcache.vendor.hjson | 28 + 84 files changed, 25376 insertions(+) create mode 100644 vendor/openhwgroup/cvhpdcache/.gitignore create mode 100644 vendor/openhwgroup/cvhpdcache/CHANGELOG.md create mode 100644 vendor/openhwgroup/cvhpdcache/CODEOWNERS create mode 100644 vendor/openhwgroup/cvhpdcache/LICENSE create mode 100644 vendor/openhwgroup/cvhpdcache/README.md create mode 100644 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/.gitignore create mode 100644 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/Makefile create mode 100644 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/latexmkrc create mode 100644 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/release/hpdcache_spec-1.0.0-draft.pdf create mode 100644 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/hpdcache_spec.bib create mode 100755 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/hpdcache_spec.tex create mode 100755 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/hpdcache_spec_changelog.tex create mode 100755 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/hpdcache_spec_preamble.tex create mode 100755 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_back_to_back.svg create mode 100755 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_ready_before_valid.svg create mode 100755 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_ready_when_valid.svg create mode 100755 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_valid_before_ready.svg create mode 100644 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_core.svg create mode 100755 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_data_ram_organization.svg create mode 100755 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_request_address_data_alignment.svg create mode 100644 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_request_arbiter.svg create mode 100755 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_back_to_back.json create mode 100755 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_ready_before_valid.json create mode 100755 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_ready_when_valid.json create mode 100755 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_valid_before_ready.json create mode 100644 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/supplement/download_wavedrom.sh create mode 100644 vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/version create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/hpdcache.Flist create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/hpdcache_cva6.Flist create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/include/hpdcache_typedef.svh create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_data_downsize.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_data_upsize.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_demux.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_fifo_reg.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_fxarb.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_mux.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_prio_1hot_encoder.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_regbank_wbyteenable_1rw.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_regbank_wmask_1rw.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_rrarb.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_sram.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_sram_wbyteenable.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_sram_wmask.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/macros/behav/hpdcache_sram_1rw.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/macros/behav/hpdcache_sram_wbyteenable_1rw.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/common/macros/behav/hpdcache_sram_wmask_1rw.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache.vlt create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_amo.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_cmo.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_core_arbiter.sv create mode 100755 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_ctrl.sv create mode 100755 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_ctrl_pe.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_memarray.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_memctrl.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_miss_handler.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_mshr.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_mshr_to_cache_set.sv create mode 100755 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_pkg.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_plru.sv create mode 100755 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_rtab.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_uncached.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_wbuf.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_wbuf_wrapper.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_arb.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_pkg.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_snooper.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_wrapper.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_cmo_if_adapter.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_if_adapter.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_params_pkg.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_subsystem.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_subsystem_axi_arbiter.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/target/generic/hpdcache_params_pkg.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_req_read_arbiter.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_req_write_arbiter.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_resp_demux.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_to_axi_read.sv create mode 100644 vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_to_axi_write.sv create mode 100644 vendor/openhwgroup_cvhpdcache.lock.hjson create mode 100644 vendor/openhwgroup_cvhpdcache.vendor.hjson diff --git a/Makefile b/Makefile index f1685fa1e79..f1e832ec22a 100644 --- a/Makefile +++ b/Makefile @@ -47,6 +47,8 @@ $(warning must set CVA6_REPO_DIR to point at the root of CVA6 sources -- doing i export CVA6_REPO_DIR = $(abspath $(root-dir)) endif +export HPDCACHE_DIR = $(CVA6_REPO_DIR)/vendor/openhwgroup/cvhpdcache + support_verilator_4 := $(shell ($(verilator) --version | grep '4\.') > /dev/null 2>&1 ; echo $$?) ifeq ($(support_verilator_4), 0) verilator_threads := 1 diff --git a/core/Flist.cva6 b/core/Flist.cva6 index d4211c9060e..44dde45a4f6 100644 --- a/core/Flist.cva6 +++ b/core/Flist.cva6 @@ -154,6 +154,7 @@ ${CVA6_REPO_DIR}/core/cache_subsystem/cache_ctrl.sv ${CVA6_REPO_DIR}/core/cache_subsystem/cva6_icache_axi_wrapper.sv ${CVA6_REPO_DIR}/core/cache_subsystem/std_cache_subsystem.sv ${CVA6_REPO_DIR}/core/cache_subsystem/std_nbdcache.sv +-F ${CVA6_REPO_DIR}/vendor/openhwgroup/cvhpdcache/rtl/hpdcache_cva6.Flist // Physical Memory Protection // NOTE: pmp.sv modified for DSIM (unchanged for other simulators) diff --git a/vendor/openhwgroup/cvhpdcache/.gitignore b/vendor/openhwgroup/cvhpdcache/.gitignore new file mode 100644 index 00000000000..599abb88196 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/.gitignore @@ -0,0 +1,6 @@ +vnc_logs/ +veloce.map +VRMDATA/ +*.log +*.wlf +*.ucdb diff --git a/vendor/openhwgroup/cvhpdcache/CHANGELOG.md b/vendor/openhwgroup/cvhpdcache/CHANGELOG.md new file mode 100644 index 00000000000..1ce8d2fc85e --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/CHANGELOG.md @@ -0,0 +1,80 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +### Removed + +### Changed + +### Fixed + +## [3.0.0] 2023-10-08 + +### Added + +- Add support for virtually-indexed addressing + +### Fixed + +- Fix forwarding logic of uncacheable Icache response in the cva6 cache subsystem. +- Fix wrong mask signal when implementing the MSHR in registers + +## [2.1.0] - 2023-09-25 + +### Added + +- Add additional configuration to implement MSHR in registers (when the number + of entries is low) + +### Fixed + +- Fix cache data SRAM chip-select generation when word width is different than + 64 bits (e.g. 32 bits) + +## [2.0.0] - 2023-09-18 + +### Added + +- Add parameters in the HPDcache module to define the types of interfaces to + the memory +- Add helper verilog header file with macros to ease the type definition of + interfaces to the memory +- Add new event signals in the HPDCache top module +- Add generic single-port RAM macros with byte-enable signals +- Add parameters in the package to choose between RAM macros implementing + byte-enable or bitmask for the different RAMs instances +- Add additional assertions to verify parameters +- Add additional configuration signal to inhibit write coalescing in the write + buffer + +### Removed + +- Remove base_id ports in the HPDCache top module +- Remove nettype (wire,var) in ports as it looks like is badly supported in + some cases by some simulation tools + +### Changed + +- Split the hpdcache_pkg into: (1) the hpdcache_pkg contains internally defined + parameters; (2) a new hpdcache_params_pkg that defines user parameters +- New selection policy of ready requests in the replay table. It gives priority + to requests in the same linked list. +- The write buffer now accepts writes from requesters in a pending slot when it + is waiting for the internal arbiter to forward the data to the NoC. + +### Fixed + +- Correctly support HPDCACHE_ACCESS_WORDS=1 +- Correctly support HPDCACHE_ACCESS_WORDS=HPDCACHE_CL_WORDS +- Fix width of the nlines count register in the HW memory prefetcher. + +## [1.0.0] - 2023-02-22 + +### Added +- Initial release to the OpenHW Group diff --git a/vendor/openhwgroup/cvhpdcache/CODEOWNERS b/vendor/openhwgroup/cvhpdcache/CODEOWNERS new file mode 100644 index 00000000000..ce692f92417 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/CODEOWNERS @@ -0,0 +1,2 @@ +# Global Owners +* @cfuguet diff --git a/vendor/openhwgroup/cvhpdcache/LICENSE b/vendor/openhwgroup/cvhpdcache/LICENSE new file mode 100644 index 00000000000..279d97adb07 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/LICENSE @@ -0,0 +1,97 @@ +Solderpad Hardware License v2.1 + +This license operates as a wraparound license to the Apache License +Version 2.0 (the “Apache License”) and incorporates the terms and +conditions of the Apache License (which can be found here: +http://apache.org/licenses/LICENSE-2.0), with the following additions and +modifications. It must be read in conjunction with the Apache License. +Section 1 below modifies definitions and terminology in the Apache +License and Section 2 below replaces Section 2 of the Apache License. +The Appendix replaces the Appendix in the Apache License. You may, at +your option, choose to treat any Work released under this license as +released under the Apache License (thus ignoring all sections written +below entirely). + +1. Terminology in the Apache License is supplemented or modified as +follows: + +“Authorship”: any reference to ‘authorship’ shall be taken to read +“authorship or design”. + +“Copyright owner”: any reference to ‘copyright owner’ shall be taken to +read “Rights owner”. + +“Copyright statement”: the reference to ‘copyright statement’ shall be +taken to read ‘copyright or other statement pertaining to Rights’. + +The following new definition shall be added to the Definitions section of +the Apache License: + +“Rights” means copyright and any similar right including design right +(whether registered or unregistered), rights in semiconductor +topographies (mask works) and database rights (but excluding Patents and +Trademarks). + +The following definitions shall replace the corresponding definitions in +the Apache License: + +“License” shall mean this Solderpad Hardware License version 2.1, being +the terms and conditions for use, manufacture, instantiation, adaptation, +reproduction, and distribution as defined by Sections 1 through 9 of this +document. + +“Licensor” shall mean the owner of the Rights or entity authorized by the +owner of the Rights that is granting the License. + +“Derivative Works” shall mean any work, whether in Source or Object form, +that is based on (or derived from) the Work and for which the editorial +revisions, annotations, elaborations, or other modifications represent, +as a whole, an original work of authorship or design. For the purposes of +this License, Derivative Works shall not include works that remain +reversibly separable from, or merely link (or bind by name) or physically +connect to or interoperate with the Work and Derivative Works thereof. + +“Object” form shall mean any form resulting from mechanical +transformation or translation of a Source form or the application of a +Source form to physical material, including but not limited to compiled +object code, generated documentation, the instantiation of a hardware +design or physical object or material and conversions to other media +types, including intermediate forms such as bytecodes, FPGA bitstreams, +moulds, artwork and semiconductor topographies (mask works). + +“Source” form shall mean the preferred form for making modifications, +including but not limited to source code, net lists, board layouts, CAD +files, documentation source, and configuration files. + +“Work” shall mean the work of authorship or design, whether in Source or +Object form, made available under the License, as indicated by a notice +relating to Rights that is included in or attached to the work (an +example is provided in the Appendix below). + +2. Grant of License. Subject to the terms and conditions of this License, +each Contributor hereby grants to You a perpetual, worldwide, +non-exclusive, no-charge, royalty-free, irrevocable license under the +Rights to reproduce, prepare Derivative Works of, make, adapt, repair, +publicly display, publicly perform, sublicense, and distribute the Work +and such Derivative Works in Source or Object form and do anything in +relation to the Work as if the Rights did not exist. + +APPENDIX + +Copyright 2023 CEA* +*Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + +SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + +Licensed under the Solderpad Hardware License v 2.1 (the “License”); you +may not use this file except in compliance with the License, or, at your +option, the Apache License version 2.0. You may obtain a copy of the +License at + +https://solderpad.org/licenses/SHL-2.1/ + +Unless required by applicable law or agreed to in writing, any work +distributed under the License is distributed on an “AS IS” BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations +under the License. diff --git a/vendor/openhwgroup/cvhpdcache/README.md b/vendor/openhwgroup/cvhpdcache/README.md new file mode 100644 index 00000000000..76f638ad8fd --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/README.md @@ -0,0 +1,45 @@ +# OpenHW Core-V High-Performance L1 Dcache (CV-HPDcache) + +The HPDcache is an open-source High-Performance, Multi-requester, Out-of-Order L1 Dcache for RISC-V cores and accelerators. + + +## Directory Structure + + + + + + + + + + + + + + + + + + + + + + +
DirectoryDescription
rtlContains the file lists to be used for the compiling of the HPDcache
rtl/srcContains the SystemVerilog RTL sources of the HPDcache
rtl/src/targetContains processor-dependent sources (e.g. adapter modules for the CVA6 core)
docsContains documentation of the HPDcache
+ + +## Documentation + +The HPDcache specification document can be found in the *docs/hpdcache_spec_document* folder. +It is written in LaTeX. +You cand find pre-compiled PDF documents in *docs/hpdcache_spec_document/release*. + +If you need to recompile the specification document, a dedicated *Makefile* is in the specification folder. +This *Makefile* needs the *latexmk* command-line tool (included in most common LaTeX distributions) and the *inkscape* tool to convert SVG images into PDF. + + +## Licensing + +The HPDcache is released under the Solderpad Hardware License (version 2.1). +Please refer to the [LICENSE](LICENSE) file for further information. diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/.gitignore b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/.gitignore new file mode 100644 index 00000000000..4c96dcadd6a --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/.gitignore @@ -0,0 +1,3 @@ +build/ +pdf/ +supplement/package diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/Makefile b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/Makefile new file mode 100644 index 00000000000..a9fd0c4fe61 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/Makefile @@ -0,0 +1,122 @@ +## +## Copyright 2023 CEA* +## *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) +## +## SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +## +## Licensed under the Solderpad Hardware License v 2.1 (the “License”); you +## may not use this file except in compliance with the License, or, at your +## option, the Apache License version 2.0. You may obtain a copy of the +## License at +## +## https://solderpad.org/licenses/SHL-2.1/ +## +## Unless required by applicable law or agreed to in writing, any work +## distributed under the License is distributed on an “AS IS” BASIS, WITHOUT +## WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +## License for the specific language governing permissions and limitations +## under the License. +## +## Author(s): Cesar Fuguet +## Date: February, 2023 +## Description: Makefile for the specification document of the HPDcache +## hardware IP +## +LATEXMK = latexmk -pdf +INKSCAPE = inkscape --without-gui +PDFVIEWER = evince +RM = rm -rf +RMDIR = rmdir -p +CP = cp -f +ECHO = echo -e +MKDIR = mkdir -p + +PDF_DIR = pdf +AUX_DIR = build +SOURCE_DIR = source +RELEASE_DIR = release + +VERSION = $(shell cat version) + +TARGET = hpdcache_spec +TEX_SOURCES = $(SOURCE_DIR)/$(TARGET).bib \ + $(SOURCE_DIR)/hpdcache_spec_changelog.tex \ + $(SOURCE_DIR)/hpdcache_spec_preamble.tex \ + $(AUX_DIR)/hpdcache_data_ram_organization.pdf \ + $(AUX_DIR)/hpdcache_request_arbiter.pdf \ + $(AUX_DIR)/hpdcache_core.pdf \ + $(AUX_DIR)/hpdcache_request_address_data_alignment.pdf \ + $(AUX_DIR)/hpdcache_data_ram_organization.emf \ + $(AUX_DIR)/hpdcache_request_arbiter.emf \ + $(AUX_DIR)/hpdcache_core.emf \ + $(AUX_DIR)/hpdcache_request_address_data_alignment.emf \ + $(AUX_DIR)/wave_ready_before_valid.pdf \ + $(AUX_DIR)/wave_valid_before_ready.pdf \ + $(AUX_DIR)/wave_ready_when_valid.pdf \ + $(AUX_DIR)/wave_back_to_back.pdf \ + $(AUX_DIR)/wave_ready_before_valid.emf \ + $(AUX_DIR)/wave_valid_before_ready.emf \ + $(AUX_DIR)/wave_ready_when_valid.emf \ + $(AUX_DIR)/wave_back_to_back.emf + +LATEXMK_ARGS = -bibtex \ + $(if $(VERBOSE),,-silent) \ + -pretex='\newcommand{\docversion}{$(VERSION)}' \ + -usepretex + +vpath %.svg $(SOURCE_DIR)/images +vpath %.svg $(SOURCE_DIR)/images/exported + +all: + @$(ECHO) "usage: make [target]\n" + @$(ECHO) "Target candidates:\n" + @$(ECHO) "pdf generate PDF document" + @$(ECHO) "release make a release of the PDF document" + @$(ECHO) "view view PDF document" + @$(ECHO) "clean clean auxiliary files" + @$(ECHO) "clean_pdf clean PDF file" + @$(ECHO) "distclean clean all generated files" + +.PHONY: release +release: $(RELEASE_DIR)/$(TARGET)-$(VERSION).pdf + +$(RELEASE_DIR)/$(TARGET)-$(VERSION).pdf: $(PDF_DIR)/$(TARGET).pdf + @$(MKDIR) $(dir $@) + $(CP) $< $@ + +.PHONY: pdf +pdf: $(PDF_DIR)/$(TARGET).pdf + +$(PDF_DIR)/$(TARGET).pdf: $(AUX_DIR)/$(TARGET).pdf + @$(MKDIR) $(dir $@) + $(CP) $< $@ + +$(AUX_DIR)/$(TARGET).pdf: $(SOURCE_DIR)/$(TARGET).tex \ + $(TEX_SOURCES) + @$(MKDIR) $(dir $@) + $(LATEXMK) $(LATEXMK_ARGS) --output-directory=$(dir $@) $< + +$(AUX_DIR)/%.pdf: %.svg + @$(MKDIR) $(dir $@) + $(INKSCAPE) --export-pdf=$@ --export-area-drawing $< + +$(AUX_DIR)/%.emf: %.svg + @$(MKDIR) $(dir $@) + $(INKSCAPE) --export-emf=$@ --export-area-drawing $< + +.PHONY: view +view: $(PDF_DIR)/$(TARGET).pdf + @$(ECHO) "Opening PDF viewer..." + @$(PDFVIEWER) $< >&/dev/null & + +.PHONY: clean clean_pdf distclean +clean: + @$(ECHO) "Cleaning build directory..." + @$(RM) $(AUX_DIR) + +clean_pdf: + @$(ECHO) "Cleaning generated PDF file..." + @$(RM) $(PDF_DIR)/$(TARGET).pdf + @$(RMDIR) $(PDF_DIR) >&/dev/null || true + +distclean: clean clean_pdf diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/latexmkrc b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/latexmkrc new file mode 100644 index 00000000000..364f8350542 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/latexmkrc @@ -0,0 +1,2 @@ +$ENV{'TEXINPUTS'}=':source:source/images:source/images/exported:build:'; +$ENV{'BIBINPUTS'}=':source:'; diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/release/hpdcache_spec-1.0.0-draft.pdf b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/release/hpdcache_spec-1.0.0-draft.pdf new file mode 100644 index 0000000000000000000000000000000000000000..33de1b69438b6f48cf6a1c725125313b2235711f GIT binary patch literal 568647 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�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 1}$\\ + $\rightarrow$~The \ac{MSHR} behaves as a fully-associative access array.\\ + \midrule + When $\mathsf{CONF\_HPDCACHE\_MSHR\_SETS > 1}~\text{and}~\mathsf{CONF\_HPDCACHE\_MSHR\_WAYS = 1}$\\ + $\rightarrow$~The \ac{MSHR} behaves as a direct access array.\\ + \midrule + When $\mathsf{CONF\_HPDCACHE\_MSHR\_SETS > 1}~\text{and}~\mathsf{CONF\_HPDCACHE\_MSHR\_WAYS > 1}$\\ + $\rightarrow$~The \ac{MSHR} behaves as a set-associative access array\\ +\end{tabular} + +A high number of entries in the \ac{MSHR} allows to overlap multiple accesses to the memory, and hides its latency. +Of course, the more entries there are, the more area the \ac{MSHR} consumes. +Therefore, the system architect must choose \ac{MSHR} parameters depending on a combination of memory latency, memory throughput, required area and performance, and the capability of requesters to issue multiple read transactions. + +\begin{tcolorbox}[colback=red!10!white, + colframe=white!10!red, + title=\textbf{Important}, + center, valign=top, halign=left, + center title, + width=.950\linewidth] +Regarding the last condition, regardless whether the requesters can issue multiple read requests, the hardware memory prefetcher exploits having multiple in-flight read miss requests. +\end{tcolorbox} + +An entry in the \ac{MSHR} contains the following information: + +\begin{center} +\begin{tabular}{lccccc} +\toprule% +{\bf Bits} &% +T &% +R &% +S &% +W &% +1 \\ +\midrule +{\bf Description} &% +MSHR Tag &% +Request ID &% +Source ID &% +Word Index &% +Need Response\\ +\end{tabular} + +\begin{tabular}{ll} +\toprule% +{\bf Field} &% +{\bf Width} \\ +\midrule% +MSHR tag (T) &% +$\mathsf{T = HPDCACHE\_NLINE\_WIDTH - log_2(CONF\_HPDCACHE\_MSHR\_SETS)}$ \\ +\midrule% +Request ID (R) &% +$\mathsf{R = CONF\_HPDCACHE\_REQ\_TRANS\_ID\_WIDTH}$ \\ +\midrule% +Source ID (S) &% +$\mathsf{S = CONF\_HPDCACHE\_REQ\_SRC\_ID\_WIDTH}$ \\ +\midrule% +Word Index (W) &% +$\mathsf{W = log_2(CONF\_HPDCACHE\_CL\_WORDS})$ \\ +\end{tabular} +\end{center} + +\subsubsection{\acs*{MSHR} implementation} +\seclabel{mshr_implementation} + +In order to limit the area cost of the \ac{MSHR}, it can be implemented using SRAM macros. +The depth of the macros is $\mathsf{CONF\_HPDCACHE\_MSHR\_SETS\_PER\_RAM}$. +Multiple ways, for the same set, can be put side-by-side in the same SRAM word ($\mathsf{CONF\_HPDCACHE\_MSHR\_WAYS\_PER\_RAM\_WORD}$), therefore the width is a multiple of $\mathsf{HPDCACHE\_MSHR\_ENTRY = T + R + S + W + 1}$ bits. +The total number of SRAM macros is: + +\begin{equation*} +\begin{split} +\mathsf{(CONF\_HPDCACHE\_MSHR\_WAYS/CONF\_HPDCACHE\_MSHR\_WAYS\_PER\_RAM\_WORD)\times} \\ +\mathsf{\lceil{}CONF\_HPDCACHE\_MSHR\_SETS/CONF\_HPDCACHE\_MSHR\_SETS\_PER\_RAM{}\rceil} +\end{split} +\end{equation*} + +SRAM macros shall be selected depending on the required number of entries, and the target technology node. Additional information about \ac{MSHR} SRAM macros can be found in \apxref{ram_macros}. +When the number of entries is low (e.g. sets times ways are less than 16), it is generally better to implement the \ac{MSHR} using flip-flops. + +This makes \ac{MSHR} fully-associative and thus removes associativity conflicts. + + +\section{Uncacheable Handler} + +This block is responsible for handling uncacheable (see \secref{if_req_uncacheable}) load and store requests, as well as atomic requests (regardless of whether they are cacheable or not). +For more information about atomic requests see \charef{amo}. + +All requests handled by this block produce a request to the memory. +This request to the memory is issued through the memory uncached interfaces. +Uncacheable read requests are forwarded to the memory through the memory read uncached interface (\tabref{if_mem_uc_read}); +and uncacheable write requests or atomic requests are forwarded through the memory write uncached interface (\tabref{if_mem_uc_write}). + + +\section{\acf{CMO} Handler} + +This block is responsible for handling \acp{CMO}. +\acp{CMO} are special requests from requesters that address the cache itself, and not the memory nor a peripheral. +These operations allow to either invalidate designated cachelines in the cache, or produce explicit memory read and write fences. + +The complete list of supported \acp{CMO} is detailed in \charef{cmo}. + +\section{Cache Directory and Data} + +\subsection{RAM Organization} +\seclabel{dir_data_ram_implementation} + +The \ac{HPDcache} cache uses RAM macros for the directory and data parts of the cache. +These RAM macros are synchronous, read/write, single-port RAMs. +Additional information about RAM macros in the cache can be found in \apxref{ram_macros}. + +The organization of the RAMs, for the directory and the data, targets the following: +\begin{enumerate}[itemsep=1em] +\item {\bf High memory bandwidth to/from the requesters} + +To improve performance, the organization allows to read one data word (1, 2, 4, 8, 16 or 32 bytes) per cycle, with a latency of one cycle. + +\item {\bf Low energy-consumption} + +To limit the energy-consumption, the RAMs are organized in a way that the cache enables only a limited number of RAM macros. +This number depends on the number of requested bytes, and it also depends on the target technology. +Depending on the target technology, the RAM macros have different trade-offs between width, depth and timing (performance). + +\item {\bf Small RAM footprint} + +To limit the footprint of RAMs, the selected organization implements a small number of RAMs macros. +The macros are selected in a way that they are as deep and as wide as possible. +The selected ratios (depth x width) depend on the target technology as explained above. + +\end{enumerate} + +\subsection{Example cache data/directory RAM organization} + +\Figref{dcache_ram_organization} illustrates an example organization of the RAMs. +The illustrated organization allows to implement 32 KB of data cache (128 sets, 4 ways, and 64 bytes lines). +This example organization has a refilling latency of two cycles because the cache needs to write two different entries on a given memory cut. + +\begin{figure}[htbp] + \includegraphics[width=\textwidth]{hpdcache_data_ram_organization.pdf} + \caption{\figlabel{dcache_ram_organization}Data Cache Micro-Architecture} +\end{figure} + +The example RAM organization in \figref{dcache_ram_organization} allows to access from 1 to 32 bytes of a given cacheline per cycle. + +The energy consumption is dependent on the length of the access. Accesses from 1 to 8 bytes need to read two memory cuts (one containing ways 0 and 1, and the other containing ways 2 and 3); accesses from 8 to 16 bytes need to read 4 memory cuts; and so on. For reading 24 to 32 bytes, the cache needs to access all the cuts at the same time (8 cuts). + +\section{\acf*{RTAB}} + +The \ac{RTAB} is implemented as an array of linked lists. +It is a fully-associative multi-entry buffer, where each valid entry, belongs to a linked list. +It is implemented in flip-flops. +The linked lists contain a list of requests that target the same cacheline. +There can be multiple linked lists, but each shall target a different cacheline. +The head of each linked list contains the oldest request while the tail contains the newest request. +The requests are processed from the head to the tail in order to respect the \acp{MCR} explained in section \secref{rtab_mcr}. + +Regarding the pop operation (extracting a ready request from the replay table), it is possible that once the request is replayed, some of the resources it needs are again busy. +Therefore, the request needs to be put on-hold again. +In this case, the request needs to keep its position as head of the linked list. +This is to preserve the program order. +For this reason, the pop operation is implemented as a two-step operation: pop then commit, or pop then rollback. +The commit operation allows to actually remove the request, while the rollback allows to undo the pop. + +An entry of the \ac{RTAB} has the following structure (LL means Linked List): + +\begin{center} +\begin{tabular}{p{.15\linewidth}p{.10\linewidth}p{.10\linewidth}p{.10\linewidth}p{.10\linewidth}p{.07\linewidth}} + \toprule% + Request \mbox{($\approx$200 bits)} & \mbox{LL tail} \mbox{(1 bit)} & \mbox{LL head} \mbox{(1 bit)} & \mbox{LL next} \mbox{(2-3 bits)} & Deps \mbox{(5 bits)} & Valid \mbox{(1 bit)} \\ + \midrule% +\end{tabular} +\end{center} + +\begin{itemize} +\item Request: contains the on-hold request from the core (data + meta-data). +\item LL tail: indicates if the entry is the tail of a linked list. +\item LL head: indicates if the entry is the head of a linked list. +\item LL next: designates the next (older) request in the linked list. +\item Deps bits: indicates the kind of dependency that keeps the request on-hold. +\item Valid: indicates if the entry contains valid information (if unset the entry is free). +\end{itemize} + +The following table briefly describes the possible dependencies between memory requests. +For each kind of dependency, there is a corresponding bit in the "deps bits" field of \ac{RTAB} entries. + +\begin{tabular}{p{.30\linewidth}p{.70\linewidth}} + \toprule% + \bf Dependency + & \bf Description \\ + \midrule% + MSHR\_hit + & There is an outstanding miss request on the target address \\ + \midrule% + MSHR\_full + & The MSHR is full \\ + \midrule% + MISS\_handler\_busy + & The MISS HANDLER is busy and cannot send a new miss request \\ + \midrule% + WBUF\_hit + & There is a match with a open, closed, or sent entry in the write buffer \\ + \midrule% + WBUF\_not\_ready + & There is a match with a closed entry in the write buffer or the write-buffer is full\\ +\end{tabular} + +\paragraph{\ac{RTAB} operations}\mbox{} + +The \ac{RTAB} implements the following operations: + +\begin{tabular}{p{.30\linewidth}p{.70\linewidth}} + \toprule + \textbf{Operation} & \textbf{Description} \\ + \midrule + $\mathsf{rtab\_alloc()}$ & Allocate a new linked list \\ + \midrule + $\mathsf{rtab\_alloc\_and\_link()}$ & Allocate a new entry and link it to an existing linked list \\ + \midrule + $\mathsf{rtab\_pop\_try()}$ & Get a ready request from one of the linked list (wihout actually removing it from the list) \\ + \midrule + $\mathsf{rtab\_pop\_commit()}$ & Actually remove a popped request from the list \\ + \midrule + $\mathsf{rtab\_pop\_rollback()}$ & Rollback a previously popped request (with a possible update of its dependencies) \\ + \midrule + $\mathsf{rtab\_find\_ready()}$ & Find a ready request among the heads of valid linked lists \\ + \midrule + $\mathsf{rtab\_find\_empty()}$ & Find an empty request \\ + \midrule + $\mathsf{rtab\_empty()}$ & Is the RTAB empty ? \\ + \midrule + $\mathsf{rtab\_full()}$ & Is the RTAB full ? \\ + \midrule + $\mathsf{update\_deps()}$ & Update the dependency bits of valid requests \\ +\end{tabular} + +\begin{lstlisting}[language=c] +int rtab_alloc(req_t r, deps_t d) +{ + int index = rtab_find_empty_entry(); + rtab[index] = { + valid : 1, + deps : d, + ll_head : 1, + ll_tail : 1, + ll_next : 0, + request : r + }; + return index; +} +\end{lstlisting} + +\begin{lstlisting} +int rtab_alloc_and_link(req_t r, int n) +{ + int index = rtab_find_empty_entry(); + + // replace the tail of the linked list + rtab[n].ll_tail = 0; + + // add the new request as the tail of the linked list + rtab[index] = { + valid : 1, + deps : 0, + ll_head : 0, + ll_tail : 1, + ll_next : n, + request : r + }; + + return index; +} +\end{lstlisting} + +\begin{lstlisting} +req_t rtab_pop_try(int &index) +{ + index = rtab_find_ready_entry(); + + // Temporarily unset the head bit. This is to prevent the + // request to be rescheduled. + rtab[index].ll_head = 0; + + return rtab[index].request; +} +\end{lstlisting} + +\begin{lstlisting} +void rtab_pop_commit(int index) +{ + // Change the head of the popped linked list + // (look for a valid entry with the next field + // pointing to the popped entry) + for (int i = 0; i < RTAB_NENTRIES; i++) { + if (rtab[i].valid && (i != index) && (rtab[i].next == index) { + rtab[i].ll_head = 1; + } + } + + rtab[index].valid = 0; +} +\end{lstlisting} + +\begin{lstlisting} +void rtab_pop_rollback(int index, bitvector deps) +{ + rtab[index].ll_head = 1; + rtab[index].deps = deps; +} +\end{lstlisting} + +\begin{lstlisting} +int rtab_find_ready_entry(int last) +{ + // choose a ready entry using a round-robin policy + int i = (last + 1) % RTAB_NENTRIES; + for (;;) { + // ready entry found + if (rtab[i].valid && rtab[i].ll_head && (rtab[i].deps == 0)) + return i; + + // there is no ready entry + if (i == last) + return -1; + + i = (i + 1) % RTAB_NENTRIES; + } +} +\end{lstlisting} + +\begin{lstlisting} +int rtab_find_empty_entry() +{ + for (int i = 0; i < RTAB_NENTRIES; i++) + if (!rtab[i].valid) + return i; + + return -1; +} +\end{lstlisting} + +\begin{lstlisting} +bool rtab_is_full() +{ + return (rtab_find_empty_entry() == -1); +} +\end{lstlisting} + +\begin{lstlisting} +int rtab_is_empty() +{ + for (int i = 0; i < RTAB_NENTRIES; i++) + if (rtab[i].valid) + return 0; + + return 1; +} +\end{lstlisting} + +\subsection{\ac{RTAB} integration in the cache} + +The data cache has a 3-stages pipeline. +The \ac{RTAB} will be used in stages 0 and 1 (st0 and st1). +The following table summarizes the actions performed on the \ac{RTAB}: + +{\footnotesize% +\begin{tabular}{% +p{.12\linewidth}p{.17\linewidth}p{.11\linewidth}p{.11\linewidth}p{.11\linewidth}p{.11\linewidth}p{.11\linewidth}p{.11\linewidth}} + \toprule% + {\bf \mbox{New Request}} + & {\bf Match @ in \ac{RTAB}} + & {\bf Match @ in \ac{MSHR}} + & {\bf Match @ in \ac{WBUF}} + & {\bf Cache Miss AND \ac{MSHR} is full} + & {\bf Cache Miss AND Miss Handler is not ready} + & {\bf \ac{WBUF} is full} \\ + \midrule% + LOAD + & $\mathsf{alloc\_and\_link}$ (st0) + & $\mathsf{alloc\_new}$ (st1) + & $\mathsf{alloc\_new}$ (st1) + & $\mathsf{alloc\_new}$ (st1) + & $\mathsf{alloc\_new}$ (st1) + & $\phi$ \\ + \midrule% + STORE + & $\mathsf{alloc\_and\_link}$ (st0) + & $\mathsf{alloc\_new}$ (st1) + & $\mathsf{alloc\_new}$ (st1) (if $\mathsf{wbuf\_entry}$ is closed) + & $\phi$ + & $\phi$ + & $\mathsf{alloc\_new}$ (st1) \\ + \midrule% +\end{tabular}} + +\subsection{Policy for taking new requests in the data cache} + +With the \ac{RTAB}, the cache has three possible sources of requests: +\begin{enumerate} +\item Requesters (new requests); +\item the \ac{RTAB} (on-hold requests); +\item the miss handler (refill requests). +\end{enumerate} + +The policy to choose the request is as follows: + +\begin{lstlisting} +rtab_req = rtab_find_ready_entry(); +if (rtab_is_full()) { + new_req = rtab_req; +} else { + new_req = (rtab_req != -1) ? rtab_req : core_req; +} + +accepted_req = round_robin(new_req, refill_req); +\end{lstlisting} + +To summarize: \ac{RTAB} ready requests have higher priority than core requests (this is to flush the pipeline as fast as possible). +However, if the \ac{RTAB} is full, the cache does not accept core requests because if they need to be put on-hold that could cause a deadlock. +Then, between the refill requests, the \ac{RTAB} or the core requests, the data cache applies a round-robin policy. + +\subsection{Possible improvements for the \acs*{RTAB} integration} + +\begin{itemize} + \item Avoid introducing a NOP after an entry is replayed (popped). + This is currently done to simplify the resolution of a concurrent \verb$alloc_and_link$ and \verb$pop_commit$ where the request being allocated depends on the one being popped. +\end{itemize} + + +\section{Write-buffer} + +This cache implements a write-through policy. +In this policy, the write accesses from requesters are systematically transferred to the memory, regardless of whether the write access hits or misses in the \ac{HPDcache}. + +To decouple the acknowledgement from the memory to the \ac{HPDcache}, and the acknowledgement from the \ac{HPDcache} to the requester, this \ac{HPDcache} implements a write-buffer. +The goal is to increase the performance: the requester does not wait the acknowledgement from the memory, which may suffer from a very high latency. +Additionally, to improve the bandwidth utilization of data channels in the \ac{NoC}, the write-buffer implements coalescing of write data. + +The write-buffer implements two different parts: directory and data. +The directory enables tracking of active writes. +The data buffers are used to coalesce writes from the requester. +Entries in the data buffers are usually wider ($\mathsf{CONF\_HPDCACHE\_WBUF\_WORDS}$) than the data interface of requesters. +This is to enable the coalescing of multiple writes onto contiguous addresses. + +A given entry in the directory of the write-buffer may be in four different states: + +\begin{center} +\begin{tabular}{lp{.8\linewidth}} +\textbf{FREE} & The entry is available.\\ +\textbf{OPEN} & The entry is currently used by a previous write access. The entry accepts new writes (coalescing).\\ +\textbf{PEND} & The entry is waiting to be sent to the memory. In this state, the entry continues to accept new writes (coalescing).\\ +\textbf{SENT} & The entry was forwarded to the memory, and is waiting for the acknowledgement.\\ +\end{tabular} +\end{center} + +\subsection{Memory Write Consistency Model} +\seclabel{wbuf_mcr} + +The \ac{HPDcache} complies with the \ac{RVWMO} memory consistency model. +Regarding writes, in this consistency model, there are two important properties: + +\begin{enumerate} + +\item The order in which write accesses on different addresses are forwarded to memory MAY differ from the order they arrived from the requester (program order); + +\item Writes onto the same address, MUST be visible in order. If there is a data written by a write A on address @x followed by an another write B on the same address, the data of A cannot be visible after the processing of B. + +\end{enumerate} + +The second property allows write coalescing if the hardware ensures that the last write persists. + +The write-buffer exploits the first property. +Multiple "in-flight" writes are supported due to the multiple directory and data entries. +These writes can be forwarded to the memory in an order different than the program order. + +To comply with the second property, the write-buffer does not accept a write when there is an address conflict with a \textbf{SENT} entry. +In that case, the write is put on-hold following the policy described in \secref{onhold}. +The system may choose to relax the constraint of putting a write on-hold in case of an address conflict with a \textbf{SENT} entry. +This can be relaxed when the \ac{NoC} guaranties in-order delivery. +The runtime configuration bit~$\mathsf{cfig\_wbuf.S}$~(see \tabref{cfig_wbuf}) shall be set to 0 to relax this dependency. + +\subsection{Functional Description} +\seclabel{wbuf_funcdesc} + +When an entry of the write-buffer directory is in the \textbf{OPEN} or \textbf{PEND} states, there is an allocated data buffer, and it contains data that has not yet been sent to the memory. +When an entry of the write-buffer directory is in the \textbf{SENT} state, the corresponding data was transferred to the memory, and the corresponding data buffer was freed (and can be reused for another write). +A given entry in the write-buffer directory goes from \textbf{FREE} to \textbf{OPEN} state when a new write is accepted, and cannot be coalesced with another \textbf{OPEN} or \textbf{PEND} entry (e.g. not in the same address range). + +A directory entry passes from \textbf{OPEN} to \textbf{PEND} after a given number of clock cycles. +This number of clock cycles depends on different runtime configurable values. +Each directory entry contains a life-time counter. +This counter starts at 0 when a new write is accepted (\textbf{FREE}->\textbf{OPEN}), and incremented each cycle while in \textbf{OPEN}. +When the counter reaches~$\mathsf{cfig\_wbuf.threshold}$~(see \tabref{cfig_wbuf}), the write-buffer directory entry goes to \textbf{PEND}. +Another runtime configurable bit, $\mathsf{cfig\_wbuf.R}$~(see \tabref{cfig_wbuf}), defines the behavior of an entry when a new write is coalesced into an \textbf{OPEN} entry. +If this last configuration bit is set, the life-time counter is reset to 0 when a new write is coalesced. +Otherwise, the counter keeps its value. + +The life-time of a given write-buffer directory entry is longer than the life-time of a data entry. +A given directory entry is freed (\textbf{SENT}->\textbf{FREE}) when the write acknowledgement is received from the memory. +The number of cycles to get an acknowledgement from the memory may be significant and it is system-dependent. +Thus, to improve utilization of data buffers, the number of entries in the directory is generally greater than the number of data buffers. +However, there is a trade-off between area and performance because the area cost of data buffers is the most critical cost in the write-buffer. +The synthesis-time parameters $\mathsf{CONF\_HPDCACHE\_WBUF\_DIR\_ENTRIES}$ and $\mathsf{CONF\_HPDCACHE\_WBUF\_DATA\_ENTRIES}$ define the number of entries in the write-buffer directory and write-buffer data, respectively. + +When the $\mathsf{cfig\_wbuf.I}$~(see \tabref{cfig_wbuf}) is set, the write buffer does not perform any write coalescing. This means that the entry passes from \textbf{FREE} to \textbf{PEND} (bypassing the \textbf{OPEN} state). The $\mathsf{cfig\_wbuf.threshold}$ is ignored by the write buffer. While an entry is in the \textbf{PEND} state, and $\mathsf{cfig\_wbuf.I}$ is set, that entry does not accept any new writes, and only waits for the data to be sent. + +\Todo{Investigate an implementation of the data buffers in RAM. +At most, only one entry is written and read per cycle in the write buffer. +Thus an implementation with a 2-ports RAM could be more efficient. +Write masks (at least at byte granularity) in the RAM are necessary to allow the write coalescing} + +\subsubsection{Memory Fences} + +In multi-core systems, or more generally, in systems with multiple \acs{DMA}-capable devices, when synchronization is needed, it is necessary to implement memory fences from the software. +In the case of RISC-V, there is specific instructions for this (i.e. fence). + +Fence instructions shall be forwarded to the cache to ensure ordering of writes. The fence will force the write-buffer to send all pending writes before accepting new ones. +This cache implements two ways of signalling a fence: sending a specific \ac{CMO} instruction from the core (described later on \charef{cmo}), or by asserting $\mathsf{wbuf\_flush\_i}$ pin (during one cycle). + + +\section{Cache-coherency} +\seclabel{cache_coherency} + +The current version of the cache does not implement any hardware cache-coherency protocol. + +In multi-core systems integrating this cache, cache-coherency needs to be enforced by the software. To this end, this cache provides cache invalidation instructions among the supported \acp{CMO}. These are described in \charef{cmo}. These can be used to solve the cache-obsolescence problem. + +As the cache implements a write-through policy, there is no memory-obsolescence problem. This is because all writes are forwarded to the memory. + + +%\textit{Note: To solve the memory obsolescence problem using a write-back policy, we need to implement dirty bits in the cache directory. +%However, to support a byte granularity, we would need to implement 64 bits per cacheline, which represents an overhead of almost 13\% in the RAM area of the cache (considering a 32 KB cache).} + +% \section{Write-back Data} + +% The directory implements a given number of dirty bits per cacheline. +%Dirty bits indicate which data has been locally modified in the cache and therefore, the next levels of memory contain an obsolete state. +%In case of a cacheline eviction, only "dirty" data is actually write-back upstream. + +% In the simplest case, L1 caches implement a single dirty bit. +%This means that anytime a modified cacheline needs to be evicted, even if a single bit has been modified, the entire cacheline is written-back. +%However, this behavior may cause problems when two different cores write in the same cacheline but different bytes (this situation is known as false-sharing). +%In that case, if no special mechanism is implemented, when a core writes-back a cacheline, it will potentially overwrite the changes from another core. +%When a write-invalidate cache-coherency protocol is implemented, this situation is avoided because a single core can own a modified cacheline. +%However, we do not implement a hardware cache-coherency protocol. + +% In our case, to avoid the false-sharing problem we need a finer granularity for indicating the dirty data. +%One way is to have more than 1 dirty bit per cacheline. +%For example, we could implement 1-bit per 32-bits words. +%As we have 64 bytes cachelines, this would need 16 dirty bits per cacheline. + +%\section{Cache Pipeline} + +\clearpage +\chapter{\acfp{CSR}} +\chalabel{csr} +\minitoc +\newpage + +\section{Dedicated CSR address space} +\seclabel{csr_address_space} + +\begin{tcolorbox}[colback=red!10!white, + colframe=white!10!red, + title=\textbf{Important}, + center, valign=top, halign=left, + center title, + width=.950\linewidth] +This CSR address space is not yet implemented in version 1.0.0 of the RTL. +In this version, runtime configuration values are passed through external ports of the HPDcache. +Performance counters are not implemented either. +\end{tcolorbox} + +The \ac{HPDcache} defines a dedicated memory address space for configuring and checking the internal status. +This memory space is shared among all the requesters connected to the same \ac{HPDcache}. +However, this space is private to those requesters in a system-wide point of view. +This is, this dedicated \ac{CSR} address space is not visible to other requesters integrated in the system. + +The dedicated \ac{CSR} address space is aligned to 4 Kibytes and has this same size. +Current version of the \ac{HPDcache} uses a very small subset of this address space, but the aligning to 4 Kibytes, allows easier mapping in the virtual address space by the \ac{OS}. +The smallest virtual/physical page size defined in the \citetitle{RISCV_privileged_spec}\cite{RISCV_privileged_spec} is 4 Kibytes. +This is the reason of this choice. +\Figref{csr_address_space} displays the layout of the dedicated \ac{CSR} address space of the \ac{HPDcache}. + +The $\mathsf{CFIG\_BASE}$ address is specified through an input port of the \ac{HPDcache}. +The name of this input pin is \lstinline{cfig_base_i}. +It is a multi-bit signal. +The number of bits is $\mathsf{CONF\_HPDCACHE\_PA\_WIDTH}$. + +\begin{figure}[!htbp] +\begin{center} + \begin{tikzpicture}[scale=.7] + \footnotesize + \draw[line width=2] (0,0) rectangle (4,8); + + % top line for segment 0 + \node at (2, 1) {\sf CFIG}; + \node [anchor=west] at (4, 0) {\sf CFIG\_BASE + 0x0000}; + \node [anchor=west] at (4, 2) {\sf CFIG\_BASE + 0x0200}; + \draw [line width=2](0,2) + -- (4,2); + + % top line for segment 1 + \node at (2, 3) {\sf CFIG\_HWPF}; + \node [anchor=west] at (4, 4) {\sf CFIG\_BASE + 0x0400}; + \draw [line width=2](0,4) + -- (4,4); + + % top line for segment 2 + \node at (2, 5) {\sf PERF}; + \node [anchor=west] at (4, 6) {\sf CFIG\_BASE + 0x0600}; + \draw [line width=2](0,6) + -- (4,6); + + \node [anchor=west] at (4, 8) {\sf CFIG\_BASE + 0x800}; + \draw[fill=lightgray, draw=black, line width=2] (0,6) rectangle (4,8); + \node [anchor=west] at (14, 8) {\sf CFIG\_BASE + 0x1000}; + \draw[fill=lightgray, draw=black, line width=2] (10,6) rectangle (14,8); + \node [anchor=west] at (14, 6) {\sf CFIG\_BASE + 0xe00}; + \draw[fill=lightgray, draw=black, line width=2] (10,4) rectangle (14,6); + \node [anchor=west] at (14, 4) {\sf CFIG\_BASE + 0xc00}; + \draw[fill=lightgray, draw=black, line width=2] (10,2) rectangle (14,4); + \node [anchor=west] at (14, 2) {\sf CFIG\_BASE + 0xa00}; + \draw[fill=lightgray, draw=black, line width=2] (10,0) rectangle (14,2); + \node [anchor=west] at (14, 0) {\sf CFIG\_BASE + 0x800}; + \end{tikzpicture} + \caption{Dedicated CSR address space}% + \figlabel{csr_address_space} +\end{center} +\end{figure} + +\newpage +\section{Configuration registers} + +\Tabref{csr_config} lists the configuration registers implemented in the \ac{HPDcache}. + +These are mapped on the $\mathsf{CFIG}$ memory address segment in \figref{csr_address_space}. + +\begin{figure}[!htbp] + \begin{center} + \caption{Configuration registers in the \ac*{HPDcache}}% + \tablabel{csr_config} + {\small% + \begin{tabular}{p{.25\textwidth}p{.44\textwidth}p{.21\textwidth}} + \textbf{CFIG Segment} & &\\ + \toprule + \textbf{Register} + & \textbf{Description} + & \textbf{Base address} \\ + \toprule + $\mathsf{cfig\_info}$ + & 64-bits register with cache information + & $\mathtt{~+~0x00}$\\ + \midrule + $\mathsf{cfig\_ctrl}$ + & 64-bits register for configuring the cache controller + & $\mathtt{~+~0x08}$\\ + \midrule + $\mathsf{cfig\_wbuf}$ + & 64-bits register for configuring the write-buffer + & $\mathtt{~+~0x10}$\\ + & & \\ + \textbf{CFIG\_HWPF Segment} & &\\ + \toprule + \textbf{Register} + & \textbf{Description} + & \textbf{Base address} \\ + \toprule + $\mathsf{cfig\_hwpf\_status}$ + & 64-bits register with the status of the hardware prefetcher + & $\mathtt{~+~0x200}$\\ + \midrule + \verb$for (i = 0; i < 4; i++) {$ & & \\ + \midrule + $\mathsf{cfig\_hwpf\_base\_engine[i]}$ + & 64-bits base cline register of the engine $\mathtt{i}$ of the hardware prefetcher + & $\mathtt{~+~0x200}$ + $\mathtt{+~(i~+~1)\times{}0x20~+~0x0}$\\ + \midrule + $\mathsf{cfig\_hwpf\_param\_engine[i]}$ + & 64-bits parameters register of the engine $\mathtt{i}$ of the hardware prefetcher + & $\mathtt{~+~0x200}$ + $\mathtt{+~(i~+~1)\times{}0x20~+~0x8}$\\ + \midrule + $\mathsf{cfig\_hwpf\_throttle\_engine[i]}$ + & 64-bits throttle register of the engine $\mathtt{i}$ of the hardware prefetcher + & $\mathtt{~+~0x200}$ + $\mathtt{+~(i~+~1)\times{}0x20~+~0x10}$\\ + \midrule + \verb$}$ & & \\ + \bottomrule + \end{tabular}} + \end{center} +\end{figure} + +\begin{minipage}{\textwidth} +\paragraph{$\mathbf{cfig\_info}$ - $\mathtt{~+~0x00}$}\mbox{}\\[1em] + \begin{bytefield}[endianness=big,bitwidth=\linewidth/64,% + boxformatting={\centering\footnotesize\sf}]{64} + \bitheader{0,7,8,15,16,19,20,23,48,63} \\ + \bitbox{16}{ID} &% + \bitbox{24}{\color{lightgray}\rule{\width}{\height}} &% + \bitbox{4}{HwPf} &% + \bitbox{4}{LnSz} &% + \bitbox{8}{Ways} &% + \bitbox{8}{Sets}% + \end{bytefield} + + \begin{center} + {\footnotesize\begin{tabular}{p{.03\textwidth}p{.17\textwidth}p{.03\textwidth}p{.25\textwidth}p{.35\textwidth}} + \textbf{Field} & \textbf{Description} & \textbf{Mode} & \textbf{Reset value} + & \textbf{Comment}\\ + \toprule + Sets & Number of sets & RO + & $\mathsf{CONF\_HPDCACHE\_SETS}$ + & Indicates the number of sets implemented.\\ + \midrule + Ways & Number of ways & RO + & $\mathsf{CONF\_HPDCACHE\_WAYS}$ + & Indicates the number of ways implemented.\\ + \midrule + LnSz & Number of bytes per cacheline (power of 2) & RO + & $\mathsf{log_2(HPDCACHE\_CL\_WIDTH/8)}$ + & It contains the $\mathsf{log_2}$ of the size in bytes of cachelines.\\ + \midrule + HwPf & Number of engines in the hardware prefetcher & RO + & 4 + & Indicates the number of simultaneous streams supported by the hardware prefetcher \\ + \midrule + ID & Version ID & RO + & $\mathtt{0xCEA0}$ + & Version ID of the \ac{HPDcache}.\\ + \bottomrule + \end{tabular}} + \end{center} +\end{minipage}\\[1em] + +\begin{minipage}{\textwidth} +\paragraph{$\mathbf{cfig\_ctrl}$ - $\mathtt{~+~0x08}$}\mbox{}\\[1em] + \begin{bytefield}[endianness=big,bitwidth=\linewidth/64,% + boxformatting={\centering\footnotesize\sf}]{64} + \bitheader{0,56,57,63} \\ + \bitbox{6}{\color{lightgray}\rule{\width}{\height}} &% + \bitbox{1}{A} &% + \bitbox{1}{R} &% + \bitbox{55}{\color{lightgray}\rule{\width}{\height}} &% + \bitbox{1}{E}% + \end{bytefield} + + \begin{center} + {\small\begin{tabular}{p{.05\textwidth}p{.30\textwidth}p{.05\textwidth}p{.05\textwidth}p{.40\textwidth}} + \textbf{Field} & \textbf{Description} & \textbf{Mode} & \textbf{Reset value} + & \textbf{Comment}\\ + \toprule + E & Cache Enable & RW & \texttt{0b0} + & When set to 0, all memory accesses are considered non-cacheable.\\ + \midrule + R & Single-entry RTAB (fallback mode) & RW & \texttt{0b0} + & This is a fallback mode. When set to 1, the cache controller only uses one entry in the \ac{RTAB}.\\ + \midrule + A & Forbid AMO mode (\secref{amo_implementation}) & RW & \texttt{0b0} + & When set to 1, the cache controller responds with an error to AMO requests targeting cacheable addresses.\\ + \bottomrule + \end{tabular}} + \end{center} +\end{minipage}\\[1em] + +\begin{minipage}{\textwidth} +\paragraph{$\mathbf{cfig\_wbuf}$ - $\mathtt{~+~0x10}$}\mbox{}\\[1em] + \begin{bytefield}[endianness=big,bitwidth=\linewidth/64,% + boxformatting={\centering\footnotesize\sf}]{64} + \bitheader{0,1,8,15,63} \\ + \bitbox{48}{\color{lightgray}\rule{\width}{\height}} &% + \bitbox{8}{Threshold}% + \bitbox{6}{\color{lightgray}\rule{\width}{\height}} &% + \bitbox{1}{S}% + \bitbox{1}{R}% + \end{bytefield} + + \begin{center} + \tablabel{cfig_wbuf} + {\small\begin{tabular}{p{.08\textwidth}p{.28\textwidth}p{.05\textwidth}p{.05\textwidth}p{.40\textwidth}} + \textbf{Field} & \textbf{Description} & \textbf{Mode} & \textbf{Reset value} + & \textbf{Comment}\\ + \toprule + R & Reset time-counter on write & RW & \texttt{0b1} + & When set to 1, writes restart the time-counter in the corresponding write-buffer entry.\\ + \midrule + S & Sequential Write-After-Write & RW & \texttt{0b0} + & When set to 1, the write-buffer holds-back writes requests that matches the target address of an on-the-fly write.\\ + \midrule + Threshold & Number of keep-alive cycles of entries in the write-buffer & RW & \texttt{0x04} + & The maximum accepted value is $\mathsf{CONF\_HPDCACHE\_WBUF\_TIMECNT\_MAX}$. + When set to 0, a write immediatly closes the corresponding entry.\\ + \midrule + I & Inhibit write coalescing & RW & \texttt{0b0} + & When set to 1, the write-buffer does not perform write coalescing. It accepts one write per entry.\\ + \bottomrule + \end{tabular}} + \end{center} +\end{minipage}\\[1em] + +\begin{minipage}{\textwidth} +\paragraph{$\mathbf{cfig\_hwpf\_*}$}\mbox{}\\[1em] +These registers are related to the hardware prefetcher. +They are mapped on the $\mathsf{CFIG\_HWPF}$ memory address segment.\\[1em] + +Details on hardware prefetcher configuration registers are in \secref{prefetch_csrs}. +\end{minipage}\\[1em] + + +\section{Performance counters} +\seclabel{csr_performance} + +The \ac{HPDcache} provides a set of performance counters. +These counters provide important information that can be used by software developers, at \ac{OS} level or user application level, to, for example, debug performance issues. + +\Tabref{csr_performance} lists the performance counters provided by the \ac{HPDcache}. +These are mapped on the $\mathsf{PERF}$ memory address segment in \figref{csr_address_space}. + +\begin{figure}[!htbp] + \begin{center} + \caption{Performance counters in the \ac*{HPDcache}}% + \tablabel{csr_performance} + {\footnotesize% + \begin{tabular}{lll} + \toprule + \textbf{Counter} + & \textbf{Description} + & \textbf{Base address} \\ + \midrule + $\mathsf{perf\_write\_req}$ + & 64-bits counter for processed write requests + & $\mathtt{^\alpha~+~0x00}$\\ + \midrule + $\mathsf{perf\_read\_req}$ + & 64-bits counter for processed read requests + & $\mathtt{^\alpha~+~0x08}$\\ + \midrule + $\mathsf{perf\_prefetch\_req}$ + & 64-bits counter for processed prefetch requests + & $\mathtt{^\alpha~+~0x10}$\\ + \midrule + $\mathsf{perf\_uncached\_req}$ + & 64-bits counter for processed uncached requests + & $\mathtt{^\alpha~+~0x18}$\\ + \midrule + $\mathsf{perf\_cmo\_req}$ + & 64-bits counter for processed \ac{CMO} requests + & $\mathtt{^\alpha~+~0x20}$\\ + \midrule + $\mathsf{perf\_accepted\_req}$ + & 64-bits counter for accepted requests + & $\mathtt{^\alpha~+~0x28}$\\ + \midrule + $\mathsf{perf\_cache\_write\_miss}$ + & 64-bits counter for write cache misses + & $\mathtt{^\alpha~+~0x30}$\\ + \midrule + $\mathsf{perf\_cache\_read\_miss}$ + & 64-bits counter for read cache misses + & $\mathtt{^\alpha~+~0x38}$\\ + \midrule + $\mathsf{perf\_on\_hold\_req}$ + & 64-bits counter for requests put on-hold + & $\mathtt{^\alpha~+~0x40}$\\ + \bottomrule + % empty + & $\mathtt{\alpha:~~=~~+~0x400}$ + & + \end{tabular}} + \end{center} +\end{figure} + + +\section{Event signals} +\seclabel{csr_events} + +In addition to the performance registers explained in \secref{csr_performance}, the \ac{HPDcache} provides a set of one-shot signals that indicate when a given event is detected. +As one-shot signals, they are set to 1 for one cycle each time the corresponding event is detected. +If the same event is detected N cycles in a row, the corresponding event signal will remain set to 1 for N cycles. +\Tabref{csr_events} lists these event signals. + +These event signals are output-only. +They can be either left unconnected, if they are not used, or connected with the remainder of the system. +The system can use those signals, for example, for counting those events externally or for triggering some specific actions. + +\begin{figure}[!htbp] + \begin{center} + \caption{Event signals in the \ac*{HPDcache}}% + \tablabel{csr_events} + {\footnotesize% + \begin{tabular}{ll} + \toprule + \textbf{Signal} + & \textbf{Event description} \\ + \midrule + $\mathsf{evt\_cache\_write\_miss\_o}$ + & Cache miss on write operation\\ + \midrule + $\mathsf{evt\_cache\_read\_miss\_o}$ + & Cache miss on read operation\\ + \midrule + $\mathsf{evt\_uncached\_req\_o}$ + & The cache processed an uncached request\\ + \midrule + $\mathsf{evt\_cmo\_req\_o}$ + & The cache processed a \ac{CMO} request\\ + \midrule + $\mathsf{evt\_write\_req\_o}$ + & The cache processed a write request\\ + \midrule + $\mathsf{evt\_read\_req\_o}$ + & The cache processed a read request\\ + \midrule + $\mathsf{evt\_prefetch\_req\_o}$ + & The cache processed a prefetch request\\ + \midrule + $\mathsf{evt\_on\_hold\_req\_o}$ + & The cache put on-hold a request\\ + \midrule + $\mathsf{evt\_rtab\_rollback\_o}$ + & A replayed request has been pushed back into the replay table\\ + \midrule + $\mathsf{evt\_stall\_refill\_o}$ + & A new request is stalled because of an ongoing refill operation\\ + \midrule + $\mathsf{evt\_stall\_o}$ + & A new request is stalled because of a hazard in the pipeline (it includes refill stalls)\\ + \bottomrule + \end{tabular}} + \end{center} +\end{figure} + + + +\chapter{Cache Management Operations (CMOs)} +\chalabel{cmo} +\minitoc +\newpage + +The \ac{HPDcache} is able of performing the following \aclp{CMO}: + +\begin{itemize} + \item memory write fence; + \item invalidate a cacheline given a physical address; + \item invalidate one or more cachelines in a given set given the set and one or more ways; + \item invalidate all the cachelines; + \item prefetch the cacheline indicated by its physical address. +\end{itemize} + +Any of the clients of the HPDCACHE can trigger one of this operation anytime by using specific opcodes in their request. + +\begin{table}[h!] +\begin{center} +\caption{CMO operation types}% +\tablabel{dcache_req_cmo} +{\footnotesize +\begin{tabular}{lll} + \toprule + \textbf{Mnemonic} + & \textbf{Encoding} + & \textbf{Type} \\ + \midrule + $\mathsf{HPDCACHE\_CMO\_FENCE}$ + & 0b000 + & Memory write fence.\\ + \midrule + $\mathsf{HPDCACHE\_CMO\_INVAL\_NLINE}$ + & 0b010 + & Invalidate a given cacheline.\\ + \midrule + $\mathsf{HPDCACHE\_CMO\_INVAL\_SET\_WAY}$ + & 0b011 + & Invalidate one or more ways of in a given set of the cache.\\ + \midrule + $\mathsf{HPDCACHE\_CMO\_INVAL\_ALL}$ + & 0b100 + & Invalidate the entire cache.\\ + \midrule + $\mathsf{HPDCACHE\_CMO\_PREFETCH}$ + & 0b101 + & Prefetch a given cacheline.\\ + \midrule +\end{tabular}} +\end{center} +\end{table} + +The $\mathsf{HPDCACHE\_REQ\_OP}$ must be set to $\mathsf{HPDCACHE\_REQ\_CMO}$ (see \tabref{dcache_req_op}). +The \ac{CMO} subtype (\tabref{dcache_req_cmo}) is transferred into the $\mathsf{HPDCACHE\_REQ\_SIZE}$ signal of the request. + +The following sections describe in detail each of the \ac{CMO} operations, and how the requests shall be encoded to trigger each of them. + + +\newpage +\section{Memory write fence} + +To make sure that the \ac{HPDcache} accepts new requests only when all previous writes are sent and acknowledged from the memory, a requester can issue a fence operation. + +To do this, the requester shall build the request as follows: + +{\centering\footnotesize\begin{tabular}{p{.38\linewidth}p{.55\linewidth}} + \toprule + \textbf{Signal} + & \textbf{Value} \\ + \midrule + $\mathsf{HPDCACHE\_REQ\_ADDR}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_OP}$ + & $\mathsf{HPDCACHE\_REQ\_CMO}$ \\ + \midrule + $\mathsf{HPDCACHE\_REQ\_WDATA}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_BE}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_SIZE}$ + & $\mathsf{HPDCACHE\_CMO\_FENCE}$ \\ + \midrule + $\mathsf{HPDCACHE\_REQ\_UNCACHEABLE}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_SID}$ + & Corresponding source ID of the requester\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_TID}$ + & Transaction identifier from the requester\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_NEED\_RSP}$ + & *\\ + \bottomrule + & * means don't care \\ +\end{tabular}} + +As for any regular request, the request shall follow the \textbf{VALID}/\textbf{READY} handshake protocol described in \secref{if_valid_ready}. + +This operation has the following effects: +\begin{itemize} +\item All open entries in the write buffer (write requests waiting to be sent to the memory) are immediately closed; +\item No new requests from any requester are acknowledged until all pending write requests in the cache have been acknowledged on the \ac{NoC} interface. +\end{itemize} + + +\newpage +\section{Invalidate a cacheline by its physical address} + +To invalidate a cacheline by its physical address, the requester shall build the request as follows: + +{\centering\footnotesize\begin{tabular}{p{.38\linewidth}p{.55\linewidth}} + \toprule + \textbf{Signal} + & \textbf{Value} \\ + \midrule + $\mathsf{HPDCACHE\_REQ\_ADDR}$ + & Physical address to invalidate in the cache.\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_OP}$ + & $\mathsf{HPDCACHE\_REQ\_CMO}$ \\ + \midrule + $\mathsf{HPDCACHE\_REQ\_WDATA}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_BE}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_SIZE}$ + & $\mathsf{HPDCACHE\_CMO\_INVAL\_NLINE}$ \\ + \midrule + $\mathsf{HPDCACHE\_REQ\_UNCACHEABLE}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_SID}$ + & Corresponding source ID of the requester\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_TID}$ + & Transaction identifier from the requester\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_NEED\_RSP}$ + & *\\ + \bottomrule + & * means don't care \\ +\end{tabular}} + +As for any regular request, the request shall follow the \textbf{VALID}/\textbf{READY} handshake protocol described in \secref{if_valid_ready}. + +For the sake of design simplification, this operation works as a memory read fence. +That is, before handling the operation, the \ac{HPDcache} waits for all pending read misses to complete. +Future versions of the HPDcache could wait only for a pending read miss on the same address that is being invalidated. + +If the given physical address is not cached, the operation does nothing. +However it still works as a memory read fence. + +Regarding the latency of this operation, it depends on the time to serve all pending read misses. +Only one cycle is needed to invalidate the corresponding cacheline. + + +\newpage +\section{Invalidate a group of cachelines by their a set and way} + +To invalidate a group of cachelines, the requester shall build the request as follows: + +{\centering\footnotesize\begin{tabular}{p{.38\linewidth}p{.55\linewidth}} + \toprule + \textbf{Signal} + & \textbf{Value} \\ + \midrule + $\mathsf{HPDCACHE\_REQ\_ADDR}$ + & Index of the set to invalidate.\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_OP}$ + & $\mathsf{HPDCACHE\_REQ\_CMO}$ \\ + \midrule + $\mathsf{HPDCACHE\_REQ\_WDATA}$ + & Bit-vector with target ways to invalidate. + The number of bits decoded depends on the number of ways implemented ($\mathsf{CONF\_HPDCACHE\_WAYS}$). + The least significant bit corresponds to way 0, the second to way 1, etc.\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_BE}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_SIZE}$ + & $\mathsf{HPDCACHE\_CMO\_INVAL\_SET\_WAY}$\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_UNCACHEABLE}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_SID}$ + & Corresponding source ID of the requester\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_TID}$ + & Transaction identifier from the requester\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_NEED\_RSP}$ + & *\\ + \bottomrule + & * means don't care \\ +\end{tabular}} + +As for any regular request, the request shall follow the \textbf{VALID}/\textbf{READY} handshake protocol described in \secref{if_valid_ready}. + +For the sake of design simplification, this operation works as a memory read fence. +That is, before handling the operation, the \ac{HPDcache} waits for all pending read misses to complete. +Future versions of the HPDcache could wait only for a pending read misses on the same set that is being invalidated. + +If the given set and ways contains no valid cachelines, the operation does nothing. +However it still works as a memory read fence. + +Regarding the latency of this operation, it depends on the time to serve all pending reads. +Only one cycle is needed to invalidate the given set and ways because the ways are invalidated simultaneously. + + +\newpage +\section{Invalidate the entire cache} + +With this operation, all the cachelines in the \ac{HPDcache} are invalidated. + +To perform a complete invalidation of the \ac{HPDcache}, the requester shall build the request as follows: + +{\centering\footnotesize\begin{tabular}{p{.38\linewidth}p{.55\linewidth}} + \toprule + \textbf{Signal} + & \textbf{Value} \\ + \midrule + $\mathsf{HPDCACHE\_REQ\_ADDR}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_OP}$ + & $\mathsf{HPDCACHE\_REQ\_CMO}$ \\ + \midrule + $\mathsf{HPDCACHE\_REQ\_WDATA}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_BE}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_SIZE}$ + & $\mathsf{HPDCACHE\_CMO\_INVAL\_ALL}$\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_UNCACHEABLE}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_SID}$ + & Corresponding source ID of the requester\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_TID}$ + & Transaction identifier from the requester\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_NEED\_RSP}$ + & *\\ + \bottomrule + & * means don't care \\ +\end{tabular}} + +As for any regular request, the request shall follow the \textbf{VALID}/\textbf{READY} handshake protocol described in \secref{if_valid_ready}. + +This operation works as a memory read fence. +This is, before handling the operation, the \ac{HPDcache} waits for all pending read misses to complete. + +Regarding the latency of this operation, it has two aggregated components: + +\begin{itemize} +\item The time to serve all pending reads. +\item One cycle per set implemented in the \ac{HPDcache} (all ways of a given set are invalidated in simultaneously). +\end{itemize} + + +\newpage +\section{Prefetch a cacheline given its physical address} + +With this operation, the cacheline corresponding to the indicated physical address is (pre-)fetched into the \ac{HPDcache} + +To perform a prefetch, the requester shall build the request as follows: + +{\centering\footnotesize\begin{tabular}{p{.38\linewidth}p{.55\linewidth}} + \toprule + \textbf{Signal} + & \textbf{Value} \\ + \midrule + $\mathsf{HPDCACHE\_REQ\_ADDR}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_OP}$ + & $\mathsf{HPDCACHE\_REQ\_CMO}$ \\ + \midrule + $\mathsf{HPDCACHE\_REQ\_WDATA}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_BE}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_SIZE}$ + & $\mathsf{HPDCACHE\_CMO\_PREFETCH}$\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_UNCACHEABLE}$ + & *\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_SID}$ + & Corresponding source ID of the requester\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_TID}$ + & Transaction identifier from the requester\\ + \midrule + $\mathsf{HPDCACHE\_REQ\_NEED\_RSP}$ + & Indicates if the requester needs an acknowledgement when the prefetch of the cacheline is completed.\\ + \bottomrule + & * means don't care \\ +\end{tabular}} + +As for any regular request, the request shall follow the \textbf{VALID}/\textbf{READY} handshake protocol described in \secref{if_valid_ready}. + +If the requested cacheline is already in the cache, at the moment the request is processed, this request has no effect. If the requested cacheline is not present in the cache, the cacheline is fetched from the memory and replicated into the cache. + +When the prefetch transaction is completed, and the $\mathsf{HPDCACHE\_REQ\_NEED\_RSP}$ signal was set to 1, an acknowledgement is sent to the corresponding requester. + + +\chapter{Atomic Memory Operations (AMOs)} +\chalabel{amo} +\minitoc +\newpage + +\section{Background} + +The \acp{AMO} are special load/store accesses that implements a read-modify-write semantic. +A single instruction is able to read a data from the memory, perform an arithmetical/logical operation on that data, and store the result. +All this is performed as a single operation (no other operation can come in between the read-modify-write operations). + +These operations are meant for synchronization in multi-core environments. +To enable this synchronization, \acp{AMO} need to be performed on the \acf{PoS}, point where all accesses from the different cores converge. +This is usually a shared cache memory (when multiple levels of cache are implemented) or the external RAM controllers. +Thus, the \ac{HPDcache} needs to forward these operations to the \ac{PoS} through the \ac{NoC} interface. + +\section{Supported \acp*{AMO}} + +On the interface from requesters, the supported \acp{AMO} are the ones listed in \tabref{dcache_req_op}. +The supported \acp{AMO} are the ones defined in the atomic (A) extension of the RISC-V ISA specification: \citetitle{RISCV_spec}\cite{RISCV_spec}. + + +\section{Implementation} +\seclabel{amo_implementation} + +This cache does not implement a hardware cache-coherency protocol. +Therefore, the software needs to solve the cache obsolescence problem to ensure it reads the last value of the shared data. +There are two common ways of doing this: +\begin{enumerate} +\item Statically, by placing all shared data into uncacheable segments (never replicated in the \ac{HPDcache}); + +\item Dynamically, by explicitly invalidating local copies of shared data from the \ac{HPDcache}. +\end{enumerate} + +The cache obsolescence problem applies to \acp{AMO}. +As these operations are used for implementing synchronization mechanism, the manipulated data is by nature shared and need to be coherent between the different caches. +The \ac{HPDcache} implements two different modes for handling \acp{AMO}: + +\begin{description} +\item[Replicated AMO mode] \mbox{}\\% +Forward the \ac{AMO} to the \ac{PoS}, and wait for the response with the old data. +If the data of the target address is replicated in the \ac{HPDcache}, the \ac{HPDcache} computes the new value locally, and updates the target word in the corresponding cacheline. +With this solution the modified word with the \ac{AMO} will be up to date (coherent) with respect to the value in memory. +This solution needs explicit treatment from the software. +In particular, it requires that synchronization variables are always written (and possibly read) using \acp{AMO}. +For reading a shared variable, the software has two possibilities: (1) send an \ac{AMO} that does not modify the memory (e.g. AMOOR with bit-mask equal to zero); (2) invalidate the local cacheline prior to issuing the load instruction. + +\item[Forbid AMO mode] \mbox{}\\% +This is a much more strict policy. +\acp{AMO} can only be performed on uncacheable memory addresses. +If requests do not follow this rule, an exception is signalled from the cache to the corresponding requester. + +\end{description} + +The \ac{HPDcache} supports both modes, but only one can be active at any given time. +The \verb$cfig_error_on_cacheable_amo$ configuration bit selects the mode of operation. +When this bit is set to 0, the \textbf{Replicated AMO mode} is active. +When this bit is set to 1, the \textbf{Forbid AMO mode} is active. + +The \ac{HPDcache} handle \acp{AMO} as non-allocating operations, regardless of the \ac{AMO} mode described above. +This is, \acp{AMO} never fetch a replica of the target cacheline from the memory to the cache. +If the target cacheline IS NOT replicated in the cache, the \ac{AMO} modifies the memory. +If the target cacheline IS replicated in the cache, the \ac{AMO} modifies both the memory and the cache. + +\section{AMO ordering} + +As specified in the RISC-V ISA specification~\cite{RISCV_spec}, the base RISC-V ISA has a relaxed memory model. +To provide additional ordering constraints, \acp{AMO} (including \acs*{LR}/\acs*{SC}) specify two bits, \textit{aq} and \textit{rl}, for \textit{acquire} and \textit{release} semantics. + +The \ac{HPDcache} always ignores \textit{aq} and \textit{rl} bits. +It considers that they are always set. +Hence, \ac{HPDcache} handles \acp{AMO} always as sequentially consistent memory operations. +The \ac{HPDcache} waits for all pending read and write operations to complete before serving the \ac{AMO} request. + +This behavior implies that when the \ac{HPDcache} forwards an \ac{AMO} to the \ac{NoC}, it will be the only pending request from the \ac{HPDcache}. +In addition, no new requests from the requesters are served until the \ac{AMO} is completed. + + +\section{LR/SC support} + +\acf{LR} and \acf{SC} are part of the Atomic (A) extension of the RISC-V ISA specification~\cite{RISCV_spec}. +These instructions allow {\it "complex atomic operations on a single memory word or double-word"}. + +The \ac{HPDcache} fully supports all the instructions of the A extension of the RISC-V ISA, including \ac{LR} and \ac{SC} operations. + +In the specification of these instructions in the RISC-V ISA document, some details are dependent to the implementation. +Namely, the size of the reservation set and the return code of a \ac{SC} failure. + + +\subsection{LR/SC reservation set} + +When a requester executes a \ac{LR} operation, it "reserves" a set of bytes in memory. +This set contains at least the bytes solicited in the request but may contain more. +RISC-V ISA defines two sizes for \ac{LR} operations: 4 bytes or 8 bytes. +{\bf The \ac{HPDcache} reserves 8-bytes (double-word) containing the addressed memory location regardless of whether the \ac{LR} size is 4 or 8 bytes}. +The start address of the reservation set is a 8-bytes aligned address. + +When the \ac{LR} size is 8 bytes, the address is also aligned to 8 bytes (\secref{if_addr_data_alignment}). +In this case, the reservation set matches exactly the address interval defined in the request. +When the \ac{LR} size is 4 bytes, there are two possibilities: (1)~the target address is not aligned to 8 bytes. +The start address of the reservation set contains additional 4 bytes before the target address ; +(2)~the target address is aligned to 8 bytes. +The reservation set starts at the target address but contains additional 4 bytes after the requested ones. + +In summary, in case of \ac{LR} operation, the reservation set address range is computed as follows: + +\begin{equation*} + \mathbf{reservation\_set =} + \begin{cases} + \mathsf{\lfloor{}HPDCACHE\_REQ\_ADDR / 8\rfloor{} \times 8} & + (start\_address) \\ + \mathsf{(\lfloor{}HPDCACHE\_REQ\_ADDR / 8\rfloor{} \times 8) + 8} & + (end\_address) \\ + \end{cases} +\end{equation*} + +{\bf When a requester executes a \ac{SC} operation, the \ac{HPDcache} forwards the operation to the memory ONLY IF the bytes addressed by the \ac{SC} are part of an active reservation set}. +If the \ac{SC} accesses a smaller number of bytes that those in the active reservation set but within that reservation set, the \ac{SC} is still forwarded to the memory. + +The \ac{HPDcache} keeps an unique active reservation set. +If multiple requesters perform \ac{LR} operations, the unique active reservation set is the one specified by the last \ac{LR} operation. + +\Todo{Could this be a problem ? Should we keep one reservation set per requester ?} + +After a \ac{SC} operation, the unique active reservation set, if any, is invalidated. +This is regardless whether the \ac{SC} operation succeeds or not. + + +\subsection{\ac*{SC} failure response code} +\seclabel{sc_failure_code} + +The RISC-V ISA~\cite{RISCV_spec} specifies that when a \ac{SC} operation succeeds, the core shall write zero into the destination register of the operation. +Otherwise, in case of \ac{SC} failure, the core shall write a non-zero value into the destination register. + +The \ac{HPDcache} returns the status of an \ac{SC} operation into the $\mathsf{HPDCACHE\_RSP\_RDATA}$~(\tabref{if_rsp}) signal of the response interface to requesters. +The following table specifies the values returned by the \ac{HPDcache} into the $\mathsf{HPDCACHE\_RSP\_RDATA}$ signal in case of \ac{SC} operation. + +\begin{center} + {\small% + \begin{tabular}{p{.15\linewidth}p{.20\linewidth}} + \toprule + \textbf{Case} + & \textbf{Return value (status)}\\ + \midrule + SC success + & \texttt{0x0000\_0000} \\ + \midrule + SC failure + & \texttt{0x0000\_0001} \\ + \bottomrule + \end{tabular}} +\end{center} + +Depending on the specified size ($\mathsf{HPDCACHE\_REQ\_SIZE}$) in the request (\tabref{if_rsp}), the returned value is extended with zeros on the most significant bits. +This is, if the SC request size is 8 bytes, and the SC is a failure, then the returned value is \texttt{0x0000\_0000\_0000\_0001}. + +In addition, if the width of the $\mathsf{HPDCACHE\_RSP\_RDATA}$ signal is wider than the size of the SC request, the return value is replicated $\mathsf{CONF\_HPDCACHE\_REQ\_WORDS}$~(\tabref{dcache_parameters}) times. + + +\chapter{Hardware Memory Prefetcher} +\minitoc +\newpage + +In order to predict future data accesses and reduce the data cache miss rate, the cache implements a programmable hardware mechanism allowing to prefetch cachelines before they are actually requested. + +The \ac{HPDcache} implements a prefetcher that contains multiple prefetch engines. +Each prefetch engine works independently, and simultaneously. +A round-robin arbiter at the output of the prefetcher allows to select one prefetch request from one of the engines per cycle. +This arbiter guarantees the correct behavior when multiple prefetch engines are active. + +Each engine, if activated, fetches a stream of cachelines. +A stream is defined as a sequence of prefetch requests. +An engine reads one or multiple blocks of a given number of cachelines. +The first block starts at a given base cacheline. +Between blocks, one can configure a given address offset (also known as the stride). + +The four parameters (base cacheline, number of cachelines in a block, number of blocks, and the stride) of each stream (one per engine) are configured through dedicated \acp{CSR}. + +\section{Triggering} + +A given prefetcher engine starts operating when the following conditions are met: + +\begin{enumerate} +\item Each engine implements an enable bit in its dedicated \acp{CSR}. +This enable bit shall be set to 1 to allow the triggering of a given prefetcher engine. + +\item Each enabled engine (condition 1 is met), snoops on the requests ports from the requesters. +If there is a match between the issued address and the configured base cacheline of the engine, the engine starts the prefetching. + +\end{enumerate} + +Once an engine starts its operation, it does not snoop anymore the request ports. +At that moment, it issues a sequence of prefetch operations starting from $\mathsf{base\_cline}$, until the cacheline in the equation below. +When the last cacheline is reached, the behavior of the engine is described in the following section. + +\begin{equation*} + \mathsf{end\_cline = base\_cline + (Nblocks + 1)\times{}(Stride + 1)} +\end{equation*} + +A prefetch operation behaves as a read in the cache, but no data is expected in response by the prefetcher. +This means, that prefetch operations do not need to enable the data array of the cache (thus reducing the energy consumption for this operation). +Prefetch operations only access cache directory memories to check if the requested cacheline is cached or if it needs to be fetched from the memory. + +\begin{tcolorbox}[colbacktitle=green!50!black, + colback=green!10!white, + colframe=green!50!black, + title=\textbf{Programming note}, + center, valign=top, halign=justify, + center title, + width=.950\linewidth] + +As explained in this section, a requester needs to issue a load transaction within the base cacheline of an engine to start its operation. + +When the requester is a programmable processor core, an additional feature that could be implemented in the core is a software prefetch instruction. +This instruction would allow the software to prefetch a given cacheline, without stalling the core while waiting the response from the cache. +Such instruction could also be used to start an enabled prefetcher engine. + +In RISC-V cores, one possibility to implement this software prefetch instruction could be to use the following: + +\vspace{.8em} + +\begin{verbatim} +lw x0, offset(rs1) +\end{verbatim} + +\vspace{.8em} + +As the \verb|x0| register is always equal to zero, the data is dropped. +Therefore, an efficient implementation of this instruction in the core consists on forwarding the load to the L1 data cache but do not wait for the response. +\end{tcolorbox} + +\section{Activation/Deactivation Policies} +\seclabel{prefetch_activation_policies} + +The prefetcher engines implement different automatic activation/deactivation policies: + +\begin{tabular}{p{.3\linewidth}p{.65\linewidth}} +\toprule +\textbf{Policies} +& \\ +\midrule +\textbf{Disarm when finished} +& When the engine completes the configured stream, it is automatically disabled.\\ +\midrule + +\textbf{Rearm when finished} +& When the prefetcher completes the configured stream, it does not disable. +However, it stops and waits to be triggered again. + +At that point, the base cacheline \ac{CSR} of the engine saves the last accessed cacheline plus the stride. +This is, it saves the next address to prefetch. + +The \acp{CSR} for the number of blocks, cachelines per block and stride keep their originally configured values.\\ +\midrule + +\textbf{Rearm and Cycle when finished} +& In this policy, the prefetch engine behaves as in the "Rearm when finished" policy, but the base cacheline \ac{CSR} is reset to the originally configured value.\\ + +\end{tabular} + +\section{CSRs} +\seclabel{prefetch_csrs} + +Each prefetcher engine has three dedicated \acp{CSR}. + +\begin{itemize} + \item Base cline (base cacheline) - $\mathsf{cfig\_hwpf\_base\_engine}$~(see \tabref{csr_config}) + + \begin{bytefield}[endianness=big,bitwidth=\linewidth/64,% + boxformatting={\centering\footnotesize\sf}]{64} + \bitheader{0,1,2,3,4,5,6,63} \\ + \bitbox{58}{Base~cline} &% + \bitbox{2}{\color{lightgray}\rule{\width}{\height}} &% + \bitbox{1}{U} &% + \bitbox{1}{C} &% + \bitbox{1}{R} &% + \bitbox{1}{E}% + \end{bytefield} + + \begin{tabular}{ll} + \textbf{E:} & Enable bit \\ + \textbf{R:} & Rearm bit \\ + \textbf{C:} & Cycle bit \\ + \textbf{U:} & Upstream bit \\ + \end{tabular} + + \begin{tabular}{lll} + \textbf{Mode} & \textbf{R} & \textbf{C} \\ + Disarm when finished & 0 & X \\ + Rearm when finished & 1 & 0 \\ + Cycle and rearm when finished & 1 & 1 \\ + \end{tabular} + + \item Parameters - $\mathsf{cfig\_hwpf\_param\_engine}$~(see \tabref{csr_config}) + + \begin{bytefield}[endianness=big,bitwidth=\linewidth/32,% + boxformatting={\centering\footnotesize\sf}]{32} + \bitheader[lsb=32]{32,47,48,63} \\ + \bitbox{16}{Nblocks} &% + \bitbox{16}{Nlines} &% + \\[.5em]% + \bitheader[lsb=0]{0,31} \\ + \bitbox{32}{Stride} &% + \end{bytefield} + + \item Throttle - $\mathsf{cfig\_hwpf\_throttle\_engine}$~(see \tabref{csr_config}) + + \begin{bytefield}[endianness=big,bitwidth=\linewidth/32,% + boxformatting={\centering\footnotesize\sf}]{32} + \bitheader[lsb=0]{0,15,16,31} \\ + \bitbox{16}{Ninflight} &% + \bitbox{16}{Nwait} &% + \end{bytefield} +\end{itemize} + +\begin{description} + +\item [\textsf{Stride} parameter] \mbox{}\\ +It is an unsigned, one-based ($\mathsf{value + 1}$), 32-bits wide value. +The stride is in number of cachelines. +This means that the stride is always a multiple of $\mathsf{(HPDCACHE\_CL\_WIDTH/8)}$ bytes. + +\item [\textsf{Nblocks} parameter] \mbox{}\\ +It is an unsigned, one-based ($\mathsf{value + 1}$), 16-bits wide value. +This value corresponds to the number of blocks to prefetch. +The 16-bit value allows the prefetcher to prefetch up to 65536 blocks (of at least one cacheline). +This parameter is clearly over-dimensioned with respect to the usual capacity of the \ac{HPDcache} (e.g. 512, 64-byte, cachelines with a 32KB capacity). + +\item [\textsf{Nlines} parameter] \mbox{}\\ +It is an unsigned, one-based, 16-bits wide value. +It indicates the number of cachelines within blocks. +As the number of bits is 16, the maximum number of cachelines in a given block is 65536. + +\item [\textsf{Nwait} parameter] \mbox{}\\ +It is an unsigned, one-based, 16-bits wide value. +It defines the number of cycles (plus 1) between two requests of the prefetcher engine. +The zero value indicates that the engine can issue a request every cycle. + +\item [\textsf{Ninflight} parameter] \mbox{}\\ +It is an unsigned, zero-based, 16-bits wide value. +It defines the maximum number of in-flight (sent but not yet acknowledged) transactions from the prefetcher engine. +This parameter allows to throttle the memory bandwidth solicited by the prefetcher engine. +The zero value indicates that the number of in-flight transactions is unlimited. + +\item [\textsf{U} bit] \mbox{}\\ +When this upstream bit is set, prefetch operations targets the next level in the memory hierarchy. +In this case, upstream prefetch operations do not allocate cachelines in the L1 data-cache. +These are forwarded to the next memory level that can then prefetch the requested address. +THIS BIT IS NOT CURRENTLY IMPLEMENTED AND IGNORED. + +\item [\textsf{C} bit] \mbox{}\\ +This bit is only considered when the R bit (rearm) is also set. +When this cycle bit is set, after the prefetcher engine completes the prefetch stream, it resets the base cacheline to the originally configured one (see \secref{prefetch_activation_policies}). + +\item [\textsf{R} bit] \mbox{}\\ +When this rearm bit is set, after the prefetcher engine completes the prefetch stream, it "rearms" itself (remains enabled), and snoops for core requests (see \secref{prefetch_activation_policies}). +The address it snoops after it finishes depends on the Cycles (C) bit. +If the C bit is set, the behavior is described here above. +If the C bit is unset, after the prefetcher engine finishes, the snoop address is set to $\mathsf{end\_cline}$. + +\end{description} + +There is also a global status register for the prefetcher to monitor the status of the different prefetcher engines: + +\begin{itemize} + \item Status register + + \begin{bytefield}[endianness=big,bitwidth=\linewidth/16,% + boxformatting={\centering\footnotesize\sf}]{16} + \bitheader[lsb=48]{48,63} \\ + \bitbox{16}{\color{lightgray}\rule{\width}{\height}} &% + \\[.5em]% + \bitheader[lsb=32]{32,33,34,35,36,47} \\ + \bitbox{12}{\color{lightgray}\rule{\width}{\height}} &% + \bitbox{1}{P3 busy} &% + \bitbox{1}{P2 busy} &% + \bitbox{1}{P1 busy} &% + \bitbox{1}{P0 busy}% + \\[.5em]% + \bitheader[lsb=16]{16,19,20,30,31} \\ + \bitbox{1}{Free} &% + \bitbox{11}{\color{lightgray}\rule{\width}{\height}} &% + \bitbox{4}{Free Index} &% + \\[.5em]% + \bitheader[lsb=0]{0,1,2,3,4,15} \\ + \bitbox{12}{\color{lightgray}\rule{\width}{\height}} &% + \bitbox{1}{P3 en} &% + \bitbox{1}{P2 en} &% + \bitbox{1}{P1 en} &% + \bitbox{1}{P0 en}% + \end{bytefield} +\end{itemize} + +\begin{description} + \item [\textsf{P0-P3~enable bits}] \mbox{}\\ + Indicate if the corresponding prefetcher is enabled. + + \item [\textsf{Free~index bits}] \mbox{}\\ + Indicate the index (decimal) of the first available prefetcher from 0 to 3. + The software can use this information to easily compute the address offset of the configuration registers of the target prefetcher engine. + + \item [\textsf{Free bit}] \mbox{}\\ + It is set when the \emph{Free Index} is valid, this is, when there is effectively a free prefetcher. + + \item [\textsf{P0-P3~busy bits}] \mbox{}\\ + Indicate if the corresponding prefetcher is busy (it is enabled and active). + +\end{description} + +\section{Prefetch Request Algorithm} + +\Algref{prefetch_issue} shows how a prefetch engine calculates the address to prefetch and the operation of the throttling mechanisms. + +\begin{figure}[hptb] +\begin{lstlisting}[% +frame=single, language=c, numbers=left,% +basicstyle=\footnotesize] +const bit [63:0] LINES_PER_BLOCK = Nlines + 1; +const bit [63:0] BLOCK_INCREMENT = Stride + 1; +bit [63:0] block_nline; + +// Iterates over the blocks of cachelines +block_nline = Base_cline; +for (nb = 0; nb < (Nblocks + 1); nb++) + // Iterates over the cachelines within each block. + for (nl = 0; nl < LINES_PER_BLOCK; nl++) { + // Skip the first cacheline of the first block as it is already requested by the + // request triggering the prefetcher + if ((nl == 0) && (nb == 0)) continue; + + if (Ninflight > 0) { + // Wait while the number of in-flight prefetch requests is equal to the configured + // threshold (Ninflight). This is a throttling mechanism. + // The inflight counter is decremented by another process each time the prefetcher + // receives an acknowledgement for an inflight request. + while (inflight >= Ninflight) { + wait (1); // cycles + } + } + + // Send the prefetch operation for the calculated cacheline. + // Cachelines are contiguous within a block. + prefetch_address((block_nline + nl)*64); + + // The inflight counter is incremented each time the prefetcher sends a prefetch request. + inflight++; + + // Wait a given number of cycles between two prefetch requests. + // This is a throttling mechanism + wait (Nwait + 1); // cycles + } + + // The first cacheline of a block is offset (defined by the Stride) + // with respect to the previous block. + block_nline += BLOCK_INCREMENT; +} + +// If the cycle bit is not set, update the Base_cline with the +// address that would follow the last accessed one. +if (!cfig.base_cline.c) { + Base_cline = block_nline; +} +\end{lstlisting} +\caption{\alglabel{prefetch_issue}Request issuing algorithm of prefetch engines} +\end{figure} + +\section{Prefetch Abort} + +It is possible for the user to abort an active prefetch sequence from an engine. +To do that, the user can reset to 0 the $\mathsf{enable(E)}$ bit in the $\mathsf{base\_cline}$ \ac{CSR} register of the corresponding prefetcher engine. + +Such action, makes the corresponding target engine to stop its current sequence of prefetch requests. +If there were inflight not-yet-acknowledge requests from that engine, it will wait for the corresponding acknowledgements. +During this time, the prefetcher engine is not usable, and its corresponding $\mathsf{busy}$ bit in the $\mathsf{Status}$ \ac{CSR} is kept set to 1. +While the $\mathsf{busy}$ bit is set to 1, any write in \ac{CSR} registers of that prefetcher engine has no effect on the engine behavior. +However, the modified \ac{CSR} registers will keep the written values. + +When all acknowledgements are received, the corresponding prefetcher engine has its $\mathsf{busy}$ bit set to 0. +All other \ac{CSR} of the prefetcher engine keep their configured values. +At this point, the prefetcher engine is usable and can be reconfigured normally. + +% +% appendix +% +\appendix + +\chapter{Appendices} +\minitoc +\newpage + +\section{RAM macros} +\apxlabel{ram_macros} + +This cache uses memory arrays in multiple subcomponents. +When targeting \acs{ASIC}/\acs{FPGA} implementations integrating this cache, memory arrays shall be implemented using technology-specific \acs{SRAM} macros. +In the case of \acs{FPGA} implementations, this is less critical because synthesis tools for \acs{FPGA} usually select automatically embedded RAMs when possible. + +\Tabref{ram_macros} summarises the instances of RAM macros implemented in the \ac{HPDcache}. +This table has: +\begin{enumerate} +\item The path in the RTL model where that memory array is found; +\item a reference to the section that gives details about their dimensions, the number of instances and their content; +\item the number of read/write ports; +\item the read/write latency. +\end{enumerate} + +\begin{table}[h!] +\begin{center} +\caption{Summary of RAM macros in the \acs*{HPDcache}}% +\tablabel{ram_macros} +{\footnotesize\begin{tabular}{ll} +\toprule +\toprule +\multicolumn{2}{c}{\textbf{\acs{MSHR}}} \\ +\midrule +\textbf{\acs{RTL} Instance} +& \verb$.hpdcache_miss_handler_i.hpdcache_mshr_i.mshr_sram$ \\ +\midrule +\textbf{Details} +& \Secref{mshr_implementation} \\ +\midrule +\textbf{Latency} +& 1 clock cycle (RW) \\ +\midrule +\textbf{Ports} +& 1RW \\ + +\toprule +\toprule +\multicolumn{2}{c}{\textbf{Cache Directory}} \\ +\midrule +\textbf{\acs{RTL} Instance} +& \verb$.hpdcache_ctrl_i.hpdcache_memctrl_i.hpdcache_memarray_i.dir_sram[i]$ \\ +\midrule +\textbf{Details} +& \Secref{dir_data_ram_implementation} \\ +\midrule +\textbf{Latency} +& 1 clock cycle (RW) \\ +\midrule +\textbf{Ports} +& 1RW \\ + +\toprule +\toprule +\multicolumn{2}{c}{\textbf{Cache Data}} \\ +\midrule +\textbf{\acs{RTL} Instance} +& \verb$.hpdcache_ctrl_i.hpdcache_memctrl_i.hpdcache_memarray_i.data_sram[i]$ \\ +\midrule +\textbf{Details} +& \Secref{dir_data_ram_implementation} \\ +\midrule +\textbf{Latency} +& 1 clock cycle (RW) \\ +\midrule +\textbf{Ports} +& 1RW \\ +\end{tabular}} +\end{center} +\end{table} + + +\section{Implementations} +\apxlabel{implementations} + +\subsection{EPI Accelerator and RHEA Chip} + +In the context of the European Processor Initiative (EPI) project, in the accelerator stream~\cite{epac_website_2022}, this cache is used as the L1 data cache for the VRP~\cite{durand_vrp_2022} accelerator that is integrated in both, the EPI accelerator (EPAC1.5) test-chip and the RHEA chip. + +The parameters of the cache are the following on those implementations: + +\begin{tabular}{ll} + \textbf{Capacity} + & 32 KBytes \\ + \textbf{Sets} + & 128 \\ + \textbf{Ways} + & 4 \\ + \textbf{Line Size} + & 64 bytes \\ + \textbf{Physical Address Width} + & 49 bits \\ + \textbf{Write Policy} + & Write-Through \\ + \textbf{Maximum Access width (Requester-side)} + & 32 bytes per cycle \\ +\end{tabular} + +% +% bibliography +% +\printbibliography + +\end{document} diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/hpdcache_spec_changelog.tex b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/hpdcache_spec_changelog.tex new file mode 100755 index 00000000000..5b3242f0dff --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/hpdcache_spec_changelog.tex @@ -0,0 +1,35 @@ +%% +%% Copyright 2023 CEA* +%% *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) +%% +%% SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +%% +%% Licensed under the Solderpad Hardware License v 2.1 (the “License”); you +%% may not use this file except in compliance with the License, or, at your +%% option, the Apache License version 2.0. You may obtain a copy of the +%% License at +%% +%% https://solderpad.org/licenses/SHL-2.1/ +%% +%% Unless required by applicable law or agreed to in writing, any work +%% distributed under the License is distributed on an “AS IS” BASIS, WITHOUT +%% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +%% License for the specific language governing permissions and limitations +%% under the License. +%% +%% Author(s): Cesar Fuguet +%% Date: February, 2023 +%% Description: Specification document of the HPDcache hardware IP +%% +\chapter*{Preface} + +The document contains the version~\docversion~of the HPDcache. + +\section*{Preface to document version~1.0.0-draft} + +The changes in this version of the document include: +\begin{itemize} +\parskip 0pt +\itemsep 1pt +\item Initial version of the L1 data cache (HPDcache) specification. +\end{itemize} diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/hpdcache_spec_preamble.tex b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/hpdcache_spec_preamble.tex new file mode 100755 index 00000000000..fd495de6eae --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/hpdcache_spec_preamble.tex @@ -0,0 +1,351 @@ +%% +%% Copyright 2023 CEA* +%% *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) +%% +%% SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +%% +%% Licensed under the Solderpad Hardware License v 2.1 (the “License”); you +%% may not use this file except in compliance with the License, or, at your +%% option, the Apache License version 2.0. You may obtain a copy of the +%% License at +%% +%% https://solderpad.org/licenses/SHL-2.1/ +%% +%% Unless required by applicable law or agreed to in writing, any work +%% distributed under the License is distributed on an “AS IS” BASIS, WITHOUT +%% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +%% License for the specific language governing permissions and limitations +%% under the License. +%% +%% Author(s): Cesar Fuguet +%% Date: February, 2023 +%% Description: Specification document of the HPDcache hardware IP +%% + +%%% +%% Font packages +%%% +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage{fourier} + +\usepackage{amsmath} +\usepackage{amsthm} + +%\usepackage{lmodern} +\usepackage{xcolor} + +\definecolor{lightgray}{gray}{0.8} + +% use Helvetica Adobe sans serif fonts +\renewcommand{\sfdefault}{phv} + +%%% +%% Language packages +%%% +\usepackage{csquotes} +\usepackage[english]{babel} + +%%% +%% Page margins configuration +%%% +\usepackage{geometry} +\geometry{top=3cm, bottom=3cm} + +%%% +%% Figures' configuration packages and command +%%% +\usepackage{ifpdf} + +\ifpdf +\usepackage[pdftex]{graphicx} +\DeclareGraphicsExtensions{.jpg,.png,.pdf} +\else +\usepackage[dvips]{graphicx} +\DeclareGraphicsExtensions{{.eps}} +\fi + +\usepackage[font=footnotesize,position=top,skip=0pt]{caption} +\usepackage[font=footnotesize,position=top,skip=0pt]{subcaption} + +%%% +%% Tables' configuration packages +%%% +\usepackage{booktabs} +\usepackage{tabularx} +\usepackage{multirow} + +\newcolumntype{L}[1]{>{\hsize=#1\hsize\raggedright\arraybackslash}X}% +\newcolumntype{C}[1]{>{\hsize=#1\hsize\centering\arraybackslash}X}% + +%%% +%% Misc configuration +%%% +\usepackage{minitoc} +\usepackage{emptypage} % prevent headings in empty pages +\usepackage{xspace} +\usepackage{enumitem} +\usepackage[printonlyused]{acronym} +\usepackage{tikz} +\newcommand*\circled[1]{\tikz[baseline=(char.base)]{% + \node[shape=circle,draw=black,inner sep=1pt] (char){\textsf{\bfseries #1}};% + }% +} +\usetikzlibrary{shapes,arrows,chains} + +% Color boxing +\usepackage[many]{tcolorbox} + +%%% +%% Math environments +%%% +\theoremstyle{plain} +\newtheorem{property}{Property}[section] +\newtheorem{lemma}{Lemma}[property] + +\theoremstyle{definition} +\newtheorem{definition}{Definition}[section] + +\newcommand{\eqvar}[1]{$\mathit{#1}$} +\renewcommand\qedsymbol{$\blacksquare$} + +%%% +%% Table of Contents (TOC), and chapters and section titles format +%%% +\usepackage{titletoc} +\usepackage{titlesec} + +%%% +%% To Do notes +%%% +\usepackage[% + colorinlistoftodos, + prependcaption +]{todonotes} + +\ifdefined\isdraft + \newcommand{\TodoSide}[1]{\todo[color=red!20]{\textbf{To do}: #1}} + \newcommand{\NoteSide}[1]{\todo[color=green!20]{\textbf{Note}: #1}} + \newcommand{\Todo}[1]{\todo[inline, color=red!20]{\textbf{To do}: #1}} + \newcommand{\Note}[1]{\todo[inline, color=green!20]{\textbf{Note}: #1}} +\else + \newcommand{\TodoSide}[1]{} + \newcommand{\NoteSide}[1]{} + \newcommand{\Todo}[1]{} + \newcommand{\Note}[1]{} +\fi + + +% maximum depth of the table of contents (2: subsection) + +\setcounter{tocdepth}{2} + +% format for general table of contents +\titlecontents{chapter}% +[1.5em]% +{\addvspace{1em plus 0pt minus 0pt}\bfseries}% +{\contentslabel{1.3em}}% +{\hspace{-1.3em}}% +{\hfill\contentspage}% +[\addvspace{0pt}] + +\titlecontents{section}% +[3.8em]% +{\addvspace{.4em plus 0pt minus 0pt}\bfseries}% +{\contentslabel{2.3em}}% +{}% +{\titlerule*[0.75em]{\normalfont.}\contentspage} + +\titlecontents{subsection}% +[7.0em]% +{\addvspace{.2em plus 0pt minus 0pt}}% +{\contentslabel{3.2em}}% +{}% +{\titlerule*[.75em]{.}\contentspage} + +% format for partial table of contents (at each chapter) + +\titlecontents{psection}% +[2.3em]% +{\addvspace{.4em plus 0pt minus 0pt}\bfseries}% +{\contentslabel{2.3em}}% +{}% +{\titlerule*[.75em]{\normalfont.}\contentspage} + +\titlecontents{psubsection}% +[5.5em]% +{\addvspace{.2em plus 0pt minus 0pt}}% +{\contentslabel{3.2em}}% +{}% +{\titlerule*[.75em]{.}\contentspage} + +\titlecontents{figure}% +[3.8em]% +{\addvspace{.4em plus 0pt minus 0pt}\normalfont}% +{\contentslabel{2.3em}}% +{}% +{\titlerule*[0.75em]{\normalfont.}\contentspage} + +\titlecontents{table}% +[3.8em]% +{\addvspace{.4em plus 0pt minus 0pt}\normalfont}% +{\contentslabel{2.3em}}% +{}% +{\titlerule*[0.75em]{\normalfont.}\contentspage} + +% insert this command at each chapter's beginning to add a partial TOC + +\newcommand{\chaptertoc}{% + \vspace*{1.25ex}% + \vbox{\bfseries\Large Contents}% + \vspace*{1ex}\titlerule% + \normalfont\normalsize% + \startcontents[sections]% + \printcontents[sections]{p}{1}{}% + \vspace*{1ex}\titlerule\vspace*{1ex}% + \newpage} + +\titleformat{\chapter}[display]{\bfseries\huge}% +{\chaptertitlename~\thechapter}{.75ex}% +{\titlerule[2pt]\vspace*{.75ex}\filright}% +[]%[\vspace*{.75ex}\titlerule] +\titlespacing*{\chapter}{0pt}{30pt}{20pt}[0pt] + +\titleformat{\section}[hang]{\normalfont\Large\bfseries}{% + \thesection}{1em}{} +\titlespacing*{\section}{0pt}{% + 3.5ex plus 1ex minus .2ex}{2.3ex plus .2ex}[0pt] + +\titleformat{\subsection}[hang]{\normalfont\large\bfseries}{% + \thesubsection}{1em}{} +\titlespacing*{\subsection}{0pt}{% + 3.25ex plus 1ex minus .2ex}{1.5ex plus .2ex}[0pt] + +\titleformat{\subsubsection}[hang]{\normalfont\normalsize\bfseries}{% + \thesubsubsection}{1em}{} +\titlespacing*{\subsubsection}{0pt}{% + 3.25ex plus 1ex minus .2ex}{1.5ex plus .2ex}[0pt] + +\titleformat{\paragraph}[runin]{\normalfont\normalsize\bfseries}{% + \theparagraph}{1em}{}[] +\titlespacing*{\paragraph}{0pt}{% + 3.25ex plus 1ex minus .2ex}{1em} + +\titleformat{\subparagraph}[runin]{\normalfont\normalsize\bfseries}{% + \thesubparagraph}{1em}{}[] +\titlespacing*{\subparagraph}{\parindent}{% + 3.25ex plus 1ex minus .2ex}{1em} + +%%% +%% Header / footer configuration +%%% +\usepackage{fancyhdr} + +\fancypagestyle{fancystyle}{% + \fancyhf{}% clear header and footer fields + \fancyhead[RO,LE]{\footnotesize\sffamily\nouppercase{\rightmark}}% + \fancyhead[RE,LO]{\footnotesize\sffamily\mbox{}Version~\docversion}% + \fancyfoot[LO,RE]{\footnotesize\sffamily\mbox{}\docauthor}% + \fancyfoot[CE,CO]{\footnotesize\sffamily\mbox{}Copyright~\textcopyright~2023~Commissariat à l'Energie Atomique et aux Energies Alternatives (CEA)}% + \fancyfoot[RO,LE]{\footnotesize\sffamily\mbox{}\thepage}% + \renewcommand{\headrulewidth}{.6pt}% + \renewcommand{\footrulewidth}{.6pt}% +} + +\fancypagestyle{plain}{% + \fancyhf{}% clear header and footer fields + \fancyfoot[C]{\normalfont\sffamily\thepage}% + \renewcommand{\headrulewidth}{0pt}% + \renewcommand{\footrulewidth}{0pt}% +} + +\renewcommand{\sectionmark}{\markright} + +\addtolength{\headheight}{\baselineskip} + +%%% +%% Bibliography configuration +%%% +\usepackage[ + backend=biber, + bibencoding=utf8, + citestyle=ieee, + style=ieee +]{biblatex} + +%%% +%% Hyperref package (must be declared at last to avoid conflicts) +%%% +\usepackage[pdfusetitle]{hyperref} +\usepackage{url} +\hypersetup{% +colorlinks,% +linkcolor=blue% +} + +%% Plot drawing package +\usepackage{pgfplots} + +%% Programming code formatting +\usepackage{listings} + +%% Algorithm formatting +\usepackage{algorithm} +\usepackage{algorithmic} + +%% Formatting of network protocol specification +\usepackage{bytefield} + + +%%% +%% Definition of command aliases +%%% +%%% +%% Add vertical space between paragraphs and remove indentation +%%% +\usepackage{parskip} + +% keep the parskip for theorems (AMS packages). +\makeatletter +\def\thm@space@setup{% + \thm@preskip=\parskip \thm@postskip=0pt +} +\makeatother + +%%% +%% Label and reference commands +%%% +\newcommand{\figfont}[1]{\textsf{\bfseries #1}} + +\newcommand{\figlabel}[1]{\label{fig:#1}} +\newcommand{\Figref}[1]{\hyperref[fig:#1]{\mbox{Figure~\ref{fig:#1}}}} +\newcommand{\figref}[1]{\hyperref[fig:#1]{\mbox{figure~\ref{fig:#1}}}} +\newcommand{\fighypref}[2]{\hyperref[fig:#1]{#2}} +\newcommand{\chalabel}[1]{\label{cha:#1}} +\newcommand{\Charef}[1]{\hyperref[cha:#1]{\mbox{Chapter~\ref{cha:#1}}}} +\newcommand{\charef}[1]{\hyperref[cha:#1]{\mbox{chapter~\ref{cha:#1}}}} +\newcommand{\chafullref}[1]{Chapter~\ref{cha:#1}-\nameref{cha:#1}} +\newcommand{\chahypref}[2]{\hyperref[cha:#1]{#2}} +\newcommand{\seclabel}[1]{\label{sec:#1}} +\newcommand{\Secref}[1]{\hyperref[sec:#1]{\mbox{Section~\ref{sec:#1}}}} +\newcommand{\secref}[1]{\hyperref[sec:#1]{\mbox{section~\ref{sec:#1}}}} +\newcommand{\sechypref}[2]{\hyperref[sec:#1]{#2}} +\newcommand{\apxlabel}[1]{\label{apx:#1}} +\newcommand{\Apxref}[1]{\hyperref[apx:#1]{\mbox{Appendix~\ref{apx:#1}}}} +\newcommand{\apxref}[1]{\hyperref[apx:#1]{\mbox{appendix~\ref{apx:#1}}}} +\newcommand{\apxhypref}[2]{\hyperref[apx:#1]{#2}} +\newcommand{\tablabel}[1]{\label{tab:#1}} +\newcommand{\Tabref}[1]{\hyperref[tab:#1]{\mbox{Table~\ref{tab:#1}}}} +\newcommand{\tabref}[1]{\hyperref[tab:#1]{\mbox{table~\ref{tab:#1}}}} +\newcommand{\tabhypref}[2]{\hyperref[tab:#1]{#2}} +\newcommand{\alglabel}[1]{\label{alg:#1}} +\newcommand{\Algref}[1]{\hyperref[alg:#1]{\mbox{Algorithm~\ref{alg:#1}}}} +\newcommand{\algref}[1]{\hyperref[alg:#1]{\mbox{algorithm~\ref{alg:#1}}}} +\newcommand{\alghypref}[2]{\hyperref[alg:#1]{#2}} +\newcommand{\prplabel}[1]{\label{prp:#1}} +\newcommand{\prpref}[1]{\hyperref[prp:#1]{\mbox{Property~\ref{prp:#1}}}} +\newcommand{\lemlabel}[1]{\label{lem:#1}} +\newcommand{\lemref}[1]{\hyperref[lem:#1]{\mbox{Lemma~\ref{lem:#1}}}} +\newcommand{\deflabel}[1]{\label{def:#1}} +\newcommand{\defref}[1]{\hyperref[def:#1]{\mbox{Definition~\ref{def:#1}}}} + diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_back_to_back.svg b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_back_to_back.svg new file mode 100755 index 00000000000..fea7140c0ab --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_back_to_back.svg @@ -0,0 +1,4 @@ + + + +012345CLKPAYLOADdat0dat1VALIDREADY \ No newline at end of file diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_ready_before_valid.svg b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_ready_before_valid.svg new file mode 100755 index 00000000000..a7dd0fa115b --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_ready_before_valid.svg @@ -0,0 +1,4 @@ + + + +01234CLKPAYLOADdataVALIDREADY \ No newline at end of file diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_ready_when_valid.svg b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_ready_when_valid.svg new file mode 100755 index 00000000000..587f606ee53 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_ready_when_valid.svg @@ -0,0 +1,4 @@ + + + +01234CLKPAYLOADdataVALIDREADY \ No newline at end of file diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_valid_before_ready.svg b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_valid_before_ready.svg new file mode 100755 index 00000000000..ccc7b4f67db --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/exported/wave_valid_before_ready.svg @@ -0,0 +1,4 @@ + + + +01234CLKPAYLOADdataVALIDREADY \ No newline at end of file diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_core.svg b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_core.svg new file mode 100644 index 00000000000..76db8edfe47 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_core.svg @@ -0,0 +1,3436 @@ + + + + + HPDcache Core + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + HPDcache Core + February, 2023 + + + Cesar Fuguet + + + + + Commissaria a l'Energie Atomique et aux Energies Alternatives (CEA) + + + + + + + + English + + + + + + + + + + + + Miss Handler + + + + + + + + + +  Cache Directory and Data + + + + + + + + + + + + + + + + + + ways + + + sets + + v tag + + + + + = + + + + + + data to processor + + + + + + + + + tags + + @tag + hit + + + + + + + valids + @set + + way1 + way0 + + + + sets xwords/x_cuts + + {@set,@word[2]} + + + + + + + @word[1:0] + + + + + en[3] + en[2] + en[1] + en[0] + + 64 bits + + + + + @word[1:0] + + + + + + + + + way1 + way0 + + + way1 + way0 + + + way1 + way0 + + set0:word3 + set0:word2 + set0:word1 + set0:word0 + + + set0:word7 + set0:word6 + set0:word5 + set0:word4 + + + + set1:word3 + set1:word2 + set1:word1 + set1:word0 + + + set1:word7 + set1:word6 + set1:word5 + set1:word4 + + + set127:word3 + set127:word2 + set127:word1 + set127:word0 + + + set127:word7 + set127:word6 + set127:word5 + set127:word4 + + way3 + way2 + way3 + way2 + way3 + way2 + way3 + way2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + way selection + word selection + + + + + MSHR + + + + Uncacheable & AMOHandler (UC) + + + + + + + + + + + CacheManagementOperationHandler (CMO) + + + + + + + + + + + + Cache Controller + + ARBITER + + REFILL + + + + Write Buffer(WBUF) + + + Data + + + + Dir + + + + CONFIGURATION + + READMISSREQUEST + HPDcache Core + REQ + + RSP + + + + + READMISSRESPONSE + + ProtocolEngineStage 0 + + + + + + + + + + + + READUNCACHEDREQUEST + READUNCACHEDRESPONSE + + + WRITE/AMOUNCACHEDREQUEST + WRITE/AMOUNCACHEDRESPONSE + + + WRITEREQUEST + WRITERESPONSE + + ProtocolEngineStage 1 + + + + + + + + ProtocolEngineStage 2 + + + + + + + + + + + + + + ReplayTable(RTAB) +   + + diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_data_ram_organization.svg b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_data_ram_organization.svg new file mode 100755 index 00000000000..915dd28aa0a --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_data_ram_organization.svg @@ -0,0 +1,2344 @@ + + + + + HPDcache Data RAM Organization + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + HPDcache Data RAM Organization + February, 2023 + + + Cesar Fuguet + + + + + Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + + + English + + + + + + + + + + + + + + + + + + + + + + ways + + + sets + + + tag + + + + set + word + + tag + @ + 64-bits address from processor + 63 + 0 + + + + + = + + + + + + data to processor + + + + + + + + + tags + + @tag + hit + + + + + + + valids + @set + + + 55 + 56 + + 2 + 5 + 6 + 12 + 13 + + + way1 + way0 + + + + + + sets xwords/x_cuts + + {@set,@word[2]} + + + + + + + @word[1:0] + + + + + en[3] + en[2] + en[1] + en[0] + + 64 bits + + + + + @word[1:0] + + + + + + + + + way1 + way0 + + + way1 + way0 + + + way1 + way0 + + set0:word3 + set0:word2 + set0:word1 + set0:word0 + + + set0:word7 + set0:word6 + set0:word5 + set0:word4 + + + + set1:word3 + set1:word2 + set1:word1 + set1:word0 + + + set1:word7 + set1:word6 + set1:word5 + set1:word4 + + + set127:word3 + set127:word2 + set127:word1 + set127:word0 + + + set127:word7 + set127:word6 + set127:word5 + set127:word4 + + way3 + way2 + way3 + way2 + way3 + way2 + way3 + way2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + way selection + word selection + 3 + + + diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_request_address_data_alignment.svg b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_request_address_data_alignment.svg new file mode 100755 index 00000000000..5d9119ecf1d --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_request_address_data_alignment.svg @@ -0,0 +1,2016 @@ + + + HPDcache Request Address Data Alignment + + + + image/svg+xml + + HPDcache Request Address Data Alignment + February, 2023 + + + Cesar Fuguet + + + + + Commissariat a l'Energie Atomique et aux Energies Alternatives + + + English + + + + + + + + + @8004 + + + + + + WDATA + + BE + + + + 1 + + + + + + + + + 0 + + + + + + + + + 0xAA + + 0xBB + + 0xCC + + 0xDD + + + + + + + + + + @8008 + + 0 + + 0 + + + + + + 0 + + 0 + + + + + + 0xBB + + 0xAA + + 0x99 + + 0x88 + + 1 + + 1 + + 1 + + 1 + + 0xCC + + 0xDD + + 0xEE + + 0xFF + + 1 + + 1 + + 1 + + 1 + + XX + + XX + + + + 0 + + 0 + + 0 + + 0 + + @8009 + + + + 0 + + 56 + + 127 + + 64 + + + 8 + + 0 + + 1 + + 15 + + 8 + + 7 + + + + + + + + + + + + + + + + + + 0xAA + + + + + 1 + + + + + + + + + + + WDATA + + WDATA + + BE + + BE + + + XX + XX + XX + XX + XX + XX + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + XX + XX + XX + XX + XX + XX + XX + XX + XX + XX + XX + XX + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + XX + XX + XX + XX + XX + XX + XX + XX + XX + XX + XX + XX + XX + XX + XX + 0 + + 56 + 127 + + 64 + + + 8 + 0 + + 1 + 15 + + 8 + + 7 + 0 + 56 + 127 + 64 + 8 + 0 + + 1 + 15 + + 8 + + 7 + SIZE=3 (8 bytes) + SIZE=2 (4 bytes) + SIZE=0 (1 byte) + diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_request_arbiter.svg b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_request_arbiter.svg new file mode 100644 index 00000000000..9fe73bbad77 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/hpdcache_request_arbiter.svg @@ -0,0 +1,428 @@ + + + HPDcache Request Arbiter + + + + image/svg+xml + + HPDcache Request Arbiter + February, 2023 + + + Cesar Fuguet + + + + + Commissariat a l'Energie Atomique et aux Energies Alternatives + + + English + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 1 + 2 + N-1 + + + N + HPDcache + + CSRs + + + HPDcacheCore + MemoryInterface + Requester0 + Requester1 + Requester2 + RequesterN-1 + ... + HardwareMemoryPrefetcher + 1 request/cycle + Fixed-Priority Arbiter + diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_back_to_back.json b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_back_to_back.json new file mode 100755 index 00000000000..c4fecb2662e --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_back_to_back.json @@ -0,0 +1,10 @@ +{signal: [ + {name: 'CLK', wave: 'p....'}, + {name: 'PAYLOAD', wave: 'xx22x', data: ['dat0', 'dat1']}, + {name: 'VALID', wave: '0.1.0'}, + {name: 'READY', wave: '01..0'} +], + head:{ + tick:0 + } +} diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_ready_before_valid.json b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_ready_before_valid.json new file mode 100755 index 00000000000..fe8a44623b7 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_ready_before_valid.json @@ -0,0 +1,10 @@ +{signal: [ + {name: 'CLK', wave: 'p...'}, + {name: 'PAYLOAD', wave: 'x.2x', data: ['data']}, + {name: 'VALID', wave: '0.10'}, + {name: 'READY', wave: '01.0'} +], + head:{ + tick:0 + } +} diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_ready_when_valid.json b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_ready_when_valid.json new file mode 100755 index 00000000000..35075278afa --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_ready_when_valid.json @@ -0,0 +1,10 @@ +{signal: [ + {name: 'CLK', wave: 'p...'}, + {name: 'PAYLOAD', wave: 'x.2x', data: ['data']}, + {name: 'VALID', wave: '0.10'}, + {name: 'READY', wave: '0.10'} +], + head:{ + tick:0 + } +} diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_valid_before_ready.json b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_valid_before_ready.json new file mode 100755 index 00000000000..16c313eb190 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/source/images/wave_valid_before_ready.json @@ -0,0 +1,10 @@ +{signal: [ + {name: 'CLK', wave: 'p...'}, + {name: 'PAYLOAD', wave: 'x2.x', data: ['data']}, + {name: 'VALID', wave: '01.0'}, + {name: 'READY', wave: '0.10'} +], + head:{ + tick:0 + } +} diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/supplement/download_wavedrom.sh b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/supplement/download_wavedrom.sh new file mode 100644 index 00000000000..7dbf9c3c744 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/supplement/download_wavedrom.sh @@ -0,0 +1,22 @@ +#!/bin/bash +WAVEDROM_ARCHIVE=wavedrom-editor-v2.9.1-linux-x64 +WAVEDROM_URL=https://github.com/wavedrom/wavedrom.github.io/releases/download/v2.9.1/${WAVEDROM_ARCHIVE}.tar.gz + +WAVEDROM_CLI=package/wavedrom/wavedrom-cli.js +WAVEDROM_CLI_URL=https://github.com/wavedrom/cli/releases/download/v0.3.1/wavedrom-cli.js + +echo -e 'Download the archive' +if [[ ! -e ${WAVEDROM_ARCHIVE}.tar.gz ]]; then + wget -q ${WAVEDROM_URL} +fi + +echo -e 'Decompress the archive' +if [[ ! -e package/wavedrom/${WAVEDROM_ARCHIVE} ]]; then + mkdir -p package/wavedrom + tar xzf ${WAVEDROM_ARCHIVE} -C package/wavedrom +fi + +echo -e 'Download wavedrom command-line client' +if [[ ! -e ${WAVEDROM_CLI} ]]; then + wget -q -O ${WAVEDROM_CLI} ${WAVEDROM_CLI_URL} +fi diff --git a/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/version b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/version new file mode 100644 index 00000000000..2f79e10c82a --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/docs/hpdcache_spec_document/version @@ -0,0 +1 @@ +1.1.0-draft diff --git a/vendor/openhwgroup/cvhpdcache/rtl/hpdcache.Flist b/vendor/openhwgroup/cvhpdcache/rtl/hpdcache.Flist new file mode 100644 index 00000000000..fa7a1aa03a7 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/hpdcache.Flist @@ -0,0 +1,64 @@ +// +// Copyright 2023 CEA* +// *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you +// may not use this file except in compliance with the License, or, at your +// option, the Apache License version 2.0. You may obtain a copy of the +// License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// +// Authors : Cesar Fuguet +// Creation Date : January, 2023 +// Description : File list for the HPDcache +// History : +// ++incdir+${HPDCACHE_DIR}/rtl/include +${HPDCACHE_DIR}/rtl/src/hpdcache_pkg.sv +${HPDCACHE_DIR}/rtl/src/common/hpdcache_demux.sv +${HPDCACHE_DIR}/rtl/src/common/hpdcache_fifo_reg.sv +${HPDCACHE_DIR}/rtl/src/common/hpdcache_fxarb.sv +${HPDCACHE_DIR}/rtl/src/common/hpdcache_rrarb.sv +${HPDCACHE_DIR}/rtl/src/common/hpdcache_mux.sv +${HPDCACHE_DIR}/rtl/src/common/hpdcache_prio_1hot_encoder.sv +${HPDCACHE_DIR}/rtl/src/common/hpdcache_sram.sv +${HPDCACHE_DIR}/rtl/src/common/hpdcache_sram_wbyteenable.sv +${HPDCACHE_DIR}/rtl/src/common/hpdcache_sram_wmask.sv +${HPDCACHE_DIR}/rtl/src/common/hpdcache_regbank_wbyteenable_1rw.sv +${HPDCACHE_DIR}/rtl/src/common/hpdcache_regbank_wmask_1rw.sv +${HPDCACHE_DIR}/rtl/src/common/hpdcache_data_downsize.sv +${HPDCACHE_DIR}/rtl/src/common/hpdcache_data_upsize.sv +${HPDCACHE_DIR}/rtl/src/hwpf_stride/hwpf_stride_pkg.sv +${HPDCACHE_DIR}/rtl/src/hwpf_stride/hwpf_stride.sv +${HPDCACHE_DIR}/rtl/src/hwpf_stride/hwpf_stride_arb.sv +${HPDCACHE_DIR}/rtl/src/hwpf_stride/hwpf_stride_snooper.sv +${HPDCACHE_DIR}/rtl/src/hwpf_stride/hwpf_stride_wrapper.sv +${HPDCACHE_DIR}/rtl/src/hpdcache.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_amo.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_cmo.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_core_arbiter.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_ctrl.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_ctrl_pe.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_memarray.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_memctrl.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_miss_handler.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_mshr.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_mshr_to_cache_set.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_plru.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_rtab.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_uncached.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_wbuf.sv +${HPDCACHE_DIR}/rtl/src/hpdcache_wbuf_wrapper.sv +${HPDCACHE_DIR}/rtl/src/utils/hpdcache_mem_req_read_arbiter.sv +${HPDCACHE_DIR}/rtl/src/utils/hpdcache_mem_req_write_arbiter.sv +${HPDCACHE_DIR}/rtl/src/utils/hpdcache_mem_resp_demux.sv diff --git a/vendor/openhwgroup/cvhpdcache/rtl/hpdcache_cva6.Flist b/vendor/openhwgroup/cvhpdcache/rtl/hpdcache_cva6.Flist new file mode 100644 index 00000000000..e0a138eb441 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/hpdcache_cva6.Flist @@ -0,0 +1,35 @@ +// +// Copyright 2023 CEA* +// *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you +// may not use this file except in compliance with the License, or, at your +// option, the Apache License version 2.0. You may obtain a copy of the +// License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// +// +// Authors : Cesar Fuguet +// Creation Date : January, 2023 +// Description : File list for the HPDcache and adapters for the CVA6 core +// History : +// +${HPDCACHE_DIR}/rtl/src/target/cva6/cva6_hpdcache_params_pkg.sv +-F ${HPDCACHE_DIR}/rtl/hpdcache.Flist +${HPDCACHE_DIR}/rtl/src/utils/hpdcache_mem_to_axi_read.sv +${HPDCACHE_DIR}/rtl/src/utils/hpdcache_mem_to_axi_write.sv +${HPDCACHE_DIR}/rtl/src/target/cva6/cva6_hpdcache_subsystem.sv +${HPDCACHE_DIR}/rtl/src/target/cva6/cva6_hpdcache_subsystem_axi_arbiter.sv +${HPDCACHE_DIR}/rtl/src/target/cva6/cva6_hpdcache_if_adapter.sv + +//+define+HPDCACHE_ENABLE_CMO +//${HPDCACHE_DIR}/rtl/src/target/cva6/cva6_hpdcache_cmo_if_adapter.sv diff --git a/vendor/openhwgroup/cvhpdcache/rtl/include/hpdcache_typedef.svh b/vendor/openhwgroup/cvhpdcache/rtl/include/hpdcache_typedef.svh new file mode 100644 index 00000000000..5e92a791a81 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/include/hpdcache_typedef.svh @@ -0,0 +1,62 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : February, 2023 + * Description : HPDcache Types' Definition + * History : + */ +`ifndef __HPDCACHE_TYPEDEF_SVH__ +`define __HPDCACHE_TYPEDEF_SVH__ + +`define HPDCACHE_TYPEDEF_MEM_REQ_T(__name__, addr_t, id_t) \ + typedef struct packed { \ + addr_t mem_req_addr; \ + hpdcache_pkg::hpdcache_mem_len_t mem_req_len; \ + hpdcache_pkg::hpdcache_mem_size_t mem_req_size; \ + id_t mem_req_id; \ + hpdcache_pkg::hpdcache_mem_command_e mem_req_command; \ + hpdcache_pkg::hpdcache_mem_atomic_e mem_req_atomic; \ + logic mem_req_cacheable; \ + } __name__ + +`define HPDCACHE_TYPEDEF_MEM_RESP_R_T(__name__, id_t, data_t) \ + typedef struct packed { \ + hpdcache_pkg::hpdcache_mem_error_e mem_resp_r_error; \ + id_t mem_resp_r_id; \ + data_t mem_resp_r_data; \ + logic mem_resp_r_last; \ + } __name__ + +`define HPDCACHE_TYPEDEF_MEM_REQ_W_T(__name__, data_t, be_t) \ + typedef struct packed { \ + data_t mem_req_w_data; \ + be_t mem_req_w_be; \ + logic mem_req_w_last; \ + } __name__ + +`define HPDCACHE_TYPEDEF_MEM_RESP_W_T(__name__, id_t) \ + typedef struct packed { \ + logic mem_resp_w_is_atomic; \ + hpdcache_pkg::hpdcache_mem_error_e mem_resp_w_error; \ + id_t mem_resp_w_id; \ + } __name__ + +`endif diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_data_downsize.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_data_downsize.sv new file mode 100644 index 00000000000..33816790e93 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_data_downsize.sv @@ -0,0 +1,187 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : November 22, 2022 + * Description : Refill data downsize + * History : + */ +module hpdcache_data_downsize +// {{{ +import hpdcache_pkg::*; +// Parameters +// {{{ +#( + parameter int WR_WIDTH = 0, + parameter int RD_WIDTH = 0, + parameter int DEPTH = 0, + + localparam type wdata_t = logic [WR_WIDTH-1:0], + localparam type rdata_t = logic [RD_WIDTH-1:0] +) +// }}} +// Ports +// {{{ +( + input logic clk_i, + input logic rst_ni, + + input logic w_i, + output logic wok_o, + input wdata_t wdata_i, + + input logic r_i, + output logic rok_o, + output rdata_t rdata_o +); +// }}} +// Architecture +// {{{ + // Local definitions + // {{{ + localparam int RD_WORDS = WR_WIDTH/RD_WIDTH; + localparam int PTR_WIDTH = $clog2(DEPTH); + localparam int WORDCNT_WIDTH = $clog2(RD_WORDS); + typedef logic [PTR_WIDTH-1:0] bufptr_t; + typedef logic [WORDCNT_WIDTH-1:0] wordptr_t; + typedef logic [PTR_WIDTH:0] occupancy_t; + // }}} + + // Internal registers and signals + // {{{ + rdata_t [DEPTH-1:0][RD_WORDS-1:0] buf_q; + bufptr_t wrptr_q, wrptr_d; + bufptr_t rdptr_q, rdptr_d; + occupancy_t used_q, used_d; + logic used_inc, used_dec; + wordptr_t [DEPTH-1:0] words_q, words_d; + logic words_set, words_dec; + logic full, empty; + // }}} + + // Control-Path + // {{{ + assign full = (hpdcache_uint'(used_q) == DEPTH), + empty = (used_q == 0), + wok_o = ~full, + rok_o = ~empty; + + always_comb + begin : write_comb + wrptr_d = wrptr_q; + used_inc = 1'b0; + words_set = 1'b0; + if (w_i && wok_o) begin + used_inc = 1'b1; + words_set = 1'b1; + if (hpdcache_uint'(wrptr_q) == (DEPTH-1)) begin + wrptr_d = 0; + end else begin + wrptr_d = wrptr_q + 1; + end + end + end + + always_comb + begin : read_comb + rdptr_d = rdptr_q; + words_dec = 1'b0; + used_dec = 1'b0; + if (r_i && rok_o) begin + words_dec = (words_q[rdptr_q] > 0); + if (words_q[rdptr_q] == 0) begin + used_dec = 1'b1; + if (hpdcache_uint'(rdptr_q) == (DEPTH-1)) begin + rdptr_d = 0; + end else begin + rdptr_d = rdptr_q + 1; + end + end + end + end + + always_comb + begin : used_comb + case ({used_inc, used_dec}) + 2'b10 : used_d = used_q + 1; + 2'b01 : used_d = used_q - 1; + default: used_d = used_q; + endcase + end + + always_comb + begin : words_comb + words_d = words_q; + if (words_set) begin + words_d[wrptr_q] = wordptr_t'(RD_WORDS - 1); + end + if (words_dec) begin + words_d[rdptr_q] = words_q[rdptr_q] - 1; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) + begin : ctrl_ff + if (!rst_ni) begin + rdptr_q <= 0; + wrptr_q <= 0; + used_q <= 0; + words_q <= 0; + end else begin + rdptr_q <= rdptr_d; + wrptr_q <= wrptr_d; + used_q <= used_d; + words_q <= words_d; + end + end + // }}} + + // Data-Path + // {{{ + always_ff @(posedge clk_i or negedge rst_ni) + begin : buf_ff + if (!rst_ni) begin + buf_q <= '0; + end else begin + if (words_set) begin + buf_q[wrptr_q] <= wdata_i; + end + end + end + + assign rdata_o = buf_q[rdptr_q][RD_WORDS - hpdcache_uint'(words_q[rdptr_q]) - 1]; + // }}} + + // Assertions + // {{{ + // pragma translate_off + initial + begin : initial_assertions + assert (DEPTH > 0) else $error("DEPTH must be greater than 0"); + assert (WR_WIDTH > 0) else $error("WR_WIDTH must be greater than 0"); + assert (RD_WIDTH > 0) else $error("RD_WIDTH must be greater than 0"); + assert (RD_WIDTH < WR_WIDTH) else $error("RD_WIDTH must be less to WR_WIDTH"); + assert ((WR_WIDTH % RD_WIDTH) == 0) else $error("WR_WIDTH must be a multiple RD_WIDTH"); + end + // pragma translate_on + // }}} +// }}} +endmodule +// }}} diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_data_upsize.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_data_upsize.sv new file mode 100644 index 00000000000..1017dee3b70 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_data_upsize.sv @@ -0,0 +1,189 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : November 22, 2022 + * Description : Refill data upsize + * History : + */ +module hpdcache_data_upsize +// {{{ +import hpdcache_pkg::*; +// Parameters +// {{{ +#( + parameter int WR_WIDTH = 0, + parameter int RD_WIDTH = 0, + parameter int DEPTH = 0, + + localparam type wdata_t = logic [WR_WIDTH-1:0], + localparam type rdata_t = logic [RD_WIDTH-1:0] +) +// }}} +// Ports +// {{{ +( + input logic clk_i, + input logic rst_ni, + + input logic w_i, + input logic wlast_i, + output logic wok_o, + input wdata_t wdata_i, + + input logic r_i, + output logic rok_o, + output rdata_t rdata_o +); +// }}} +// Architecture +// {{{ + // Local definitions + // {{{ + localparam int WR_WORDS = RD_WIDTH/WR_WIDTH; + localparam int PTR_WIDTH = $clog2(DEPTH); + localparam int WORDCNT_WIDTH = $clog2(WR_WORDS); + typedef logic [PTR_WIDTH-1:0] bufptr_t; + typedef logic [WORDCNT_WIDTH-1:0] wordptr_t; + typedef logic [PTR_WIDTH:0] occupancy_t; + // }}} + + // Internal registers and signals + // {{{ + wdata_t [DEPTH-1:0][WR_WORDS-1:0] buf_q; + bufptr_t wrptr_q, wrptr_d; + bufptr_t rdptr_q, rdptr_d; + occupancy_t used_q, used_d; + logic used_inc, used_dec; + wordptr_t [DEPTH-1:0] words_q, words_d; + logic words_inc, words_reset; + logic full, empty; + logic shift; + // }}} + + // Control-Path + // {{{ + assign full = (hpdcache_uint'(used_q) == DEPTH), + empty = (used_q == 0), + wok_o = ~full, + rok_o = ~empty; + + always_comb + begin : write_comb + wrptr_d = wrptr_q; + used_inc = 1'b0; + words_inc = 1'b0; + shift = 1'b0; + if (w_i && wok_o) begin + shift = 1'b1; + words_inc = (hpdcache_uint'(words_q[wrptr_q]) < (WR_WORDS-1)); + if (hpdcache_uint'(words_q[wrptr_q]) == (WR_WORDS-1) || wlast_i) begin + used_inc = 1'b1; + if (hpdcache_uint'(wrptr_q) == (DEPTH-1)) begin + wrptr_d = 0; + end else begin + wrptr_d = wrptr_q + 1; + end + end + end + end + + always_comb + begin : read_comb + rdptr_d = rdptr_q; + used_dec = 1'b0; + words_reset = 1'b0; + if (r_i && rok_o) begin + used_dec = 1'b1; + words_reset = 1'b1; + if (hpdcache_uint'(rdptr_q) == (DEPTH-1)) begin + rdptr_d = 0; + end else begin + rdptr_d = rdptr_q + 1; + end + end + end + + always_comb + begin : used_comb + case ({used_inc, used_dec}) + 2'b10 : used_d = used_q + 1; + 2'b01 : used_d = used_q - 1; + default: used_d = used_q; + endcase + end + + always_comb + begin : words_comb + words_d = words_q; + if (words_inc) begin + words_d[wrptr_q] = words_q[wrptr_q] + 1; + end + if (words_reset) begin + words_d[rdptr_q] = 0; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) + begin : ctrl_ff + if (!rst_ni) begin + rdptr_q <= 0; + wrptr_q <= 0; + used_q <= 0; + words_q <= '0; + end else begin + rdptr_q <= rdptr_d; + wrptr_q <= wrptr_d; + used_q <= used_d; + words_q <= words_d; + end + end + // }}} + + // Data-Path + // {{{ + always_ff @(posedge clk_i or negedge rst_ni) + begin : buf_ff + if (!rst_ni) begin + buf_q <= '0; + end else begin + if (shift) buf_q[wrptr_q][words_q[wrptr_q]] <= wdata_i; + end + end + + assign rdata_o = buf_q[rdptr_q]; + // }}} + + // Assertions + // {{{ + // pragma translate_off + initial + begin : initial_assertions + assert (DEPTH > 0) else $error("DEPTH must be greater than 0"); + assert (WR_WIDTH > 0) else $error("WR_WIDTH must be greater than 0"); + assert (RD_WIDTH > 0) else $error("RD_WIDTH must be greater than 0"); + assert (WR_WIDTH < RD_WIDTH) else $error("WR_WIDTH must be less to RD_WIDTH"); + assert ((RD_WIDTH % WR_WIDTH) == 0) else $error("RD_WIDTH must be a multiple WR_WIDTH"); + end + // pragma translate_on + // }}} +// }}} +endmodule +// }}} diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_demux.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_demux.sv new file mode 100644 index 00000000000..3be21e0814e --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_demux.sv @@ -0,0 +1,69 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : Simple multiplexor + * History : + */ +module hpdcache_demux +// Parameters +// {{{ +#( + // Number of outputs + parameter int unsigned NOUTPUT = 0, + + // Width in bits of each input + parameter int unsigned DATA_WIDTH = 0, + + // Selector signal is one-hot encoded + parameter bit ONE_HOT_SEL = 0, + + // Compute the width of the selection signal + localparam int unsigned NOUTPUT_LOG2 = $clog2(NOUTPUT), + localparam int unsigned SEL_WIDTH = ONE_HOT_SEL ? NOUTPUT : NOUTPUT_LOG2, + + localparam type data_t = logic [DATA_WIDTH-1:0], + localparam type sel_t = logic [SEL_WIDTH-1:0] +) +// }}} + +// Ports +// {{{ +( + input data_t data_i, + input sel_t sel_i, + output data_t [NOUTPUT-1:0] data_o +); +// }}} + + generate + always_comb + begin : demux_comb + for (int unsigned i = 0; i < NOUTPUT; i++) begin + if (!ONE_HOT_SEL) begin + data_o[i] = (sel_t'(i) == sel_i) ? data_i : '0; + end else begin + data_o[i] = sel_i[i] ? data_i : '0; + end + end + end + endgenerate +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_fifo_reg.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_fifo_reg.sv new file mode 100644 index 00000000000..5e6eabf5ed1 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_fifo_reg.sv @@ -0,0 +1,144 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : FIFO buffer (using registers) + * Based on design of Ivan Miro-Panades + * History : + */ +module hpdcache_fifo_reg + // Parameters + // {{{ +#( + parameter int unsigned FIFO_DEPTH = 0, + parameter type fifo_data_t = logic +) + // }}} + // Ports + // {{{ +( + input logic clk_i, + input logic rst_ni, + input logic w_i, + output logic wok_o, + input fifo_data_t wdata_i, + input logic r_i, + output logic rok_o, + output fifo_data_t rdata_o +); + // }}} + + // Declaration of constants, types and functions + // {{{ + typedef logic unsigned [$clog2(FIFO_DEPTH)-1:0] fifo_addr_t; + // }}} + + // Declaration of internal wires and registers + // {{{ + fifo_data_t [FIFO_DEPTH-1:0] fifo_mem_q; + fifo_addr_t rptr_q, rptr_d; // read pointer + fifo_addr_t wptr_q, wptr_d; // write pointer + logic crossover_q, crossover_d; // write pointer has wrap + logic rexec, wexec; + logic rptr_max, wptr_max; + logic match_ptr; + // }}} + + // Global control signals + // {{{ + assign match_ptr = (wptr_q == rptr_q); + assign rok_o = match_ptr ? crossover_q : 1'b1; + assign wok_o = match_ptr ? ~crossover_q : 1'b1; + assign rexec = rok_o & r_i; + assign wexec = wok_o & w_i; + // }}} + + // Control of read and write pointers + // {{{ + assign rptr_max = (rptr_q == fifo_addr_t'(FIFO_DEPTH-1)); + assign wptr_max = (wptr_q == fifo_addr_t'(FIFO_DEPTH-1)); + + always_comb + begin : rptr_comb + if (rexec) begin + rptr_d = rptr_max ? 0 : rptr_q + 1; + end else begin + rptr_d = rptr_q; + end + end + + always_comb + begin : wptr_comb + if (wexec) begin + wptr_d = wptr_max ? 0 : wptr_q + 1; + end else begin + wptr_d = wptr_q; + end + end + + always_comb + begin : crossover_comb + if (rexec && rptr_max) begin + crossover_d = 1'b0; + end else if (wexec && wptr_max) begin + crossover_d = 1'b1; + end else begin + crossover_d = crossover_q; + end + end + // }}} + + // FIFO buffer memory management + // {{{ + always_ff @(posedge clk_i) + begin + if (wexec) fifo_mem_q[wptr_q] <= wdata_i; + end + + assign rdata_o = fifo_mem_q[rptr_q]; + // }}} + + // Setting of internal state + // {{{ + always_ff @(posedge clk_i or negedge rst_ni) + begin + if (!rst_ni) begin + rptr_q <= 0; + wptr_q <= 0; + crossover_q <= 1'b0; + end else begin + rptr_q <= rptr_d; + wptr_q <= wptr_d; + crossover_q <= crossover_d; + end + end + // }}} + + // Assertions + // {{{ + // pragma translate_off + rptr_ahead_wptr_assert: assert property (@(posedge clk_i) + ((rptr_q <= wptr_q) && !crossover_q) || ((rptr_q >= wptr_q) && crossover_q)) else + $error("fifo: read pointer is ahead of the write pointer"); + // pragma translate_on + // }}} + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_fxarb.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_fxarb.sv new file mode 100644 index 00000000000..292eada7dbc --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_fxarb.sv @@ -0,0 +1,85 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : Fixed-Priority Arbiter + * History : + */ +module hpdcache_fxarb + // Parameters + // {{{ +#( + // Number of requesters + parameter int unsigned N = 0 +) + // }}} + // Ports + // {{{ +( + input logic clk_i, + input logic rst_ni, + input logic [N-1:0] req_i, + output logic [N-1:0] gnt_o, + input logic ready_i +); + // }}} + + // Declaration of internal wires and registers + // {{{ + logic [N-1:0] gnt_q, gnt; + logic wait_q; + // }}} + + // Compute the grant vector + // {{{ + hpdcache_prio_1hot_encoder #(.N(N)) prio_msk_i (.val_i(req_i), .val_o(gnt)); + // }}} + + // Compute the output grant vector + // {{{ + assign gnt_o = wait_q ? gnt_q : gnt; + // }}} + + // Setting of internal state + // {{{ + always_ff @(posedge clk_i or negedge rst_ni) + begin + if (!rst_ni) begin + wait_q <= 1'b0; + gnt_q <= '0; + end else begin + wait_q <= ~ready_i & (wait_q | (|req_i)); + if (!ready_i && !wait_q && (|req_i)) begin + gnt_q <= gnt; + end + end + end + // }}} + + // Assertions + // {{{ + // pragma translate_off + gnt_at_most_one_requester: assert property (@(posedge clk_i) + $onehot0(gnt_o)) else $error("arbiter: granting more than one requester"); + // pragma translate_on + // }}} + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_mux.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_mux.sv new file mode 100644 index 00000000000..d78e1ebf313 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_mux.sv @@ -0,0 +1,79 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Author(s) : Cesar Fuguet + * Creation Date : April, 2021 + * Description : Simple multiplexor + * History : + */ +module hpdcache_mux + // Parameters + // {{{ +#( + // Number of inputs + parameter int unsigned NINPUT = 0, + + // Width in bits of each input + parameter int unsigned DATA_WIDTH = 0, + + // Selector signal is one-hot encoded + parameter bit ONE_HOT_SEL = 0, + + // Compute the width of the selection signal + localparam int unsigned NINPUT_LOG2 = $clog2(NINPUT), + localparam int unsigned SEL_WIDTH = ONE_HOT_SEL ? NINPUT : NINPUT_LOG2, + + localparam type data_t = logic [DATA_WIDTH-1:0], + localparam type sel_t = logic [SEL_WIDTH-1:0] +) + // }}} + + // Ports + // {{{ +( + input data_t [NINPUT-1:0] data_i, + input sel_t sel_i, + output data_t data_o +); + // }}} + + generate + // Selector is one-hot encoded + if (ONE_HOT_SEL == 1) begin + always_comb + begin : data_out_mux_comb + data_o = '0; + for (int unsigned i = 0; i < NINPUT; i++) begin + data_o |= sel_i[i] ? data_i[i] : '0; + end + end + + // Selector is binary encoded + end else begin + always_comb + begin : data_out_mux_comb + data_o = '0; + for (int unsigned i = 0; i < NINPUT; i++) begin + data_o |= (i == int'(sel_i)) ? data_i[i] : '0; + end + end + end + endgenerate +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_prio_1hot_encoder.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_prio_1hot_encoder.sv new file mode 100644 index 00000000000..36fe5bcf737 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_prio_1hot_encoder.sv @@ -0,0 +1,43 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : Priority One-hot Encoder + * History : + */ +module hpdcache_prio_1hot_encoder + // Parameters +#( + parameter int unsigned N = 0 +) + // Ports +( + input logic [N-1:0] val_i, + output logic [N-1:0] val_o +); + + generate + assign val_o[0] = val_i[0]; + for (genvar i = 1; i < int'(N); i++) begin : prio_gen + assign val_o[i] = val_i[i] & ~(|val_i[i-1:0]); + end + endgenerate +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_regbank_wbyteenable_1rw.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_regbank_wbyteenable_1rw.sv new file mode 100644 index 00000000000..184e6fbf40d --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_regbank_wbyteenable_1rw.sv @@ -0,0 +1,63 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : March, 2020 + * Description : 1RW register bank with write byte enable + * History : + */ +module hpdcache_regbank_wbyteenable_1rw +#( + parameter int unsigned ADDR_SIZE = 0, + parameter int unsigned DATA_SIZE = 0, + parameter int unsigned DEPTH = 2**ADDR_SIZE +) +( + input logic clk, + input logic rst_n, + input logic cs, + input logic we, + input logic [ADDR_SIZE-1:0] addr, + input logic [DATA_SIZE-1:0] wdata, + input logic [DATA_SIZE/8-1:0] wbyteenable, + output logic [DATA_SIZE-1:0] rdata +); + + /* + * Internal memory array declaration + */ + typedef logic [DATA_SIZE-1:0] mem_t [DEPTH]; + mem_t mem; + + /* + * Process to update or read the memory array + */ + always_ff @(posedge clk) + begin : mem_update_ff + if (cs == 1'b1) begin + if (we == 1'b1) begin + for (int i = 0; i < DATA_SIZE/8; i++) begin + if (wbyteenable[i]) mem[addr][i*8 +: 8] <= wdata[i*8 +: 8]; + end + end + rdata <= mem[addr]; + end + end : mem_update_ff +endmodule : hpdcache_regbank_wbyteenable_1rw diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_regbank_wmask_1rw.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_regbank_wmask_1rw.sv new file mode 100644 index 00000000000..e185bc40494 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_regbank_wmask_1rw.sv @@ -0,0 +1,61 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : March, 2020 + * Description : 1RW register bank with write bit mask + * History : + */ +module hpdcache_regbank_wmask_1rw +#( + parameter int unsigned ADDR_SIZE = 0, + parameter int unsigned DATA_SIZE = 0, + parameter int unsigned DEPTH = 2**ADDR_SIZE +) +( + input logic clk, + input logic rst_n, + input logic cs, + input logic we, + input logic [ADDR_SIZE-1:0] addr, + input logic [DATA_SIZE-1:0] wdata, + input logic [DATA_SIZE-1:0] wmask, + output logic [DATA_SIZE-1:0] rdata +); + + /* + * Internal memory array declaration + */ + typedef logic [DATA_SIZE-1:0] mem_t [DEPTH]; + mem_t mem; + + /* + * Process to update or read the memory array + */ + always_ff @(posedge clk) + begin : mem_update_ff + if (cs == 1'b1) begin + if (we == 1'b1) begin + mem[addr] <= (mem[addr] & ~wmask) | (wdata & wmask); + end + rdata <= mem[addr]; + end + end : mem_update_ff +endmodule : hpdcache_regbank_wmask_1rw diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_rrarb.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_rrarb.sv new file mode 100644 index 00000000000..d609cb3ade0 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_rrarb.sv @@ -0,0 +1,121 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/** + * Author(s) : Cesar Fuguet + * Creation Date : April, 2021 + * Description : Round-Robin Arbiter + * Based on design from + * http://www.rtlery.com/articles/how-design-round-robin-arbiter + * History : + */ +module hpdcache_rrarb + // Parameters + // {{{ +#( + // Number of requesters + parameter int unsigned N = 0 +) + // }}} + // Ports + // {{{ +( + input logic clk_i, + input logic rst_ni, + input logic [N-1:0] req_i, + output logic [N-1:0] gnt_o, + input logic ready_i +); + // }}} + + // Declaration of internal wires and registers + // {{{ + logic [N-1:0] gnt_q, gnt; + logic [N-1:0] nxt; + logic wait_q; + logic [N-1:0] mask, gnt_msk, gnt_nomsk; + logic pending; + genvar gen_i; + // }}} + + // Elaboration-time assertions + // {{{ + // pragma translate_off + generate + if (N == 0) $error("N must be greater than 0"); + endgenerate + // pragma translate_on + // }}} + + // Compute the thermometer mask vector + // {{{ + generate + if (N > 1) begin : gen_nxt_gt_1 + assign nxt = {gnt_q[N-2:0], gnt_q[N-1]}; + end else begin : gen_nxt_1 + assign nxt = gnt_q[0]; + end + + for (gen_i = 0; gen_i < int'(N); gen_i++) begin : gen_mask + assign mask[gen_i] = |nxt[gen_i:0]; + end + endgenerate + // }}} + + // Compute the grant vector + // {{{ + hpdcache_prio_1hot_encoder #(.N(N)) prio_msk_i (.val_i(req_i & mask), .val_o(gnt_msk)); + hpdcache_prio_1hot_encoder #(.N(N)) prio_nomsk_i (.val_i(req_i) , .val_o(gnt_nomsk)); + assign gnt = |gnt_msk ? gnt_msk : gnt_nomsk; + // }}} + + // Compute the output grant vector + // {{{ + assign gnt_o = wait_q ? gnt_q : gnt; + // }}} + + // Setting of internal state + // {{{ + assign pending = |req_i; + + always_ff @(posedge clk_i or negedge rst_ni) + begin + if (!rst_ni) begin + wait_q <= 1'b0; + gnt_q <= {1'b1, {N-1{1'b0}}}; + end else begin + wait_q <= ~ready_i & (wait_q | pending); + if (!wait_q && pending) begin + gnt_q <= gnt; + end + end + end + // }}} + + // Assertions + // {{{ + // pragma translate_off + gnt_at_most_one_requester: assert property (@(posedge clk_i) + $onehot0(gnt)) else $error("arbiter: granting more than one requester"); + gnt_q_exactly_one_requester: assert property (@(posedge clk_i) + $onehot(gnt_q)) else $error("arbiter: grant state is not one-hot"); + // pragma translate_on + // }}} + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_sram.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_sram.sv new file mode 100644 index 00000000000..d4cab7de79d --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_sram.sv @@ -0,0 +1,56 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : March, 2020 + * Description : Wrapper for Behavioral SRAM macros + * History : + */ +module hpdcache_sram +#( + parameter int unsigned ADDR_SIZE = 0, + parameter int unsigned DATA_SIZE = 0, + parameter int unsigned DEPTH = 2**ADDR_SIZE +) +( + input logic clk, + input logic rst_n, + input logic cs, + input logic we, + input logic [ADDR_SIZE-1:0] addr, + input logic [DATA_SIZE-1:0] wdata, + output logic [DATA_SIZE-1:0] rdata +); + + hpdcache_sram_1rw #( + .ADDR_SIZE(ADDR_SIZE), + .DATA_SIZE(DATA_SIZE), + .DEPTH(DEPTH) + ) ram_i ( + .clk, + .rst_n, + .cs, + .we, + .addr, + .wdata, + .rdata + ); + +endmodule : hpdcache_sram diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_sram_wbyteenable.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_sram_wbyteenable.sv new file mode 100644 index 00000000000..43bdb4506f6 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_sram_wbyteenable.sv @@ -0,0 +1,58 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : March, 2020 + * Description : Wrapper for 1RW SRAM macros implementing a write byte enable + * History : + */ +module hpdcache_sram_wbyteenable +#( + parameter int unsigned ADDR_SIZE = 0, + parameter int unsigned DATA_SIZE = 0, + parameter int unsigned DEPTH = 2**ADDR_SIZE +) +( + input logic clk, + input logic rst_n, + input logic cs, + input logic we, + input logic [ADDR_SIZE-1:0] addr, + input logic [DATA_SIZE-1:0] wdata, + input logic [DATA_SIZE/8-1:0] wbyteenable, + output logic [DATA_SIZE-1:0] rdata +); + + hpdcache_sram_wbyteenable_1rw #( + .ADDR_SIZE(ADDR_SIZE), + .DATA_SIZE(DATA_SIZE), + .DEPTH(DEPTH) + ) ram_i ( + .clk, + .rst_n, + .cs, + .we, + .addr, + .wdata, + .wbyteenable, + .rdata + ); + +endmodule : hpdcache_sram_wbyteenable diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_sram_wmask.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_sram_wmask.sv new file mode 100644 index 00000000000..a4771e3bd55 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/hpdcache_sram_wmask.sv @@ -0,0 +1,58 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : March, 2020 + * Description : Wrapper for 1RW SRAM macros implementing write bit mask + * History : + */ +module hpdcache_sram_wmask +#( + parameter int unsigned ADDR_SIZE = 0, + parameter int unsigned DATA_SIZE = 0, + parameter int unsigned DEPTH = 2**ADDR_SIZE +) +( + input logic clk, + input logic rst_n, + input logic cs, + input logic we, + input logic [ADDR_SIZE-1:0] addr, + input logic [DATA_SIZE-1:0] wdata, + input logic [DATA_SIZE-1:0] wmask, + output logic [DATA_SIZE-1:0] rdata +); + + hpdcache_sram_wmask_1rw #( + .ADDR_SIZE(ADDR_SIZE), + .DATA_SIZE(DATA_SIZE), + .DEPTH(DEPTH) + ) ram_i ( + .clk, + .rst_n, + .cs, + .we, + .addr, + .wdata, + .wmask, + .rdata + ); + +endmodule : hpdcache_sram_wmask diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/macros/behav/hpdcache_sram_1rw.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/macros/behav/hpdcache_sram_1rw.sv new file mode 100644 index 00000000000..7288c731fdc --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/macros/behav/hpdcache_sram_1rw.sv @@ -0,0 +1,60 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : March, 2020 + * Description : SRAM behavioral model + * History : + */ +module hpdcache_sram_1rw +#( + parameter int unsigned ADDR_SIZE = 0, + parameter int unsigned DATA_SIZE = 0, + parameter int unsigned DEPTH = 2**ADDR_SIZE +) +( + input logic clk, + input logic rst_n, + input logic cs, + input logic we, + input logic [ADDR_SIZE-1:0] addr, + input logic [DATA_SIZE-1:0] wdata, + output logic [DATA_SIZE-1:0] rdata +); + + /* + * Internal memory array declaration + */ + typedef logic [DATA_SIZE-1:0] mem_t [DEPTH]; + mem_t mem; + + /* + * Process to update or read the memory array + */ + always_ff @(posedge clk) + begin : mem_update_ff + if (cs == 1'b1) begin + if (we == 1'b1) begin + mem[addr] <= wdata; + end + rdata <= mem[addr]; + end + end : mem_update_ff +endmodule : hpdcache_sram_1rw diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/macros/behav/hpdcache_sram_wbyteenable_1rw.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/macros/behav/hpdcache_sram_wbyteenable_1rw.sv new file mode 100644 index 00000000000..0e5e2256ccf --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/macros/behav/hpdcache_sram_wbyteenable_1rw.sv @@ -0,0 +1,63 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : March, 2020 + * Description : Behavioral model of a 1RW SRAM with write byte enable + * History : + */ +module hpdcache_sram_wbyteenable_1rw +#( + parameter int unsigned ADDR_SIZE = 0, + parameter int unsigned DATA_SIZE = 0, + parameter int unsigned DEPTH = 2**ADDR_SIZE +) +( + input logic clk, + input logic rst_n, + input logic cs, + input logic we, + input logic [ADDR_SIZE-1:0] addr, + input logic [DATA_SIZE-1:0] wdata, + input logic [DATA_SIZE/8-1:0] wbyteenable, + output logic [DATA_SIZE-1:0] rdata +); + + /* + * Internal memory array declaration + */ + typedef logic [DATA_SIZE-1:0] mem_t [DEPTH]; + mem_t mem; + + /* + * Process to update or read the memory array + */ + always_ff @(posedge clk) + begin : mem_update_ff + if (cs == 1'b1) begin + if (we == 1'b1) begin + for (int i = 0; i < DATA_SIZE/8; i++) begin + if (wbyteenable[i]) mem[addr][i*8 +: 8] <= wdata[i*8 +: 8]; + end + end + rdata <= mem[addr]; + end + end : mem_update_ff +endmodule : hpdcache_sram_wbyteenable_1rw diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/common/macros/behav/hpdcache_sram_wmask_1rw.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/common/macros/behav/hpdcache_sram_wmask_1rw.sv new file mode 100644 index 00000000000..5058ba28ba7 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/common/macros/behav/hpdcache_sram_wmask_1rw.sv @@ -0,0 +1,61 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : March, 2020 + * Description : Behavioral model of a 1RW SRAM with write bit mask + * History : + */ +module hpdcache_sram_wmask_1rw +#( + parameter int unsigned ADDR_SIZE = 0, + parameter int unsigned DATA_SIZE = 0, + parameter int unsigned DEPTH = 2**ADDR_SIZE +) +( + input logic clk, + input logic rst_n, + input logic cs, + input logic we, + input logic [ADDR_SIZE-1:0] addr, + input logic [DATA_SIZE-1:0] wdata, + input logic [DATA_SIZE-1:0] wmask, + output logic [DATA_SIZE-1:0] rdata +); + + /* + * Internal memory array declaration + */ + typedef logic [DATA_SIZE-1:0] mem_t [DEPTH]; + mem_t mem; + + /* + * Process to update or read the memory array + */ + always_ff @(posedge clk) + begin : mem_update_ff + if (cs == 1'b1) begin + if (we == 1'b1) begin + mem[addr] <= (mem[addr] & ~wmask) | (wdata & wmask); + end + rdata <= mem[addr]; + end + end : mem_update_ff +endmodule : hpdcache_sram_wmask_1rw diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache.sv new file mode 100644 index 00000000000..861e60c2c26 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache.sv @@ -0,0 +1,658 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : HPDcache top + * History : + */ +module hpdcache +import hpdcache_pkg::*; + // Parameters + // {{{ +#( + parameter int NREQUESTERS = 1, + parameter int HPDcacheMemIdWidth = 8, + parameter int HPDcacheMemDataWidth = 512, + parameter type hpdcache_mem_req_t = logic, + parameter type hpdcache_mem_req_w_t = logic, + parameter type hpdcache_mem_resp_r_t = logic, + parameter type hpdcache_mem_resp_w_t = logic +) + // }}} + + // Ports + // {{{ +( + // Clock and reset signals + input logic clk_i, + input logic rst_ni, + + // Force the write buffer to send all pending writes + input logic wbuf_flush_i, + + // Core request interface + // 1st cycle + input logic core_req_valid_i [NREQUESTERS-1:0], + output logic core_req_ready_o [NREQUESTERS-1:0], + input hpdcache_req_t core_req_i [NREQUESTERS-1:0], + // 2nd cycle + input logic core_req_abort_i [NREQUESTERS-1:0], + input hpdcache_tag_t core_req_tag_i [NREQUESTERS-1:0], + input hpdcache_pma_t core_req_pma_i [NREQUESTERS-1:0], + + // Core response interface + output logic core_rsp_valid_o [NREQUESTERS-1:0], + output hpdcache_rsp_t core_rsp_o [NREQUESTERS-1:0], + + // Miss read interface + input logic mem_req_miss_read_ready_i, + output logic mem_req_miss_read_valid_o, + output hpdcache_mem_req_t mem_req_miss_read_o, + + output logic mem_resp_miss_read_ready_o, + input logic mem_resp_miss_read_valid_i, + input hpdcache_mem_resp_r_t mem_resp_miss_read_i, + + // Write-buffer write interface + input logic mem_req_wbuf_write_ready_i, + output logic mem_req_wbuf_write_valid_o, + output hpdcache_mem_req_t mem_req_wbuf_write_o, + + input logic mem_req_wbuf_write_data_ready_i, + output logic mem_req_wbuf_write_data_valid_o, + output hpdcache_mem_req_w_t mem_req_wbuf_write_data_o, + + output logic mem_resp_wbuf_write_ready_o, + input logic mem_resp_wbuf_write_valid_i, + input hpdcache_mem_resp_w_t mem_resp_wbuf_write_i, + + // Uncached read interface + input logic mem_req_uc_read_ready_i, + output logic mem_req_uc_read_valid_o, + output hpdcache_mem_req_t mem_req_uc_read_o, + + output logic mem_resp_uc_read_ready_o, + input logic mem_resp_uc_read_valid_i, + input hpdcache_mem_resp_r_t mem_resp_uc_read_i, + + // Uncached write interface + input logic mem_req_uc_write_ready_i, + output logic mem_req_uc_write_valid_o, + output hpdcache_mem_req_t mem_req_uc_write_o, + + input logic mem_req_uc_write_data_ready_i, + output logic mem_req_uc_write_data_valid_o, + output hpdcache_mem_req_w_t mem_req_uc_write_data_o, + + output logic mem_resp_uc_write_ready_o, + input logic mem_resp_uc_write_valid_i, + input hpdcache_mem_resp_w_t mem_resp_uc_write_i, + + // Performance events + output logic evt_cache_write_miss_o, + output logic evt_cache_read_miss_o, + output logic evt_uncached_req_o, + output logic evt_cmo_req_o, + output logic evt_write_req_o, + output logic evt_read_req_o, + output logic evt_prefetch_req_o, + output logic evt_req_on_hold_o, + output logic evt_rtab_rollback_o, + output logic evt_stall_refill_o, + output logic evt_stall_o, + + // Status interface + output logic wbuf_empty_o, + + // Configuration interface + input logic cfg_enable_i, + input wbuf_timecnt_t cfg_wbuf_threshold_i, + input logic cfg_wbuf_reset_timecnt_on_write_i, + input logic cfg_wbuf_sequential_waw_i, + input logic cfg_wbuf_inhibit_write_coalescing_i, + input logic cfg_prefetch_updt_plru_i, + input logic cfg_error_on_cacheable_amo_i, + input logic cfg_rtab_single_entry_i +); + + // }}} + + // Declaration of internal signals + // {{{ + logic refill_req_valid; + logic refill_req_ready; + logic refill_busy; + logic refill_updt_plru; + hpdcache_set_t refill_set; + hpdcache_dir_entry_t refill_dir_entry; + hpdcache_way_vector_t refill_read_victim_way; + hpdcache_way_vector_t refill_write_victim_way; + logic refill_write_dir; + logic refill_write_data; + hpdcache_word_t refill_word; + hpdcache_refill_data_t refill_data; + logic refill_core_rsp_valid; + hpdcache_rsp_t refill_core_rsp; + hpdcache_nline_t refill_nline; + logic refill_updt_rtab; + + logic miss_mshr_empty; + logic miss_mshr_check; + mshr_set_t miss_mshr_check_set; + mshr_tag_t miss_mshr_check_tag; + logic miss_mshr_hit; + logic miss_mshr_alloc_cs; + logic miss_mshr_alloc; + logic miss_mshr_alloc_ready; + logic miss_mshr_alloc_full; + hpdcache_nline_t miss_mshr_alloc_nline; + hpdcache_req_tid_t miss_mshr_alloc_tid; + hpdcache_req_sid_t miss_mshr_alloc_sid; + hpdcache_word_t miss_mshr_alloc_word; + logic miss_mshr_alloc_need_rsp; + logic miss_mshr_alloc_is_prefetch; + + logic wbuf_flush_all; + logic wbuf_write; + logic wbuf_write_ready; + wbuf_addr_t wbuf_write_addr; + wbuf_data_t wbuf_write_data; + wbuf_be_t wbuf_write_be; + logic wbuf_write_uncacheable; + logic wbuf_read_hit; + logic wbuf_read_flush_hit; + hpdcache_req_addr_t wbuf_rtab_addr; + logic wbuf_rtab_is_read; + logic wbuf_rtab_hit_open; + logic wbuf_rtab_hit_pend; + logic wbuf_rtab_hit_sent; + logic wbuf_rtab_not_ready; + + logic uc_ready; + logic uc_req_valid; + hpdcache_uc_op_t uc_req_op; + hpdcache_req_addr_t uc_req_addr; + hpdcache_req_size_t uc_req_size; + hpdcache_req_data_t uc_req_data; + hpdcache_req_be_t uc_req_be; + logic uc_req_uncacheable; + hpdcache_req_sid_t uc_req_sid; + hpdcache_req_tid_t uc_req_tid; + logic uc_req_need_rsp; + logic uc_wbuf_flush_all; + logic uc_dir_amo_match; + hpdcache_set_t uc_dir_amo_match_set; + hpdcache_tag_t uc_dir_amo_match_tag; + logic uc_dir_amo_update_plru; + hpdcache_way_vector_t uc_dir_amo_hit_way; + logic uc_data_amo_write; + logic uc_data_amo_write_enable; + hpdcache_set_t uc_data_amo_write_set; + hpdcache_req_size_t uc_data_amo_write_size; + hpdcache_word_t uc_data_amo_write_word; + logic [63:0] uc_data_amo_write_data; + logic [7:0] uc_data_amo_write_be; + logic uc_lrsc_snoop; + hpdcache_req_addr_t uc_lrsc_snoop_addr; + hpdcache_req_size_t uc_lrsc_snoop_size; + logic uc_core_rsp_ready; + logic uc_core_rsp_valid; + hpdcache_rsp_t uc_core_rsp; + + logic cmo_req_valid; + logic cmo_ready; + hpdcache_cmoh_op_t cmo_req_op; + hpdcache_req_addr_t cmo_req_addr; + hpdcache_req_data_t cmo_req_wdata; + logic cmo_wbuf_flush_all; + logic cmo_dir_check; + hpdcache_set_t cmo_dir_check_set; + hpdcache_tag_t cmo_dir_check_tag; + hpdcache_way_vector_t cmo_dir_check_hit_way; + logic cmo_dir_inval; + hpdcache_set_t cmo_dir_inval_set; + hpdcache_way_vector_t cmo_dir_inval_way; + + logic rtab_empty; + logic ctrl_empty; + + logic core_rsp_valid; + hpdcache_rsp_t core_rsp; + + logic arb_req_valid; + logic arb_req_ready; + hpdcache_req_t arb_req; + logic arb_abort; + hpdcache_tag_t arb_tag; + hpdcache_pma_t arb_pma; + + localparam logic [HPDcacheMemIdWidth-1:0] HPDCACHE_UC_READ_ID = {HPDcacheMemIdWidth{1'b1}}; + localparam logic [HPDcacheMemIdWidth-1:0] HPDCACHE_UC_WRITE_ID = {HPDcacheMemIdWidth{1'b1}}; + // }}} + + // Requesters arbiter + // {{{ + hpdcache_core_arbiter #( + .NREQUESTERS (NREQUESTERS) + ) core_req_arbiter_i ( + .clk_i, + .rst_ni, + + .core_req_valid_i, + .core_req_ready_o, + .core_req_i, + .core_req_abort_i, + .core_req_tag_i, + .core_req_pma_i, + + .core_rsp_valid_i (core_rsp_valid), + .core_rsp_i (core_rsp), + .core_rsp_valid_o, + .core_rsp_o, + + .arb_req_valid_o (arb_req_valid), + .arb_req_ready_i (arb_req_ready), + .arb_req_o (arb_req), + .arb_abort_o (arb_abort), + .arb_tag_o (arb_tag), + .arb_pma_o (arb_pma) + ); + // }}} + + // HPDcache controller + // {{{ + hpdcache_ctrl hpdcache_ctrl_i( + .clk_i, + .rst_ni, + + .core_req_valid_i (arb_req_valid), + .core_req_ready_o (arb_req_ready), + .core_req_i (arb_req), + .core_req_abort_i (arb_abort), + .core_req_tag_i (arb_tag), + .core_req_pma_i (arb_pma), + + .core_rsp_valid_o (core_rsp_valid), + .core_rsp_o (core_rsp), + + .wbuf_flush_i, + + .cachedir_hit_o (/* unused */), + + .miss_mshr_check_o (miss_mshr_check), + .miss_mshr_check_set_o (miss_mshr_check_set), + .miss_mshr_check_tag_o (miss_mshr_check_tag), + .miss_mshr_alloc_o (miss_mshr_alloc), + .miss_mshr_alloc_cs_o (miss_mshr_alloc_cs), + .miss_mshr_alloc_ready_i (miss_mshr_alloc_ready), + .miss_mshr_alloc_full_i (miss_mshr_alloc_full), + .miss_mshr_alloc_nline_o (miss_mshr_alloc_nline), + .miss_mshr_alloc_tid_o (miss_mshr_alloc_tid), + .miss_mshr_alloc_sid_o (miss_mshr_alloc_sid), + .miss_mshr_alloc_word_o (miss_mshr_alloc_word), + .miss_mshr_alloc_need_rsp_o (miss_mshr_alloc_need_rsp), + .miss_mshr_alloc_is_prefetch_o (miss_mshr_alloc_is_prefetch), + .miss_mshr_hit_i (miss_mshr_hit), + + .refill_req_valid_i (refill_req_valid), + .refill_req_ready_o (refill_req_ready), + .refill_busy_i (refill_busy), + .refill_updt_plru_i (refill_updt_plru), + .refill_set_i (refill_set), + .refill_dir_entry_i (refill_dir_entry), + .refill_victim_way_o (refill_read_victim_way), + .refill_victim_way_i (refill_write_victim_way), + .refill_write_dir_i (refill_write_dir), + .refill_write_data_i (refill_write_data), + .refill_word_i (refill_word), + .refill_data_i (refill_data), + .refill_core_rsp_valid_i (refill_core_rsp_valid), + .refill_core_rsp_i (refill_core_rsp), + .refill_nline_i (refill_nline), + .refill_updt_rtab_i (refill_updt_rtab), + + .wbuf_empty_i (wbuf_empty_o), + .wbuf_flush_all_o (wbuf_flush_all), + .wbuf_write_o (wbuf_write), + .wbuf_write_ready_i (wbuf_write_ready), + .wbuf_write_addr_o (wbuf_write_addr), + .wbuf_write_data_o (wbuf_write_data), + .wbuf_write_be_o (wbuf_write_be), + .wbuf_write_uncacheable_o (wbuf_write_uncacheable), + .wbuf_read_hit_i (wbuf_read_hit), + .wbuf_read_flush_hit_o (wbuf_read_flush_hit), + .wbuf_rtab_addr_o (wbuf_rtab_addr), + .wbuf_rtab_is_read_o (wbuf_rtab_is_read), + .wbuf_rtab_hit_open_i (wbuf_rtab_hit_open), + .wbuf_rtab_hit_pend_i (wbuf_rtab_hit_pend), + .wbuf_rtab_hit_sent_i (wbuf_rtab_hit_sent), + .wbuf_rtab_not_ready_i (wbuf_rtab_not_ready), + + .uc_busy_i (~uc_ready), + .uc_lrsc_snoop_o (uc_lrsc_snoop), + .uc_lrsc_snoop_addr_o (uc_lrsc_snoop_addr), + .uc_lrsc_snoop_size_o (uc_lrsc_snoop_size), + .uc_req_valid_o (uc_req_valid), + .uc_req_op_o (uc_req_op), + .uc_req_addr_o (uc_req_addr), + .uc_req_size_o (uc_req_size), + .uc_req_data_o (uc_req_data), + .uc_req_be_o (uc_req_be), + .uc_req_uc_o (uc_req_uncacheable), + .uc_req_sid_o (uc_req_sid), + .uc_req_tid_o (uc_req_tid), + .uc_req_need_rsp_o (uc_req_need_rsp), + .uc_wbuf_flush_all_i (uc_wbuf_flush_all), + .uc_dir_amo_match_i (uc_dir_amo_match), + .uc_dir_amo_match_set_i (uc_dir_amo_match_set), + .uc_dir_amo_match_tag_i (uc_dir_amo_match_tag), + .uc_dir_amo_update_plru_i (uc_dir_amo_update_plru), + .uc_dir_amo_hit_way_o (uc_dir_amo_hit_way), + .uc_data_amo_write_i (uc_data_amo_write), + .uc_data_amo_write_enable_i (uc_data_amo_write_enable), + .uc_data_amo_write_set_i (uc_data_amo_write_set), + .uc_data_amo_write_size_i (uc_data_amo_write_size), + .uc_data_amo_write_word_i (uc_data_amo_write_word), + .uc_data_amo_write_data_i (uc_data_amo_write_data), + .uc_data_amo_write_be_i (uc_data_amo_write_be), + .uc_core_rsp_ready_o (uc_core_rsp_ready), + .uc_core_rsp_valid_i (uc_core_rsp_valid), + .uc_core_rsp_i (uc_core_rsp), + + .cmo_busy_i (~cmo_ready), + .cmo_req_valid_o (cmo_req_valid), + .cmo_req_op_o (cmo_req_op), + .cmo_req_addr_o (cmo_req_addr), + .cmo_req_wdata_o (cmo_req_wdata), + .cmo_wbuf_flush_all_i (cmo_wbuf_flush_all), + .cmo_dir_check_i (cmo_dir_check), + .cmo_dir_check_set_i (cmo_dir_check_set), + .cmo_dir_check_tag_i (cmo_dir_check_tag), + .cmo_dir_check_hit_way_o (cmo_dir_check_hit_way), + .cmo_dir_inval_i (cmo_dir_inval), + .cmo_dir_inval_set_i (cmo_dir_inval_set), + .cmo_dir_inval_way_i (cmo_dir_inval_way), + + .rtab_empty_o (rtab_empty), + .ctrl_empty_o (ctrl_empty), + + .cfg_enable_i, + .cfg_rtab_single_entry_i, + + .evt_cache_write_miss_o, + .evt_cache_read_miss_o, + .evt_uncached_req_o, + .evt_cmo_req_o, + .evt_write_req_o, + .evt_read_req_o, + .evt_prefetch_req_o, + .evt_req_on_hold_o, + .evt_rtab_rollback_o, + .evt_stall_refill_o, + .evt_stall_o + ); + // }}} + + // HPDcache write-buffer + // {{{ + hpdcache_wbuf_wrapper #( + .HPDcacheMemIdWidth (HPDcacheMemIdWidth), + .HPDcacheMemDataWidth (HPDcacheMemDataWidth), + .hpdcache_mem_req_t (hpdcache_mem_req_t), + .hpdcache_mem_req_w_t (hpdcache_mem_req_w_t), + .hpdcache_mem_resp_w_t (hpdcache_mem_resp_w_t) + ) hpdcache_wbuf_i( + .clk_i, + .rst_ni, + + .empty_o (wbuf_empty_o), + .full_o (/* unused */), + .flush_all_i (wbuf_flush_all), + + .cfg_threshold_i (cfg_wbuf_threshold_i), + .cfg_reset_timecnt_on_write_i (cfg_wbuf_reset_timecnt_on_write_i), + .cfg_sequential_waw_i (cfg_wbuf_sequential_waw_i), + .cfg_inhibit_write_coalescing_i (cfg_wbuf_inhibit_write_coalescing_i), + + .write_i (wbuf_write), + .write_ready_o (wbuf_write_ready), + .write_addr_i (wbuf_write_addr), + .write_data_i (wbuf_write_data), + .write_be_i (wbuf_write_be), + .write_uc_i (wbuf_write_uncacheable), + + .read_addr_i (wbuf_write_addr), + .read_hit_o (wbuf_read_hit), + .read_flush_hit_i (wbuf_read_flush_hit), + + .replay_addr_i (wbuf_rtab_addr), + .replay_is_read_i (wbuf_rtab_is_read), + .replay_open_hit_o (wbuf_rtab_hit_open), + .replay_pend_hit_o (wbuf_rtab_hit_pend), + .replay_sent_hit_o (wbuf_rtab_hit_sent), + .replay_not_ready_o (wbuf_rtab_not_ready), + + .mem_req_write_ready_i (mem_req_wbuf_write_ready_i), + .mem_req_write_valid_o (mem_req_wbuf_write_valid_o), + .mem_req_write_o (mem_req_wbuf_write_o), + + .mem_req_write_data_ready_i (mem_req_wbuf_write_data_ready_i), + .mem_req_write_data_valid_o (mem_req_wbuf_write_data_valid_o), + .mem_req_write_data_o (mem_req_wbuf_write_data_o), + + .mem_resp_write_ready_o (mem_resp_wbuf_write_ready_o), + .mem_resp_write_valid_i (mem_resp_wbuf_write_valid_i), + .mem_resp_write_i (mem_resp_wbuf_write_i) + ); + // }}} + + // Miss handler + // {{{ + hpdcache_miss_handler #( + .HPDcacheMemIdWidth (HPDcacheMemIdWidth), + .HPDcacheMemDataWidth (HPDcacheMemDataWidth), + .hpdcache_mem_req_t (hpdcache_mem_req_t), + .hpdcache_mem_resp_r_t (hpdcache_mem_resp_r_t) + ) hpdcache_miss_handler_i( + .clk_i, + .rst_ni, + + .mshr_empty_o (miss_mshr_empty), + .mshr_full_o (/* unused */), + + .cfg_prefetch_updt_plru_i, + + .mshr_check_i (miss_mshr_check), + .mshr_check_set_i (miss_mshr_check_set), + .mshr_check_tag_i (miss_mshr_check_tag), + .mshr_check_hit_o (miss_mshr_hit), + + .mshr_alloc_ready_o (miss_mshr_alloc_ready), + .mshr_alloc_i (miss_mshr_alloc), + .mshr_alloc_cs_i (miss_mshr_alloc_cs), + .mshr_alloc_full_o (miss_mshr_alloc_full), + .mshr_alloc_nline_i (miss_mshr_alloc_nline), + .mshr_alloc_tid_i (miss_mshr_alloc_tid), + .mshr_alloc_sid_i (miss_mshr_alloc_sid), + .mshr_alloc_word_i (miss_mshr_alloc_word), + .mshr_alloc_need_rsp_i (miss_mshr_alloc_need_rsp), + .mshr_alloc_is_prefetch_i (miss_mshr_alloc_is_prefetch), + + .refill_req_ready_i (refill_req_ready), + .refill_req_valid_o (refill_req_valid), + .refill_busy_o (refill_busy), + .refill_updt_plru_o (refill_updt_plru), + .refill_set_o (refill_set), + .refill_dir_entry_o (refill_dir_entry), + .refill_victim_way_i (refill_read_victim_way), + .refill_write_dir_o (refill_write_dir), + .refill_write_data_o (refill_write_data), + .refill_victim_way_o (refill_write_victim_way), + .refill_data_o (refill_data), + .refill_word_o (refill_word), + .refill_nline_o (refill_nline), + .refill_updt_rtab_o (refill_updt_rtab), + + .refill_core_rsp_valid_o (refill_core_rsp_valid), + .refill_core_rsp_o (refill_core_rsp), + + .mem_req_ready_i (mem_req_miss_read_ready_i), + .mem_req_valid_o (mem_req_miss_read_valid_o), + .mem_req_o (mem_req_miss_read_o), + + .mem_resp_ready_o (mem_resp_miss_read_ready_o), + .mem_resp_valid_i (mem_resp_miss_read_valid_i), + .mem_resp_i (mem_resp_miss_read_i) + ); + // }}} + + // Uncacheable request handler + // {{{ + hpdcache_uncached #( + .HPDcacheMemIdWidth (HPDcacheMemIdWidth), + .HPDcacheMemDataWidth (HPDcacheMemDataWidth), + .hpdcache_mem_req_t (hpdcache_mem_req_t), + .hpdcache_mem_req_w_t (hpdcache_mem_req_w_t), + .hpdcache_mem_resp_r_t (hpdcache_mem_resp_r_t), + .hpdcache_mem_resp_w_t (hpdcache_mem_resp_w_t) + ) hpdcache_uc_i( + .clk_i, + .rst_ni, + + .wbuf_empty_i (wbuf_empty_o), + .mshr_empty_i (miss_mshr_empty), + .rtab_empty_i (rtab_empty), + .ctrl_empty_i (ctrl_empty), + + .req_valid_i (uc_req_valid), + .req_ready_o (uc_ready), + .req_op_i (uc_req_op), + .req_addr_i (uc_req_addr), + .req_size_i (uc_req_size), + .req_data_i (uc_req_data), + .req_be_i (uc_req_be), + .req_uc_i (uc_req_uncacheable), + .req_sid_i (uc_req_sid), + .req_tid_i (uc_req_tid), + .req_need_rsp_i (uc_req_need_rsp), + + .wbuf_flush_all_o (uc_wbuf_flush_all), + + .dir_amo_match_o (uc_dir_amo_match), + .dir_amo_match_set_o (uc_dir_amo_match_set), + .dir_amo_match_tag_o (uc_dir_amo_match_tag), + .dir_amo_update_plru_o (uc_dir_amo_update_plru), + .dir_amo_hit_way_i (uc_dir_amo_hit_way), + + .data_amo_write_o (uc_data_amo_write), + .data_amo_write_enable_o (uc_data_amo_write_enable), + .data_amo_write_set_o (uc_data_amo_write_set), + .data_amo_write_size_o (uc_data_amo_write_size), + .data_amo_write_word_o (uc_data_amo_write_word), + .data_amo_write_data_o (uc_data_amo_write_data), + .data_amo_write_be_o (uc_data_amo_write_be), + + .lrsc_snoop_i (uc_lrsc_snoop), + .lrsc_snoop_addr_i (uc_lrsc_snoop_addr), + .lrsc_snoop_size_i (uc_lrsc_snoop_size), + + .core_rsp_ready_i (uc_core_rsp_ready), + .core_rsp_valid_o (uc_core_rsp_valid), + .core_rsp_o (uc_core_rsp), + + .mem_read_id_i (HPDCACHE_UC_READ_ID), + .mem_write_id_i (HPDCACHE_UC_WRITE_ID), + + .mem_req_read_ready_i (mem_req_uc_read_ready_i), + .mem_req_read_valid_o (mem_req_uc_read_valid_o), + .mem_req_read_o (mem_req_uc_read_o), + + .mem_resp_read_ready_o (mem_resp_uc_read_ready_o), + .mem_resp_read_valid_i (mem_resp_uc_read_valid_i), + .mem_resp_read_i (mem_resp_uc_read_i), + + .mem_req_write_ready_i (mem_req_uc_write_ready_i), + .mem_req_write_valid_o (mem_req_uc_write_valid_o), + .mem_req_write_o (mem_req_uc_write_o), + + .mem_req_write_data_ready_i (mem_req_uc_write_data_ready_i), + .mem_req_write_data_valid_o (mem_req_uc_write_data_valid_o), + .mem_req_write_data_o (mem_req_uc_write_data_o), + + .mem_resp_write_ready_o (mem_resp_uc_write_ready_o), + .mem_resp_write_valid_i (mem_resp_uc_write_valid_i), + .mem_resp_write_i (mem_resp_uc_write_i), + + .cfg_error_on_cacheable_amo_i + ); + + // CMO Request Handler + // {{{ + hpdcache_cmo hpdcache_cmo_i( + .clk_i, + .rst_ni, + + .wbuf_empty_i (wbuf_empty_o), + .mshr_empty_i (miss_mshr_empty), + .rtab_empty_i (rtab_empty), + .ctrl_empty_i (ctrl_empty), + + .req_valid_i (cmo_req_valid), + .req_ready_o (cmo_ready), + .req_op_i (cmo_req_op), + .req_addr_i (cmo_req_addr), + .req_wdata_i (cmo_req_wdata), + + .wbuf_flush_all_o (cmo_wbuf_flush_all), + + .dir_check_o (cmo_dir_check), + .dir_check_set_o (cmo_dir_check_set), + .dir_check_tag_o (cmo_dir_check_tag), + .dir_check_hit_way_i (cmo_dir_check_hit_way), + + .dir_inval_o (cmo_dir_inval), + .dir_inval_set_o (cmo_dir_inval_set), + .dir_inval_way_o (cmo_dir_inval_way) + ); + // }}} + + // Assertions + // {{{ + // pragma translate_off + initial begin + req_access_width_assert: + assert (HPDCACHE_REQ_WORDS <= HPDCACHE_ACCESS_WORDS) else + $error("req data width shall be l.e. to cache access width"); + refill_access_width_assert: + assert (HPDCACHE_CL_WORDS >= HPDCACHE_ACCESS_WORDS) else + $error("cache access width shall be l.e. to cache-line width"); + miss_mem_id_width_assert: + assert (HPDcacheMemIdWidth >= (HPDCACHE_MSHR_WAY_WIDTH + HPDCACHE_MSHR_SET_WIDTH)) else + $error("insufficient ID bits on the mem interface to transport misses"); + wbuf_mem_id_width_assert: + assert (HPDcacheMemIdWidth >= HPDCACHE_WBUF_DIR_PTR_WIDTH) else + $error("insufficient ID bits on the mem interface to transport writes"); + + end + // pragma translate_on + // }}} + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache.vlt b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache.vlt new file mode 100644 index 00000000000..2a35859eecc --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache.vlt @@ -0,0 +1,29 @@ +`verilator_config +// +// Copyright 2023 CEA* +// *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) +// +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 +// +// Licensed under the Solderpad Hardware License v 2.1 (the “License”); you +// may not use this file except in compliance with the License, or, at your +// option, the Apache License version 2.0. You may obtain a copy of the +// License at +// +// https://solderpad.org/licenses/SHL-2.1/ +// +// Unless required by applicable law or agreed to in writing, any work +// distributed under the License is distributed on an “AS IS” BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. +// + +// +// Authors Cesar Fuguet +// Creation Date April, 2021 +// Description Verilator's configuration file +// History +// +lint_off -rule PINCONNECTEMPTY +lint_off -rule DECLFILENAME diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_amo.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_amo.sv new file mode 100644 index 00000000000..d233af1d83e --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_amo.sv @@ -0,0 +1,67 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : May, 2021 + * Description : HPDcache AMO computing unit + * History : + */ +module hpdcache_amo +import hpdcache_pkg::*; +// Ports +// {{{ +( + input logic [63:0] ld_data_i, + input logic [63:0] st_data_i, + input hpdcache_uc_op_t op_i, + output logic [63:0] result_o +); +// }}} + + logic signed [63:0] ld_data; + logic signed [63:0] st_data; + logic signed [63:0] sum; + logic ugt, sgt; + + assign ld_data = ld_data_i, + st_data = st_data_i; + + assign ugt = (ld_data_i > st_data_i), + sgt = (ld_data > st_data), + sum = ld_data + st_data; + + always_comb + begin : amo_compute_comb + unique case (1'b1) + op_i.is_amo_lr : result_o = ld_data_i; + op_i.is_amo_sc : result_o = st_data_i; + op_i.is_amo_swap : result_o = st_data_i; + op_i.is_amo_add : result_o = sum; + op_i.is_amo_and : result_o = ld_data_i & st_data_i; + op_i.is_amo_or : result_o = ld_data_i | st_data_i; + op_i.is_amo_xor : result_o = ld_data_i ^ st_data_i; + op_i.is_amo_max : result_o = sgt ? ld_data_i : st_data_i; + op_i.is_amo_maxu : result_o = ugt ? ld_data_i : st_data_i; + op_i.is_amo_min : result_o = sgt ? st_data_i : ld_data_i; + op_i.is_amo_minu : result_o = ugt ? st_data_i : ld_data_i; + default : result_o = '0; + endcase + end +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_cmo.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_cmo.sv new file mode 100644 index 00000000000..8302d0a9d7a --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_cmo.sv @@ -0,0 +1,250 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : July, 2021 + * Description : HPDcache Cache-Management-Operation Handler + * History : + */ +module hpdcache_cmo +import hpdcache_pkg::*; +// Ports +// {{{ +( + input logic clk_i, + input logic rst_ni, + + // Global control signals + // {{{ + input logic wbuf_empty_i, + input logic mshr_empty_i, + input logic rtab_empty_i, + input logic ctrl_empty_i, + // }}} + + // Request interface + // {{{ + input logic req_valid_i, + output logic req_ready_o, + input hpdcache_cmoh_op_t req_op_i, + input hpdcache_req_addr_t req_addr_i, + input hpdcache_req_data_t req_wdata_i, + // }}} + + // Write Buffer Interface + // {{{ + output logic wbuf_flush_all_o, + // }}} + + // Cache Directory Interface + // {{{ + output logic dir_check_o, + output hpdcache_set_t dir_check_set_o, + output hpdcache_tag_t dir_check_tag_o, + input hpdcache_way_vector_t dir_check_hit_way_i, + + output logic dir_inval_o, + output hpdcache_set_t dir_inval_set_o, + output hpdcache_way_vector_t dir_inval_way_o + // }}} +); +// }}} + +// Definition of constants and types +// {{{ + typedef enum { + CMOH_IDLE, + CMOH_FENCE_WAIT_WBUF_RTAB_EMPTY, + CMOH_INVAL_WAIT_MSHR_RTAB_EMPTY, + CMOH_INVAL_CHECK_NLINE, + CMOH_INVAL_SET + } hpdcache_cmoh_fsm_t; +// }}} + +// Internal signals and registers +// {{{ + hpdcache_cmoh_fsm_t cmoh_fsm_q, cmoh_fsm_d; + hpdcache_cmoh_op_t cmoh_op_q, cmoh_op_d; + hpdcache_req_addr_t cmoh_addr_q, cmoh_addr_d; + hpdcache_way_vector_t cmoh_way_q, cmoh_way_d; + hpdcache_set_t cmoh_set_cnt_q, cmoh_set_cnt_d; + hpdcache_nline_t cmoh_nline_q; + hpdcache_tag_t cmoh_tag_q; + hpdcache_set_t cmoh_set_q; + hpdcache_data_word_t cmoh_wdata; +// }}} + +// CMO request handler FSM +// {{{ + assign cmoh_nline_q = cmoh_addr_q[HPDCACHE_OFFSET_WIDTH +: HPDCACHE_NLINE_WIDTH], + cmoh_set_q = cmoh_nline_q[0 +: HPDCACHE_SET_WIDTH], + cmoh_tag_q = cmoh_nline_q[HPDCACHE_SET_WIDTH +: HPDCACHE_TAG_WIDTH]; + + assign dir_check_set_o = cmoh_set_q, + dir_check_tag_o = cmoh_tag_q; + + assign req_ready_o = (cmoh_fsm_q == CMOH_IDLE); + + // Only the least significant word of the write data contains parameters + // for the CMO handler + assign cmoh_wdata = req_wdata_i[0]; + + always_comb + begin : cmoh_fsm_comb + cmoh_op_d = cmoh_op_q; + cmoh_addr_d = cmoh_addr_q; + cmoh_way_d = cmoh_way_q; + cmoh_set_cnt_d = cmoh_set_cnt_q; + + dir_check_o = 1'b0; + + dir_inval_o = 1'b0; + dir_inval_set_o = cmoh_set_q; + dir_inval_way_o = '0; + + wbuf_flush_all_o = 1'b0; + + cmoh_fsm_d = cmoh_fsm_q; + + case (cmoh_fsm_q) + CMOH_IDLE: begin + cmoh_fsm_d = CMOH_IDLE; + + if (req_valid_i) begin + unique case (1'b1) + req_op_i.is_fence: begin + // request to the write buffer to send all open entries + wbuf_flush_all_o = rtab_empty_i; + + // then wait for the write buffer to be empty + if (!rtab_empty_i || !wbuf_empty_i) begin + cmoh_fsm_d = CMOH_FENCE_WAIT_WBUF_RTAB_EMPTY; + end + end + req_op_i.is_inval_by_nline, + req_op_i.is_inval_by_set, + req_op_i.is_inval_all: begin + cmoh_op_d = req_op_i; + cmoh_addr_d = req_addr_i; + cmoh_way_d = cmoh_wdata[0 +: HPDCACHE_WAYS]; + cmoh_set_cnt_d = 0; + if (mshr_empty_i && rtab_empty_i && ctrl_empty_i) begin + if (req_op_i.is_inval_by_nline) begin + cmoh_fsm_d = CMOH_INVAL_CHECK_NLINE; + end else begin + cmoh_fsm_d = CMOH_INVAL_SET; + end + end else begin + cmoh_fsm_d = CMOH_INVAL_WAIT_MSHR_RTAB_EMPTY; + end + end + default: begin + // pragma translate_off + $error("cmo handler: unexpected operation"); + // pragma translate_on + end + endcase + end + end + CMOH_FENCE_WAIT_WBUF_RTAB_EMPTY: begin + wbuf_flush_all_o = rtab_empty_i; + + if (wbuf_empty_i && rtab_empty_i) begin + cmoh_fsm_d = CMOH_IDLE; + end else begin + cmoh_fsm_d = CMOH_FENCE_WAIT_WBUF_RTAB_EMPTY; + end + end + CMOH_INVAL_WAIT_MSHR_RTAB_EMPTY: begin + cmoh_fsm_d = CMOH_INVAL_WAIT_MSHR_RTAB_EMPTY; + if (mshr_empty_i && rtab_empty_i && ctrl_empty_i) begin + if (cmoh_op_q.is_inval_by_nline) begin + cmoh_fsm_d = CMOH_INVAL_CHECK_NLINE; + end else begin + cmoh_fsm_d = CMOH_INVAL_SET; + end + end + end + CMOH_INVAL_CHECK_NLINE: begin + dir_check_o = 1'b1; + cmoh_fsm_d = CMOH_INVAL_SET; + end + CMOH_INVAL_SET: begin + cmoh_fsm_d = CMOH_INVAL_SET; + case (1'b1) + cmoh_op_q.is_inval_by_nline: begin + dir_inval_o = |dir_check_hit_way_i; + dir_inval_way_o = dir_check_hit_way_i; + cmoh_fsm_d = CMOH_IDLE; + end + cmoh_op_q.is_inval_all: begin + dir_inval_o = 1'b1; + dir_inval_way_o = {HPDCACHE_WAYS{1'b1}}; + dir_inval_set_o = cmoh_set_cnt_q; + cmoh_set_cnt_d = cmoh_set_cnt_q + 1; + if (cmoh_set_cnt_q == hpdcache_set_t'(HPDCACHE_SETS - 1)) begin + cmoh_fsm_d = CMOH_IDLE; + end + end + cmoh_op_q.is_inval_by_set: begin + dir_inval_o = 1'b1; + dir_inval_way_o = cmoh_way_q; + cmoh_fsm_d = CMOH_IDLE; + end + endcase + end + endcase + end +// }}} + +// CMO request handler set state +// {{{ + always_ff @(posedge clk_i or negedge rst_ni) + begin + if (!rst_ni) begin + cmoh_fsm_q <= CMOH_IDLE; + end else begin + cmoh_fsm_q <= cmoh_fsm_d; + end + end + + always_ff @(posedge clk_i) + begin + cmoh_op_q <= cmoh_op_d; + cmoh_addr_q <= cmoh_addr_d; + cmoh_way_q <= cmoh_way_d; + cmoh_set_cnt_q <= cmoh_set_cnt_d; + end +// }}} + +// Assertions +// {{{ +// pragma translate_off + assert property (@(posedge clk_i) + req_valid_i -> $onehot(req_op_i)) else + $error("cmo_handler: more than one operation type requested"); + + assert property (@(posedge clk_i) + req_valid_i -> (cmoh_fsm_q == CMOH_IDLE)) else + $error("cmo_handler: new request received while busy"); +// pragma translate_on +// }}} + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_core_arbiter.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_core_arbiter.sv new file mode 100644 index 00000000000..1f8f5a475c3 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_core_arbiter.sv @@ -0,0 +1,171 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : September, 2023 + * Description : HPDcache request arbiter + * History : + */ +module hpdcache_core_arbiter +import hpdcache_pkg::*; + // Parameters + // {{{ +#( + parameter int NREQUESTERS = 1 +) + // }}} + + // Ports + // {{{ +( + // Clock and reset signals + input logic clk_i, + input logic rst_ni, + + // Core request interface + // 1st cycle + input logic core_req_valid_i [NREQUESTERS-1:0], + output logic core_req_ready_o [NREQUESTERS-1:0], + input hpdcache_req_t core_req_i [NREQUESTERS-1:0], + // 2nd cycle + input logic core_req_abort_i [NREQUESTERS-1:0], + input hpdcache_tag_t core_req_tag_i [NREQUESTERS-1:0], + input hpdcache_pma_t core_req_pma_i [NREQUESTERS-1:0], + + // Core response interface + input logic core_rsp_valid_i, + input hpdcache_rsp_t core_rsp_i, + output logic core_rsp_valid_o [NREQUESTERS-1:0], + output hpdcache_rsp_t core_rsp_o [NREQUESTERS-1:0], + + // Granted request + output logic arb_req_valid_o, + input logic arb_req_ready_i, + output hpdcache_req_t arb_req_o, + output logic arb_abort_o, + output hpdcache_tag_t arb_tag_o, + output hpdcache_pma_t arb_pma_o +); + + // }}} + + // Declaration of internal signals + // {{{ + logic [NREQUESTERS-1:0] core_req_valid; + hpdcache_req_t [NREQUESTERS-1:0] core_req; + logic [NREQUESTERS-1:0] core_req_abort; + hpdcache_tag_t [NREQUESTERS-1:0] core_req_tag; + hpdcache_pma_t [NREQUESTERS-1:0] core_req_pma; + + logic [NREQUESTERS-1:0] arb_req_gnt_q, arb_req_gnt_d; + // }}} + + // Requesters arbiter + // {{{ + // Pack request ports + genvar gen_i; + + generate + for (gen_i = 0; gen_i < int'(NREQUESTERS); gen_i++) begin : gen_core_req + assign core_req_ready_o[gen_i] = arb_req_gnt_d[gen_i] & arb_req_ready_i, + core_req_valid[gen_i] = core_req_valid_i[gen_i], + core_req[gen_i] = core_req_i[gen_i]; + + assign core_req_abort[gen_i] = core_req_abort_i[gen_i], + core_req_tag[gen_i] = core_req_tag_i[gen_i], + core_req_pma[gen_i] = core_req_pma_i[gen_i]; + end + endgenerate + + // Arbiter + hpdcache_fxarb #(.N(NREQUESTERS)) req_arbiter_i + ( + .clk_i, + .rst_ni, + .req_i (core_req_valid), + .gnt_o (arb_req_gnt_d), + .ready_i (arb_req_ready_i) + ); + + // Request multiplexor + hpdcache_mux #( + .NINPUT (NREQUESTERS), + .DATA_WIDTH ($bits(hpdcache_req_t)), + .ONE_HOT_SEL (1'b1) + ) core_req_mux_i ( + .data_i (core_req), + .sel_i (arb_req_gnt_d), + .data_o (arb_req_o) + ); + + // Request abort multiplexor + hpdcache_mux #( + .NINPUT (NREQUESTERS), + .DATA_WIDTH (1), + .ONE_HOT_SEL (1'b1) + ) core_req_abort_mux_i ( + .data_i (core_req_abort), + .sel_i (arb_req_gnt_q), + .data_o (arb_abort_o) + ); + + // Tag Multiplexor + hpdcache_mux #( + .NINPUT (NREQUESTERS), + .DATA_WIDTH ($bits(hpdcache_tag_t)), + .ONE_HOT_SEL (1'b1) + ) core_req_tag_mux_i ( + .data_i (core_req_tag), + .sel_i (arb_req_gnt_q), + .data_o (arb_tag_o) + ); + + // PMA Multiplexor + hpdcache_mux #( + .NINPUT (NREQUESTERS), + .DATA_WIDTH ($bits(hpdcache_pma_t)), + .ONE_HOT_SEL (1'b1) + ) core_req_pma_mux_i ( + .data_i (core_req_pma), + .sel_i (arb_req_gnt_q), + .data_o (arb_pma_o) + ); + + // Save the grant signal for the tag in the next cycle + always_ff @(posedge clk_i or negedge rst_ni) + begin : arb_req_gnt_ff + if (!rst_ni) arb_req_gnt_q <= '0; + else arb_req_gnt_q <= arb_req_gnt_d; + end + + assign arb_req_valid_o = |arb_req_gnt_d; + // }}} + + // Response demultiplexor + // {{{ + always_comb + begin : resp_demux + for (int unsigned i = 0; i < NREQUESTERS; i++) begin + core_rsp_valid_o[i] = core_rsp_valid_i && (i == int'(core_rsp_i.sid)); + core_rsp_o[i] = core_rsp_i; + end + end + // }}} +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_ctrl.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_ctrl.sv new file mode 100755 index 00000000000..09fc29eabfc --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_ctrl.sv @@ -0,0 +1,760 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : HPDcache controller + * History : + */ +module hpdcache_ctrl + // Package imports + // {{{ +import hpdcache_pkg::*; + // }}} + + // Ports + // {{{ +( + input logic clk_i, + input logic rst_ni, + + // Core request interface + input logic core_req_valid_i, + output logic core_req_ready_o, + input hpdcache_req_t core_req_i, + input logic core_req_abort_i, + input hpdcache_tag_t core_req_tag_i, + input hpdcache_pma_t core_req_pma_i, + + // Core response interface + output logic core_rsp_valid_o, + output hpdcache_rsp_t core_rsp_o, + + // Force the write buffer to send all pending writes + input logic wbuf_flush_i, + + // Global control signals + output logic cachedir_hit_o, + + // Miss handler interface + output logic miss_mshr_check_o, + output mshr_set_t miss_mshr_check_set_o, + output mshr_tag_t miss_mshr_check_tag_o, + output logic miss_mshr_alloc_o, + output logic miss_mshr_alloc_cs_o, + input logic miss_mshr_alloc_ready_i, + input logic miss_mshr_alloc_full_i, + output hpdcache_nline_t miss_mshr_alloc_nline_o, + output hpdcache_req_tid_t miss_mshr_alloc_tid_o, + output hpdcache_req_sid_t miss_mshr_alloc_sid_o, + output hpdcache_word_t miss_mshr_alloc_word_o, + output logic miss_mshr_alloc_need_rsp_o, + output logic miss_mshr_alloc_is_prefetch_o, + input logic miss_mshr_hit_i, + + // Refill interface + input logic refill_req_valid_i, + output logic refill_req_ready_o, + input logic refill_busy_i, + input logic refill_updt_plru_i, + input hpdcache_set_t refill_set_i, + input hpdcache_dir_entry_t refill_dir_entry_i, + output hpdcache_way_vector_t refill_victim_way_o, + input hpdcache_way_vector_t refill_victim_way_i, + input logic refill_write_dir_i, + input logic refill_write_data_i, + input hpdcache_word_t refill_word_i, + input hpdcache_refill_data_t refill_data_i, + input logic refill_core_rsp_valid_i, + input hpdcache_rsp_t refill_core_rsp_i, + input hpdcache_nline_t refill_nline_i, + input logic refill_updt_rtab_i, + + // Write buffer interface + input logic wbuf_empty_i, + output logic wbuf_flush_all_o, + output logic wbuf_write_o, + input logic wbuf_write_ready_i, + output wbuf_addr_t wbuf_write_addr_o, + output wbuf_data_t wbuf_write_data_o, + output wbuf_be_t wbuf_write_be_o, + output logic wbuf_write_uncacheable_o, + input logic wbuf_read_hit_i, + output logic wbuf_read_flush_hit_o, + output hpdcache_req_addr_t wbuf_rtab_addr_o, + output logic wbuf_rtab_is_read_o, + input logic wbuf_rtab_hit_open_i, + input logic wbuf_rtab_hit_pend_i, + input logic wbuf_rtab_hit_sent_i, + input logic wbuf_rtab_not_ready_i, + + // Uncacheable request handler + input logic uc_busy_i, + output logic uc_lrsc_snoop_o, + output hpdcache_req_addr_t uc_lrsc_snoop_addr_o, + output hpdcache_req_size_t uc_lrsc_snoop_size_o, + output logic uc_req_valid_o, + output hpdcache_uc_op_t uc_req_op_o, + output hpdcache_req_addr_t uc_req_addr_o, + output hpdcache_req_size_t uc_req_size_o, + output hpdcache_req_data_t uc_req_data_o, + output hpdcache_req_be_t uc_req_be_o, + output logic uc_req_uc_o, + output hpdcache_req_sid_t uc_req_sid_o, + output hpdcache_req_tid_t uc_req_tid_o, + output logic uc_req_need_rsp_o, + input logic uc_wbuf_flush_all_i, + input logic uc_dir_amo_match_i, + input hpdcache_set_t uc_dir_amo_match_set_i, + input hpdcache_tag_t uc_dir_amo_match_tag_i, + input logic uc_dir_amo_update_plru_i, + output hpdcache_way_vector_t uc_dir_amo_hit_way_o, + input logic uc_data_amo_write_i, + input logic uc_data_amo_write_enable_i, + input hpdcache_set_t uc_data_amo_write_set_i, + input hpdcache_req_size_t uc_data_amo_write_size_i, + input hpdcache_word_t uc_data_amo_write_word_i, + input logic [63:0] uc_data_amo_write_data_i, + input logic [7:0] uc_data_amo_write_be_i, + output logic uc_core_rsp_ready_o, + input logic uc_core_rsp_valid_i, + input hpdcache_rsp_t uc_core_rsp_i, + + // Cache Management Operation (CMO) + input logic cmo_busy_i, + output logic cmo_req_valid_o, + output hpdcache_cmoh_op_t cmo_req_op_o, + output hpdcache_req_addr_t cmo_req_addr_o, + output hpdcache_req_data_t cmo_req_wdata_o, + input logic cmo_wbuf_flush_all_i, + input logic cmo_dir_check_i, + input hpdcache_set_t cmo_dir_check_set_i, + input hpdcache_tag_t cmo_dir_check_tag_i, + output hpdcache_way_vector_t cmo_dir_check_hit_way_o, + input logic cmo_dir_inval_i, + input hpdcache_set_t cmo_dir_inval_set_i, + input hpdcache_way_vector_t cmo_dir_inval_way_i, + + output logic rtab_empty_o, + output logic ctrl_empty_o, + + // Configuration signals + input logic cfg_enable_i, + input logic cfg_rtab_single_entry_i, + + // Performance events + output logic evt_cache_write_miss_o, + output logic evt_cache_read_miss_o, + output logic evt_uncached_req_o, + output logic evt_cmo_req_o, + output logic evt_write_req_o, + output logic evt_read_req_o, + output logic evt_prefetch_req_o, + output logic evt_req_on_hold_o, + output logic evt_rtab_rollback_o, + output logic evt_stall_refill_o, + output logic evt_stall_o +); + // }}} + + // Definition of internal registers + // {{{ + logic st1_req_valid_q, st1_req_valid_d; + hpdcache_req_t st1_req_q; + logic st1_req_rtab_q; + rtab_ptr_t st1_rtab_pop_try_ptr_q; + + logic st2_req_valid_q, st2_req_valid_d; + logic st2_req_is_prefetch_q, st2_req_is_prefetch_d; + logic st2_req_need_rsp_q; + hpdcache_req_addr_t st2_req_addr_q; + hpdcache_req_sid_t st2_req_sid_q; + hpdcache_req_tid_t st2_req_tid_q; + // }}} + + // Definition of internal signals + // {{{ + logic [1:0] st0_arb_req; + logic [1:0] st0_arb_req_grant; + logic st0_arb_ready; + + logic st0_req_ready; + + logic st0_req_valid; + hpdcache_req_t st0_req; + logic st0_req_is_uncacheable; + logic st0_req_is_load; + logic st0_req_is_store; + logic st0_req_is_amo; + logic st0_req_is_cmo_fence; + logic st0_req_is_cmo_inval; + logic st0_req_is_cmo_prefetch; + logic st0_req_cachedir_read; + logic st0_req_cachedata_read; + hpdcache_set_t st0_req_set; + hpdcache_word_t st0_req_word; + logic st0_rtab_pop_try_valid; + logic st0_rtab_pop_try_ready; + hpdcache_req_t st0_rtab_pop_try_req; + logic st0_rtab_pop_try_sel; + rtab_ptr_t st0_rtab_pop_try_ptr; + + logic st1_rsp_valid; + logic st1_rsp_aborted; + hpdcache_req_t st1_req; + logic st1_req_abort; + logic st1_req_cachedata_write; + logic st1_req_cachedata_write_enable; + hpdcache_pma_t st1_req_pma; + hpdcache_tag_t st1_req_tag; + hpdcache_set_t st1_req_set; + hpdcache_word_t st1_req_word; + hpdcache_nline_t st1_req_nline; + hpdcache_req_addr_t st1_req_addr; + logic st1_req_updt_lru; + logic st1_req_is_uncacheable; + logic st1_req_is_load; + logic st1_req_is_store; + logic st1_req_is_amo; + logic st1_req_is_amo_lr; + logic st1_req_is_amo_sc; + logic st1_req_is_amo_swap; + logic st1_req_is_amo_add; + logic st1_req_is_amo_and; + logic st1_req_is_amo_or; + logic st1_req_is_amo_xor; + logic st1_req_is_amo_max; + logic st1_req_is_amo_maxu; + logic st1_req_is_amo_min; + logic st1_req_is_amo_minu; + logic st1_req_is_cmo_inval; + logic st1_req_is_cmo_fence; + logic st1_req_is_cmo_prefetch; + hpdcache_way_vector_t st1_dir_hit; + hpdcache_req_data_t st1_read_data; + logic st1_rtab_alloc; + logic st1_rtab_alloc_and_link; + logic st1_rtab_pop_try_commit; + logic st1_rtab_pop_try_rback; + logic st1_rtab_mshr_hit; + logic st1_rtab_mshr_full; + logic st1_rtab_mshr_ready; + logic st1_rtab_wbuf_hit; + logic st1_rtab_wbuf_not_ready; + logic st1_rtab_check; + logic st1_rtab_check_hit; + + logic st2_req_we; + hpdcache_word_t st2_req_word; + + logic rtab_full; + + logic hpdcache_init_ready; + // }}} + + // Decoding of the request + // {{{ + // Select between request in the replay table or a new core requests + assign st0_req_valid = st0_rtab_pop_try_sel ? st0_rtab_pop_try_valid + : core_req_valid_i, + st0_req.addr_offset = st0_rtab_pop_try_sel ? st0_rtab_pop_try_req.addr_offset + : core_req_i.addr_offset, + st0_req.addr_tag = st0_rtab_pop_try_sel ? st0_rtab_pop_try_req.addr_tag + : core_req_i.addr_tag, + st0_req.wdata = st0_rtab_pop_try_sel ? st0_rtab_pop_try_req.wdata + : core_req_i.wdata, + st0_req.op = st0_rtab_pop_try_sel ? st0_rtab_pop_try_req.op + : core_req_i.op, + st0_req.be = st0_rtab_pop_try_sel ? st0_rtab_pop_try_req.be + : core_req_i.be, + st0_req.size = st0_rtab_pop_try_sel ? st0_rtab_pop_try_req.size + : core_req_i.size, + st0_req.sid = st0_rtab_pop_try_sel ? st0_rtab_pop_try_req.sid + : core_req_i.sid, + st0_req.tid = st0_rtab_pop_try_sel ? st0_rtab_pop_try_req.tid + : core_req_i.tid, + st0_req.need_rsp = st0_rtab_pop_try_sel ? st0_rtab_pop_try_req.need_rsp + : core_req_i.need_rsp, + st0_req.phys_indexed = st0_rtab_pop_try_sel ? 1'b1 + : core_req_i.phys_indexed, + st0_req.pma = st0_rtab_pop_try_sel ? st0_rtab_pop_try_req.pma + : core_req_i.pma; + + // Decode operation in stage 0 + assign st0_req_is_uncacheable = ~cfg_enable_i | ( st0_req.phys_indexed + & st0_req.pma.uncacheable), + st0_req_is_load = is_load(st0_req.op), + st0_req_is_store = is_store(st0_req.op), + st0_req_is_amo = is_amo(st0_req.op), + st0_req_is_cmo_fence = is_cmo_fence(st0_req.op, st0_req.size), + st0_req_is_cmo_inval = is_cmo_inval(st0_req.op, st0_req.size), + st0_req_is_cmo_prefetch = is_cmo_prefetch(st0_req.op, st0_req.size); + + // Decode operation in stage 1 + + // In case of replay or physically-indexed cache, the tag and PMA come + // from stage 0. Otherwise, this information come directly from the + // requester in stage 1 + assign st1_req_tag = st1_req_q.phys_indexed ? st1_req_q.addr_tag : core_req_tag_i, + st1_req_pma = st1_req_q.phys_indexed ? st1_req_q.pma : core_req_pma_i; + + assign st1_req.addr_offset = st1_req_q.addr_offset, + st1_req.addr_tag = st1_req_rtab_q ? st1_req_q.addr_tag : st1_req_tag, + st1_req.wdata = st1_req_q.wdata, + st1_req.op = st1_req_q.op, + st1_req.be = st1_req_q.be, + st1_req.size = st1_req_q.size, + st1_req.sid = st1_req_q.sid, + st1_req.tid = st1_req_q.tid, + st1_req.need_rsp = st1_req_q.need_rsp, + st1_req.phys_indexed = st1_req_q.phys_indexed, + st1_req.pma = st1_req_rtab_q ? st1_req_q.pma : st1_req_pma; + + // A requester can ask to abort a request it initiated on the + // previous cycle (stage 0). Useful in case of TLB miss for example + assign st1_req_abort = core_req_abort_i & ~st1_req.phys_indexed; + + assign st1_req_is_uncacheable = ~cfg_enable_i | st1_req.pma.uncacheable, + st1_req_is_load = is_load(st1_req.op), + st1_req_is_store = is_store(st1_req.op), + st1_req_is_amo = is_amo(st1_req.op), + st1_req_is_amo_lr = is_amo_lr(st1_req.op), + st1_req_is_amo_sc = is_amo_sc(st1_req.op), + st1_req_is_amo_swap = is_amo_swap(st1_req.op), + st1_req_is_amo_add = is_amo_add(st1_req.op), + st1_req_is_amo_and = is_amo_and(st1_req.op), + st1_req_is_amo_or = is_amo_or(st1_req.op), + st1_req_is_amo_xor = is_amo_xor(st1_req.op), + st1_req_is_amo_max = is_amo_max(st1_req.op), + st1_req_is_amo_maxu = is_amo_maxu(st1_req.op), + st1_req_is_amo_min = is_amo_min(st1_req.op), + st1_req_is_amo_minu = is_amo_minu(st1_req.op), + st1_req_is_cmo_inval = is_cmo_inval(st1_req.op, st1_req.size), + st1_req_is_cmo_fence = is_cmo_fence(st1_req.op, st1_req.size), + st1_req_is_cmo_prefetch = is_cmo_prefetch(st1_req.op, st1_req.size); + // }}} + + // Refill arbiter: it arbitrates between normal requests (from the core, + // coprocessor, prefetch) and refill requests (from the miss handler). + // + // TODO This arbiter could be replaced by a weighted-round-robin arbiter. + // This way we could distribute asymetrically the bandwidth to the core + // and the refill interfaces. + // {{{ + hpdcache_rrarb #(.N(2)) st0_arb_i + ( + .clk_i, + .rst_ni, + .req_i (st0_arb_req), + .gnt_o (st0_arb_req_grant), + .ready_i (st0_arb_ready) + ); + + // The arbiter can cycle the priority token when: + // - The granted request is consumed (req_grant & req_valid & req_ready) + // - The granted request is aborted (req_grant & ~req_valid) + assign st0_arb_ready = ((st0_arb_req_grant[0] & st0_req_valid & st0_req_ready ) | + (st0_arb_req_grant[1] & refill_req_valid_i & refill_req_ready_o) | + (st0_arb_req_grant[0] & ~st0_req_valid ) | + (st0_arb_req_grant[1] & ~refill_req_valid_i)); + + assign st0_arb_req[0] = st0_req_valid, + st0_arb_req[1] = refill_req_valid_i; + + assign core_req_ready_o = st0_req_ready & ~st0_rtab_pop_try_sel, + st0_rtab_pop_try_ready = st0_req_ready & st0_rtab_pop_try_sel; + + // Trigger an event signal when the pipeline is stalled (new request is not consumed) + assign evt_stall_o = core_req_valid_i & ~core_req_ready_o; + // }}} + + // Cache controller protocol engine + // {{{ + hpdcache_ctrl_pe hpdcache_ctrl_pe_i( + .arb_st0_req_valid_i (st0_req_valid & st0_arb_req_grant[0]), + .arb_st0_req_ready_o (st0_req_ready), + .arb_refill_valid_i (refill_req_valid_i & st0_arb_req_grant[1]), + .arb_refill_ready_o (refill_req_ready_o), + .st0_req_is_uncacheable_i (st0_req_is_uncacheable), + .st0_req_need_rsp_i (st0_req.need_rsp), + .st0_req_is_load_i (st0_req_is_load), + .st0_req_is_store_i (st0_req_is_store), + .st0_req_is_amo_i (st0_req_is_amo), + .st0_req_is_cmo_fence_i (st0_req_is_cmo_fence), + .st0_req_is_cmo_inval_i (st0_req_is_cmo_inval), + .st0_req_is_cmo_prefetch_i (st0_req_is_cmo_prefetch), + .st0_req_mshr_check_o (miss_mshr_check_o), + .st0_req_cachedir_read_o (st0_req_cachedir_read), + .st0_req_cachedata_read_o (st0_req_cachedata_read), + + .st1_req_valid_i (st1_req_valid_q), + .st1_req_abort_i (st1_req_abort), + .st1_req_rtab_i (st1_req_rtab_q), + .st1_req_is_uncacheable_i (st1_req_is_uncacheable), + .st1_req_need_rsp_i (st1_req.need_rsp), + .st1_req_is_load_i (st1_req_is_load), + .st1_req_is_store_i (st1_req_is_store), + .st1_req_is_amo_i (st1_req_is_amo), + .st1_req_is_cmo_inval_i (st1_req_is_cmo_inval), + .st1_req_is_cmo_fence_i (st1_req_is_cmo_fence), + .st1_req_is_cmo_prefetch_i (st1_req_is_cmo_prefetch), + .st1_req_valid_o (st1_req_valid_d), + .st1_rsp_valid_o (st1_rsp_valid), + .st1_rsp_aborted_o (st1_rsp_aborted), + .st1_req_cachedir_updt_lru_o (st1_req_updt_lru), + .st1_req_cachedata_write_o (st1_req_cachedata_write), + .st1_req_cachedata_write_enable_o (st1_req_cachedata_write_enable), + + .st2_req_valid_i (st2_req_valid_q), + .st2_req_is_prefetch_i (st2_req_is_prefetch_q), + .st2_req_valid_o (st2_req_valid_d), + .st2_req_we_o (st2_req_we), + .st2_req_is_prefetch_o (st2_req_is_prefetch_d), + .st2_req_mshr_alloc_o (miss_mshr_alloc_o), + .st2_req_mshr_alloc_cs_o (miss_mshr_alloc_cs_o), + + .rtab_full_i (rtab_full), + .rtab_req_valid_i (st0_rtab_pop_try_valid), + .rtab_sel_o (st0_rtab_pop_try_sel), + .rtab_check_o (st1_rtab_check), + .rtab_check_hit_i (st1_rtab_check_hit), + .st1_rtab_alloc_o (st1_rtab_alloc), + .st1_rtab_alloc_and_link_o (st1_rtab_alloc_and_link), + .st1_rtab_commit_o (st1_rtab_pop_try_commit), + .st1_rtab_rback_o (st1_rtab_pop_try_rback), + .st1_rtab_mshr_hit_o (st1_rtab_mshr_hit), + .st1_rtab_mshr_full_o (st1_rtab_mshr_full), + .st1_rtab_mshr_ready_o (st1_rtab_mshr_ready), + .st1_rtab_wbuf_hit_o (st1_rtab_wbuf_hit), + .st1_rtab_wbuf_not_ready_o (st1_rtab_wbuf_not_ready), + + .cachedir_hit_i (cachedir_hit_o), + .cachedir_init_ready_i (hpdcache_init_ready), + + .mshr_alloc_ready_i (miss_mshr_alloc_ready_i), + .mshr_hit_i (miss_mshr_hit_i), + .mshr_full_i (miss_mshr_alloc_full_i), + + .refill_busy_i, + .refill_core_rsp_valid_i, + + .wbuf_write_valid_o (wbuf_write_o), + .wbuf_write_ready_i, + .wbuf_read_hit_i, + .wbuf_write_uncacheable_o, + .wbuf_read_flush_hit_o, + + .uc_busy_i, + .uc_req_valid_o, + .uc_core_rsp_ready_o, + + .cmo_busy_i, + .cmo_req_valid_o, + + .evt_cache_write_miss_o, + .evt_cache_read_miss_o, + .evt_uncached_req_o, + .evt_cmo_req_o, + .evt_write_req_o, + .evt_read_req_o, + .evt_prefetch_req_o, + .evt_req_on_hold_o, + .evt_rtab_rollback_o, + .evt_stall_refill_o + ); + + assign ctrl_empty_o = ~(st1_req_valid_q | st2_req_valid_q); + // }}} + + // Replay table + // {{{ + hpdcache_rtab #( + .rtab_entry_t (hpdcache_req_t) + ) hpdcache_rtab_i( + .clk_i, + .rst_ni, + + .empty_o (rtab_empty_o), + .full_o (rtab_full), + + .check_i (st1_rtab_check), + .check_nline_i (st1_req_nline), + .check_hit_o (st1_rtab_check_hit), + + .alloc_i (st1_rtab_alloc), + .alloc_and_link_i (st1_rtab_alloc_and_link), + .alloc_req_i (st1_req), + .alloc_mshr_hit_i (st1_rtab_mshr_hit), + .alloc_mshr_full_i (st1_rtab_mshr_full), + .alloc_mshr_ready_i (st1_rtab_mshr_ready), + .alloc_wbuf_hit_i (st1_rtab_wbuf_hit), + .alloc_wbuf_not_ready_i (st1_rtab_wbuf_not_ready), + + .pop_try_valid_o (st0_rtab_pop_try_valid), + .pop_try_i (st0_rtab_pop_try_ready), + .pop_try_req_o (st0_rtab_pop_try_req), + .pop_try_ptr_o (st0_rtab_pop_try_ptr), + + .pop_commit_i (st1_rtab_pop_try_commit), + .pop_commit_ptr_i (st1_rtab_pop_try_ptr_q), + + .pop_rback_i (st1_rtab_pop_try_rback), + .pop_rback_ptr_i (st1_rtab_pop_try_ptr_q), + .pop_rback_mshr_hit_i (st1_rtab_mshr_hit), + .pop_rback_mshr_full_i (st1_rtab_mshr_full), + .pop_rback_mshr_ready_i (st1_rtab_mshr_ready), + .pop_rback_wbuf_hit_i (st1_rtab_wbuf_hit), + .pop_rback_wbuf_not_ready_i (st1_rtab_wbuf_not_ready), + + .wbuf_addr_o (wbuf_rtab_addr_o), + .wbuf_is_read_o (wbuf_rtab_is_read_o), + .wbuf_hit_open_i (wbuf_rtab_hit_open_i), + .wbuf_hit_pend_i (wbuf_rtab_hit_pend_i), + .wbuf_hit_sent_i (wbuf_rtab_hit_sent_i), + .wbuf_not_ready_i (wbuf_rtab_not_ready_i), + + .miss_ready_i (miss_mshr_alloc_ready_i), + + .refill_i (refill_updt_rtab_i), + .refill_nline_i, + + .cfg_single_entry_i (cfg_rtab_single_entry_i) + ); + // }}} + + // Pipeline stage 1 registers + // {{{ + always_ff @(posedge clk_i) + begin : st1_req_payload_ff + if (st0_req_ready) begin + st1_req_q <= st0_req; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) + begin : st1_req_valid_ff + if (!rst_ni) begin + st1_req_valid_q <= 1'b0; + st1_req_rtab_q <= 1'b0; + st1_rtab_pop_try_ptr_q <= '0; + end else begin + st1_req_valid_q <= st1_req_valid_d; + if (st0_req_ready) begin + st1_req_rtab_q <= st0_rtab_pop_try_sel; + if (st0_rtab_pop_try_sel) begin + st1_rtab_pop_try_ptr_q <= st0_rtab_pop_try_ptr; + end + end + end + end + // }}} + + // Pipeline stage 2 registers + // {{{ + always_ff @(posedge clk_i) + begin : st2_req_payload_ff + if (st2_req_we) begin + st2_req_need_rsp_q <= st1_req.need_rsp; + st2_req_addr_q <= st1_req_addr; + st2_req_sid_q <= st1_req.sid; + st2_req_tid_q <= st1_req.tid; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) + begin : st2_req_valid_ff + if (!rst_ni) begin + st2_req_valid_q <= 1'b0; + st2_req_is_prefetch_q <= 1'b0; + end else begin + st2_req_valid_q <= st2_req_valid_d; + st2_req_is_prefetch_q <= st2_req_is_prefetch_d; + end + end + // }}} + + // Controller for the HPDcache directory and data memory arrays + // {{{ + assign st0_req_set = hpdcache_get_req_offset_set(st0_req.addr_offset), + st0_req_word = hpdcache_get_req_offset_word(st0_req.addr_offset), + st1_req_set = hpdcache_get_req_offset_set(st1_req.addr_offset), + st1_req_word = hpdcache_get_req_offset_word(st1_req.addr_offset), + st1_req_addr = {st1_req.addr_tag, st1_req.addr_offset}, + st1_req_nline = hpdcache_get_req_addr_nline(st1_req_addr), + st2_req_word = hpdcache_get_req_addr_word(st2_req_addr_q); + + hpdcache_memctrl hpdcache_memctrl_i ( + .clk_i, + .rst_ni, + + .ready_o (hpdcache_init_ready), + + .dir_match_i (st0_req_cachedir_read), + .dir_match_set_i (st0_req_set), + .dir_match_tag_i (st1_req.addr_tag), + .dir_update_lru_i (st1_req_updt_lru), + .dir_hit_way_o (st1_dir_hit), + + .dir_amo_match_i (uc_dir_amo_match_i), + .dir_amo_match_set_i (uc_dir_amo_match_set_i), + .dir_amo_match_tag_i (uc_dir_amo_match_tag_i), + .dir_amo_update_plru_i (uc_dir_amo_update_plru_i), + .dir_amo_hit_way_o (uc_dir_amo_hit_way_o), + + .dir_refill_i (refill_write_dir_i), + .dir_refill_set_i (refill_set_i), + .dir_refill_entry_i (refill_dir_entry_i), + .dir_refill_updt_plru_i (refill_updt_plru_i), + .dir_victim_way_o (refill_victim_way_o), + + .dir_cmo_check_i (cmo_dir_check_i), + .dir_cmo_check_set_i (cmo_dir_check_set_i), + .dir_cmo_check_tag_i (cmo_dir_check_tag_i), + .dir_cmo_check_hit_way_o (cmo_dir_check_hit_way_o), + + .dir_cmo_inval_i (cmo_dir_inval_i), + .dir_cmo_inval_set_i (cmo_dir_inval_set_i), + .dir_cmo_inval_way_i (cmo_dir_inval_way_i), + + .data_req_read_i (st0_req_cachedata_read), + .data_req_read_set_i (st0_req_set), + .data_req_read_size_i (st0_req.size), + .data_req_read_word_i (st0_req_word), + .data_req_read_data_o (st1_read_data), + + .data_req_write_i (st1_req_cachedata_write), + .data_req_write_enable_i (st1_req_cachedata_write_enable), + .data_req_write_set_i (st1_req_set), + .data_req_write_size_i (st1_req.size), + .data_req_write_word_i (st1_req_word), + .data_req_write_data_i (st1_req.wdata), + .data_req_write_be_i (st1_req.be), + + .data_amo_write_i (uc_data_amo_write_i), + .data_amo_write_enable_i (uc_data_amo_write_enable_i), + .data_amo_write_set_i (uc_data_amo_write_set_i), + .data_amo_write_size_i (uc_data_amo_write_size_i), + .data_amo_write_word_i (uc_data_amo_write_word_i), + .data_amo_write_data_i (uc_data_amo_write_data_i), + .data_amo_write_be_i (uc_data_amo_write_be_i), + + .data_refill_i (refill_write_data_i), + .data_refill_way_i (refill_victim_way_i), + .data_refill_set_i (refill_set_i), + .data_refill_word_i (refill_word_i), + .data_refill_data_i (refill_data_i) + ); + + assign cachedir_hit_o = |st1_dir_hit; + // }}} + + // Write buffer outputs + // {{{ + assign wbuf_write_addr_o = st1_req_addr, + wbuf_write_data_o = st1_req.wdata, + wbuf_write_be_o = st1_req.be, + wbuf_flush_all_o = cmo_wbuf_flush_all_i | uc_wbuf_flush_all_i | wbuf_flush_i; + // }}} + + // Miss handler outputs + // {{{ + assign miss_mshr_check_set_o = + st0_req.addr_offset[HPDCACHE_OFFSET_WIDTH +: HPDCACHE_MSHR_SET_WIDTH]; + assign miss_mshr_check_tag_o = + st1_req_nline[HPDCACHE_MSHR_SET_WIDTH +: HPDCACHE_MSHR_TAG_WIDTH]; + + assign miss_mshr_alloc_nline_o = hpdcache_get_req_addr_nline(st2_req_addr_q), + miss_mshr_alloc_tid_o = st2_req_tid_q, + miss_mshr_alloc_sid_o = st2_req_sid_q, + miss_mshr_alloc_word_o = st2_req_word, + miss_mshr_alloc_need_rsp_o = st2_req_need_rsp_q, + miss_mshr_alloc_is_prefetch_o = st2_req_is_prefetch_q; + // }}} + + // Uncacheable request handler outputs + // {{{ + assign uc_lrsc_snoop_o = st1_req_valid_q & st1_req_is_store, + uc_lrsc_snoop_addr_o = st1_req_addr, + uc_lrsc_snoop_size_o = st1_req.size, + uc_req_addr_o = st1_req_addr, + uc_req_size_o = st1_req.size, + uc_req_data_o = st1_req.wdata, + uc_req_be_o = st1_req.be, + uc_req_uc_o = st1_req_is_uncacheable, + uc_req_sid_o = st1_req.sid, + uc_req_tid_o = st1_req.tid, + uc_req_need_rsp_o = st1_req.need_rsp, + uc_req_op_o.is_ld = st1_req_is_load, + uc_req_op_o.is_st = st1_req_is_store, + uc_req_op_o.is_amo_lr = st1_req_is_amo_lr, + uc_req_op_o.is_amo_sc = st1_req_is_amo_sc, + uc_req_op_o.is_amo_swap = st1_req_is_amo_swap, + uc_req_op_o.is_amo_add = st1_req_is_amo_add, + uc_req_op_o.is_amo_and = st1_req_is_amo_and, + uc_req_op_o.is_amo_or = st1_req_is_amo_or, + uc_req_op_o.is_amo_xor = st1_req_is_amo_xor, + uc_req_op_o.is_amo_max = st1_req_is_amo_max, + uc_req_op_o.is_amo_maxu = st1_req_is_amo_maxu, + uc_req_op_o.is_amo_min = st1_req_is_amo_min, + uc_req_op_o.is_amo_minu = st1_req_is_amo_minu; + // }}} + + // CMO request handler outputs + // {{{ + assign cmo_req_addr_o = st1_req_addr, + cmo_req_wdata_o = st1_req.wdata, + cmo_req_op_o.is_fence = st1_req_is_cmo_fence, + cmo_req_op_o.is_inval_by_nline = st1_req_is_cmo_inval & + is_cmo_inval_by_nline(st1_req.size), + cmo_req_op_o.is_inval_by_set = st1_req_is_cmo_inval & + is_cmo_inval_by_set(st1_req.size), + cmo_req_op_o.is_inval_all = st1_req_is_cmo_inval & + is_cmo_inval_all(st1_req.size); + // }}} + + // Control of the response to the core + // {{{ + assign core_rsp_valid_o = refill_core_rsp_valid_i | + (uc_core_rsp_valid_i & uc_core_rsp_ready_o) | + st1_rsp_valid, + core_rsp_o.rdata = (refill_core_rsp_valid_i ? refill_core_rsp_i.rdata : + (uc_core_rsp_valid_i ? uc_core_rsp_i.rdata : + st1_read_data)), + core_rsp_o.sid = (refill_core_rsp_valid_i ? refill_core_rsp_i.sid : + (uc_core_rsp_valid_i ? uc_core_rsp_i.sid : + st1_req.sid)), + core_rsp_o.tid = (refill_core_rsp_valid_i ? refill_core_rsp_i.tid : + (uc_core_rsp_valid_i ? uc_core_rsp_i.tid : + st1_req.tid)), + core_rsp_o.error = (refill_core_rsp_valid_i ? refill_core_rsp_i.error : + (uc_core_rsp_valid_i ? uc_core_rsp_i.error : + /* FIXME */1'b0)), + core_rsp_o.aborted = st1_rsp_aborted; + // }}} + + // Assertions + // pragma translate_off + // {{{ + assert property (@(posedge clk_i) + $onehot0({core_req_ready_o, st0_rtab_pop_try_ready, refill_req_ready_o})) else + $error("ctrl: only one request can be served per cycle"); + // }}} + // pragma translate_on +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_ctrl_pe.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_ctrl_pe.sv new file mode 100755 index 00000000000..13b4f5883cd --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_ctrl_pe.sv @@ -0,0 +1,620 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : HPDcache Control Protocol Engine + * History : + */ +module hpdcache_ctrl_pe + // Ports + // {{{ +( + // Refill arbiter + // {{{ + input logic arb_st0_req_valid_i, + output logic arb_st0_req_ready_o, + input logic arb_refill_valid_i, + output logic arb_refill_ready_o, + // }}} + + // Pipeline stage 0 + // {{{ + input logic st0_req_is_uncacheable_i, + input logic st0_req_need_rsp_i, + input logic st0_req_is_load_i, + input logic st0_req_is_store_i, + input logic st0_req_is_amo_i, + input logic st0_req_is_cmo_fence_i, + input logic st0_req_is_cmo_inval_i, + input logic st0_req_is_cmo_prefetch_i, + output logic st0_req_mshr_check_o, + output logic st0_req_cachedir_read_o, + output logic st0_req_cachedata_read_o, + // }}} + + // Pipeline stage 1 + // {{{ + input logic st1_req_valid_i, + input logic st1_req_abort_i, + input logic st1_req_rtab_i, + input logic st1_req_is_uncacheable_i, + input logic st1_req_need_rsp_i, + input logic st1_req_is_load_i, + input logic st1_req_is_store_i, + input logic st1_req_is_amo_i, + input logic st1_req_is_cmo_inval_i, + input logic st1_req_is_cmo_fence_i, + input logic st1_req_is_cmo_prefetch_i, + output logic st1_req_valid_o, + output logic st1_rsp_valid_o, + output logic st1_rsp_aborted_o, + output logic st1_req_cachedir_updt_lru_o, + output logic st1_req_cachedata_write_o, + output logic st1_req_cachedata_write_enable_o, + // }}} + + // Pipeline stage 2 + // {{{ + input logic st2_req_valid_i, + input logic st2_req_is_prefetch_i, + output logic st2_req_valid_o, + output logic st2_req_we_o, + output logic st2_req_is_prefetch_o, + output logic st2_req_mshr_alloc_o, + output logic st2_req_mshr_alloc_cs_o, + // }}} + + // Replay + // {{{ + input logic rtab_full_i, + input logic rtab_req_valid_i, + output logic rtab_sel_o, + output logic rtab_check_o, + input logic rtab_check_hit_i, + output logic st1_rtab_alloc_o, + output logic st1_rtab_alloc_and_link_o, + output logic st1_rtab_commit_o, + output logic st1_rtab_rback_o, + output logic st1_rtab_mshr_hit_o, + output logic st1_rtab_mshr_full_o, + output logic st1_rtab_mshr_ready_o, + output logic st1_rtab_wbuf_hit_o, + output logic st1_rtab_wbuf_not_ready_o, + // }}} + + // Cache directory + // {{{ + input logic cachedir_hit_i, + input logic cachedir_init_ready_i, + // }}} + + // Miss Status Holding Register (MSHR) + // {{{ + input logic mshr_alloc_ready_i, + input logic mshr_hit_i, + input logic mshr_full_i, + // }}} + + // Refill interface + // {{{ + input logic refill_busy_i, + input logic refill_core_rsp_valid_i, + // }}} + + // Write buffer + // {{{ + input logic wbuf_write_ready_i, + input logic wbuf_read_hit_i, + output logic wbuf_write_valid_o, + output logic wbuf_write_uncacheable_o, + output logic wbuf_read_flush_hit_o, + // }}} + + // Uncacheable request handler + // {{{ + input logic uc_busy_i, + output logic uc_req_valid_o, + output logic uc_core_rsp_ready_o, + // }}} + + // Cache Management Operation (CMO) + // {{{ + input logic cmo_busy_i, + output logic cmo_req_valid_o, + // }}} + + // Performance events + // {{{ + output logic evt_cache_write_miss_o, + output logic evt_cache_read_miss_o, + output logic evt_uncached_req_o, + output logic evt_cmo_req_o, + output logic evt_write_req_o, + output logic evt_read_req_o, + output logic evt_prefetch_req_o, + output logic evt_req_on_hold_o, + output logic evt_rtab_rollback_o, + output logic evt_stall_refill_o + // }}} +); + // }}} + + // Definition of internal signals + // {{{ + logic st1_fence; + logic st1_rtab_alloc, st1_rtab_alloc_and_link; + // }}} + + // Global control signals + // {{{ + + // Determine if the new request is a "fence". Here, fence instructions are + // considered those that need to be executed in program order + // (irrespectively of addresses). This means that all memory operations + // arrived before the "fence" instruction need to be finished, and only + // then the "fence" instruction is executed. In the same manner, all + // instructions following the "fence" need to wait the completion of this + // last before being executed. + assign st1_fence = st1_req_is_uncacheable_i | + st1_req_is_cmo_fence_i | + st1_req_is_cmo_inval_i | + st1_req_is_amo_i; + // }}} + + // Arbitration of responses to the core + // {{{ + assign uc_core_rsp_ready_o = ~refill_core_rsp_valid_i; + // }}} + + // Arbiter between core or replay request. + // {{{ + // Take the replay request when: + // - The replay table is full. + // - The replay table has a ready request (request with all dependencies solved) + // - There is an outstanding CMO or uncached/AMO request + // + // IMPORTANT: When the replay table is full, the cache cannot accept new core + // requests because this can introduce a dead-lock : If the core request needs to + // be put on hold, as there is no place the replay table, the pipeline needs to + // stall. If the pipeline is stalled, dependencies of on-hold requests cannot be + // solved, and the system is locked. + assign rtab_sel_o = rtab_full_i | + rtab_req_valid_i | + (st1_req_valid_i & st1_fence) | + cmo_busy_i | + uc_busy_i; + // }}} + + // Replay logic + // {{{ + // Replay table allocation + assign st1_rtab_alloc_o = st1_rtab_alloc & ~st1_req_rtab_i, + st1_rtab_alloc_and_link_o = st1_rtab_alloc_and_link, + st1_rtab_rback_o = st1_rtab_alloc & st1_req_rtab_i; + + // Performance event + assign evt_req_on_hold_o = st1_rtab_alloc | st1_rtab_alloc_and_link, + evt_rtab_rollback_o = st1_rtab_rback_o; + // }}} + + // Data-cache control lines + // {{{ + always_comb + begin : hpdcache_ctrl_comb + automatic logic nop, st1_nop, st2_nop; + + uc_req_valid_o = 1'b0; + + cmo_req_valid_o = 1'b0; + + wbuf_write_valid_o = 1'b0; + wbuf_read_flush_hit_o = 1'b0; + wbuf_write_uncacheable_o = 1'b0; // unused + + arb_st0_req_ready_o = 1'b0; + arb_refill_ready_o = 1'b0; + + st0_req_mshr_check_o = 1'b0; + st0_req_cachedir_read_o = 1'b0; + st0_req_cachedata_read_o = 1'b0; + + st1_req_valid_o = st1_req_valid_i; + st1_nop = 1'b0; + st1_req_cachedata_write_o = 1'b0; + st1_req_cachedata_write_enable_o = 1'b0; + st1_req_cachedir_updt_lru_o = 1'b0; + st1_rsp_valid_o = 1'b0; + st1_rsp_aborted_o = 1'b0; + + st2_req_valid_o = st2_req_valid_i; + st2_req_we_o = 1'b0; + st2_req_is_prefetch_o = 1'b0; + st2_req_mshr_alloc_cs_o = 1'b0; + st2_req_mshr_alloc_o = 1'b0; + st2_nop = 1'b0; + + nop = 1'b0; + + rtab_check_o = 1'b0; + st1_rtab_alloc = 1'b0; + st1_rtab_alloc_and_link = 1'b0; + st1_rtab_commit_o = 1'b0; + st1_rtab_mshr_hit_o = 1'b0; + st1_rtab_mshr_full_o = 1'b0; + st1_rtab_mshr_ready_o = 1'b0; + st1_rtab_wbuf_hit_o = 1'b0; + st1_rtab_wbuf_not_ready_o = 1'b0; + + evt_cache_write_miss_o = 1'b0; + evt_cache_read_miss_o = 1'b0; + evt_uncached_req_o = 1'b0; + evt_cmo_req_o = 1'b0; + evt_write_req_o = 1'b0; + evt_read_req_o = 1'b0; + evt_prefetch_req_o = 1'b0; + evt_stall_refill_o = 1'b0; + + // Wait for the cache to be initialized + // {{{ + if (!cachedir_init_ready_i) begin + // initialization of the cache RAMs + end + // }}} + + // Refilling the cache + // {{{ + else if (refill_busy_i) begin + // miss handler has the control of the cache + evt_stall_refill_o = arb_st0_req_valid_i; + end + // }}} + + // Normal pipeline operation + // {{{ + else begin + // Stage 2 request pending + // {{{ + if (st2_req_valid_i) begin + st2_req_valid_o = 1'b0; + + // Allocate an entry in the MSHR + st2_req_mshr_alloc_cs_o = 1'b1; + st2_req_mshr_alloc_o = 1'b1; + + // Introduce a NOP in the next cycle to prevent a hazard on the MSHR + st2_nop = 1'b1; + + // Performance event + evt_cache_read_miss_o = ~st2_req_is_prefetch_i; + evt_read_req_o = ~st2_req_is_prefetch_i; + evt_prefetch_req_o = st2_req_is_prefetch_i; + end + // }}} + + // Stage 1 request pending + // {{{ + if (st1_req_valid_i) begin + // Check if the request in stage 1 has a conflict with one of the + // request in the replay table. + rtab_check_o = ~st1_req_rtab_i & ~st1_fence; + + // Check if the current request is aborted. If so, respond to the + // core (when need_rsp is set) and set the aborted flag + if (st1_req_abort_i && !st1_req_rtab_i) begin + st1_rsp_valid_o = st1_req_need_rsp_i; + st1_rsp_aborted_o = 1'b1; + end + + // Allocate a new entry in the replay table in case of conflict with + // an on-hold request + else if (rtab_check_o && rtab_check_hit_i) begin + st1_rtab_alloc_and_link = 1'b1; + + // Do not consume a request in this cycle in stage 0 + st1_nop = 1'b1; + end + + // CMO fence or invalidate + // {{{ + else if (st1_req_is_cmo_fence_i || st1_req_is_cmo_inval_i) begin + cmo_req_valid_o = 1'b1; + st1_nop = 1'b1; + + // Performance event + evt_cmo_req_o = 1'b1; + end + // }}} + + // Uncacheable load, store or AMO request + // {{{ + else if (st1_req_is_uncacheable_i) begin + uc_req_valid_o = 1'b1; + st1_nop = 1'b1; + + // Performance event + evt_uncached_req_o = 1'b1; + end + // }}} + + // Cacheable request + // {{{ + else begin + // AMO cacheable request + // {{{ + if (st1_req_is_amo_i) begin + uc_req_valid_o = 1'b1; + st1_nop = 1'b1; + + // Performance event + evt_uncached_req_o = 1'b1; + end + // }}} + + // Load cacheable request + // {{{ + if (|{st1_req_is_load_i, + st1_req_is_cmo_prefetch_i}) + begin + // Cache miss + // {{{ + if (!cachedir_hit_i) begin + // If there is a match in the write buffer, lets send the + // entry right away + wbuf_read_flush_hit_o = 1'b1; + + // Do not consume a request in this cycle in stage 0 + st1_nop = 1'b1; + + // Pending miss on the same line + if (mshr_hit_i) begin + // Put the request in the replay table + st1_rtab_alloc = 1'b1; + + st1_rtab_mshr_hit_o = 1'b1; + end + + // No available slot in the MSHR + else if (mshr_full_i) begin + // Put the request in the replay table + st1_rtab_alloc = 1'b1; + + st1_rtab_mshr_full_o = 1'b1; + end + + // Hit on an open entry of the write buffer: + // wait for the entry to be acknowledged + else if (wbuf_read_hit_i) begin + // Put the request in the replay table + st1_rtab_alloc = 1'b1; + + st1_rtab_wbuf_hit_o = 1'b1; + end + + // Miss Handler is not ready to send + else if (!mshr_alloc_ready_i) begin + // Put the request on hold if the MISS HANDLER is not + // ready to send a new miss request. This is to prevent + // a deadlock between the read request channel and the + // read response channel. + // + // The request channel may be stalled by targets if they + // are not able to send a response (response is + // prioritary). Therefore, we need to put the request on + // hold to allow a possible refill read response to be + // accomplished. + st1_rtab_alloc = 1'b1; + + st1_rtab_mshr_ready_o = 1'b1; + end + + // Forward the request to the next stage to allocate the + // entry in the MSHR and send the refill request + else begin + // If the request comes from the replay table, free the + // corresponding RTAB entry + st1_rtab_commit_o = st1_req_rtab_i; + + st2_req_valid_o = 1'b1; + st2_req_we_o = 1'b1; + st2_req_is_prefetch_o = st1_req_is_cmo_prefetch_i; + end + end + // }}} + + // Cache hit + // {{{ + else begin + // If the request comes from the replay table, free the + // corresponding RTAB entry + st1_rtab_commit_o = st1_req_rtab_i; + + // Add a NOP when replaying a request, and there is no available + // request from the replay table. + st1_nop = st1_req_rtab_i & ~rtab_sel_o; + + // Update the PLRU bit for the accessed set + st1_req_cachedir_updt_lru_o = st1_req_is_load_i; + + // Respond to the core (if needed) + st1_rsp_valid_o = st1_req_need_rsp_i; + + // Performance event + evt_read_req_o = ~st1_req_is_cmo_prefetch_i; + evt_prefetch_req_o = st1_req_is_cmo_prefetch_i; + end + // }}} + end + // }}} + + // Store cacheable request + // {{{ + if (st1_req_is_store_i) begin + // Write in the write buffer if there is no pending miss in the same line. + // + // We assume here that the NoC that transports read and write transactions does + // not guaranty the order between transactions on those channels. + // Therefore, the cache must hold a write if there is a pending read on the + // same address. + wbuf_write_valid_o = ~mshr_hit_i; + + // Add a NOP in the pipeline when: + // - Structural hazard on the cache data if the st0 request is a load + // operation. + // - Replaying a request, the cache cannot accept a request from the + // core the next cycle. It can however accept a new request from the + // replay table + // + // IMPORTANT: we could remove the NOP in the first scenario if the + // controller checks for the hit of this write. However, this adds + // a DIR_RAM -> DATA_RAM timing path. + st1_nop = (arb_st0_req_valid_i & st0_req_is_load_i) | + (st1_req_rtab_i & ~rtab_sel_o); + + // Enable the data RAM in case of write. However, the actual write + // depends on the hit signal from the cache directory. + // + // IMPORTANT: this produces unnecessary power consumption in case of + // write misses, but removes timing paths between the cache directory + // RAM and the data RAM chip-select. + st1_req_cachedata_write_o = 1'b1; + + // Cache miss + if (!cachedir_hit_i) begin + // Pending miss on the same line + if (mshr_hit_i) begin + // Put the request in the replay table + st1_rtab_alloc = 1'b1; + + st1_rtab_mshr_hit_o = 1'b1; + + // Do not consume a request in this cycle in stage 0 + st1_nop = 1'b1; + end + + // No available entry in the write buffer (or conflict on pending entry) + else if (!wbuf_write_ready_i) begin + // Put the request in the replay table + st1_rtab_alloc = 1'b1; + + st1_rtab_wbuf_not_ready_o = 1'b1; + + // Do not consume a request in this cycle in stage 0 + st1_nop = 1'b1; + end + + else begin + // If the request comes from the replay table, free the + // corresponding RTAB entry + st1_rtab_commit_o = st1_req_rtab_i; + + // Respond to the core (if needed) + st1_rsp_valid_o = st1_req_need_rsp_i; + + // Performance event + evt_cache_write_miss_o = 1'b1; + evt_write_req_o = 1'b1; + end + end + + // Cache hit + else begin + // No available entry in the write buffer (or conflict on pending entry) + if (!wbuf_write_ready_i) begin + // Put the request in the replay table + st1_rtab_alloc = 1'b1; + + st1_rtab_wbuf_not_ready_o = 1'b1; + + // Do not consume a request in this cycle in stage 0 + st1_nop = 1'b1; + end + + // The store can be performed in the write buffer and in the cache + else begin + // If the request comes from the replay table, free the + // corresponding RTAB entry + st1_rtab_commit_o = st1_req_rtab_i; + + // Respond to the core + st1_rsp_valid_o = st1_req_need_rsp_i; + + // Update the PLRU bit for the accessed set + st1_req_cachedir_updt_lru_o = 1'b1; + + // Write in the data RAM + st1_req_cachedata_write_enable_o = 1'b1; + + // Performance event + evt_write_req_o = 1'b1; + end + end + end + // }}} + end + // }}} + end + // }}} + + // New request + // {{{ + nop = st1_nop | st2_nop; + + // The cache controller accepts a core request when: + // - The req-refill arbiter grants the request + // - The pipeline is not being flushed + arb_st0_req_ready_o = arb_st0_req_valid_i & ~nop; + + // The cache controller accepts a refill when: + // - The req-refill arbiter grants the refill + // - The pipeline is empty + arb_refill_ready_o = arb_refill_valid_i & ~(st1_req_valid_i | st2_req_valid_i); + + // Forward the request to stage 1 + // - There is a valid request in stage 0 + st1_req_valid_o = arb_st0_req_ready_o; + + // New cacheable stage 0 request granted + // {{{ + // IMPORTANT: here the RAM is enabled independently if the + // request needs to be put on-hold. + // This increases the power consumption in that cases, but + // removes the timing paths RAM-to-RAM between the cache + // directory and the data array. + if (arb_st0_req_valid_i && !st0_req_is_uncacheable_i) begin + st0_req_cachedata_read_o = + st0_req_is_load_i & + ~(st1_req_valid_i & st1_req_is_store_i & ~st1_req_is_uncacheable_i); + if (st0_req_is_load_i | + st0_req_is_cmo_prefetch_i | + st0_req_is_store_i | + st0_req_is_amo_i ) + begin + st0_req_mshr_check_o = 1'b1; + st0_req_cachedir_read_o = ~st0_req_is_amo_i; + end + end + // }}} + // }}} + end + // }}} end of normal pipeline operation + end + // }}} +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_memarray.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_memarray.sv new file mode 100644 index 00000000000..7c7ee6597ce --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_memarray.sv @@ -0,0 +1,120 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : HPDcache Directory and Data Memory Arrays + * History : + */ +module hpdcache_memarray +import hpdcache_pkg::*; + // Ports + // {{{ +( + input logic clk_i, + input logic rst_ni, + + input hpdcache_dir_addr_t dir_addr_i, + input hpdcache_way_vector_t dir_cs_i, + input hpdcache_way_vector_t dir_we_i, + input hpdcache_dir_entry_t [HPDCACHE_WAYS-1:0] dir_wentry_i, + output hpdcache_dir_entry_t [HPDCACHE_WAYS-1:0] dir_rentry_o, + + input hpdcache_data_addr_t data_addr_i, + input hpdcache_data_enable_t data_cs_i, + input hpdcache_data_enable_t data_we_i, + input hpdcache_data_be_entry_t data_wbyteenable_i, + input hpdcache_data_entry_t data_wentry_i, + output hpdcache_data_entry_t data_rentry_o +); + // }}} + + // Memory arrays + // {{{ + generate + genvar x, y, dir_w; + + // Directory + // + for (dir_w = 0; dir_w < int'(HPDCACHE_WAYS); dir_w++) begin : dir_sram_gen + hpdcache_sram #( + .DATA_SIZE (HPDCACHE_DIR_RAM_WIDTH), + .ADDR_SIZE (HPDCACHE_DIR_RAM_ADDR_WIDTH) + ) dir_sram ( + .clk (clk_i), + .rst_n (rst_ni), + .cs (dir_cs_i[dir_w]), + .we (dir_we_i[dir_w]), + .addr (dir_addr_i), + .wdata (dir_wentry_i[dir_w]), + .rdata (dir_rentry_o[dir_w]) + ); + end + + // Data + // + for (y = 0; y < int'(HPDCACHE_DATA_RAM_Y_CUTS); y++) begin : data_sram_row_gen + for (x = 0; x < int'(HPDCACHE_DATA_RAM_X_CUTS); x++) begin : data_sram_col_gen + if (HPDCACHE_DATA_RAM_WBYTEENABLE) begin : data_sram_wbyteenable_gen + hpdcache_sram_wbyteenable #( + .DATA_SIZE (HPDCACHE_DATA_RAM_WIDTH), + .ADDR_SIZE (HPDCACHE_DATA_RAM_ADDR_WIDTH) + ) data_sram ( + .clk (clk_i), + .rst_n (rst_ni), + .cs (data_cs_i[y][x]), + .we (data_we_i[y][x]), + .addr (data_addr_i[y][x]), + .wdata (data_wentry_i[y][x]), + .wbyteenable (data_wbyteenable_i[y][x]), + .rdata (data_rentry_o[y][x]) + ); + end else begin : data_sram_wmask_gen + hpdcache_data_ram_data_t data_wmask; + + // build the bitmask from the write byte enable signal + always_comb + begin : data_wmask_comb + for (int w = 0; w < HPDCACHE_DATA_WAYS_PER_RAM_WORD; w++) begin + for (int b = 0; b < HPDCACHE_WORD_WIDTH/8; b++) begin + data_wmask[w][8*b +: 8] = {8{data_wbyteenable_i[y][x][w][b]}}; + end + end + end + + hpdcache_sram_wmask #( + .DATA_SIZE (HPDCACHE_DATA_RAM_WIDTH), + .ADDR_SIZE (HPDCACHE_DATA_RAM_ADDR_WIDTH) + ) data_sram ( + .clk (clk_i), + .rst_n (rst_ni), + .cs (data_cs_i[y][x]), + .we (data_we_i[y][x]), + .addr (data_addr_i[y][x]), + .wdata (data_wentry_i[y][x]), + .wmask (data_wmask), + .rdata (data_rentry_o[y][x]) + ); + end + end + end + endgenerate + // }}} +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_memctrl.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_memctrl.sv new file mode 100644 index 00000000000..e0949a2365f --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_memctrl.sv @@ -0,0 +1,656 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : HPDcache Directory and Data Memory RAMs Controller + * History : + */ +module hpdcache_memctrl +import hpdcache_pkg::*; + // Ports + // {{{ +( + // Global clock and reset signals + // {{{ + input logic clk_i, + input logic rst_ni, + // }}} + + // Global control signals + // {{{ + output logic ready_o, + // }}} + + // DIR array access interface + // {{{ + input logic dir_match_i, + input hpdcache_set_t dir_match_set_i, + input hpdcache_tag_t dir_match_tag_i, + input logic dir_update_lru_i, + output hpdcache_way_vector_t dir_hit_way_o, + + input logic dir_amo_match_i, + input hpdcache_set_t dir_amo_match_set_i, + input hpdcache_tag_t dir_amo_match_tag_i, + input logic dir_amo_update_plru_i, + output hpdcache_way_vector_t dir_amo_hit_way_o, + + input logic dir_refill_i, + input hpdcache_set_t dir_refill_set_i, + input hpdcache_dir_entry_t dir_refill_entry_i, + input logic dir_refill_updt_plru_i, + output hpdcache_way_vector_t dir_victim_way_o, + + input logic dir_cmo_check_i, + input hpdcache_set_t dir_cmo_check_set_i, + input hpdcache_tag_t dir_cmo_check_tag_i, + output hpdcache_way_vector_t dir_cmo_check_hit_way_o, + + input logic dir_cmo_inval_i, + input hpdcache_set_t dir_cmo_inval_set_i, + input hpdcache_way_vector_t dir_cmo_inval_way_i, + + // }}} + + // DATA array access interface + // {{{ + input logic data_req_read_i, + input hpdcache_set_t data_req_read_set_i, + input hpdcache_req_size_t data_req_read_size_i, + input hpdcache_word_t data_req_read_word_i, + output hpdcache_req_data_t data_req_read_data_o, + + input logic data_req_write_i, + input logic data_req_write_enable_i, + input hpdcache_set_t data_req_write_set_i, + input hpdcache_req_size_t data_req_write_size_i, + input hpdcache_word_t data_req_write_word_i, + input hpdcache_req_data_t data_req_write_data_i, + input hpdcache_req_be_t data_req_write_be_i, + + input logic data_amo_write_i, + input logic data_amo_write_enable_i, + input hpdcache_set_t data_amo_write_set_i, + input hpdcache_req_size_t data_amo_write_size_i, + input hpdcache_word_t data_amo_write_word_i, + input logic [63:0] data_amo_write_data_i, + input logic [7:0] data_amo_write_be_i, + + input logic data_refill_i, + input hpdcache_way_vector_t data_refill_way_i, + input hpdcache_set_t data_refill_set_i, + input hpdcache_word_t data_refill_word_i, + input hpdcache_refill_data_t data_refill_data_i + // }}} +); + // }}} + + // Definition of constants + // {{{ + localparam int unsigned HPDCACHE_ALL_CUTS = HPDCACHE_DATA_RAM_X_CUTS*HPDCACHE_DATA_RAM_Y_CUTS; + localparam int unsigned HPDCACHE_DATA_REQ_RATIO = HPDCACHE_ACCESS_WORDS/HPDCACHE_REQ_WORDS; + // }}} + + // Definition of functions + // {{{ + + // hpdcache_compute_data_ram_cs + // + // description: This function computes the chip-select signal for data + // RAMs depending on the request size and the word offset + function automatic hpdcache_data_row_enable_t hpdcache_compute_data_ram_cs( + input hpdcache_req_size_t size_i, + input hpdcache_word_t word_i); + + localparam hpdcache_uint32 off_width = + HPDCACHE_ACCESS_WORDS > 1 ? $clog2(HPDCACHE_ACCESS_WORDS) : 1; + + hpdcache_data_row_enable_t ret; + hpdcache_uint32 off; + + case (size_i) + 3'h0, + 3'h1, + 3'h2, + 3'h3: ret = hpdcache_data_row_enable_t'({ 64/HPDCACHE_WORD_WIDTH{1'b1}}); + 3'h4: ret = hpdcache_data_row_enable_t'({128/HPDCACHE_WORD_WIDTH{1'b1}}); + 3'h5: ret = hpdcache_data_row_enable_t'({256/HPDCACHE_WORD_WIDTH{1'b1}}); + default: ret = hpdcache_data_row_enable_t'({512/HPDCACHE_WORD_WIDTH{1'b1}}); + endcase + + off = HPDCACHE_ACCESS_WORDS > 1 ? hpdcache_uint'(word_i[0 +: off_width]) : 0; + return hpdcache_data_row_enable_t'(ret << off); + endfunction + + function automatic hpdcache_data_ram_row_idx_t hpdcache_way_to_data_ram_row( + input hpdcache_way_vector_t way); + for (hpdcache_uint i = 0; i < HPDCACHE_WAYS; i++) begin + if (way[i]) return hpdcache_data_ram_row_idx_t'(i / HPDCACHE_DATA_WAYS_PER_RAM_WORD); + end + return 0; + endfunction + + function automatic hpdcache_data_ram_way_idx_t hpdcache_way_to_data_ram_word( + input hpdcache_way_vector_t way); + for (hpdcache_uint i = 0; i < HPDCACHE_WAYS; i++) begin + if (way[i]) return hpdcache_data_ram_way_idx_t'(i % HPDCACHE_DATA_WAYS_PER_RAM_WORD); + end + return 0; + endfunction + + function automatic hpdcache_data_ram_addr_t hpdcache_set_to_data_ram_addr( + input hpdcache_set_t set, + input hpdcache_word_t word); + hpdcache_uint ret; + + ret = (hpdcache_uint'(set)*(HPDCACHE_CL_WORDS / HPDCACHE_ACCESS_WORDS)) + + (hpdcache_uint'(word) / HPDCACHE_ACCESS_WORDS); + + return hpdcache_data_ram_addr_t'(ret); + endfunction + // }}} + + // Definition of internal signals and registers + // {{{ + genvar gen_i, gen_j, gen_k; + + // Directory initialization signals and registers + logic init_q, init_d; + hpdcache_dir_addr_t init_set_q, init_set_d; + hpdcache_way_vector_t init_dir_cs; + hpdcache_way_vector_t init_dir_we; + hpdcache_dir_entry_t init_dir_wentry; + + // Directory valid bit vector (one bit per set and way) + hpdcache_way_vector_t [HPDCACHE_SETS-1:0] dir_valid_q, dir_valid_d; + hpdcache_set_t dir_req_set_q, dir_req_set_d; + hpdcache_dir_addr_t dir_addr; + hpdcache_way_vector_t dir_cs; + hpdcache_way_vector_t dir_we; + hpdcache_dir_entry_t [HPDCACHE_WAYS-1:0] dir_wentry; + hpdcache_dir_entry_t [HPDCACHE_WAYS-1:0] dir_rentry; + + hpdcache_data_addr_t data_addr; + hpdcache_data_enable_t data_cs; + hpdcache_data_enable_t data_we; + hpdcache_data_be_entry_t data_wbyteenable; + hpdcache_data_entry_t data_wentry; + hpdcache_data_entry_t data_rentry; + + logic data_write; + logic data_write_enable; + hpdcache_set_t data_write_set; + hpdcache_req_size_t data_write_size; + hpdcache_word_t data_write_word; + hpdcache_refill_data_t data_write_data; + hpdcache_refill_be_t data_write_be; + + hpdcache_refill_data_t data_req_write_data; + hpdcache_refill_be_t data_req_write_be; + + hpdcache_refill_data_t data_amo_write_data; + hpdcache_refill_be_t data_amo_write_be; + + hpdcache_way_vector_t data_way; + + hpdcache_data_ram_row_idx_t data_ram_row; + hpdcache_data_ram_way_idx_t data_ram_word; + + // }}} + + // Init FSM + // {{{ + always_comb + begin : init_comb + init_dir_wentry.tag = '0; + init_dir_wentry.reserved = '0; + init_dir_cs = '0; + init_dir_we = '0; + init_d = init_q; + init_set_d = init_set_q; + + case (init_q) + 1'b0: begin + init_d = (hpdcache_uint'(init_set_q) == (HPDCACHE_SETS - 1)); + init_set_d = init_set_q + 1; + init_dir_cs = '1; + init_dir_we = '1; + end + + 1'b1: begin + init_d = 1'b1; + init_set_d = init_set_q; + end + endcase + end + + assign ready_o = init_q; + + always_ff @(posedge clk_i or negedge rst_ni) + begin : init_ff + if (!rst_ni) begin + init_q <= 1'b0; + init_set_q <= 0; + dir_valid_q <= '0; + end else begin + init_q <= init_d; + init_set_q <= init_set_d; + dir_valid_q <= dir_valid_d; + end + end + // }}} + + // Memory arrays + // {{{ + hpdcache_memarray hpdcache_memarray_i( + .clk_i, + .rst_ni, + + .dir_addr_i (dir_addr), + .dir_cs_i (dir_cs), + .dir_we_i (dir_we), + .dir_wentry_i (dir_wentry), + .dir_rentry_o (dir_rentry), + + .data_addr_i (data_addr), + .data_cs_i (data_cs), + .data_we_i (data_we), + .data_wbyteenable_i (data_wbyteenable), + .data_wentry_i (data_wentry), + .data_rentry_o (data_rentry) + ); + // }}} + + // Directory RAM request mux + // {{{ + always_comb + begin : dir_ctrl_comb + case (1'b1) + // Cache directory initialization + ~init_q: begin + dir_addr = init_set_q; + dir_cs = init_dir_cs; + dir_we = init_dir_we; + dir_wentry = {HPDCACHE_WAYS{init_dir_wentry}}; + end + + // Cache directory match tag -> hit + dir_match_i: begin + dir_addr = dir_match_set_i; + dir_cs = '1; + dir_we = '0; + dir_wentry = '0; + end + + // Cache directory AMO match tag -> hit + dir_amo_match_i: begin + dir_addr = dir_amo_match_set_i; + dir_cs = '1; + dir_we = '0; + dir_wentry = '0; + end + + // Cache directory update + dir_refill_i: begin + dir_addr = dir_refill_set_i; + dir_cs = dir_victim_way_o; + dir_we = dir_victim_way_o; + dir_wentry = {HPDCACHE_WAYS{dir_refill_entry_i}}; + end + + // Cache directory CMO match tag + dir_cmo_check_i: begin + dir_addr = dir_cmo_check_set_i; + dir_cs = '1; + dir_we = '0; + dir_wentry = '0; + end + + // Do nothing + default: begin + dir_addr = '0; + dir_cs = '0; + dir_we = '0; + dir_wentry = '0; + end + endcase + end + // }}} + + // Directory valid logic + // {{{ + always_comb + begin : dir_valid_comb + dir_valid_d = dir_valid_q; + + unique case (1'b1) + // Refill the cache after a miss + dir_refill_i: begin + dir_valid_d[dir_refill_set_i] = dir_valid_q[dir_refill_set_i] | dir_victim_way_o; + end + // CMO invalidate a set + dir_cmo_inval_i: begin + dir_valid_d[dir_cmo_inval_set_i] = dir_valid_q[dir_cmo_inval_set_i] & ~dir_cmo_inval_way_i; + end + default: begin + // do nothing + end + endcase + end + // }}} + + // Directory hit logic + // {{{ + assign dir_req_set_d = dir_match_i ? dir_match_set_i : + dir_amo_match_i ? dir_amo_match_set_i : + dir_cmo_check_i ? dir_cmo_check_set_i : + dir_req_set_q ; + + generate + hpdcache_way_vector_t req_hit; + hpdcache_way_vector_t amo_hit; + hpdcache_way_vector_t cmo_hit; + + for (gen_i = 0; gen_i < int'(HPDCACHE_WAYS); gen_i++) + begin : dir_match_tag_gen + assign req_hit[gen_i] = (dir_rentry[gen_i].tag == dir_match_tag_i), + amo_hit[gen_i] = (dir_rentry[gen_i].tag == dir_amo_match_tag_i), + cmo_hit[gen_i] = (dir_rentry[gen_i].tag == dir_cmo_check_tag_i); + + assign dir_hit_way_o [gen_i] = dir_valid_q[dir_req_set_q][gen_i] & req_hit[gen_i], + dir_amo_hit_way_o [gen_i] = dir_valid_q[dir_req_set_q][gen_i] & amo_hit[gen_i], + dir_cmo_check_hit_way_o[gen_i] = dir_valid_q[dir_req_set_q][gen_i] & cmo_hit[gen_i]; + end + endgenerate + // }}} + + // Directory victim select logic + // {{{ + logic plru_updt; + hpdcache_way_vector_t plru_updt_way; + + assign plru_updt = dir_update_lru_i | dir_amo_update_plru_i, + plru_updt_way = dir_update_lru_i ? dir_hit_way_o : dir_amo_hit_way_o; + + hpdcache_plru #( + .SETS (HPDCACHE_SETS), + .WAYS (HPDCACHE_WAYS) + ) plru_i ( + .clk_i, + .rst_ni, + + .updt_i (plru_updt), + .updt_set_i (dir_req_set_q), + .updt_way_i (plru_updt_way), + + .repl_i (dir_refill_i), + .repl_set_i (dir_refill_set_i), + .repl_dir_valid_i (dir_valid_q[dir_refill_set_i]), + .repl_updt_plru_i (dir_refill_updt_plru_i), + + .victim_way_o (dir_victim_way_o) + ); + // }}} + + // Data RAM request multiplexor + // {{{ + + // Upsize the request interface to match the maximum access width of the data RAM + generate + if (HPDCACHE_DATA_REQ_RATIO > 1) begin : upsize_data_req_write_gen + // demux request DATA + assign data_req_write_data = {HPDCACHE_DATA_REQ_RATIO{data_req_write_data_i}}; + + // demux request BE + hpdcache_demux #( + .NOUTPUT (HPDCACHE_DATA_REQ_RATIO), + .DATA_WIDTH (HPDCACHE_REQ_DATA_WIDTH/8), + .ONE_HOT_SEL (1'b0) + ) data_req_write_be_demux_i ( + .data_i (data_req_write_be_i), + .sel_i (data_req_write_word_i[HPDCACHE_REQ_WORD_INDEX_WIDTH +: + $clog2(HPDCACHE_DATA_REQ_RATIO)]), + .data_o (data_req_write_be) + ); + end else begin + assign data_req_write_data = data_req_write_data_i, + data_req_write_be = data_req_write_be_i; + end + endgenerate + + // Upsize the AMO data interface to match the maximum access width of the data RAM + generate + localparam hpdcache_uint AMO_DATA_RATIO = HPDCACHE_DATA_RAM_ACCESS_WIDTH/64; + localparam hpdcache_uint AMO_DATA_INDEX_WIDTH = $clog2(AMO_DATA_RATIO); + + if (AMO_DATA_RATIO > 1) begin + assign data_amo_write_data = {AMO_DATA_RATIO{data_amo_write_data_i}}; + + hpdcache_demux #( + .NOUTPUT (AMO_DATA_RATIO), + .DATA_WIDTH (8), + .ONE_HOT_SEL (1'b0) + ) amo_be_demux_i ( + .data_i (data_amo_write_be_i), + .sel_i (data_amo_write_word_i[0 +: AMO_DATA_INDEX_WIDTH]), + .data_o (data_amo_write_be) + ); + end else begin + assign data_amo_write_data = data_amo_write_data_i, + data_amo_write_be = data_amo_write_be_i; + end + endgenerate + + // Multiplex between data write requests + always_comb + begin : data_write_comb + case (1'b1) + data_refill_i: begin + data_write = 1'b1; + data_write_enable = 1'b1; + data_write_set = data_refill_set_i; + data_write_size = hpdcache_req_size_t'($clog2(HPDCACHE_DATA_RAM_ACCESS_WIDTH/8)); + data_write_word = data_refill_word_i; + data_write_data = data_refill_data_i; + data_write_be = '1; + end + + data_req_write_i: begin + data_write = 1'b1; + data_write_enable = data_req_write_enable_i; + data_write_set = data_req_write_set_i; + data_write_size = data_req_write_size_i; + data_write_word = data_req_write_word_i; + data_write_data = data_req_write_data; + data_write_be = data_req_write_be; + end + + data_amo_write_i: begin + data_write = 1'b1; + data_write_enable = data_amo_write_enable_i; + data_write_set = data_amo_write_set_i; + data_write_size = data_amo_write_size_i; + data_write_word = data_amo_write_word_i; + data_write_data = data_amo_write_data; + data_write_be = data_amo_write_be; + end + + default: begin + data_write = 1'b0; + data_write_enable = 1'b0; + data_write_set = '0; + data_write_size = '0; + data_write_word = '0; + data_write_data = '0; + data_write_be = '0; + end + endcase + end + + // Multiplex between read and write access on the data RAM + assign data_way = data_refill_i ? data_refill_way_i : + data_amo_write_i ? dir_amo_hit_way_o : + dir_hit_way_o; + + // Decode way index + assign data_ram_word = hpdcache_way_to_data_ram_word(data_way), + data_ram_row = hpdcache_way_to_data_ram_row(data_way); + + always_comb + begin : data_ctrl_comb + case (1'b1) + // Select data read inputs + data_req_read_i: begin + data_addr = {HPDCACHE_ALL_CUTS{hpdcache_set_to_data_ram_addr(data_req_read_set_i, + data_req_read_word_i)}}; + + data_we = '0; + data_wbyteenable = '0; + data_wentry = '0; + for (int unsigned i = 0; i < HPDCACHE_DATA_RAM_Y_CUTS; i++) begin + data_cs[i] = hpdcache_compute_data_ram_cs(data_req_read_size_i, + data_req_read_word_i); + end + end + + // Select data write inputs + data_write: begin + data_addr = {HPDCACHE_ALL_CUTS{hpdcache_set_to_data_ram_addr(data_write_set, + data_write_word)}}; + + for (int unsigned i = 0; i < HPDCACHE_DATA_RAM_Y_CUTS; i++) begin + for (int unsigned j = 0; j < HPDCACHE_DATA_RAM_X_CUTS; j++) begin + data_wentry[i][j] = {HPDCACHE_DATA_WAYS_PER_RAM_WORD{data_write_data[j]}}; + end + end + + for (int unsigned i = 0; i < HPDCACHE_DATA_RAM_Y_CUTS; i++) begin + data_cs[i] = hpdcache_compute_data_ram_cs(data_write_size, data_write_word); + + if (i == hpdcache_uint'(data_ram_row)) begin + data_we[i] = data_write_enable ? data_cs[i] : '0; + end else begin + data_we[i] = '0; + end + + // Build the write mask + for (int unsigned j = 0; j < HPDCACHE_ACCESS_WORDS; j++) begin + for (int unsigned k = 0; k < HPDCACHE_DATA_WAYS_PER_RAM_WORD; k++) begin + data_wbyteenable[i][j][k] = (k == hpdcache_uint'(data_ram_word)) ? + data_write_be[j] : '0; + end + end + end + end + + // Do nothing + default: begin + data_addr = '0; + data_cs = '0; + data_we = '0; + data_wbyteenable = '0; + data_wentry = '0; + end + endcase + end + // }}} + + // Data RAM read data multiplexor + // {{{ + generate + hpdcache_req_data_t [HPDCACHE_DATA_REQ_RATIO-1:0][HPDCACHE_WAYS-1:0] data_read_words; + hpdcache_req_data_t [HPDCACHE_WAYS-1:0] data_read_req_word; + + // Organize the read data by words (all ways for the same word are contiguous) + for (gen_i = 0; gen_i < int'(HPDCACHE_DATA_REQ_RATIO); gen_i++) begin + for (gen_j = 0; gen_j < int'(HPDCACHE_WAYS); gen_j++) begin + for (gen_k = 0; gen_k < int'(HPDCACHE_REQ_WORDS); gen_k++) begin + assign data_read_words[gen_i][gen_j][gen_k] = + data_rentry[(gen_j / HPDCACHE_DATA_WAYS_PER_RAM_WORD)] + [(gen_i * HPDCACHE_REQ_WORDS ) + gen_k] + [(gen_j % HPDCACHE_DATA_WAYS_PER_RAM_WORD)]; + end + end + end + + // Mux the data according to the access word + if (HPDCACHE_DATA_REQ_RATIO > 1) begin : req_width_lt_ram_width + typedef logic [$clog2(HPDCACHE_DATA_REQ_RATIO)-1:0] data_req_word_t; + data_req_word_t data_read_req_word_index_q; + + hpdcache_mux #( + .NINPUT (HPDCACHE_DATA_REQ_RATIO), + .DATA_WIDTH (HPDCACHE_REQ_DATA_WIDTH*HPDCACHE_WAYS) + ) data_read_req_word_mux_i( + .data_i (data_read_words), + .sel_i (data_read_req_word_index_q), + .data_o (data_read_req_word) + ); + + always_ff @(posedge clk_i) + begin : data_req_read_word_ff + data_read_req_word_index_q <= + data_req_read_word_i[HPDCACHE_REQ_WORD_INDEX_WIDTH +: + $clog2(HPDCACHE_DATA_REQ_RATIO)]; + end + end + + // Request data interface width is equal to the data RAM width + else begin : req_width_eq_ram_width + assign data_read_req_word = data_read_words; + end + + // Mux the data according to the hit way + hpdcache_mux #( + .NINPUT (HPDCACHE_WAYS), + .DATA_WIDTH (HPDCACHE_REQ_DATA_WIDTH), + .ONE_HOT_SEL (1'b1) + ) data_read_req_word_way_mux_i( + .data_i (data_read_req_word), + .sel_i (dir_hit_way_o), + .data_o (data_req_read_data_o) + ); + endgenerate + + + // Delay the accessed set for checking the tag from the directory in the + // next cycle (hit logic) + always_ff @(posedge clk_i) + begin : req_read_ff + if (dir_match_i || dir_amo_match_i || dir_cmo_check_i) begin + dir_req_set_q <= dir_req_set_d; + end + end + // }}} + + // Assertions + // {{{ + // pragma translate_off + concurrent_dir_access_assert: assert property (@(posedge clk_i) + $onehot0({dir_match_i, dir_amo_match_i, dir_cmo_check_i, dir_refill_i})) else + $error("hpdcache_memctrl: more than one process is accessing the cache directory"); + + concurrent_data_access_assert: assert property (@(posedge clk_i) + $onehot0({data_req_read_i, data_req_write_i, data_amo_write_i, data_refill_i})) else + $error("hpdcache_memctrl: more than one process is accessing the cache data"); + // pragma translate_on + // }}} +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_miss_handler.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_miss_handler.sv new file mode 100644 index 00000000000..cec5750dfdd --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_miss_handler.sv @@ -0,0 +1,673 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : HPDcache Miss Handler + * History : + */ +/* Possible improvements + * ===================== + * TODO Allow pipelining of the refilling operation. + * The pipelining would be as follows: + * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | + * | MSHR | WDATLO | WDATHI | | | | | + * | | NOP | MSHR | WDATLO | WDATHI | | | + * | | NOP | NOP | NOP | MSHR | WDATLO | WDATHI | + * + * This allows to handle 1 refill every 2 cycles. Otherwise, current implementation handles + * 1 refill every 3 cycles. + */ +module hpdcache_miss_handler +// {{{ +import hpdcache_pkg::*; +// Parameters +// {{{ +#( + parameter int HPDcacheMemIdWidth = 8, + parameter int HPDcacheMemDataWidth = 512, + parameter type hpdcache_mem_req_t = logic, + parameter type hpdcache_mem_resp_r_t = logic, + localparam type hpdcache_mem_id_t = logic [HPDcacheMemIdWidth-1:0] +) +// }}} +// Ports +// {{{ +( + input logic clk_i, + input logic rst_ni, + + // Global control signals + // {{{ + output logic mshr_empty_o, + output logic mshr_full_o, + // }}} + + // Configuration signals + // {{{ + input logic cfg_prefetch_updt_plru_i, + // }}} + + // CHECK interface + // {{{ + input logic mshr_check_i, + input mshr_set_t mshr_check_set_i, + input mshr_tag_t mshr_check_tag_i, + output logic mshr_check_hit_o, + // }}} + + // MISS interface + // {{{ + // MISS request interface + output logic mshr_alloc_ready_o, + input logic mshr_alloc_i, + input logic mshr_alloc_cs_i, + input hpdcache_nline_t mshr_alloc_nline_i, + output logic mshr_alloc_full_o, + input hpdcache_req_tid_t mshr_alloc_tid_i, + input hpdcache_req_sid_t mshr_alloc_sid_i, + input hpdcache_word_t mshr_alloc_word_i, + input logic mshr_alloc_need_rsp_i, + input logic mshr_alloc_is_prefetch_i, + + // REFILL MISS interface + input logic refill_req_ready_i, + output logic refill_req_valid_o, + output logic refill_busy_o, + output logic refill_updt_plru_o, + output hpdcache_set_t refill_set_o, + output hpdcache_dir_entry_t refill_dir_entry_o, + input hpdcache_way_vector_t refill_victim_way_i, + output logic refill_write_dir_o, + output logic refill_write_data_o, + output hpdcache_way_vector_t refill_victim_way_o, + output hpdcache_refill_data_t refill_data_o, + output hpdcache_word_t refill_word_o, + output hpdcache_nline_t refill_nline_o, + output logic refill_updt_rtab_o, + + // REFILL core response interface + output logic refill_core_rsp_valid_o, + output hpdcache_rsp_t refill_core_rsp_o, + // }}} + + // MEMORY interface + // {{{ + input logic mem_req_ready_i, + output logic mem_req_valid_o, + output hpdcache_mem_req_t mem_req_o, + + output logic mem_resp_ready_o, + input logic mem_resp_valid_i, + input hpdcache_mem_resp_r_t mem_resp_i + // }}} +); +// }}} + + // Declaration of constants and types + // {{{ + localparam int unsigned REFILL_REQ_RATIO = HPDCACHE_ACCESS_WORDS/HPDCACHE_REQ_WORDS; + + typedef enum logic { + MISS_REQ_IDLE = 1'b0, + MISS_REQ_SEND = 1'b1 + } miss_req_fsm_e; + + typedef enum { + REFILL_IDLE, + REFILL_WRITE, + REFILL_WRITE_DIR + } refill_fsm_e; + + typedef struct packed { + hpdcache_mem_error_e r_error; + hpdcache_mem_id_t r_id; + } mem_resp_metadata_t; + + function automatic mshr_set_t get_ack_mshr_set(hpdcache_mem_id_t id); + return id[0 +: HPDCACHE_MSHR_SET_WIDTH]; + endfunction + + function automatic mshr_way_t get_ack_mshr_way(hpdcache_mem_id_t id); + return id[HPDCACHE_MSHR_SET_WIDTH +: HPDCACHE_MSHR_WAY_WIDTH]; + endfunction + // }}} + + // Declaration of internal signals and registers + // {{{ + miss_req_fsm_e miss_req_fsm_q, miss_req_fsm_d; + mshr_way_t mshr_alloc_way_q, mshr_alloc_way_d; + mshr_set_t mshr_alloc_set_q, mshr_alloc_set_d; + mshr_tag_t mshr_alloc_tag_q, mshr_alloc_tag_d; + + refill_fsm_e refill_fsm_q, refill_fsm_d; + hpdcache_set_t refill_set_q; + hpdcache_tag_t refill_tag_q; + hpdcache_way_vector_t refill_way_q; + hpdcache_req_sid_t refill_sid_q; + hpdcache_req_tid_t refill_tid_q; + hpdcache_word_t refill_cnt_q, refill_cnt_d; + logic refill_need_rsp_q; + logic refill_is_prefetch_q; + hpdcache_word_t refill_core_rsp_word_q; + logic refill_way_bypass; + + mem_resp_metadata_t refill_fifo_resp_meta_wdata, refill_fifo_resp_meta_rdata; + logic refill_fifo_resp_meta_w, refill_fifo_resp_meta_wok; + logic refill_fifo_resp_meta_r, refill_fifo_resp_meta_rok; + + logic refill_fifo_resp_data_w, refill_fifo_resp_data_wok; + hpdcache_refill_data_t refill_fifo_resp_data_rdata; + logic refill_fifo_resp_data_r; + + hpdcache_req_sid_t refill_core_rsp_sid_q, refill_core_rsp_sid_d; + hpdcache_req_tid_t refill_core_rsp_tid_q, refill_core_rsp_tid_d; + hpdcache_req_data_t refill_core_rsp_data_q, refill_core_rsp_data_d; + logic refill_core_rsp_error_q, refill_core_rsp_error_d; + logic refill_core_rsp_valid_q, refill_core_rsp_valid_d; + hpdcache_word_t refill_core_rsp_word; + logic refill_core_rsp_valid; + + logic refill_is_error; + + logic mshr_alloc; + logic mshr_alloc_cs; + logic mshr_ack; + logic mshr_ack_cs; + mshr_set_t mshr_ack_set; + mshr_way_t mshr_ack_way; + hpdcache_nline_t mshr_ack_nline; + hpdcache_req_sid_t mshr_ack_src_id; + hpdcache_req_tid_t mshr_ack_req_id; + hpdcache_word_t mshr_ack_word; + logic mshr_ack_need_rsp; + logic mshr_ack_is_prefetch; + logic mshr_empty; + // }}} + + // Miss Request FSM + // {{{ + always_comb + begin : miss_req_fsm_comb + mshr_alloc_ready_o = 1'b0; + mshr_alloc = 1'b0; + mshr_alloc_cs = 1'b0; + mem_req_valid_o = 1'b0; + + miss_req_fsm_d = miss_req_fsm_q; + + case (miss_req_fsm_q) + MISS_REQ_IDLE: begin + mshr_alloc_ready_o = 1'b1; + mshr_alloc = mshr_alloc_i; + mshr_alloc_cs = mshr_alloc_cs_i; + if (mshr_alloc_i) begin + miss_req_fsm_d = MISS_REQ_SEND; + end else begin + miss_req_fsm_d = MISS_REQ_IDLE; + end + end + MISS_REQ_SEND: begin + mem_req_valid_o = 1'b1; + if (mem_req_ready_i) begin + miss_req_fsm_d = MISS_REQ_IDLE; + end else begin + miss_req_fsm_d = MISS_REQ_SEND; + end + end + endcase + end + + localparam hpdcache_uint REFILL_REQ_SIZE = $clog2(HPDcacheMemDataWidth/8); + localparam hpdcache_uint REFILL_REQ_LEN = HPDCACHE_CL_WIDTH/HPDcacheMemDataWidth; + + assign mem_req_o.mem_req_addr = {mshr_alloc_tag_q, mshr_alloc_set_q, {HPDCACHE_OFFSET_WIDTH{1'b0}} }, + mem_req_o.mem_req_len = hpdcache_mem_len_t'(REFILL_REQ_LEN-1), + mem_req_o.mem_req_size = hpdcache_mem_size_t'(REFILL_REQ_SIZE), + mem_req_o.mem_req_id = hpdcache_mem_id_t'({mshr_alloc_way_q, mshr_alloc_set_q}), + mem_req_o.mem_req_command = HPDCACHE_MEM_READ, + mem_req_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_ADD, + mem_req_o.mem_req_cacheable = 1'b1; + + always_ff @(posedge clk_i) + begin : miss_req_fsm_internal_ff + if (mshr_alloc) begin + mshr_alloc_way_q <= mshr_alloc_way_d; + mshr_alloc_set_q <= mshr_alloc_set_d; + mshr_alloc_tag_q <= mshr_alloc_tag_d; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) + begin : miss_req_fsm_ff + if (!rst_ni) begin + miss_req_fsm_q <= MISS_REQ_IDLE; + end else begin + miss_req_fsm_q <= miss_req_fsm_d; + end + end + // }}} + + // Refill FSM + // {{{ + + // ask permission to the refill arbiter if there is a pending refill + assign refill_req_valid_o = refill_fsm_q == REFILL_IDLE ? refill_fifo_resp_meta_rok : 1'b0; + + // forward the victim way directly from the victim selection logic or + // from the internal register + assign refill_victim_way_o = refill_way_bypass ? refill_victim_way_i : refill_way_q; + + always_comb + begin : miss_resp_fsm_comb + automatic hpdcache_uint REFILL_LAST_CHUNK_WORD; + REFILL_LAST_CHUNK_WORD = HPDCACHE_CL_WORDS - HPDCACHE_ACCESS_WORDS; + + refill_updt_plru_o = 1'b0; + refill_set_o = '0; + refill_write_dir_o = 1'b0; + refill_write_data_o = 1'b0; + refill_word_o = 0; + refill_data_o = '0; + refill_updt_rtab_o = 1'b0; + refill_cnt_d = refill_cnt_q; + refill_way_bypass = 1'b0; + + refill_core_rsp_valid = 1'b0; + refill_core_rsp_sid_d = refill_core_rsp_sid_q; + refill_core_rsp_tid_d = refill_core_rsp_tid_q; + refill_core_rsp_error_d = refill_core_rsp_error_q; + refill_core_rsp_word = 0; + + refill_fifo_resp_meta_r = 1'b0; + refill_fifo_resp_data_r = 1'b0; + + mshr_ack_cs = 1'b0; + mshr_ack = 1'b0; + + refill_fsm_d = refill_fsm_q; + + case (refill_fsm_q) + // Wait for refill responses + // {{{ + REFILL_IDLE: begin + if (refill_fifo_resp_meta_rok) begin + // anticipate the activation of the MSHR independently of the grant signal from + // the refill arbiter. This is to avoid the introduction of unnecessary timing + // paths (however there could be a minor augmentation of the power + // consumption). + mshr_ack_cs = 1'b1; + + // if the permission is granted, start refilling + if (refill_req_ready_i) begin + refill_fsm_d = REFILL_WRITE; + + // read the MSHR and reset the valid bit for the + // corresponding entry + mshr_ack = 1'b1; + + // initialize the counter for refill words + refill_cnt_d = 0; + end + end + end + // }}} + + // Write refill data into the cache + // {{{ + REFILL_WRITE: begin + automatic logic is_prefetch; + + // Respond to the core (when needed) + if (refill_cnt_q == 0) begin + automatic hpdcache_uint _core_rsp_word; + _core_rsp_word = hpdcache_uint'(mshr_ack_word)/HPDCACHE_ACCESS_WORDS; + + if (mshr_ack_need_rsp) begin + refill_core_rsp_valid = (hpdcache_uint'(_core_rsp_word) == 0); + end + + refill_core_rsp_sid_d = mshr_ack_src_id; + refill_core_rsp_tid_d = mshr_ack_req_id; + refill_core_rsp_error_d = refill_is_error; + refill_core_rsp_word = hpdcache_word_t'( + hpdcache_uint'(mshr_ack_word)/HPDCACHE_REQ_WORDS); + end else begin + automatic hpdcache_uint _core_rsp_word; + _core_rsp_word = hpdcache_uint'(refill_core_rsp_word_q)/ + HPDCACHE_ACCESS_WORDS; + + if (refill_need_rsp_q) begin + automatic hpdcache_uint _refill_cnt; + _refill_cnt = hpdcache_uint'(refill_cnt_q)/HPDCACHE_ACCESS_WORDS; + refill_core_rsp_valid = (_core_rsp_word == _refill_cnt); + end + + refill_core_rsp_sid_d = refill_sid_q; + refill_core_rsp_tid_d = refill_tid_q; + refill_core_rsp_error_d = refill_is_error; + refill_core_rsp_word = hpdcache_word_t'( + hpdcache_uint'(refill_core_rsp_word_q)/HPDCACHE_REQ_WORDS); + end + + // Write the the data in the cache data array + if (refill_cnt_q == 0) begin + refill_set_o = mshr_ack_nline[0 +: HPDCACHE_SET_WIDTH]; + refill_way_bypass = 1'b1; + is_prefetch = mshr_ack_is_prefetch; + end else begin + refill_set_o = refill_set_q; + refill_way_bypass = 1'b0; + is_prefetch = refill_is_prefetch_q; + end + refill_write_data_o = ~refill_is_error; + refill_data_o = refill_fifo_resp_data_rdata; + refill_word_o = refill_cnt_q; + + // Consume chunk of data from the FIFO buffer in the memory interface + refill_fifo_resp_data_r = 1'b1; + + // Update directory on the last chunk of data + refill_cnt_d = refill_cnt_q + hpdcache_word_t'(HPDCACHE_ACCESS_WORDS); + + if (hpdcache_uint'(refill_cnt_q) == REFILL_LAST_CHUNK_WORD) begin + if (REFILL_LAST_CHUNK_WORD == 0) begin + // Special case: if the cache-line data can be written in a single cycle, + // wait an additional cycle to write the directory. This allows to prevent + // a RAM-to-RAM timing path between the MSHR and the DIR. + refill_fsm_d = REFILL_WRITE_DIR; + end else begin + // Write the new entry in the cache directory + refill_write_dir_o = ~refill_is_error; + + // Update the PLRU bits. Only in the following cases: + // - There is no error in response AND + // - It is a prefetch and the cfg_prefetch_updt_plru_i is set OR + // - It is a read miss. + refill_updt_plru_o = ~refill_is_error & + (~is_prefetch | cfg_prefetch_updt_plru_i); + + // Update dependency flags in the retry table + refill_updt_rtab_o = 1'b1; + + // consume the response from the network + refill_fifo_resp_meta_r = 1'b1; + + refill_fsm_d = REFILL_IDLE; + end + end + end + // }}} + + // Write cache directory (this state is only visited when ACCESS_WORDS == CL_WORDS, + // this is when the entire cache-line can be written in a single cycle) + // {{{ + REFILL_WRITE_DIR: begin + automatic logic is_prefetch; + is_prefetch = refill_is_prefetch_q; + + // Select the target set and way + refill_set_o = refill_set_q; + refill_way_bypass = 1'b0; + + // Write the new entry in the cache directory + refill_write_dir_o = ~refill_is_error; + + // Update the PLRU bits. Only in the following cases: + // - There is no error in response AND + // - It is a prefetch and the cfg_prefetch_updt_plru_i is set OR + // - It is a read miss. + refill_updt_plru_o = ~refill_is_error & + (~is_prefetch | cfg_prefetch_updt_plru_i); + + // Update dependency flags in the retry table + refill_updt_rtab_o = 1'b1; + + // consume the response from the network + refill_fifo_resp_meta_r = 1'b1; + + refill_fsm_d = REFILL_IDLE; + end + // }}} + + default: begin + // pragma translate_off + $error("Illegal state"); + // pragma translate_on + end + endcase + end + + assign refill_is_error = (refill_fifo_resp_meta_rdata.r_error == HPDCACHE_MEM_RESP_NOK); + + assign refill_busy_o = (refill_fsm_q != REFILL_IDLE), + refill_nline_o = {refill_tag_q, refill_set_q}; + + assign mshr_ack_set = get_ack_mshr_set(refill_fifo_resp_meta_rdata.r_id), + mshr_ack_way = get_ack_mshr_way(refill_fifo_resp_meta_rdata.r_id); + + assign refill_dir_entry_o.tag = refill_tag_q, + refill_dir_entry_o.reserved = '0; + + assign refill_core_rsp_valid_d = ~refill_core_rsp_valid_q & refill_core_rsp_valid; + + assign refill_core_rsp_valid_o = refill_core_rsp_valid_q, + refill_core_rsp_o.rdata = refill_core_rsp_data_q, + refill_core_rsp_o.sid = refill_core_rsp_sid_q, + refill_core_rsp_o.tid = refill_core_rsp_tid_q, + refill_core_rsp_o.error = refill_core_rsp_error_q, + refill_core_rsp_o.aborted = 1'b0; + + generate + // refill's width is bigger than the width of the core's interface + if (REFILL_REQ_RATIO > 1) begin : core_rsp_data_mux_gen + hpdcache_mux #( + .NINPUT (REFILL_REQ_RATIO), + .DATA_WIDTH (HPDCACHE_REQ_DATA_WIDTH) + ) data_read_rsp_mux_i( + .data_i (refill_data_o), + .sel_i (refill_core_rsp_word[0 +: $clog2(REFILL_REQ_RATIO)]), + .data_o (refill_core_rsp_data_d) + ); + end + + // refill's width is equal to the width of the core's interface + else begin + assign refill_core_rsp_data_d = refill_data_o; + end + endgenerate + + /* FIXME: when multiple chunks, in case of error, the error bit is not + * necessarily set on all chunks */ + assign refill_fifo_resp_meta_wdata = '{ + r_error: mem_resp_i.mem_resp_r_error, + r_id : mem_resp_i.mem_resp_r_id + }; + + hpdcache_fifo_reg #( + .FIFO_DEPTH (2), + .fifo_data_t (mem_resp_metadata_t) + ) i_r_metadata_fifo ( + .clk_i, + .rst_ni, + + .w_i (refill_fifo_resp_meta_w), + .wok_o (refill_fifo_resp_meta_wok), + .wdata_i(refill_fifo_resp_meta_wdata), + + .r_i (refill_fifo_resp_meta_r), + .rok_o (refill_fifo_resp_meta_rok), + .rdata_o(refill_fifo_resp_meta_rdata) + ); + + generate + if (HPDcacheMemDataWidth < HPDCACHE_REFILL_DATA_WIDTH) begin + hpdcache_data_upsize #( + .WR_WIDTH(HPDcacheMemDataWidth), + .RD_WIDTH(HPDCACHE_REFILL_DATA_WIDTH), + .DEPTH(2*(HPDCACHE_CL_WIDTH/HPDCACHE_REFILL_DATA_WIDTH)) + ) i_rdata_upsize ( + .clk_i, + .rst_ni, + + .w_i (refill_fifo_resp_data_w), + .wlast_i (mem_resp_i.mem_resp_r_last), + .wok_o (refill_fifo_resp_data_wok), + .wdata_i (mem_resp_i.mem_resp_r_data), + + .r_i (refill_fifo_resp_data_r), + .rok_o (/* unused */), + .rdata_o (refill_fifo_resp_data_rdata) + ); + end else if (HPDcacheMemDataWidth > HPDCACHE_REFILL_DATA_WIDTH) begin + hpdcache_data_downsize #( + .WR_WIDTH(HPDcacheMemDataWidth), + .RD_WIDTH(HPDCACHE_REFILL_DATA_WIDTH), + .DEPTH(2*(HPDCACHE_CL_WIDTH/HPDcacheMemDataWidth)) + ) i_rdata_downsize ( + .clk_i, + .rst_ni, + + .w_i (refill_fifo_resp_data_w), + .wok_o (refill_fifo_resp_data_wok), + .wdata_i (mem_resp_i.mem_resp_r_data), + + .r_i (refill_fifo_resp_data_r), + .rok_o (/* unused */), + .rdata_o (refill_fifo_resp_data_rdata) + ); + end else begin + hpdcache_fifo_reg #( + .FIFO_DEPTH (2), + .fifo_data_t (hpdcache_refill_data_t) + ) i_rdata_fifo ( + .clk_i, + .rst_ni, + + .w_i (refill_fifo_resp_data_w), + .wok_o (refill_fifo_resp_data_wok), + .wdata_i (mem_resp_i.mem_resp_r_data), + + .r_i (refill_fifo_resp_data_r), + .rok_o (/* unused */), + .rdata_o (refill_fifo_resp_data_rdata) + ); + end + endgenerate + + assign refill_fifo_resp_data_w = mem_resp_valid_i & + (refill_fifo_resp_meta_wok | ~mem_resp_i.mem_resp_r_last), + refill_fifo_resp_meta_w = mem_resp_valid_i & + (refill_fifo_resp_data_wok & mem_resp_i.mem_resp_r_last), + mem_resp_ready_o = refill_fifo_resp_data_wok & + (refill_fifo_resp_meta_wok | ~mem_resp_i.mem_resp_r_last); + + always_ff @(posedge clk_i or negedge rst_ni) + begin : miss_resp_fsm_ff + if (!rst_ni) begin + refill_fsm_q <= REFILL_IDLE; + refill_core_rsp_valid_q <= 1'b0; + end else begin + refill_fsm_q <= refill_fsm_d; + refill_core_rsp_valid_q <= refill_core_rsp_valid_d; + end + end + + always_ff @(posedge clk_i) + begin : miss_resp_fsm_internal_ff + if ((refill_fsm_q == REFILL_WRITE) && (refill_cnt_q == 0)) begin + refill_set_q <= mshr_ack_nline[0 +: HPDCACHE_SET_WIDTH]; + refill_tag_q <= mshr_ack_nline[HPDCACHE_SET_WIDTH +: HPDCACHE_TAG_WIDTH];; + refill_way_q <= refill_victim_way_i; + refill_sid_q <= mshr_ack_src_id; + refill_tid_q <= mshr_ack_req_id; + refill_need_rsp_q <= mshr_ack_need_rsp; + refill_is_prefetch_q <= mshr_ack_is_prefetch; + refill_core_rsp_word_q <= mshr_ack_word; + end + refill_cnt_q <= refill_cnt_d; + end + + always_ff @(posedge clk_i) + begin : core_rsp_ff + if (!refill_core_rsp_valid_q && refill_core_rsp_valid) begin + refill_core_rsp_sid_q <= refill_core_rsp_sid_d; + refill_core_rsp_tid_q <= refill_core_rsp_tid_d; + refill_core_rsp_data_q <= refill_core_rsp_data_d; + refill_core_rsp_error_q <= refill_core_rsp_error_d; + end + end + // }}} + + // Miss Status Holding Register component + // {{{ + hpdcache_mshr hpdcache_mshr_i ( + .clk_i, + .rst_ni, + + .empty_o (mshr_empty), + .full_o (mshr_full_o), + + .check_i (mshr_check_i), + .check_set_i (mshr_check_set_i), + .check_tag_i (mshr_check_tag_i), + .hit_o (mshr_check_hit_o), + .alloc_i (mshr_alloc), + .alloc_cs_i (mshr_alloc_cs), + .alloc_nline_i (mshr_alloc_nline_i), + .alloc_req_id_i (mshr_alloc_tid_i), + .alloc_src_id_i (mshr_alloc_sid_i), + .alloc_word_i (mshr_alloc_word_i), + .alloc_need_rsp_i (mshr_alloc_need_rsp_i), + .alloc_is_prefetch_i (mshr_alloc_is_prefetch_i), + .alloc_full_o (mshr_alloc_full_o), + .alloc_set_o (mshr_alloc_set_d), + .alloc_tag_o (mshr_alloc_tag_d), + .alloc_way_o (mshr_alloc_way_d), + + .ack_i (mshr_ack), + .ack_cs_i (mshr_ack_cs), + .ack_set_i (mshr_ack_set), + .ack_way_i (mshr_ack_way), + .ack_req_id_o (mshr_ack_req_id), + .ack_src_id_o (mshr_ack_src_id), + .ack_nline_o (mshr_ack_nline), + .ack_word_o (mshr_ack_word), + .ack_need_rsp_o (mshr_ack_need_rsp), + .ack_is_prefetch_o (mshr_ack_is_prefetch) + ); + + // Indicate to the cache controller that there is no pending miss. This + // is, when the MSHR is empty, and the MISS handler has finished of + // processing the last miss response. + assign mshr_empty_o = mshr_empty & ~refill_busy_o; + // }}} + + // Assertions + // {{{ + // pragma translate_off + initial assert (HPDcacheMemIdWidth >= (HPDCACHE_MSHR_SET_WIDTH + HPDCACHE_MSHR_WAY_WIDTH)) else + $error("miss_handler: not enough ID bits in the memory interface"); + // pragma translate_on + // }}} + +endmodule +// }}} diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_mshr.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_mshr.sv new file mode 100644 index 00000000000..f63e408f38d --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_mshr.sv @@ -0,0 +1,385 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : HPDcache Miss Status Holding Register (MSHR) + * History : + */ +module hpdcache_mshr +import hpdcache_pkg::*; + // Ports + // {{{ +( + // Clock and reset signals + input logic clk_i, + input logic rst_ni, + + // Global control signals + output logic empty_o, + output logic full_o, + + // Check and allocation interface + input logic check_i, + input mshr_set_t check_set_i, + input mshr_tag_t check_tag_i, + output logic hit_o, + input logic alloc_i, + input logic alloc_cs_i, + input hpdcache_nline_t alloc_nline_i, + input hpdcache_req_tid_t alloc_req_id_i, + input hpdcache_req_sid_t alloc_src_id_i, + input hpdcache_word_t alloc_word_i, + input logic alloc_need_rsp_i, + input logic alloc_is_prefetch_i, + output logic alloc_full_o, + output mshr_set_t alloc_set_o, + output mshr_tag_t alloc_tag_o, + output mshr_way_t alloc_way_o, + + // Acknowledge interface + input logic ack_i, + input logic ack_cs_i, + input mshr_set_t ack_set_i, + input mshr_way_t ack_way_i, + output hpdcache_req_tid_t ack_req_id_o, + output hpdcache_req_sid_t ack_src_id_o, + output hpdcache_nline_t ack_nline_o, + output hpdcache_word_t ack_word_o, + output logic ack_need_rsp_o, + output logic ack_is_prefetch_o +); + // }}} + + // Definition of constants and types + // {{{ + typedef struct packed { + mshr_tag_t tag; + hpdcache_req_tid_t req_id; + hpdcache_req_sid_t src_id; + hpdcache_word_t word_idx; + logic need_rsp; + logic is_prefetch; + } mshr_entry_t; + + + // Compute the width of MSHR entries depending on the support of write + // bitmask or not (write byte enable) + localparam int unsigned HPDCACHE_MSHR_ENTRY_BITS = $bits(mshr_entry_t); + + localparam int unsigned HPDCACHE_MSHR_RAM_ENTRY_BITS = + HPDCACHE_MSHR_RAM_WBYTEENABLE ? + ((HPDCACHE_MSHR_ENTRY_BITS + 7)/8) * 8 : // align to 8 bits + HPDCACHE_MSHR_ENTRY_BITS; // or use the exact number of bits + + typedef logic [HPDCACHE_MSHR_RAM_ENTRY_BITS-1:0] mshr_sram_data_t; + // }}} + + // Definition of internal wires and registers + // {{{ + logic [HPDCACHE_MSHR_SETS*HPDCACHE_MSHR_WAYS-1:0] mshr_valid_q, mshr_valid_d; + mshr_set_t check_set_q; + mshr_set_t alloc_set; + mshr_tag_t alloc_tag; + hpdcache_set_t alloc_dcache_set; + mshr_way_t ack_way_q; + mshr_set_t ack_set_q; + hpdcache_set_t ack_dcache_set; + hpdcache_tag_t ack_dcache_tag; + + logic [HPDCACHE_MSHR_SETS*HPDCACHE_MSHR_WAYS-1:0] mshr_valid_set, mshr_valid_rst; + mshr_entry_t [HPDCACHE_MSHR_WAYS-1:0] mshr_wentry; + mshr_sram_data_t [HPDCACHE_MSHR_WAYS-1:0] mshr_wdata; + mshr_entry_t [HPDCACHE_MSHR_WAYS-1:0] mshr_rentry; + mshr_sram_data_t [HPDCACHE_MSHR_WAYS-1:0] mshr_rdata; + + logic mshr_we; + logic mshr_cs; + mshr_set_t mshr_addr; + logic check; + // }}} + + // Control part for the allocation and check operations + // {{{ + + // The allocation operation is prioritary with respect to the check operation + assign check = check_i & ~alloc_i; + + assign alloc_set = alloc_nline_i[0 +: HPDCACHE_MSHR_SET_WIDTH], + alloc_tag = alloc_nline_i[HPDCACHE_MSHR_SET_WIDTH +: HPDCACHE_MSHR_TAG_WIDTH], + alloc_dcache_set = alloc_nline_i[0 +: HPDCACHE_SET_WIDTH]; + + // Look for an available way in case of allocation + always_comb + begin + automatic mshr_way_t found_available_way; + + found_available_way = 0; + for (int unsigned i = 0; i < HPDCACHE_MSHR_WAYS; i++) begin + if (!mshr_valid_q[i*HPDCACHE_MSHR_SETS + int'(alloc_set)]) begin + found_available_way = mshr_way_t'(i); + break; + end + end + alloc_way_o = found_available_way; + end + + // Look if the mshr can accept the checked nline (in case of allocation) + always_comb + begin + automatic bit found_available; + + found_available = 1'b0; + for (int unsigned i = 0; i < HPDCACHE_MSHR_WAYS; i++) begin + if (!mshr_valid_q[i*HPDCACHE_MSHR_SETS + int'(check_set_q)]) begin + found_available = 1'b1; + break; + end + end + alloc_full_o = ~found_available; + end + + assign alloc_set_o = alloc_set, + alloc_tag_o = alloc_tag; + + // Write when there is an allocation operation + assign mshr_we = alloc_i; + + // HPDcache SET to MSHR SET translation table + hpdcache_mshr_to_cache_set trlt_i ( + .clk_i, + .write_i (mshr_we), + .write_dcache_set_i (alloc_dcache_set), + .write_mshr_way_i (alloc_way_o), + .read_mshr_set_i (ack_set_q), + .read_mshr_way_i (ack_way_q), + .read_dcache_set_o (ack_dcache_set) + ); + + + // Generate write data and mask depending on the available way + always_comb + begin + for (int unsigned i = 0; i < HPDCACHE_MSHR_WAYS; i++) begin + mshr_wentry[i].tag = alloc_tag; + mshr_wentry[i].req_id = alloc_req_id_i; + mshr_wentry[i].src_id = alloc_src_id_i; + mshr_wentry[i].word_idx = alloc_word_i; + mshr_wentry[i].need_rsp = alloc_need_rsp_i; + mshr_wentry[i].is_prefetch = alloc_is_prefetch_i; + end + end + // }}} + + // Shared control signals + // {{{ + assign mshr_cs = check_i | alloc_cs_i | ack_cs_i; + assign mshr_addr = ack_i ? ack_set_i : + (alloc_i ? alloc_set : check_set_i); + + always_comb + begin : mshr_valid_comb + automatic logic unsigned [HPDCACHE_MSHR_WAY_WIDTH+HPDCACHE_MSHR_SET_WIDTH-1:0] mshr_alloc_slot; + automatic logic unsigned [HPDCACHE_MSHR_WAY_WIDTH+HPDCACHE_MSHR_SET_WIDTH-1:0] mshr_ack_slot; + + mshr_alloc_slot = {alloc_way_o, alloc_set}; + mshr_ack_slot = { ack_way_i, ack_set_i}; + + for (int unsigned i = 0; i < HPDCACHE_MSHR_SETS*HPDCACHE_MSHR_WAYS; i++) begin + mshr_valid_rst[i] = (i == hpdcache_uint'(mshr_ack_slot)) ? ack_i : 1'b0; + mshr_valid_set[i] = (i == hpdcache_uint'(mshr_alloc_slot)) ? alloc_i : 1'b0; + end + end + assign mshr_valid_d = (~mshr_valid_q & mshr_valid_set) | (mshr_valid_q & ~mshr_valid_rst); + // }}} + + // Read interface (ack) + // {{{ + generate + // extract HPDcache tag from the MSb of the MSHT TAG + if (HPDCACHE_SETS >= HPDCACHE_MSHR_SETS) begin : ack_dcache_set_ge_mshr_set_gen + assign ack_dcache_tag = mshr_rentry[ack_way_q].tag[ + HPDCACHE_MSHR_TAG_WIDTH - 1 : + HPDCACHE_MSHR_TAG_WIDTH - HPDCACHE_TAG_WIDTH]; + end + + // extract HPDcache tag from MSb of the MSHR set concatenated with the MSHR tag + else begin : ack_dcache_set_lt_mshr_set_gen + assign ack_dcache_tag = { + mshr_rentry[ack_way_q].tag , + ack_set_q[HPDCACHE_MSHR_SET_WIDTH - 1:HPDCACHE_SET_WIDTH]}; + end + endgenerate + + assign ack_req_id_o = mshr_rentry[ack_way_q].req_id, + ack_src_id_o = mshr_rentry[ack_way_q].src_id, + ack_nline_o = {ack_dcache_tag, ack_dcache_set}, + ack_word_o = mshr_rentry[ack_way_q].word_idx, + ack_need_rsp_o = mshr_rentry[ack_way_q].need_rsp, + ack_is_prefetch_o = mshr_rentry[ack_way_q].is_prefetch; + // }}} + + // Global control signals + // {{{ + assign empty_o = ~|mshr_valid_q; + assign full_o = &mshr_valid_q; + + always_comb + begin : hit_comb + automatic bit [HPDCACHE_MSHR_WAYS-1:0] __hit_way; + + for (int unsigned w = 0; w < HPDCACHE_MSHR_WAYS; w++) begin + automatic bit __valid; + automatic bit __match; + __valid = mshr_valid_q[w*HPDCACHE_MSHR_SETS + int'(check_set_q)]; + __match = (mshr_rentry[w].tag == check_tag_i); + __hit_way[w] = (__valid && __match); + end + + hit_o = |__hit_way; + end + // }}} + + // Internal state assignment + // {{{ + always_ff @(posedge clk_i or negedge rst_ni) + begin : mshr_ff_set + if (!rst_ni) begin + mshr_valid_q <= '0; + ack_way_q <= '0; + ack_set_q <= '0; + check_set_q <= '0; + end else begin + mshr_valid_q <= mshr_valid_d; + if (ack_i) begin + ack_way_q <= ack_way_i; + ack_set_q <= ack_set_i; + end + if (check) begin + check_set_q <= check_set_i; + end + end + end + // }}} + + // Internal components + // {{{ + generate + if (HPDCACHE_MSHR_RAM_WBYTEENABLE) begin : mshr_wbyteenable_gen + typedef logic [HPDCACHE_MSHR_RAM_ENTRY_BITS/8-1:0] mshr_sram_wbyteenable_t; + mshr_sram_wbyteenable_t [HPDCACHE_MSHR_WAYS-1:0] mshr_wbyteenable; + + always_comb + begin : mshr_wbyteenable_comb + for (int unsigned i = 0; i < HPDCACHE_MSHR_WAYS; i++) begin + mshr_wbyteenable[i] = (int'(alloc_way_o) == i) ? '1 : '0; + end + end + + if (HPDCACHE_MSHR_USE_REGBANK) begin : mshr_regbank_gen + hpdcache_regbank_wbyteenable_1rw #( + .DATA_SIZE (HPDCACHE_MSHR_WAYS*HPDCACHE_MSHR_RAM_ENTRY_BITS), + .ADDR_SIZE (HPDCACHE_MSHR_SET_WIDTH) + ) mshr_mem( + .clk (clk_i), + .rst_n (rst_ni), + .cs (mshr_cs), + .we (mshr_we), + .addr (mshr_addr), + .wbyteenable (mshr_wbyteenable), + .wdata (mshr_wdata), + .rdata (mshr_rdata) + ); + end else begin : mshr_sram_gen + hpdcache_sram_wbyteenable #( + .DATA_SIZE (HPDCACHE_MSHR_WAYS*HPDCACHE_MSHR_RAM_ENTRY_BITS), + .ADDR_SIZE (HPDCACHE_MSHR_SET_WIDTH) + ) mshr_mem( + .clk (clk_i), + .rst_n (rst_ni), + .cs (mshr_cs), + .we (mshr_we), + .addr (mshr_addr), + .wbyteenable (mshr_wbyteenable), + .wdata (mshr_wdata), + .rdata (mshr_rdata) + ); + end + end else begin : mshr_wmask_gen + typedef logic [HPDCACHE_MSHR_RAM_ENTRY_BITS-1:0] mshr_sram_wmask_t; + mshr_sram_wmask_t [HPDCACHE_MSHR_WAYS-1:0] mshr_wmask; + + always_comb + begin : mshr_wmask_comb + for (int unsigned i = 0; i < HPDCACHE_MSHR_WAYS; i++) begin + mshr_wmask[i] = (int'(alloc_way_o) == i) ? '1 : '0; + end + end + + if (HPDCACHE_MSHR_USE_REGBANK) begin : mshr_regbank_gen + hpdcache_regbank_wmask_1rw #( + .DATA_SIZE (HPDCACHE_MSHR_WAYS*HPDCACHE_MSHR_RAM_ENTRY_BITS), + .ADDR_SIZE (HPDCACHE_MSHR_SET_WIDTH) + ) mshr_mem( + .clk (clk_i), + .rst_n (rst_ni), + .cs (mshr_cs), + .we (mshr_we), + .addr (mshr_addr), + .wmask (mshr_wmask), + .wdata (mshr_wdata), + .rdata (mshr_rdata) + ); + end else begin : mshr_sram_gen + hpdcache_sram_wmask #( + .DATA_SIZE (HPDCACHE_MSHR_WAYS*HPDCACHE_MSHR_RAM_ENTRY_BITS), + .ADDR_SIZE (HPDCACHE_MSHR_SET_WIDTH) + ) mshr_mem( + .clk (clk_i), + .rst_n (rst_ni), + .cs (mshr_cs), + .we (mshr_we), + .addr (mshr_addr), + .wmask (mshr_wmask), + .wdata (mshr_wdata), + .rdata (mshr_rdata) + ); + end + end + endgenerate + + always_comb + begin : ram_word_fitting_comb + for (int unsigned i = 0; i < HPDCACHE_MSHR_WAYS; i++) begin + mshr_wdata[i] = mshr_sram_data_t'(mshr_wentry[i]); + mshr_rentry[i] = mshr_entry_t'(mshr_rdata[i][0 +: HPDCACHE_MSHR_ENTRY_BITS]); + end + end + // }}} + + // Assertions + // {{{ + // pragma translate_off + one_command_assert: assert property (@(posedge clk_i) + (ack_i -> !(alloc_i || check_i))) else + $error("MSHR: ack with concurrent alloc or check"); + // pragma translate_on + // }}} +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_mshr_to_cache_set.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_mshr_to_cache_set.sv new file mode 100644 index 00000000000..3dc8b73af55 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_mshr_to_cache_set.sv @@ -0,0 +1,105 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : HPDcache MSHR set translation table + * History : + */ +module hpdcache_mshr_to_cache_set +import hpdcache_pkg::*; +// Ports +// {{{ +( + // Clock signals + input logic clk_i, + + // Write interface + input logic write_i, + input hpdcache_set_t write_dcache_set_i, + input mshr_way_t write_mshr_way_i, + + // Read interface + input mshr_way_t read_mshr_way_i, + input mshr_set_t read_mshr_set_i, + output hpdcache_set_t read_dcache_set_o +); +// }}} + // + + generate + // Number of HPDcache sets is bigger than the MSHR sets + // In this case, a translation table (in flip-flops) is needed + // {{{ + // Write most significant bits of the HPDcache set into the + // translation table + if (HPDCACHE_SETS > HPDCACHE_MSHR_SETS) begin : hpdcache_sets_gt_mshr_sets_gen + localparam hpdcache_uint TRLT_TAB_ENTRY_WIDTH = + HPDCACHE_SET_WIDTH - HPDCACHE_MSHR_SET_WIDTH; + typedef logic [TRLT_TAB_ENTRY_WIDTH-1:0] trlt_entry_t; + + + // Translation table + // + // This table is used to store the most significant bits of the HPDcache set + trlt_entry_t [HPDCACHE_MSHR_SETS-1:0][HPDCACHE_MSHR_WAYS-1:0] tab; + trlt_entry_t tab_wdata; + mshr_set_t write_mshr_set; + + // Write operation + // {{{ + // Write most significant bits of the HPDcache set into the + // translation table + always_ff @(posedge clk_i) + begin + if (write_i) begin + tab[write_mshr_set][write_mshr_way_i] <= tab_wdata; + end + end + + assign tab_wdata = write_dcache_set_i[HPDCACHE_MSHR_SET_WIDTH +: + TRLT_TAB_ENTRY_WIDTH], + write_mshr_set = write_dcache_set_i[0 +: HPDCACHE_MSHR_SET_WIDTH]; + // }}} + + // Read operation + // {{{ + // Concatenate the mshr set with the most significant bits of the + // dcache set stored in the translation table + assign read_dcache_set_o = {tab[read_mshr_set_i][read_mshr_way_i], read_mshr_set_i}; + // }}} + end + // }}} + + // Number of HPDcache sets is smaller or equal than the MSHR sets + // In this case, no translation table is needed + // {{{ + else begin : hpdcache_sets_le_mshr_sets_gen + assign read_dcache_set_o = hpdcache_set_t'(read_mshr_set_i); + end + // }}} + endgenerate + +// Assertions +// {{{ +// pragma translate_off +// pragma translate_on +// }}} +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_pkg.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_pkg.sv new file mode 100755 index 00000000000..81db44d0871 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_pkg.sv @@ -0,0 +1,613 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : Write-Through (WT), High-Throughput (HTPUT) HPDcache Package + * History : + */ +package hpdcache_pkg; + // Definition of global constants for the HPDcache data and directory + // {{{ + + // HPDcache physical address width (bits) + localparam int unsigned HPDCACHE_PA_WIDTH = hpdcache_params_pkg::PARAM_PA_WIDTH; + + // HPDcache number of sets + localparam int unsigned HPDCACHE_SETS = hpdcache_params_pkg::PARAM_SETS; + + // HPDcache number of ways + localparam int unsigned HPDCACHE_WAYS = hpdcache_params_pkg::PARAM_WAYS; + + // HPDcache word width (bits) + localparam int unsigned HPDCACHE_WORD_WIDTH = hpdcache_params_pkg::PARAM_WORD_WIDTH; + + // HPDcache cache-line width (bits) + localparam int unsigned HPDCACHE_CL_WORDS = hpdcache_params_pkg::PARAM_CL_WORDS; + + // HPDcache number of words in the request data channels (request and response) + localparam int unsigned HPDCACHE_REQ_WORDS = hpdcache_params_pkg::PARAM_REQ_WORDS; + + // HPDcache request transaction ID width (bits) + localparam int unsigned HPDCACHE_REQ_TRANS_ID_WIDTH = hpdcache_params_pkg::PARAM_REQ_TRANS_ID_WIDTH; + + // HPDcache request source ID width (bits) + localparam int unsigned HPDCACHE_REQ_SRC_ID_WIDTH = hpdcache_params_pkg::PARAM_REQ_SRC_ID_WIDTH; + // }}} + + // Utility definitions + // {{{ + typedef logic unsigned [31:0] hpdcache_uint; + typedef logic signed [31:0] hpdcache_int; + typedef logic unsigned [31:0] hpdcache_uint32; + typedef logic signed [31:0] hpdcache_int32; + typedef logic unsigned [63:0] hpdcache_uint64; + typedef logic signed [63:0] hpdcache_int64; + // }}} + + // Definition of constants and types for HPDcache directory memory + // {{{ + localparam int unsigned HPDCACHE_CL_WIDTH = HPDCACHE_CL_WORDS*HPDCACHE_WORD_WIDTH; + localparam int unsigned HPDCACHE_OFFSET_WIDTH = $clog2(HPDCACHE_CL_WIDTH/8); + localparam int unsigned HPDCACHE_NLINE_WIDTH = HPDCACHE_PA_WIDTH - HPDCACHE_OFFSET_WIDTH; + localparam int unsigned HPDCACHE_SET_WIDTH = $clog2(HPDCACHE_SETS); + localparam int unsigned HPDCACHE_TAG_WIDTH = HPDCACHE_NLINE_WIDTH - HPDCACHE_SET_WIDTH; + localparam int unsigned HPDCACHE_WORD_IDX_WIDTH = $clog2(HPDCACHE_CL_WORDS); + + typedef logic unsigned [ HPDCACHE_OFFSET_WIDTH-1:0] hpdcache_offset_t; + typedef logic unsigned [ HPDCACHE_NLINE_WIDTH-1:0] hpdcache_nline_t; + typedef logic unsigned [ HPDCACHE_SET_WIDTH-1:0] hpdcache_set_t; + typedef logic unsigned [ HPDCACHE_TAG_WIDTH-1:0] hpdcache_tag_t; + typedef logic unsigned [ $clog2(HPDCACHE_WAYS)-1:0] hpdcache_way_t; + typedef logic unsigned [ HPDCACHE_WAYS-1:0] hpdcache_way_vector_t; + typedef logic unsigned [HPDCACHE_WORD_IDX_WIDTH-1:0] hpdcache_word_t; + + typedef struct packed { + hpdcache_tag_t tag; + logic [1:0] reserved; + } hpdcache_dir_entry_t; + + localparam int unsigned HPDCACHE_DIR_RAM_WIDTH = $bits(hpdcache_dir_entry_t); + localparam int unsigned HPDCACHE_DIR_RAM_DEPTH = HPDCACHE_SETS; + localparam int unsigned HPDCACHE_DIR_RAM_ADDR_WIDTH = $clog2(HPDCACHE_DIR_RAM_DEPTH); + + typedef logic [HPDCACHE_DIR_RAM_ADDR_WIDTH-1:0] hpdcache_dir_addr_t; + + function automatic hpdcache_way_t hpdcache_way_vector_to_index(input hpdcache_way_vector_t way); + for (int unsigned i = 0; i < HPDCACHE_WAYS; i++) begin + if (way[i]) return hpdcache_way_t'(i); + end + return 0; + endfunction + + // }}} + + // Definition of constants and types for HPDcache data memory + // {{{ + localparam int unsigned HPDCACHE_DATA_WAYS_PER_RAM_WORD = + hpdcache_params_pkg::PARAM_DATA_WAYS_PER_RAM_WORD; + + localparam int unsigned HPDCACHE_DATA_SETS_PER_RAM = /* FIXME this parameter is currently ignored */ + hpdcache_params_pkg::PARAM_DATA_SETS_PER_RAM; + + // HPDcache DATA RAM implements write byte enable + localparam bit HPDCACHE_DATA_RAM_WBYTEENABLE = + hpdcache_params_pkg::PARAM_DATA_RAM_WBYTEENABLE; + + // Define the number of memory contiguous words that can be accessed + // simultaneously from the cache. + // - This limits the maximum width for the data channel from requesters + // - This impacts the refill latency + localparam int unsigned HPDCACHE_ACCESS_WORDS = hpdcache_params_pkg::PARAM_ACCESS_WORDS; + + + localparam int unsigned HPDCACHE_DATA_RAM_WIDTH = + HPDCACHE_DATA_WAYS_PER_RAM_WORD*HPDCACHE_WORD_WIDTH; + localparam int unsigned HPDCACHE_DATA_RAM_Y_CUTS = HPDCACHE_WAYS/HPDCACHE_DATA_WAYS_PER_RAM_WORD; + localparam int unsigned HPDCACHE_DATA_RAM_X_CUTS = HPDCACHE_ACCESS_WORDS; + localparam int unsigned HPDCACHE_DATA_RAM_ACCESS_WIDTH = HPDCACHE_ACCESS_WORDS*HPDCACHE_WORD_WIDTH; + localparam int unsigned HPDCACHE_DATA_RAM_ENTR_PER_SET = HPDCACHE_CL_WORDS/HPDCACHE_ACCESS_WORDS; + localparam int unsigned HPDCACHE_DATA_RAM_DEPTH = HPDCACHE_SETS*HPDCACHE_DATA_RAM_ENTR_PER_SET; + localparam int unsigned HPDCACHE_DATA_RAM_ADDR_WIDTH = $clog2(HPDCACHE_DATA_RAM_DEPTH); + + typedef logic [ HPDCACHE_WORD_WIDTH-1:0] hpdcache_data_word_t; + typedef logic [ HPDCACHE_WORD_WIDTH/8-1:0] hpdcache_data_be_t; + typedef logic [ $clog2(HPDCACHE_DATA_RAM_Y_CUTS)-1:0] hpdcache_data_ram_row_idx_t; + typedef logic [ $clog2(HPDCACHE_DATA_WAYS_PER_RAM_WORD)-1:0] hpdcache_data_ram_way_idx_t; + + typedef logic [HPDCACHE_DATA_RAM_ADDR_WIDTH-1:0] hpdcache_data_ram_addr_t; + typedef hpdcache_data_word_t[HPDCACHE_DATA_WAYS_PER_RAM_WORD-1:0] hpdcache_data_ram_data_t; + typedef hpdcache_data_be_t [HPDCACHE_DATA_WAYS_PER_RAM_WORD-1:0] hpdcache_data_ram_be_t; + + typedef hpdcache_data_ram_data_t + [HPDCACHE_DATA_RAM_Y_CUTS-1:0] + [HPDCACHE_DATA_RAM_X_CUTS-1:0] + hpdcache_data_entry_t; + + typedef hpdcache_data_ram_be_t + [HPDCACHE_DATA_RAM_Y_CUTS-1:0] + [HPDCACHE_DATA_RAM_X_CUTS-1:0] + hpdcache_data_be_entry_t; + + typedef logic + [HPDCACHE_DATA_RAM_X_CUTS-1:0] + hpdcache_data_row_enable_t; + + typedef hpdcache_data_row_enable_t + [HPDCACHE_DATA_RAM_Y_CUTS-1:0] + hpdcache_data_enable_t; + + typedef hpdcache_data_ram_addr_t + [HPDCACHE_DATA_RAM_Y_CUTS-1:0] + [HPDCACHE_DATA_RAM_X_CUTS-1:0] + hpdcache_data_addr_t; + // }}} + + // Definition of interface with miss handler + // {{{ + localparam int unsigned HPDCACHE_REFILL_DATA_WIDTH = HPDCACHE_DATA_RAM_ACCESS_WIDTH; + + typedef hpdcache_data_word_t[HPDCACHE_ACCESS_WORDS-1:0] hpdcache_refill_data_t; + typedef hpdcache_data_be_t [HPDCACHE_ACCESS_WORDS-1:0] hpdcache_refill_be_t; + // }}} + + // Definition of interface with requesters + // {{{ + localparam int unsigned HPDCACHE_REQ_DATA_WIDTH = HPDCACHE_REQ_WORDS*HPDCACHE_WORD_WIDTH; + localparam int unsigned HPDCACHE_REQ_DATA_BYTES = HPDCACHE_REQ_DATA_WIDTH/8; + localparam int unsigned HPDCACHE_REQ_WORD_INDEX_WIDTH = $clog2(HPDCACHE_REQ_WORDS); + localparam int unsigned HPDCACHE_REQ_BYTE_OFFSET_WIDTH = $clog2(HPDCACHE_REQ_DATA_BYTES); + localparam int unsigned HPDCACHE_REQ_OFFSET_WIDTH = HPDCACHE_PA_WIDTH - HPDCACHE_TAG_WIDTH; + + typedef logic [HPDCACHE_PA_WIDTH-1:0] hpdcache_req_addr_t; + typedef logic [HPDCACHE_REQ_OFFSET_WIDTH-1:0] hpdcache_req_offset_t; + typedef hpdcache_data_word_t [HPDCACHE_REQ_WORDS-1:0] hpdcache_req_data_t; + typedef hpdcache_data_be_t [HPDCACHE_REQ_WORDS-1:0] hpdcache_req_be_t; + typedef logic [2:0] hpdcache_req_size_t; + typedef logic [HPDCACHE_REQ_SRC_ID_WIDTH-1:0] hpdcache_req_sid_t; + typedef logic [HPDCACHE_REQ_TRANS_ID_WIDTH-1:0] hpdcache_req_tid_t; + + // Definition of operation codes + // {{{ + typedef enum logic [3:0] { + HPDCACHE_REQ_LOAD = 4'h0, + HPDCACHE_REQ_STORE = 4'h1, + // RESERVED = 4'h2, + // RESERVED = 4'h3, + HPDCACHE_REQ_AMO_LR = 4'h4, + HPDCACHE_REQ_AMO_SC = 4'h5, + HPDCACHE_REQ_AMO_SWAP = 4'h6, + HPDCACHE_REQ_AMO_ADD = 4'h7, + HPDCACHE_REQ_AMO_AND = 4'h8, + HPDCACHE_REQ_AMO_OR = 4'h9, + HPDCACHE_REQ_AMO_XOR = 4'ha, + HPDCACHE_REQ_AMO_MAX = 4'hb, + HPDCACHE_REQ_AMO_MAXU = 4'hc, + HPDCACHE_REQ_AMO_MIN = 4'hd, + HPDCACHE_REQ_AMO_MINU = 4'he, + HPDCACHE_REQ_CMO = 4'hf + } hpdcache_req_op_t; + // }}} + + // Definition of CMO codes + // {{{ + typedef enum hpdcache_req_size_t { + HPDCACHE_REQ_CMO_FENCE = 3'h0, + // RESERVED = 3'h1, + HPDCACHE_REQ_CMO_INVAL_NLINE = 3'h2, + HPDCACHE_REQ_CMO_INVAL_SET_WAY = 3'h3, + HPDCACHE_REQ_CMO_INVAL_ALL = 3'h4, + HPDCACHE_REQ_CMO_PREFETCH = 3'h5 + } hpdcache_req_cmo_t; + // }}} + + // Definition of PMA flags + // {{{ + typedef struct packed + { + logic uncacheable; + logic io; // FIXME: for future use + } hpdcache_pma_t; + // }}} + + // Definition of interfaces + // {{{ + // Request Interface + typedef struct packed + { + hpdcache_req_offset_t addr_offset; + hpdcache_req_data_t wdata; + hpdcache_req_op_t op; + hpdcache_req_be_t be; + hpdcache_req_size_t size; + hpdcache_req_sid_t sid; + hpdcache_req_tid_t tid; + logic need_rsp; + + // only valid in case of physically indexed requests + logic phys_indexed; + hpdcache_tag_t addr_tag; + hpdcache_pma_t pma; + } hpdcache_req_t; + + // Response Interface + typedef struct packed + { + hpdcache_req_data_t rdata; + hpdcache_req_sid_t sid; + hpdcache_req_tid_t tid; + logic error; + logic aborted; + } hpdcache_rsp_t; + // }}} + + // Definition of functions + // {{{ + function automatic logic is_load(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_LOAD: return 1'b1; + default: return 1'b0; + endcase + endfunction + + function automatic logic is_store(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_STORE: return 1'b1; + default: return 1'b0; + endcase + endfunction + + function automatic logic is_amo(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_AMO_LR, + HPDCACHE_REQ_AMO_SC, + HPDCACHE_REQ_AMO_SWAP, + HPDCACHE_REQ_AMO_ADD, + HPDCACHE_REQ_AMO_AND, + HPDCACHE_REQ_AMO_OR, + HPDCACHE_REQ_AMO_XOR, + HPDCACHE_REQ_AMO_MAX, + HPDCACHE_REQ_AMO_MAXU, + HPDCACHE_REQ_AMO_MIN, + HPDCACHE_REQ_AMO_MINU: + return 1'b1; + default: + return 1'b0; + endcase + endfunction + + function automatic logic is_amo_lr(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_AMO_LR: return 1'b1; + default: return 1'b0; + endcase + endfunction + + function automatic logic is_amo_sc(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_AMO_SC: return 1'b1; + default: return 1'b0; + endcase + endfunction + + function automatic logic is_amo_swap(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_AMO_SWAP: return 1'b1; + default: return 1'b0; + endcase + endfunction + + function automatic logic is_amo_add(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_AMO_ADD: return 1'b1; + default: return 1'b0; + endcase + endfunction + + function automatic logic is_amo_and(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_AMO_AND: return 1'b1; + default: return 1'b0; + endcase + endfunction + + function automatic logic is_amo_or(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_AMO_OR: return 1'b1; + default: return 1'b0; + endcase + endfunction + + function automatic logic is_amo_xor(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_AMO_XOR: return 1'b1; + default: return 1'b0; + endcase + endfunction + + function automatic logic is_amo_max(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_AMO_MAX: return 1'b1; + default: return 1'b0; + endcase + endfunction + + function automatic logic is_amo_maxu(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_AMO_MAXU: return 1'b1; + default: return 1'b0; + endcase + endfunction + + function automatic logic is_amo_min(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_AMO_MIN: return 1'b1; + default: return 1'b0; + endcase + endfunction + + function automatic logic is_amo_minu(input hpdcache_req_op_t op); + case (op) + HPDCACHE_REQ_AMO_MINU: return 1'b1; + default: return 1'b0; + endcase + endfunction + + function automatic logic is_cmo_inval( + input hpdcache_req_op_t op, + input hpdcache_req_size_t sz); + case (op) + HPDCACHE_REQ_CMO: + case (sz) + HPDCACHE_REQ_CMO_INVAL_NLINE, + HPDCACHE_REQ_CMO_INVAL_SET_WAY, + HPDCACHE_REQ_CMO_INVAL_ALL: begin + return 1'b1; + end + default: begin + return 1'b0; + end + endcase + default: begin + return 1'b0; + end + endcase + endfunction + + function automatic logic is_cmo_inval_by_nline(input hpdcache_req_size_t sz); + return (sz == HPDCACHE_REQ_CMO_INVAL_NLINE); + endfunction + + function automatic logic is_cmo_inval_by_set(input hpdcache_req_size_t sz); + return (sz == HPDCACHE_REQ_CMO_INVAL_SET_WAY); + endfunction + + function automatic logic is_cmo_inval_all(input hpdcache_req_size_t sz); + return (sz == HPDCACHE_REQ_CMO_INVAL_ALL); + endfunction + + function automatic logic is_cmo_fence( + input hpdcache_req_op_t op, + input hpdcache_req_size_t sz); + case (op) + HPDCACHE_REQ_CMO: begin + return (sz == HPDCACHE_REQ_CMO_FENCE); + end + default: begin + return 1'b0; + end + endcase + endfunction + + function automatic logic is_cmo_prefetch( + input hpdcache_req_op_t op, + input hpdcache_req_size_t sz); + case (op) + HPDCACHE_REQ_CMO: begin + return (sz == HPDCACHE_REQ_CMO_PREFETCH); + end + default: begin + return 1'b0; + end + endcase + endfunction + + function automatic hpdcache_tag_t hpdcache_get_req_addr_tag(input hpdcache_req_addr_t addr); + return addr[(HPDCACHE_OFFSET_WIDTH + HPDCACHE_SET_WIDTH) +: HPDCACHE_TAG_WIDTH]; + endfunction + + function automatic hpdcache_set_t hpdcache_get_req_addr_set(input hpdcache_req_addr_t addr); + return addr[HPDCACHE_OFFSET_WIDTH +: HPDCACHE_SET_WIDTH]; + endfunction + + function automatic hpdcache_word_t hpdcache_get_req_addr_word(input hpdcache_req_addr_t addr); + return addr[$clog2(HPDCACHE_WORD_WIDTH/8) +: HPDCACHE_WORD_IDX_WIDTH]; + endfunction + + function automatic hpdcache_offset_t hpdcache_get_req_addr_offset(input hpdcache_req_addr_t addr); + return addr[0 +: HPDCACHE_OFFSET_WIDTH]; + endfunction + + function automatic hpdcache_nline_t hpdcache_get_req_addr_nline(input hpdcache_req_addr_t addr); + return addr[HPDCACHE_OFFSET_WIDTH +: HPDCACHE_NLINE_WIDTH]; + endfunction + + function automatic hpdcache_set_t hpdcache_get_req_offset_set(input hpdcache_req_offset_t offset); + return offset[HPDCACHE_OFFSET_WIDTH +: HPDCACHE_SET_WIDTH]; + endfunction + + function automatic hpdcache_word_t hpdcache_get_req_offset_word(input hpdcache_req_offset_t offset); + return offset[$clog2(HPDCACHE_WORD_WIDTH/8) +: HPDCACHE_WORD_IDX_WIDTH]; + endfunction + + // }}} + // }}} + + // Definition of constants and types for the Miss Status Holding Register (MSHR) + // {{{ + + // HPDcache MSHR number of sets + localparam int unsigned HPDCACHE_MSHR_SETS = + hpdcache_params_pkg::PARAM_MSHR_SETS; + + // HPDcache MSHR number of ways + localparam int unsigned HPDCACHE_MSHR_WAYS = + hpdcache_params_pkg::PARAM_MSHR_WAYS; + + // HPDcache MSHR number of ways in the same SRAM word + localparam int unsigned HPDCACHE_MSHR_WAYS_PER_RAM_WORD = + hpdcache_params_pkg::PARAM_MSHR_WAYS_PER_RAM_WORD; /* FIXME this parameter is currently ignored */ + + // HPDcache MSHR number of sets in the same SRAM + localparam int unsigned HPDCACHE_MSHR_SETS_PER_RAM = + hpdcache_params_pkg::PARAM_MSHR_SETS_PER_RAM; /* FIXME this parameter is currently ignored */ + + // HPDcache MSHR implements write byte enable + localparam bit HPDCACHE_MSHR_RAM_WBYTEENABLE = + hpdcache_params_pkg::PARAM_MSHR_RAM_WBYTEENABLE; + localparam bit HPDCACHE_MSHR_USE_REGBANK = + hpdcache_params_pkg::PARAM_MSHR_USE_REGBANK; + + localparam int unsigned HPDCACHE_MSHR_SET_WIDTH = $clog2(HPDCACHE_MSHR_SETS); + localparam int unsigned HPDCACHE_MSHR_WAY_WIDTH = $clog2(HPDCACHE_MSHR_WAYS); + localparam int unsigned HPDCACHE_MSHR_TAG_WIDTH = HPDCACHE_NLINE_WIDTH - HPDCACHE_MSHR_SET_WIDTH; + + typedef logic unsigned [HPDCACHE_MSHR_SET_WIDTH-1:0] mshr_set_t; + typedef logic unsigned [HPDCACHE_MSHR_TAG_WIDTH-1:0] mshr_tag_t; + typedef logic unsigned [HPDCACHE_MSHR_WAY_WIDTH-1:0] mshr_way_t; + // }}} + + // Definition of interface with memory + // {{{ + typedef logic [7:0] hpdcache_mem_len_t; + typedef logic [2:0] hpdcache_mem_size_t; + + typedef enum logic [1:0] { + HPDCACHE_MEM_RESP_OK = 2'b00, + HPDCACHE_MEM_RESP_NOK = 2'b01 + } hpdcache_mem_error_e; + + typedef enum logic [1:0] { + HPDCACHE_MEM_READ = 2'b00, + HPDCACHE_MEM_WRITE = 2'b01, + HPDCACHE_MEM_ATOMIC = 2'b10 + // Reserved = 2'b11 - TODO: CMO ? + } hpdcache_mem_command_e; + + typedef enum logic [3:0] { + HPDCACHE_MEM_ATOMIC_ADD = 4'b0000, + HPDCACHE_MEM_ATOMIC_CLR = 4'b0001, + HPDCACHE_MEM_ATOMIC_SET = 4'b0010, + HPDCACHE_MEM_ATOMIC_EOR = 4'b0011, + HPDCACHE_MEM_ATOMIC_SMAX = 4'b0100, + HPDCACHE_MEM_ATOMIC_SMIN = 4'b0101, + HPDCACHE_MEM_ATOMIC_UMAX = 4'b0110, + HPDCACHE_MEM_ATOMIC_UMIN = 4'b0111, + HPDCACHE_MEM_ATOMIC_SWAP = 4'b1000, + // Reserved = 4'b1001, + // Reserved = 4'b1010, + // Reserved = 4'b1011, + HPDCACHE_MEM_ATOMIC_LDEX = 4'b1100, + HPDCACHE_MEM_ATOMIC_STEX = 4'b1101 + // Reserved = 4'b1110, + // Reserved = 4'b1111 + } hpdcache_mem_atomic_e; + + function automatic hpdcache_mem_size_t get_hpdcache_mem_size(int unsigned bytes); + if (bytes == 0) return 0; + else if (bytes <= 2) return 1; + else if (bytes <= 4) return 2; + else if (bytes <= 8) return 3; + else if (bytes <= 16) return 4; + else if (bytes <= 32) return 5; + else if (bytes <= 64) return 6; + else if (bytes <= 128) return 7; + // pragma translate_off + else $error("hpdcache: unsupported number of bytes"); + // pragma translate_on + endfunction + // }}} + + // Definition of constants and types for the Write Buffer (WBUF) + // {{{ + localparam int unsigned HPDCACHE_WBUF_DIR_ENTRIES = + hpdcache_params_pkg::PARAM_WBUF_DIR_ENTRIES; + + localparam int unsigned HPDCACHE_WBUF_DATA_ENTRIES = + hpdcache_params_pkg::PARAM_WBUF_DATA_ENTRIES; + + localparam int unsigned HPDCACHE_WBUF_WORDS = + hpdcache_params_pkg::PARAM_WBUF_WORDS; + + localparam int unsigned HPDCACHE_WBUF_TIMECNT_WIDTH = + hpdcache_params_pkg::PARAM_WBUF_TIMECNT_WIDTH; + + localparam int unsigned HPDCACHE_WBUF_DATA_WIDTH = HPDCACHE_REQ_DATA_WIDTH* + HPDCACHE_WBUF_WORDS; + localparam int unsigned HPDCACHE_WBUF_DATA_PTR_WIDTH = $clog2(HPDCACHE_WBUF_DATA_ENTRIES); + localparam int unsigned HPDCACHE_WBUF_DIR_PTR_WIDTH = $clog2(HPDCACHE_WBUF_DIR_ENTRIES); + + typedef hpdcache_req_addr_t wbuf_addr_t; + typedef hpdcache_nline_t wbuf_match_t; + typedef hpdcache_req_data_t wbuf_data_t; + typedef hpdcache_req_be_t wbuf_be_t; + typedef wbuf_data_t[HPDCACHE_WBUF_WORDS-1:0] wbuf_data_buf_t; + typedef wbuf_be_t [HPDCACHE_WBUF_WORDS-1:0] wbuf_be_buf_t; + typedef logic unsigned [ HPDCACHE_WBUF_TIMECNT_WIDTH-1:0] wbuf_timecnt_t; + typedef logic unsigned [ HPDCACHE_WBUF_DIR_PTR_WIDTH-1:0] wbuf_dir_ptr_t; + typedef logic unsigned [HPDCACHE_WBUF_DATA_PTR_WIDTH-1:0] wbuf_data_ptr_t; + // }}} + + // Definition of constants and types for the Replay Table (RTAB) + // {{{ + localparam int HPDCACHE_RTAB_ENTRIES = hpdcache_params_pkg::PARAM_RTAB_ENTRIES; + + typedef logic [$clog2(HPDCACHE_RTAB_ENTRIES)-1:0] rtab_ptr_t; + // }}} + + // Definition of constants and types for the uncacheable request handler (UC) + // {{{ + typedef struct packed { + logic is_ld; + logic is_st; + logic is_amo_lr; + logic is_amo_sc; + logic is_amo_swap; + logic is_amo_add; + logic is_amo_and; + logic is_amo_or; + logic is_amo_xor; + logic is_amo_max; + logic is_amo_maxu; + logic is_amo_min; + logic is_amo_minu; + } hpdcache_uc_op_t; + // }}} + + // Definition of constants and types for the CMO request handler (CMOH) + // {{{ + typedef struct packed { + logic is_inval_by_nline; + logic is_inval_by_set; + logic is_inval_all; + logic is_fence; + } hpdcache_cmoh_op_t; + // }}} +endpackage diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_plru.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_plru.sv new file mode 100644 index 00000000000..7697737d684 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_plru.sv @@ -0,0 +1,138 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : May, 2021 + * Description : HPDcache Pseudo-LRU replacement policy + * History : + */ +module hpdcache_plru + // Parameters + // {{{ +#( + parameter int unsigned SETS = 0, + parameter int unsigned WAYS = 0, + + localparam type set_t = logic [$clog2(SETS)-1:0], + localparam type way_vector_t = logic [WAYS-1:0] +) + // }}} + + // Ports + // {{{ +( + input logic clk_i, + input logic rst_ni, + + // PLRU update interface + input logic updt_i, + input set_t updt_set_i, + input way_vector_t updt_way_i, + + // Victim replacement interface + input logic repl_i, + input set_t repl_set_i, + input way_vector_t repl_dir_valid_i, + input logic repl_updt_plru_i, + + output way_vector_t victim_way_o +); + // }}} + + // Internal signals and registers + // {{{ + way_vector_t [SETS-1:0] plru_q, plru_d; + way_vector_t updt_plru; + way_vector_t repl_plru; + way_vector_t used_victim_way, unused_victim_way; + // }}} + + // Victim way selection + // {{{ + hpdcache_prio_1hot_encoder #(.N(WAYS)) + used_victim_select_i ( + .val_i (~plru_q[repl_set_i]), + .val_o (used_victim_way) + ); + + hpdcache_prio_1hot_encoder #(.N(WAYS)) + unused_victim_select_i ( + .val_i (~repl_dir_valid_i), + .val_o (unused_victim_way) + ); + + // If there is a free entry in the directory (valid == 0), choose it as victim + assign victim_way_o = |unused_victim_way ? unused_victim_way : used_victim_way; + // }}} + + // Pseudo-LRU update process + // {{{ + assign updt_plru = plru_q[updt_set_i] | updt_way_i; + assign repl_plru = plru_q[repl_set_i] | victim_way_o; + + always_comb + begin : plru_update_comb + plru_d = plru_q; + + case (1'b1) + // When replacing a cache-line, set the PLRU bit of the new line + repl_i: + if (repl_updt_plru_i) begin + // If all PLRU bits of a given would be set, reset them all + // but the currently accessed way + if (&repl_plru) begin + plru_d[repl_set_i] = victim_way_o; + end else begin + plru_d[repl_set_i] = repl_plru; + end + end + + // When accessing a cache-line, set the corresponding PLRU bit + updt_i: + // If all PLRU bits of a given would be set, reset them all + // but the currently accessed way + if (&updt_plru) begin + plru_d[updt_set_i] = updt_way_i; + end else begin + plru_d[updt_set_i] = updt_plru; + end + + default: begin + // do nothing + end + endcase + end + // }}} + + // Set state process + // {{{ + always_ff @(posedge clk_i or negedge rst_ni) + begin : lru_ff + if (!rst_ni) begin + plru_q <= '0; + end else begin + if (updt_i || repl_i) begin + plru_q <= plru_d; + end + end + end + // }}} + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_rtab.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_rtab.sv new file mode 100755 index 00000000000..6df18bc2878 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_rtab.sv @@ -0,0 +1,666 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : September, 2021 + * Description : HPDcache Replay Table + * History : + */ +module hpdcache_rtab +import hpdcache_pkg::*; +// Parameters +// {{{ +#( + parameter type rtab_entry_t = logic +) +// }}} +// Ports +// {{{ +( + // Clock and reset signals + input logic clk_i, + input logic rst_ni, + + // Global control signals + output logic empty_o, // RTAB is empty + output logic full_o, // RTAB is full + + // Check RTAB signals + // This interface allows to check if there is an address-overlapping + // request in the RTAB with respect to the given nline. + input logic check_i, // Check for hit (nline) in the RTAB + input hpdcache_nline_t check_nline_i, + output logic check_hit_o, + + // Allocate signals + // This interface allows to allocate a new request in a new linked list + input logic alloc_i, + input logic alloc_and_link_i, + input rtab_entry_t alloc_req_i, + input logic alloc_mshr_hit_i, + input logic alloc_mshr_full_i, + input logic alloc_mshr_ready_i, + input logic alloc_wbuf_hit_i, + input logic alloc_wbuf_not_ready_i, + + // Pop signals + // This interface allows to read (and remove) a request from the RTAB + output logic pop_try_valid_o, // Request ready to be replayed + input logic pop_try_i, + output rtab_entry_t pop_try_req_o, + output rtab_ptr_t pop_try_ptr_o, + + // Pop Commit signals + // This interface allows to actually remove a popped request + input logic pop_commit_i, + input rtab_ptr_t pop_commit_ptr_i, + + // Pop Rollback signals + // This interface allows to put back a popped request + input logic pop_rback_i, + input rtab_ptr_t pop_rback_ptr_i, + input logic pop_rback_mshr_hit_i, + input logic pop_rback_mshr_full_i, + input logic pop_rback_mshr_ready_i, + input logic pop_rback_wbuf_hit_i, + input logic pop_rback_wbuf_not_ready_i, + + + // Control signals from/to WBUF + output hpdcache_req_addr_t wbuf_addr_o, // address to check against ongoing writes + output logic wbuf_is_read_o, // monitored request is read + input logic wbuf_hit_open_i, // Hit on open entry in the write buf + input logic wbuf_hit_pend_i, // Hit on pend entry in the write buf + input logic wbuf_hit_sent_i, // Hit on sent entry in the write buf + input logic wbuf_not_ready_i, // Write buffer cannot accept the write + + // Control signals from the Miss Handler + input logic miss_ready_i, // Miss Handler is ready + + // Control signals from the Refill Handler + input logic refill_i, // Active refill + input hpdcache_nline_t refill_nline_i, // Cache-line index being refilled + + // Configuration parameters + input logic cfg_single_entry_i // Enable only one entry of the table +); +// }}} + +// Definition of constants, types and functions +// {{{ + localparam int N = HPDCACHE_RTAB_ENTRIES; + + function automatic rtab_ptr_t rtab_bv_to_index( + input logic [N-1:0] bv); + for (int i = 0; i < N; i++) begin + if (bv[i]) return rtab_ptr_t'(i); + end + return 0; + endfunction + + function automatic logic [N-1:0] rtab_index_to_bv( + input rtab_ptr_t index); + logic [N-1:0] bv; + + for (int i = 0; i < N; i++) begin + bv[i] = (rtab_ptr_t'(i) == index); + end + return bv; + endfunction + + function automatic bit rtab_mshr_set_equal( + input hpdcache_nline_t x, + input hpdcache_nline_t y); + return (x[0 +: HPDCACHE_MSHR_SET_WIDTH] == y[0 +: HPDCACHE_MSHR_SET_WIDTH]); + endfunction + + function automatic logic [N-1:0] rtab_next(rtab_ptr_t [N-1:0] next, rtab_ptr_t x); + return rtab_index_to_bv(next[x]); + endfunction + + typedef enum { + POP_TRY_HEAD, + POP_TRY_NEXT, + POP_TRY_NEXT_WAIT + } rtab_pop_try_state_e; +// }}} + +// Internal signals and registers +// {{{ + rtab_entry_t [N-1:0] req_q; + rtab_ptr_t [N-1:0] next_q; + + rtab_pop_try_state_e pop_try_state_q, pop_try_state_d; + logic [N-1:0] pop_try_next_q, pop_try_next_d; + + logic [N-1:0] valid_q; + logic [N-1:0] valid_set, valid_rst; + logic [N-1:0] alloc_valid_set; + logic [N-1:0] pop_commit_valid_rst; + + // Bits indicating if the corresponding entry is the head of a linked list + logic [N-1:0] head_q; + logic [N-1:0] head_set, head_rst; + logic [N-1:0] alloc_head_set, alloc_head_rst; + logic [N-1:0] pop_try_head_rst; + logic [N-1:0] pop_commit_head_set; + logic [N-1:0] pop_rback_head_set; + + // Bits indicating if the corresponding entry is the tail of a linked list + logic [N-1:0] tail_q; + logic [N-1:0] tail_set, tail_rst; + logic [N-1:0] alloc_tail_set, alloc_tail_rst; + + // There is a pend ing miss on the target nline + logic [N-1:0] deps_mshr_hit_q; + logic [N-1:0] deps_mshr_hit_set, deps_mshr_hit_rst; + logic [N-1:0] alloc_deps_mshr_hit_set; + logic [N-1:0] pop_rback_deps_mshr_hit_set; + + // The MSHR has no available slot for the new miss + logic [N-1:0] deps_mshr_full_q; + logic [N-1:0] deps_mshr_full_set, deps_mshr_full_rst; + logic [N-1:0] alloc_deps_mshr_full_set; + logic [N-1:0] pop_rback_deps_mshr_full_set; + + // The MSHR is not ready to send a new miss requests + logic [N-1:0] deps_mshr_ready_q; + logic [N-1:0] deps_mshr_ready_set, deps_mshr_ready_rst; + logic [N-1:0] alloc_deps_mshr_ready_set; + logic [N-1:0] pop_rback_deps_mshr_ready_set; + + // Hit on an non-e mpty entry of the write buffer + logic [N-1:0] deps_wbuf_hit_q; + logic [N-1:0] deps_wbuf_hit_set, deps_wbuf_hit_rst; + logic [N-1:0] alloc_deps_wbuf_hit_set; + logic [N-1:0] pop_rback_deps_wbuf_hit_set; + + // Hit on a pend entry of the write buffer + logic [N-1:0] deps_wbuf_not_ready_q; + logic [N-1:0] deps_wbuf_not_ready_set, deps_wbuf_not_ready_rst; + logic [N-1:0] alloc_deps_wbuf_not_ready_set; + logic [N-1:0] pop_rback_deps_wbuf_not_ready_set; + + logic [N-1:0] nodeps; + hpdcache_nline_t [N-1:0] nline; + hpdcache_req_addr_t [N-1:0] addr; + logic [N-1:0] is_read; + logic [N-1:0] check_hit; + logic [N-1:0] match_check_nline; + logic [N-1:0] match_check_tail; + logic [N-1:0] match_refill_nline; + logic [N-1:0] match_refill_mshr_set; + + logic [N-1:0] free; + logic [N-1:0] free_alloc; + logic alloc; + + logic [N-1:0] pop_match_next; + logic [N-1:0] pop_rback_ptr_bv; + logic [N-1:0] pop_try_bv; + logic [N-1:0] ready; + + genvar gen_i; +// }}} + +// Compute global control signals +// {{{ + // compute if entries are ready to be replayed + assign nodeps = ~(deps_mshr_hit_q | + deps_mshr_full_q | + deps_mshr_ready_q | + deps_wbuf_hit_q | + deps_wbuf_not_ready_q); + + assign ready = valid_q & head_q & nodeps; + + assign free = ~valid_q; + + // compute the free vector (one-hot signal) + hpdcache_prio_1hot_encoder #( + .N (N) + ) free_encoder_i ( + .val_i (free), + .val_o (free_alloc) + ); + + // full and empty signals + assign empty_o = &(~valid_q); + assign full_o = &( valid_q) | (|valid_q & cfg_single_entry_i); +// }}} + +// Check interface +// {{{ + generate + for (gen_i = 0; gen_i < N; gen_i++) begin : check_gen + assign addr[gen_i] = {req_q[gen_i].addr_tag, req_q[gen_i].addr_offset}, + nline[gen_i] = hpdcache_get_req_addr_nline(addr[gen_i]), + match_check_nline[gen_i] = (check_nline_i == nline[gen_i]); + + assign is_read[gen_i] = is_load(req_q[gen_i].op) | + is_cmo_prefetch(req_q[gen_i].op, req_q[gen_i].size); + end + endgenerate + + assign check_hit = valid_q & match_check_nline, + check_hit_o = |check_hit, + match_check_tail = check_hit & tail_q; +// }}} + +// Allocation process +// {{{ + assign alloc = alloc_i | alloc_and_link_i; + + // Set the valid bit-vector of the replay table + assign alloc_valid_set = free_alloc & {N{alloc}}; + + // Set of head and tail bit-vectors during an allocation + // - The head bit is only set when creating a new linked-list + // - The tail bit is always set because new requests are added on the tail. + assign alloc_head_set = free_alloc & {N{alloc_i}}, + alloc_tail_set = alloc_valid_set; + + // Reset of head and tail bit-vectors during an allocation + // - When doing an allocation and link, head bit shall be reset + // - when doing an allocation and link, the "prev" tail shall be reset + assign alloc_head_rst = free_alloc & {N{alloc_and_link_i}}, + alloc_tail_rst = match_check_tail & {N{alloc_and_link_i}}; + + // Set the dependency bits for the allocated entry + assign alloc_deps_mshr_hit_set = alloc_valid_set & {N{ alloc_mshr_hit_i}}, + alloc_deps_mshr_full_set = alloc_valid_set & {N{ alloc_mshr_full_i}}, + alloc_deps_mshr_ready_set = alloc_valid_set & {N{ alloc_mshr_ready_i}}, + alloc_deps_wbuf_hit_set = alloc_valid_set & {N{ alloc_wbuf_hit_i}}, + alloc_deps_wbuf_not_ready_set = alloc_valid_set & {N{alloc_wbuf_not_ready_i}}; +// }}} + +// Update replay table dependencies +// {{{ + // Update write buffer hit dependencies + // {{{ + // Build a bit-vector with HEAD requests waiting for a conflict in the wbuf + logic [N-1:0] wbuf_rd_pending, wbuf_wr_pending; + logic [N-1:0] wbuf_rd_gnt, wbuf_wr_gnt; + logic [ 1:0] wbuf_pending; + logic [ 1:0] wbuf_gnt; + logic wbuf_ready; + logic [N-1:0] wbuf_sel; + + assign wbuf_rd_pending = valid_q & head_q & deps_wbuf_hit_q, + wbuf_wr_pending = valid_q & head_q & deps_wbuf_not_ready_q; + + // Choose in a round-robin manner a ready transaction waiting for a conflict in the wbuf + hpdcache_rrarb #( + .N (N) + ) wbuf_rd_pending_arb_i ( + .clk_i, + .rst_ni, + .req_i (wbuf_rd_pending), + .gnt_o (wbuf_rd_gnt), + .ready_i (wbuf_gnt[0] & wbuf_ready) + ); + + hpdcache_rrarb #( + .N (N) + ) wbuf_wr_pending_arb_i ( + .clk_i, + .rst_ni, + .req_i (wbuf_wr_pending), + .gnt_o (wbuf_wr_gnt), + .ready_i (wbuf_gnt[1] & wbuf_ready) + ); + + assign wbuf_pending = {|wbuf_wr_gnt, |wbuf_rd_gnt}, + wbuf_ready = |(pop_try_bv & (wbuf_rd_gnt | wbuf_wr_gnt)); + + hpdcache_fxarb #( + .N (2) + ) wbuf_pending_arb_i ( + .clk_i, + .rst_ni, + .req_i (wbuf_pending), + .gnt_o (wbuf_gnt), + .ready_i (wbuf_ready) + ); + + assign wbuf_sel = wbuf_gnt[0] ? wbuf_rd_gnt : + wbuf_gnt[1] ? wbuf_wr_gnt : '0; + + hpdcache_mux #( + .NINPUT (N), + .DATA_WIDTH ($bits(hpdcache_req_addr_t)), + .ONE_HOT_SEL (1'b1) + ) wbuf_pending_addr_mux_i ( + .data_i (addr), + .sel_i (wbuf_sel), + .data_o (wbuf_addr_o) + ); + + hpdcache_mux #( + .NINPUT (N), + .DATA_WIDTH (1), + .ONE_HOT_SEL (1'b1) + ) wbuf_pending_is_read_mux_i ( + .data_i (is_read), + .sel_i (wbuf_sel), + .data_o (wbuf_is_read_o) + ); + + // reset write buffer dependency bits with the output from the write buffer + assign deps_wbuf_hit_rst = + wbuf_sel & ~{N{wbuf_hit_open_i | wbuf_hit_pend_i | wbuf_hit_sent_i}}; + assign deps_wbuf_not_ready_rst = + wbuf_sel & ~{N{wbuf_not_ready_i}}; + // }}} + + // Update miss handler dependency + // {{{ + assign deps_mshr_ready_rst = {N{miss_ready_i}}; + // }}} + + // Update refill dependencies + // {{{ + generate + for (gen_i = 0; gen_i < N; gen_i++) begin : match_refill_gen + assign match_refill_mshr_set[gen_i] = + rtab_mshr_set_equal(refill_nline_i, nline[gen_i]); + assign match_refill_nline[gen_i] = + (refill_nline_i == nline[gen_i]); + end + endgenerate + + assign deps_mshr_full_rst = {N{refill_i}} & match_refill_mshr_set; + assign deps_mshr_hit_rst = {N{refill_i}} & match_refill_nline; + // }}} +// }}} + +// Pop interface +// {{{ + logic [N-1:0] pop_sel; + logic [N-1:0] pop_commit_bv; + + assign pop_commit_bv = rtab_index_to_bv(pop_commit_ptr_i); + + // Pop try process + // {{{ + logic [N-1:0] pop_gnt; + logic pop_head; + + hpdcache_rrarb #( + .N (N) + ) pop_arb_i ( + .clk_i, + .rst_ni, + .req_i (ready), + .gnt_o (pop_gnt), + .ready_i (pop_head) + ); + + always_comb + begin : req_valid_comb + case(pop_try_state_q) + POP_TRY_HEAD : pop_try_valid_o = |ready; + POP_TRY_NEXT : pop_try_valid_o = 1'b1; + POP_TRY_NEXT_WAIT: pop_try_valid_o = 1'b1; + default : pop_try_valid_o = 1'b0; + endcase + end + + always_comb + begin : pop_entry_sel_comb + pop_try_state_d = pop_try_state_q; + pop_try_next_d = pop_try_next_q; + pop_head = 1'b0; + pop_sel = '0; + + case (pop_try_state_q) + POP_TRY_HEAD: begin + // This FSM may be in this state after forwarding the tail of + // a list. In that case, a rollback may arrive in this cycle. + pop_sel = pop_gnt; + if (!pop_rback_i && pop_try_valid_o) begin + if (pop_try_i) begin + // If the request interface accepts the request, go to the next request + // in the list (if the current request is not the tail). Otherwise, stay in + // the same state to to forward a request from a new list + pop_head = 1'b1; + if ((pop_gnt & ~tail_q) != 0) begin + pop_try_state_d = POP_TRY_NEXT; + pop_try_next_d = rtab_next(next_q, pop_try_ptr_o); + end + end + end + end + POP_TRY_NEXT: begin + pop_sel = pop_try_next_q; + if (pop_rback_i) begin + pop_try_state_d = POP_TRY_HEAD; + end else begin + if (pop_try_i) begin + // If the request interface accepts the new request, go to the next request + // in the list (if the current request is not the tail). Otherwise, return + // to the POP_TRY_HEAD state to forward a request from a new list + if ((pop_try_next_q & ~tail_q) != 0) begin + pop_try_state_d = POP_TRY_NEXT; + pop_try_next_d = rtab_next(next_q, pop_try_ptr_o); + end else begin + pop_try_state_d = POP_TRY_HEAD; + end + end else begin + // If the request interface is not ready to consume the new request, wait + // until it is + pop_try_state_d = POP_TRY_NEXT_WAIT; + end + end + end + POP_TRY_NEXT_WAIT: begin + // Wait for the current request to be accepted. Then go to the next request in the + // list or to a new list + pop_sel = pop_try_next_q; + if (pop_try_i) begin + if ((pop_try_next_q & ~tail_q) != 0) begin + pop_try_state_d = POP_TRY_NEXT; + pop_try_next_d = rtab_next(next_q, pop_try_ptr_o); + end else begin + pop_try_state_d = POP_TRY_HEAD; + end + end + end + default: begin + end + endcase + end + + assign pop_commit_head_set = '0; + + hpdcache_mux #( + .NINPUT (N), + .DATA_WIDTH ($bits(rtab_entry_t)), + .ONE_HOT_SEL (1'b1) + ) pop_mux_i ( + .data_i (req_q), + .sel_i (pop_sel), + .data_o (pop_try_req_o) + ); + + // Temporarily unset the head bit of the popped request to prevent it to be rescheduled + assign pop_try_bv = pop_sel & {N{pop_try_i}}, + pop_try_head_rst = pop_try_bv; + + + // Forward the index of the entry being popped. This is used later by the + // commit or rollback operations + assign pop_try_ptr_o = rtab_bv_to_index(pop_sel); + + // }}} + + // Pop commit process + // {{{ + // Invalidate the entry being popped (head of the linked list) + assign pop_commit_valid_rst = {N{pop_commit_i}} & rtab_index_to_bv(pop_commit_ptr_i); + // }}} + + // Pop rollback process + // {{{ + // Set again the head bit of the rolled-back request + assign pop_rback_ptr_bv = rtab_index_to_bv(pop_rback_ptr_i); + + assign pop_rback_head_set = {N{pop_rback_i}} & pop_rback_ptr_bv; + + assign pop_rback_deps_mshr_hit_set = {N{pop_rback_i}} & pop_rback_ptr_bv & {N{pop_rback_mshr_hit_i}}, + pop_rback_deps_mshr_full_set = {N{pop_rback_i}} & pop_rback_ptr_bv & {N{pop_rback_mshr_full_i}}, + pop_rback_deps_mshr_ready_set = {N{pop_rback_i}} & pop_rback_ptr_bv & {N{pop_rback_mshr_ready_i}}, + pop_rback_deps_wbuf_hit_set = {N{pop_rback_i}} & pop_rback_ptr_bv & {N{pop_rback_wbuf_hit_i}}, + pop_rback_deps_wbuf_not_ready_set = {N{pop_rback_i}} & pop_rback_ptr_bv & {N{pop_rback_wbuf_not_ready_i}}; + // }}} +// }}} + +// Internal state assignment +// {{{ + assign head_set = alloc_head_set | pop_commit_head_set | pop_rback_head_set, + head_rst = alloc_head_rst | pop_try_head_rst; + + assign tail_set = alloc_tail_set, + tail_rst = alloc_tail_rst; + + assign valid_set = alloc_valid_set, + valid_rst = pop_commit_valid_rst; + + assign deps_mshr_hit_set = alloc_deps_mshr_hit_set | pop_rback_deps_mshr_hit_set, + deps_mshr_full_set = alloc_deps_mshr_full_set | pop_rback_deps_mshr_full_set, + deps_mshr_ready_set = alloc_deps_mshr_ready_set | pop_rback_deps_mshr_ready_set, + deps_wbuf_hit_set = alloc_deps_wbuf_hit_set | pop_rback_deps_wbuf_hit_set, + deps_wbuf_not_ready_set = alloc_deps_wbuf_not_ready_set | pop_rback_deps_wbuf_not_ready_set; + + always_ff @(posedge clk_i or negedge rst_ni) + begin : rtab_valid_ff + if (!rst_ni) begin + valid_q <= '0; + head_q <= '0; + tail_q <= '0; + deps_mshr_hit_q <= '0; + deps_mshr_full_q <= '0; + deps_mshr_ready_q <= '0; + deps_wbuf_hit_q <= '0; + deps_wbuf_not_ready_q <= '0; + next_q <= '0; + end else begin + valid_q <= (~valid_q & valid_set) | + ( valid_q & ~valid_rst); + + // update head and tail flags + head_q <= (~head_q & head_set) | + ( head_q & ~head_rst); + + tail_q <= (~tail_q & tail_set) | + ( tail_q & ~tail_rst); + + // update dependency flags + deps_mshr_hit_q <= (~deps_mshr_hit_q & deps_mshr_hit_set) | + ( deps_mshr_hit_q & ~deps_mshr_hit_rst); + deps_mshr_full_q <= (~deps_mshr_full_q & deps_mshr_full_set) | + ( deps_mshr_full_q & ~deps_mshr_full_rst); + deps_mshr_ready_q <= (~deps_mshr_ready_q & deps_mshr_ready_set) | + ( deps_mshr_ready_q & ~deps_mshr_ready_rst); + deps_wbuf_hit_q <= (~deps_wbuf_hit_q & deps_wbuf_hit_set) | + ( deps_wbuf_hit_q & ~deps_wbuf_hit_rst); + deps_wbuf_not_ready_q <= (~deps_wbuf_not_ready_q & deps_wbuf_not_ready_set) | + ( deps_wbuf_not_ready_q & ~deps_wbuf_not_ready_rst); + + // update the next pointers + for (int i = 0; i < N; i++) begin + if (alloc_and_link_i && match_check_tail[i]) begin + next_q[i] <= rtab_bv_to_index(free_alloc); + end + end + end + end + + always_ff @(posedge clk_i or negedge rst_ni) + begin : pop_try_ff + if (!rst_ni) begin + pop_try_state_q <= POP_TRY_HEAD; + pop_try_next_q <= '0; + end else begin + pop_try_state_q <= pop_try_state_d; + pop_try_next_q <= pop_try_next_d; + end + end + + always_ff @(posedge clk_i) + begin : rtab_ff + for (int i = 0; i < N; i++) begin + // update the request array + if (valid_set[i]) begin + req_q[i] <= alloc_req_i; + end + end + end +// }}} + +// Assertions +// {{{ +// pragma translate_off + assert property (@(posedge clk_i) + check_i |-> $onehot0(match_check_tail)) else + $error("rtab: more than one entry matching"); + + assert property (@(posedge clk_i) + alloc_and_link_i |-> (check_i & check_hit_o)) else + $error("rtab: alloc and link shall be performed in case of check hit"); + + assert property (@(posedge clk_i) + alloc_and_link_i |-> + ({alloc_req_i.addr_tag, hpdcache_get_req_offset_set(alloc_req_i.addr_offset)} == + check_nline_i)) else + $error("rtab: nline for alloc and link shall match the one being checked"); + + assert property (@(posedge clk_i) + alloc_i |-> !alloc_and_link_i) else + $error("rtab: only one allocation per cycle is allowed"); + +`ifndef VERILATOR + assert property (@(posedge clk_i) + pop_try_i |-> ##1 (pop_commit_i | pop_rback_i)) else + $error("rtab: a pop try shall be followed by a commit or rollback"); +`endif + + assert property (@(posedge clk_i) + pop_commit_i |-> valid_q[pop_commit_ptr_i]) else + $error("rtab: commiting an invalid entry"); + + assert property (@(posedge clk_i) + pop_rback_i |-> valid_q[pop_rback_ptr_i]) else + $error("rtab: rolling-back an invalid entry"); + + assert property (@(posedge clk_i) + pop_rback_i |-> !pop_try_i) else + $error("rtab: cache shall not accept a new request while rolling back"); + + assert property (@(posedge clk_i) + alloc |-> ~full_o) else + $error("rtab: trying to allocate while the table is full"); + + assert property (@(posedge clk_i) + alloc_and_link_i |-> ~cfg_single_entry_i) else + $error("rtab: trying to link a request in single entry mode"); +// pragma translate_on +// }}} +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_uncached.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_uncached.sv new file mode 100644 index 00000000000..ba449dc1be2 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_uncached.sv @@ -0,0 +1,965 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : May, 2021 + * Description : HPDcache uncached and AMO request handler + * History : + */ +module hpdcache_uncached +import hpdcache_pkg::*; + // Parameters + // {{{ +#( + parameter int HPDcacheMemIdWidth = 8, + parameter int HPDcacheMemDataWidth = 512, + parameter type hpdcache_mem_req_t = logic, + parameter type hpdcache_mem_req_w_t = logic, + parameter type hpdcache_mem_resp_r_t = logic, + parameter type hpdcache_mem_resp_w_t = logic, + + localparam type hpdcache_mem_id_t = logic [HPDcacheMemIdWidth-1:0] +) + // }}} +// Ports +// {{{ +( + input logic clk_i, + input logic rst_ni, + + // Global control signals + // {{{ + input logic wbuf_empty_i, + input logic mshr_empty_i, + input logic rtab_empty_i, + input logic ctrl_empty_i, + // }}} + + // Cache-side request interface + // {{{ + input logic req_valid_i, + output logic req_ready_o, + input hpdcache_uc_op_t req_op_i, + input hpdcache_req_addr_t req_addr_i, + input hpdcache_req_size_t req_size_i, + input hpdcache_req_data_t req_data_i, + input hpdcache_req_be_t req_be_i, + input logic req_uc_i, + input hpdcache_req_sid_t req_sid_i, + input hpdcache_req_tid_t req_tid_i, + input logic req_need_rsp_i, + // }}} + + // Write buffer interface + // {{{ + output logic wbuf_flush_all_o, + // }}} + + // AMO Cache Interface + // {{{ + output logic dir_amo_match_o, + output hpdcache_set_t dir_amo_match_set_o, + output hpdcache_tag_t dir_amo_match_tag_o, + output logic dir_amo_update_plru_o, + input hpdcache_way_vector_t dir_amo_hit_way_i, + + output logic data_amo_write_o, + output logic data_amo_write_enable_o, + output hpdcache_set_t data_amo_write_set_o, + output hpdcache_req_size_t data_amo_write_size_o, + output hpdcache_word_t data_amo_write_word_o, + output logic [63:0] data_amo_write_data_o, + output logic [7:0] data_amo_write_be_o, + // }}} + + // LR/SC reservation buffer + // {{{ + input logic lrsc_snoop_i, + input hpdcache_req_addr_t lrsc_snoop_addr_i, + input hpdcache_req_size_t lrsc_snoop_size_i, + // }}} + + // Core response interface + // {{{ + input logic core_rsp_ready_i, + output logic core_rsp_valid_o, + output hpdcache_rsp_t core_rsp_o, + // }}} + + // MEMORY interfaces + // {{{ + // Memory request unique identifier + input hpdcache_mem_id_t mem_read_id_i, + input hpdcache_mem_id_t mem_write_id_i, + + // Read interface + input logic mem_req_read_ready_i, + output logic mem_req_read_valid_o, + output hpdcache_mem_req_t mem_req_read_o, + + output logic mem_resp_read_ready_o, + input logic mem_resp_read_valid_i, + input hpdcache_mem_resp_r_t mem_resp_read_i, + + // Write interface + input logic mem_req_write_ready_i, + output logic mem_req_write_valid_o, + output hpdcache_mem_req_t mem_req_write_o, + + input logic mem_req_write_data_ready_i, + output logic mem_req_write_data_valid_o, + output hpdcache_mem_req_w_t mem_req_write_data_o, + + output logic mem_resp_write_ready_o, + input logic mem_resp_write_valid_i, + input hpdcache_mem_resp_w_t mem_resp_write_i, + // }}} + + // Configuration interface + // {{{ + input logic cfg_error_on_cacheable_amo_i + // }}} +); +// }}} + +// Definition of constants and types +// {{{ + localparam hpdcache_uint MEM_REQ_RATIO = HPDcacheMemDataWidth/HPDCACHE_REQ_DATA_WIDTH; + localparam hpdcache_uint MEM_REQ_WORD_INDEX_WIDTH = $clog2(MEM_REQ_RATIO); + + typedef enum { + UC_IDLE, + UC_WAIT_PENDING, + UC_MEM_REQ, + UC_MEM_W_REQ, + UC_MEM_WDATA_REQ, + UC_MEM_WAIT_RSP, + UC_CORE_RSP, + UC_AMO_READ_DIR, + UC_AMO_WRITE_DATA + } hpdcache_uc_fsm_t; + + localparam logic AMO_SC_SUCCESS = 1'b0; + localparam logic AMO_SC_FAILURE = 1'b1; + + function automatic logic [63:0] prepare_amo_data_operand( + input logic [63:0] data_i, + input hpdcache_req_size_t size_i, + input hpdcache_req_addr_t addr_i, + input logic sign_extend_i + ); + // 64-bits AMOs are already aligned, thus do nothing + if (size_i == hpdcache_req_size_t'(3)) begin + return data_i; + end + + // 32-bits AMOs + else begin + if (addr_i[2] == 1'b1) begin + if (sign_extend_i) begin + return {{32{data_i[63]}}, data_i[63:32]}; + end else begin + return {{32{ 1'b0}}, data_i[63:32]}; + end + end else begin + if (sign_extend_i) begin + return {{32{data_i[31]}}, data_i[31: 0]}; + end else begin + return {{32{ 1'b0}}, data_i[31: 0]}; + end + end + end + endfunction; + + function automatic logic [63:0] prepare_amo_data_result( + input logic [63:0] data_i, + input hpdcache_req_size_t size_i + ); + // 64-bits AMOs are already aligned, thus do nothing + if (size_i == hpdcache_req_size_t'(3)) begin + return data_i; + end + + // 32-bits AMOs + else begin + return {2{data_i[31:0]}}; + end + endfunction; + + function automatic logic amo_need_sign_extend(hpdcache_uc_op_t op); + unique case (1'b1) + op.is_amo_add, + op.is_amo_max, + op.is_amo_min: return 1'b1; + default : return 1'b0; + endcase; + endfunction +// }}} + +// Internal signals and registers +// {{{ + hpdcache_uc_fsm_t uc_fsm_q, uc_fsm_d; + hpdcache_uc_op_t req_op_q; + hpdcache_req_addr_t req_addr_q; + hpdcache_req_size_t req_size_q; + hpdcache_req_data_t req_data_q; + hpdcache_req_be_t req_be_q; + logic req_uc_q; + hpdcache_req_sid_t req_sid_q; + hpdcache_req_tid_t req_tid_q; + logic req_need_rsp_q; + + logic uc_sc_retcode_q, uc_sc_retcode_d; + + hpdcache_req_data_t rsp_rdata_q, rsp_rdata_d; + logic rsp_error_set, rsp_error_rst; + logic rsp_error_q; + logic mem_resp_write_valid_q, mem_resp_write_valid_d; + logic mem_resp_read_valid_q, mem_resp_read_valid_d; + + hpdcache_req_data_t mem_req_write_data; + logic [63:0] amo_req_ld_data; + logic [63:0] amo_ld_data; + logic [63:0] amo_req_st_data; + logic [63:0] amo_st_data; + logic [ 7:0] amo_st_be; + logic [63:0] amo_result; +// }}} + +// LR/SC reservation buffer logic +// {{{ + logic lrsc_rsrv_valid_q; + hpdcache_req_addr_t lrsc_rsrv_addr_q, lrsc_rsrv_addr_d; + hpdcache_nline_t lrsc_rsrv_nline; + hpdcache_offset_t lrsc_rsrv_word; + + hpdcache_offset_t lrsc_snoop_words; + hpdcache_nline_t lrsc_snoop_nline; + hpdcache_offset_t lrsc_snoop_base, lrsc_snoop_end; + logic lrsc_snoop_hit; + logic lrsc_snoop_reset; + + hpdcache_nline_t lrsc_uc_nline; + hpdcache_offset_t lrsc_uc_word; + logic lrsc_uc_hit; + logic lrsc_uc_set, lrsc_uc_reset; + + // NOTE: Reservation set for LR instruction is always 8-bytes in this + // implementation. + assign lrsc_rsrv_nline = hpdcache_get_req_addr_nline(lrsc_rsrv_addr_q), + lrsc_rsrv_word = hpdcache_get_req_addr_offset(lrsc_rsrv_addr_q) >> 3; + + // Check hit on LR/SC reservation for snoop port (normal write accesses) + assign lrsc_snoop_words = (lrsc_snoop_size_i < 3) ? 1 : hpdcache_offset_t'((8'h1 << lrsc_snoop_size_i) >> 3), + lrsc_snoop_nline = hpdcache_get_req_addr_nline(lrsc_snoop_addr_i), + lrsc_snoop_base = hpdcache_get_req_addr_offset(lrsc_snoop_addr_i) >> 3, + lrsc_snoop_end = lrsc_snoop_base + lrsc_snoop_words; + + assign lrsc_snoop_hit = lrsc_rsrv_valid_q & (lrsc_rsrv_nline == lrsc_snoop_nline) & + (lrsc_rsrv_word >= lrsc_snoop_base) & + (lrsc_rsrv_word < lrsc_snoop_end ); + + assign lrsc_snoop_reset = lrsc_snoop_i & lrsc_snoop_hit; + + // Check hit on LR/SC reservation for AMOs and SC + assign lrsc_uc_nline = hpdcache_get_req_addr_nline(req_addr_i), + lrsc_uc_word = hpdcache_get_req_addr_offset(req_addr_i) >> 3; + + assign lrsc_uc_hit = lrsc_rsrv_valid_q & (lrsc_rsrv_nline == lrsc_uc_nline) & + (lrsc_rsrv_word == lrsc_uc_word); +// }}} + +// Uncacheable request FSM +// {{{ + always_comb + begin : uc_fsm_comb + mem_resp_write_valid_d = mem_resp_write_valid_q; + mem_resp_read_valid_d = mem_resp_read_valid_q; + rsp_error_set = 1'b0; + rsp_error_rst = 1'b0; + lrsc_rsrv_addr_d = lrsc_rsrv_addr_q; + uc_sc_retcode_d = uc_sc_retcode_q; + wbuf_flush_all_o = 1'b0; + lrsc_uc_set = 1'b0; + lrsc_uc_reset = 1'b0; + + uc_fsm_d = uc_fsm_q; + + case (uc_fsm_q) + // Wait for a request + // {{{ + UC_IDLE: begin + + if (req_valid_i) begin + wbuf_flush_all_o = 1'b1; + + unique case (1'b1) + req_op_i.is_ld, + req_op_i.is_st: begin + if (wbuf_empty_i && mshr_empty_i && rtab_empty_i && ctrl_empty_i) begin + uc_fsm_d = UC_MEM_REQ; + end else begin + uc_fsm_d = UC_WAIT_PENDING; + end + end + + req_op_i.is_amo_swap, + req_op_i.is_amo_add, + req_op_i.is_amo_and, + req_op_i.is_amo_or, + req_op_i.is_amo_xor, + req_op_i.is_amo_max, + req_op_i.is_amo_maxu, + req_op_i.is_amo_min, + req_op_i.is_amo_minu, + req_op_i.is_amo_lr: begin + // Reset LR/SC reservation if AMO matches its address + lrsc_uc_reset = ~req_op_i.is_amo_lr & lrsc_uc_hit; + + if (!req_uc_i && cfg_error_on_cacheable_amo_i) begin + rsp_error_set = 1'b1; + uc_fsm_d = UC_CORE_RSP; + end else begin + if (wbuf_empty_i && mshr_empty_i && rtab_empty_i && ctrl_empty_i) begin + uc_fsm_d = UC_MEM_REQ; + end else begin + uc_fsm_d = UC_WAIT_PENDING; + end + end + end + + req_op_i.is_amo_sc: begin + if (!req_uc_i && cfg_error_on_cacheable_amo_i) begin + rsp_error_set = 1'b1; + uc_fsm_d = UC_CORE_RSP; + end else begin + // Reset previous reservation (if any) + lrsc_uc_reset = 1'b1; + + // SC with valid reservation + if (lrsc_uc_hit) begin + if (wbuf_empty_i && mshr_empty_i && rtab_empty_i && ctrl_empty_i) begin + uc_fsm_d = UC_MEM_REQ; + end else begin + uc_fsm_d = UC_WAIT_PENDING; + end + end + // SC with no valid reservation, thus respond with the failure code + else begin + uc_sc_retcode_d = AMO_SC_FAILURE; + uc_fsm_d = UC_CORE_RSP; + end + end + end + + default: begin + if (req_need_rsp_i) begin + rsp_error_set = 1'b1; + uc_fsm_d = UC_CORE_RSP; + end + end + endcase + end + end + // }}} + + // Wait for the write buffer to be empty + // {{{ + UC_WAIT_PENDING: begin + if (wbuf_empty_i && mshr_empty_i && rtab_empty_i && ctrl_empty_i) begin + uc_fsm_d = UC_MEM_REQ; + end else begin + uc_fsm_d = UC_WAIT_PENDING; + end + end + // }}} + + // Send request to memory + // {{{ + UC_MEM_REQ: begin + uc_fsm_d = UC_MEM_REQ; + + mem_resp_write_valid_d = 1'b0; + mem_resp_read_valid_d = 1'b0; + + case (1'b1) + req_op_q.is_ld, + req_op_q.is_amo_lr: begin + if (mem_req_read_ready_i) begin + uc_fsm_d = UC_MEM_WAIT_RSP; + end + end + + req_op_q.is_st, + req_op_q.is_amo_sc, + req_op_q.is_amo_swap, + req_op_q.is_amo_add, + req_op_q.is_amo_and, + req_op_q.is_amo_or, + req_op_q.is_amo_xor, + req_op_q.is_amo_max, + req_op_q.is_amo_maxu, + req_op_q.is_amo_min, + req_op_q.is_amo_minu: begin + if (mem_req_write_ready_i && mem_req_write_data_ready_i) begin + uc_fsm_d = UC_MEM_WAIT_RSP; + end else if (mem_req_write_ready_i) begin + uc_fsm_d = UC_MEM_WDATA_REQ; + end else if (mem_req_write_data_ready_i) begin + uc_fsm_d = UC_MEM_W_REQ; + end + end + endcase + end + // }}} + + // Send write address + // {{{ + UC_MEM_W_REQ: begin + mem_resp_write_valid_d = mem_resp_write_valid_q | mem_resp_write_valid_i; + mem_resp_read_valid_d = mem_resp_read_valid_q | mem_resp_read_valid_i; + + if (mem_req_write_ready_i) begin + uc_fsm_d = UC_MEM_WAIT_RSP; + end else begin + uc_fsm_d = UC_MEM_W_REQ; + end + end + // }}} + + // Send write data + // {{{ + UC_MEM_WDATA_REQ: begin + mem_resp_write_valid_d = mem_resp_write_valid_q | mem_resp_write_valid_i; + mem_resp_read_valid_d = mem_resp_read_valid_q | mem_resp_read_valid_i; + + if (mem_req_write_data_ready_i) begin + uc_fsm_d = UC_MEM_WAIT_RSP; + end else begin + uc_fsm_d = UC_MEM_WDATA_REQ; + end + end + // }}} + + // Wait for the response from the memory + // {{{ + UC_MEM_WAIT_RSP: begin + automatic bit rd_error; + automatic bit wr_error; + + uc_fsm_d = UC_MEM_WAIT_RSP; + mem_resp_write_valid_d = mem_resp_write_valid_q | mem_resp_write_valid_i; + mem_resp_read_valid_d = mem_resp_read_valid_q | mem_resp_read_valid_i; + + rd_error = mem_resp_read_valid_i && + ( mem_resp_read_i.mem_resp_r_error == HPDCACHE_MEM_RESP_NOK); + wr_error = mem_resp_write_valid_i && + (mem_resp_write_i.mem_resp_w_error == HPDCACHE_MEM_RESP_NOK); + rsp_error_set = req_need_rsp_q & (rd_error | wr_error); + + case (1'b1) + req_op_q.is_ld: begin + if (mem_resp_read_valid_i) begin + if (req_need_rsp_q) begin + uc_fsm_d = UC_CORE_RSP; + end else begin + uc_fsm_d = UC_IDLE; + end + end + end + req_op_q.is_st: begin + if (mem_resp_write_valid_i) begin + if (req_need_rsp_q) begin + uc_fsm_d = UC_CORE_RSP; + end else begin + uc_fsm_d = UC_IDLE; + end + end + end + req_op_q.is_amo_lr: begin + if (mem_resp_read_valid_i) begin + // set a new reservation + if (!rd_error) + begin + lrsc_uc_set = 1'b1; + lrsc_rsrv_addr_d = req_addr_q; + end + // in case of a memory error, do not make the reservation and + // invalidate an existing one (if valid) + else begin + lrsc_uc_reset = 1'b1; + end + + if (req_uc_q || rd_error) begin + uc_fsm_d = UC_CORE_RSP; + end else begin + uc_fsm_d = UC_AMO_READ_DIR; + end + end + end + req_op_q.is_amo_sc: begin + if (mem_resp_write_valid_i) begin + automatic bit is_atomic; + + is_atomic = mem_resp_write_i.mem_resp_w_is_atomic && !wr_error; + uc_sc_retcode_d = is_atomic ? AMO_SC_SUCCESS : AMO_SC_FAILURE; + + if (req_uc_q || !is_atomic) begin + uc_fsm_d = UC_CORE_RSP; + end else begin + uc_fsm_d = UC_AMO_READ_DIR; + end + end + end + req_op_q.is_amo_swap, + req_op_q.is_amo_add, + req_op_q.is_amo_and, + req_op_q.is_amo_or, + req_op_q.is_amo_xor, + req_op_q.is_amo_max, + req_op_q.is_amo_maxu, + req_op_q.is_amo_min, + req_op_q.is_amo_minu: begin + // wait for both old data and write acknowledged were received + if ((mem_resp_read_valid_i && mem_resp_write_valid_i) || + (mem_resp_read_valid_i && mem_resp_write_valid_q) || + (mem_resp_read_valid_q && mem_resp_write_valid_i)) + begin + if (req_uc_q || rsp_error_q || rd_error || wr_error) begin + uc_fsm_d = UC_CORE_RSP; + end else begin + uc_fsm_d = UC_AMO_READ_DIR; + end + end + end + endcase + end + // }}} + + // Send the response to the requester + // {{{ + UC_CORE_RSP: begin + if (core_rsp_ready_i) begin + rsp_error_rst = 1'b1; + uc_fsm_d = UC_IDLE; + end else begin + uc_fsm_d = UC_CORE_RSP; + end + end + // }}} + + // Check for a cache hit on the AMO target address + // {{{ + UC_AMO_READ_DIR: begin + uc_fsm_d = UC_AMO_WRITE_DATA; + end + // }}} + + // Write the locally computed AMO result in the cache + // {{{ + UC_AMO_WRITE_DATA: begin + uc_fsm_d = UC_CORE_RSP; + end + // }}} + endcase + end +// }}} + +// AMO unit +// {{{ + localparam hpdcache_uint AMO_WORD_INDEX_WIDTH = $clog2(HPDCACHE_REQ_DATA_WIDTH/64); + + generate + if (AMO_WORD_INDEX_WIDTH > 0) begin : amo_operand_mux_gen + hpdcache_mux #( + .NINPUT (HPDCACHE_REQ_DATA_WIDTH/64), + .DATA_WIDTH (64), + .ONE_HOT_SEL (1'b0) + ) amo_ld_data_mux_i ( + .data_i (rsp_rdata_q), + .sel_i (req_addr_q[3 +: AMO_WORD_INDEX_WIDTH]), + .data_o (amo_req_ld_data) + ); + + hpdcache_mux #( + .NINPUT (HPDCACHE_REQ_DATA_WIDTH/64), + .DATA_WIDTH (64), + .ONE_HOT_SEL (1'b0) + ) amo_st_data_mux_i ( + .data_i (req_data_q), + .sel_i (req_addr_q[3 +: AMO_WORD_INDEX_WIDTH]), + .data_o (amo_req_st_data) + ); + + hpdcache_mux #( + .NINPUT (HPDCACHE_REQ_DATA_WIDTH/64), + .DATA_WIDTH (8), + .ONE_HOT_SEL (1'b0) + ) amo_st_be_mux_i ( + .data_i (req_be_q), + .sel_i (req_addr_q[3 +: AMO_WORD_INDEX_WIDTH]), + .data_o (amo_st_be) + ); + + end else begin + assign amo_req_ld_data = rsp_rdata_q; + assign amo_req_st_data = req_data_q; + assign amo_st_be = req_be_q; + end + endgenerate + + assign amo_ld_data = prepare_amo_data_operand(amo_req_ld_data, req_size_q, + req_addr_q, amo_need_sign_extend(req_op_q)); + assign amo_st_data = prepare_amo_data_operand(amo_req_st_data, req_size_q, + req_addr_q, amo_need_sign_extend(req_op_q)); + + hpdcache_amo amo_unit_i ( + .ld_data_i (amo_ld_data), + .st_data_i (amo_st_data), + .op_i (req_op_q), + .result_o (amo_result) + ); + + assign dir_amo_match_o = (uc_fsm_q == UC_AMO_READ_DIR), + dir_amo_match_set_o = hpdcache_get_req_addr_set(req_addr_q), + dir_amo_match_tag_o = hpdcache_get_req_addr_tag(req_addr_q), + dir_amo_update_plru_o = dir_amo_match_o; + + assign data_amo_write_o = (uc_fsm_q == UC_AMO_WRITE_DATA), + data_amo_write_enable_o = |dir_amo_hit_way_i, + data_amo_write_set_o = hpdcache_get_req_addr_set(req_addr_q), + data_amo_write_size_o = req_size_q, + data_amo_write_word_o = hpdcache_get_req_addr_word(req_addr_q), + data_amo_write_data_o = prepare_amo_data_result(amo_result, req_size_q), + data_amo_write_be_o = amo_st_be; +// }}} + +// Core response outputs +// {{{ + assign req_ready_o = (uc_fsm_q == UC_IDLE), + core_rsp_valid_o = (uc_fsm_q == UC_CORE_RSP); +// }}} + +// Memory read request outputs +// {{{ + always_comb + begin : mem_req_read_comb + mem_req_read_o.mem_req_addr = req_addr_q; + mem_req_read_o.mem_req_len = 0; + mem_req_read_o.mem_req_size = req_size_q; + mem_req_read_o.mem_req_id = mem_read_id_i; + mem_req_read_o.mem_req_cacheable = 1'b0; + mem_req_read_o.mem_req_command = HPDCACHE_MEM_READ; + mem_req_read_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_ADD; + + unique case (1'b1) + req_op_q.is_ld: begin + mem_req_read_valid_o = (uc_fsm_q == UC_MEM_REQ); + end + req_op_q.is_amo_lr: begin + mem_req_read_o.mem_req_command = HPDCACHE_MEM_ATOMIC; + mem_req_read_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_LDEX; + mem_req_read_valid_o = (uc_fsm_q == UC_MEM_REQ); + end + default: begin + mem_req_read_valid_o = 1'b0; + end + endcase + end +// }}} + +// Memory write request outputs +// {{{ + always_comb + begin : mem_req_write_comb + mem_req_write_data = req_data_q; + mem_req_write_o.mem_req_addr = req_addr_q; + mem_req_write_o.mem_req_len = 0; + mem_req_write_o.mem_req_size = req_size_q; + mem_req_write_o.mem_req_id = mem_write_id_i; + mem_req_write_o.mem_req_cacheable = 1'b0; + unique case (1'b1) + req_op_q.is_amo_sc: begin + mem_req_write_o.mem_req_command = HPDCACHE_MEM_ATOMIC; + mem_req_write_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_STEX; + end + req_op_q.is_amo_swap: begin + mem_req_write_o.mem_req_command = HPDCACHE_MEM_ATOMIC; + mem_req_write_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_SWAP; + end + req_op_q.is_amo_add: begin + mem_req_write_o.mem_req_command = HPDCACHE_MEM_ATOMIC; + mem_req_write_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_ADD; + end + req_op_q.is_amo_and: begin + mem_req_write_data = ~req_data_q; + mem_req_write_o.mem_req_command = HPDCACHE_MEM_ATOMIC; + mem_req_write_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_CLR; + end + req_op_q.is_amo_or: begin + mem_req_write_o.mem_req_command = HPDCACHE_MEM_ATOMIC; + mem_req_write_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_SET; + end + req_op_q.is_amo_xor: begin + mem_req_write_o.mem_req_command = HPDCACHE_MEM_ATOMIC; + mem_req_write_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_EOR; + end + req_op_q.is_amo_max: begin + mem_req_write_o.mem_req_command = HPDCACHE_MEM_ATOMIC; + mem_req_write_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_SMAX; + end + req_op_q.is_amo_maxu: begin + mem_req_write_o.mem_req_command = HPDCACHE_MEM_ATOMIC; + mem_req_write_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_UMAX; + end + req_op_q.is_amo_min: begin + mem_req_write_o.mem_req_command = HPDCACHE_MEM_ATOMIC; + mem_req_write_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_SMIN; + end + req_op_q.is_amo_minu: begin + mem_req_write_o.mem_req_command = HPDCACHE_MEM_ATOMIC; + mem_req_write_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_UMIN; + end + default: begin + mem_req_write_o.mem_req_command = HPDCACHE_MEM_WRITE; + mem_req_write_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_ADD; + end + endcase + + unique case (uc_fsm_q) + UC_MEM_REQ: begin + unique case (1'b1) + req_op_q.is_st, + req_op_q.is_amo_sc, + req_op_q.is_amo_swap, + req_op_q.is_amo_add, + req_op_q.is_amo_and, + req_op_q.is_amo_or, + req_op_q.is_amo_xor, + req_op_q.is_amo_max, + req_op_q.is_amo_maxu, + req_op_q.is_amo_min, + req_op_q.is_amo_minu: begin + mem_req_write_data_valid_o = 1'b1; + mem_req_write_valid_o = 1'b1; + end + + default: begin + mem_req_write_data_valid_o = 1'b0; + mem_req_write_valid_o = 1'b0; + end + endcase + end + + UC_MEM_W_REQ: begin + mem_req_write_valid_o = 1'b1; + mem_req_write_data_valid_o = 1'b0; + end + + UC_MEM_WDATA_REQ: begin + mem_req_write_valid_o = 1'b0; + mem_req_write_data_valid_o = 1'b1; + end + + default: begin + mem_req_write_valid_o = 1'b0; + mem_req_write_data_valid_o = 1'b0; + end + endcase + end + + generate + // memory data width is bigger than the width of the core's interface + if (MEM_REQ_RATIO > 1) begin : mem_req_data_gen + // replicate data + assign mem_req_write_data_o.mem_req_w_data = {MEM_REQ_RATIO{mem_req_write_data}}; + + // demultiplex the byte-enable + hpdcache_demux #( + .NOUTPUT (MEM_REQ_RATIO), + .DATA_WIDTH (HPDCACHE_REQ_DATA_WIDTH/8) + ) mem_write_be_demux_i ( + .data_i (req_be_q), + .sel_i (req_addr_q[HPDCACHE_REQ_BYTE_OFFSET_WIDTH +: MEM_REQ_WORD_INDEX_WIDTH]), + .data_o (mem_req_write_data_o.mem_req_w_be) + ); + end + + // memory data width is equal to the width of the core's interface + else begin + assign mem_req_write_data_o.mem_req_w_data = mem_req_write_data; + assign mem_req_write_data_o.mem_req_w_be = req_be_q; + end + + assign mem_req_write_data_o.mem_req_w_last = 1'b1; + endgenerate +// }}} + +// Response handling +// {{{ + logic [63:0] sc_retcode; + logic [63:0] sc_rdata; + + assign sc_retcode = {{63{1'b0}}, uc_sc_retcode_q}, + sc_rdata = prepare_amo_data_result(sc_retcode, req_size_q); + + assign core_rsp_o.rdata = req_op_q.is_amo_sc ? {HPDCACHE_REQ_WORDS{sc_rdata}} : rsp_rdata_q, + core_rsp_o.sid = req_sid_q, + core_rsp_o.tid = req_tid_q, + core_rsp_o.error = rsp_error_q, + core_rsp_o.aborted = 1'b0; + + // Resize the memory response data to the core response width + generate + // memory data width is bigger than the width of the core's interface + if (MEM_REQ_RATIO > 1) begin : core_rsp_data_gen + hpdcache_mux #( + .NINPUT (MEM_REQ_RATIO), + .DATA_WIDTH (HPDCACHE_REQ_DATA_WIDTH) + ) data_read_rsp_mux_i( + .data_i (mem_resp_read_i.mem_resp_r_data), + .sel_i (req_addr_q[HPDCACHE_REQ_BYTE_OFFSET_WIDTH +: MEM_REQ_WORD_INDEX_WIDTH]), + .data_o (rsp_rdata_d) + ); + end + + // memory data width is equal to the width of the core's interface + else begin + assign rsp_rdata_d = mem_resp_read_i.mem_resp_r_data; + end + endgenerate + + // This FSM is always ready to accept the response + assign mem_resp_read_ready_o = 1'b1, + mem_resp_write_ready_o = 1'b1; +// }}} + +// Set cache request registers +// {{{ + always_ff @(posedge clk_i) + begin : req_ff + if (req_valid_i && req_ready_o) begin + req_op_q <= req_op_i; + req_addr_q <= req_addr_i; + req_size_q <= req_size_i; + req_data_q <= req_data_i; + req_be_q <= req_be_i; + req_uc_q <= req_uc_i; + req_sid_q <= req_sid_i; + req_tid_q <= req_tid_i; + req_need_rsp_q <= req_need_rsp_i; + end + end +// }}} + +// Uncacheable request FSM set state +// {{{ + logic lrsc_rsrv_valid_set, lrsc_rsrv_valid_reset; + + assign lrsc_rsrv_valid_set = lrsc_uc_set, + lrsc_rsrv_valid_reset = lrsc_uc_reset | lrsc_snoop_reset; + + always_ff @(posedge clk_i or negedge rst_ni) + begin : uc_fsm_ff + if (!rst_ni) begin + uc_fsm_q <= UC_IDLE; + lrsc_rsrv_valid_q <= 1'b0; + end else begin + uc_fsm_q <= uc_fsm_d; + lrsc_rsrv_valid_q <= (~lrsc_rsrv_valid_q & lrsc_rsrv_valid_set ) | + ( lrsc_rsrv_valid_q & ~lrsc_rsrv_valid_reset); + end + end + + always_ff @(posedge clk_i) + begin : uc_amo_ff + lrsc_rsrv_addr_q <= lrsc_rsrv_addr_d; + uc_sc_retcode_q <= uc_sc_retcode_d; + end +// }}} + +// Response registers +// {{{ + always_ff @(posedge clk_i) + begin + if (mem_resp_read_valid_i) begin + rsp_rdata_q <= rsp_rdata_d; + end + mem_resp_write_valid_q <= mem_resp_write_valid_d; + mem_resp_read_valid_q <= mem_resp_read_valid_d; + end + + always_ff @(posedge clk_i or negedge rst_ni) + begin + if (!rst_ni) begin + rsp_error_q <= 1'b0; + end else begin + rsp_error_q <= (~rsp_error_q & rsp_error_set) | + ( rsp_error_q & ~rsp_error_rst); + end + end +// }}} + +// Assertions +// {{{ +// pragma translate_off + assert property (@(posedge clk_i) + (req_valid_i && req_op_i.is_ld) -> req_uc_i) else + $error("uc_handler: unexpected load request on cacheable region"); + + assert property (@(posedge clk_i) + (req_valid_i && req_op_i.is_st) -> req_uc_i) else + $error("uc_handler: unexpected store request on cacheable region"); + + assert property (@(posedge clk_i) + (req_valid_i && (req_op_i.is_amo_lr || + req_op_i.is_amo_sc || + req_op_i.is_amo_swap || + req_op_i.is_amo_add || + req_op_i.is_amo_and || + req_op_i.is_amo_or || + req_op_i.is_amo_xor || + req_op_i.is_amo_max || + req_op_i.is_amo_maxu || + req_op_i.is_amo_min || + req_op_i.is_amo_minu )) -> req_need_rsp_i) else + $error("uc_handler: amo requests shall need a response"); + + assert property (@(posedge clk_i) + (req_valid_i && (req_op_i.is_amo_lr || + req_op_i.is_amo_sc || + req_op_i.is_amo_swap || + req_op_i.is_amo_add || + req_op_i.is_amo_and || + req_op_i.is_amo_or || + req_op_i.is_amo_xor || + req_op_i.is_amo_max || + req_op_i.is_amo_maxu || + req_op_i.is_amo_min || + req_op_i.is_amo_minu )) -> (req_size_i inside {2,3})) else + $error("uc_handler: amo requests shall be 4 or 8 bytes wide"); + + assert property (@(posedge clk_i) + (mem_resp_write_valid_i || mem_resp_read_valid_i) -> (uc_fsm_q == UC_MEM_WAIT_RSP)) else + $error("uc_handler: unexpected response from memory"); +// pragma translate_on +// }}} + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_wbuf.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_wbuf.sv new file mode 100644 index 00000000000..e6cf560dc36 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_wbuf.sv @@ -0,0 +1,685 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : HPDcache Write Buffer + * History : + */ +/* + * Improvements + * ================= + * TODO Use a feedthrough FIFO for the data pointers in the send data interface. + * Currently, there is always an one-cycle latency between the write + * and the availability of the data. + */ +module hpdcache_wbuf + // Parameters + // {{{ +#( + // Number of entries in the directory part of the Write Buffer + parameter int unsigned WBUF_DIR_ENTRIES = 0, + // Number of entries in the data part of the Write Buffer + parameter int unsigned WBUF_DATA_ENTRIES = 0, + // Width in bits of the write words + parameter int unsigned WBUF_WORD_WIDTH = 0, + // Number of words per line in the write buffer + parameter int unsigned WBUF_WORDS = 0, + // Width in bits of the physical address + parameter int unsigned WBUF_PA_WIDTH = 0, + // Maximum value of the time counter + parameter int unsigned WBUF_TIMECNT_MAX = 8, + // Number of most significant bits to check for read conflicts + parameter int unsigned WBUF_READ_MATCH_WIDTH = 0, + + localparam int unsigned WBUF_OFFSET_WIDTH = $clog2((WBUF_WORD_WIDTH*WBUF_WORDS)/8), + localparam int unsigned WBUF_TAG_WIDTH = WBUF_PA_WIDTH - WBUF_OFFSET_WIDTH, + localparam int unsigned WBUF_WORD_OFFSET = $clog2(WBUF_WORD_WIDTH/8), + localparam int unsigned WBUF_DATA_PTR_WIDTH = $clog2(WBUF_DATA_ENTRIES), + localparam int unsigned WBUF_DIR_PTR_WIDTH = $clog2(WBUF_DIR_ENTRIES), + localparam int unsigned WBUF_TIMECNT_WIDTH = $clog2(WBUF_TIMECNT_MAX), + localparam type wbuf_addr_t = logic unsigned [ WBUF_PA_WIDTH-1:0], + localparam type wbuf_dir_ptr_t = logic unsigned [ WBUF_DIR_PTR_WIDTH-1:0], + localparam type wbuf_data_ptr_t = logic unsigned [ WBUF_DATA_PTR_WIDTH-1:0], + localparam type wbuf_data_t = logic [ WBUF_WORD_WIDTH-1:0], + localparam type wbuf_be_t = logic [ WBUF_WORD_WIDTH/8-1:0], + localparam type wbuf_data_buf_t = wbuf_data_t [ WBUF_WORDS-1:0], + localparam type wbuf_be_buf_t = wbuf_be_t [ WBUF_WORDS-1:0], + localparam type wbuf_tag_t = logic unsigned [ WBUF_TAG_WIDTH-1:0], + localparam type wbuf_match_t = logic unsigned [WBUF_READ_MATCH_WIDTH-1:0], + localparam type wbuf_timecnt_t = logic unsigned [ WBUF_TIMECNT_WIDTH-1:0] +) + // }}} + // Ports + // {{{ +( + // Clock and reset signals + input logic clk_i, + input logic rst_ni, + + // Global control signals + output logic empty_o, + output logic full_o, + input logic flush_all_i, + + // Configuration signals + // Timer threshold + input wbuf_timecnt_t cfg_threshold_i, + // Reset timer on write + input logic cfg_reset_timecnt_on_write_i, + // Sequentialize write-after-write hazards + input logic cfg_sequential_waw_i, + // Inhibit write coalescing + input logic cfg_inhibit_write_coalescing_i, + + // Write interface + input logic write_i, + output logic write_ready_o, + input wbuf_addr_t write_addr_i, + input wbuf_data_t write_data_i, + input wbuf_be_t write_be_i, // byte-enable + input logic write_uc_i, // uncacheable write + + // Read hit interface + input wbuf_addr_t read_addr_i, + output logic read_hit_o, + input logic read_flush_hit_i, + + // Replay hit interface + input wbuf_addr_t replay_addr_i, + input logic replay_is_read_i, + output logic replay_open_hit_o, + output logic replay_pend_hit_o, + output logic replay_sent_hit_o, + output logic replay_not_ready_o, + + // Send interface + input logic send_meta_ready_i, + output logic send_meta_valid_o, + output wbuf_addr_t send_addr_o, + output wbuf_dir_ptr_t send_id_o, + output logic send_uc_o, + + input logic send_data_ready_i, + output logic send_data_valid_o, + output wbuf_addr_t send_data_tag_o, + output wbuf_data_buf_t send_data_o, + output wbuf_be_buf_t send_be_o, + + // Acknowledge interface + input logic ack_i, + input wbuf_dir_ptr_t ack_id_i, + input logic ack_error_i +); + // }}} + + // Definition of constants, types and functions + // {{{ + localparam int WBUF_SEND_FIFO_DEPTH = WBUF_DATA_ENTRIES; + + typedef logic unsigned [31:0] wbuf_uint; + + typedef enum logic [1:0] { + WBUF_FREE = 2'b00, // unused/free slot + WBUF_OPEN = 2'b01, // there are pending writes in this slot + WBUF_PEND = 2'b10, // the slot is waiting to be sent + WBUF_SENT = 2'b11 // the slot is sent and waits for the memory acknowledge + } wbuf_state_e; + + typedef struct packed { + wbuf_data_ptr_t ptr; + wbuf_timecnt_t cnt; + wbuf_tag_t tag; + logic uc; + } wbuf_dir_entry_t; + + typedef struct packed { + wbuf_data_buf_t data; + wbuf_be_buf_t be; + } wbuf_data_entry_t; + + typedef struct packed { + wbuf_data_ptr_t send_data_ptr; + wbuf_tag_t send_data_tag; + } wbuf_send_data_t; + + typedef struct packed { + wbuf_tag_t send_meta_tag; + wbuf_dir_ptr_t send_meta_id; + logic send_meta_uc; + } wbuf_send_meta_t; + + function automatic wbuf_dir_ptr_t wbuf_dir_find_next( + input wbuf_dir_ptr_t curr_ptr, + input wbuf_state_e [WBUF_DIR_ENTRIES-1:0] dir_state, + input wbuf_state_e state); + automatic wbuf_dir_ptr_t next_ptr; + for (int unsigned i = 0; i < WBUF_DIR_ENTRIES; i++) begin + next_ptr = wbuf_dir_ptr_t'((i + int'(curr_ptr) + 1) % WBUF_DIR_ENTRIES); + if (dir_state[next_ptr] == state) begin + return next_ptr; + end + end + return curr_ptr; + endfunction + + function automatic wbuf_data_ptr_t wbuf_data_find_next( + input wbuf_data_ptr_t curr_ptr, + input logic [WBUF_DATA_ENTRIES-1:0] data_valid, + input logic state); + automatic wbuf_data_ptr_t next_ptr; + for (int unsigned i = 0; i < WBUF_DATA_ENTRIES; i++) begin + next_ptr = wbuf_data_ptr_t'((i + int'(curr_ptr) + 1) % WBUF_DATA_ENTRIES); + if (data_valid[next_ptr] == state) begin + return next_ptr; + end + end + return curr_ptr; + endfunction + + function automatic void wbuf_data_write( + output wbuf_data_buf_t wbuf_ret_data, + output wbuf_be_buf_t wbuf_ret_be, + input wbuf_data_buf_t wbuf_old_data, + input wbuf_be_buf_t wbuf_old_be, + input wbuf_data_buf_t wbuf_new_data, + input wbuf_be_buf_t wbuf_new_be); + for (int unsigned w = 0; w < WBUF_WORDS; w++) begin + for (int unsigned b = 0; b < WBUF_WORD_WIDTH/8; b++) begin + wbuf_ret_data[w][b*8 +: 8] = wbuf_new_be[w][b] ? + wbuf_new_data[w][b*8 +: 8] : + wbuf_old_data[w][b*8 +: 8]; + end + wbuf_ret_be[w] = wbuf_old_be[w] | wbuf_new_be[w]; + end + endfunction + + function automatic wbuf_match_t wbuf_tag_to_match_addr(wbuf_tag_t tag); + return tag[WBUF_TAG_WIDTH - 1:WBUF_TAG_WIDTH - WBUF_READ_MATCH_WIDTH]; + endfunction + // }}} + + // Definition of internal wires and registers + // {{{ + wbuf_state_e [ WBUF_DIR_ENTRIES-1:0] wbuf_dir_state_q, wbuf_dir_state_d; + wbuf_dir_entry_t [ WBUF_DIR_ENTRIES-1:0] wbuf_dir_q, wbuf_dir_d; + logic [WBUF_DATA_ENTRIES-1:0] wbuf_data_valid_q, wbuf_data_valid_d; + wbuf_data_entry_t [WBUF_DATA_ENTRIES-1:0] wbuf_data_q, wbuf_data_d; + + wbuf_dir_ptr_t wbuf_dir_free_ptr_q, wbuf_dir_free_ptr_d; + logic wbuf_dir_free; + wbuf_dir_ptr_t wbuf_dir_send_ptr_q, wbuf_dir_send_ptr_d; + wbuf_data_ptr_t wbuf_data_free_ptr_q, wbuf_data_free_ptr_d; + logic wbuf_data_free; + + logic wbuf_write_free; + logic wbuf_write_hit_open; + logic wbuf_write_hit_pend; + logic wbuf_write_hit_sent; + wbuf_dir_ptr_t wbuf_write_hit_open_dir_ptr; + wbuf_dir_ptr_t wbuf_write_hit_pend_dir_ptr; + + logic send_meta_valid; + logic send_meta_ready; + wbuf_send_meta_t send_meta_wdata, send_meta_rdata; + + logic fifo_send_data_wok; + logic fifo_send_data_w; + wbuf_send_data_t fifo_send_data_d; + logic fifo_send_data_r; + logic fifo_send_data_rok; + wbuf_send_data_t fifo_send_data_q; + + wbuf_tag_t write_tag; + wbuf_data_buf_t write_data; + wbuf_be_buf_t write_be; + + logic [WBUF_DIR_ENTRIES-1:0] replay_match; + logic [WBUF_DIR_ENTRIES-1:0] replay_open_hit; + logic [WBUF_DIR_ENTRIES-1:0] replay_pend_hit; + logic [WBUF_DIR_ENTRIES-1:0] replay_sent_hit; + + genvar gen_i; + // }}} + + // Global control signals + // {{{ + always_comb + begin : empty_comb + empty_o = 1'b1; + for (int unsigned i = 0; i < WBUF_DIR_ENTRIES; i++) begin + empty_o &= (wbuf_dir_state_q[i] == WBUF_FREE); + end + end + + always_comb + begin : full_comb + full_o = 1'b1; + for (int unsigned i = 0; i < WBUF_DIR_ENTRIES; i++) begin + full_o &= (wbuf_dir_state_q[i] != WBUF_FREE); + end + end + // }}} + + // Write control + // {{{ + assign write_tag = write_addr_i[WBUF_PA_WIDTH-1:WBUF_OFFSET_WIDTH]; + + always_comb + begin : wbuf_write_data_comb + for (int unsigned w = 0; w < WBUF_WORDS; w++) begin + write_data[w] = write_data_i; + end + end + + generate + if (WBUF_OFFSET_WIDTH > WBUF_WORD_OFFSET) begin : wbuf_write_be_gt_gen + always_comb + begin : wbuf_write_be_comb + for (int unsigned w = 0; w < WBUF_WORDS; w++) begin + if (w == int'(write_addr_i[WBUF_OFFSET_WIDTH-1:WBUF_WORD_OFFSET])) begin + write_be[w] = write_be_i; + end else begin + write_be[w] = '0; + end + end + end + end else begin : wbuf_write_be_le_gen + always_comb + begin : wbuf_write_be_comb + for (int unsigned w = 0; w < WBUF_WORDS; w++) begin + write_be[w] = write_be_i; + end + end + end + endgenerate + + always_comb + begin : wbuf_free_comb + wbuf_dir_free_ptr_d = wbuf_dir_free_ptr_q; + if (ack_i) begin + wbuf_dir_free_ptr_d = ack_id_i; + end else if (write_i && wbuf_write_free) begin + wbuf_dir_free_ptr_d = wbuf_dir_find_next(wbuf_dir_free_ptr_q, wbuf_dir_state_q, WBUF_FREE); + end + + wbuf_data_free_ptr_d = wbuf_data_free_ptr_q; + if (send_data_valid_o && send_data_ready_i) begin + wbuf_data_free_ptr_d = fifo_send_data_q.send_data_ptr; + end else if (write_i && wbuf_write_free) begin + wbuf_data_free_ptr_d = wbuf_data_find_next(wbuf_data_free_ptr_q, wbuf_data_valid_q, 1'b0); + end + end + + assign wbuf_dir_free = (wbuf_dir_state_q[wbuf_dir_free_ptr_q] == WBUF_FREE); + assign wbuf_data_free = ~wbuf_data_valid_q[wbuf_data_free_ptr_q]; + + always_comb + begin : wbuf_write_hit_comb + wbuf_write_hit_open = 1'b0; + wbuf_write_hit_pend = 1'b0; + wbuf_write_hit_sent = 1'b0; + + wbuf_write_hit_open_dir_ptr = 0; + wbuf_write_hit_pend_dir_ptr = 0; + for (int unsigned i = 0; i < WBUF_DIR_ENTRIES; i++) begin + if (wbuf_dir_q[i].tag == write_tag) begin + unique case (wbuf_dir_state_q[i]) + WBUF_OPEN: begin + wbuf_write_hit_open = 1'b1; + wbuf_write_hit_open_dir_ptr = wbuf_dir_ptr_t'(i); + end + WBUF_PEND: begin + wbuf_write_hit_pend = 1'b1; + wbuf_write_hit_pend_dir_ptr = wbuf_dir_ptr_t'(i); + end + WBUF_SENT: begin + wbuf_write_hit_sent = 1'b1; + end + default: begin + /* do nothing */ + end + endcase + end + end + end + + // Check if there is a match between the read address and the tag of one + // of the used slots in the write buffer directory + always_comb + begin : read_hit_comb + automatic logic [WBUF_DIR_ENTRIES-1:0] read_hit; + + for (int unsigned i = 0; i < WBUF_DIR_ENTRIES; i++) begin + read_hit[i] = 1'b0; + unique case (wbuf_dir_state_q[i]) + WBUF_OPEN, WBUF_PEND, WBUF_SENT: begin + automatic wbuf_addr_t wbuf_addr; + automatic wbuf_match_t wbuf_tag; + automatic wbuf_match_t read_tag; + + wbuf_addr = wbuf_addr_t'(wbuf_dir_q[i].tag) << WBUF_OFFSET_WIDTH; + read_tag = read_addr_i[WBUF_PA_WIDTH-1:WBUF_PA_WIDTH - WBUF_READ_MATCH_WIDTH]; + wbuf_tag = wbuf_addr [WBUF_PA_WIDTH-1:WBUF_PA_WIDTH - WBUF_READ_MATCH_WIDTH]; + read_hit[i] = (read_tag == wbuf_tag) ? 1'b1 : 1'b0; + end + default: begin + /* do nothing */ + end + endcase + end + + read_hit_o = |read_hit; + end + + // Check if there is a match between the replay address and the tag of one + // of the used slots in the write buffer directory + generate + for (gen_i = 0; gen_i < WBUF_DIR_ENTRIES; gen_i++) begin : replay_match_gen + assign replay_match[gen_i] = replay_is_read_i ? + /* replay is read: compare address block tag (e.g. cache line) */ + (wbuf_tag_to_match_addr(wbuf_dir_q[gen_i].tag) == + replay_addr_i[WBUF_PA_WIDTH - 1:WBUF_PA_WIDTH - WBUF_READ_MATCH_WIDTH]) : + /* replay is write: compare wbuf tag */ + (wbuf_dir_q[gen_i].tag == + replay_addr_i[WBUF_PA_WIDTH - 1:WBUF_PA_WIDTH - WBUF_TAG_WIDTH]); + + assign replay_open_hit[gen_i] = + replay_match[gen_i] && (wbuf_dir_state_q[gen_i] == WBUF_OPEN); + assign replay_pend_hit[gen_i] = + replay_match[gen_i] && (wbuf_dir_state_q[gen_i] == WBUF_PEND); + assign replay_sent_hit[gen_i] = + replay_match[gen_i] && (wbuf_dir_state_q[gen_i] == WBUF_SENT); + end + endgenerate + + assign replay_open_hit_o = |replay_open_hit, + replay_pend_hit_o = |replay_pend_hit, + replay_sent_hit_o = |replay_sent_hit; + + always_comb + begin : replay_wbuf_not_ready_comb + replay_not_ready_o = 1'b0; + if (replay_pend_hit_o) begin + replay_not_ready_o = 1'b1; + end else if (replay_sent_hit_o && cfg_sequential_waw_i) begin + replay_not_ready_o = 1'b1; + end else if (!replay_open_hit_o && (!wbuf_dir_free || !wbuf_data_free)) begin + replay_not_ready_o = 1'b1; + end + end + + assign wbuf_write_free = + wbuf_dir_free + & wbuf_data_free + & ~wbuf_write_hit_open + & ~wbuf_write_hit_pend + & ~(wbuf_write_hit_sent & cfg_sequential_waw_i); + + assign write_ready_o = wbuf_write_free + | ((wbuf_write_hit_open | wbuf_write_hit_pend) + & ~cfg_inhibit_write_coalescing_i); + // }}} + + // Update control + // {{{ + always_comb + begin : wbuf_update_comb + automatic bit timeout; + automatic bit write_hit; + automatic bit read_hit; + automatic bit match_open_ptr; + automatic bit match_pend_ptr; + automatic bit match_free; + automatic bit send; + + timeout = 1'b0; + write_hit = 1'b0; + read_hit = 1'b0; + match_open_ptr = 1'b0; + match_pend_ptr = 1'b0; + match_free = 1'b0; + send = 1'b0; + + wbuf_dir_state_d = wbuf_dir_state_q; + wbuf_dir_d = wbuf_dir_q; + wbuf_data_d = wbuf_data_q; + + fifo_send_data_w = 1'b0; + send_meta_valid = 1'b0; + + for (int unsigned i = 0; i < WBUF_DIR_ENTRIES; i++) begin + case (wbuf_dir_state_q[i]) + WBUF_FREE: begin + match_free = wbuf_write_free && (i == int'(wbuf_dir_free_ptr_q)); + + if (write_i && match_free) begin + send = (cfg_threshold_i == 0) + | write_uc_i + | flush_all_i + | cfg_inhibit_write_coalescing_i; + + wbuf_dir_state_d[i] = send ? WBUF_PEND : WBUF_OPEN; + wbuf_dir_d[i].tag = write_tag; + wbuf_dir_d[i].cnt = 0; + wbuf_dir_d[i].ptr = wbuf_data_free_ptr_q; + wbuf_dir_d[i].uc = write_uc_i; + + wbuf_data_write( + wbuf_data_d[wbuf_data_free_ptr_q].data, + wbuf_data_d[wbuf_data_free_ptr_q].be, + '0, + '0, + write_data, + write_be + ); + end + end + + WBUF_OPEN: begin + match_open_ptr = (i == int'(wbuf_write_hit_open_dir_ptr)); + timeout = (wbuf_dir_q[i].cnt == (cfg_threshold_i - 1)); + read_hit = read_flush_hit_i & wbuf_write_hit_open & match_open_ptr; + write_hit = write_i + & wbuf_write_hit_open + & match_open_ptr + & ~cfg_inhibit_write_coalescing_i; + + if (!flush_all_i) begin + if (write_hit && cfg_reset_timecnt_on_write_i) begin + timeout = 1'b0; + wbuf_dir_d[i].cnt = 0; + end else if (!timeout) begin + wbuf_dir_d[i].cnt = wbuf_dir_q[i].cnt + 1; + end + + if (read_hit | timeout | cfg_inhibit_write_coalescing_i) begin + wbuf_dir_state_d[i] = WBUF_PEND; + end + end else begin + wbuf_dir_state_d[i] = WBUF_PEND; + end + + if (write_hit) begin + wbuf_data_write( + wbuf_data_d[wbuf_dir_q[i].ptr].data, + wbuf_data_d[wbuf_dir_q[i].ptr].be, + wbuf_data_q[wbuf_dir_q[i].ptr].data, + wbuf_data_q[wbuf_dir_q[i].ptr].be, + write_data, + write_be + ); + end + end + + WBUF_PEND: begin + match_pend_ptr = (i == int'(wbuf_write_hit_pend_dir_ptr)); + write_hit = write_i + & wbuf_write_hit_pend + & match_pend_ptr + & ~cfg_inhibit_write_coalescing_i; + + if (write_hit) begin + wbuf_data_write( + wbuf_data_d[wbuf_dir_q[i].ptr].data, + wbuf_data_d[wbuf_dir_q[i].ptr].be, + wbuf_data_q[wbuf_dir_q[i].ptr].data, + wbuf_data_q[wbuf_dir_q[i].ptr].be, + write_data, + write_be + ); + end + + if (i == int'(wbuf_dir_send_ptr_q)) begin + fifo_send_data_w = send_meta_ready; + send_meta_valid = fifo_send_data_wok; + if (send_meta_ready && fifo_send_data_wok) begin + wbuf_dir_state_d[i] = WBUF_SENT; + end + end + end + + WBUF_SENT: begin + if (ack_i && (i == int'(ack_id_i))) begin + wbuf_dir_state_d[i] = WBUF_FREE; + end + end + endcase + end + end + + always_comb + begin : wbuf_data_valid_comb + wbuf_data_valid_d = wbuf_data_valid_q; + + // allocate a free data buffer on new write + if (write_i && wbuf_write_free) begin + wbuf_data_valid_d[wbuf_data_free_ptr_q] = 1'b1; + end + + // de-allocate a data buffer as soon as it is send + if (send_data_valid_o && send_data_ready_i) begin + wbuf_data_valid_d[fifo_send_data_q.send_data_ptr] = 1'b0; + end + end + // }}} + + // Send control + // {{{ + // Data channel + assign fifo_send_data_d.send_data_ptr = wbuf_dir_q[wbuf_dir_send_ptr_q].ptr, + fifo_send_data_d.send_data_tag = wbuf_dir_q[wbuf_dir_send_ptr_q].tag; + + hpdcache_fifo_reg #( + .FIFO_DEPTH (WBUF_SEND_FIFO_DEPTH), + .fifo_data_t (wbuf_send_data_t) + ) send_data_ptr_fifo_i ( + .clk_i, + .rst_ni, + .w_i (fifo_send_data_w), + .wok_o (fifo_send_data_wok), + .wdata_i (fifo_send_data_d), + .r_i (fifo_send_data_r), + .rok_o (fifo_send_data_rok), + .rdata_o (fifo_send_data_q) + ); + + assign fifo_send_data_r = send_data_ready_i, + send_data_valid_o = fifo_send_data_rok, + send_data_tag_o = wbuf_addr_t'(fifo_send_data_q.send_data_tag), + send_data_o = wbuf_data_q[fifo_send_data_q.send_data_ptr].data, + send_be_o = wbuf_data_q[fifo_send_data_q.send_data_ptr].be; + + // Meta-data channel + hpdcache_fifo_reg #( + .FIFO_DEPTH (WBUF_SEND_FIFO_DEPTH), + .fifo_data_t (wbuf_send_meta_t) + ) send_meta_fifo_i ( + .clk_i, + .rst_ni, + .w_i (send_meta_valid), + .wok_o (send_meta_ready), + .wdata_i (send_meta_wdata), + .r_i (send_meta_ready_i), + .rok_o (send_meta_valid_o), + .rdata_o (send_meta_rdata) + ); + + assign send_meta_wdata.send_meta_tag = wbuf_dir_q[wbuf_dir_send_ptr_q].tag, + send_meta_wdata.send_meta_id = wbuf_dir_send_ptr_q, + send_meta_wdata.send_meta_uc = wbuf_dir_q[wbuf_dir_send_ptr_q].uc; + + assign send_addr_o = { send_meta_rdata.send_meta_tag, {WBUF_OFFSET_WIDTH{1'b0}} }, + send_id_o = send_meta_rdata.send_meta_id, + send_uc_o = send_meta_rdata.send_meta_uc; + + // Send pointer + always_comb + begin : wbuf_send_comb + wbuf_dir_send_ptr_d = wbuf_dir_find_next(wbuf_dir_send_ptr_q, wbuf_dir_state_q, WBUF_PEND); + if (wbuf_dir_state_q[wbuf_dir_send_ptr_q] == WBUF_PEND) begin + if (!send_meta_valid || !send_meta_ready) begin + wbuf_dir_send_ptr_d = wbuf_dir_send_ptr_q; + end + end + end + // }}} + + // Internal state assignment + // {{{ + always_ff @(posedge clk_i) wbuf_data_q <= wbuf_data_d; + + always_ff @(posedge clk_i or negedge rst_ni) + begin : wbuf_state_ff + if (!rst_ni) begin + wbuf_dir_q <= '0; + wbuf_dir_state_q <= {WBUF_DIR_ENTRIES{WBUF_FREE}}; + wbuf_data_valid_q <= '0; + wbuf_dir_free_ptr_q <= 0; + wbuf_dir_send_ptr_q <= 0; + wbuf_data_free_ptr_q <= 0; + end else begin + wbuf_dir_q <= wbuf_dir_d; + wbuf_dir_state_q <= wbuf_dir_state_d; + wbuf_data_valid_q <= wbuf_data_valid_d; + wbuf_dir_free_ptr_q <= wbuf_dir_free_ptr_d; + wbuf_dir_send_ptr_q <= wbuf_dir_send_ptr_d; + wbuf_data_free_ptr_q <= wbuf_data_free_ptr_d; + end + end + // }}} + + // Assertions + // {{{ + // pragma translate_off + initial assert(WBUF_WORDS inside {1, 2, 4, 8, 16}) else + $error("WBUF: width of data buffers must be a power of 2"); + ack_sent_assert: assert property (@(posedge clk_i) + (ack_i -> (wbuf_dir_state_q[ack_id_i] == WBUF_SENT))) else + $error("WBUF: acknowledging a not SENT slot"); + send_pend_assert: assert property (@(posedge clk_i) + (send_meta_valid -> (wbuf_dir_state_q[wbuf_dir_send_ptr_q] == WBUF_PEND))) else + $error("WBUF: sending a not PEND slot"); + send_valid_data_assert: assert property (@(posedge clk_i) + (send_data_valid_o -> (wbuf_data_valid_q[fifo_send_data_q.send_data_ptr] == 1'b1))) else + $error("WBUF: sending a not valid data"); + // pragma translate_on + // }}} +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_wbuf_wrapper.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_wbuf_wrapper.sv new file mode 100644 index 00000000000..abb4e211d3c --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hpdcache_wbuf_wrapper.sv @@ -0,0 +1,227 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : HPDcache Write Buffer Wrapper + * History : + */ +/* This wrapper adapts the send interface of the write buffer to the memory + * interface of the cache. + */ +module hpdcache_wbuf_wrapper +import hpdcache_pkg::*; + // Parameters + // {{{ +#( + parameter int HPDcacheMemIdWidth = 8, + parameter int HPDcacheMemDataWidth = 512, + parameter type hpdcache_mem_req_t = logic, + parameter type hpdcache_mem_req_w_t = logic, + parameter type hpdcache_mem_resp_w_t = logic, + + localparam type hpdcache_mem_id_t = logic [HPDcacheMemIdWidth-1:0] +) + // }}} + // Ports + // {{{ +( + // Clock and reset signals + input logic clk_i, + input logic rst_ni, + + // Global control signals + output logic empty_o, + output logic full_o, + input logic flush_all_i, + + // Configuration signals + // Timer threshold + input wbuf_timecnt_t cfg_threshold_i, + // Reset timer on write + input logic cfg_reset_timecnt_on_write_i, + // Sequentialize write-after-write hazards + input logic cfg_sequential_waw_i, + // Inhibit write coalescing + input logic cfg_inhibit_write_coalescing_i, + + // Write interface + input logic write_i, + output logic write_ready_o, + input wbuf_addr_t write_addr_i, + input wbuf_data_t write_data_i, + input wbuf_be_t write_be_i, // byte-enable + input logic write_uc_i, // uncacheable write + + // Read hit interface + input wbuf_addr_t read_addr_i, + output logic read_hit_o, + input logic read_flush_hit_i, + + // Replay hit interface + input wbuf_addr_t replay_addr_i, + input logic replay_is_read_i, + output logic replay_open_hit_o, + output logic replay_pend_hit_o, + output logic replay_sent_hit_o, + output logic replay_not_ready_o, + + // Memory interface + input logic mem_req_write_ready_i, + output logic mem_req_write_valid_o, + output hpdcache_mem_req_t mem_req_write_o, + + input logic mem_req_write_data_ready_i, + output logic mem_req_write_data_valid_o, + output hpdcache_mem_req_w_t mem_req_write_data_o, + + output logic mem_resp_write_ready_o, + input logic mem_resp_write_valid_i, + input hpdcache_mem_resp_w_t mem_resp_write_i +); + // }}} + + // Internal signals + // {{{ + wbuf_addr_t send_addr; + wbuf_dir_ptr_t send_id; + logic send_uc; + wbuf_addr_t send_data_tag; + wbuf_data_buf_t send_data; + wbuf_be_buf_t send_be; + wbuf_dir_ptr_t ack_id; + logic ack_error; + // }}} + + // Wrapped write buffer + // {{{ + hpdcache_wbuf #( + .WBUF_DIR_ENTRIES (HPDCACHE_WBUF_DIR_ENTRIES), + .WBUF_DATA_ENTRIES (HPDCACHE_WBUF_DATA_ENTRIES), + .WBUF_WORD_WIDTH (HPDCACHE_REQ_DATA_WIDTH), + .WBUF_WORDS (HPDCACHE_WBUF_WORDS), + .WBUF_PA_WIDTH (HPDCACHE_PA_WIDTH), + .WBUF_TIMECNT_MAX ((2**HPDCACHE_WBUF_TIMECNT_WIDTH) - 1), + .WBUF_READ_MATCH_WIDTH (HPDCACHE_NLINE_WIDTH) + ) hpdcache_wbuf_i ( + .clk_i, + .rst_ni, + .empty_o, + .full_o, + .flush_all_i, + .cfg_threshold_i, + .cfg_reset_timecnt_on_write_i, + .cfg_sequential_waw_i, + .cfg_inhibit_write_coalescing_i, + .write_i, + .write_ready_o, + .write_addr_i, + .write_data_i, + .write_be_i, + .write_uc_i, + .read_addr_i, + .read_hit_o, + .read_flush_hit_i, + .replay_addr_i, + .replay_is_read_i, + .replay_open_hit_o, + .replay_pend_hit_o, + .replay_sent_hit_o, + .replay_not_ready_o, + .send_meta_ready_i (mem_req_write_ready_i), + .send_meta_valid_o (mem_req_write_valid_o), + .send_addr_o (send_addr), + .send_id_o (send_id), + .send_uc_o (send_uc), + .send_data_ready_i (mem_req_write_data_ready_i), + .send_data_valid_o (mem_req_write_data_valid_o), + .send_data_tag_o (send_data_tag), + .send_data_o (send_data), + .send_be_o (send_be), + .ack_i (mem_resp_write_valid_i), + .ack_id_i (ack_id), + .ack_error_i (ack_error) + ); + // }}} + + // Memory interface + // {{{ + assign mem_req_write_o.mem_req_addr = send_addr, + mem_req_write_o.mem_req_len = 0, + mem_req_write_o.mem_req_size = get_hpdcache_mem_size(HPDCACHE_WBUF_DATA_WIDTH/8), + mem_req_write_o.mem_req_id = hpdcache_mem_id_t'(send_id), + mem_req_write_o.mem_req_command = HPDCACHE_MEM_WRITE, + mem_req_write_o.mem_req_atomic = HPDCACHE_MEM_ATOMIC_ADD, + mem_req_write_o.mem_req_cacheable = ~send_uc; + + generate + localparam int unsigned WBUF_MEM_DATA_RATIO = HPDcacheMemDataWidth/HPDCACHE_WBUF_DATA_WIDTH; + localparam int unsigned WBUF_MEM_DATA_WORD_INDEX_WIDTH = $clog2(WBUF_MEM_DATA_RATIO); + + assign mem_req_write_data_o.mem_req_w_last = 1'b1; + + if (WBUF_MEM_DATA_RATIO > 1) + begin : wbuf_data_upsizing_gen + logic [HPDCACHE_WBUF_DATA_WIDTH/8-1:0][WBUF_MEM_DATA_RATIO-1:0] mem_req_be; + + // demux send BE + hpdcache_demux #( + .NOUTPUT (WBUF_MEM_DATA_RATIO), + .DATA_WIDTH (HPDCACHE_WBUF_DATA_WIDTH/8), + .ONE_HOT_SEL (1'b0) + ) mem_write_be_demux_i ( + .data_i (send_be), + .sel_i (send_data_tag[0 +: WBUF_MEM_DATA_WORD_INDEX_WIDTH]), + .data_o (mem_req_be) + ); + + assign mem_req_write_data_o.mem_req_w_data = {WBUF_MEM_DATA_RATIO{send_data}}, + mem_req_write_data_o.mem_req_w_be = mem_req_be; + + end else if (WBUF_MEM_DATA_RATIO == 1) + begin : wbuf_data_forwarding_gen + assign mem_req_write_data_o.mem_req_w_data = send_data, + mem_req_write_data_o.mem_req_w_be = send_be; + end + + // Assertions + // {{{ + // pragma translate_off + initial assert(WBUF_MEM_DATA_RATIO > 0) else + $error($sformatf("WBUF: data width of mem interface (%d) shall be g.e. to wbuf data width(%d)", + HPDcacheMemDataWidth, HPDCACHE_WBUF_DATA_WIDTH)); + // pragma translate_on + // }}} + endgenerate + + assign mem_resp_write_ready_o = 1'b1, + ack_id = mem_resp_write_i.mem_resp_w_id[0 +: HPDCACHE_WBUF_DIR_PTR_WIDTH], + ack_error = (mem_resp_write_i.mem_resp_w_error != HPDCACHE_MEM_RESP_OK); + // }}} + + // Assertions + // {{{ + // pragma translate_off + initial assert (HPDCACHE_WBUF_DIR_PTR_WIDTH <= HPDcacheMemIdWidth) else + $fatal("HPDcacheMemIdWidth is not wide enough to fit all possible write buffer transactions"); + // pragma translate_on + // }}} + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride.sv new file mode 100644 index 00000000000..dfef92daac2 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride.sv @@ -0,0 +1,374 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Riccardo Alidori, Cesar Fuguet + * Maintainers(s): Cesar Fuguet + * Creation Date : June, 2021 + * Description : HPDcache Linear Hardware Memory Prefetcher. + * History : + */ +module hwpf_stride +import hwpf_stride_pkg::*; +import hpdcache_pkg::*; +// Parameters +// {{{ +#( + parameter int CACHE_LINE_BYTES = 64 +) +// }}} + +// Ports +// {{{ +( + input logic clk_i, + input logic rst_ni, + + // CSR + input logic csr_base_set_i, + input hwpf_stride_base_t csr_base_i, + input logic csr_param_set_i, + input hwpf_stride_param_t csr_param_i, + input logic csr_throttle_set_i, + input hwpf_stride_throttle_t csr_throttle_i, + + output hwpf_stride_base_t csr_base_o, + output hwpf_stride_param_t csr_param_o, + output hwpf_stride_throttle_t csr_throttle_o, + + // If high, the prefetcher is enabled and active + output logic busy_o, + + // Snooping + // Address to snoop on requests ports + output hpdcache_nline_t snoop_nline_o, + // If set to one, the snoop address matched one of the requests + input snoop_match_i, + + // D-Cache interface + output logic hpdcache_req_valid_o, + input logic hpdcache_req_ready_i, + output hpdcache_req_t hpdcache_req_o, + input logic hpdcache_rsp_valid_i, + input hpdcache_rsp_t hpdcache_rsp_i +); +// }}} + + import hpdcache_pkg::hpdcache_req_addr_t; + + // Definition of constants + // {{{ + localparam int STRIDE_WIDTH = $bits(csr_param_i.stride); + localparam int NBLOCKS_WIDTH = $bits(csr_param_i.nblocks); + localparam int NLINES_WIDTH = $bits(csr_param_i.nlines); + localparam int NWAIT_WIDTH = $bits(csr_throttle_i.nwait); + localparam int INFLIGHT_WIDTH = $bits(csr_throttle_i.ninflight); + localparam int NLINES_CNT_WIDTH = NLINES_WIDTH; + // }}} + + // Internal registers and signals + // {{{ + // FSM + enum { + IDLE, + SNOOP, + SEND_REQ, + WAIT, + DONE, + ABORT + } state_d, state_q; + + logic [NBLOCKS_WIDTH-1:0] nblocks_cnt_d, nblocks_cnt_q; + logic [NLINES_CNT_WIDTH-1:0] nlines_cnt_d, nlines_cnt_q; + logic [NWAIT_WIDTH-1:0] nwait_cnt_d, nwait_cnt_q; + logic [INFLIGHT_WIDTH-1:0] inflight_cnt_d, inflight_cnt_q; + logic inflight_inc, inflight_dec; + + hwpf_stride_base_t csr_base_q; + hwpf_stride_base_t shadow_base_q, shadow_base_d; + hwpf_stride_param_t csr_param_q; + hwpf_stride_param_t shadow_param_q, shadow_param_d; + hwpf_stride_throttle_t csr_throttle_q; + hwpf_stride_throttle_t shadow_throttle_q, shadow_throttle_d; + hpdcache_nline_t request_nline_q, request_nline_d; + + hpdcache_set_t hpdcache_req_set; + hpdcache_tag_t hpdcache_req_tag; + + logic csr_base_update; + hpdcache_nline_t increment_stride; + logic is_inflight_max; + + // Default assignment + assign increment_stride = hpdcache_nline_t'(shadow_param_q.stride) + 1'b1; + assign inflight_dec = hpdcache_rsp_valid_i; + assign snoop_nline_o = shadow_base_q.base_cline; + assign is_inflight_max = ( shadow_throttle_q.ninflight == '0 ) ? + 1'b0 : ( inflight_cnt_q >= shadow_throttle_q.ninflight ); + assign csr_base_o = csr_base_q; + assign csr_param_o = csr_param_q; + assign csr_throttle_o = csr_throttle_q; + // }}} + + // Dcache outputs + // {{{ + assign hpdcache_req_set = request_nline_q[0 +: HPDCACHE_SET_WIDTH], + hpdcache_req_tag = request_nline_q[HPDCACHE_SET_WIDTH +: HPDCACHE_TAG_WIDTH]; + + assign hpdcache_req_o.addr_offset = { hpdcache_req_set, {HPDCACHE_OFFSET_WIDTH{1'b0}} }, + hpdcache_req_o.wdata = '0, + hpdcache_req_o.op = HPDCACHE_REQ_CMO, + hpdcache_req_o.be = '1, + hpdcache_req_o.size = HPDCACHE_REQ_CMO_PREFETCH, + hpdcache_req_o.sid = '0, // this is set when connecting to the dcache + hpdcache_req_o.tid = '0, // this is set by the wrapper of the prefetcher + hpdcache_req_o.need_rsp = 1'b1, + hpdcache_req_o.phys_indexed = 1'b1, + hpdcache_req_o.addr_tag = hpdcache_req_tag, + hpdcache_req_o.pma.uncacheable = 1'b0, + hpdcache_req_o.pma.io = 1'b0; + // }}} + + // Set state of internal registers + // {{{ + always_ff @(posedge clk_i or negedge rst_ni) + begin + if (!rst_ni) begin + csr_base_q <= '0; + csr_param_q <= '0; + shadow_base_q <= '0; + shadow_param_q <= '0; + shadow_throttle_q <= '0; + request_nline_q <= '0; + state_q <= IDLE; + end else begin + if (csr_base_set_i) csr_base_q <= csr_base_i; + else if (csr_base_update) csr_base_q <= shadow_base_d; + if (csr_param_set_i) csr_param_q <= csr_param_i; + if (csr_throttle_set_i) csr_throttle_q <= csr_throttle_i; + shadow_base_q <= shadow_base_d; + shadow_param_q <= shadow_param_d; + shadow_throttle_q <= shadow_throttle_d; + request_nline_q <= request_nline_d; + state_q <= state_d; + end + end + // }}} + + // Update internal counters + // {{{ + always_comb begin : inflight_cnt + inflight_cnt_d = inflight_cnt_q; + + // Every time we send a dcache request, increment the counter + if ( inflight_inc ) begin + inflight_cnt_d++; + end + + // Every time we got a response from the cache, decrement the counter + if ( inflight_dec && ( inflight_cnt_q > 0 )) begin + inflight_cnt_d--; + end + end + + always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + nblocks_cnt_q <= '0; + nlines_cnt_q <= '0; + nwait_cnt_q <= '0; + inflight_cnt_q <= '0; + end else begin + nblocks_cnt_q <= nblocks_cnt_d; + nlines_cnt_q <= nlines_cnt_d; + nwait_cnt_q <= nwait_cnt_d; + inflight_cnt_q <= inflight_cnt_d; + end + end + // }}} + + // FSM + // {{{ + always_comb begin : fsm_control + // default assignments + hpdcache_req_valid_o = 1'b0; + nblocks_cnt_d = nblocks_cnt_q; + nlines_cnt_d = nlines_cnt_q; + nwait_cnt_d = nwait_cnt_q; + inflight_inc = 1'b0; + busy_o = 1'b0; + csr_base_update = 1'b0; + + shadow_base_d = shadow_base_q; + shadow_param_d = shadow_param_q; + shadow_throttle_d = shadow_throttle_q; + request_nline_d = request_nline_q; + state_d = state_q; + + case ( state_q ) + + IDLE: begin + // If enabled, go snooping the dcache ports + if ( csr_base_q.enable ) begin + shadow_base_d = csr_base_q; + if (( csr_param_q.nlines > 0 ) || ( csr_param_q.nblocks > 0 )) begin + shadow_param_d = csr_param_q; + shadow_throttle_d = csr_throttle_q; + state_d = SNOOP; + end else begin + // no prefetch needed, disarm immediately + shadow_base_d.enable = 1'b0; + csr_base_update = 1'b1; + end + end + end + + + SNOOP: begin + if ( csr_base_q.enable ) begin + // If a snooper matched an address, send the request + if ( snoop_match_i ) begin + state_d = SEND_REQ; + + if ( shadow_param_q.nlines == 0 ) begin + // skip the first block + request_nline_d = shadow_base_q.base_cline + + hpdcache_nline_t'(increment_stride); + nblocks_cnt_d = ( shadow_param_q.nblocks > 0 ) ? + shadow_param_q.nblocks - 1 : 0; + nlines_cnt_d = 0; + + // update the base cacheline to the first one of the next block + shadow_base_d.base_cline = request_nline_d; + end else begin + // skip the first cacheline (of the first block) + request_nline_d = shadow_base_q.base_cline + 1'b1; + nblocks_cnt_d = shadow_param_q.nblocks; + nlines_cnt_d = shadow_param_q.nlines - 1; + end + end + end else begin + state_d = IDLE; + end + end + + + SEND_REQ: begin + busy_o = 1'b1; + + // make the prefetch request to memory + hpdcache_req_valid_o = 1'b1; + + // we've got a grant, so we can move to the next request + if ( hpdcache_req_ready_i ) begin + inflight_inc = 1'b1; + + if ( nlines_cnt_q == 0 ) begin + // go to the first cacheline of the next block + request_nline_d = shadow_base_q.base_cline + + hpdcache_nline_t'(increment_stride); + nblocks_cnt_d = ( nblocks_cnt_q > 0 ) ? nblocks_cnt_q - 1 : 0; + nlines_cnt_d = shadow_param_q.nlines; + + // update the base cacheline to the first one of the next block + shadow_base_d.base_cline = request_nline_d; + end else begin + // go to the next cacheline (within the same block) + request_nline_d = request_nline_q + 1'b1; + nlines_cnt_d = nlines_cnt_q - 1; + end + + // if the NWAIT parameter is equal 0, we can issue a request every cycle + if (( nblocks_cnt_q == 0 ) && ( nlines_cnt_q == 0 )) begin + state_d = DONE; + end else if ( shadow_throttle_q.nwait == 0 ) begin + // Wait if the number of inflight requests is greater than + // the maximum indicated. Otherwise, send the next request + state_d = is_inflight_max ? WAIT : SEND_REQ; + end else begin + // Wait the indicated cycles before sending the next request + nwait_cnt_d = shadow_throttle_q.nwait; + state_d = WAIT; + end + + if ( !csr_base_q.enable ) state_d = ABORT; + end + end + + + WAIT: begin + // Wait until: + // - the indicated number of wait cycles between requests is reached (nwait) + // - the number of inflight requests is below the indicated maximum (ninflight) + busy_o = 1'b1; + if ( csr_base_q.enable ) begin + if ( !is_inflight_max && ( nwait_cnt_q == 0 )) begin + state_d = SEND_REQ; + end + + if ( nwait_cnt_q > 0 ) begin + nwait_cnt_d = nwait_cnt_q - 1; + end + end else begin + state_d = ABORT; + end + end + + + DONE: begin + busy_o = 1'b1; + if ( csr_base_q.enable ) begin + if (( inflight_cnt_q == 0 ) && !is_inflight_max && ( nwait_cnt_q == 0 )) begin + // Copy back shadow base register into the user visible one + csr_base_update = 1'b1; + + // Check the rearm bit + if ( shadow_base_q.rearm ) begin + state_d = SNOOP; + end else begin + state_d = IDLE; + + // disarm the prefetcher + shadow_base_d.enable = 1'b0; + end + + // Check the cycle bit + if ( shadow_base_q.cycle ) begin + // restore the base address + shadow_base_d.base_cline = csr_base_q.base_cline; + end + end + + if ( nwait_cnt_q > 0 ) begin + nwait_cnt_d = nwait_cnt_q - 1; + end + end else begin + state_d = ABORT; + end + end + + ABORT: begin + busy_o = 1'b1; + if ( inflight_cnt_q == 0 ) begin + state_d = IDLE; + end + end + endcase + end + // }}} +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_arb.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_arb.sv new file mode 100644 index 00000000000..1aa9df485ff --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_arb.sv @@ -0,0 +1,117 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Author(s) : Riccardo Alidori, Cesar Fuguet + * Creation Date : June, 2021 + * Description : Hw prefetchers arbiter + * History : + */ +module hwpf_stride_arb +import hpdcache_pkg::*; +// Parameters +// {{{ +#( + parameter NUM_HW_PREFETCH = 4 +) +// }}} + +// Ports +// {{{ +( + input logic clk_i, + input logic rst_ni, + + // Dcache input interface + input logic [NUM_HW_PREFETCH-1:0] hwpf_stride_req_valid_i, + output logic [NUM_HW_PREFETCH-1:0] hwpf_stride_req_ready_o, + input hpdcache_req_t [NUM_HW_PREFETCH-1:0] hwpf_stride_req_i, + output logic [NUM_HW_PREFETCH-1:0] hwpf_stride_rsp_valid_o, + output hpdcache_rsp_t [NUM_HW_PREFETCH-1:0] hwpf_stride_rsp_o, // Not used + + // Dcache output interface + output logic hpdcache_req_valid_o, + input logic hpdcache_req_ready_i, + output hpdcache_req_t hpdcache_req_o, + input logic hpdcache_rsp_valid_i, + input hpdcache_rsp_t hpdcache_rsp_i // Not used +); +// }}} + + // Internal signals + // {{{ + logic [NUM_HW_PREFETCH-1:0] hwpf_stride_req_valid; + hpdcache_req_t [NUM_HW_PREFETCH-1:0] hwpf_stride_req; + logic [NUM_HW_PREFETCH-1:0] arb_req_gnt; + // }}} + + // Requesters arbiter + // {{{ + // Pack request ports + genvar gen_i; + generate + for (gen_i = 0; gen_i < NUM_HW_PREFETCH; gen_i++) begin : gen_hwpf_stride_req + assign hwpf_stride_req_ready_o[gen_i] = arb_req_gnt[gen_i] & hpdcache_req_ready_i, + hwpf_stride_req_valid[gen_i] = hwpf_stride_req_valid_i[gen_i], + hwpf_stride_req[gen_i] = hwpf_stride_req_i[gen_i]; + end + endgenerate + + // Arbiter + hpdcache_rrarb #( + .N (NUM_HW_PREFETCH) + ) hwpf_stride_req_arbiter_i ( + .clk_i, + .rst_ni, + .req_i (hwpf_stride_req_valid), + .gnt_o (arb_req_gnt), + .ready_i (hpdcache_req_ready_i) + ); + + // Request Multiplexor + hpdcache_mux #( + .NINPUT (NUM_HW_PREFETCH), + .DATA_WIDTH ($bits(hpdcache_req_t)), + .ONE_HOT_SEL (1'b1) + ) hwpf_stride_req_mux_i ( + .data_i (hwpf_stride_req), + .sel_i (arb_req_gnt), + .data_o (hpdcache_req_o) + ); + + assign hpdcache_req_valid_o = |arb_req_gnt; + // }}} + + // Response demultiplexor + // {{{ + // As the HW prefetcher does not need the TID field in the request, we + // use it to transport the identifier of the specific hardware + // prefetcher. + // This way we share the same SID for all HW prefetchers. Using + // different SIDs means that we need different ports to the cache and + // we actually want to reduce those. + always_comb + begin : resp_demux + for (int unsigned i = 0; i < NUM_HW_PREFETCH; i++) begin + hwpf_stride_rsp_valid_o[i] = hpdcache_rsp_valid_i && (i == int'(hpdcache_rsp_i.tid)); + hwpf_stride_rsp_o[i] = hpdcache_rsp_i; + end + end + // }}} +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_pkg.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_pkg.sv new file mode 100644 index 00000000000..3470b78620d --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_pkg.sv @@ -0,0 +1,68 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : January, 2023 + * Description : High-Performance, Data-cache (HPDcache) HW memory + * prefetcher package + * History : + */ +package hwpf_stride_pkg; + // Base address configuration register of the hardware memory prefetcher + // {{{ + typedef struct packed { + logic [63:6] base_cline; + logic [5:3] unused; + logic cycle; + logic rearm; + logic enable; + } hwpf_stride_base_t; + // }}} + + // Parameters configuration register of the hardware memory prefetcher + // {{{ + typedef struct packed { + logic [63:48] nblocks; + logic [47:32] nlines; + logic [31:0] stride; + } hwpf_stride_param_t; + // }}} + + // Throttle configuration register of the hardware memory prefetcher + // {{{ + typedef struct packed { + logic [31:16] ninflight; + logic [15:0] nwait; + } hwpf_stride_throttle_t; + // }}} + + // Status register of the hardware memory prefetcher + // {{{ + typedef struct packed { + logic [63:48] unused1; + logic [47:32] busy; + logic free; + logic [30:20] unused0; + logic [19:16] free_index; + logic [15:0] enabled; + } hwpf_stride_status_t; + // }}} + +endpackage diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_snooper.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_snooper.sv new file mode 100644 index 00000000000..ba995b50621 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_snooper.sv @@ -0,0 +1,38 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Riccardo Alidori, Cesar Fuguet + * Creation Date : June, 2021 + * Description : Snooper used by the hardware memory prefetcher + * History : + */ +module hwpf_stride_snooper +import hpdcache_pkg::*; +( + input logic en_i, // Snooper enable bit. + input hpdcache_nline_t base_nline_i, // Address to check + input hpdcache_nline_t snoop_addr_i, // Input address to snoop + output snoop_match_o // If high, the Snoopers matched the snoop_address +); + + // The snooper match if enabled and the two addresses are equal + assign snoop_match_o = en_i && ( base_nline_i == snoop_addr_i ); + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_wrapper.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_wrapper.sv new file mode 100644 index 00000000000..fa1cfa4f9ee --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/hwpf_stride/hwpf_stride_wrapper.sv @@ -0,0 +1,265 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Riccardo Alidori, Cesar Fuguet + * Creation Date : June, 2021 + * Description : Linear Hardware Memory Prefetcher wrapper. + * History : + */ +module hwpf_stride_wrapper +import hwpf_stride_pkg::*; +import hpdcache_pkg::*; +// Parameters +// {{{ +#( + parameter NUM_HW_PREFETCH = 4, + parameter NUM_SNOOP_PORTS = 1 +) +// }}} + +// Ports +// {{{ +( + input logic clk_i, + input logic rst_ni, + + // CSR + // {{{ + input logic [NUM_HW_PREFETCH-1:0] hwpf_stride_base_set_i, + input hwpf_stride_base_t [NUM_HW_PREFETCH-1:0] hwpf_stride_base_i, + output hwpf_stride_base_t [NUM_HW_PREFETCH-1:0] hwpf_stride_base_o, + + input logic [NUM_HW_PREFETCH-1:0] hwpf_stride_param_set_i, + input hwpf_stride_param_t [NUM_HW_PREFETCH-1:0] hwpf_stride_param_i, + output hwpf_stride_param_t [NUM_HW_PREFETCH-1:0] hwpf_stride_param_o, + + input logic [NUM_HW_PREFETCH-1:0] hwpf_stride_throttle_set_i, + input hwpf_stride_throttle_t [NUM_HW_PREFETCH-1:0] hwpf_stride_throttle_i, + output hwpf_stride_throttle_t [NUM_HW_PREFETCH-1:0] hwpf_stride_throttle_o, + + output hwpf_stride_status_t hwpf_stride_status_o, + // }}} + + // Snooping + // {{{ + input logic [NUM_SNOOP_PORTS-1:0] snoop_valid_i, + input logic [NUM_SNOOP_PORTS-1:0] snoop_abort_i, + input hpdcache_req_offset_t [NUM_SNOOP_PORTS-1:0] snoop_addr_offset_i, + input hpdcache_tag_t [NUM_SNOOP_PORTS-1:0] snoop_addr_tag_i, + input logic [NUM_SNOOP_PORTS-1:0] snoop_phys_indexed_i, + // }}} + + // Dcache interface + // {{{ + input hpdcache_req_sid_t hpdcache_req_sid_i, + output logic hpdcache_req_valid_o, + input logic hpdcache_req_ready_i, + output hpdcache_req_t hpdcache_req_o, + output logic hpdcache_req_abort_o, + output hpdcache_tag_t hpdcache_req_tag_o, + output hpdcache_pma_t hpdcache_req_pma_o, + input logic hpdcache_rsp_valid_i, + input hpdcache_rsp_t hpdcache_rsp_i + // }}} +); +// }}} + + // Internal registers + // {{{ + logic [NUM_SNOOP_PORTS-1:0] snoop_valid_q; + hpdcache_req_offset_t [NUM_SNOOP_PORTS-1:0] snoop_addr_offset_q; + // }}} + + // Internal signals + // {{{ + logic [NUM_HW_PREFETCH-1:0] hwpf_stride_enable; + logic [NUM_HW_PREFETCH-1:0] hwpf_stride_free; + logic [NUM_HW_PREFETCH-1:0] hwpf_stride_status_busy; + logic [3:0] hwpf_stride_status_free_idx; + + hpdcache_nline_t [NUM_HW_PREFETCH-1:0] hwpf_snoop_nline; + logic [NUM_HW_PREFETCH-1:0] hwpf_snoop_match; + + logic [NUM_HW_PREFETCH-1:0] hwpf_stride_req_valid; + logic [NUM_HW_PREFETCH-1:0] hwpf_stride_req_ready; + hpdcache_req_t [NUM_HW_PREFETCH-1:0] hwpf_stride_req; + + logic [NUM_HW_PREFETCH-1:0] hwpf_stride_arb_in_req_valid; + logic [NUM_HW_PREFETCH-1:0] hwpf_stride_arb_in_req_ready; + hpdcache_req_t [NUM_HW_PREFETCH-1:0] hwpf_stride_arb_in_req; + logic [NUM_HW_PREFETCH-1:0] hwpf_stride_arb_in_rsp_valid; + hpdcache_rsp_t [NUM_HW_PREFETCH-1:0] hwpf_stride_arb_in_rsp; + // }}} + + // Assertions + // {{{ + // pragma translate_off + initial + begin + max_hwpf_stride_assert: assert (NUM_HW_PREFETCH <= 16) else + $error("hwpf_stride: maximum number of HW prefetchers is 16"); + end + // pragma translate_on + // }}} + + // Compute the status information + // {{{ + always_comb begin: hwpf_stride_priority_encoder + hwpf_stride_status_free_idx = '0; + for (int unsigned i = 0; i < NUM_HW_PREFETCH; i++) begin + if (hwpf_stride_free[i]) begin + hwpf_stride_status_free_idx = i; + break; + end + end + end + + // Free flag of engines + assign hwpf_stride_free = ~(hwpf_stride_enable | hwpf_stride_status_busy); + // Busy flags + assign hwpf_stride_status_o[63:32] = {{32-NUM_HW_PREFETCH{1'b0}}, hwpf_stride_status_busy}; + // Global free flag + assign hwpf_stride_status_o[31] = |hwpf_stride_free; + // Free Index + assign hwpf_stride_status_o[30:16] = {11'b0, hwpf_stride_status_free_idx}; + // Enable flags + assign hwpf_stride_status_o[15:0] = {{16-NUM_HW_PREFETCH{1'b0}}, hwpf_stride_enable}; + // }}} + + // Hardware prefetcher engines + // {{{ + generate + for (genvar j = 0; j < NUM_SNOOP_PORTS; j++) begin + always_ff @(posedge clk_i or negedge rst_ni) + begin : snoop_ff + if (!rst_ni) begin + snoop_valid_q[j] <= 1'b0; + snoop_addr_offset_q[j] <= '0; + end else begin + if (snoop_phys_indexed_i[j]) begin + snoop_valid_q[j] <= snoop_valid_i[j]; + snoop_addr_offset_q[j] <= snoop_addr_offset_i[j]; + end + end + end + end + + for (genvar i = 0; i < NUM_HW_PREFETCH; i++) begin + assign hwpf_stride_enable[i] = hwpf_stride_base_o[i].enable; + + // Compute snoop match signals + // {{{ + always_comb + begin : snoop_comb + hwpf_snoop_match[i] = 1'b0; + for (int j = 0; j < NUM_SNOOP_PORTS; j++) begin + automatic logic snoop_valid; + automatic hpdcache_req_offset_t snoop_offset; + automatic hpdcache_nline_t snoop_nline; + + if (snoop_phys_indexed_i[j]) begin + snoop_valid = snoop_valid_i[j]; + snoop_offset = snoop_addr_offset_i[j]; + end else begin + snoop_valid = snoop_valid_q[j]; + snoop_offset = snoop_addr_offset_q[j]; + end + snoop_nline = {snoop_addr_tag_i[j], snoop_offset}; + hwpf_snoop_match[i] |= (snoop_valid && !snoop_abort_i[j] && + (hwpf_snoop_nline[i] == snoop_nline)); + end + end + // }}} + + hwpf_stride #( + .CACHE_LINE_BYTES ( HPDCACHE_CL_WIDTH/8 ) + ) hwpf_stride_i( + .clk_i, + .rst_ni, + + .csr_base_set_i ( hwpf_stride_base_set_i[i] ), + .csr_base_i ( hwpf_stride_base_i[i] ), + .csr_param_set_i ( hwpf_stride_param_set_i[i] ), + .csr_param_i ( hwpf_stride_param_i[i] ), + .csr_throttle_set_i ( hwpf_stride_throttle_set_i[i] ), + .csr_throttle_i ( hwpf_stride_throttle_i[i] ), + + .csr_base_o ( hwpf_stride_base_o[i] ), + .csr_param_o ( hwpf_stride_param_o[i] ), + .csr_throttle_o ( hwpf_stride_throttle_o[i] ), + + .busy_o ( hwpf_stride_status_busy[i] ), + + .snoop_nline_o ( hwpf_snoop_nline[i] ), + .snoop_match_i ( hwpf_snoop_match[i] ), + + .hpdcache_req_valid_o ( hwpf_stride_req_valid[i] ), + .hpdcache_req_ready_i ( hwpf_stride_req_ready[i] ), + .hpdcache_req_o ( hwpf_stride_req[i] ), + .hpdcache_rsp_valid_i ( hwpf_stride_arb_in_rsp_valid[i] ), + .hpdcache_rsp_i ( hwpf_stride_arb_in_rsp[i] ) + ); + + assign hwpf_stride_req_ready[i] = hwpf_stride_arb_in_req_ready[i], + hwpf_stride_arb_in_req_valid[i] = hwpf_stride_req_valid[i], + hwpf_stride_arb_in_req[i].addr_offset = hwpf_stride_req[i].addr_offset, + hwpf_stride_arb_in_req[i].wdata = hwpf_stride_req[i].wdata, + hwpf_stride_arb_in_req[i].op = hwpf_stride_req[i].op, + hwpf_stride_arb_in_req[i].be = hwpf_stride_req[i].be, + hwpf_stride_arb_in_req[i].size = hwpf_stride_req[i].size, + hwpf_stride_arb_in_req[i].sid = hpdcache_req_sid_i, + hwpf_stride_arb_in_req[i].tid = hpdcache_req_tid_t'(i), + hwpf_stride_arb_in_req[i].need_rsp = hwpf_stride_req[i].need_rsp, + hwpf_stride_arb_in_req[i].phys_indexed = hwpf_stride_req[i].phys_indexed, + hwpf_stride_arb_in_req[i].addr_tag = '0, + hwpf_stride_arb_in_req[i].pma = '0; + end + endgenerate + // }}} + + // Hardware prefetcher arbiter betweem engines + // {{{ + hwpf_stride_arb #( + .NUM_HW_PREFETCH ( NUM_HW_PREFETCH ) + ) hwpf_stride_arb_i ( + .clk_i, + .rst_ni, + + // DCache input interface + .hwpf_stride_req_valid_i ( hwpf_stride_arb_in_req_valid ), + .hwpf_stride_req_ready_o ( hwpf_stride_arb_in_req_ready ), + .hwpf_stride_req_i ( hwpf_stride_arb_in_req ), + .hwpf_stride_rsp_valid_o ( hwpf_stride_arb_in_rsp_valid ), + .hwpf_stride_rsp_o ( hwpf_stride_arb_in_rsp ), + + // DCache output interface + .hpdcache_req_valid_o, + .hpdcache_req_ready_i, + .hpdcache_req_o, + .hpdcache_rsp_valid_i, + .hpdcache_rsp_i + ); + + assign hpdcache_req_abort_o = 1'b0, // unused on physically indexed requests + hpdcache_req_tag_o = '0, // unused on physically indexed requests + hpdcache_req_pma_o = '0; // unused on physically indexed requests + // }}} + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_cmo_if_adapter.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_cmo_if_adapter.sv new file mode 100644 index 00000000000..a487006c6c6 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_cmo_if_adapter.sv @@ -0,0 +1,186 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : Interface adapter for the CMO interface of the CVA6 core + * History : + */ +module cva6_hpdcache_cmo_if_adapter +import hpdcache_pkg::*; + +// Parameters +// {{{ +#( + parameter type cmo_req_t = logic, + parameter type cmo_rsp_t = logic +) +// }}} + +// Ports +// {{{ +( + // Clock and active-low reset pins + input logic clk_i, + input logic rst_ni, + + // Port ID + input hpdcache_pkg::hpdcache_req_sid_t dcache_req_sid_i, + + // Request/response ports from/to the CVA6 core + input cmo_req_t cva6_cmo_req_i, + output cmo_rsp_t cva6_cmo_resp_o, + + // Request port to the L1 Dcache + output logic dcache_req_valid_o, + input logic dcache_req_ready_i, + output hpdcache_pkg::hpdcache_req_t dcache_req_o, + + // Response port from the L1 Dcache + input logic dcache_rsp_valid_i, + input hpdcache_pkg::hpdcache_rsp_t dcache_rsp_i +); +// }}} + + // Internal nets and registers + // {{{ + enum { + FORWARD_IDLE, + FORWARD_CMO, + FORWARD_CMO_ACK + } forward_state_q, forward_state_d; + + logic forward_cmo; + hpdcache_pkg::hpdcache_req_t dcache_req_cmo; + logic [ariane_pkg::TRANS_ID_BITS-1:0] cmo_tid_q, cmo_tid_d; + logic cmo_ack; + logic stall; + // }}} + + // Request forwarding + // {{{ + always_comb + begin : req_forward_comb + forward_state_d = forward_state_q; + forward_cmo = 1'b0; + cmo_tid_d = cmo_tid_q; + cmo_ack = 1'b0; + stall = 1'b0; + + case (forward_state_q) + FORWARD_IDLE: begin + if (cva6_cmo_req_i.req) begin + stall = ~dcache_req_ready_i; + forward_cmo = 1'b1; + cmo_tid_d = cva6_cmo_req_i.trans_id; + if (!dcache_req_ready_i) begin + forward_state_d = FORWARD_CMO; + end else begin + forward_state_d = FORWARD_CMO_ACK; + end + end + end + + FORWARD_CMO: begin + stall = ~dcache_req_ready_i; + forward_cmo = 1'b1; + if (dcache_req_ready_i) begin + forward_state_d = FORWARD_CMO_ACK; + end + end + + FORWARD_CMO_ACK: begin + stall = 1'b1; + cmo_ack = 1'b1; + if (cva6_cmo_req_i.req) begin + stall = ~dcache_req_ready_i; + forward_cmo = 1'b1; + cmo_tid_d = cva6_cmo_req_i.trans_id; + if (!dcache_req_ready_i) begin + forward_state_d = FORWARD_CMO; + end else begin + forward_state_d = FORWARD_CMO_ACK; + end + end else begin + forward_state_d = FORWARD_IDLE; + end + end + endcase + end + + always_ff @(posedge clk_i or negedge rst_ni) + begin : forward_ff + if (!rst_ni) begin + forward_state_q <= FORWARD_IDLE; + cmo_tid_q <= '0; + end else begin + forward_state_q <= forward_state_d; + cmo_tid_q <= cmo_tid_d; + end + end + + // CMO request + // {{{ + always_comb + begin : cmo_req + dcache_req_cmo.addr = hpdcache_req_addr_t'(cva6_cmo_req_i.address); + dcache_req_cmo.need_rsp = 1'b0; + dcache_req_cmo.uncacheable = 1'b0; + dcache_req_cmo.sid = dcache_req_sid_i; + dcache_req_cmo.tid = cva6_cmo_req_i.trans_id; + dcache_req_cmo.wdata = '0; + dcache_req_cmo.be = '0; + dcache_req_cmo.op = HPDCACHE_REQ_CMO; + dcache_req_cmo.size = '0; + case (cva6_cmo_req_i.cmo_op) + ariane_pkg::CMO_CLEAN, + ariane_pkg::CMO_FLUSH, + ariane_pkg::CMO_ZERO: begin + // FIXME + end + ariane_pkg::CMO_INVAL: begin + dcache_req_cmo.size = HPDCACHE_REQ_CMO_INVAL_NLINE; + end + ariane_pkg::CMO_PREFETCH_R, + ariane_pkg::CMO_PREFETCH_W: begin + dcache_req_cmo.size = HPDCACHE_REQ_CMO_PREFETCH; + end + ariane_pkg::CMO_CLEAN_ALL, + ariane_pkg::CMO_FLUSH_ALL: begin + end + ariane_pkg::CMO_INVAL_ALL: begin + dcache_req_cmo.size = HPDCACHE_REQ_CMO_INVAL_ALL; + end + endcase + end + // }}} + + assign dcache_req_valid_o = forward_cmo, + dcache_req_o = dcache_req_cmo, + cva6_cmo_resp_o.req_ready = ~stall; + // }}} + + // Response forwarding + // {{{ + assign cva6_cmo_resp_o.ack = cmo_ack, + cva6_cmo_resp_o.trans_id = cmo_tid_q; + // }}} + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_if_adapter.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_if_adapter.sv new file mode 100644 index 00000000000..dd298efed4d --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_if_adapter.sv @@ -0,0 +1,217 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : Interface adapter for the CVA6 core + * History : + */ +module cva6_hpdcache_if_adapter +import hpdcache_pkg::*; + +// Parameters +// {{{ +#( + parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty, + parameter bit is_load_port = 1'b1 +) +// }}} + +// Ports +// {{{ +( + // Clock and active-low reset pins + input logic clk_i, + input logic rst_ni, + + // Port ID + input hpdcache_pkg::hpdcache_req_sid_t hpdcache_req_sid_i, + + // Request/response ports from/to the CVA6 core + input ariane_pkg::dcache_req_i_t cva6_req_i, + output ariane_pkg::dcache_req_o_t cva6_req_o, + input ariane_pkg::amo_req_t cva6_amo_req_i, + output ariane_pkg::amo_resp_t cva6_amo_resp_o, + + // Request port to the L1 Dcache + output logic hpdcache_req_valid_o, + input logic hpdcache_req_ready_i, + output hpdcache_pkg::hpdcache_req_t hpdcache_req_o, + output logic hpdcache_req_abort_o, + output hpdcache_pkg::hpdcache_tag_t hpdcache_req_tag_o, + output hpdcache_pkg::hpdcache_pma_t hpdcache_req_pma_o, + + // Response port from the L1 Dcache + input logic hpdcache_rsp_valid_i, + input hpdcache_pkg::hpdcache_rsp_t hpdcache_rsp_i +); +// }}} + + // Internal nets and registers + // {{{ + logic forward_store, forward_amo; + logic hpdcache_req_is_uncacheable; + // }}} + + // Request forwarding + // {{{ + generate + // LOAD request + // {{{ + if (is_load_port == 1'b1) begin : load_port_gen + assign hpdcache_req_is_uncacheable = + !config_pkg::is_inside_cacheable_regions(CVA6Cfg, + {{64 - ariane_pkg::DCACHE_TAG_WIDTH{1'b0}} + , cva6_req_i.address_tag + , {ariane_pkg::DCACHE_INDEX_WIDTH{1'b0}}}); + + // Request forwarding + assign hpdcache_req_valid_o = cva6_req_i.data_req, + hpdcache_req_o.addr_offset = cva6_req_i.address_index, + hpdcache_req_o.wdata = '0, + hpdcache_req_o.op = hpdcache_pkg::HPDCACHE_REQ_LOAD, + hpdcache_req_o.be = cva6_req_i.data_be, + hpdcache_req_o.size = cva6_req_i.data_size, + hpdcache_req_o.sid = hpdcache_req_sid_i, + hpdcache_req_o.tid = cva6_req_i.data_id, + hpdcache_req_o.need_rsp = 1'b1, + hpdcache_req_o.phys_indexed = 1'b0, + hpdcache_req_o.addr_tag = '0, // unused on virtually indexed request + hpdcache_req_o.pma = '0; // unused on virtually indexed request + + assign hpdcache_req_abort_o = cva6_req_i.kill_req, + hpdcache_req_tag_o = cva6_req_i.address_tag, + hpdcache_req_pma_o.uncacheable = hpdcache_req_is_uncacheable, + hpdcache_req_pma_o.io = 1'b0; + + // Response forwarding + assign cva6_req_o.data_rvalid = hpdcache_rsp_valid_i, + cva6_req_o.data_rdata = hpdcache_rsp_i.rdata, + cva6_req_o.data_rid = hpdcache_rsp_i.tid, + cva6_req_o.data_gnt = hpdcache_req_ready_i; + end + // }}} + + // STORE/AMO request + // {{{ + else begin : store_amo_gen + hpdcache_req_addr_t amo_addr; + hpdcache_req_offset_t amo_addr_offset; + hpdcache_tag_t amo_tag; + logic amo_is_word, amo_is_word_hi; + hpdcache_req_data_t amo_data; + hpdcache_req_be_t amo_data_be; + hpdcache_req_op_t amo_op; + logic [31:0] amo_resp_word; + + // AMO logic + // {{{ + always_comb + begin : amo_op_comb + amo_addr = cva6_amo_req_i.operand_a; + amo_addr_offset = amo_addr[0 +: HPDCACHE_REQ_OFFSET_WIDTH]; + amo_tag = amo_addr[HPDCACHE_REQ_OFFSET_WIDTH +: HPDCACHE_TAG_WIDTH]; + amo_is_word = (cva6_amo_req_i.size == 2'b10); + amo_is_word_hi = cva6_amo_req_i.operand_a[2]; + + amo_data = amo_is_word ? {2{cva6_amo_req_i.operand_b[0 +: 32]}} + : cva6_amo_req_i.operand_b; + + amo_data_be = amo_is_word_hi ? 8'hf0 : + amo_is_word ? 8'h0f : 8'hff; + + unique case(cva6_amo_req_i.amo_op) + ariane_pkg::AMO_LR: amo_op = HPDCACHE_REQ_AMO_LR; + ariane_pkg::AMO_SC: amo_op = HPDCACHE_REQ_AMO_SC; + ariane_pkg::AMO_SWAP: amo_op = HPDCACHE_REQ_AMO_SWAP; + ariane_pkg::AMO_ADD: amo_op = HPDCACHE_REQ_AMO_ADD; + ariane_pkg::AMO_AND: amo_op = HPDCACHE_REQ_AMO_AND; + ariane_pkg::AMO_OR: amo_op = HPDCACHE_REQ_AMO_OR; + ariane_pkg::AMO_XOR: amo_op = HPDCACHE_REQ_AMO_XOR; + ariane_pkg::AMO_MAX: amo_op = HPDCACHE_REQ_AMO_MAX; + ariane_pkg::AMO_MAXU: amo_op = HPDCACHE_REQ_AMO_MAXU; + ariane_pkg::AMO_MIN: amo_op = HPDCACHE_REQ_AMO_MIN; + ariane_pkg::AMO_MINU: amo_op = HPDCACHE_REQ_AMO_MINU; + default: amo_op = HPDCACHE_REQ_LOAD; + endcase + end + + assign amo_resp_word = amo_is_word_hi ? hpdcache_rsp_i.rdata[0][32 +: 32] + : hpdcache_rsp_i.rdata[0][0 +: 32]; + // }}} + + // Request forwarding + // {{{ + assign hpdcache_req_is_uncacheable = + !config_pkg::is_inside_cacheable_regions(CVA6Cfg, + {{64 - ariane_pkg::DCACHE_TAG_WIDTH{1'b0}} + , hpdcache_req_o.addr_tag, {ariane_pkg::DCACHE_INDEX_WIDTH{1'b0}}}); + + assign forward_store = cva6_req_i.data_req, + forward_amo = cva6_amo_req_i.req; + + assign hpdcache_req_valid_o = forward_store | forward_amo, + hpdcache_req_o.addr_offset = forward_amo ? amo_addr_offset + : cva6_req_i.address_index, + hpdcache_req_o.wdata = forward_amo ? amo_data + : cva6_req_i.data_wdata, + hpdcache_req_o.op = forward_amo ? amo_op + : hpdcache_pkg::HPDCACHE_REQ_STORE, + hpdcache_req_o.be = forward_amo ? amo_data_be + : cva6_req_i.data_be, + hpdcache_req_o.size = forward_amo ? cva6_amo_req_i.size + : cva6_req_i.data_size, + hpdcache_req_o.sid = hpdcache_req_sid_i, + hpdcache_req_o.tid = forward_amo ? '1 : '0, + hpdcache_req_o.need_rsp = forward_amo, + hpdcache_req_o.phys_indexed = 1'b1, + hpdcache_req_o.addr_tag = forward_amo ? amo_tag : cva6_req_i.address_tag, + hpdcache_req_o.pma.uncacheable = hpdcache_req_is_uncacheable, + hpdcache_req_o.pma.io = 1'b0, + hpdcache_req_abort_o = 1'b0, // unused on physically indexed requests + hpdcache_req_tag_o = '0, // unused on physically indexed requests + hpdcache_req_pma_o = '0; // unused on physically indexed requests + // }}} + + // Response forwarding + // {{{ + assign cva6_req_o.data_rvalid = hpdcache_rsp_valid_i && (hpdcache_rsp_i.tid != '1), + cva6_req_o.data_rdata = hpdcache_rsp_i.rdata, + cva6_req_o.data_rid = hpdcache_rsp_i.tid, + cva6_req_o.data_gnt = hpdcache_req_ready_i; + + assign cva6_amo_resp_o.ack = hpdcache_rsp_valid_i && (hpdcache_rsp_i.tid == '1), + cva6_amo_resp_o.result = amo_is_word ? {{32{amo_resp_word[31]}}, amo_resp_word} + : hpdcache_rsp_i.rdata[0][63:0]; + // }}} + end + // }}} + endgenerate + // }}} + + // Assertions + // {{{ + // pragma translate_off + forward_one_request_assert: assert property (@(posedge clk_i) + ($onehot0({forward_store, forward_amo}))) else + $error("Only one request shall be forwarded"); + // pragma translate_on + // }}} +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_params_pkg.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_params_pkg.sv new file mode 100644 index 00000000000..da7baa0bd19 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_params_pkg.sv @@ -0,0 +1,182 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2023 + * Description : Package with parameters for the HPDcache in a CVA6 platform + * History : + */ +package hpdcache_params_pkg; + // Imports from the CVA6 configuration package + // {{{ + import cva6_config_pkg::CVA6ConfigXlen; + import cva6_config_pkg::CVA6ConfigDcacheByteSize; + import cva6_config_pkg::CVA6ConfigDcacheSetAssoc; + import cva6_config_pkg::CVA6ConfigDcacheLineWidth; + import cva6_config_pkg::CVA6ConfigDcacheIdWidth; + import cva6_config_pkg::CVA6ConfigWtDcacheWbufDepth; + // }}} + + // Definition of constants used only in this file + // {{{ + localparam int unsigned __BYTES_PER_WAY = + CVA6ConfigDcacheByteSize/CVA6ConfigDcacheSetAssoc; + + localparam int unsigned __BYTES_PER_CACHELINE = + CVA6ConfigDcacheLineWidth/8; + // }}} + + // Definition of global constants for the HPDcache data and directory + // {{{ + // HPDcache physical address width (in bits) + localparam int unsigned PARAM_PA_WIDTH = riscv::PLEN; + + // HPDcache number of sets + localparam int unsigned PARAM_SETS = __BYTES_PER_WAY/__BYTES_PER_CACHELINE; + + // HPDcache number of ways + localparam int unsigned PARAM_WAYS = CVA6ConfigDcacheSetAssoc; + + // HPDcache word width (bits) + localparam int unsigned PARAM_WORD_WIDTH = CVA6ConfigXlen; + + // HPDcache cache-line width (bits) + localparam int unsigned PARAM_CL_WORDS = CVA6ConfigDcacheLineWidth/PARAM_WORD_WIDTH; + + // HPDcache number of words in the request data channels (request and response) + `ifndef CONF_HPDCACHE_REQ_WORDS + `define CONF_HPDCACHE_REQ_WORDS 1 + `endif + localparam int unsigned PARAM_REQ_WORDS = `CONF_HPDCACHE_REQ_WORDS; + + // HPDcache request transaction ID width (bits) + localparam int unsigned PARAM_REQ_TRANS_ID_WIDTH = CVA6ConfigDcacheIdWidth; + + // HPDcache request source ID width (bits) + `ifndef CONF_HPDCACHE_REQ_SRC_ID_WIDTH + `define CONF_HPDCACHE_REQ_SRC_ID_WIDTH 3 + `endif + localparam int unsigned PARAM_REQ_SRC_ID_WIDTH = `CONF_HPDCACHE_REQ_SRC_ID_WIDTH; + + // HPDcache physically indexed + `ifndef CONF_HPDCACHE_PHYSICALLY_INDEXED + `define CONF_HPDCACHE_PHYSICALLY_INDEXED 1'b0 + `endif + localparam bit PARAM_PHYSICALLY_INDEXED = `CONF_HPDCACHE_PHYSICALLY_INDEXED; + // }}} + + // Definition of constants and types for HPDcache data memory + // {{{ + `ifndef CONF_HPDCACHE_DATA_WAYS_PER_RAM_WORD + `define CONF_HPDCACHE_DATA_WAYS_PER_RAM_WORD 128/PARAM_WORD_WIDTH + `endif + localparam int unsigned PARAM_DATA_WAYS_PER_RAM_WORD = `CONF_HPDCACHE_DATA_WAYS_PER_RAM_WORD; + + `ifndef CONF_HPDCACHE_DATA_SETS_PER_RAM + `define CONF_HPDCACHE_DATA_SETS_PER_RAM PARAM_SETS + `endif + localparam int unsigned PARAM_DATA_SETS_PER_RAM = `CONF_HPDCACHE_DATA_SETS_PER_RAM; + + // HPDcache DATA RAM implements write byte enable + `ifndef CONF_HPDCACHE_DATA_RAM_WBYTEENABLE + `define CONF_HPDCACHE_DATA_RAM_WBYTEENABLE 1'b0 + `endif + localparam bit PARAM_DATA_RAM_WBYTEENABLE = `CONF_HPDCACHE_DATA_RAM_WBYTEENABLE; + + // Define the number of memory contiguous words that can be accessed + // simultaneously from the cache. + // - This limits the maximum width for the data channel from requesters + // - This impacts the refill latency + `ifndef CONF_HPDCACHE_ACCESS_WORDS + `define CONF_HPDCACHE_ACCESS_WORDS PARAM_CL_WORDS/2 + `endif + localparam int unsigned PARAM_ACCESS_WORDS = `CONF_HPDCACHE_ACCESS_WORDS; + // }}} + + // Definition of constants and types for the Miss Status Holding Register (MSHR) + // {{{ + `ifndef CONF_HPDCACHE_MSHR_SETS + `define CONF_HPDCACHE_MSHR_SETS 2 + `endif + localparam int unsigned PARAM_MSHR_SETS = `CONF_HPDCACHE_MSHR_SETS; + + // HPDcache MSHR number of ways + `ifndef CONF_HPDCACHE_MSHR_WAYS + `define CONF_HPDCACHE_MSHR_WAYS 4 + `endif + localparam int unsigned PARAM_MSHR_WAYS = `CONF_HPDCACHE_MSHR_WAYS; + + // HPDcache MSHR number of ways in the same SRAM word + `ifndef CONF_HPDCACHE_MSHR_WAYS_PER_RAM_WORD + `define CONF_HPDCACHE_MSHR_WAYS_PER_RAM_WORD 2 + `endif + localparam int unsigned PARAM_MSHR_WAYS_PER_RAM_WORD = `CONF_HPDCACHE_MSHR_WAYS_PER_RAM_WORD; + + // HPDcache MSHR number of sets in the same SRAM + `ifndef CONF_HPDCACHE_MSHR_SETS_PER_RAM + `define CONF_HPDCACHE_MSHR_SETS_PER_RAM PARAM_MSHR_SETS + `endif + localparam int unsigned PARAM_MSHR_SETS_PER_RAM = `CONF_HPDCACHE_MSHR_SETS_PER_RAM; + + // HPDcache MSHR implements write byte enable + `ifndef CONF_HPDCACHE_MSHR_RAM_WBYTEENABLE + `define CONF_HPDCACHE_MSHR_RAM_WBYTEENABLE 1'b0 + `endif + localparam bit PARAM_MSHR_RAM_WBYTEENABLE = `CONF_HPDCACHE_MSHR_RAM_WBYTEENABLE; + + `ifndef CONF_HPDCACHE_MSHR_USE_REGBANK + `define CONF_HPDCACHE_MSHR_USE_REGBANK 0 + `endif + localparam bit PARAM_MSHR_USE_REGBANK = `CONF_HPDCACHE_MSHR_USE_REGBANK; + // }}} + + // Definition of constants and types for the Write Buffer (WBUF) + // {{{ + `ifndef CONF_HPDCACHE_WBUF_DATA_ENTRIES + `define __WBUF_DATA_ENTRIES_DESIRED (CVA6ConfigWtDcacheWbufDepth/2) + `define __WBUF_DATA_ENTRIES_MAX (CVA6ConfigWtDcacheWbufDepth) + `define CONF_HPDCACHE_WBUF_DATA_ENTRIES \ + ((`__WBUF_DATA_ENTRIES_DESIRED) < 1 ? 1 : \ + ((`__WBUF_DATA_ENTRIES_DESIRED) < (`__WBUF_DATA_ENTRIES_MAX) ? \ + (`__WBUF_DATA_ENTRIES_DESIRED) : (`__WBUF_DATA_ENTRIES_MAX))) + `endif + localparam int unsigned PARAM_WBUF_DIR_ENTRIES = CVA6ConfigWtDcacheWbufDepth; + localparam int unsigned PARAM_WBUF_DATA_ENTRIES = `CONF_HPDCACHE_WBUF_DATA_ENTRIES; + + `ifndef CONF_HPDCACHE_WBUF_WORDS + `define CONF_HPDCACHE_WBUF_WORDS PARAM_REQ_WORDS + `endif + localparam int unsigned PARAM_WBUF_WORDS = `CONF_HPDCACHE_WBUF_WORDS; + + `ifndef CONF_HPDCACHE_WBUF_TIMECNT_WIDTH + `define CONF_HPDCACHE_WBUF_TIMECNT_WIDTH 4 + `endif + localparam int unsigned PARAM_WBUF_TIMECNT_WIDTH = `CONF_HPDCACHE_WBUF_TIMECNT_WIDTH; + // }}} + + // Definition of constants and types for the Replay Table (RTAB) + // {{{ + `ifndef CONF_HPDCACHE_RTAB_ENTRIES + `define CONF_HPDCACHE_RTAB_ENTRIES 4 + `endif + localparam int PARAM_RTAB_ENTRIES = `CONF_HPDCACHE_RTAB_ENTRIES; + // }}} + +endpackage diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_subsystem.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_subsystem.sv new file mode 100644 index 00000000000..68993958f7d --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_subsystem.sv @@ -0,0 +1,601 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : June, 2022 + * Description : CVA6 cache subsystem integrating standard CVA6's + * instruction cache and the Core-V High-Performance L1 +* data cache (CV-HPDcache). + * History : + */ +module cva6_hpdcache_subsystem +// Parameters +// {{{ +#( + parameter config_pkg::cva6_cfg_t CVA6Cfg = config_pkg::cva6_cfg_empty, + parameter int NumPorts = 4, + parameter int NrHwPrefetchers = 4, + parameter type noc_req_t = logic, + parameter type noc_resp_t = logic, + parameter type cmo_req_t = logic, + parameter type cmo_rsp_t = logic +) +// }}} + +// Ports +// {{{ +( + input logic clk_i, + input logic rst_ni, + + // I$ + // {{{ + input logic icache_en_i, // enable icache (or bypass e.g: in debug mode) + input logic icache_flush_i, // flush the icache, flush and kill have to be asserted together + output logic icache_miss_o, // to performance counter + // address translation requests + input ariane_pkg::icache_areq_t icache_areq_i, // to/from frontend + output ariane_pkg::icache_arsp_t icache_areq_o, + // data requests + input ariane_pkg::icache_dreq_t icache_dreq_i, // to/from frontend + output ariane_pkg::icache_drsp_t icache_dreq_o, + // }}} + + // D$ + // {{{ + // Cache management + input logic dcache_enable_i, // from CSR + input logic dcache_flush_i, // high until acknowledged + output logic dcache_flush_ack_o, // send a single cycle acknowledge signal when the cache is flushed + output logic dcache_miss_o, // we missed on a ld/st + + // AMO interface + input ariane_pkg::amo_req_t dcache_amo_req_i, // from LSU + output ariane_pkg::amo_resp_t dcache_amo_resp_o, // to LSU + // CMO interface + input cmo_req_t dcache_cmo_req_i, // from CMO FU + output cmo_rsp_t dcache_cmo_resp_o, // to CMO FU + // Request ports + input ariane_pkg::dcache_req_i_t [NumPorts-1:0] dcache_req_ports_i, // from LSU + output ariane_pkg::dcache_req_o_t [NumPorts-1:0] dcache_req_ports_o, // to LSU + // Write Buffer status + output logic wbuffer_empty_o, + output logic wbuffer_not_ni_o, + + // Hardware memory prefetcher configuration + input logic [NrHwPrefetchers-1:0] hwpf_base_set_i, + input logic [NrHwPrefetchers-1:0][63:0] hwpf_base_i, + output logic [NrHwPrefetchers-1:0][63:0] hwpf_base_o, + input logic [NrHwPrefetchers-1:0] hwpf_param_set_i, + input logic [NrHwPrefetchers-1:0][63:0] hwpf_param_i, + output logic [NrHwPrefetchers-1:0][63:0] hwpf_param_o, + input logic [NrHwPrefetchers-1:0] hwpf_throttle_set_i, + input logic [NrHwPrefetchers-1:0][63:0] hwpf_throttle_i, + output logic [NrHwPrefetchers-1:0][63:0] hwpf_throttle_o, + output logic [63:0] hwpf_status_o, + // }}} + + // AXI port to upstream memory/peripherals + // {{{ + output noc_req_t noc_req_o, + input noc_resp_t noc_resp_i + // }}} +); +// }}} + + `include "axi/typedef.svh" + + // I$ instantiation + // {{{ + logic icache_miss_valid, icache_miss_ready; + wt_cache_pkg::icache_req_t icache_miss; + + logic icache_miss_resp_valid; + wt_cache_pkg::icache_rtrn_t icache_miss_resp; + + localparam int ICACHE_RDTXID = 1 << (ariane_pkg::MEM_TID_WIDTH - 1); + + cva6_icache #( + .CVA6Cfg (CVA6Cfg), + .RdTxId (ICACHE_RDTXID) + ) i_cva6_icache ( + .clk_i (clk_i), + .rst_ni (rst_ni), + .flush_i (icache_flush_i), + .en_i (icache_en_i), + .miss_o (icache_miss_o), + .areq_i (icache_areq_i), + .areq_o (icache_areq_o), + .dreq_i (icache_dreq_i), + .dreq_o (icache_dreq_o), + .mem_rtrn_vld_i (icache_miss_resp_valid), + .mem_rtrn_i (icache_miss_resp), + .mem_data_req_o (icache_miss_valid), + .mem_data_ack_i (icache_miss_ready), + .mem_data_o (icache_miss) + ); + // }}} + + // D$ instantiation + // {{{ + `include "hpdcache_typedef.svh" + + // 0: Page-Table Walk (PTW) + // 1: Load unit + // 2: Accelerator load + // 3: Store/AMO + // . + // . + // . + // NumPorts: CMO + // NumPorts + 1: Hardware Memory Prefetcher (hwpf) + localparam int HPDCACHE_NREQUESTERS = NumPorts + 2; + + typedef logic [CVA6Cfg.AxiAddrWidth-1:0] hpdcache_mem_addr_t; + typedef logic [ariane_pkg::MEM_TID_WIDTH-1:0] hpdcache_mem_id_t; + typedef logic [CVA6Cfg.AxiDataWidth-1:0] hpdcache_mem_data_t; + typedef logic [CVA6Cfg.AxiDataWidth/8-1:0] hpdcache_mem_be_t; + `HPDCACHE_TYPEDEF_MEM_REQ_T(hpdcache_mem_req_t, hpdcache_mem_addr_t, hpdcache_mem_id_t); + `HPDCACHE_TYPEDEF_MEM_RESP_R_T(hpdcache_mem_resp_r_t, hpdcache_mem_id_t, hpdcache_mem_data_t); + `HPDCACHE_TYPEDEF_MEM_REQ_W_T(hpdcache_mem_req_w_t, hpdcache_mem_data_t, hpdcache_mem_be_t); + `HPDCACHE_TYPEDEF_MEM_RESP_W_T(hpdcache_mem_resp_w_t, hpdcache_mem_id_t); + + typedef logic [63:0] hwpf_stride_param_t; + + logic dcache_req_valid [HPDCACHE_NREQUESTERS-1:0]; + logic dcache_req_ready [HPDCACHE_NREQUESTERS-1:0]; + hpdcache_pkg::hpdcache_req_t dcache_req [HPDCACHE_NREQUESTERS-1:0]; + logic dcache_req_abort [HPDCACHE_NREQUESTERS-1:0]; + hpdcache_pkg::hpdcache_tag_t dcache_req_tag [HPDCACHE_NREQUESTERS-1:0]; + hpdcache_pkg::hpdcache_pma_t dcache_req_pma [HPDCACHE_NREQUESTERS-1:0]; + logic dcache_rsp_valid [HPDCACHE_NREQUESTERS-1:0]; + hpdcache_pkg::hpdcache_rsp_t dcache_rsp [HPDCACHE_NREQUESTERS-1:0]; + logic dcache_read_miss, dcache_write_miss; + + logic [2:0] snoop_valid; + logic [2:0] snoop_abort; + hpdcache_pkg::hpdcache_req_offset_t [2:0] snoop_addr_offset; + hpdcache_pkg::hpdcache_tag_t [2:0] snoop_addr_tag; + logic [2:0] snoop_phys_indexed; + + logic dcache_cmo_req_is_prefetch; + + logic dcache_miss_ready; + logic dcache_miss_valid; + hpdcache_mem_req_t dcache_miss; + + logic dcache_miss_resp_ready; + logic dcache_miss_resp_valid; + hpdcache_mem_resp_r_t dcache_miss_resp; + + logic dcache_wbuf_ready; + logic dcache_wbuf_valid; + hpdcache_mem_req_t dcache_wbuf; + + logic dcache_wbuf_data_ready; + logic dcache_wbuf_data_valid; + hpdcache_mem_req_w_t dcache_wbuf_data; + + logic dcache_wbuf_resp_ready; + logic dcache_wbuf_resp_valid; + hpdcache_mem_resp_w_t dcache_wbuf_resp; + + logic dcache_uc_read_ready; + logic dcache_uc_read_valid; + hpdcache_mem_req_t dcache_uc_read; + + logic dcache_uc_read_resp_ready; + logic dcache_uc_read_resp_valid; + hpdcache_mem_resp_r_t dcache_uc_read_resp; + + logic dcache_uc_write_ready; + logic dcache_uc_write_valid; + hpdcache_mem_req_t dcache_uc_write; + + logic dcache_uc_write_data_ready; + logic dcache_uc_write_data_valid; + hpdcache_mem_req_w_t dcache_uc_write_data; + + logic dcache_uc_write_resp_ready; + logic dcache_uc_write_resp_valid; + hpdcache_mem_resp_w_t dcache_uc_write_resp; + + hwpf_stride_pkg::hwpf_stride_throttle_t [NrHwPrefetchers-1:0] hwpf_throttle_in; + hwpf_stride_pkg::hwpf_stride_throttle_t [NrHwPrefetchers-1:0] hwpf_throttle_out; + + generate + ariane_pkg::dcache_req_i_t dcache_req_ports[HPDCACHE_NREQUESTERS-1:0]; + + for (genvar r = 0; r < (NumPorts-1); r++) begin : cva6_hpdcache_load_if_adapter_gen + assign dcache_req_ports[r] = dcache_req_ports_i[r]; + + cva6_hpdcache_if_adapter #( + .CVA6Cfg (CVA6Cfg), + .is_load_port (1'b1) + ) i_cva6_hpdcache_load_if_adapter ( + .clk_i, + .rst_ni, + + .hpdcache_req_sid_i (hpdcache_pkg::hpdcache_req_sid_t'(r)), + + .cva6_req_i (dcache_req_ports[r]), + .cva6_req_o (dcache_req_ports_o[r]), + .cva6_amo_req_i ('0), + .cva6_amo_resp_o (/* unused */), + + .hpdcache_req_valid_o (dcache_req_valid[r]), + .hpdcache_req_ready_i (dcache_req_ready[r]), + .hpdcache_req_o (dcache_req[r]), + .hpdcache_req_abort_o (dcache_req_abort[r]), + .hpdcache_req_tag_o (dcache_req_tag[r]), + .hpdcache_req_pma_o (dcache_req_pma[r]), + + .hpdcache_rsp_valid_i (dcache_rsp_valid[r]), + .hpdcache_rsp_i (dcache_rsp[r]) + ); + end + + cva6_hpdcache_if_adapter #( + .CVA6Cfg (CVA6Cfg), + .is_load_port (1'b0) + ) i_cva6_hpdcache_store_if_adapter ( + .clk_i, + .rst_ni, + + .hpdcache_req_sid_i (hpdcache_pkg::hpdcache_req_sid_t'(NumPorts-1)), + + .cva6_req_i (dcache_req_ports_i[NumPorts-1]), + .cva6_req_o (dcache_req_ports_o[NumPorts-1]), + .cva6_amo_req_i (dcache_amo_req_i), + .cva6_amo_resp_o (dcache_amo_resp_o), + + .hpdcache_req_valid_o (dcache_req_valid[NumPorts-1]), + .hpdcache_req_ready_i (dcache_req_ready[NumPorts-1]), + .hpdcache_req_o (dcache_req[NumPorts-1]), + .hpdcache_req_abort_o (dcache_req_abort[NumPorts-1]), + .hpdcache_req_tag_o (dcache_req_tag[NumPorts-1]), + .hpdcache_req_pma_o (dcache_req_pma[NumPorts-1]), + + .hpdcache_rsp_valid_i (dcache_rsp_valid[NumPorts-1]), + .hpdcache_rsp_i (dcache_rsp[NumPorts-1]) + ); + +`ifdef HPDCACHE_ENABLE_CMO + cva6_hpdcache_cmo_if_adapter #( + .cmo_req_t (cmo_req_t), + .cmo_rsp_t (cmo_rsp_t) + ) i_cva6_hpdcache_cmo_if_adapter ( + .clk_i, + .rst_ni, + + .dcache_req_sid_i (hpdcache_pkg::hpdcache_req_sid_t'(NumPorts)), + + .cva6_cmo_req_i (dcache_cmo_req_i), + .cva6_cmo_resp_o (dcache_cmo_resp_o), + + .dcache_req_valid_o (dcache_req_valid[NumPorts]), + .dcache_req_ready_i (dcache_req_ready[NumPorts]), + .dcache_req_o (dcache_req[NumPorts]), + .dcache_req_abort_o (dcache_req_abort[NumPorts]), + .dcache_req_tag_o (dcache_req_tag[NumPorts]), + .dcache_req_pma_o (dcache_req_pma[NumPorts]), + + .dcache_rsp_valid_i (dcache_rsp_valid[NumPorts]), + .dcache_rsp_i (dcache_rsp[NumPorts]) + ); +`else + assign dcache_req_valid[NumPorts] = 1'b0, + dcache_req [NumPorts] = '0, + dcache_req_abort[NumPorts] = 1'b0, + dcache_req_tag [NumPorts] = '0, + dcache_req_pma [NumPorts] = '0; +`endif + endgenerate + + // Snoop load port + assign snoop_valid[0] = dcache_req_valid[1] & dcache_req_ready[1], + snoop_abort[0] = dcache_req_abort[1], + snoop_addr_offset[0] = dcache_req[1].addr_offset, + snoop_addr_tag[0] = dcache_req_tag[1], + snoop_phys_indexed[0] = dcache_req[1].phys_indexed; + + // Snoop Store/AMO port + assign snoop_valid[1] = dcache_req_valid[NumPorts-1] & dcache_req_ready[NumPorts-1], + snoop_abort[1] = dcache_req_abort[NumPorts-1], + snoop_addr_offset[1] = dcache_req[NumPorts-1].addr_offset, + snoop_addr_tag[1] = dcache_req_tag[NumPorts-1], + snoop_phys_indexed[1] = dcache_req[NumPorts-1].phys_indexed; + +`ifdef HPDCACHE_ENABLE_CMO + // Snoop CMO port (in case of read prefetch accesses) + assign dcache_cmo_req_is_prefetch = + hpdcache_pkg::is_cmo_prefetch(dcache_req[NumPorts].op, dcache_req[NumPorts].size); + assign snoop_valid[2] = dcache_req_valid[NumPorts] + & dcache_req_ready[NumPorts] + & dcache_cmo_req_is_prefetch, + snoop_abort[2] = dcache_req_abort[NumPorts], + snoop_addr_offset[2] = dcache_req[NumPorts].addr_offset, + snoop_addr_tag[2] = dcache_req_tag[NumPorts], + snoop_phys_indexed[2] = dcache_req[NumPorts].phys_indexed; +`else + assign snoop_valid[2] = 1'b0, + snoop_abort[2] = 1'b0, + snoop_addr_offset[2] = '0, + snoop_addr_tag[2] = '0, + snoop_phys_indexed[2] = 1'b0; +`endif + + generate + for (genvar h = 0; h < NrHwPrefetchers; h++) begin : hwpf_throttle_gen + assign hwpf_throttle_in[h] = hwpf_stride_pkg::hwpf_stride_throttle_t'(hwpf_throttle_i[h]), + hwpf_throttle_o[h] = hwpf_stride_pkg::hwpf_stride_param_t'(hwpf_throttle_out[h]); + end + endgenerate + + hwpf_stride_wrapper #( + .NUM_HW_PREFETCH (NrHwPrefetchers), + .NUM_SNOOP_PORTS (3) + ) i_hwpf_stride_wrapper ( + .clk_i, + .rst_ni, + + .hwpf_stride_base_set_i (hwpf_base_set_i), + .hwpf_stride_base_i (hwpf_base_i), + .hwpf_stride_base_o (hwpf_base_o), + .hwpf_stride_param_set_i (hwpf_param_set_i), + .hwpf_stride_param_i (hwpf_param_i), + .hwpf_stride_param_o (hwpf_param_o), + .hwpf_stride_throttle_set_i (hwpf_throttle_set_i), + .hwpf_stride_throttle_i (hwpf_throttle_in), + .hwpf_stride_throttle_o (hwpf_throttle_out), + .hwpf_stride_status_o (hwpf_status_o), + + .snoop_valid_i (snoop_valid), + .snoop_abort_i (snoop_abort), + .snoop_addr_offset_i (snoop_addr_offset), + .snoop_addr_tag_i (snoop_addr_tag), + .snoop_phys_indexed_i (snoop_phys_indexed), + + .hpdcache_req_sid_i (hpdcache_pkg::hpdcache_req_sid_t'(NumPorts+1)), + + .hpdcache_req_valid_o (dcache_req_valid[NumPorts+1]), + .hpdcache_req_ready_i (dcache_req_ready[NumPorts+1]), + .hpdcache_req_o (dcache_req[NumPorts+1]), + .hpdcache_req_abort_o (dcache_req_abort[NumPorts+1]), + .hpdcache_req_tag_o (dcache_req_tag[NumPorts+1]), + .hpdcache_req_pma_o (dcache_req_pma[NumPorts+1]), + .hpdcache_rsp_valid_i (dcache_rsp_valid[NumPorts+1]), + .hpdcache_rsp_i (dcache_rsp[NumPorts+1]) + ); + + hpdcache #( + .NREQUESTERS (HPDCACHE_NREQUESTERS), + .HPDcacheMemIdWidth (ariane_pkg::MEM_TID_WIDTH), + .HPDcacheMemDataWidth (CVA6Cfg.AxiDataWidth), + .hpdcache_mem_req_t (hpdcache_mem_req_t), + .hpdcache_mem_req_w_t (hpdcache_mem_req_w_t), + .hpdcache_mem_resp_r_t (hpdcache_mem_resp_r_t), + .hpdcache_mem_resp_w_t (hpdcache_mem_resp_w_t) + ) i_hpdcache( + .clk_i, + .rst_ni, + + .wbuf_flush_i (dcache_flush_i), + + .core_req_valid_i (dcache_req_valid), + .core_req_ready_o (dcache_req_ready), + .core_req_i (dcache_req), + .core_req_abort_i (dcache_req_abort), + .core_req_tag_i (dcache_req_tag), + .core_req_pma_i (dcache_req_pma), + + .core_rsp_valid_o (dcache_rsp_valid), + .core_rsp_o (dcache_rsp), + + .mem_req_miss_read_ready_i (dcache_miss_ready), + .mem_req_miss_read_valid_o (dcache_miss_valid), + .mem_req_miss_read_o (dcache_miss), + + .mem_resp_miss_read_ready_o (dcache_miss_resp_ready), + .mem_resp_miss_read_valid_i (dcache_miss_resp_valid), + .mem_resp_miss_read_i (dcache_miss_resp), + + .mem_req_wbuf_write_ready_i (dcache_wbuf_ready), + .mem_req_wbuf_write_valid_o (dcache_wbuf_valid), + .mem_req_wbuf_write_o (dcache_wbuf), + + .mem_req_wbuf_write_data_ready_i (dcache_wbuf_data_ready), + .mem_req_wbuf_write_data_valid_o (dcache_wbuf_data_valid), + .mem_req_wbuf_write_data_o (dcache_wbuf_data), + + .mem_resp_wbuf_write_ready_o (dcache_wbuf_resp_ready), + .mem_resp_wbuf_write_valid_i (dcache_wbuf_resp_valid), + .mem_resp_wbuf_write_i (dcache_wbuf_resp), + + .mem_req_uc_read_ready_i (dcache_uc_read_ready), + .mem_req_uc_read_valid_o (dcache_uc_read_valid), + .mem_req_uc_read_o (dcache_uc_read), + + .mem_resp_uc_read_ready_o (dcache_uc_read_resp_ready), + .mem_resp_uc_read_valid_i (dcache_uc_read_resp_valid), + .mem_resp_uc_read_i (dcache_uc_read_resp), + + .mem_req_uc_write_ready_i (dcache_uc_write_ready), + .mem_req_uc_write_valid_o (dcache_uc_write_valid), + .mem_req_uc_write_o (dcache_uc_write), + + .mem_req_uc_write_data_ready_i (dcache_uc_write_data_ready), + .mem_req_uc_write_data_valid_o (dcache_uc_write_data_valid), + .mem_req_uc_write_data_o (dcache_uc_write_data), + + .mem_resp_uc_write_ready_o (dcache_uc_write_resp_ready), + .mem_resp_uc_write_valid_i (dcache_uc_write_resp_valid), + .mem_resp_uc_write_i (dcache_uc_write_resp), + + .evt_cache_write_miss_o (dcache_write_miss), + .evt_cache_read_miss_o (dcache_read_miss), + .evt_uncached_req_o (/* unused */), + .evt_cmo_req_o (/* unused */), + .evt_write_req_o (/* unused */), + .evt_read_req_o (/* unused */), + .evt_prefetch_req_o (/* unused */), + .evt_req_on_hold_o (/* unused */), + .evt_rtab_rollback_o (/* unused */), + .evt_stall_refill_o (/* unused */), + .evt_stall_o (/* unused */), + + .wbuf_empty_o (wbuffer_empty_o), + + .cfg_enable_i (dcache_enable_i), + .cfg_wbuf_threshold_i (4'd2), + .cfg_wbuf_reset_timecnt_on_write_i (1'b1), + .cfg_wbuf_sequential_waw_i (1'b0), + .cfg_wbuf_inhibit_write_coalescing_i (1'b0), + .cfg_prefetch_updt_plru_i (1'b1), + .cfg_error_on_cacheable_amo_i (1'b0), + .cfg_rtab_single_entry_i (1'b0) + ); + + assign dcache_miss_o = dcache_read_miss, + wbuffer_not_ni_o = wbuffer_empty_o; + + always_ff @(posedge clk_i or negedge rst_ni) + begin : dcache_flush_ff + if (!rst_ni) dcache_flush_ack_o <= 1'b0; + else dcache_flush_ack_o <= ~dcache_flush_ack_o & dcache_flush_i; + end + + // }}} + + // AXI arbiter instantiation + // {{{ + typedef logic [CVA6Cfg.AxiAddrWidth-1:0] axi_addr_t; + typedef logic [CVA6Cfg.AxiDataWidth-1:0] axi_data_t; + typedef logic [CVA6Cfg.AxiDataWidth/8-1:0] axi_strb_t; + typedef logic [CVA6Cfg.AxiIdWidth-1:0] axi_id_t; + typedef logic [CVA6Cfg.AxiUserWidth-1:0] axi_user_t; + `AXI_TYPEDEF_AW_CHAN_T(axi_aw_chan_t, axi_addr_t, axi_id_t, axi_user_t) + `AXI_TYPEDEF_W_CHAN_T(axi_w_chan_t, axi_data_t, axi_strb_t, axi_user_t) + `AXI_TYPEDEF_B_CHAN_T(axi_b_chan_t, axi_id_t, axi_user_t) + `AXI_TYPEDEF_AR_CHAN_T(axi_ar_chan_t, axi_addr_t, axi_id_t, axi_user_t) + `AXI_TYPEDEF_R_CHAN_T(axi_r_chan_t, axi_data_t, axi_id_t, axi_user_t) + + cva6_hpdcache_subsystem_axi_arbiter #( + .HPDcacheMemIdWidth (ariane_pkg::MEM_TID_WIDTH), + .HPDcacheMemDataWidth (CVA6Cfg.AxiDataWidth), + .hpdcache_mem_req_t (hpdcache_mem_req_t), + .hpdcache_mem_req_w_t (hpdcache_mem_req_w_t), + .hpdcache_mem_resp_r_t (hpdcache_mem_resp_r_t), + .hpdcache_mem_resp_w_t (hpdcache_mem_resp_w_t), + + .AxiAddrWidth (CVA6Cfg.AxiAddrWidth), + .AxiDataWidth (CVA6Cfg.AxiDataWidth), + .AxiIdWidth (CVA6Cfg.AxiIdWidth), + .AxiUserWidth (CVA6Cfg.AxiUserWidth), + .axi_ar_chan_t (axi_ar_chan_t), + .axi_aw_chan_t (axi_aw_chan_t), + .axi_w_chan_t (axi_w_chan_t), + .axi_req_t (noc_req_t), + .axi_rsp_t (noc_resp_t) + ) i_axi_arbiter ( + .clk_i, + .rst_ni, + + .icache_miss_valid_i (icache_miss_valid), + .icache_miss_ready_o (icache_miss_ready), + .icache_miss_i (icache_miss), + .icache_miss_id_i (hpdcache_mem_id_t'(ICACHE_RDTXID)), + + .icache_miss_resp_valid_o (icache_miss_resp_valid), + .icache_miss_resp_o (icache_miss_resp), + + .dcache_miss_ready_o (dcache_miss_ready), + .dcache_miss_valid_i (dcache_miss_valid), + .dcache_miss_i (dcache_miss), + + .dcache_miss_resp_ready_i (dcache_miss_resp_ready), + .dcache_miss_resp_valid_o (dcache_miss_resp_valid), + .dcache_miss_resp_o (dcache_miss_resp), + + .dcache_wbuf_ready_o (dcache_wbuf_ready), + .dcache_wbuf_valid_i (dcache_wbuf_valid), + .dcache_wbuf_i (dcache_wbuf), + + .dcache_wbuf_data_ready_o (dcache_wbuf_data_ready), + .dcache_wbuf_data_valid_i (dcache_wbuf_data_valid), + .dcache_wbuf_data_i (dcache_wbuf_data), + + .dcache_wbuf_resp_ready_i (dcache_wbuf_resp_ready), + .dcache_wbuf_resp_valid_o (dcache_wbuf_resp_valid), + .dcache_wbuf_resp_o (dcache_wbuf_resp), + + .dcache_uc_read_ready_o (dcache_uc_read_ready), + .dcache_uc_read_valid_i (dcache_uc_read_valid), + .dcache_uc_read_i (dcache_uc_read), + .dcache_uc_read_id_i ('1), + + .dcache_uc_read_resp_ready_i (dcache_uc_read_resp_ready), + .dcache_uc_read_resp_valid_o (dcache_uc_read_resp_valid), + .dcache_uc_read_resp_o (dcache_uc_read_resp), + + .dcache_uc_write_ready_o (dcache_uc_write_ready), + .dcache_uc_write_valid_i (dcache_uc_write_valid), + .dcache_uc_write_i (dcache_uc_write), + .dcache_uc_write_id_i ('1), + + .dcache_uc_write_data_ready_o (dcache_uc_write_data_ready), + .dcache_uc_write_data_valid_i (dcache_uc_write_data_valid), + .dcache_uc_write_data_i (dcache_uc_write_data), + + .dcache_uc_write_resp_ready_i (dcache_uc_write_resp_ready), + .dcache_uc_write_resp_valid_o (dcache_uc_write_resp_valid), + .dcache_uc_write_resp_o (dcache_uc_write_resp), + + .axi_req_o (noc_req_o), + .axi_resp_i (noc_resp_i) + ); + // }}} + + // Assertions + // {{{ + // pragma translate_off + initial assert (hpdcache_pkg::HPDCACHE_REQ_SRC_ID_WIDTH >= $clog2(HPDCACHE_NREQUESTERS)) + else $fatal(1, "HPDCACHE_REQ_SRC_ID_WIDTH is not wide enough"); + + a_invalid_instruction_fetch: assert property ( + @(posedge clk_i) disable iff (!rst_ni) icache_dreq_o.valid |-> (|icache_dreq_o.data) !== 1'hX) + else $warning(1,"[l1 dcache] reading invalid instructions: vaddr=%08X, data=%08X", + icache_dreq_o.vaddr, icache_dreq_o.data); + + a_invalid_write_data: assert property ( + @(posedge clk_i) disable iff (!rst_ni) dcache_req_ports_i[2].data_req |-> |dcache_req_ports_i[2].data_be |-> (|dcache_req_ports_i[2].data_wdata) !== 1'hX) + else $warning(1,"[l1 dcache] writing invalid data: paddr=%016X, be=%02X, data=%016X", + {dcache_req_ports_i[2].address_tag, dcache_req_ports_i[2].address_index}, dcache_req_ports_i[2].data_be, dcache_req_ports_i[2].data_wdata); + + for (genvar j=0; j<2; j++) begin : gen_assertion + a_invalid_read_data: assert property ( + @(posedge clk_i) disable iff (!rst_ni) dcache_req_ports_o[j].data_rvalid && ~dcache_req_ports_i[j].kill_req |-> (|dcache_req_ports_o[j].data_rdata) !== 1'hX) + else $warning(1,"[l1 dcache] reading invalid data on port %01d: data=%016X", + j, dcache_req_ports_o[j].data_rdata); + end + // pragma translate_on + // }}} + +endmodule : cva6_hpdcache_subsystem diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_subsystem_axi_arbiter.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_subsystem_axi_arbiter.sv new file mode 100644 index 00000000000..ae3dd04edb3 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/target/cva6/cva6_hpdcache_subsystem_axi_arbiter.sv @@ -0,0 +1,593 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date: June, 2022 + * Description : AXI arbiter for the CVA6 cache subsystem integrating standard + * CVA6's instruction cache and the Core-V High-Performance +* L1 Dcache (CV-HPDcache). + * History : + */ +module cva6_hpdcache_subsystem_axi_arbiter +// Parameters +// {{{ +#( + parameter int HPDcacheMemIdWidth = 8, + parameter int HPDcacheMemDataWidth = 512, + parameter type hpdcache_mem_req_t = logic, + parameter type hpdcache_mem_req_w_t = logic, + parameter type hpdcache_mem_resp_r_t = logic, + parameter type hpdcache_mem_resp_w_t = logic, + + parameter int unsigned AxiAddrWidth = 1, + parameter int unsigned AxiDataWidth = 1, + parameter int unsigned AxiIdWidth = 1, + parameter int unsigned AxiUserWidth = 1, + parameter type axi_ar_chan_t = logic, + parameter type axi_aw_chan_t = logic, + parameter type axi_w_chan_t = logic, + parameter type axi_req_t = logic, + parameter type axi_rsp_t = logic, + + localparam type hpdcache_mem_id_t = logic [HPDcacheMemIdWidth-1:0] +) +// }}} + +// Ports +// {{{ +( + input logic clk_i, + input logic rst_ni, + + // Interfaces from/to I$ + // {{{ + input logic icache_miss_valid_i, + output logic icache_miss_ready_o, + input wt_cache_pkg::icache_req_t icache_miss_i, + input hpdcache_mem_id_t icache_miss_id_i, + + output logic icache_miss_resp_valid_o, + output wt_cache_pkg::icache_rtrn_t icache_miss_resp_o, + // }}} + + // Interfaces from/to D$ + // {{{ + output logic dcache_miss_ready_o, + input logic dcache_miss_valid_i, + input hpdcache_mem_req_t dcache_miss_i, + + input logic dcache_miss_resp_ready_i, + output logic dcache_miss_resp_valid_o, + output hpdcache_mem_resp_r_t dcache_miss_resp_o, + + // Write-buffer write interface + output logic dcache_wbuf_ready_o, + input logic dcache_wbuf_valid_i, + input hpdcache_mem_req_t dcache_wbuf_i, + + output logic dcache_wbuf_data_ready_o, + input logic dcache_wbuf_data_valid_i, + input hpdcache_mem_req_w_t dcache_wbuf_data_i, + + input logic dcache_wbuf_resp_ready_i, + output logic dcache_wbuf_resp_valid_o, + output hpdcache_mem_resp_w_t dcache_wbuf_resp_o, + + // Uncached read interface + output logic dcache_uc_read_ready_o, + input logic dcache_uc_read_valid_i, + input hpdcache_mem_req_t dcache_uc_read_i, + input hpdcache_mem_id_t dcache_uc_read_id_i, + + input logic dcache_uc_read_resp_ready_i, + output logic dcache_uc_read_resp_valid_o, + output hpdcache_mem_resp_r_t dcache_uc_read_resp_o, + + // Uncached write interface + output logic dcache_uc_write_ready_o, + input logic dcache_uc_write_valid_i, + input hpdcache_mem_req_t dcache_uc_write_i, + input hpdcache_mem_id_t dcache_uc_write_id_i, + + output logic dcache_uc_write_data_ready_o, + input logic dcache_uc_write_data_valid_i, + input hpdcache_mem_req_w_t dcache_uc_write_data_i, + + input logic dcache_uc_write_resp_ready_i, + output logic dcache_uc_write_resp_valid_o, + output hpdcache_mem_resp_w_t dcache_uc_write_resp_o, + // }}} + + // AXI port to upstream memory/peripherals + // {{{ + output axi_req_t axi_req_o, + input axi_rsp_t axi_resp_i + // }}} +); +// }}} + + // Internal type definitions + // {{{ + typedef struct packed { + logic [AxiIdWidth-1:0] id; + logic [AxiDataWidth-1:0] data; + axi_pkg::resp_t resp; + logic last; + logic [AxiUserWidth-1:0] user; + } axi_r_chan_t; + + typedef struct packed { + logic [AxiIdWidth-1:0] id; + axi_pkg::resp_t resp; + logic [AxiUserWidth-1:0] user; + } axi_b_chan_t; + + localparam int MEM_RESP_RT_DEPTH = (1 << HPDcacheMemIdWidth); + typedef hpdcache_mem_id_t [MEM_RESP_RT_DEPTH-1:0] mem_resp_rt_t; + typedef logic [ariane_pkg::ICACHE_LINE_WIDTH-1:0] icache_resp_data_t; + // }}} + + // Adapt the I$ interface to the HPDcache memory interface + // {{{ + localparam int ICACHE_CL_WORDS = ariane_pkg::ICACHE_LINE_WIDTH/64; + localparam int ICACHE_CL_WORD_INDEX = $clog2(ICACHE_CL_WORDS); + localparam int ICACHE_CL_SIZE = $clog2(ariane_pkg::ICACHE_LINE_WIDTH/8); + localparam int ICACHE_WORD_SIZE = 3; + localparam int ICACHE_MEM_REQ_CL_LEN = + (ariane_pkg::ICACHE_LINE_WIDTH + HPDcacheMemDataWidth - 1)/HPDcacheMemDataWidth; + localparam int ICACHE_MEM_REQ_CL_SIZE = + (HPDcacheMemDataWidth <= ariane_pkg::ICACHE_LINE_WIDTH) ? + $clog2(HPDcacheMemDataWidth/8) : ICACHE_CL_SIZE; + + // I$ request + hpdcache_mem_req_t icache_miss_req_wdata; + logic icache_miss_req_w, icache_miss_req_wok; + + hpdcache_mem_req_t icache_miss_req_rdata; + logic icache_miss_req_r, icache_miss_req_rok; + + logic icache_miss_pending_q; + + // This FIFO has two functionnalities: + // - Stabilize the ready-valid protocol. The ICACHE can abort a valid + // transaction without receiving the corresponding ready signal. This + // behavior is not supported by AXI. + // - Cut a possible long timing path. + hpdcache_fifo_reg #( + .FIFO_DEPTH (1), + .fifo_data_t (hpdcache_mem_req_t) + ) i_icache_miss_req_fifo( + .clk_i, + .rst_ni, + + .w_i (icache_miss_req_w), + .wok_o (icache_miss_req_wok), + .wdata_i (icache_miss_req_wdata), + + .r_i (icache_miss_req_r), + .rok_o (icache_miss_req_rok), + .rdata_o (icache_miss_req_rdata) + ); + + assign icache_miss_req_w = icache_miss_valid_i, + icache_miss_ready_o = icache_miss_req_wok; + + assign icache_miss_req_wdata.mem_req_addr = icache_miss_i.paddr, + icache_miss_req_wdata.mem_req_len = icache_miss_i.nc ? 0 : ICACHE_MEM_REQ_CL_LEN - 1, + icache_miss_req_wdata.mem_req_size = icache_miss_i.nc ? ICACHE_WORD_SIZE : ICACHE_MEM_REQ_CL_SIZE, + icache_miss_req_wdata.mem_req_id = icache_miss_i.tid, + icache_miss_req_wdata.mem_req_command = hpdcache_pkg::HPDCACHE_MEM_READ, + icache_miss_req_wdata.mem_req_atomic = hpdcache_pkg::hpdcache_mem_atomic_e'(0), + icache_miss_req_wdata.mem_req_cacheable = ~icache_miss_i.nc; + + + // I$ response + logic icache_miss_resp_w, icache_miss_resp_wok; + hpdcache_mem_resp_r_t icache_miss_resp_wdata; + + logic icache_miss_resp_data_w, icache_miss_resp_data_wok; + logic icache_miss_resp_data_r, icache_miss_resp_data_rok; + icache_resp_data_t icache_miss_resp_data_rdata; + + logic icache_miss_resp_meta_w, icache_miss_resp_meta_wok; + logic icache_miss_resp_meta_r, icache_miss_resp_meta_rok; + hpdcache_mem_id_t icache_miss_resp_meta_id; + + icache_resp_data_t icache_miss_rdata; + + generate + if (HPDcacheMemDataWidth < ariane_pkg::ICACHE_LINE_WIDTH) begin + hpdcache_fifo_reg #( + .FIFO_DEPTH (1), + .fifo_data_t (hpdcache_mem_id_t) + ) i_icache_refill_meta_fifo ( + .clk_i, + .rst_ni, + + .w_i (icache_miss_resp_meta_w), + .wok_o (icache_miss_resp_meta_wok), + .wdata_i (icache_miss_resp_wdata.mem_resp_r_id), + + .r_i (icache_miss_resp_meta_r), + .rok_o (icache_miss_resp_meta_rok), + .rdata_o (icache_miss_resp_meta_id) + ); + + hpdcache_data_upsize #( + .WR_WIDTH (HPDcacheMemDataWidth), + .RD_WIDTH (ariane_pkg::ICACHE_LINE_WIDTH), + .DEPTH (1) + ) i_icache_hpdcache_data_upsize ( + .clk_i, + .rst_ni, + + .w_i (icache_miss_resp_data_w), + .wlast_i (icache_miss_resp_wdata.mem_resp_r_last), + .wok_o (icache_miss_resp_data_wok), + .wdata_i (icache_miss_resp_wdata.mem_resp_r_data), + + .r_i (icache_miss_resp_data_r), + .rok_o (icache_miss_resp_data_rok), + .rdata_o (icache_miss_resp_data_rdata) + ); + + assign icache_miss_resp_meta_r = 1'b1, + icache_miss_resp_data_r = 1'b1; + + assign icache_miss_resp_meta_w = icache_miss_resp_w & + icache_miss_resp_wdata.mem_resp_r_last; + + assign icache_miss_resp_data_w = icache_miss_resp_w; + + assign icache_miss_resp_wok = icache_miss_resp_data_wok & ( + icache_miss_resp_meta_wok | ~icache_miss_resp_wdata.mem_resp_r_last); + + assign icache_miss_rdata = icache_miss_resp_data_rdata; + + end else begin + assign icache_miss_resp_data_rok = icache_miss_resp_w; + assign icache_miss_resp_meta_rok = icache_miss_resp_w; + assign icache_miss_resp_wok = 1'b1; + assign icache_miss_resp_meta_id = icache_miss_resp_wdata.mem_resp_r_id; + assign icache_miss_resp_data_rdata = icache_miss_resp_wdata.mem_resp_r_data; + + // In the case of uncacheable accesses, the Icache expects the data to be right-aligned + always_comb + begin : icache_miss_resp_data_comb + if (!icache_miss_req_rdata.mem_req_cacheable) begin + automatic logic [ICACHE_CL_WORD_INDEX - 1: 0] icache_miss_word_index; + automatic logic [63:0] icache_miss_word; + icache_miss_word_index = icache_miss_req_rdata.mem_req_addr[3 +: ICACHE_CL_WORD_INDEX]; + icache_miss_word = icache_miss_resp_data_rdata[icache_miss_word_index*64 +: 64]; + icache_miss_rdata = {{ariane_pkg::ICACHE_LINE_WIDTH-64{1'b0}}, icache_miss_word}; + end else begin + icache_miss_rdata = icache_miss_resp_data_rdata; + end + end + end + endgenerate + + assign icache_miss_resp_valid_o = icache_miss_resp_meta_rok, + icache_miss_resp_o.rtype = wt_cache_pkg::ICACHE_IFILL_ACK, + icache_miss_resp_o.user = '0, + icache_miss_resp_o.inv = '0, + icache_miss_resp_o.tid = icache_miss_resp_meta_id, + icache_miss_resp_o.data = icache_miss_rdata; + + // consume the Icache miss on the arrival of the response. The request + // metadata is decoded to forward the correct word in case of uncacheable + // Icache access + assign icache_miss_req_r = icache_miss_resp_meta_rok; + // }}} + + // Read request arbiter + // {{{ + logic mem_req_read_ready [2:0]; + logic mem_req_read_valid [2:0]; + hpdcache_mem_req_t mem_req_read [2:0]; + + logic mem_req_read_ready_arb; + logic mem_req_read_valid_arb; + hpdcache_mem_req_t mem_req_read_arb; + + assign mem_req_read_valid[0] = icache_miss_req_rok & ~icache_miss_pending_q, + mem_req_read[0] = icache_miss_req_rdata; + + assign dcache_miss_ready_o = mem_req_read_ready[1], + mem_req_read_valid[1] = dcache_miss_valid_i, + mem_req_read[1] = dcache_miss_i; + + assign dcache_uc_read_ready_o = mem_req_read_ready[2], + mem_req_read_valid[2] = dcache_uc_read_valid_i, + mem_req_read[2] = dcache_uc_read_i; + + hpdcache_mem_req_read_arbiter #( + .N (3), + .hpdcache_mem_req_t (hpdcache_mem_req_t) + ) i_mem_req_read_arbiter ( + .clk_i, + .rst_ni, + + .mem_req_read_ready_o (mem_req_read_ready), + .mem_req_read_valid_i (mem_req_read_valid), + .mem_req_read_i (mem_req_read), + + .mem_req_read_ready_i (mem_req_read_ready_arb), + .mem_req_read_valid_o (mem_req_read_valid_arb), + .mem_req_read_o (mem_req_read_arb) + ); + // }}} + + // Read response demultiplexor + // {{{ + logic mem_resp_read_ready; + logic mem_resp_read_valid; + hpdcache_mem_resp_r_t mem_resp_read; + + logic mem_resp_read_ready_arb [2:0]; + logic mem_resp_read_valid_arb [2:0]; + hpdcache_mem_resp_r_t mem_resp_read_arb [2:0]; + + mem_resp_rt_t mem_resp_read_rt; + + always_comb + begin + for (int i = 0; i < MEM_RESP_RT_DEPTH; i++) begin + mem_resp_read_rt[i] = (i == int'( icache_miss_id_i)) ? 0 : + (i == int'(dcache_uc_read_id_i)) ? 2 : 1; + end + end + + hpdcache_mem_resp_demux #( + .N (3), + .resp_t (hpdcache_mem_resp_r_t), + .resp_id_t (hpdcache_mem_id_t) + ) i_mem_resp_read_demux ( + .clk_i, + .rst_ni, + + .mem_resp_ready_o (mem_resp_read_ready), + .mem_resp_valid_i (mem_resp_read_valid), + .mem_resp_id_i (mem_resp_read.mem_resp_r_id), + .mem_resp_i (mem_resp_read), + + .mem_resp_ready_i (mem_resp_read_ready_arb), + .mem_resp_valid_o (mem_resp_read_valid_arb), + .mem_resp_o (mem_resp_read_arb), + + .mem_resp_rt_i (mem_resp_read_rt) + ); + + assign icache_miss_resp_w = mem_resp_read_valid_arb[0], + icache_miss_resp_wdata = mem_resp_read_arb[0], + mem_resp_read_ready_arb[0] = icache_miss_resp_wok; + + assign dcache_miss_resp_valid_o = mem_resp_read_valid_arb[1], + dcache_miss_resp_o = mem_resp_read_arb[1], + mem_resp_read_ready_arb[1] = dcache_miss_resp_ready_i; + + assign dcache_uc_read_resp_valid_o = mem_resp_read_valid_arb[2], + dcache_uc_read_resp_o = mem_resp_read_arb[2], + mem_resp_read_ready_arb[2] = dcache_uc_read_resp_ready_i; + // }}} + + // Write request arbiter + // {{{ + logic mem_req_write_ready [1:0]; + logic mem_req_write_valid [1:0]; + hpdcache_mem_req_t mem_req_write [1:0]; + + logic mem_req_write_data_ready [1:0]; + logic mem_req_write_data_valid [1:0]; + hpdcache_mem_req_w_t mem_req_write_data [1:0]; + + logic mem_req_write_ready_arb; + logic mem_req_write_valid_arb; + hpdcache_mem_req_t mem_req_write_arb; + + logic mem_req_write_data_ready_arb; + logic mem_req_write_data_valid_arb; + hpdcache_mem_req_w_t mem_req_write_data_arb; + + assign dcache_wbuf_ready_o = mem_req_write_ready[0], + mem_req_write_valid[0] = dcache_wbuf_valid_i, + mem_req_write[0] = dcache_wbuf_i; + + assign dcache_wbuf_data_ready_o = mem_req_write_data_ready[0], + mem_req_write_data_valid[0] = dcache_wbuf_data_valid_i, + mem_req_write_data[0] = dcache_wbuf_data_i; + + assign dcache_uc_write_ready_o = mem_req_write_ready[1], + mem_req_write_valid[1] = dcache_uc_write_valid_i, + mem_req_write[1] = dcache_uc_write_i; + + assign dcache_uc_write_data_ready_o = mem_req_write_data_ready[1], + mem_req_write_data_valid[1] = dcache_uc_write_data_valid_i, + mem_req_write_data[1] = dcache_uc_write_data_i; + + hpdcache_mem_req_write_arbiter #( + .N (2), + .hpdcache_mem_req_t (hpdcache_mem_req_t), + .hpdcache_mem_req_w_t (hpdcache_mem_req_w_t) + ) i_mem_req_write_arbiter ( + .clk_i, + .rst_ni, + + .mem_req_write_ready_o (mem_req_write_ready), + .mem_req_write_valid_i (mem_req_write_valid), + .mem_req_write_i (mem_req_write), + + .mem_req_write_data_ready_o (mem_req_write_data_ready), + .mem_req_write_data_valid_i (mem_req_write_data_valid), + .mem_req_write_data_i (mem_req_write_data), + + .mem_req_write_ready_i (mem_req_write_ready_arb), + .mem_req_write_valid_o (mem_req_write_valid_arb), + .mem_req_write_o (mem_req_write_arb), + + .mem_req_write_data_ready_i (mem_req_write_data_ready_arb), + .mem_req_write_data_valid_o (mem_req_write_data_valid_arb), + .mem_req_write_data_o (mem_req_write_data_arb) + ); + // }}} + + // Write response demultiplexor + // {{{ + logic mem_resp_write_ready; + logic mem_resp_write_valid; + hpdcache_mem_resp_w_t mem_resp_write; + + logic mem_resp_write_ready_arb [1:0]; + logic mem_resp_write_valid_arb [1:0]; + hpdcache_mem_resp_w_t mem_resp_write_arb [1:0]; + + mem_resp_rt_t mem_resp_write_rt; + + always_comb + begin + for (int i = 0; i < MEM_RESP_RT_DEPTH; i++) begin + mem_resp_write_rt[i] = (i == int'(dcache_uc_write_id_i)) ? 1 : 0; + end + end + + hpdcache_mem_resp_demux #( + .N (2), + .resp_t (hpdcache_mem_resp_w_t), + .resp_id_t (hpdcache_mem_id_t) + ) i_hpdcache_mem_resp_write_demux ( + .clk_i, + .rst_ni, + + .mem_resp_ready_o (mem_resp_write_ready), + .mem_resp_valid_i (mem_resp_write_valid), + .mem_resp_id_i (mem_resp_write.mem_resp_w_id), + .mem_resp_i (mem_resp_write), + + .mem_resp_ready_i (mem_resp_write_ready_arb), + .mem_resp_valid_o (mem_resp_write_valid_arb), + .mem_resp_o (mem_resp_write_arb), + + .mem_resp_rt_i (mem_resp_write_rt) + ); + + assign dcache_wbuf_resp_valid_o = mem_resp_write_valid_arb[0], + dcache_wbuf_resp_o = mem_resp_write_arb[0], + mem_resp_write_ready_arb[0] = dcache_wbuf_resp_ready_i; + + assign dcache_uc_write_resp_valid_o = mem_resp_write_valid_arb[1], + dcache_uc_write_resp_o = mem_resp_write_arb[1], + mem_resp_write_ready_arb[1] = dcache_uc_write_resp_ready_i; + // }}} + + // I$ miss pending + // {{{ + always_ff @(posedge clk_i or negedge rst_ni) + begin : icache_miss_pending_ff + if (!rst_ni) begin + icache_miss_pending_q <= 1'b0; + end else begin + icache_miss_pending_q <= ( (icache_miss_req_rok & mem_req_read_ready[0]) & ~icache_miss_pending_q) | + (~(icache_miss_req_r & icache_miss_req_rok) & icache_miss_pending_q); + end + end + // }}} + + // AXI adapters + // {{{ + axi_req_t axi_req; + axi_rsp_t axi_resp; + + hpdcache_mem_to_axi_write #( + .hpdcache_mem_req_t (hpdcache_mem_req_t), + .hpdcache_mem_req_w_t (hpdcache_mem_req_w_t), + .hpdcache_mem_resp_w_t (hpdcache_mem_resp_w_t), + .aw_chan_t (axi_aw_chan_t), + .w_chan_t (axi_w_chan_t), + .b_chan_t (axi_b_chan_t) + ) i_hpdcache_mem_to_axi_write ( + .req_ready_o (mem_req_write_ready_arb), + .req_valid_i (mem_req_write_valid_arb), + .req_i (mem_req_write_arb), + + .req_data_ready_o (mem_req_write_data_ready_arb), + .req_data_valid_i (mem_req_write_data_valid_arb), + .req_data_i (mem_req_write_data_arb), + + .resp_ready_i (mem_resp_write_ready), + .resp_valid_o (mem_resp_write_valid), + .resp_o (mem_resp_write), + + .axi_aw_valid_o (axi_req.aw_valid), + .axi_aw_o (axi_req.aw), + .axi_aw_ready_i (axi_resp.aw_ready), + + .axi_w_valid_o (axi_req.w_valid), + .axi_w_o (axi_req.w), + .axi_w_ready_i (axi_resp.w_ready), + + .axi_b_valid_i (axi_resp.b_valid), + .axi_b_i (axi_resp.b), + .axi_b_ready_o (axi_req.b_ready) + ); + + hpdcache_mem_to_axi_read #( + .hpdcache_mem_req_t (hpdcache_mem_req_t), + .hpdcache_mem_resp_r_t (hpdcache_mem_resp_r_t), + .ar_chan_t (axi_ar_chan_t), + .r_chan_t (axi_r_chan_t) + ) i_hpdcache_mem_to_axi_read ( + .req_ready_o (mem_req_read_ready_arb), + .req_valid_i (mem_req_read_valid_arb), + .req_i (mem_req_read_arb), + + .resp_ready_i (mem_resp_read_ready), + .resp_valid_o (mem_resp_read_valid), + .resp_o (mem_resp_read), + + .axi_ar_valid_o (axi_req.ar_valid), + .axi_ar_o (axi_req.ar), + .axi_ar_ready_i (axi_resp.ar_ready), + + .axi_r_valid_i (axi_resp.r_valid), + .axi_r_i (axi_resp.r), + .axi_r_ready_o (axi_req.r_ready) + ); + + assign axi_req_o = axi_req; + assign axi_resp = axi_resp_i; + // }}} + + // Assertions + // {{{ + // pragma translate_off + initial assert (HPDcacheMemIdWidth <= AxiIdWidth) else + $fatal("HPDcacheMemIdWidth shall be less or equal to AxiIdWidth"); + initial assert (HPDcacheMemIdWidth >= (hpdcache_pkg::HPDCACHE_MSHR_SET_WIDTH + hpdcache_pkg::HPDCACHE_MSHR_WAY_WIDTH + 1)) else + $fatal("HPDcacheMemIdWidth shall be wide enough to identify all pending HPDcache misses and Icache misses"); + initial assert (HPDcacheMemIdWidth >= (hpdcache_pkg::HPDCACHE_WBUF_DIR_PTR_WIDTH + 1)) else + $fatal("HPDcacheMemIdWidth shall be wide enough to identify all pending HPDcache cacheable writes and uncacheable writes"); + initial assert (HPDcacheMemDataWidth <= ariane_pkg::ICACHE_LINE_WIDTH) else + $fatal("HPDcacheMemDataWidth shall be less or equal to the width of a Icache line"); + initial assert (HPDcacheMemDataWidth <= ariane_pkg::DCACHE_LINE_WIDTH) else + $fatal("HPDcacheMemDataWidth shall be less or equal to the width of a Dcache line"); + // pragma translate_on + // }}} + +endmodule : cva6_hpdcache_subsystem_axi_arbiter diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/target/generic/hpdcache_params_pkg.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/target/generic/hpdcache_params_pkg.sv new file mode 100644 index 00000000000..92f8d1de5ca --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/target/generic/hpdcache_params_pkg.sv @@ -0,0 +1,180 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2023 + * Description : Generic parameters package for the HPDcache. All parameters + * can be overriden by Verilog preprocessor definitions. + * History : + */ +package hpdcache_params_pkg; + // Definition of global constants for the HPDcache data and directory + // {{{ + `ifndef CONF_HPDCACHE_PA_WIDTH + `define CONF_HPDCACHE_PA_WIDTH 49 + `endif + localparam int unsigned PARAM_PA_WIDTH = `CONF_HPDCACHE_PA_WIDTH; + + // HPDcache number of sets + `ifndef CONF_HPDCACHE_SETS + `define CONF_HPDCACHE_SETS 128 + `endif + localparam int unsigned PARAM_SETS = `CONF_HPDCACHE_SETS; + + // HPDcache number of ways + `ifndef CONF_HPDCACHE_WAYS + `define CONF_HPDCACHE_WAYS 4 + `endif + localparam int unsigned PARAM_WAYS = `CONF_HPDCACHE_WAYS; + + // HPDcache word width (bits) + `ifndef CONF_HPDCACHE_WORD_WIDTH + `define CONF_HPDCACHE_WORD_WIDTH 64 + `endif + localparam int unsigned PARAM_WORD_WIDTH = `CONF_HPDCACHE_WORD_WIDTH; + + // HPDcache cache-line width (bits) + `ifndef CONF_HPDCACHE_CL_WORDS + `define CONF_HPDCACHE_CL_WORDS 8 + `endif + localparam int unsigned PARAM_CL_WORDS = `CONF_HPDCACHE_CL_WORDS; + + // HPDcache number of words in the request data channels (request and response) + `ifndef CONF_HPDCACHE_REQ_WORDS + `define CONF_HPDCACHE_REQ_WORDS 1 + `endif + localparam int unsigned PARAM_REQ_WORDS = `CONF_HPDCACHE_REQ_WORDS; + + // HPDcache request transaction ID width (bits) + `ifndef CONF_HPDCACHE_REQ_TRANS_ID_WIDTH + `define CONF_HPDCACHE_REQ_TRANS_ID_WIDTH 7 + `endif + localparam int unsigned PARAM_REQ_TRANS_ID_WIDTH = `CONF_HPDCACHE_REQ_TRANS_ID_WIDTH; + + // HPDcache request source ID width (bits) + `ifndef CONF_HPDCACHE_REQ_SRC_ID_WIDTH + `define CONF_HPDCACHE_REQ_SRC_ID_WIDTH 3 + `endif + localparam int unsigned PARAM_REQ_SRC_ID_WIDTH = `CONF_HPDCACHE_REQ_SRC_ID_WIDTH; + + // HPDcache physically indexed + `ifndef CONF_HPDCACHE_PHYSICALLY_INDEXED + `define CONF_HPDCACHE_PHYSICALLY_INDEXED 1'b0 + `endif + localparam bit PARAM_PHYSICALLY_INDEXED = `CONF_HPDCACHE_PHYSICALLY_INDEXED; + // }}} + + // Definition of constants and types for HPDcache data memory + // {{{ + `ifndef CONF_HPDCACHE_DATA_WAYS_PER_RAM_WORD + `define CONF_HPDCACHE_DATA_WAYS_PER_RAM_WORD 2 + `endif + localparam int unsigned PARAM_DATA_WAYS_PER_RAM_WORD = `CONF_HPDCACHE_DATA_WAYS_PER_RAM_WORD; + + `ifndef CONF_HPDCACHE_DATA_SETS_PER_RAM + `define CONF_HPDCACHE_DATA_SETS_PER_RAM PARAM_SETS + `endif + localparam int unsigned PARAM_DATA_SETS_PER_RAM = `CONF_HPDCACHE_DATA_SETS_PER_RAM; + + // HPDcache DATA RAM implements write byte enable + `ifndef CONF_HPDCACHE_DATA_RAM_WBYTEENABLE + `define CONF_HPDCACHE_DATA_RAM_WBYTEENABLE 0 + `endif + localparam bit PARAM_DATA_RAM_WBYTEENABLE = `CONF_HPDCACHE_DATA_RAM_WBYTEENABLE; + + // Define the number of memory contiguous words that can be accessed + // simultaneously from the cache. + // - This limits the maximum width for the data channel from requesters + // - This impacts the refill latency + `ifndef CONF_HPDCACHE_ACCESS_WORDS + `define CONF_HPDCACHE_ACCESS_WORDS 4 + `endif + localparam int unsigned PARAM_ACCESS_WORDS = `CONF_HPDCACHE_ACCESS_WORDS; + // }}} + + // Definition of constants and types for the Miss Status Holding Register (MSHR) + // {{{ + `ifndef CONF_HPDCACHE_MSHR_SETS + `define CONF_HPDCACHE_MSHR_SETS 64 + `endif + localparam int unsigned PARAM_MSHR_SETS = `CONF_HPDCACHE_MSHR_SETS; + + // HPDcache MSHR number of ways + `ifndef CONF_HPDCACHE_MSHR_WAYS + `define CONF_HPDCACHE_MSHR_WAYS 2 + `endif + localparam int unsigned PARAM_MSHR_WAYS = `CONF_HPDCACHE_MSHR_WAYS; + + // HPDcache MSHR number of ways in the same SRAM word + `ifndef CONF_HPDCACHE_MSHR_WAYS_PER_RAM_WORD + `define CONF_HPDCACHE_MSHR_WAYS_PER_RAM_WORD 2 + `endif + localparam int unsigned PARAM_MSHR_WAYS_PER_RAM_WORD = `CONF_HPDCACHE_MSHR_WAYS_PER_RAM_WORD; + + // HPDcache MSHR number of sets in the same SRAM + `ifndef CONF_HPDCACHE_MSHR_SETS_PER_RAM + `define CONF_HPDCACHE_MSHR_SETS_PER_RAM PARAM_MSHR_SETS + `endif + localparam int unsigned PARAM_MSHR_SETS_PER_RAM = `CONF_HPDCACHE_MSHR_SETS_PER_RAM; + + // HPDcache MSHR implements write byte enable + `ifndef CONF_HPDCACHE_MSHR_RAM_WBYTEENABLE + `define CONF_HPDCACHE_MSHR_RAM_WBYTEENABLE 0 + `endif + localparam bit PARAM_MSHR_RAM_WBYTEENABLE = `CONF_HPDCACHE_MSHR_RAM_WBYTEENABLE; + + `ifndef CONF_HPDCACHE_MSHR_USE_REGBANK + `define CONF_HPDCACHE_MSHR_USE_REGBANK 0 + `endif + localparam bit PARAM_MSHR_USE_REGBANK = `CONF_HPDCACHE_MSHR_USE_REGBANK; + // }}} + + // Definition of constants and types for the Write Buffer (WBUF) + // {{{ + `ifndef CONF_HPDCACHE_WBUF_DIR_ENTRIES + `define CONF_HPDCACHE_WBUF_DIR_ENTRIES 16 + `endif + localparam int unsigned PARAM_WBUF_DIR_ENTRIES = `CONF_HPDCACHE_WBUF_DIR_ENTRIES; + + `ifndef CONF_HPDCACHE_WBUF_DATA_ENTRIES + `define CONF_HPDCACHE_WBUF_DATA_ENTRIES 4 + `endif + localparam int unsigned PARAM_WBUF_DATA_ENTRIES = `CONF_HPDCACHE_WBUF_DATA_ENTRIES; + + `ifndef CONF_HPDCACHE_WBUF_WORDS + `define CONF_HPDCACHE_WBUF_WORDS PARAM_REQ_WORDS + `endif + localparam int unsigned PARAM_WBUF_WORDS = `CONF_HPDCACHE_WBUF_WORDS; + + `ifndef CONF_HPDCACHE_WBUF_TIMECNT_WIDTH + `define CONF_HPDCACHE_WBUF_TIMECNT_WIDTH 4 + `endif + localparam int unsigned PARAM_WBUF_TIMECNT_WIDTH = `CONF_HPDCACHE_WBUF_TIMECNT_WIDTH; + // }}} + + // Definition of constants and types for the Replay Table (RTAB) + // {{{ + `ifndef CONF_HPDCACHE_RTAB_ENTRIES + `define CONF_HPDCACHE_RTAB_ENTRIES 8 + `endif + localparam int PARAM_RTAB_ENTRIES = `CONF_HPDCACHE_RTAB_ENTRIES; + // }}} + +endpackage diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_req_read_arbiter.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_req_read_arbiter.sv new file mode 100644 index 00000000000..cb32acf57a8 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_req_read_arbiter.sv @@ -0,0 +1,103 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : Dcache Memory Read Request Channel Arbiter + * History : + */ +module hpdcache_mem_req_read_arbiter +import hpdcache_pkg::*; +// Parameters +// {{{ +#( + parameter hpdcache_uint N = 0, + parameter type hpdcache_mem_req_t = logic +) +// }}} + +// Ports +// {{{ +( + input logic clk_i, + input logic rst_ni, + + output logic mem_req_read_ready_o [N-1:0], + input logic mem_req_read_valid_i [N-1:0], + input hpdcache_mem_req_t mem_req_read_i [N-1:0], + + input logic mem_req_read_ready_i, + output logic mem_req_read_valid_o, + output hpdcache_mem_req_t mem_req_read_o +); +// }}} + + logic [N-1:0] mem_read_arb_req_valid; + hpdcache_mem_req_t [N-1:0] mem_read_arb_req; + logic [N-1:0] mem_read_arb_req_gnt; + + logic req_valid; + + genvar gen_i; + + + // Pack inputs + generate + for (gen_i = 0; gen_i < int'(N); gen_i++) begin : pack_inputs_gen + assign mem_read_arb_req_valid[gen_i] = mem_req_read_valid_i[gen_i], + mem_read_arb_req [gen_i] = mem_req_read_i[gen_i]; + end + endgenerate + + assign req_valid = |(mem_read_arb_req_gnt & mem_read_arb_req_valid); + + // Fixed-priority arbiter + hpdcache_fxarb #( + .N (N) + ) hpdcache_fxarb_mem_req_write_i ( + .clk_i, + .rst_ni, + .req_i (mem_read_arb_req_valid), + .gnt_o (mem_read_arb_req_gnt), + .ready_i (mem_req_read_ready_i) + ); + + // Demultiplexor for the ready signal + generate + for (gen_i = 0; gen_i < int'(N); gen_i++) begin : req_ready_gen + assign mem_req_read_ready_o[gen_i] = mem_req_read_ready_i & + mem_read_arb_req_gnt[gen_i] & mem_read_arb_req_valid[gen_i]; + end + endgenerate + + assign mem_req_read_valid_o = req_valid; + + // Multiplexor for requests + hpdcache_mux #( + .NINPUT (N), + .DATA_WIDTH ($bits(hpdcache_mem_req_t)), + .ONE_HOT_SEL (1'b1) + ) mem_read_req_mux_i ( + .data_i (mem_read_arb_req), + .sel_i (mem_read_arb_req_gnt), + .data_o (mem_req_read_o) + ); + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_req_write_arbiter.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_req_write_arbiter.sv new file mode 100644 index 00000000000..a7916eca7e2 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_req_write_arbiter.sv @@ -0,0 +1,193 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : Dcache Memory Write Channels Arbiter + * History : + */ +module hpdcache_mem_req_write_arbiter +import hpdcache_pkg::*; +// Parameters +// {{{ +#( + parameter hpdcache_uint N = 0, + parameter type hpdcache_mem_req_t = logic, + parameter type hpdcache_mem_req_w_t = logic +) +// }}} + +// Ports +// {{{ +( + input logic clk_i, + input logic rst_ni, + + output logic mem_req_write_ready_o [N-1:0], + input logic mem_req_write_valid_i [N-1:0], + input hpdcache_mem_req_t mem_req_write_i [N-1:0], + + output logic mem_req_write_data_ready_o [N-1:0], + input logic mem_req_write_data_valid_i [N-1:0], + input hpdcache_mem_req_w_t mem_req_write_data_i [N-1:0], + + input logic mem_req_write_ready_i, + output logic mem_req_write_valid_o, + output hpdcache_mem_req_t mem_req_write_o, + + input logic mem_req_write_data_ready_i, + output logic mem_req_write_data_valid_o, + output hpdcache_mem_req_w_t mem_req_write_data_o +); +// }}} + + typedef enum { + REQ_IDLE, + REQ_META_SENT, + REQ_DATA_SENT + } req_send_fsm_t; + + req_send_fsm_t req_send_fsm_q, req_send_fsm_d; + logic req_valid; + logic req_data_valid; + + logic [N-1:0] mem_write_arb_req_valid; + hpdcache_mem_req_t [N-1:0] mem_write_arb_req; + logic [N-1:0] mem_write_arb_req_data_valid; + hpdcache_mem_req_w_t [N-1:0] mem_write_arb_req_data; + logic [N-1:0] mem_write_arb_req_gnt; + logic mem_write_arb_req_ready; + + genvar gen_i; + + + generate + for (gen_i = 0; gen_i < int'(N); gen_i++) begin : pack_inputs_gen + assign mem_write_arb_req_valid [gen_i] = mem_req_write_valid_i[gen_i], + mem_write_arb_req [gen_i] = mem_req_write_i[gen_i], + mem_write_arb_req_data_valid[gen_i] = mem_req_write_data_valid_i[gen_i], + mem_write_arb_req_data [gen_i] = mem_req_write_data_i[gen_i]; + end + endgenerate + + // Fixed-priority arbiter + hpdcache_fxarb #( + .N (2) + ) hpdcache_fxarb_mem_req_write_i ( + .clk_i, + .rst_ni, + .req_i (mem_write_arb_req_valid), + .gnt_o (mem_write_arb_req_gnt), + .ready_i (mem_write_arb_req_ready) + ); + + assign req_valid = |(mem_write_arb_req_gnt & mem_write_arb_req_valid); + assign req_data_valid = |(mem_write_arb_req_gnt & mem_write_arb_req_data_valid); + + // Request sent FSM + // + // This FSM allows to make sure that the request and its corresponding + // data are sent in order. This is, when a requester sends a request, this + // FSM keeps the grant signal on this requester until it has sent the + // corresponding data. + // + // {{{ + always_comb + begin : req_send_fsm_comb + req_send_fsm_d = req_send_fsm_q; + mem_write_arb_req_ready = 1'b0; + case (req_send_fsm_q) + REQ_IDLE: + if (req_valid && mem_req_write_ready_i) begin + if (req_data_valid) begin + if (mem_req_write_data_ready_i) begin + mem_write_arb_req_ready = 1'b1; + req_send_fsm_d = REQ_IDLE; + end else begin + req_send_fsm_d = REQ_META_SENT; + end + end + end else if (req_data_valid && mem_req_write_data_ready_i) begin + req_send_fsm_d = REQ_DATA_SENT; + end + + REQ_META_SENT: + if (req_data_valid && mem_req_write_data_ready_i) begin + mem_write_arb_req_ready = 1'b1; + req_send_fsm_d = REQ_IDLE; + end + + REQ_DATA_SENT: + if (req_valid && mem_req_write_ready_i) begin + mem_write_arb_req_ready = 1'b1; + req_send_fsm_d = REQ_IDLE; + end + endcase + end + + always_ff @(posedge clk_i or negedge rst_ni) + begin : req_send_fsm_ff + if (!rst_ni) begin + req_send_fsm_q <= REQ_IDLE; + end else begin + req_send_fsm_q <= req_send_fsm_d; + end + end + // }}} + + generate + for (gen_i = 0; gen_i < int'(N); gen_i++) begin : req_ready_gen + assign mem_req_write_ready_o[gen_i] = + (mem_write_arb_req_gnt[gen_i] & mem_req_write_ready_i) & + (req_send_fsm_q != REQ_META_SENT); + + assign mem_req_write_data_ready_o[gen_i] = + (mem_write_arb_req_gnt[gen_i] & mem_req_write_data_ready_i) & + (req_send_fsm_q != REQ_DATA_SENT); + end + endgenerate + + // Output assignments + // {{{ + assign mem_req_write_valid_o = req_valid & (req_send_fsm_q != REQ_META_SENT); + assign mem_req_write_data_valid_o = req_data_valid & (req_send_fsm_q != REQ_DATA_SENT); + + hpdcache_mux #( + .NINPUT (N), + .DATA_WIDTH ($bits(hpdcache_mem_req_t)), + .ONE_HOT_SEL (1'b1) + ) mem_write_req_mux_i ( + .data_i (mem_write_arb_req), + .sel_i (mem_write_arb_req_gnt), + .data_o (mem_req_write_o) + ); + + hpdcache_mux #( + .NINPUT (N), + .DATA_WIDTH ($bits(hpdcache_mem_req_w_t)), + .ONE_HOT_SEL (1'b1) + ) mem_write_data_req_mux_i ( + .data_i (mem_write_arb_req_data), + .sel_i (mem_write_arb_req_gnt), + .data_o (mem_req_write_data_o) + ); + // }}} + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_resp_demux.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_resp_demux.sv new file mode 100644 index 00000000000..c1502a985bb --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_resp_demux.sv @@ -0,0 +1,108 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : June, 2022 + * Description : Dcache Memory Reponse Demultiplexer + * History : + */ +module hpdcache_mem_resp_demux +// Parameters +// {{{ +#( + parameter int N = 0, + parameter type resp_t = logic, + parameter type resp_id_t = logic, + + localparam int RT_DEPTH = (1 << $bits(resp_id_t)), + localparam type rt_t = resp_id_t [RT_DEPTH-1:0] +) +// }}} + +// Ports +// {{{ +( + input logic clk_i, + input logic rst_ni, + + output logic mem_resp_ready_o, + input logic mem_resp_valid_i, + input resp_id_t mem_resp_id_i, + input resp_t mem_resp_i, + + input logic mem_resp_ready_i [N-1:0], + output logic mem_resp_valid_o [N-1:0], + output resp_t mem_resp_o [N-1:0], + + input rt_t mem_resp_rt_i +); +// }}} + + typedef logic [$clog2(N)-1:0] sel_t; + + logic [N-1:0] mem_resp_demux_valid; + resp_t [N-1:0] mem_resp_demux; + logic [N-1:0] mem_resp_demux_ready; + sel_t mem_resp_demux_sel; + + // Route the response according to the response ID and the routing table + assign mem_resp_demux_sel = mem_resp_rt_i[int'(mem_resp_id_i)]; + + // Forward the response to the corresponding output port + hpdcache_demux #( + .NOUTPUT (N), + .DATA_WIDTH (1), + .ONE_HOT_SEL (0) + ) i_resp_valid_demux ( + .data_i (mem_resp_valid_i), + .sel_i (mem_resp_demux_sel), + .data_o (mem_resp_demux_valid) + ); + + hpdcache_demux #( + .NOUTPUT (N), + .DATA_WIDTH ($bits(resp_t)), + .ONE_HOT_SEL (0) + ) i_resp_demux ( + .data_i (mem_resp_i), + .sel_i (mem_resp_demux_sel), + .data_o (mem_resp_demux) + ); + + hpdcache_mux #( + .NINPUT (N), + .DATA_WIDTH (1), + .ONE_HOT_SEL (0) + ) i_resp_ready_mux ( + .data_i (mem_resp_demux_ready), + .sel_i (mem_resp_demux_sel), + .data_o (mem_resp_ready_o) + ); + + // Pack/unpack responses + generate + for (genvar gen_i = 0; gen_i < int'(N); gen_i++) begin : pack_unpack_resp_gen + assign mem_resp_valid_o [gen_i] = mem_resp_demux_valid [gen_i]; + assign mem_resp_o [gen_i] = mem_resp_demux [gen_i]; + assign mem_resp_demux_ready [gen_i] = mem_resp_ready_i [gen_i]; + end + endgenerate + +endmodule : hpdcache_mem_resp_demux diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_to_axi_read.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_to_axi_read.sv new file mode 100644 index 00000000000..ec3fad741f7 --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_to_axi_read.sv @@ -0,0 +1,95 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : Dcache memory request to axi read channels + * History : + */ +module hpdcache_mem_to_axi_read +import hpdcache_pkg::*; +#( + parameter type hpdcache_mem_req_t = logic, + parameter type hpdcache_mem_resp_r_t = logic, + parameter type ar_chan_t = logic, + parameter type r_chan_t = logic +) +( + output logic req_ready_o, + input logic req_valid_i, + input hpdcache_mem_req_t req_i, + + input logic resp_ready_i, + output logic resp_valid_o, + output hpdcache_mem_resp_r_t resp_o, + + output logic axi_ar_valid_o, + output ar_chan_t axi_ar_o, + input logic axi_ar_ready_i, + + input logic axi_r_valid_i, + input r_chan_t axi_r_i, + output logic axi_r_ready_o +); + + logic lock; + axi_pkg::cache_t cache; + hpdcache_mem_error_e resp; + + assign lock = (req_i.mem_req_command == HPDCACHE_MEM_ATOMIC) && + (req_i.mem_req_atomic == HPDCACHE_MEM_ATOMIC_LDEX); + + assign cache = req_i.mem_req_cacheable ? + axi_pkg::CACHE_BUFFERABLE | + axi_pkg::CACHE_MODIFIABLE | + axi_pkg::CACHE_RD_ALLOC | + axi_pkg::CACHE_WR_ALLOC : '0; + + always_comb + begin : resp_decode_comb + case (axi_r_i.resp) + axi_pkg::RESP_SLVERR, + axi_pkg::RESP_DECERR: resp = HPDCACHE_MEM_RESP_NOK; + default: resp = HPDCACHE_MEM_RESP_OK; + endcase + end + + assign req_ready_o = axi_ar_ready_i, + axi_ar_valid_o = req_valid_i, + axi_ar_o.id = req_i.mem_req_id, + axi_ar_o.addr = req_i.mem_req_addr, + axi_ar_o.len = req_i.mem_req_len, + axi_ar_o.size = req_i.mem_req_size, + axi_ar_o.burst = axi_pkg::BURST_INCR, + axi_ar_o.lock = lock, + axi_ar_o.cache = cache, + axi_ar_o.prot = '0, + axi_ar_o.qos = '0, + axi_ar_o.region = '0, + axi_ar_o.user = '0; + + assign axi_r_ready_o = resp_ready_i, + resp_valid_o = axi_r_valid_i, + resp_o.mem_resp_r_error = resp, + resp_o.mem_resp_r_id = axi_r_i.id, + resp_o.mem_resp_r_data = axi_r_i.data, + resp_o.mem_resp_r_last = axi_r_i.last; + +endmodule diff --git a/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_to_axi_write.sv b/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_to_axi_write.sv new file mode 100644 index 00000000000..8d8eb9f6d8c --- /dev/null +++ b/vendor/openhwgroup/cvhpdcache/rtl/src/utils/hpdcache_mem_to_axi_write.sv @@ -0,0 +1,148 @@ +/* + * Copyright 2023 CEA* + * *Commissariat a l'Energie Atomique et aux Energies Alternatives (CEA) + * + * SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1 + * + * Licensed under the Solderpad Hardware License v 2.1 (the “License”); you + * may not use this file except in compliance with the License, or, at your + * option, the Apache License version 2.0. You may obtain a copy of the + * License at + * + * https://solderpad.org/licenses/SHL-2.1/ + * + * Unless required by applicable law or agreed to in writing, any work + * distributed under the License is distributed on an “AS IS” BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Authors : Cesar Fuguet + * Creation Date : April, 2021 + * Description : Dcache memory request to axi write channels + * History : + */ +module hpdcache_mem_to_axi_write +import hpdcache_pkg::*; +#( + parameter type hpdcache_mem_req_t = logic, + parameter type hpdcache_mem_req_w_t = logic, + parameter type hpdcache_mem_resp_w_t = logic, + parameter type aw_chan_t = logic, + parameter type w_chan_t = logic, + parameter type b_chan_t = logic +) +( + output logic req_ready_o, + input logic req_valid_i, + input hpdcache_mem_req_t req_i, + + output logic req_data_ready_o, + input logic req_data_valid_i, + input hpdcache_mem_req_w_t req_data_i, + + input logic resp_ready_i, + output logic resp_valid_o, + output hpdcache_mem_resp_w_t resp_o, + + output logic axi_aw_valid_o, + output aw_chan_t axi_aw_o, + input logic axi_aw_ready_i, + + output logic axi_w_valid_o, + output w_chan_t axi_w_o, + input logic axi_w_ready_i, + + input logic axi_b_valid_i, + input b_chan_t axi_b_i, + output logic axi_b_ready_o +); + + logic lock; + axi_pkg::atop_t atop; + axi_pkg::cache_t cache; + hpdcache_mem_error_e resp; + + always_comb + begin : atop_comb + lock = 1'b0; + atop = '0; + case (req_i.mem_req_command) + HPDCACHE_MEM_ATOMIC: begin + case (req_i.mem_req_atomic) + HPDCACHE_MEM_ATOMIC_STEX: lock = 1'b1; + HPDCACHE_MEM_ATOMIC_ADD : atop = {axi_pkg::ATOP_ATOMICLOAD, + axi_pkg::ATOP_LITTLE_END, + axi_pkg::ATOP_ADD}; + HPDCACHE_MEM_ATOMIC_CLR : atop = {axi_pkg::ATOP_ATOMICLOAD, + axi_pkg::ATOP_LITTLE_END, + axi_pkg::ATOP_CLR}; + HPDCACHE_MEM_ATOMIC_SET : atop = {axi_pkg::ATOP_ATOMICLOAD, + axi_pkg::ATOP_LITTLE_END, + axi_pkg::ATOP_SET}; + HPDCACHE_MEM_ATOMIC_EOR : atop = {axi_pkg::ATOP_ATOMICLOAD, + axi_pkg::ATOP_LITTLE_END, + axi_pkg::ATOP_EOR}; + HPDCACHE_MEM_ATOMIC_SMAX: atop = {axi_pkg::ATOP_ATOMICLOAD, + axi_pkg::ATOP_LITTLE_END, + axi_pkg::ATOP_SMAX}; + HPDCACHE_MEM_ATOMIC_SMIN: atop = {axi_pkg::ATOP_ATOMICLOAD, + axi_pkg::ATOP_LITTLE_END, + axi_pkg::ATOP_SMIN}; + HPDCACHE_MEM_ATOMIC_UMAX: atop = {axi_pkg::ATOP_ATOMICLOAD, + axi_pkg::ATOP_LITTLE_END, + axi_pkg::ATOP_UMAX}; + HPDCACHE_MEM_ATOMIC_UMIN: atop = {axi_pkg::ATOP_ATOMICLOAD, + axi_pkg::ATOP_LITTLE_END, + axi_pkg::ATOP_UMIN}; + HPDCACHE_MEM_ATOMIC_SWAP: atop = axi_pkg::ATOP_ATOMICSWAP; + endcase + end + endcase + end + + assign cache = (req_i.mem_req_cacheable && !lock) ? + axi_pkg::CACHE_BUFFERABLE | + axi_pkg::CACHE_MODIFIABLE | + axi_pkg::CACHE_RD_ALLOC | + axi_pkg::CACHE_WR_ALLOC : '0; + + always_comb + begin : resp_decode_comb + case (axi_b_i.resp) + axi_pkg::RESP_SLVERR, + axi_pkg::RESP_DECERR: resp = HPDCACHE_MEM_RESP_NOK; + default: resp = HPDCACHE_MEM_RESP_OK; + endcase + end + + assign req_ready_o = axi_aw_ready_i, + axi_aw_valid_o = req_valid_i, + axi_aw_o.id = req_i.mem_req_id, + axi_aw_o.addr = req_i.mem_req_addr, + axi_aw_o.len = req_i.mem_req_len, + axi_aw_o.size = req_i.mem_req_size, + axi_aw_o.burst = axi_pkg::BURST_INCR, + axi_aw_o.lock = lock, + axi_aw_o.cache = cache, + axi_aw_o.prot = '0, + axi_aw_o.qos = '0, + axi_aw_o.region = '0, + axi_aw_o.atop = atop, + axi_aw_o.user = '0; + + assign req_data_ready_o = axi_w_ready_i, + axi_w_valid_o = req_data_valid_i, + axi_w_o.data = req_data_i.mem_req_w_data, + axi_w_o.strb = req_data_i.mem_req_w_be, + axi_w_o.last = req_data_i.mem_req_w_last, + axi_w_o.user = '0; + + assign axi_b_ready_o = resp_ready_i, + resp_valid_o = axi_b_valid_i, + resp_o.mem_resp_w_error = resp, + resp_o.mem_resp_w_id = axi_b_i.id, + resp_o.mem_resp_w_is_atomic = (axi_b_i.resp == axi_pkg::RESP_EXOKAY); + +endmodule diff --git a/vendor/openhwgroup_cvhpdcache.lock.hjson b/vendor/openhwgroup_cvhpdcache.lock.hjson new file mode 100644 index 00000000000..f2faf95734b --- /dev/null +++ b/vendor/openhwgroup_cvhpdcache.lock.hjson @@ -0,0 +1,14 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// This file is generated by the util/vendor script. Please do not modify it +// manually. + +{ + upstream: + { + url: https://github.com/openhwgroup/cv-hpdcache + rev: 0cf8e7970bba32ec4ff87ba70d7ee25044fd0382 + } +} diff --git a/vendor/openhwgroup_cvhpdcache.vendor.hjson b/vendor/openhwgroup_cvhpdcache.vendor.hjson new file mode 100644 index 00000000000..9072460164d --- /dev/null +++ b/vendor/openhwgroup_cvhpdcache.vendor.hjson @@ -0,0 +1,28 @@ +// -*- coding: utf-8 -*- +// Copyright (C) 2023 Commissariat a l'Energie Atomique et aux +// Energies Alternatives +// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0. +// Original Author: Cesar Fuguet (cesar.fuguettortolero@cea.fr) + +{ + // Name of the project + name: "openhwgroup_cvhpdcache", + + // Target directory: relative to the location of this script. + target_dir: "openhwgroup/cvhpdcache", + + // Upstream repository + upstream: { + // URL + url: "https://github.com/openhwgroup/cv-hpdcache", + // revision + rev: "v3.0.0", + } + + // Patch dir for local changes + patch_dir: "patches/openhwgroup/cvhpdcache", + + // Exclusions from upstream content + exclude_from_upstream: [] +} +