├── .gitignore ├── Bender.yml ├── LICENSE ├── Makefile ├── README.md ├── ace.core ├── doc ├── ace_ccu_top.md └── images │ ├── ccu_fsm.drawio │ ├── ccu_fsm.drawio.svg │ ├── ccu_logic.drawio │ ├── ccu_logic.drawio.svg │ ├── ccu_top.drawio │ └── ccu_top.drawio.svg ├── include └── ace │ ├── assign.svh │ └── typedef.svh ├── scripts ├── compile_vsim.sh └── run_vsim.sh ├── src ├── ace_ccu_top.sv ├── ace_intf.sv ├── ace_pkg.sv ├── ace_test.sv ├── ace_trs_dec.sv ├── ccu_fsm.sv ├── snoop_intf.sv ├── snoop_pkg.sv └── snoop_test.sv ├── src_files.yml └── test ├── tb_ace_ccu_pkg.sv ├── tb_ace_ccu_top.sv └── tb_ace_ccu_top_sanity.sv /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | !.git* 3 | !.ci/ 4 | /.git/ 5 | /build 6 | /Bender.lock 7 | /Bender.local 8 | *.log 9 | work/ 10 | transcript 11 | compile.tcl 12 | -------------------------------------------------------------------------------- /Bender.yml: -------------------------------------------------------------------------------- 1 | package: 2 | name: ace 3 | authors: 4 | # Alphabetically ordered by last name (maintainers first) 5 | 6 | dependencies: 7 | axi: { git: "https://github.com/pulp-platform/axi.git", version: 0.39.0-beta.2 } 8 | 9 | export_include_dirs: 10 | - include 11 | 12 | sources: 13 | # Source files grouped in levels. Files in level 0 have no dependencies on files in this 14 | # package. Files in level 1 only depend on files in level 0, files in level 2 on files in 15 | # levels 1 and 0, etc. Files within a level are ordered alphabetically. 16 | # Level 0 17 | - src/ace_pkg.sv 18 | - src/snoop_pkg.sv 19 | # Level 1 20 | - src/ace_intf.sv 21 | - src/snoop_intf.sv 22 | # Level 2 23 | - src/ace_trs_dec.sv 24 | - src/ccu_fsm.sv 25 | # Level 3 26 | - src/ace_ccu_top.sv 27 | 28 | - target: simulation 29 | files: 30 | - src/ace_test.sv 31 | - src/snoop_test.sv 32 | 33 | - target: test 34 | files: 35 | # Level 0 36 | - test/tb_ace_ccu_pkg.sv 37 | # Level 1 38 | - test/tb_ace_ccu_top.sv 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | SOLDERPAD HARDWARE LICENSE version 0.51 2 | 3 | This license is based closely on the Apache License Version 2.0, but is not 4 | approved or endorsed by the Apache Foundation. A copy of the non-modified 5 | Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0. 6 | 7 | As this license is not currently OSI or FSF approved, the Licensor permits any 8 | Work licensed under this License, at the option of the Licensee, to be treated 9 | as licensed under the Apache License Version 2.0 (which is so approved). 10 | 11 | This License is licensed under the terms of this License and in particular 12 | clause 7 below (Disclaimer of Warranties) applies in relation to its use. 13 | 14 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 15 | 16 | 1. Definitions. 17 | 18 | "License" shall mean the terms and conditions for use, reproduction, and 19 | distribution as defined by Sections 1 through 9 of this document. 20 | 21 | "Licensor" shall mean the Rights owner or entity authorized by the Rights owner 22 | that is granting the License. 23 | 24 | "Legal Entity" shall mean the union of the acting entity and all other entities 25 | that control, are controlled by, or are under common control with that entity. 26 | For the purposes of this definition, "control" means (i) the power, direct or 27 | indirect, to cause the direction or management of such entity, whether by 28 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 29 | outstanding shares, or (iii) beneficial ownership of such entity. 30 | 31 | "You" (or "Your") shall mean an individual or Legal Entity exercising 32 | permissions granted by this License. 33 | 34 | "Rights" means copyright and any similar right including design right (whether 35 | registered or unregistered), semiconductor topography (mask) rights and 36 | database rights (but excluding Patents and Trademarks). 37 | 38 | "Source" form shall mean the preferred form for making modifications, including 39 | but not limited to source code, net lists, board layouts, CAD files, 40 | documentation source, and configuration files. 41 | 42 | "Object" form shall mean any form resulting from mechanical transformation or 43 | translation of a Source form, including but not limited to compiled object 44 | code, generated documentation, the instantiation of a hardware design and 45 | conversions to other media types, including intermediate forms such as 46 | bytecodes, FPGA bitstreams, artwork and semiconductor topographies (mask 47 | works). 48 | 49 | "Work" shall mean the work of authorship, whether in Source form or other 50 | Object form, made available under the License, as indicated by a Rights notice 51 | that is included in or attached to the work (an example is provided in the 52 | Appendix below). 53 | 54 | "Derivative Works" shall mean any work, whether in Source or Object form, that 55 | is based on (or derived from) the Work and for which the editorial revisions, 56 | annotations, elaborations, or other modifications represent, as a whole, an 57 | original work of authorship. For the purposes of this License, Derivative Works 58 | shall not include works that remain separable from, or merely link (or bind by 59 | name) or physically connect to or interoperate with the interfaces of, the Work 60 | and Derivative Works thereof. 61 | 62 | "Contribution" shall mean any design or work of authorship, including the 63 | original version of the Work and any modifications or additions to that Work or 64 | Derivative Works thereof, that is intentionally submitted to Licensor for 65 | inclusion in the Work by the Rights owner or by an individual or Legal Entity 66 | authorized to submit on behalf of the Rights owner. For the purposes of this 67 | definition, "submitted" means any form of electronic, verbal, or written 68 | communication sent to the Licensor or its representatives, including but not 69 | limited to communication on electronic mailing lists, source code control 70 | systems, and issue tracking systems that are managed by, or on behalf of, the 71 | Licensor for the purpose of discussing and improving the Work, but excluding 72 | communication that is conspicuously marked or otherwise designated in writing 73 | by the Rights owner as "Not a Contribution." 74 | 75 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 76 | of whom a Contribution has been received by Licensor and subsequently 77 | incorporated within the Work. 78 | 79 | 2. Grant of License. Subject to the terms and conditions of this License, each 80 | Contributor hereby grants to You a perpetual, worldwide, non-exclusive, 81 | no-charge, royalty-free, irrevocable license under the Rights to reproduce, 82 | prepare Derivative Works of, publicly display, publicly perform, sublicense, 83 | and distribute the Work and such Derivative Works in Source or Object form and 84 | do anything in relation to the Work as if the Rights did not exist. 85 | 86 | 3. Grant of Patent License. Subject to the terms and conditions of this 87 | License, each Contributor hereby grants to You a perpetual, worldwide, 88 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this 89 | section) patent license to make, have made, use, offer to sell, sell, import, 90 | and otherwise transfer the Work, where such license applies only to those 91 | patent claims licensable by such Contributor that are necessarily infringed by 92 | their Contribution(s) alone or by combination of their Contribution(s) with the 93 | Work to which such Contribution(s) was submitted. If You institute patent 94 | litigation against any entity (including a cross-claim or counterclaim in a 95 | lawsuit) alleging that the Work or a Contribution incorporated within the Work 96 | constitutes direct or contributory patent infringement, then any patent 97 | licenses granted to You under this License for that Work shall terminate as of 98 | the date such litigation is filed. 99 | 100 | 4. Redistribution. You may reproduce and distribute copies of the Work or 101 | Derivative Works thereof in any medium, with or without modifications, and in 102 | Source or Object form, provided that You meet the following conditions: 103 | 104 | You must give any other recipients of the Work or Derivative Works a copy 105 | of this License; and 106 | 107 | You must cause any modified files to carry prominent notices stating that 108 | You changed the files; and 109 | 110 | You must retain, in the Source form of any Derivative Works that You 111 | distribute, all copyright, patent, trademark, and attribution notices from 112 | the Source form of the Work, excluding those notices that do not pertain to 113 | any part of the Derivative Works; and 114 | 115 | If the Work includes a "NOTICE" text file as part of its distribution, then 116 | any Derivative Works that You distribute must include a readable copy of 117 | the attribution notices contained within such NOTICE file, excluding those 118 | notices that do not pertain to any part of the Derivative Works, in at 119 | least one of the following places: within a NOTICE text file distributed as 120 | part of the Derivative Works; within the Source form or documentation, if 121 | provided along with the Derivative Works; or, within a display generated by 122 | the Derivative Works, if and wherever such third-party notices normally 123 | appear. The contents of the NOTICE file are for informational purposes only 124 | and do not modify the License. You may add Your own attribution notices 125 | within Derivative Works that You distribute, alongside or as an addendum to 126 | the NOTICE text from the Work, provided that such additional attribution 127 | notices cannot be construed as modifying the License. You may add Your own 128 | copyright statement to Your modifications and may provide additional or 129 | different license terms and conditions for use, reproduction, or 130 | distribution of Your modifications, or for any such Derivative Works as a 131 | whole, provided Your use, reproduction, and distribution of the Work 132 | otherwise complies with the conditions stated in this License. 133 | 134 | 5. Submission of Contributions. Unless You explicitly state otherwise, any 135 | Contribution intentionally submitted for inclusion in the Work by You to the 136 | Licensor shall be under the terms and conditions of this License, without any 137 | additional terms or conditions. Notwithstanding the above, nothing herein shall 138 | supersede or modify the terms of any separate license agreement you may have 139 | executed with Licensor regarding such Contributions. 140 | 141 | 6. Trademarks. This License does not grant permission to use the trade names, 142 | trademarks, service marks, or product names of the Licensor, except as required 143 | for reasonable and customary use in describing the origin of the Work and 144 | reproducing the content of the NOTICE file. 145 | 146 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in 147 | writing, Licensor provides the Work (and each Contributor provides its 148 | Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 149 | KIND, either express or implied, including, without limitation, any warranties 150 | or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any risks 153 | associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, whether in 156 | tort (including negligence), contract, or otherwise, unless required by 157 | applicable law (such as deliberate and grossly negligent acts) or agreed to in 158 | writing, shall any Contributor be liable to You for damages, including any 159 | direct, indirect, special, incidental, or consequential damages of any 160 | character arising as a result of this License or out of the use or inability to 161 | use the Work (including but not limited to damages for loss of goodwill, work 162 | stoppage, computer failure or malfunction, or any and all other commercial 163 | damages or losses), even if such Contributor has been advised of the 164 | possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or 167 | Derivative Works thereof, You may choose to offer, and charge a fee for, 168 | acceptance of support, warranty, indemnity, or other liability obligations 169 | and/or rights consistent with this License. However, in accepting such 170 | obligations, You may act only on Your own behalf and on Your sole 171 | responsibility, not on behalf of any other Contributor, and only if You agree 172 | to indemnify, defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason of your 174 | accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright and related rights are licensed under the Solderpad Hardware 2 | # License, Version 0.51 (the "License"); you may not use this file except in 3 | # compliance with the License. You may obtain a copy of the License at 4 | # http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 5 | # or agreed to in writing, software, hardware and materials distributed under 6 | # this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 7 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 8 | # specific language governing permissions and limitations under the License. 9 | # 10 | # Authors: 11 | # - Thomas Benz 12 | 13 | # select IIS-internal tool commands if we run on IIS machines 14 | ifneq (,$(wildcard /etc/iis.version)) 15 | VSIM ?= questa-2022.3 vsim 16 | SYNOPSYS_DC ?= synopsys-2022.03 dcnxt_shell 17 | else 18 | VSIM ?= vsim 19 | SYNOPSYS_DC ?= dc_shell 20 | endif 21 | 22 | TBS ?= ace_ccu_top \ 23 | ace_ccu_top_sanity 24 | 25 | SIM_TARGETS := $(addsuffix .log,$(addprefix sim-,$(TBS))) 26 | 27 | 28 | .SHELL: bash 29 | 30 | .PHONY: help all sim_all clean 31 | 32 | 33 | help: 34 | @echo "" 35 | @echo "elab.log: elaborates all files using Synopsys DC" 36 | @echo "compile.log: compile files using Questasim" 37 | @echo "sim-#TB#.log: simulates a given testbench, available TBs are:" 38 | @echo "$(addprefix ###############-#,$(TBS))" | sed -e 's/ /\n/g' | sed -e 's/#/ /g' 39 | @echo "sim_all: simulates all available testbenches" 40 | @echo "" 41 | @echo "clean: cleans generated files" 42 | @echo "" 43 | 44 | 45 | all: compile.log elab.log sim_all 46 | 47 | 48 | sim_all: $(SIM_TARGETS) 49 | 50 | 51 | build: 52 | mkdir -p $@ 53 | 54 | 55 | elab.log: Bender.yml | build 56 | export SYNOPSYS_DC="$(SYNOPSYS_DC)"; cd build && ../scripts/synth.sh | tee ../$@ 57 | (! grep -n "Error:" $@) 58 | 59 | 60 | compile.log: Bender.yml | build 61 | export VSIM="$(VSIM)"; cd build && ../scripts/compile_vsim.sh | tee ../$@ 62 | (! grep -n "Error:" $@) 63 | 64 | 65 | sim-%.log: compile.log 66 | export VSIM="$(VSIM)"; cd build && ../scripts/run_vsim.sh --random-seed $* | tee ../$@ 67 | (! grep -n "Error:" $@) 68 | (! grep -n "Fatal:" $@) 69 | 70 | 71 | clean: 72 | rm -rf build 73 | rm -f *.log 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ACE SystemVerilog modules for cache coherent SoC design 2 | 3 | This repository provides modules to implement cache coherence SoC's. 4 | 5 | ## List of modules 6 | 7 | | Name | Description | Doc | 8 | |------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|--------------------------------| 9 | | [`ace_ccu_top`](src/ace_ccu_top.sv) | ACE interconnector, broadcasts snooping messages to the cache controllers and AXI transactions to the slave | [Doc](doc/ace_ccu_top.md) | 10 | 11 | ## License 12 | 13 | The ACE repository is released under Solderpad v0.51 (SHL-0.51) see [LICENSE](LICENSE) -------------------------------------------------------------------------------- /ace.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | 3 | name : planv::ace:0.0.1-pulp 4 | 5 | filesets: 6 | rtl: 7 | files: 8 | - include/axi/assign.svh : {is_include_file : true, include_path : include} 9 | - include/axi/typedef.svh : {is_include_file : true, include_path : include} 10 | # Source files grouped in levels. Files in level 0 have no dependencies on files in this 11 | # package. Files in level 1 only depend on files in level 0, files in level 2 on files in 12 | # levels 1 and 0, etc. Files within a level are ordered alphabetically. 13 | # Level 0 14 | - src/ace_pkg.sv 15 | - src/snoop_pkg.sv 16 | # Level 1 17 | - src/ace_intf.sv 18 | - src/snoop_intf.sv 19 | # Level 2 20 | - src/ace_trs_dec.sv 21 | - src/ccu_logic.sv 22 | # Level 3 23 | - src/ace_ccu_top.sv 24 | - src/axi_test.sv 25 | - src/ace_test.sv 26 | - src/snoop_test.sv 27 | file_type : systemVerilogSource 28 | depend : 29 | - ">=pulp-platform.org::axi:0.39.0-beta.2" 30 | benchs: 31 | files: 32 | - test/tb_ace_ccu_pkg.sv 33 | - test/tb_ace_ccu_top.sv 34 | file_type : systemVerilogSource 35 | depend : 36 | - ">=pulp-platform.org::common_verification:0.2.3" 37 | 38 | targets: 39 | default: 40 | filesets : [rtl] 41 | sim: &sim 42 | filesets : [rtl,benchs] 43 | description: Simulate the design 44 | toplevel: tb_ace_ccu_top 45 | sim_ace_ccu : { filesets : [rtl,benchs] , toplevel: tb_ace_ccu_top } 46 | -------------------------------------------------------------------------------- /doc/ace_ccu_top.md: -------------------------------------------------------------------------------- 1 | # ACE_CCU_TOP 2 | 3 | The coherence control unit (CCU) implements the ACE interconnector functions, which broadcasts the snooping transactions to all the cache controllers and forwards the AXI transactions to a single the AXI master. 4 | The number of ACE slave ports is configurable, but it doesn't scale well beyond 8. 5 | 6 | ![Block diagram of the CCU](images/ccu_top.drawio.svg "Block diagram of the CCU") 7 | 8 | The CCU consists of three main components: 9 | 10 | - AXI DEMUX 11 | - AXI MUX 12 | - CCU logic 13 | 14 | The AXI DEMUX is responsible for routing the incoming request from a master, with the route dependent on the transaction type. For shareable and cacheable types the incoming request is routed to CCU logic whereas all other type of transactions are routed directly to RAM via AXI MUX. The CCU logic component is responsible for maintaining the data coherency protocol. It communicates with the cache controllers to enforce the cache coherence protocol, ensuring that all caches have consistent copies of shared data. The CCU logic component handles data sharing and synchronization, guaranteeing the integrity of shared data in multiprocessor systems. The implementation details of CCU logic are given below. 15 | 16 | The AXI DEMUX and AXI MUX components are sourced from [PULP platform](https://github.com/pulp-platform/axi/). 17 | 18 | ## CCU logic 19 | 20 | The CCU Logic is responsible for translating the AXI requests into snoop requests. CCU logic is further composed of two main components: the AXI MUX and the CCU FSM as shown in diagram below. This AXI MUX, which has been extended to support the ACE protocol. It serializes incoming requests to the CCU from multiple AXI masters. Each request received by the AXI MUX is then passed to the CCU FSM (Finite State Machine) for further processing. The CCU FSM is responsible for managing the data coherence and sharing process. It controls the flow of requests and orchestrates the necessary actions to ensure data coherency among the caches using snoop ports. In case of data unavailability or invalidated dirty cache line, it forwards the request to memory using AXI port. 21 | 22 | ![ccu_logic](images/ccu_logic.drawio.svg "Block diagram of the CCU logix submodule") 23 | 24 | The CCU FSM implements the state transitions and control logic for handling read and write transactions in the coherence control unit. The breakdown of the different states and their corresponding functionality is as follows: 25 | 26 | ![ccu_fsm](images/ccu_fsm.drawio.svg "FSM of the CCU") 27 | 28 | - IDLE: 29 | - Waits for incoming valid AXI requests from the master. 30 | - Determines the transaction type (read or write) and transitions to the respective state. 31 | - Sets initiator flags so that snoop requests are not sent to the initiating master (to avoid deadlock) . 32 | 33 | - DECODE_R: 34 | - Checks the read transaction type. 35 | - If it's not a CleanUnique request, transitions to SEND_READ otherwise, transitions to SEND_INVALID_R. 36 | 37 | - DECODE_W: 38 | - Transitions to SEND_INVALID_W. 39 | 40 | - SEND_INVALID_R/W: 41 | - Sends snoop CleanInvalid requests to all the snooping masters i.e., cache controller 42 | - Asserts ac_valid for all snoop masters except initiating master and wait for them to de-assert ac_ready indicating that they have received a CleanInvalid request. 43 | - Transitions to WAIT_INVALID_R/W once all snoop masters are ready. 44 | 45 | - WAIT_INVALID_R: 46 | - Waits for all snoop masters to send snoop response with CR valid. 47 | - If data is available and dirty, transitions to SEND_AXI_REQ_WRITE_BACK_R/W otherwise, transitions to SEND_ACK_I_R. 48 | 49 | - WAIT_INVALID_W: 50 | - Waits for all snoop masters to send snoop response with CR valid. 51 | - If data is available and dirty, transitions to SEND_AXI_REQ_WRITE_BACK_W otherwise, transitions to SEND_AXI_REQ_W. 52 | 53 | - SEND_AXI_REQ_WRITE_BACK_R/W 54 | - Initiates an AXI write transaction (AW) to write back the dirty data in main memory. 55 | - Transitions to WRITE_BACK_MEM_R/W once aw_ready is asserted. 56 | 57 | - WRITE_BACK_MEM_R: 58 | - Sends dirty data via W channel of AXI to main memory 59 | - Transitions to SEND_ACK_I_R once data is written and b_valid is asserted by the main memory. 60 | 61 | - WRITE_BACK_MEM_W: 62 | - Sends dirty data via W channel of AXI to main memory 63 | - Transitions to SEND_AXI_REQ_W once data is written and b_valid is asserted by the main memory. 64 | 65 | - SEND_ACK_I_R: 66 | - Indicates to the initiating master that clean invalid operation is completed by sending r_valid 67 | - Transitions back to IDLE once r_ready is asserted. 68 | 69 | - SEND_READ: 70 | - Sends snoop ReadX requests to all the snooping masters 71 | - Asserts ac_valid for all snoop masters except initiating master and wait for them to de-assert ac_ready indicating that they have received a ReadX request. 72 | - Transitions to WAIT_RESP_R once all snoop masters have received the request. 73 | 74 | - WAIT_RESP_R: 75 | - Waits for all snoop masters to send snoop response with CR valid. 76 | - If data is available and there are no response errors, transitions to READ_SNP_DATA. Otherwise, transitions to SEND_AXI_REQ_R. 77 | 78 | - READ_SNP_DATA: 79 | - Waits for data to be available and checks for end-of-transmission conditions ( entire cache line is read i.e., 2 CD beats are received). 80 | - Transitions to IDLE once the end-of-transmission conditions are met. 81 | 82 | - SEND_AXI_REQ_R: 83 | - Sends data read request to main memory via AXI MUX and waits for the responding slave to assert ar_ready. 84 | - Transitions to READ_MEM once ar_ready is asserted. 85 | 86 | - READ_MEM: 87 | - Waits for the main memory to send back the data in R channel. 88 | - upon receiving the last data transitions to IDLE state. 89 | 90 | - SEND_AXI_REQ_W: 91 | - Initiates an AXI write transaction (AW) to write back the incoming data from initiating master to the main memory. 92 | - Transitions to WRITE_MEM once aw_ready is asserted. 93 | 94 | - WRITE_MEM: 95 | - Sends incoming data via W channel of AXI to main memory 96 | - Once data is written and b_valid is asserted by the main memory: 97 | - In case of ATOP, state transitions to READ_MEM to receive an extra R beat 98 | - otherwise state transitions to IDLE 99 | 100 | ## Known limitations and possible improvements 101 | 102 | - Serialization of the incoming transactions: it would in theory be possible to process multiple non-conflicting transactions in parallel. This would require the instantiation of multiple ccu\_logic modules and the logic to avoid them to target the same cacheline at the same time. It would also require the CPUs' cache controllers to be able to handle multiple requests at the same time. This would probably move the bottleneck from the CCU to the cache, which should be able to process an higher number of requests in parallel. 103 | 104 | - Serialization of the read operations towards the caches and shared memory: in the current implementation, a read to the shared memory is done only after failing to read a cacheline from another CPU. This situation could be improved by making the two requests in parallel: the new scenario has the drawback of increasing the traffic on the AXI port and of adding a sometimes unnecessary latency to the read transactions which hit data on a CPU's cache; the response to the initiator should be sent as soon as there's a valid data being transferred over the snoop port, and the response from the AXI should be discarded. 105 | 106 | - Serialization of the writeback in case of invalidation: in the current implementation, in case of CleanInvalid operations, the CCU takes care of the writeback of the dirty cachelines and terminates the transaction only once this is done. The writeback is necessary because otherwise, in case of 2 CPU invalidating each other's cacheline, the system can end up in a situation where the latest data get lost. Performance could be improved by decoupling the writeback from the termination of the transaction, so that the transaction can be finished without waiting for the writeback to be complete. By profiling the Splash-3 benchmarks it has been noticed that the time spent in executing CleanUnique/ReadUnique operations is a negligible fraction of the whole time, so this operation would bring limited benefits. -------------------------------------------------------------------------------- /doc/images/ccu_fsm.drawio: -------------------------------------------------------------------------------- 1 | 7Vxde6I6EP41XnYfPgUu/erWfWq7q3vW7rnpkwpVdpFYwK/++hM0CCQR0QLBPXslGUIMk3dm3gwDDbkz33z2wGI2gKblNCTB3DTkbkOSRFGQ0E8o2e4lelPdC6aebeJOsWBkv1tYKGDp0jYtP9UxgNAJ7EVaOIGua02ClAx4Hlynu71CJ/2vCzC1KMFoAhxaOrbNYIbvQhVi+Z1lT2fB4YbxmTmIOmOBPwMmXCdEcq8hdzwIg/3RfNOxnFB5kV72190eOXuYmGe5QZ4LVlt1/TA2BsM7YfoN/lr8++VucCPvR1kBZ4lvuCE1HTRe27RX6HAaHg4tYD66Eys6hf4jcfbIBaMZmpkZnXzxyO7kIDsVBdtI75aJlgE3oRfM4BS6wOnF0rYHl65phTcnoFbc5x7CBRKKSPjLCoItxhRYBhCJZsHcwWetjR08JY5/hkN9UnGru8Ej7xpb3KCVjtfBh0tvgucO1M/yYyDeju+EyXB+v3wRV9oNtoMAeFMryFgR3C+8/8Qf4CX9bMG5FXhb1AFb2I3wSVQkY3+RZzkgsFdp6AJsAdPDtYfhvkIb3UbcBb6++mhyKRRFffD/NSPDxPYsRpYQjbFXBL4qHggdJKYfi3YgPQOwKgXYjmMB9x/XfkMCHihy0Q09xdAJmz8j6ISNGEi71jYBq6cU4n4msMgLfUpO9FWANNUgkGaUhjSmyuS6+KRsTMT4S6EvBuMR/OXCEhMjIo2lLMwVh6XUCp+7nCrP5RTOX06xbssp8lrOrFkn4kC/e9+j19hxEFMM13I9swNrtAA7XawRWU2v1FH9rSwvsDaZd4zPymraYem4uY55YxOLZgnKqAglqUhjcLvqTeByYOaNWc1aAVOitD7qPXRpHjzstbpc4aqT8ZU3Xo0rx6uSE696rfCq5MRr/+FH677PF7KKloasJHOGbJNS3rjV/84y9tHXWhn7QU28NCfS0ak1eLwug9dzGrzILUK9yGNjsxLVgdKGC+X2ceS4vyPqxJ8Jn0q2HNtaH6hxJhcmtF3yEn9wQXeXtjwPbBMdFuHW1k+MTOyQFTlt1LIsJsFxsj+VMST6y3pmf3Swn/Gl224mOul41AUBCLWyArbDE7rn5Ak/tisvC7oLc/z+2FSfp+qk7zgj4fbty2ZPWHmxD/1aAihJPWQxXEy+IZTeA7OpW+up/zzsfXse8qUghDeRFZqC6CXpj5nQULg4kwvzO6WlizMZS764VySzuSgQqkIaWkozO7AZ+sf6Rw/5igqEP5rKRrjZrkfDTjcQfj9pU2AwMlypJ20CcOypuzvRfFuGDxHbv5Z+YL9uY0HkANbADnaL4C+gi8xdEl49ON+NEU7Dd0P0IqQgPPsXP7FDbiBIY90PPPjb6kAHekjiQje0oFfbcQhRdCcThFMLyduhU7EnwGnhE3PbNJ1jXiptkgU4KolAkypV56gyrTEBhX32iOHo6xUkjSqDJNPJ0wSDJ4U8x3tf+mAxl9fPyvCffBLAbTubNevkhqHXeez2aPMYczUOkTAOkcF/KjUNKbfi+BJH0quIFWb92IgTaH389SEp33DSh2i18iF0gK1vEpz0I4dSOW7mwLVSopr6GS0nrEWpVrimk+w1Ta9QoNZ4g5pvvchFPv6SVONFPJFBFGucHSD3cxGfOLbbJ5MD53UvOjeQuQJJwx72vzOoG+8tIWnYCvdoxSftdxXkLYpep8Mct2KwzHmfNodBb1Arc2Alwas1h6spYRCltOpYabmyVHf8wVnOxy9jxhsOFequSehOFgxGYk5jaa+sKgS+ebiEE65XFQITaeo5fIt3FUIU4a+lCiFL40mv2H7mHTwoK9Z1lhVLDCuWSvKBdPSgNeSarfBFPNSaOMD37UlaMWmjLm1bn+XCT9ZIqDnpTmIZVIYzjWSXvj0T4YCs+4lrEU68G0MPRRpXkxpqr5wiXrNhqjZnHeBlILrEzZfx4sXHvHre5y1/0Xc2+uia89pyOFkilcX0/iVxOKb2GGmIgiy3ulq7grLBWeiqieEqRA34AVDnmq2qEEjUiIFKNlrGdv9kjeg9eLGcNPLyl514lm+/g5fdeCFyMCVGg6vthtrNwhL+LgG+uHH4GsAZ5Sia8EkQZENQFNEI6W9a94gDGoaqarKha4Yoq+eiInrP9fibuYUtG/2xgRqQalnUUwpVBJ12qlVSapGugC7IqdYm+ZjlLE861QhGf71qweZJ73mLwl2taXiEp+KS3lcGPIkA3iFBUzzw2ovZshXA5Y23nrt3hq8K3TdmoWs9cwjM6deL5BnSicXMiwpqoGa1qKA5HrvmFf2CeUgL3Bc//Bk9fH3utr63uJIKjdyrqQxSoTBIhfJxUsHUJk29kox5x07/MF+f9b5u0tVnga8mNq0SH5aQcn4Jhy5VICmGXq1Nl8cwKvH0fygqNFXj6unpDPADRO29g/qzNj55nVLm+341wZ9Bluxdij9RIKMl+ci+ZADSSWA21eCdqiA/4qBEhW0VVECwmbtAae5/YbGsAshr2BtcgcWiZvxJ1H33+MOycu8/ -------------------------------------------------------------------------------- /doc/images/ccu_logic.drawio: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /doc/images/ccu_logic.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
AXI
(towards Xbar)
AXI...
FSM
FSM
master0
master0
master1
master1
master2
master2
master3
master3
AXI_MUX
AXI_MUX
4xsnoop
4xsnoop
Text is not SVG - cannot display
-------------------------------------------------------------------------------- /doc/images/ccu_top.drawio: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/images/ccu_top.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
master0
master0
AXI_DEMUX
AXI_DEMUX
master1
master1
AXI_DEMUX
AXI_DEMUX
master2
master2
AXI_DEMUX
AXI_DEMUX
master3
master3
AXI_DEMUX
AXI_DEMUX
slave
slave
AXI_MUX
AXI_MUX
4x snoop
4x snoop
CCU
logic
CCU...
Text is not SVG - cannot display
-------------------------------------------------------------------------------- /include/ace/typedef.svh: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 ETH Zurich, University of Bologna 2 | // Copyright (c) 2022 PlanV GmbH 3 | // 4 | // Copyright and related rights are licensed under the Solderpad Hardware 5 | // License, Version 0.51 (the "License"); you may not use this file except in 6 | // compliance with the License. You may obtain a copy of the License at 7 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 8 | // or agreed to in writing, software, hardware and materials distributed under 9 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | // specific language governing permissions and limitations under the License. 12 | // 13 | 14 | // Macros to define ACE Channel and Request/Response Structs 15 | 16 | `ifndef ACE_TYPEDEF_SVH_ 17 | `define ACE_TYPEDEF_SVH_ 18 | 19 | `include "axi/typedef.svh" 20 | 21 | //////////////////////////////////////////////////////////////////////////////////////////////////// 22 | // AXI4+ATOP Channel and Request/Response Structs (with snoop support) 23 | // 24 | // Usage Example: 25 | // `ACE_TYPEDEF_AW_CHAN_T(axi_aw_t, axi_addr_t, axi_id_t, axi_user_t) 26 | // `ACE_TYPEDEF_AR_CHAN_T(axi_ar_t, axi_addr_t, axi_id_t, axi_user_t) 27 | // `ACE_TYPEDEF_R_CHAN_T(axi_r_t, axi_data_t, axi_id_t, axi_user_t) 28 | // `ACE_TYPEDEF_REQ_T(axi_req_t, axi_aw_t, axi_w_t, axi_ar_t) 29 | // `ACE_TYPEDEF_RESP_T(axi_resp_t, axi_b_t, axi_r_t) 30 | `define ACE_TYPEDEF_AW_CHAN_T(aw_chan_t, addr_t, id_t, user_t) \ 31 | typedef struct packed { \ 32 | id_t id; \ 33 | addr_t addr; \ 34 | axi_pkg::len_t len; \ 35 | axi_pkg::size_t size; \ 36 | axi_pkg::burst_t burst; \ 37 | logic lock; \ 38 | axi_pkg::cache_t cache; \ 39 | axi_pkg::prot_t prot; \ 40 | axi_pkg::qos_t qos; \ 41 | axi_pkg::region_t region; \ 42 | axi_pkg::atop_t atop; \ 43 | user_t user; \ 44 | ace_pkg::awsnoop_t snoop; \ 45 | ace_pkg::bar_t bar; \ 46 | ace_pkg::domain_t domain; \ 47 | ace_pkg::awunique_t awunique; \ 48 | } aw_chan_t; 49 | `define ACE_TYPEDEF_AR_CHAN_T(ar_chan_t, addr_t, id_t, user_t) \ 50 | typedef struct packed { \ 51 | id_t id; \ 52 | addr_t addr; \ 53 | axi_pkg::len_t len; \ 54 | axi_pkg::size_t size; \ 55 | axi_pkg::burst_t burst; \ 56 | logic lock; \ 57 | axi_pkg::cache_t cache; \ 58 | axi_pkg::prot_t prot; \ 59 | axi_pkg::qos_t qos; \ 60 | axi_pkg::region_t region; \ 61 | user_t user; \ 62 | ace_pkg::arsnoop_t snoop; \ 63 | ace_pkg::bar_t bar; \ 64 | ace_pkg::domain_t domain; \ 65 | } ar_chan_t; 66 | `define ACE_TYPEDEF_R_CHAN_T(r_chan_t, data_t, id_t, user_t) \ 67 | typedef struct packed { \ 68 | id_t id; \ 69 | data_t data; \ 70 | ace_pkg::rresp_t resp; \ 71 | logic last; \ 72 | user_t user; \ 73 | } r_chan_t; 74 | `define ACE_TYPEDEF_REQ_T(req_t, aw_chan_t, w_chan_t, ar_chan_t) \ 75 | typedef struct packed { \ 76 | aw_chan_t aw; \ 77 | logic aw_valid; \ 78 | w_chan_t w; \ 79 | logic w_valid; \ 80 | logic b_ready; \ 81 | ar_chan_t ar; \ 82 | logic ar_valid; \ 83 | logic r_ready; \ 84 | logic wack; \ 85 | logic rack; \ 86 | } req_t; 87 | `define ACE_TYPEDEF_RESP_T(resp_t, b_chan_t, r_chan_t) \ 88 | typedef struct packed { \ 89 | logic aw_ready; \ 90 | logic ar_ready; \ 91 | logic w_ready; \ 92 | logic b_valid; \ 93 | b_chan_t b; \ 94 | logic r_valid; \ 95 | r_chan_t r; \ 96 | } resp_t; 97 | //////////////////////////////////////////////////////////////////////////////////////////////////// 98 | 99 | //////////////////////////////////////////////////////////////////////////////////////////////////// 100 | // All AXI4+ATOP Channels and Request/Response Structs in One Macro (with snoop support) 101 | // 102 | // This can be used whenever the user is not interested in "precise" control of the naming of the 103 | // individual channels. 104 | // 105 | // Usage Example: 106 | // `AXI_TYPEDEF_ALL(axi, addr_t, id_t, data_t, strb_t, user_t) 107 | // 108 | // This defines `axi_req_t` and `axi_resp_t` request/response structs as well as `axi_aw_chan_t`, 109 | // `axi_w_chan_t`, `axi_b_chan_t`, `axi_ar_chan_t`, and `axi_r_chan_t` channel structs. 110 | `define ACE_TYPEDEF_ALL(__name, __addr_t, __id_t, __data_t, __strb_t, __user_t) \ 111 | `ACE_TYPEDEF_AW_CHAN_T(__name``_aw_chan_t, __addr_t, __id_t, __user_t) \ 112 | `AXI_TYPEDEF_W_CHAN_T(__name``_w_chan_t, __data_t, __strb_t, __user_t) \ 113 | `AXI_TYPEDEF_B_CHAN_T(__name``_b_chan_t, __id_t, __user_t) \ 114 | `ACE_TYPEDEF_AR_CHAN_T(__name``_ar_chan_t, __addr_t, __id_t, __user_t) \ 115 | `ACE_TYPEDEF_R_CHAN_T(__name``_r_chan_t, __data_t, __id_t, __user_t) \ 116 | `ACE_TYPEDEF_REQ_T(__name``_req_t, __name``_aw_chan_t, __name``_w_chan_t, __name``_ar_chan_t) \ 117 | `ACE_TYPEDEF_RESP_T(__name``_resp_t, __name``_b_chan_t, __name``_r_chan_t) 118 | //////////////////////////////////////////////////////////////////////////////////////////////////// 119 | // Usage Example: 120 | // `SNOOP_TYPEDEF_AC_CHAN_T(snoop_ac_t, snoop_addr_t) 121 | // 'SNOOP_TYPEDEF_CD_CHAN_T(snoop_cd_t, snoop_data_t) 122 | // `SNOOP_TYPEDEF_REQ_T(snoop_req_t, snoop_ac_t) 123 | // `SNOOP_TYPEDEF_RESP_T(snoop_resp_t, snoop_cd_t, snoop_cr_t) 124 | `define SNOOP_TYPEDEF_AC_CHAN_T(ac_chan_t, addr_t) \ 125 | typedef struct packed { \ 126 | addr_t addr; \ 127 | snoop_pkg::acsnoop_t snoop; \ 128 | snoop_pkg::acprot_t prot; \ 129 | } ac_chan_t; 130 | `define SNOOP_TYPEDEF_CD_CHAN_T(cd_chan_t, data_t) \ 131 | typedef struct packed { \ 132 | data_t data; \ 133 | logic last; \ 134 | } cd_chan_t; 135 | `define SNOOP_TYPEDEF_CR_CHAN_T(cr_chan_t) \ 136 | typedef snoop_pkg::crresp_t cr_chan_t; 137 | `define SNOOP_TYPEDEF_REQ_T(req_t, ac_chan_t) \ 138 | typedef struct packed { \ 139 | logic ac_valid; \ 140 | logic cd_ready; \ 141 | ac_chan_t ac; \ 142 | logic cr_ready; \ 143 | } req_t; 144 | `define SNOOP_TYPEDEF_RESP_T(resp_t, cd_chan_t, cr_chan_t) \ 145 | typedef struct packed { \ 146 | logic ac_ready; \ 147 | logic cd_valid; \ 148 | cd_chan_t cd; \ 149 | logic cr_valid; \ 150 | cr_chan_t cr_resp; \ 151 | } resp_t; 152 | //////////////////////////////////////////////////////////////////////////////////////////////////// 153 | 154 | // Usage Example: 155 | // `SNOOP_TYPEDEF_ALL(snoop, addr_t, data_t) 156 | // 157 | // This defines `snoop_req_t` and `snoop_resp_t` request/response structs as well as `snoop_ac_chan_t`, 158 | // `snoop_cd_chan_t` and `snoop_cr_chan_t` channel structs. 159 | `define SNOOP_TYPEDEF_ALL(__name, __addr_t, __data_t) \ 160 | `SNOOP_TYPEDEF_AC_CHAN_T(__name``_aw_chan_t, __addr_t) \ 161 | `SNOOP_TYPEDEF_CR_CHAN_T(__name``_cr_chan_t) \ 162 | `SNOOP_TYPEDEF_REQ_T(__name``_req_t, __name``_ac_chan_t) \ 163 | `SNOOP_TYPEDEF_RESP_T(__name``_resp_t, __name``_cd_chan_t, __name``_cr_chan_t) 164 | //////////////////////////////////////////////////////////////////////////////////////////////////// 165 | 166 | `endif 167 | -------------------------------------------------------------------------------- /scripts/compile_vsim.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2014-2018 ETH Zurich, University of Bologna 3 | # 4 | # Copyright and related rights are licensed under the Solderpad Hardware 5 | # License, Version 0.51 (the "License"); you may not use this file except in 6 | # compliance with the License. You may obtain a copy of the License at 7 | # http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 8 | # or agreed to in writing, software, hardware and materials distributed under 9 | # this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | # specific language governing permissions and limitations under the License. 12 | # 13 | # Authors: 14 | # - Andreas Kurth 15 | # - Fabian Schuiki 16 | 17 | set -e 18 | 19 | [ ! -z "$VSIM" ] || VSIM=vsim 20 | 21 | bender script vsim -t test -t rtl \ 22 | --vlog-arg="-svinputport=compat" \ 23 | --vlog-arg="-override_timescale 1ns/1ps" \ 24 | --vlog-arg="-suppress 2583" \ 25 | > compile.tcl 26 | echo 'return 0' >> compile.tcl 27 | 28 | # Add `-lint -pendanticerrors` flags only for the files in this repository. 29 | # Patching the compile script in this way is quite ugly, maybe there should be a Bender command to 30 | # add arguments just for certain targets. 31 | for x in axi_pkg; do 32 | # Adapted from https://unix.stackexchange.com/a/200610. 33 | POSIXLY_CORRECT=1 awk -v N=6 " 34 | BEGIN{N--} 35 | NR > N { 36 | if (/.*src\/$x\.sv/) 37 | print \" -lint -pedanticerrors \\\\\" 38 | print l[NR % N] 39 | } 40 | {l[NR % N] = \$0} 41 | END{ 42 | for (i = NR > N ? NR - N + 1 : 1; i <= NR; i++) print l[i % N] 43 | }" < compile.tcl > compile.patched.tcl 44 | mv compile{.patched,}.tcl 45 | done 46 | 47 | $VSIM -c -do 'exit -code [source compile.tcl]' 48 | -------------------------------------------------------------------------------- /scripts/run_vsim.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Copyright (c) 2014-2018 ETH Zurich, University of Bologna 3 | # 4 | # Copyright and related rights are licensed under the Solderpad Hardware 5 | # License, Version 0.51 (the "License"); you may not use this file except in 6 | # compliance with the License. You may obtain a copy of the License at 7 | # http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 8 | # or agreed to in writing, software, hardware and materials distributed under 9 | # this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | # specific language governing permissions and limitations under the License. 12 | # 13 | # Authors: 14 | # - Andreas Kurth 15 | # - Fabian Schuiki 16 | 17 | set -euo pipefail 18 | ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) 19 | 20 | if test -z ${VSIM+x}; then 21 | VSIM=vsim 22 | fi 23 | 24 | # Seed values for `sv_seed`; can be extended with specific values on a per-TB basis, as well as with 25 | # a random number by passing the `--random` flag. The default value, 0, is always included to stay 26 | # regression-consistent. 27 | SEEDS=(0) 28 | 29 | call_vsim() { 30 | for seed in ${SEEDS[@]}; do 31 | echo "run -all" | $VSIM -sv_seed $seed "$@" | tee vsim.log 2>&1 32 | grep "Errors: 0," vsim.log 33 | done 34 | } 35 | 36 | exec_test() { 37 | if [ ! -e "$ROOT/test/tb_$1.sv" ]; then 38 | echo "Testbench for '$1' not found!" 39 | exit 1 40 | fi 41 | case "$1" in 42 | ace_ccu_top) 43 | for NumMst in 2 4 6; do 44 | for NumSlv in 1; do 45 | for Atop in 0 1 ; do 46 | for Exclusive in 0 1; do 47 | for UniqueIds in 0 1 ; do 48 | call_vsim tb_ace_ccu_top -gTbNumMst=$NumMst -gTbNumSlv=$NumSlv \ 49 | -gTbEnAtop=$Atop -gTbEnExcl=$Exclusive \ 50 | -gTbUniqueIds=$UniqueIds 51 | done 52 | done 53 | done 54 | done 55 | done 56 | ;; 57 | ace_ccu_top_sanity) 58 | for NumMst in 2; do 59 | for NumSlv in 1; do 60 | for Atop in 0; do 61 | for Exclusive in 0; do 62 | for UniqueIds in 0; do 63 | call_vsim tb_ace_ccu_top -gTbNumMst=$NumMst -gTbNumSlv=$NumSlv \ 64 | -gTbEnAtop=$Atop -gTbEnExcl=$Exclusive \ 65 | -gTbUniqueIds=$UniqueIds 66 | done 67 | done 68 | done 69 | done 70 | done 71 | ;; 72 | *) 73 | call_vsim tb_$1 -t 1ns -coverage -voptargs="+acc +cover=bcesfx" 74 | ;; 75 | esac 76 | } 77 | 78 | # Parse flags. 79 | PARAMS="" 80 | while (( "$#" )); do 81 | case "$1" in 82 | --random-seed) 83 | SEEDS+=(random) 84 | shift;; 85 | -*--*) # unsupported flag 86 | echo "Error: Unsupported flag '$1'." >&2 87 | exit 1;; 88 | *) # preserve positional arguments 89 | PARAMS="$PARAMS $1" 90 | shift;; 91 | esac 92 | done 93 | eval set -- "$PARAMS" 94 | 95 | if [ "$#" -eq 0 ]; then 96 | tests=() 97 | while IFS= read -r -d $'\0'; do 98 | tb_name="$(basename -s .sv $REPLY)" 99 | dut_name="${tb_name#tb_}" 100 | tests+=("$dut_name") 101 | done < <(find "$ROOT/test" -name 'tb_*.sv' -a \( ! -name '*_pkg.sv' \) -print0) 102 | else 103 | tests=("$@") 104 | fi 105 | 106 | for t in "${tests[@]}"; do 107 | exec_test $t 108 | done 109 | -------------------------------------------------------------------------------- /src/ace_ccu_top.sv: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2018 ETH Zurich, University of Bologna 2 | // Copyright (c) 2023 PlanV GmbH 3 | // 4 | // Copyright and related rights are licensed under the Solderpad Hardware 5 | // License, Version 0.51 (the "License"); you may not use this file except in 6 | // compliance with the License. You may obtain a copy of the License at 7 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 8 | // or agreed to in writing, software, hardware and materials distributed under 9 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | // specific language governing permissions and limitations under the License. 12 | 13 | // ace_ccu_top: Top level module for closely coupled cache coherency protocol 14 | `include "ace/assign.svh" 15 | `include "ace/typedef.svh" 16 | 17 | module ace_ccu_top 18 | import cf_math_pkg::idx_width; 19 | #( 20 | parameter ace_pkg::ccu_cfg_t Cfg = '0, 21 | parameter bit ATOPs = 1'b1, 22 | parameter type slv_aw_chan_t = logic, 23 | parameter type mst_aw_chan_t = logic, 24 | parameter type mst_stg_aw_chan_t = logic, 25 | parameter type w_chan_t = logic, 26 | parameter type slv_b_chan_t = logic, 27 | parameter type mst_b_chan_t = logic, 28 | parameter type mst_stg_b_chan_t = logic, 29 | parameter type slv_ar_chan_t = logic, 30 | parameter type mst_ar_chan_t = logic, 31 | parameter type mst_stg_ar_chan_t = logic, 32 | parameter type slv_r_chan_t = logic, 33 | parameter type mst_r_chan_t = logic, 34 | parameter type mst_stg_r_chan_t = logic, 35 | parameter type slv_req_t = logic, 36 | parameter type slv_resp_t = logic, 37 | parameter type mst_req_t = logic, 38 | parameter type mst_resp_t = logic, 39 | parameter type mst_stg_req_t = logic, 40 | parameter type mst_stg_resp_t = logic, 41 | parameter type snoop_req_t = logic, 42 | parameter type snoop_resp_t = logic 43 | 44 | ) ( 45 | input logic clk_i, 46 | input logic rst_ni, 47 | input logic test_i, 48 | input slv_req_t [Cfg.NoSlvPorts-1:0] slv_ports_req_i, 49 | output slv_resp_t [Cfg.NoSlvPorts-1:0] slv_ports_resp_o, 50 | output snoop_req_t [Cfg.NoSlvPorts-1:0] slv_snp_req_o, 51 | input snoop_resp_t [Cfg.NoSlvPorts-1:0] slv_snp_resp_i, 52 | output mst_req_t mst_ports_req_o, 53 | input mst_resp_t mst_ports_resp_i 54 | ); 55 | 56 | // signals from the ace_demuxes 57 | slv_req_t [Cfg.NoSlvPorts-1:0] [1:0] slv_reqs; // one for non-shareable and one for shareable req 58 | slv_resp_t [Cfg.NoSlvPorts-1:0] [1:0] slv_resps; 59 | // signals into the ace_muxes 60 | mst_stg_req_t [Cfg.NoSlvPorts:0] mst_reqs; // one extra port for CCU 61 | mst_stg_resp_t [Cfg.NoSlvPorts:0] mst_resps; 62 | mst_stg_req_t [Cfg.NoSlvPorts:0] mst_reqs_tmp; 63 | // signals into the CCU 64 | slv_req_t [Cfg.NoSlvPorts-1:0] ccu_reqs_i; 65 | slv_resp_t [Cfg.NoSlvPorts-1:0] ccu_resps_o; 66 | // signals from the CCU 67 | mst_stg_req_t ccu_reqs_mux_o; 68 | mst_stg_resp_t ccu_resps_mux_i; 69 | mst_stg_req_t ccu_reqs_o; 70 | mst_stg_resp_t ccu_resps_i; 71 | 72 | // selection lines for mux and demuxes 73 | logic [Cfg.NoSlvPorts-1:0] slv_aw_select, slv_ar_select; 74 | 75 | 76 | for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_slv_port_demux 77 | 78 | // routing of incoming request through transaction type 79 | ace_trs_dec #( 80 | .slv_ace_req_t ( slv_req_t ) 81 | ) i_ace_trs_dec ( 82 | .slv_reqs_i ( slv_ports_req_i[i] ), 83 | .snoop_aw_trs ( slv_aw_select[i] ), 84 | .snoop_ar_trs ( slv_ar_select[i] ) 85 | ); 86 | 87 | // demux 88 | axi_demux #( 89 | .AxiIdWidth ( Cfg.AxiIdWidthSlvPorts ), // ID Width 90 | .AtopSupport ( ATOPs ), 91 | .aw_chan_t ( slv_aw_chan_t ), // AW Channel Type 92 | .w_chan_t ( w_chan_t ), // W Channel Type 93 | .b_chan_t ( slv_b_chan_t ), // B Channel Type 94 | .ar_chan_t ( slv_ar_chan_t ), // AR Channel Type 95 | .r_chan_t ( slv_r_chan_t ), // R Channel Type 96 | .axi_req_t ( slv_req_t ), 97 | .axi_resp_t ( slv_resp_t ), 98 | .NoMstPorts ( 2 ), // one for CCU module and one for mux 99 | .MaxTrans ( Cfg.MaxMstTrans ), 100 | .AxiLookBits ( Cfg.AxiIdUsedSlvPorts ), 101 | .UniqueIds ( Cfg.UniqueIds ), 102 | //.FallThrough ( Cfg.FallThrough ), 103 | .SpillAw ( Cfg.LatencyMode[9] ), 104 | .SpillW ( Cfg.LatencyMode[8] ), 105 | .SpillB ( Cfg.LatencyMode[7] ), 106 | .SpillAr ( Cfg.LatencyMode[6] ), 107 | .SpillR ( Cfg.LatencyMode[5] ) 108 | ) i_axi_demux ( 109 | .clk_i, // Clock 110 | .rst_ni, // Asynchronous reset active low 111 | .test_i, // Testmode enable 112 | .slv_req_i ( slv_ports_req_i[i] ), 113 | .slv_aw_select_i ( slv_aw_select[i] ), 114 | .slv_ar_select_i ( slv_ar_select[i] ), 115 | .slv_resp_o ( slv_ports_resp_o[i] ), 116 | .mst_reqs_o ( slv_reqs[i] ), 117 | .mst_resps_i ( slv_resps[i] ) 118 | ); 119 | end 120 | 121 | axi_mux #( 122 | .SlvAxiIDWidth ( Cfg.AxiIdWidthSlvPorts+$clog2(Cfg.NoSlvPorts) ), // ID width of the slave ports 123 | .slv_aw_chan_t ( mst_stg_aw_chan_t ), // AW Channel Type, slave ports 124 | .mst_aw_chan_t ( mst_aw_chan_t ), // AW Channel Type, master port 125 | .w_chan_t ( w_chan_t ), // W Channel Type, all ports 126 | .slv_b_chan_t ( mst_stg_b_chan_t ), // B Channel Type, slave ports 127 | .mst_b_chan_t ( mst_b_chan_t ), // B Channel Type, master port 128 | .slv_ar_chan_t ( mst_stg_ar_chan_t ), // AR Channel Type, slave ports 129 | .mst_ar_chan_t ( mst_ar_chan_t ), // AR Channel Type, master port 130 | .slv_r_chan_t ( mst_stg_r_chan_t ), // R Channel Type, slave ports 131 | .mst_r_chan_t ( mst_r_chan_t ), // R Channel Type, master port 132 | .slv_req_t ( mst_stg_req_t ), 133 | .slv_resp_t ( mst_stg_resp_t ), 134 | .mst_req_t ( mst_req_t ), 135 | .mst_resp_t ( mst_resp_t ), 136 | .NoSlvPorts ( Cfg.NoSlvPorts + 1 ), // Number of Masters for the modules 137 | .MaxWTrans ( Cfg.MaxMstTrans ), 138 | .FallThrough ( Cfg.FallThrough ), 139 | .SpillAw ( Cfg.LatencyMode[4] ), 140 | .SpillW ( Cfg.LatencyMode[3] ), 141 | .SpillB ( Cfg.LatencyMode[2] ), 142 | .SpillAr ( Cfg.LatencyMode[1] ), 143 | .SpillR ( Cfg.LatencyMode[0] ) 144 | ) i_axi_mux ( 145 | .clk_i, // Clock 146 | .rst_ni, // Asynchronous reset active low 147 | .test_i, // Test Mode enable 148 | .slv_reqs_i ( mst_reqs ), 149 | .slv_resps_o ( mst_resps ), 150 | .mst_req_o ( mst_ports_req_o ), 151 | .mst_resp_i ( mst_ports_resp_i ) 152 | ); 153 | 154 | 155 | // connection reqs and resps for non-shareable transactions with axi_mux 156 | for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_non_shared_conn 157 | `ACE_ASSIGN_REQ_STRUCT(mst_reqs_tmp[i], slv_reqs[i][0]) 158 | `ACE_ASSIGN_RESP_STRUCT(slv_resps[i][0], mst_resps[i]) 159 | 160 | always_comb begin 161 | mst_reqs[i] = mst_reqs_tmp[i]; 162 | mst_reqs[i].aw.user[$clog2(Cfg.NoSlvPorts)-1:0] = i[$clog2(Cfg.NoSlvPorts)-1:0]; 163 | mst_reqs[i].ar.user[$clog2(Cfg.NoSlvPorts)-1:0] = i[$clog2(Cfg.NoSlvPorts)-1:0]; 164 | 165 | end 166 | end 167 | 168 | // connect CCU reqs and resps to mux 169 | always_comb begin 170 | mst_reqs[Cfg.NoSlvPorts] = mst_reqs_tmp[Cfg.NoSlvPorts]; 171 | mst_reqs[Cfg.NoSlvPorts].aw.user[$clog2(Cfg.NoSlvPorts)-1:0] = mst_reqs_tmp[Cfg.NoSlvPorts].aw.id[Cfg.AxiIdWidthSlvPorts +: $clog2(Cfg.NoSlvPorts)]; 172 | mst_reqs[Cfg.NoSlvPorts].ar.user[$clog2(Cfg.NoSlvPorts)-1:0] = mst_reqs_tmp[Cfg.NoSlvPorts].ar.id[Cfg.AxiIdWidthSlvPorts +: $clog2(Cfg.NoSlvPorts)]; 173 | end 174 | `ACE_ASSIGN_REQ_STRUCT(mst_reqs_tmp[Cfg.NoSlvPorts], ccu_reqs_o) 175 | `ACE_ASSIGN_RESP_STRUCT(ccu_resps_i, mst_resps[Cfg.NoSlvPorts]) 176 | 177 | // connection reqs and resps for shareable transactions with CCU 178 | for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_shared_conn 179 | `ACE_ASSIGN_REQ_STRUCT(ccu_reqs_i[i], slv_reqs[i][1]) 180 | `ACE_ASSIGN_RESP_STRUCT(slv_resps[i][1], ccu_resps_o[i]) 181 | end 182 | 183 | 184 | axi_mux #( 185 | .SlvAxiIDWidth ( Cfg.AxiIdWidthSlvPorts ), // ID width of the slave ports 186 | .slv_aw_chan_t ( slv_aw_chan_t ), // AW Channel Type, slave ports 187 | .mst_aw_chan_t ( mst_stg_aw_chan_t ), // AW Channel Type, master port 188 | .w_chan_t ( w_chan_t ), // W Channel Type, all ports 189 | .slv_b_chan_t ( slv_b_chan_t ), // B Channel Type, slave ports 190 | .mst_b_chan_t ( mst_stg_b_chan_t ), // B Channel Type, master port 191 | .slv_ar_chan_t ( slv_ar_chan_t ), // AR Channel Type, slave ports 192 | .mst_ar_chan_t ( mst_stg_ar_chan_t ), // AR Channel Type, master port 193 | .slv_r_chan_t ( slv_r_chan_t ), // R Channel Type, slave ports 194 | .mst_r_chan_t ( mst_stg_r_chan_t ), // R Channel Type, master port 195 | .slv_req_t ( slv_req_t ), 196 | .slv_resp_t ( slv_resp_t ), 197 | .mst_req_t ( mst_stg_req_t ), 198 | .mst_resp_t ( mst_stg_resp_t ), 199 | .NoSlvPorts ( Cfg.NoSlvPorts ), // Number of Masters for the modules 200 | .MaxWTrans ( Cfg.MaxMstTrans ), 201 | .FallThrough ( Cfg.FallThrough ), 202 | .SpillAw ( Cfg.LatencyMode[4] ), 203 | .SpillW ( Cfg.LatencyMode[3] ), 204 | .SpillB ( Cfg.LatencyMode[2] ), 205 | .SpillAr ( Cfg.LatencyMode[1] ), 206 | .SpillR ( Cfg.LatencyMode[0] ) 207 | ) i_ace_mux ( 208 | .clk_i, // Clock 209 | .rst_ni, // Asynchronous reset active low 210 | .test_i, // Test Mode enable 211 | .slv_reqs_i ( ccu_reqs_i ), 212 | .slv_resps_o ( ccu_resps_o ), 213 | .mst_req_o ( ccu_reqs_mux_o ), 214 | .mst_resp_i ( ccu_resps_mux_i ) 215 | ); 216 | 217 | ccu_fsm #( 218 | .DcacheLineWidth ( Cfg.DcacheLineWidth ), 219 | .AxiDataWidth ( Cfg.AxiDataWidth ), 220 | .NoMstPorts ( Cfg.NoSlvPorts ), 221 | .SlvAxiIDWidth ( Cfg.AxiIdWidthSlvPorts ), // ID width of the slave ports 222 | .mst_req_t ( mst_stg_req_t ), 223 | .mst_resp_t ( mst_stg_resp_t ), 224 | .snoop_req_t ( snoop_req_t ), 225 | .snoop_resp_t ( snoop_resp_t ) 226 | 227 | ) fsm ( 228 | .clk_i, 229 | .rst_ni, 230 | .ccu_req_i ( ccu_reqs_mux_o ), 231 | .ccu_resp_o ( ccu_resps_mux_i ), 232 | .ccu_req_o ( ccu_reqs_o ), 233 | .ccu_resp_i ( ccu_resps_i ), 234 | .s2m_req_o ( slv_snp_req_o ), 235 | .m2s_resp_i ( slv_snp_resp_i ) 236 | ); 237 | 238 | endmodule 239 | 240 | 241 | 242 | module ace_ccu_top_intf 243 | import cf_math_pkg::idx_width; 244 | #( 245 | parameter ace_pkg::ccu_cfg_t Cfg = '0, 246 | parameter bit ATOPS = 1'b1 247 | ) ( 248 | input logic clk_i, 249 | input logic rst_ni, 250 | input logic test_i, 251 | SNOOP_BUS.Slave snoop_ports [Cfg.NoSlvPorts-1:0], 252 | ACE_BUS.Slave slv_ports [Cfg.NoSlvPorts-1:0], 253 | AXI_BUS.Master mst_ports 254 | ); 255 | 256 | localparam int unsigned AxiIdWidthMstPortsStage = Cfg.AxiIdWidthSlvPorts +$clog2(Cfg.NoSlvPorts); 257 | localparam int unsigned AxiIdWidthMstPorts = AxiIdWidthMstPortsStage + $clog2(Cfg.NoSlvPorts+1); 258 | 259 | typedef logic [AxiIdWidthMstPortsStage-1:0] id_mst_stg_t; 260 | typedef logic [AxiIdWidthMstPorts -1:0] id_mst_t; 261 | typedef logic [Cfg.AxiIdWidthSlvPorts -1:0] id_slv_t; 262 | typedef logic [Cfg.AxiAddrWidth -1:0] addr_t; 263 | typedef logic [Cfg.AxiDataWidth -1:0] data_t; 264 | typedef logic [Cfg.AxiDataWidth/8 -1:0] strb_t; 265 | typedef logic [Cfg.AxiUserWidth -1:0] user_t; 266 | 267 | // snoop channel conversion 268 | `ACE_TYPEDEF_AW_CHAN_T(mst_ace_stg_aw_chan_t, addr_t, id_mst_stg_t, user_t) 269 | `ACE_TYPEDEF_AW_CHAN_T(mst_ace_aw_chan_t, addr_t, id_mst_t, user_t) 270 | `ACE_TYPEDEF_AW_CHAN_T(slv_ace_aw_chan_t, addr_t, id_slv_t, user_t) 271 | `ACE_TYPEDEF_AR_CHAN_T(mst_ace_stg_ar_chan_t, addr_t, id_mst_stg_t, user_t) 272 | `ACE_TYPEDEF_AR_CHAN_T(mst_ace_ar_chan_t, addr_t, id_mst_t, user_t) 273 | `ACE_TYPEDEF_AR_CHAN_T(slv_ace_ar_chan_t, addr_t, id_slv_t, user_t) 274 | `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t) 275 | `AXI_TYPEDEF_B_CHAN_T(mst_stg_b_chan_t, id_mst_stg_t, user_t) 276 | `AXI_TYPEDEF_B_CHAN_T(mst_b_chan_t, id_mst_t, user_t) 277 | `AXI_TYPEDEF_B_CHAN_T(slv_b_chan_t, id_slv_t, user_t) 278 | `ACE_TYPEDEF_R_CHAN_T(mst_ace_stg_r_chan_t, data_t, id_mst_stg_t, user_t) 279 | `ACE_TYPEDEF_R_CHAN_T(mst_ace_r_chan_t, data_t, id_mst_t, user_t) 280 | `ACE_TYPEDEF_R_CHAN_T(slv_ace_r_chan_t, data_t, id_slv_t, user_t) 281 | `ACE_TYPEDEF_REQ_T(mst_ace_stg_req_t, mst_ace_stg_aw_chan_t, w_chan_t, mst_ace_stg_ar_chan_t) 282 | `ACE_TYPEDEF_REQ_T(mst_ace_req_t, mst_ace_aw_chan_t, w_chan_t, mst_ace_ar_chan_t) 283 | `ACE_TYPEDEF_REQ_T(slv_ace_req_t, slv_ace_aw_chan_t, w_chan_t, slv_ace_ar_chan_t) 284 | `ACE_TYPEDEF_RESP_T(mst_ace_stg_resp_t, mst_stg_b_chan_t, mst_ace_stg_r_chan_t) 285 | `ACE_TYPEDEF_RESP_T(mst_ace_resp_t, mst_b_chan_t, mst_ace_r_chan_t) 286 | `ACE_TYPEDEF_RESP_T(slv_ace_resp_t, slv_b_chan_t, slv_ace_r_chan_t) 287 | `SNOOP_TYPEDEF_AC_CHAN_T(snoop_ac_t, addr_t) 288 | `SNOOP_TYPEDEF_CD_CHAN_T(snoop_cd_t, data_t) 289 | `SNOOP_TYPEDEF_CR_CHAN_T(snoop_cr_t) 290 | `SNOOP_TYPEDEF_REQ_T(snoop_req_t, snoop_ac_t) 291 | `SNOOP_TYPEDEF_RESP_T(snoop_resp_t, snoop_cd_t, snoop_cr_t) 292 | 293 | 294 | mst_ace_req_t mst_ace_reqs; 295 | mst_ace_resp_t mst_ace_resps; 296 | slv_ace_req_t [Cfg.NoSlvPorts-1:0] slv_ace_reqs; 297 | slv_ace_resp_t [Cfg.NoSlvPorts-1:0] slv_ace_resps; 298 | snoop_req_t [Cfg.NoSlvPorts-1:0] snoop_reqs; 299 | snoop_resp_t [Cfg.NoSlvPorts-1:0] snoop_resps; 300 | 301 | 302 | /// Assigning ACE request from CCU Mux to slave(RAM) 303 | `AXI_ASSIGN_FROM_REQ(mst_ports, mst_ace_reqs) 304 | /// Assigning AXI response from slave (RAM) to CCU mux which accepts only ACE type response 305 | `ACE_ASSIGN_TO_RESP(mst_ace_resps, mst_ports) 306 | 307 | 308 | for (genvar i = 0; i < Cfg.NoSlvPorts; i++) begin : gen_assign_slv 309 | `ACE_ASSIGN_TO_REQ(slv_ace_reqs[i], slv_ports[i]) 310 | `ACE_ASSIGN_FROM_RESP(slv_ports[i], slv_ace_resps[i]) 311 | /// Assigning SNOOP request from CCU logic to master 312 | `SNOOP_ASSIGN_FROM_REQ(snoop_ports[i], snoop_reqs[i]) 313 | /// Assigning SNOOP response from master to CCU logic 314 | `SNOOP_ASSIGN_TO_RESP(snoop_resps[i], snoop_ports[i]) 315 | end 316 | 317 | 318 | ace_ccu_top #( 319 | .Cfg ( Cfg ), 320 | .ATOPs ( ATOPS ), 321 | .slv_aw_chan_t ( slv_ace_aw_chan_t ), 322 | .mst_stg_aw_chan_t ( mst_ace_stg_aw_chan_t ), 323 | .mst_aw_chan_t ( mst_ace_aw_chan_t ), 324 | .w_chan_t ( w_chan_t ), 325 | .slv_b_chan_t ( slv_b_chan_t ), 326 | .mst_b_chan_t ( mst_b_chan_t ), 327 | .mst_stg_b_chan_t ( mst_stg_b_chan_t ), 328 | .slv_ar_chan_t ( slv_ace_ar_chan_t ), 329 | .mst_ar_chan_t ( mst_ace_ar_chan_t ), 330 | .mst_stg_ar_chan_t ( mst_ace_stg_ar_chan_t ), 331 | .slv_r_chan_t ( slv_ace_r_chan_t ), 332 | .mst_r_chan_t ( mst_ace_r_chan_t ), 333 | .mst_stg_r_chan_t ( mst_ace_stg_r_chan_t ), 334 | .slv_req_t ( slv_ace_req_t ), 335 | .slv_resp_t ( slv_ace_resp_t ), 336 | .mst_req_t ( mst_ace_req_t ), 337 | .mst_resp_t ( mst_ace_resp_t ), 338 | .mst_stg_req_t ( mst_ace_stg_req_t ), 339 | .mst_stg_resp_t ( mst_ace_stg_resp_t ), 340 | .snoop_req_t ( snoop_req_t ), 341 | .snoop_resp_t ( snoop_resp_t ) 342 | ) i_ccu_top ( 343 | .clk_i, 344 | .rst_ni, 345 | .test_i, 346 | .slv_ports_req_i ( slv_ace_reqs ), 347 | .slv_ports_resp_o ( slv_ace_resps ), 348 | .slv_snp_req_o ( snoop_reqs ), 349 | .slv_snp_resp_i ( snoop_resps ), 350 | .mst_ports_req_o ( mst_ace_reqs ), 351 | .mst_ports_resp_i ( mst_ace_resps ) 352 | ); 353 | 354 | endmodule 355 | -------------------------------------------------------------------------------- /src/ace_intf.sv: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2018 ETH Zurich, University of Bologna 2 | // Copyright (c) 2022 PlanV GmbH 3 | // 4 | // Copyright and related rights are licensed under the Solderpad Hardware 5 | // License, Version 0.51 (the "License"); you may not use this file except in 6 | // compliance with the License. You may obtain a copy of the License at 7 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 8 | // or agreed to in writing, software, hardware and materials distributed under 9 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | // specific language governing permissions and limitations under the License. 12 | 13 | 14 | // ACE bus interafces 15 | interface ACE_BUS #( 16 | parameter int unsigned AXI_ADDR_WIDTH = 0, 17 | parameter int unsigned AXI_DATA_WIDTH = 0, 18 | parameter int unsigned AXI_ID_WIDTH = 0, 19 | parameter int unsigned AXI_USER_WIDTH = 0 20 | ); 21 | 22 | localparam int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8; 23 | 24 | typedef logic [AXI_ID_WIDTH-1:0] id_t; 25 | typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; 26 | typedef logic [AXI_DATA_WIDTH-1:0] data_t; 27 | typedef logic [AXI_STRB_WIDTH-1:0] strb_t; 28 | typedef logic [AXI_USER_WIDTH-1:0] user_t; 29 | 30 | id_t aw_id; 31 | addr_t aw_addr; 32 | axi_pkg::len_t aw_len; 33 | axi_pkg::size_t aw_size; 34 | axi_pkg::burst_t aw_burst; 35 | logic aw_lock; 36 | axi_pkg::cache_t aw_cache; 37 | axi_pkg::prot_t aw_prot; 38 | axi_pkg::qos_t aw_qos; 39 | axi_pkg::region_t aw_region; 40 | axi_pkg::atop_t aw_atop; 41 | user_t aw_user; 42 | logic aw_valid; 43 | logic aw_ready; 44 | ace_pkg::awsnoop_t aw_snoop; 45 | ace_pkg::bar_t aw_bar; 46 | ace_pkg::domain_t aw_domain; 47 | ace_pkg::awunique_t aw_awunique; 48 | 49 | data_t w_data; 50 | strb_t w_strb; 51 | logic w_last; 52 | user_t w_user; 53 | logic w_valid; 54 | logic w_ready; 55 | 56 | id_t b_id; 57 | axi_pkg::resp_t b_resp; 58 | user_t b_user; 59 | logic b_valid; 60 | logic b_ready; 61 | 62 | id_t ar_id; 63 | addr_t ar_addr; 64 | axi_pkg::len_t ar_len; 65 | axi_pkg::size_t ar_size; 66 | axi_pkg::burst_t ar_burst; 67 | logic ar_lock; 68 | axi_pkg::cache_t ar_cache; 69 | axi_pkg::prot_t ar_prot; 70 | axi_pkg::qos_t ar_qos; 71 | axi_pkg::region_t ar_region; 72 | user_t ar_user; 73 | logic ar_valid; 74 | logic ar_ready; 75 | ace_pkg::arsnoop_t ar_snoop; 76 | ace_pkg::bar_t ar_bar; 77 | ace_pkg::domain_t ar_domain; 78 | 79 | id_t r_id; 80 | data_t r_data; 81 | ace_pkg::rresp_t r_resp; 82 | logic r_last; 83 | user_t r_user; 84 | logic r_valid; 85 | logic r_ready; 86 | 87 | logic wack; 88 | logic rack; 89 | 90 | modport Master ( 91 | output aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_snoop, aw_bar, aw_domain, aw_awunique, input aw_ready, 92 | output w_data, w_strb, w_last, w_user, w_valid, input w_ready, 93 | input b_id, b_resp, b_user, b_valid, output b_ready, 94 | output ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_snoop, ar_bar, ar_domain, input ar_ready, 95 | input r_id, r_data, r_resp, r_last, r_user, r_valid, output r_ready, 96 | output wack, rack 97 | ); 98 | 99 | modport Slave ( 100 | input aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_snoop, aw_bar, aw_domain, aw_awunique, output aw_ready, 101 | input w_data, w_strb, w_last, w_user, w_valid, output w_ready, 102 | output b_id, b_resp, b_user, b_valid, input b_ready, 103 | input ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_snoop, ar_bar, ar_domain, output ar_ready, 104 | output r_id, r_data, r_resp, r_last, r_user, r_valid, input r_ready, 105 | input wack, rack 106 | ); 107 | 108 | modport Monitor ( 109 | input aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_ready, aw_snoop, aw_bar, aw_domain, aw_awunique, 110 | w_data, w_strb, w_last, w_user, w_valid, w_ready, 111 | b_id, b_resp, b_user, b_valid, b_ready, 112 | ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_ready, ar_snoop, ar_bar, ar_domain, 113 | r_id, r_data, r_resp, r_last, r_user, r_valid, r_ready, 114 | wack, rack 115 | ); 116 | 117 | endinterface 118 | 119 | 120 | /// A clocked ACE interface for use in design verification. 121 | interface ACE_BUS_DV #( 122 | parameter int unsigned AXI_ADDR_WIDTH = 0, 123 | parameter int unsigned AXI_DATA_WIDTH = 0, 124 | parameter int unsigned AXI_ID_WIDTH = 0, 125 | parameter int unsigned AXI_USER_WIDTH = 0 126 | )( 127 | input logic clk_i 128 | ); 129 | 130 | localparam int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8; 131 | 132 | typedef logic [AXI_ID_WIDTH-1:0] id_t; 133 | typedef logic [AXI_ADDR_WIDTH-1:0] addr_t; 134 | typedef logic [AXI_DATA_WIDTH-1:0] data_t; 135 | typedef logic [AXI_STRB_WIDTH-1:0] strb_t; 136 | typedef logic [AXI_USER_WIDTH-1:0] user_t; 137 | 138 | id_t aw_id; 139 | addr_t aw_addr; 140 | axi_pkg::len_t aw_len; 141 | axi_pkg::size_t aw_size; 142 | axi_pkg::burst_t aw_burst; 143 | logic aw_lock; 144 | axi_pkg::cache_t aw_cache; 145 | axi_pkg::prot_t aw_prot; 146 | axi_pkg::qos_t aw_qos; 147 | axi_pkg::region_t aw_region; 148 | axi_pkg::atop_t aw_atop; 149 | user_t aw_user; 150 | logic aw_valid; 151 | logic aw_ready; 152 | ace_pkg::awsnoop_t aw_snoop; 153 | ace_pkg::bar_t aw_bar; 154 | ace_pkg::domain_t aw_domain; 155 | ace_pkg::awunique_t aw_awunique; 156 | 157 | data_t w_data; 158 | strb_t w_strb; 159 | logic w_last; 160 | user_t w_user; 161 | logic w_valid; 162 | logic w_ready; 163 | 164 | id_t b_id; 165 | axi_pkg::resp_t b_resp; 166 | user_t b_user; 167 | logic b_valid; 168 | logic b_ready; 169 | 170 | id_t ar_id; 171 | addr_t ar_addr; 172 | axi_pkg::len_t ar_len; 173 | axi_pkg::size_t ar_size; 174 | axi_pkg::burst_t ar_burst; 175 | logic ar_lock; 176 | axi_pkg::cache_t ar_cache; 177 | axi_pkg::prot_t ar_prot; 178 | axi_pkg::qos_t ar_qos; 179 | axi_pkg::region_t ar_region; 180 | user_t ar_user; 181 | logic ar_valid; 182 | logic ar_ready; 183 | ace_pkg::arsnoop_t ar_snoop; 184 | ace_pkg::bar_t ar_bar; 185 | ace_pkg::domain_t ar_domain; 186 | 187 | id_t r_id; 188 | data_t r_data; 189 | ace_pkg::rresp_t r_resp; 190 | logic r_last; 191 | user_t r_user; 192 | logic r_valid; 193 | logic r_ready; 194 | 195 | logic wack; 196 | logic rack; 197 | 198 | modport Master ( 199 | output aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_snoop, aw_bar, aw_domain, aw_awunique, input aw_ready, 200 | output w_data, w_strb, w_last, w_user, w_valid, input w_ready, 201 | input b_id, b_resp, b_user, b_valid, output b_ready, 202 | output ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_snoop, ar_bar,ar_domain, input ar_ready, 203 | input r_id, r_data, r_resp, r_last, r_user, r_valid, output r_ready, 204 | output wack, rack 205 | ); 206 | 207 | modport Slave ( 208 | input aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_snoop, aw_bar, aw_domain, aw_awunique, output aw_ready, 209 | input w_data, w_strb, w_last, w_user, w_valid, output w_ready, 210 | output b_id, b_resp, b_user, b_valid, input b_ready, 211 | input ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_snoop, ar_bar, ar_domain, output ar_ready, 212 | output r_id, r_data, r_resp, r_last, r_user, r_valid, input r_ready, 213 | input wack, rack 214 | ); 215 | 216 | modport Monitor ( 217 | input aw_id, aw_addr, aw_len, aw_size, aw_burst, aw_lock, aw_cache, aw_prot, aw_qos, aw_region, aw_atop, aw_user, aw_valid, aw_ready, aw_snoop, aw_bar, aw_domain, aw_awunique, 218 | w_data, w_strb, w_last, w_user, w_valid, w_ready, 219 | b_id, b_resp, b_user, b_valid, b_ready, 220 | ar_id, ar_addr, ar_len, ar_size, ar_burst, ar_lock, ar_cache, ar_prot, ar_qos, ar_region, ar_user, ar_valid, ar_ready, ar_snoop, ar_bar, ar_domain, 221 | r_id, r_data, r_resp, r_last, r_user, r_valid, r_ready, wack, rack 222 | ); 223 | 224 | // pragma translate_off 225 | `ifndef VERILATOR 226 | // Single-Channel Assertions: Signals including valid must not change between valid and handshake. 227 | // AW 228 | assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_id))); 229 | assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_addr))); 230 | assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_len))); 231 | assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_size))); 232 | assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_burst))); 233 | assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_lock))); 234 | assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_cache))); 235 | assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_prot))); 236 | assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_qos))); 237 | assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_region))); 238 | assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_atop))); 239 | assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> $stable(aw_user))); 240 | assert property (@(posedge clk_i) (aw_valid && !aw_ready |=> aw_valid)); 241 | // W 242 | assert property (@(posedge clk_i) ( w_valid && ! w_ready |=> $stable(w_data))); 243 | assert property (@(posedge clk_i) ( w_valid && ! w_ready |=> $stable(w_strb))); 244 | assert property (@(posedge clk_i) ( w_valid && ! w_ready |=> $stable(w_last))); 245 | assert property (@(posedge clk_i) ( w_valid && ! w_ready |=> $stable(w_user))); 246 | assert property (@(posedge clk_i) ( w_valid && ! w_ready |=> w_valid)); 247 | // B 248 | assert property (@(posedge clk_i) ( b_valid && ! b_ready |=> $stable(b_id))); 249 | assert property (@(posedge clk_i) ( b_valid && ! b_ready |=> $stable(b_resp))); 250 | assert property (@(posedge clk_i) ( b_valid && ! b_ready |=> $stable(b_user))); 251 | assert property (@(posedge clk_i) ( b_valid && ! b_ready |=> b_valid)); 252 | // AR 253 | assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_id))); 254 | assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_addr))); 255 | assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_len))); 256 | assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_size))); 257 | assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_burst))); 258 | assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_lock))); 259 | assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_cache))); 260 | assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_prot))); 261 | assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_qos))); 262 | assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_region))); 263 | assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> $stable(ar_user))); 264 | assert property (@(posedge clk_i) (ar_valid && !ar_ready |=> ar_valid)); 265 | // R 266 | assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> $stable(r_id))); 267 | assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> $stable(r_data))); 268 | assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> $stable(r_resp))); 269 | assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> $stable(r_last))); 270 | assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> $stable(r_user))); 271 | assert property (@(posedge clk_i) ( r_valid && ! r_ready |=> r_valid)); 272 | `endif 273 | // pragma translate_on 274 | 275 | endinterface 276 | -------------------------------------------------------------------------------- /src/ace_pkg.sv: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2018 ETH Zurich, University of Bologna 2 | // Copyright (c) 2022 PlanV GmbH 3 | // 4 | // Copyright and related rights are licensed under the Solderpad Hardware 5 | // License, Version 0.51 (the "License"); you may not use this file except in 6 | // compliance with the License. You may obtain a copy of the License at 7 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 8 | // or agreed to in writing, software, hardware and materials distributed under 9 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | // specific language governing permissions and limitations under the License. 12 | 13 | 14 | //! ACE Package 15 | /// Contains all necessary type definitions, constants, and generally useful functions. 16 | package ace_pkg; 17 | 18 | // Support for snoop channels 19 | typedef logic [3:0] arsnoop_t; 20 | typedef logic [2:0] awsnoop_t; 21 | typedef logic [1:0] bar_t; 22 | typedef logic [1:0] domain_t; 23 | typedef logic [0:0] awunique_t; 24 | typedef logic [3:0] rresp_t; 25 | 26 | /// Slice on Demux AW channel. 27 | localparam logic [9:0] DemuxAw = (1 << 9); 28 | /// Slice on Demux W channel. 29 | localparam logic [9:0] DemuxW = (1 << 8); 30 | /// Slice on Demux B channel. 31 | localparam logic [9:0] DemuxB = (1 << 7); 32 | /// Slice on Demux AR channel. 33 | localparam logic [9:0] DemuxAr = (1 << 6); 34 | /// Slice on Demux R channel. 35 | localparam logic [9:0] DemuxR = (1 << 5); 36 | /// Slice on Mux AW channel. 37 | localparam logic [9:0] MuxAw = (1 << 4); 38 | /// Slice on Mux W channel. 39 | localparam logic [9:0] MuxW = (1 << 3); 40 | /// Slice on Mux B channel. 41 | localparam logic [9:0] MuxB = (1 << 2); 42 | /// Slice on Mux AR channel. 43 | localparam logic [9:0] MuxAr = (1 << 1); 44 | /// Slice on Mux R channel. 45 | localparam logic [9:0] MuxR = (1 << 0); 46 | /// Latency configuration for `ace_xbar`. 47 | typedef enum logic [9:0] { 48 | NO_LATENCY = 10'b000_00_000_00, 49 | CUT_SLV_AX = DemuxAw | DemuxAr, 50 | CUT_MST_AX = MuxAw | MuxAr, 51 | CUT_ALL_AX = DemuxAw | DemuxAr | MuxAw | MuxAr, 52 | CUT_SLV_PORTS = DemuxAw | DemuxW | DemuxB | DemuxAr | DemuxR, 53 | CUT_MST_PORTS = MuxAw | MuxW | MuxB | MuxAr | MuxR, 54 | CUT_ALL_PORTS = 10'b111_11_111_11 55 | } ccu_latency_e; 56 | 57 | /// Configuration for `ace_ccu`. 58 | typedef struct packed { 59 | int unsigned NoSlvPorts; 60 | int unsigned MaxMstTrans; 61 | int unsigned MaxSlvTrans; 62 | bit FallThrough; 63 | ccu_latency_e LatencyMode; 64 | int unsigned AxiIdWidthSlvPorts; 65 | int unsigned AxiIdUsedSlvPorts; 66 | bit UniqueIds; 67 | int unsigned AxiAddrWidth; 68 | int unsigned AxiDataWidth; 69 | int unsigned AxiUserWidth; 70 | int unsigned DcacheLineWidth; 71 | } ccu_cfg_t; 72 | 73 | // transaction type 74 | typedef enum logic[2:0] { 75 | READ_NO_SNOOP, 76 | READ_ONCE, 77 | READ_SHARED, 78 | READ_UNIQUE, 79 | CLEAN_UNIQUE, 80 | WRITE_NO_SNOOP, 81 | WRITE_BACK, 82 | WRITE_UNIQUE 83 | } ace_trs_t; 84 | 85 | endpackage 86 | -------------------------------------------------------------------------------- /src/ace_trs_dec.sv: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 ETH Zurich and University of Bologna. 2 | // Copyright (c) 2022 PlanV GmbH 3 | // 4 | // Copyright and related rights are licensed under the Solderpad Hardware 5 | // License, Version 0.51 (the "License"); you may not use this file except in 6 | // compliance with the License. You may obtain a copy of the License at 7 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 8 | // or agreed to in writing, software, hardware and materials distributed under 9 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | // specific language governing permissions and limitations under the License. 12 | // 13 | 14 | module ace_trs_dec 15 | #( 16 | parameter type slv_ace_req_t = logic 17 | ) ( 18 | // incoming request from master 19 | input slv_ace_req_t slv_reqs_i, 20 | // Write transaction shareable 21 | output logic snoop_aw_trs, 22 | // Read transaction shareable 23 | output logic snoop_ar_trs 24 | ); 25 | 26 | /// Types of transactions bypassing CCU 27 | logic write_back, write_no_snoop, read_no_snoop; 28 | 29 | assign write_back = (slv_reqs_i.aw.snoop == 'b011) && (slv_reqs_i.aw.bar[0] == 'b0) && 30 | ((slv_reqs_i.aw.domain == 'b00) || (slv_reqs_i.aw.domain == 'b01) || 31 | (slv_reqs_i.aw.domain == 'b10)); 32 | 33 | assign write_no_snoop = (slv_reqs_i.aw.snoop == 'b000) && (slv_reqs_i.aw.bar[0] == 'b0) && 34 | ((slv_reqs_i.aw.domain == 'b00) || (slv_reqs_i.aw.domain == 'b11) ); 35 | assign read_no_snoop = (slv_reqs_i.ar.snoop == 'b0000) && (slv_reqs_i.ar.bar[0] =='b0) && 36 | ((slv_reqs_i.ar.domain == 'b00) || (slv_reqs_i.ar.domain == 'b11) ); 37 | 38 | assign snoop_aw_trs = ~(write_back | write_no_snoop); 39 | assign snoop_ar_trs = ~(read_no_snoop); 40 | 41 | endmodule 42 | -------------------------------------------------------------------------------- /src/ccu_fsm.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2022 ETH Zurich and University of Bologna. 2 | // Solderpad Hardware License, Version 0.51, see LICENSE for details. 3 | // SPDX-License-Identifier: SHL-0.51 4 | 5 | `include "ace/assign.svh" 6 | `include "ace/typedef.svh" 7 | 8 | module ccu_fsm 9 | #( 10 | parameter int unsigned DcacheLineWidth = 0, 11 | parameter int unsigned AxiDataWidth = 0, 12 | parameter int unsigned NoMstPorts = 4, 13 | parameter int unsigned SlvAxiIDWidth = 0, 14 | parameter type mst_req_t = logic, 15 | parameter type mst_resp_t = logic, 16 | parameter type snoop_req_t = logic, 17 | parameter type snoop_resp_t = logic 18 | ) ( 19 | //clock and reset 20 | input clk_i, 21 | input rst_ni, 22 | // CCU Request In and response out 23 | input mst_req_t ccu_req_i, 24 | output mst_resp_t ccu_resp_o, 25 | //CCU Request Out and response in 26 | output mst_req_t ccu_req_o, 27 | input mst_resp_t ccu_resp_i, 28 | // Snoop channel resuest and response 29 | output snoop_req_t [NoMstPorts-1:0] s2m_req_o, 30 | input snoop_resp_t [NoMstPorts-1:0] m2s_resp_i 31 | ); 32 | 33 | localparam int unsigned DcacheLineWords = DcacheLineWidth / AxiDataWidth; 34 | localparam int unsigned MstIdxBits = $clog2(NoMstPorts); 35 | 36 | enum logic [5:0] { 37 | IDLE, // 0 38 | DECODE_R, // 1 39 | SEND_INVALID_R, // 2 40 | WAIT_INVALID_R, // 3 41 | SEND_AXI_REQ_WRITE_BACK_R, // 4 42 | WRITE_BACK_MEM_R, // 5 43 | SEND_READ, // 6 44 | WAIT_RESP_R, // 7 45 | READ_SNP_DATA, // 8 46 | SEND_AXI_REQ_R, // 9 47 | READ_MEM, // 10 48 | DECODE_W, // 11 49 | SEND_INVALID_W, // 12 50 | WAIT_INVALID_W, // 13 51 | SEND_AXI_REQ_WRITE_BACK_W, // 14 52 | WRITE_BACK_MEM_W, // 15 53 | SEND_AXI_REQ_W, // 16 54 | WRITE_MEM // 17 55 | } state_d, state_q; 56 | 57 | 58 | // snoop resoponse valid 59 | logic [NoMstPorts-1:0] cr_valid; 60 | // snoop channel ac valid 61 | logic [NoMstPorts-1:0] ac_valid; 62 | // snoop channel ac ready 63 | logic [NoMstPorts-1:0] ac_ready; 64 | // snoop channel cd last 65 | logic [NoMstPorts-1:0] cd_last; 66 | // check for availablilty of data 67 | logic [NoMstPorts-1:0] data_available; 68 | // check for response error 69 | logic [NoMstPorts-1:0] response_error; 70 | // check for data received 71 | logic [NoMstPorts-1:0] data_received; 72 | // check for shared in cr_resp 73 | logic [NoMstPorts-1:0] shared; 74 | // check for dirty in cr_resp 75 | logic [NoMstPorts-1:0] dirty; 76 | // request holder 77 | mst_req_t ccu_req_holder; 78 | // response holder 79 | mst_resp_t ccu_resp_holder; 80 | // snoop response holder 81 | snoop_resp_t [NoMstPorts-1:0] m2s_resp_holder; 82 | // initiating master port 83 | logic [NoMstPorts-1:0] initiator_d, initiator_q; 84 | logic [MstIdxBits-1:0] first_responder; 85 | 86 | logic [DcacheLineWords-1:0][AxiDataWidth-1:0] cd_data; 87 | logic [$clog2(DcacheLineWords+1)-1:0] stored_cd_data; 88 | 89 | logic r_last; 90 | logic w_last; 91 | logic r_eot; 92 | logic w_eot; 93 | 94 | typedef struct packed { 95 | logic waiting_w; 96 | logic waiting_r; 97 | } prio_t; 98 | 99 | prio_t prio_d, prio_q; 100 | 101 | // ---------------------- 102 | // Current State Block 103 | // ---------------------- 104 | always_ff @(posedge clk_i, negedge rst_ni) begin : ccu_present_state 105 | if(!rst_ni) begin 106 | state_q <= IDLE; 107 | initiator_q <= '0; 108 | prio_q <= '0; 109 | end else begin 110 | state_q <= state_d; 111 | initiator_q <= initiator_d; 112 | prio_q <= prio_d; 113 | end 114 | end 115 | 116 | // ---------------------- 117 | // Next State Block 118 | // ---------------------- 119 | always_comb begin : ccu_state_ctrl 120 | 121 | state_d = state_q; 122 | initiator_d = initiator_q; 123 | prio_d = prio_q; 124 | 125 | case(state_q) 126 | 127 | IDLE: begin 128 | initiator_d = '0; 129 | prio_d = '0; 130 | // wait for incoming valid request from master 131 | if((ccu_req_i.ar_valid & !ccu_req_i.aw_valid) | 132 | (ccu_req_i.ar_valid & prio_q.waiting_r) | 133 | (ccu_req_i.ar_valid & !prio_q.waiting_w)) begin 134 | state_d = DECODE_R; 135 | initiator_d[ccu_req_i.ar.id[SlvAxiIDWidth+:MstIdxBits]] = 1'b1; 136 | prio_d.waiting_w = ccu_req_i.aw_valid; 137 | end else if((ccu_req_i.aw_valid & !ccu_req_i.ar_valid) | 138 | (ccu_req_i.aw_valid & prio_q.waiting_w)) begin 139 | state_d = DECODE_W; 140 | initiator_d[ccu_req_i.aw.id[SlvAxiIDWidth+:MstIdxBits]] = 1'b1; 141 | prio_d.waiting_r = ccu_req_i.ar_valid; 142 | end else begin 143 | state_d = IDLE; 144 | end 145 | end 146 | 147 | //--------------------- 148 | //---- Read Branch ---- 149 | //--------------------- 150 | DECODE_R: begin 151 | //check read transaction type 152 | if (ccu_req_holder.ar.snoop == snoop_pkg::CLEAN_UNIQUE) begin // check if CleanUnique then send Invalidate 153 | state_d = SEND_INVALID_R; 154 | end else if (ccu_req_holder.ar.lock) begin // AMO LR, invalidate 155 | state_d = SEND_INVALID_R; 156 | end else begin 157 | state_d = SEND_READ; 158 | end 159 | end 160 | 161 | SEND_INVALID_R: begin 162 | // wait for all snoop masters to assert AC ready 163 | if (ac_ready != '1) begin 164 | state_d = SEND_INVALID_R; 165 | end else begin 166 | state_d = WAIT_INVALID_R; 167 | end 168 | end 169 | 170 | WAIT_INVALID_R: begin 171 | // wait for all snoop masters to assert CR valid 172 | if ((cr_valid == '1) && (ccu_req_i.r_ready || ccu_req_holder.ar.lock)) begin 173 | if(|(data_available & ~response_error)) begin 174 | state_d = SEND_AXI_REQ_WRITE_BACK_R; 175 | end else begin 176 | if (ccu_req_holder.ar.lock) begin // AMO LR, read memory 177 | state_d = SEND_AXI_REQ_R; 178 | end else begin 179 | state_d = IDLE; 180 | end 181 | end 182 | end else begin 183 | state_d = WAIT_INVALID_R; 184 | end 185 | end 186 | 187 | SEND_AXI_REQ_WRITE_BACK_R: begin 188 | // wait for responding slave to assert aw_ready 189 | if(ccu_resp_i.aw_ready !='b1) begin 190 | state_d = SEND_AXI_REQ_WRITE_BACK_R; 191 | end else begin 192 | state_d = WRITE_BACK_MEM_R; 193 | end 194 | end 195 | 196 | WRITE_BACK_MEM_R: begin 197 | // wait for responding slave to send b_valid 198 | if((ccu_resp_i.b_valid && ccu_req_o.b_ready)) begin 199 | if (ccu_req_holder.ar.lock) begin // AMO LR, read memory 200 | state_d = SEND_AXI_REQ_R; 201 | end else begin 202 | state_d = IDLE; 203 | end 204 | end else begin 205 | state_d = WRITE_BACK_MEM_R; 206 | end 207 | end 208 | 209 | SEND_READ: begin 210 | // wait for all snoop masters to de-assert AC ready 211 | if (ac_ready != '1) begin 212 | state_d = SEND_READ; 213 | end else begin 214 | state_d = WAIT_RESP_R; 215 | end 216 | end 217 | 218 | WAIT_RESP_R: begin 219 | // wait for all snoop masters to assert CR valid 220 | if (cr_valid != '1) begin 221 | state_d = WAIT_RESP_R; 222 | end else if(|(data_available & ~response_error)) begin 223 | state_d = READ_SNP_DATA; 224 | end else begin 225 | state_d = SEND_AXI_REQ_R; 226 | end 227 | end 228 | 229 | READ_SNP_DATA: begin 230 | if(cd_last == data_available && (r_eot == 1'b1 || (ccu_req_i.r_ready == 1'b1 && r_last == 1'b1))) begin 231 | state_d = IDLE; 232 | end else begin 233 | state_d = READ_SNP_DATA; 234 | end 235 | end 236 | 237 | SEND_AXI_REQ_R: begin 238 | // wait for responding slave to assert ar_ready 239 | if(ccu_resp_i.ar_ready !='b1) begin 240 | state_d = SEND_AXI_REQ_R; 241 | end else begin 242 | state_d = READ_MEM; 243 | end 244 | end 245 | 246 | READ_MEM: begin 247 | // wait for responding slave to assert r_valid 248 | if(ccu_resp_i.r_valid && ccu_req_i.r_ready) begin 249 | if(ccu_resp_i.r.last) begin 250 | state_d = IDLE; 251 | end else begin 252 | state_d = READ_MEM; 253 | end 254 | end else begin 255 | state_d = READ_MEM; 256 | end 257 | end 258 | 259 | 260 | //--------------------- 261 | //---- Write Branch --- 262 | //--------------------- 263 | 264 | DECODE_W: begin 265 | state_d = SEND_INVALID_W; 266 | end 267 | 268 | SEND_INVALID_W: begin 269 | // wait for all snoop masters to assert AC ready 270 | if (ac_ready != '1) begin 271 | state_d = SEND_INVALID_W; 272 | end else begin 273 | state_d = WAIT_INVALID_W; 274 | end 275 | end 276 | 277 | WAIT_INVALID_W: begin 278 | // wait for all snoop masters to assert CR valid 279 | if (cr_valid != '1) begin 280 | state_d = WAIT_INVALID_W; 281 | end else if(|(data_available & ~response_error)) begin 282 | state_d = SEND_AXI_REQ_WRITE_BACK_W; 283 | end else begin 284 | state_d = SEND_AXI_REQ_W; 285 | end 286 | end 287 | 288 | SEND_AXI_REQ_WRITE_BACK_W: begin 289 | // wait for responding slave to assert aw_ready 290 | if(ccu_resp_i.aw_ready !='b1) begin 291 | state_d = SEND_AXI_REQ_WRITE_BACK_W; 292 | end else begin 293 | state_d = WRITE_BACK_MEM_W; 294 | end 295 | end 296 | 297 | WRITE_BACK_MEM_W: begin 298 | // wait for responding slave to send b_valid 299 | if((ccu_resp_i.b_valid && ccu_req_o.b_ready)) begin 300 | state_d = SEND_AXI_REQ_W; 301 | end else begin 302 | state_d = WRITE_BACK_MEM_W; 303 | end 304 | end 305 | 306 | SEND_AXI_REQ_W: begin 307 | // wait for responding slave to assert aw_ready 308 | if(ccu_resp_i.aw_ready !='b1) begin 309 | state_d = SEND_AXI_REQ_W; 310 | end else begin 311 | state_d = WRITE_MEM; 312 | end 313 | end 314 | 315 | WRITE_MEM: begin 316 | // wait for responding slave to send b_valid 317 | if((ccu_resp_i.b_valid && ccu_req_i.b_ready)) begin 318 | if(ccu_req_holder.aw.atop [5]) begin 319 | state_d = READ_MEM; 320 | end else begin 321 | state_d = IDLE; 322 | end 323 | end else begin 324 | state_d = WRITE_MEM; 325 | end 326 | end 327 | 328 | default: state_d = IDLE; 329 | 330 | 331 | endcase 332 | end 333 | 334 | // ---------------------- 335 | // Output Block 336 | // ---------------------- 337 | always_comb begin : ccu_output_block 338 | logic ar_addr_offset; 339 | 340 | ar_addr_offset = ccu_req_holder.ar.addr[3]; 341 | 342 | // Default Assignments 343 | ccu_req_o = '0; 344 | ccu_resp_o = '0; 345 | s2m_req_o = '0; 346 | 347 | case(state_q) 348 | IDLE: begin 349 | 350 | end 351 | 352 | //--------------------- 353 | //---- Read Branch ---- 354 | //--------------------- 355 | DECODE_R:begin 356 | ccu_resp_o.ar_ready = 'b1; 357 | end 358 | SEND_READ: begin 359 | // send request to snooping masters 360 | for (int unsigned n = 0; n < NoMstPorts; n = n + 1) begin 361 | s2m_req_o[n].ac.addr = ccu_req_holder.ar.addr; 362 | s2m_req_o[n].ac.prot = ccu_req_holder.ar.prot; 363 | s2m_req_o[n].ac.snoop = ccu_req_holder.ar.snoop; 364 | s2m_req_o[n].ac_valid = !ac_ready[n]; 365 | end 366 | end 367 | 368 | SEND_INVALID_R:begin 369 | for (int unsigned n = 0; n < NoMstPorts; n = n + 1) begin 370 | s2m_req_o[n].ac.addr = ccu_req_holder.ar.addr; 371 | s2m_req_o[n].ac.prot = ccu_req_holder.ar.prot; 372 | s2m_req_o[n].ac.snoop = snoop_pkg::CLEAN_INVALID; 373 | s2m_req_o[n].ac_valid = !ac_ready[n]; 374 | end 375 | end 376 | 377 | WAIT_RESP_R, WAIT_INVALID_W: begin 378 | for (int unsigned n = 0; n < NoMstPorts; n = n + 1) 379 | s2m_req_o[n].cr_ready = !cr_valid[n]; //'b1; 380 | end 381 | 382 | WAIT_INVALID_R: begin 383 | for (int unsigned n = 0; n < NoMstPorts; n = n + 1) 384 | s2m_req_o[n].cr_ready = !cr_valid[n]; //'b1; 385 | 386 | if ((cr_valid == '1) && (!ccu_req_holder.ar.lock)) begin 387 | ccu_resp_o.r = '0; 388 | ccu_resp_o.r.id = ccu_req_holder.ar.id; 389 | ccu_resp_o.r.last = 'b1; 390 | ccu_resp_o.r_valid = 'b1; 391 | end 392 | end 393 | 394 | READ_SNP_DATA: begin 395 | for (int unsigned n = 0; n < NoMstPorts; n = n + 1) 396 | s2m_req_o[n].cd_ready = !cd_last[n] & data_available[n]; 397 | // response to intiating master 398 | if (!r_eot) begin 399 | if (ccu_req_holder.ar.len == 0) begin 400 | // single data request 401 | logic critical_word_valid; 402 | critical_word_valid = (stored_cd_data == ar_addr_offset + 1); 403 | ccu_resp_o.r.data = cd_data[ar_addr_offset]; 404 | ccu_resp_o.r.last = critical_word_valid; 405 | ccu_resp_o.r_valid = critical_word_valid; 406 | end else begin 407 | // cache line request 408 | ccu_resp_o.r.data = cd_data[r_last]; 409 | ccu_resp_o.r.last = r_last; 410 | ccu_resp_o.r_valid = |stored_cd_data; 411 | end 412 | ccu_resp_o.r.id = ccu_req_holder.ar.id; 413 | ccu_resp_o.r.resp[3] = |shared; // update if shared 414 | ccu_resp_o.r.resp[2] = |dirty; // update if any line dirty 415 | end 416 | end 417 | 418 | SEND_AXI_REQ_WRITE_BACK_R: begin 419 | // send writeback request 420 | ccu_req_o.aw_valid = 'b1; 421 | ccu_req_o.aw = '0; //default 422 | ccu_req_o.aw.addr = ccu_req_holder.ar.addr; 423 | ccu_req_o.aw.addr[3:0] = 4'b0; // writeback is always full cache line 424 | ccu_req_o.aw.size = 2'b11; 425 | ccu_req_o.aw.burst = axi_pkg::BURST_INCR; // Use BURST_INCR for AXI regular transaction 426 | ccu_req_o.aw.id = {first_responder, ccu_req_holder.ar.id[SlvAxiIDWidth-1:0]}; // It should be visible this data originates from the responder, important e.g. for AMO operations 427 | ccu_req_o.aw.len = DcacheLineWords-1; 428 | // WRITEBACK 429 | ccu_req_o.aw.domain = 2'b00; 430 | ccu_req_o.aw.snoop = 3'b011; 431 | end 432 | 433 | WRITE_BACK_MEM_R: begin 434 | for (int unsigned n = 0; n < NoMstPorts; n = n + 1) 435 | s2m_req_o[n].cd_ready = !cd_last[n] & data_available[n]; 436 | // write data to slave (RAM) 437 | ccu_req_o.w_valid = |stored_cd_data; 438 | ccu_req_o.w.strb = '1; 439 | ccu_req_o.w.data = cd_data[w_last]; 440 | ccu_req_o.w.last = w_last; 441 | ccu_req_o.b_ready = 'b1; 442 | end 443 | 444 | SEND_AXI_REQ_R: begin 445 | // forward request to slave (RAM) 446 | ccu_req_o.ar_valid = 'b1; 447 | ccu_req_o.ar = ccu_req_holder.ar; 448 | ccu_req_o.r_ready = ccu_req_holder.r_ready ; 449 | end 450 | 451 | READ_MEM: begin 452 | // indicate slave to send data on r channel 453 | ccu_req_o.r_ready = ccu_req_i.r_ready ; 454 | ccu_resp_o.r = ccu_resp_i.r; 455 | ccu_resp_o.r_valid = ccu_resp_i.r_valid; 456 | end 457 | 458 | //--------------------- 459 | //---- Write Branch --- 460 | //--------------------- 461 | DECODE_W: begin 462 | ccu_resp_o.aw_ready = 'b1; 463 | end 464 | 465 | SEND_INVALID_W:begin 466 | for (int unsigned n = 0; n < NoMstPorts; n = n + 1) begin 467 | s2m_req_o[n].ac.addr = ccu_req_holder.aw.addr; 468 | s2m_req_o[n].ac.prot = ccu_req_holder.aw.prot; 469 | s2m_req_o[n].ac.snoop = snoop_pkg::CLEAN_INVALID; 470 | s2m_req_o[n].ac_valid = !ac_ready[n]; 471 | end 472 | end 473 | 474 | SEND_AXI_REQ_WRITE_BACK_W: begin 475 | // send writeback request 476 | ccu_req_o.aw_valid = 'b1; 477 | ccu_req_o.aw = '0; //default 478 | ccu_req_o.aw.addr = ccu_req_holder.aw.addr; 479 | ccu_req_o.aw.addr[3:0] = 4'b0; // writeback is always full cache line 480 | ccu_req_o.aw.size = 2'b11; 481 | ccu_req_o.aw.burst = axi_pkg::BURST_INCR; // Use BURST_INCR for AXI regular transaction 482 | ccu_req_o.aw.id = {first_responder, ccu_req_holder.aw.id[SlvAxiIDWidth-1:0]}; // It should be visible this data originates from the responder, important e.g. for AMO operations 483 | ccu_req_o.aw.len = DcacheLineWords-1; 484 | // WRITEBACK 485 | ccu_req_o.aw.domain = 2'b00; 486 | ccu_req_o.aw.snoop = 3'b011; 487 | end 488 | 489 | WRITE_BACK_MEM_W: begin 490 | for (int unsigned n = 0; n < NoMstPorts; n = n + 1) 491 | s2m_req_o[n].cd_ready = !cd_last[n] & data_available[n]; 492 | // response to intiating master 493 | if (!r_eot) begin 494 | ccu_req_o.w_valid = |stored_cd_data; 495 | ccu_req_o.w.strb = '1; 496 | ccu_req_o.w.data = cd_data[w_last]; 497 | ccu_req_o.w.last = w_last; 498 | ccu_req_o.b_ready = 'b1; 499 | end 500 | end 501 | 502 | SEND_AXI_REQ_W: begin 503 | // forward request to slave (RAM) 504 | ccu_req_o.aw_valid = 'b1; 505 | ccu_req_o.aw = ccu_req_holder.aw; 506 | end 507 | 508 | WRITE_MEM: begin 509 | ccu_req_o.w = ccu_req_i.w; 510 | ccu_req_o.w_valid = ccu_req_i.w_valid; 511 | ccu_req_o.b_ready = ccu_req_i.b_ready; 512 | 513 | ccu_resp_o.b = ccu_resp_i.b; 514 | ccu_resp_o.b_valid = ccu_resp_i.b_valid; 515 | ccu_resp_o.w_ready = ccu_resp_i.w_ready; 516 | end 517 | 518 | endcase 519 | end // end output block 520 | 521 | // Hold incoming ACE request 522 | always_ff @(posedge clk_i , negedge rst_ni) begin 523 | if(!rst_ni) begin 524 | ccu_req_holder <= '0; 525 | end else if(state_q == IDLE && 526 | ((ccu_req_i.ar_valid & !ccu_req_i.aw_valid) | 527 | (ccu_req_i.ar_valid & prio_q.waiting_r) | 528 | (ccu_req_i.ar_valid & !prio_q.waiting_w))) begin 529 | ccu_req_holder.ar <= ccu_req_i.ar; 530 | ccu_req_holder.ar_valid <= ccu_req_i.ar_valid; 531 | ccu_req_holder.r_ready <= ccu_req_i.r_ready; 532 | 533 | end else if(state_q == IDLE && 534 | ((ccu_req_i.aw_valid & !ccu_req_i.ar_valid) | 535 | (ccu_req_i.aw_valid & prio_q.waiting_w))) begin 536 | ccu_req_holder.aw <= ccu_req_i.aw; 537 | ccu_req_holder.aw_valid <= ccu_req_i.aw_valid; 538 | end 539 | end 540 | 541 | // Hold snoop AC_ready 542 | always_ff @ (posedge clk_i, negedge rst_ni) begin 543 | if(!rst_ni) begin 544 | ac_ready <= '0; 545 | ac_valid <= '0; 546 | end else if(state_q == DECODE_R || state_q == DECODE_W) begin 547 | ac_ready <= initiator_q; 548 | end else if(state_q == SEND_READ || state_q == SEND_INVALID_R || state_q == SEND_INVALID_W) begin 549 | for (int i = 0; i < NoMstPorts; i = i + 1) begin 550 | ac_ready[i] <= ac_ready[i] | (m2s_resp_i[i].ac_ready & s2m_req_o[i].ac_valid); 551 | ac_valid[i] <= ac_valid[i] | (m2s_resp_i[i].ac_ready & s2m_req_o[i].ac_valid); 552 | end 553 | end else begin 554 | ac_ready <= '0; 555 | ac_valid <= '0; 556 | end 557 | end 558 | 559 | // Hold snoop CR 560 | always_ff @ (posedge clk_i, negedge rst_ni) begin 561 | logic snoop_resp_found; 562 | if(!rst_ni) begin 563 | cr_valid <= '0; 564 | data_available <= '0; 565 | shared <= '0; 566 | dirty <= '0; 567 | response_error <= '0; 568 | first_responder <= '0; 569 | snoop_resp_found <= 1'b0; 570 | end else if(state_q == IDLE) begin 571 | cr_valid <= '0; 572 | data_available <= '0; 573 | shared <= '0; 574 | dirty <= '0; 575 | response_error <= '0; 576 | first_responder <= '0; 577 | snoop_resp_found <= 1'b0; 578 | end else if(state_q == SEND_READ || state_q == SEND_INVALID_R || state_q == SEND_INVALID_W) begin 579 | cr_valid <= initiator_q; 580 | end else begin 581 | for (int i = 0; i < NoMstPorts; i = i + 1) begin 582 | if(m2s_resp_i[i].cr_valid & s2m_req_o[i].cr_ready) begin 583 | cr_valid[i] <= cr_valid[i] | 1'b1; 584 | data_available[i] <= m2s_resp_i[i].cr_resp.dataTransfer; 585 | shared[i] <= m2s_resp_i[i].cr_resp.isShared; 586 | dirty[i] <= m2s_resp_i[i].cr_resp.passDirty; 587 | response_error[i] <= m2s_resp_i[i].cr_resp.error; 588 | end 589 | end 590 | if (!snoop_resp_found) begin 591 | for (int i = 0; i < NoMstPorts; i = i + 1) begin 592 | if(m2s_resp_i[i].cr_valid & s2m_req_o[i].cr_ready & m2s_resp_i[i].cr_resp.dataTransfer & !m2s_resp_i[i].cr_resp.error) begin 593 | first_responder <= i[MstIdxBits-1:0]; 594 | snoop_resp_found <= 1'b1; 595 | break; 596 | end 597 | end 598 | end 599 | end 600 | end 601 | 602 | // Hold snoop CD 603 | always_ff @ (posedge clk_i, negedge rst_ni) begin 604 | if(!rst_ni) begin 605 | data_received <= '0; 606 | cd_last <= '0; 607 | m2s_resp_holder <= '0; 608 | cd_data <= '0; 609 | stored_cd_data <= '0; 610 | end else begin 611 | if(state_q == IDLE) begin 612 | data_received <= '0; 613 | m2s_resp_holder <= '0; 614 | cd_last <= '0; 615 | cd_data <= '0; 616 | stored_cd_data <= '0; 617 | end 618 | else begin 619 | for (int i = 0; i < NoMstPorts; i = i + 1) begin 620 | if (state_q == READ_SNP_DATA) begin 621 | if(m2s_resp_i[i].cd_valid) begin 622 | data_received[i] <= m2s_resp_i[i].cd_valid; 623 | cd_last[i] <= cd_last[i] | (m2s_resp_i[i].cd.last & data_available[i]); 624 | m2s_resp_holder[i] <= m2s_resp_i[i]; 625 | end 626 | if (data_received[i] & ccu_resp_o.r_valid) begin 627 | data_received[i] <= '0; 628 | m2s_resp_holder <= '0; 629 | end 630 | if (m2s_resp_i[first_responder].cd_valid & s2m_req_o[first_responder].cd_ready) begin 631 | cd_data[m2s_resp_i[first_responder].cd.last] <= m2s_resp_i[first_responder].cd.data; 632 | end 633 | if (s2m_req_o[first_responder].cd_ready & m2s_resp_i[first_responder].cd_valid & !(ccu_resp_o.r_valid & ccu_req_i.r_ready)) begin 634 | stored_cd_data <= stored_cd_data + 1; 635 | end else if(ccu_resp_o.r_valid & ccu_req_i.r_ready & !(s2m_req_o[first_responder].cd_ready & m2s_resp_i[first_responder].cd_valid)) begin 636 | stored_cd_data <= stored_cd_data - 1; 637 | end 638 | end else if (state_q == WRITE_BACK_MEM_R || state_q == WRITE_BACK_MEM_W) begin 639 | if(m2s_resp_i[i].cd_valid) begin 640 | data_received[i] <= m2s_resp_i[i].cd_valid; 641 | cd_last[i] <= cd_last[i] | (m2s_resp_i[i].cd.last & data_available[i]); 642 | m2s_resp_holder[i] <= m2s_resp_i[i]; 643 | end 644 | if (data_received[i] & ccu_req_o.w_valid) begin 645 | data_received[i] <= '0; 646 | m2s_resp_holder <= '0; 647 | end 648 | if (m2s_resp_i[first_responder].cd_valid & s2m_req_o[first_responder].cd_ready) begin 649 | cd_data[m2s_resp_i[first_responder].cd.last] <= m2s_resp_i[first_responder].cd.data; 650 | end 651 | if (s2m_req_o[first_responder].cd_ready & m2s_resp_i[first_responder].cd_valid & !(ccu_req_o.w_valid & ccu_resp_i.w_ready)) begin 652 | stored_cd_data <= stored_cd_data + 1; 653 | end else if(ccu_req_o.w_valid & ccu_resp_i.w_ready & !(s2m_req_o[first_responder].cd_ready & m2s_resp_i[first_responder].cd_valid)) begin 654 | stored_cd_data <= stored_cd_data - 1; 655 | end 656 | end 657 | end 658 | end 659 | end 660 | end 661 | 662 | always_ff @ (posedge clk_i, negedge rst_ni) begin 663 | if(!rst_ni) begin 664 | r_last <= 1'b0; 665 | r_eot <= 1'b0; 666 | end else begin 667 | if(state_q == IDLE) begin 668 | r_last <= 1'b0; 669 | r_eot <= 1'b0; 670 | end else if (ccu_req_i.r_ready & ccu_resp_o.r_valid) begin 671 | r_last <= !r_last; 672 | if (ccu_resp_o.r.last) 673 | r_eot <= 1'b1; 674 | end 675 | end 676 | end 677 | 678 | always_ff @ (posedge clk_i, negedge rst_ni) begin 679 | if(!rst_ni) begin 680 | w_last <= 1'b0; 681 | w_eot <= 1'b0; 682 | end else begin 683 | if(state_q == IDLE) begin 684 | w_last <= 1'b0; 685 | w_eot <= 1'b0; 686 | end else if (ccu_resp_i.w_ready & ccu_req_o.w_valid) begin 687 | w_last <= !w_last; 688 | if (w_last) 689 | w_eot <= 1'b1; 690 | end 691 | end 692 | end 693 | 694 | `ifndef VERILATOR 695 | // pragma translate_off 696 | initial begin 697 | a_dcache_line_words : assert (DcacheLineWords == 2) else 698 | $error("The ccu_fsm module is currently hardcoded to only support DcacheLineWidth = 2 * AxiDataWidth"); 699 | end 700 | // pragma translate_on 701 | `endif 702 | 703 | 704 | 705 | endmodule 706 | -------------------------------------------------------------------------------- /src/snoop_intf.sv: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2018 ETH Zurich, University of Bologna 2 | // Copyright (c) 2022 PlanV GmbH 3 | // 4 | // Copyright and related rights are licensed under the Solderpad Hardware 5 | // License, Version 0.51 (the "License"); you may not use this file except in 6 | // compliance with the License. You may obtain a copy of the License at 7 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 8 | // or agreed to in writing, software, hardware and materials distributed under 9 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | // specific language governing permissions and limitations under the License. 12 | 13 | 14 | // Snoop bus interafces 15 | interface SNOOP_BUS #( 16 | parameter int unsigned SNOOP_ADDR_WIDTH = 0, 17 | parameter int unsigned SNOOP_DATA_WIDTH = 0 18 | ); 19 | 20 | typedef logic [SNOOP_ADDR_WIDTH-1:0] addr_t; 21 | typedef logic [SNOOP_DATA_WIDTH-1:0] data_t; 22 | 23 | addr_t ac_addr; 24 | snoop_pkg::acprot_t ac_prot; 25 | snoop_pkg::acsnoop_t ac_snoop; 26 | logic ac_valid; 27 | logic ac_ready; 28 | 29 | snoop_pkg::crresp_t cr_resp; 30 | logic cr_valid; 31 | logic cr_ready; 32 | 33 | data_t cd_data; 34 | logic cd_last; 35 | logic cd_valid; 36 | logic cd_ready; 37 | 38 | modport Master ( 39 | input ac_addr, ac_prot, ac_snoop, ac_valid, output ac_ready, 40 | input cr_ready, output cr_valid, cr_resp, 41 | input cd_ready, output cd_data, cd_last, cd_valid 42 | ); 43 | 44 | modport Slave ( 45 | output ac_addr, ac_prot, ac_snoop, ac_valid, input ac_ready, 46 | output cr_ready, input cr_valid, cr_resp, 47 | output cd_ready, input cd_data, cd_last, cd_valid 48 | ); 49 | 50 | 51 | modport Monitor ( 52 | input ac_addr, ac_prot, ac_snoop, ac_valid, ac_ready, 53 | cr_ready, cr_valid, cr_resp, 54 | cd_ready, cd_data, cd_last, cd_valid 55 | ); 56 | 57 | endinterface 58 | 59 | /// A clocked SNOOP interface for use in design verification. 60 | interface SNOOP_BUS_DV #( 61 | parameter int unsigned SNOOP_ADDR_WIDTH = 0, 62 | parameter int unsigned SNOOP_DATA_WIDTH = 0 63 | )( 64 | input clk_i 65 | ); 66 | 67 | typedef logic [SNOOP_ADDR_WIDTH-1:0] addr_t; 68 | typedef logic [SNOOP_DATA_WIDTH-1:0] data_t; 69 | 70 | addr_t ac_addr; 71 | snoop_pkg::acprot_t ac_prot; 72 | snoop_pkg::acsnoop_t ac_snoop; 73 | logic ac_valid; 74 | logic ac_ready; 75 | 76 | snoop_pkg::crresp_t cr_resp; 77 | logic cr_valid; 78 | logic cr_ready; 79 | 80 | data_t cd_data; 81 | logic cd_last; 82 | logic cd_valid; 83 | logic cd_ready; 84 | 85 | modport Master ( 86 | input ac_addr, ac_prot, ac_snoop, ac_valid, output ac_ready, 87 | input cr_ready, output cr_valid, cr_resp, 88 | input cd_ready, output cd_data, cd_last, cd_valid 89 | ); 90 | 91 | modport Slave ( 92 | output ac_addr, ac_prot, ac_snoop, ac_valid, input ac_ready, 93 | output cr_ready, input cr_valid, cr_resp, 94 | output cd_ready, input cd_data, cd_last, cd_valid 95 | ); 96 | 97 | 98 | modport Monitor ( 99 | input ac_addr, ac_prot, ac_snoop, ac_valid, ac_ready, 100 | cr_ready, cr_valid, cr_resp, 101 | cd_ready, cd_data, cd_last, cd_valid 102 | ); 103 | 104 | // pragma translate_off 105 | `ifndef VERILATOR 106 | // Single-Channel Assertions: Signals including valid must not change between valid and handshake. 107 | // AC 108 | assert property (@(posedge clk_i) (ac_valid && !ac_ready |=> $stable(ac_addr))); 109 | assert property (@(posedge clk_i) (ac_valid && !ac_ready |=> $stable(ac_snoop))); 110 | assert property (@(posedge clk_i) (ac_valid && !ac_ready |=> $stable(ac_prot))); 111 | assert property (@(posedge clk_i) (ac_valid && !ac_ready |=> ac_valid)); 112 | // CR 113 | assert property (@(posedge clk_i) (cr_valid && !cr_ready |=> $stable(cr_resp))); 114 | assert property (@(posedge clk_i) (cr_valid && !cr_ready |=> cr_valid)); 115 | // CD 116 | assert property (@(posedge clk_i) (cd_valid && !cd_ready |=> $stable(cd_data))); 117 | assert property (@(posedge clk_i) (cd_valid && !cd_ready |=> $stable(cd_last))); 118 | assert property (@(posedge clk_i) (cd_valid && !cd_ready |=> cd_valid)); 119 | `endif 120 | // pragma translate_on 121 | 122 | endinterface 123 | -------------------------------------------------------------------------------- /src/snoop_pkg.sv: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2018 ETH Zurich, University of Bologna 2 | // Copyright (c) 2022 PlanV GmbH 3 | // 4 | // Copyright and related rights are licensed under the Solderpad Hardware 5 | // License, Version 0.51 (the "License"); you may not use this file except in 6 | // compliance with the License. You may obtain a copy of the License at 7 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 8 | // or agreed to in writing, software, hardware and materials distributed under 9 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | // specific language governing permissions and limitations under the License. 12 | 13 | 14 | //! ACE Package 15 | /// Contains all necessary type definitions, constants, and generally useful functions. 16 | package snoop_pkg; 17 | 18 | // CRRESP 19 | typedef struct packed { 20 | logic wasUnique; 21 | logic isShared; 22 | logic passDirty; 23 | logic error; 24 | logic dataTransfer; 25 | } crresp_t; 26 | 27 | /// Support for snoop channels 28 | typedef logic [3:0] acsnoop_t; 29 | typedef logic [2:0] acprot_t; 30 | 31 | // AC snoop encoding 32 | localparam READ_ONCE = 4'b0000; 33 | localparam READ_SHARED = 4'b0001; 34 | localparam READ_CLEAN = 4'b0010; 35 | localparam READ_NOT_SHARED_DIRTY = 4'b0011; 36 | localparam READ_UNIQUE = 4'b0111; 37 | localparam CLEAN_SHARED = 4'b1000; 38 | localparam CLEAN_INVALID = 4'b1001; 39 | localparam CLEAN_UNIQUE = 4'b1011; 40 | localparam MAKE_INVALID = 4'b1101; 41 | localparam DVM_COMPLETE = 4'b1110; 42 | localparam DVM_MESSAGE = 4'b1111; 43 | 44 | endpackage 45 | -------------------------------------------------------------------------------- /src/snoop_test.sv: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014-2018 ETH Zurich, University of Bologna 2 | // Copyright (c) 2022 PlanV GmbH 3 | // 4 | // Copyright and related rights are licensed under the Solderpad Hardware 5 | // License, Version 0.51 (the "License"); you may not use this file except in 6 | // compliance with the License. You may obtain a copy of the License at 7 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 8 | // or agreed to in writing, software, hardware and materials distributed under 9 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | // specific language governing permissions and limitations under the License. 12 | // 13 | 14 | 15 | /// A set of testbench utilities for AXI interfaces. 16 | package snoop_test; 17 | 18 | import axi_pkg::*; 19 | import ace_pkg::*; 20 | 21 | /// The data transferred on a beat on the AC channel. 22 | class ace_ac_beat #( 23 | parameter AW = 32 24 | ); 25 | rand logic [AW-1:0] ac_addr = '0; 26 | logic [3:0] ac_snoop = '0; 27 | logic [2:0] ac_prot = '0; 28 | endclass 29 | 30 | /// The data transferred on a beat on the CR channel. 31 | class ace_cr_beat; 32 | snoop_pkg::crresp_t cr_resp = '0; 33 | endclass 34 | 35 | /// The data transferred on a beat on the CD channel. 36 | class ace_cd_beat #( 37 | parameter DW = 32 38 | ); 39 | rand logic [DW-1:0] cd_data = '0; 40 | logic cd_last; 41 | endclass 42 | 43 | class snoop_driver #( 44 | parameter AW = 32, 45 | parameter DW = 32, 46 | parameter time TA = 0ns , // stimuli application time 47 | parameter time TT = 0ns // stimuli test time 48 | ); 49 | virtual SNOOP_BUS_DV #( 50 | .SNOOP_ADDR_WIDTH(AW), 51 | .SNOOP_DATA_WIDTH(DW) 52 | ) snoop; 53 | 54 | typedef ace_ac_beat #(.AW(AW)) ace_ac_beat_t; 55 | typedef ace_cd_beat #(.DW(DW)) ace_cd_beat_t; 56 | typedef ace_cr_beat ace_cr_beat_t; 57 | 58 | function new( 59 | virtual SNOOP_BUS_DV #( 60 | .SNOOP_ADDR_WIDTH(AW), 61 | .SNOOP_DATA_WIDTH(DW) 62 | ) snoop 63 | ); 64 | this.snoop = snoop; 65 | endfunction 66 | 67 | function void reset_master(); 68 | snoop.ac_valid <= '0; 69 | snoop.ac_addr <= '0; 70 | snoop.ac_snoop <= '0; 71 | snoop.ac_prot <= '0; 72 | snoop.cr_ready <= '0; 73 | snoop.cd_ready <= '0; 74 | endfunction 75 | 76 | function void reset_slave(); 77 | snoop.ac_ready <= '0; 78 | snoop.cr_valid <= '0; 79 | snoop.cr_resp <= '0; 80 | snoop.cd_valid <= '0; 81 | snoop.cd_data <= '0; 82 | snoop.cd_last <= '0; 83 | endfunction 84 | 85 | task cycle_start; 86 | #TT; 87 | endtask 88 | 89 | task cycle_end; 90 | @(posedge snoop.clk_i); 91 | endtask 92 | 93 | /// Issue a beat on the AC channel. 94 | task send_ac ( 95 | input ace_ac_beat_t beat 96 | ); 97 | snoop.ac_valid <= #TA 1; 98 | snoop.ac_addr <= #TA beat.ac_addr; 99 | snoop.ac_snoop <= #TA beat.ac_snoop; 100 | snoop.ac_prot <= #TA beat.ac_prot; 101 | cycle_start(); 102 | while (snoop.ac_ready != 1) begin cycle_end(); cycle_start(); end 103 | cycle_end(); 104 | snoop.ac_valid <= #TA '0; 105 | snoop.ac_addr <= #TA '0; 106 | snoop.ac_snoop <= #TA '0; 107 | snoop.ac_prot <= #TA '0; 108 | endtask 109 | 110 | /// Issue a beat on the CR channel. 111 | task send_cr ( 112 | input ace_cr_beat_t beat 113 | ); 114 | snoop.cr_valid <= #TA 1; 115 | snoop.cr_resp <= #TA beat.cr_resp; 116 | cycle_start(); 117 | while (snoop.cr_ready != 1) begin cycle_end(); cycle_start(); end 118 | cycle_end(); 119 | snoop.cr_valid <= #TA '0; 120 | snoop.cr_resp <= #TA '0; 121 | endtask 122 | 123 | /// Issue a beat on the CD channel. 124 | task send_cd ( 125 | input ace_cd_beat_t beat 126 | ); 127 | snoop.cd_valid <= #TA 1; 128 | snoop.cd_data <= #TA beat.cd_data; 129 | snoop.cd_last <= #TA beat.cd_last; 130 | cycle_start(); 131 | while (snoop.cd_ready != 1) begin cycle_end(); cycle_start(); end 132 | cycle_end(); 133 | snoop.cd_valid <= #TA '0; 134 | snoop.cd_data <= #TA '0; 135 | snoop.cd_last <= #TA '0; 136 | endtask 137 | 138 | /// Wait for a beat on the AC channel. 139 | task recv_ac ( 140 | output ace_ac_beat_t beat 141 | ); 142 | snoop.ac_ready <= #TA 1; 143 | cycle_start(); 144 | while (snoop.ac_valid != 1) begin cycle_end(); cycle_start(); end 145 | beat = new; 146 | beat.ac_addr = snoop.ac_addr; 147 | beat.ac_snoop = snoop.ac_snoop; 148 | beat.ac_prot = snoop.ac_prot; 149 | cycle_end(); 150 | snoop.ac_ready <= #TA 0; 151 | endtask 152 | 153 | /// Wait for a beat on the CR channel. 154 | task recv_cr ( 155 | output ace_cr_beat_t beat 156 | ); 157 | snoop.cr_ready <= #TA 1; 158 | cycle_start(); 159 | while (snoop.cr_valid != 1) begin cycle_end(); cycle_start(); end 160 | beat = new; 161 | beat.cr_resp = snoop.cr_resp; 162 | cycle_end(); 163 | snoop.cr_ready <= #TA 0; 164 | endtask 165 | 166 | /// Wait for a beat on the CD channel. 167 | task recv_cd ( 168 | output ace_cd_beat_t beat 169 | ); 170 | beat = new; 171 | beat.cd_last = '0; 172 | while (!beat.cd_last) begin 173 | snoop.cd_ready <= #TA 1; 174 | cycle_start(); 175 | while (snoop.cd_valid != 1) begin cycle_end(); cycle_start(); end 176 | beat.cd_data = snoop.cd_data; 177 | beat.cd_last = snoop.cd_last; 178 | cycle_end(); 179 | snoop.cd_ready <= #TA 0; 180 | end 181 | endtask 182 | 183 | /// Monitor the AC channel and return the next beat. 184 | task mon_ac ( 185 | output ace_ac_beat_t beat 186 | ); 187 | cycle_start(); 188 | while (!(snoop.ac_valid && snoop.ac_ready)) begin cycle_end(); cycle_start(); end 189 | beat = new; 190 | beat.ac_addr = snoop.ac_addr; 191 | beat.ac_snoop = snoop.ac_snoop; 192 | beat.ac_prot = snoop.ac_prot; 193 | cycle_end(); 194 | endtask 195 | 196 | /// Monitor the CR channel and return the next beat. 197 | task mon_cr ( 198 | output ace_cr_beat_t beat 199 | ); 200 | cycle_start(); 201 | while (!(snoop.cr_valid && snoop.cr_ready)) begin cycle_end(); cycle_start(); end 202 | beat = new; 203 | beat.cr_resp = snoop.cr_resp; 204 | cycle_end(); 205 | endtask 206 | 207 | /// Monitor the CD channel and return the next beat. 208 | task mon_cd ( 209 | output ace_cd_beat_t beat 210 | ); 211 | cycle_start(); 212 | while (!(snoop.cd_valid && snoop.cd_ready)) begin cycle_end(); cycle_start(); end 213 | beat = new; 214 | beat.cd_data = snoop.cd_data; 215 | beat.cd_last = snoop.cd_last; 216 | cycle_end(); 217 | endtask 218 | 219 | endclass 220 | 221 | class snoop_rand_master #( 222 | // AXI interface parameters 223 | parameter int AW = 32, 224 | parameter int DW = 32, 225 | // Stimuli application and test time 226 | parameter time TA = 0ps, 227 | parameter time TT = 0ps, 228 | // Upper and lower bounds on wait cycles on AC, CR, and CD channels 229 | parameter int AC_MIN_WAIT_CYCLES = 0, 230 | parameter int AC_MAX_WAIT_CYCLES = 100, 231 | parameter int CR_MIN_WAIT_CYCLES = 0, 232 | parameter int CR_MAX_WAIT_CYCLES = 5, 233 | parameter int CD_MIN_WAIT_CYCLES = 0, 234 | parameter int CD_MAX_WAIT_CYCLES = 20 235 | ); 236 | typedef snoop_test::snoop_driver #( 237 | .AW(AW), .DW(DW), .TA(TA), .TT(TT) 238 | ) snoop_driver_t; 239 | typedef logic [AW-1:0] addr_t; 240 | typedef logic [DW-1:0] data_t; 241 | typedef snoop_pkg::acsnoop_t acsnoop_t; 242 | typedef snoop_pkg::acprot_t acprot_t; 243 | typedef snoop_pkg::crresp_t crresp_t; 244 | 245 | typedef snoop_driver_t::ace_ac_beat_t ace_ac_beat_t; 246 | typedef snoop_driver_t::ace_cr_beat_t ace_cr_beat_t; 247 | typedef snoop_driver_t::ace_cd_beat_t ace_cd_beat_t; 248 | 249 | snoop_driver_t drv; 250 | 251 | typedef struct packed { 252 | addr_t addr_begin; 253 | addr_t addr_end; 254 | mem_type_t mem_type; 255 | } mem_region_t; 256 | mem_region_t mem_map[$]; 257 | 258 | function new( 259 | virtual SNOOP_BUS_DV #( 260 | .SNOOP_ADDR_WIDTH(AW), 261 | .SNOOP_DATA_WIDTH(DW) 262 | ) snoop 263 | ); 264 | this.drv = new(snoop); 265 | this.reset(); 266 | endfunction 267 | 268 | function void reset(); 269 | drv.reset_master(); 270 | endfunction 271 | 272 | function void add_memory_region(input addr_t addr_begin, input addr_t addr_end, input mem_type_t mem_type); 273 | mem_map.push_back({addr_begin, addr_end, mem_type}); 274 | endfunction 275 | 276 | function ace_ac_beat_t new_rand_burst(); 277 | automatic logic rand_success; 278 | automatic ace_ac_beat_t ace_ac_beat = new; 279 | automatic addr_t addr; 280 | automatic snoop_pkg::acsnoop_t snoop; 281 | automatic snoop_pkg::acprot_t prot; 282 | automatic int unsigned mem_region_idx; 283 | automatic mem_region_t mem_region; 284 | 285 | // No memory regions defined 286 | if (mem_map.size() == 0) begin 287 | // Return a dummy region 288 | mem_region = '{ 289 | addr_begin: '0, 290 | addr_end: '1, 291 | mem_type: axi_pkg::NORMAL_NONCACHEABLE_BUFFERABLE 292 | }; 293 | end else begin 294 | // Randomly pick a memory region 295 | mem_region_idx = $urandom_range(0,mem_map.size()-1); 296 | // std::randomize(mem_region_idx) with { 297 | // mem_region_idx < mem_map.size(); 298 | // }; assert(rand_success); 299 | mem_region = mem_map[mem_region_idx]; 300 | end 301 | 302 | // Randomize address 303 | addr = mem_region.addr_begin + $urandom_range(mem_region.addr_end-mem_region.addr_begin+1); 304 | 305 | ace_ac_beat.ac_addr = addr; 306 | snoop = $urandom(); 307 | prot = $urandom(); 308 | 309 | // rand_success = std::randomize(id); assert(rand_success); 310 | // rand_success = std::randomize(qos); assert(rand_success); 311 | // The random ID *must* be legalized with `legalize_id()` before the beat is sent! This is 312 | // currently done in the functions `create_aws()` and `send_ars()`. 313 | ace_ac_beat.ac_snoop = snoop; 314 | ace_ac_beat.ac_prot = prot; 315 | 316 | return ace_ac_beat; 317 | endfunction 318 | 319 | // TODO: The `rand_wait` task exists in `rand_verif_pkg`, but that task cannot be called with 320 | // `this.drv.ace.clk_i` as `clk` argument. What is the syntax for getting an assignable 321 | // reference? 322 | task automatic rand_wait(input int unsigned min, max); 323 | int unsigned rand_success, cycles; 324 | cycles = $urandom_range(min,max); 325 | // rand_success = std::randomize(cycles) with { 326 | // cycles >= min; 327 | // cycles <= max; 328 | // }; 329 | //assert (rand_success) else $error("Failed to randomize wait cycles!"); 330 | repeat (cycles) @(posedge this.drv.snoop.clk_i); 331 | endtask 332 | 333 | task send_acs(input int n_reads); 334 | automatic logic rand_success; 335 | repeat (n_reads) begin 336 | automatic ace_ac_beat_t ace_ac_beat = new_rand_burst(); 337 | rand_wait(AC_MIN_WAIT_CYCLES, AC_MAX_WAIT_CYCLES); 338 | drv.send_ac(ace_ac_beat); 339 | end 340 | endtask 341 | 342 | task recv_crs(ref logic ac_done); 343 | while (!ac_done) begin 344 | automatic ace_cr_beat_t ace_cr_beat; 345 | automatic ace_cd_beat_t ace_cd_beat; 346 | rand_wait(CR_MIN_WAIT_CYCLES, CR_MAX_WAIT_CYCLES); 347 | drv.recv_cr(ace_cr_beat); 348 | if (!ace_cr_beat.cr_resp.error & ace_cr_beat.cr_resp.dataTransfer) 349 | drv.recv_cd(ace_cd_beat); 350 | end 351 | endtask 352 | 353 | task recv_cds(ref logic ac_done); 354 | while (!ac_done) begin 355 | automatic ace_cd_beat_t ace_cd_beat; 356 | rand_wait(CD_MIN_WAIT_CYCLES, CD_MAX_WAIT_CYCLES); 357 | drv.recv_cd(ace_cd_beat); 358 | end 359 | endtask 360 | 361 | // Issue n_reads random read transactions to an address range 362 | task run(input int n_reads); 363 | automatic logic ac_done = 1'b0; 364 | fork 365 | begin 366 | send_acs(n_reads); 367 | ac_done = 1'b1; 368 | end 369 | recv_crs(ac_done); 370 | join 371 | endtask 372 | 373 | endclass 374 | 375 | class snoop_rand_slave #( 376 | // AXI interface parameters 377 | parameter int AW = 32, 378 | parameter int DW = 32, 379 | // Stimuli application and test time 380 | parameter time TA = 0ps, 381 | parameter time TT = 0ps, 382 | parameter bit RAND_RESP = 0, 383 | // Upper and lower bounds on wait cycles on Ax, W, and resp (R and B) channels 384 | parameter int AC_MIN_WAIT_CYCLES = 0, 385 | parameter int AC_MAX_WAIT_CYCLES = 100, 386 | parameter int CR_MIN_WAIT_CYCLES = 0, 387 | parameter int CR_MAX_WAIT_CYCLES = 5, 388 | parameter int CD_MIN_WAIT_CYCLES = 0, 389 | parameter int CD_MAX_WAIT_CYCLES = 20 390 | ); 391 | typedef snoop_test::snoop_driver #( 392 | .AW(AW), .DW(DW), .TA(TA), .TT(TT) 393 | ) snoop_driver_t; 394 | typedef snoop_driver_t::ace_ac_beat_t ace_ac_beat_t; 395 | typedef snoop_driver_t::ace_cr_beat_t ace_cr_beat_t; 396 | typedef snoop_driver_t::ace_cd_beat_t ace_cd_beat_t; 397 | 398 | typedef logic [AW-1:0] addr_t; 399 | 400 | snoop_driver_t drv; 401 | ace_ac_beat_t ace_ac_queue[$]; 402 | int unsigned cd_wait_cnt; 403 | 404 | function new( 405 | virtual SNOOP_BUS_DV #( 406 | .SNOOP_ADDR_WIDTH(AW), 407 | .SNOOP_DATA_WIDTH(DW) 408 | ) snoop 409 | ); 410 | this.drv = new(snoop); 411 | this.cd_wait_cnt = 0; 412 | this.reset(); 413 | endfunction 414 | 415 | function void reset(); 416 | this.drv.reset_slave(); 417 | endfunction 418 | 419 | // TODO: The `rand_wait` task exists in `rand_verif_pkg`, but that task cannot be called with 420 | // `this.drv.ace.clk_i` as `clk` argument. What is the syntax getting an assignable reference? 421 | task automatic rand_wait(input int unsigned min, max); 422 | int unsigned rand_success, cycles; 423 | cycles = $urandom_range(min,max); 424 | // rand_success = std::randomize(cycles) with { 425 | // cycles >= min; 426 | // cycles <= max; 427 | // }; 428 | // assert (rand_success) else $error("Failed to randomize wait cycles!"); 429 | repeat (cycles) @(posedge this.drv.snoop.clk_i); 430 | endtask 431 | 432 | task recv_acs(); 433 | forever begin 434 | automatic ace_ac_beat_t ace_ac_beat; 435 | rand_wait(AC_MIN_WAIT_CYCLES, AC_MAX_WAIT_CYCLES); 436 | drv.recv_ac(ace_ac_beat); 437 | ace_ac_queue.push_back(ace_ac_beat); 438 | end 439 | endtask 440 | 441 | task send_crs(); 442 | forever begin 443 | automatic logic rand_success; 444 | automatic ace_ac_beat_t ace_ac_beat; 445 | automatic ace_cr_beat_t ace_cr_beat = new; 446 | wait (ace_ac_queue.size() > 0); 447 | ace_ac_beat = ace_ac_queue.pop_front(); 448 | if(ace_ac_beat.ac_snoop == snoop_pkg::CLEAN_INVALID) begin 449 | ace_cr_beat.cr_resp = 0; 450 | end else begin 451 | ace_cr_beat.cr_resp[4:2] = $urandom_range(0,3'b111);//$urandom_range(0,5'b11111); 452 | ace_cr_beat.cr_resp[1] = 'b0; 453 | ace_cr_beat.cr_resp[0] = $urandom_range(0,1); 454 | end 455 | rand_wait(CR_MIN_WAIT_CYCLES, CR_MAX_WAIT_CYCLES); 456 | drv.send_cr(ace_cr_beat); 457 | if (ace_cr_beat.cr_resp.dataTransfer && !ace_cr_beat.cr_resp.error) begin 458 | cd_wait_cnt++; 459 | end 460 | end 461 | endtask 462 | 463 | task send_cds(); 464 | forever begin 465 | automatic logic rand_success; 466 | automatic ace_ac_beat_t ace_ac_beat; 467 | automatic ace_cd_beat_t ace_cd_beat = new; 468 | automatic addr_t byte_addr; 469 | wait (cd_wait_cnt > 0); 470 | // random response 471 | ace_cd_beat.cd_data = $urandom(); 472 | ace_cd_beat.cd_last = 1'b0; 473 | rand_wait(CD_MIN_WAIT_CYCLES, CD_MAX_WAIT_CYCLES); 474 | drv.send_cd(ace_cd_beat); 475 | ace_cd_beat.cd_data = $urandom(); 476 | ace_cd_beat.cd_last = 1'b1; 477 | rand_wait(CD_MIN_WAIT_CYCLES, CD_MAX_WAIT_CYCLES); 478 | drv.send_cd(ace_cd_beat); 479 | cd_wait_cnt--; 480 | end 481 | endtask 482 | 483 | task run(); 484 | fork 485 | recv_acs(); 486 | send_crs(); 487 | send_cds(); 488 | join 489 | endtask 490 | 491 | endclass 492 | 493 | /// Snoop Monitor. 494 | class snoop_monitor #( 495 | parameter AW = 32, 496 | parameter DW = 32, 497 | parameter time TA = 0ns , // stimuli application time 498 | parameter time TT = 0ns // stimuli test time 499 | ); 500 | 501 | typedef snoop_test::snoop_driver #( 502 | .AW(AW), .DW(DW), .TA(TA), .TT(TT) 503 | ) snoop_driver_t; 504 | 505 | typedef snoop_driver_t::ace_ac_beat_t ace_ac_beat_t; 506 | typedef snoop_driver_t::ace_cd_beat_t ace_cd_beat_t; 507 | typedef snoop_driver_t::ace_cr_beat_t ace_cr_beat_t; 508 | 509 | snoop_driver_t drv; 510 | mailbox ac_mbx = new, cd_mbx = new, cr_mbx = new; 511 | 512 | virtual SNOOP_BUS_DV #( 513 | .SNOOP_ADDR_WIDTH(AW), 514 | .SNOOP_DATA_WIDTH(DW) 515 | ) snoop; 516 | 517 | function new( 518 | virtual SNOOP_BUS_DV #( 519 | .SNOOP_ADDR_WIDTH(AW), 520 | .SNOOP_DATA_WIDTH(DW) 521 | ) snoop 522 | ); 523 | this.drv = new(snoop); 524 | endfunction 525 | 526 | task monitor; 527 | fork 528 | // AC 529 | forever begin 530 | automatic ace_ac_beat_t beat; 531 | this.drv.mon_ac(beat); 532 | ac_mbx.put(beat); 533 | end 534 | // CR 535 | forever begin 536 | automatic ace_cr_beat_t beat; 537 | this.drv.mon_cr(beat); 538 | cr_mbx.put(beat); 539 | end 540 | // CD 541 | forever begin 542 | automatic ace_cd_beat_t beat; 543 | this.drv.mon_cd(beat); 544 | cd_mbx.put(beat); 545 | end 546 | join 547 | endtask 548 | endclass 549 | 550 | endpackage 551 | 552 | 553 | // non synthesisable ace snoop logger module 554 | // this module logs the activity of the input snoop channel 555 | // the log files will be found in "./ace_log//" 556 | // one log file for all writes 557 | // a log file per id for the reads 558 | // atomic transactions with read response are injected into the corresponding log file of the read 559 | module snoop_chan_logger #( 560 | parameter time TestTime = 8ns, // Time after clock, where sampling happens 561 | parameter string LoggerName = "snoop_logger", // name of the logger 562 | parameter type ac_chan_t = logic, // ACE AC type 563 | parameter type cr_chan_t = logic, // ACE CR type 564 | parameter type cd_chan_t = logic // ACE CD type 565 | ) ( 566 | input logic clk_i, // Clock 567 | input logic rst_ni, // Asynchronous reset active low, when `1'b0` no sampling 568 | input logic end_sim_i, // end of simulation 569 | // AC channel 570 | input ac_chan_t ac_chan_i, 571 | input logic ac_valid_i, 572 | input logic ac_ready_i, 573 | // CR channel 574 | input cr_chan_t cr_chan_i, 575 | input logic cr_valid_i, 576 | input logic cr_ready_i, 577 | // CD channel 578 | input cd_chan_t cd_chan_i, 579 | input logic cd_valid_i, 580 | input logic cd_ready_i 581 | ); 582 | 583 | // queues for writes and reads 584 | ac_chan_t ac_queues[$]; 585 | cr_chan_t cr_queues[$]; 586 | cd_chan_t cd_queues[$]; 587 | 588 | // channel sampling into queues 589 | always @(posedge clk_i) #TestTime begin : proc_channel_sample 590 | automatic ac_chan_t ac_beat; 591 | automatic int fd; 592 | automatic string log_file; 593 | automatic string log_str; 594 | // only execute when reset is high 595 | if (rst_ni) begin 596 | // AC channel 597 | if (ac_valid_i && ac_ready_i) begin 598 | log_file = $sformatf("./ace_log/%s/snoop_read.log", LoggerName); 599 | fd = $fopen(log_file, "a"); 600 | if (fd) begin 601 | log_str = $sformatf("%0t> AC, ADDR: 0x%h SNOOP %b, PROT %b", $time, ac_chan_i.addr, ac_chan_i.snoop, ac_chan_i.prot); 602 | $fdisplay(fd, log_str); 603 | $fclose(fd); 604 | end 605 | ac_beat.addr = ac_chan_i.addr; 606 | ac_beat.snoop = ac_chan_i.snoop; 607 | ac_beat.prot = ac_chan_i.prot; 608 | ac_queues.push_back(ac_beat); 609 | end 610 | // CR channel 611 | if (cr_valid_i && cr_ready_i) begin 612 | cr_queues.push_back(cr_chan_i); 613 | end 614 | // CD channel 615 | if (cd_valid_i && cd_ready_i) begin 616 | cd_queues.push_back(cd_chan_i); 617 | end 618 | end 619 | end 620 | 621 | initial begin : proc_log 622 | automatic string log_name; 623 | automatic string log_string; 624 | automatic ac_chan_t ac_beat; 625 | automatic cr_chan_t cr_beat; 626 | automatic cd_chan_t cd_beat; 627 | automatic int unsigned no_r_beat; 628 | automatic int fd; 629 | 630 | no_r_beat = 0; 631 | 632 | // make the log dirs 633 | log_name = $sformatf("mkdir -p ./ace_log/%s/", LoggerName); 634 | $system(log_name); 635 | 636 | // open log files 637 | log_name = $sformatf("./ace_log/%s/snoop_read.log", LoggerName); 638 | fd = $fopen(log_name, "w"); 639 | if (fd) begin 640 | $display("File was opened successfully : %s", log_name); 641 | $fclose(fd); 642 | end else 643 | $display("File was NOT opened successfully : %s", log_name); 644 | 645 | // on each clock cycle update the logs if there is something in the queues 646 | wait (rst_ni); 647 | while (!end_sim_i) begin 648 | @(posedge clk_i); 649 | 650 | // update the read log files 651 | while (ac_queues.size() != 0 && cr_queues.size() != 0) begin 652 | ac_beat = ac_queues.pop_front(); 653 | cr_beat = cr_queues.pop_front(); 654 | log_name = $sformatf("./ace_log/%s/snoop_read.log", LoggerName); 655 | fd = $fopen(log_name, "a"); 656 | if (fd) begin 657 | log_string = $sformatf("%0t ns> CR %d RESP: %b, ", 658 | $time, no_r_beat, cr_beat); 659 | $fdisplay(fd, log_string); 660 | if (cr_beat.dataTransfer && !cr_beat.error) begin 661 | while(cd_queues.size() != 0) begin 662 | cd_beat = cd_queues.pop_front(); 663 | log_string = $sformatf("%0t ns> CD %d DATA: %h, ", 664 | $time, no_r_beat, cd_beat.data); 665 | $fdisplay(fd, log_string); 666 | end 667 | end 668 | $fclose(fd); 669 | end 670 | no_r_beat++; 671 | end 672 | end 673 | $fclose(fd); 674 | end 675 | endmodule 676 | -------------------------------------------------------------------------------- /src_files.yml: -------------------------------------------------------------------------------- 1 | ace: 2 | vlog_opts: [ 3 | -L common_cells_lib 4 | ] 5 | incdirs: 6 | - include 7 | - ../../common_cells/include 8 | files: 9 | # Source files grouped in levels. Files in level 0 have no dependencies on files in this 10 | # package. Files in level 1 only depend on files in level 0, files in level 2 on files in 11 | # levels 1 and 0, etc. Files within a level are ordered alphabetically. 12 | # Level 0 13 | - src/ace_pkg.sv 14 | - src/snoop_pkg.sv 15 | # Level 1 16 | - src/ace_intf.sv 17 | - src/snoop_intf.sv 18 | # Level 2 19 | - src/ace_trs_dec.sv 20 | - src/ccu_fsm.sv 21 | # Level 3 22 | - src/ace_ccu_top.sv 23 | 24 | ace_sim: 25 | files: 26 | - src/ace_test.sv 27 | - src/snoop_test.sv 28 | flags: 29 | - skip_synthesis 30 | - only_local 31 | -------------------------------------------------------------------------------- /test/tb_ace_ccu_top.sv: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 ETH Zurich and University of Bologna. 2 | // Copyright (c) 2022 PlanV GmbH 3 | // 4 | // Copyright and related rights are licensed under the Solderpad Hardware 5 | // License, Version 0.51 (the "License"); you may not use this file except in 6 | // compliance with the License. You may obtain a copy of the License at 7 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 8 | // or agreed to in writing, software, hardware and materials distributed under 9 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | // specific language governing permissions and limitations under the License. 12 | // 13 | // Authors: 14 | // - Florian Zaruba 15 | // - Andreas Kurth 16 | 17 | // Directed Random Verification Testbench for `axi_xbar`: The crossbar is instantiated with 18 | // a number of random axi master and slave modules. Each random master executes a fixed number of 19 | // writes and reads over the whole addess map. All masters simultaneously issue transactions 20 | // through the crossbar, thereby saturating it. A monitor, which snoops the transactions of each 21 | // master and slave port and models the crossbar with a network of FIFOs, checks whether each 22 | // transaction follows the expected route. 23 | 24 | `include "ace/typedef.svh" 25 | `include "ace/assign.svh" 26 | 27 | module tb_ace_ccu_top #( 28 | parameter bit TbEnAtop = 1'b1, // enable atomic operations (ATOPs) 29 | parameter bit TbEnExcl = 1'b0, // enable exclusive accesses 30 | parameter bit TbUniqueIds = 1'b0, // restrict to only unique IDs 31 | parameter int unsigned TbNumMst = 32'd4, // how many AXI masters there are 32 | parameter int unsigned TbNumSlv = 32'd1 // how many AXI slaves there are 33 | ); 34 | // Random master no Transactions 35 | localparam int unsigned NoWrites = 80; // How many writes per master 36 | localparam int unsigned NoReads = 80; // How many reads per master 37 | // timing parameters 38 | localparam time CyclTime = 10ns; 39 | localparam time ApplTime = 2ns; 40 | localparam time TestTime = 8ns; 41 | 42 | // axi configuration 43 | localparam int unsigned AxiIdWidthMasters = 4; 44 | localparam int unsigned AxiIdUsed = 3; // Has to be <= AxiIdWidthMasters 45 | localparam int unsigned AxiIdWidthSlaves = AxiIdWidthMasters + $clog2(TbNumMst)+$clog2(TbNumMst+1); 46 | localparam int unsigned AxiAddrWidth = 32; // Axi Address Width 47 | localparam int unsigned AxiDataWidth = 64; // Axi Data Width 48 | localparam int unsigned AxiStrbWidth = AxiDataWidth / 8; 49 | localparam int unsigned AxiUserWidth = 5; 50 | 51 | // in the bench can change this variables which are set here freely 52 | localparam ace_pkg::ccu_cfg_t ccu_cfg = '{ 53 | NoSlvPorts: TbNumMst, 54 | MaxMstTrans: 10, 55 | MaxSlvTrans: 6, 56 | FallThrough: 1'b1, 57 | LatencyMode: ace_pkg::NO_LATENCY, 58 | AxiIdWidthSlvPorts: AxiIdWidthMasters, 59 | AxiIdUsedSlvPorts: AxiIdUsed, 60 | UniqueIds: TbUniqueIds, 61 | AxiAddrWidth: AxiAddrWidth, 62 | AxiDataWidth: AxiDataWidth 63 | }; 64 | 65 | 66 | typedef logic [AxiIdWidthMasters-1:0] id_mst_t; 67 | typedef logic [AxiIdWidthSlaves-1:0] id_slv_t; 68 | typedef logic [AxiAddrWidth-1:0] addr_t; 69 | typedef logic [AxiDataWidth-1:0] data_t; 70 | typedef logic [AxiStrbWidth-1:0] strb_t; 71 | typedef logic [AxiUserWidth-1:0] user_t; 72 | 73 | `ACE_TYPEDEF_AW_CHAN_T(aw_chan_mst_t, addr_t, id_mst_t, user_t) 74 | `AXI_TYPEDEF_AW_CHAN_T(aw_chan_slv_t, addr_t, id_slv_t, user_t) 75 | `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t) 76 | `AXI_TYPEDEF_B_CHAN_T(b_chan_mst_t, id_mst_t, user_t) 77 | `AXI_TYPEDEF_B_CHAN_T(b_chan_slv_t, id_slv_t, user_t) 78 | 79 | `ACE_TYPEDEF_AR_CHAN_T(ar_chan_mst_t, addr_t, id_mst_t, user_t) 80 | `AXI_TYPEDEF_AR_CHAN_T(ar_chan_slv_t, addr_t, id_slv_t, user_t) 81 | `ACE_TYPEDEF_R_CHAN_T(r_chan_mst_t, data_t, id_mst_t, user_t) 82 | `AXI_TYPEDEF_R_CHAN_T(r_chan_slv_t, data_t, id_slv_t, user_t) 83 | 84 | `ACE_TYPEDEF_REQ_T(mst_req_t, aw_chan_mst_t, w_chan_t, ar_chan_mst_t) 85 | `ACE_TYPEDEF_RESP_T(mst_resp_t, b_chan_mst_t, r_chan_mst_t) 86 | `AXI_TYPEDEF_REQ_T(slv_req_t, aw_chan_slv_t, w_chan_t, ar_chan_slv_t) 87 | `AXI_TYPEDEF_RESP_T(slv_resp_t, b_chan_slv_t, r_chan_slv_t) 88 | 89 | `SNOOP_TYPEDEF_AC_CHAN_T(snoop_ac_t, addr_t) 90 | `SNOOP_TYPEDEF_CD_CHAN_T(snoop_cd_t, data_t) 91 | `SNOOP_TYPEDEF_CR_CHAN_T(snoop_cr_t) 92 | `SNOOP_TYPEDEF_REQ_T(snoop_req_t, snoop_ac_t) 93 | `SNOOP_TYPEDEF_RESP_T(snoop_resp_t, snoop_cd_t, snoop_cr_t) 94 | 95 | 96 | typedef ace_test::ace_rand_master #( 97 | // AXI interface parameters 98 | .AW ( AxiAddrWidth ), 99 | .DW ( AxiDataWidth ), 100 | .IW ( AxiIdWidthMasters ), 101 | .UW ( AxiUserWidth ), 102 | // Stimuli application and test time 103 | .TA ( ApplTime ), 104 | .TT ( TestTime ), 105 | // Maximum number of read and write transactions in flight 106 | .MAX_READ_TXNS ( 20 ), 107 | .MAX_WRITE_TXNS ( 20 ), 108 | .AXI_EXCLS ( TbEnExcl ), 109 | .AXI_ATOPS ( TbEnAtop ), 110 | .UNIQUE_IDS ( TbUniqueIds ) 111 | ) ace_rand_master_t; 112 | typedef axi_test::axi_rand_slave #( 113 | // AXI interface parameters 114 | .AW ( AxiAddrWidth ), 115 | .DW ( AxiDataWidth ), 116 | .IW ( AxiIdWidthSlaves ), 117 | .UW ( AxiUserWidth ), 118 | // Stimuli application and test time 119 | .TA ( ApplTime ), 120 | .TT ( TestTime ) 121 | ) axi_rand_slave_t; 122 | 123 | typedef snoop_test::snoop_rand_slave #( 124 | // ADDR and Data interface parameters 125 | .AW ( AxiAddrWidth ), 126 | .DW ( AxiDataWidth ), 127 | // Stimuli application and test time 128 | .TA ( ApplTime), 129 | .TT ( TestTime), 130 | .RAND_RESP ( '0), 131 | // Upper and lower bounds on wait cycles on Ax, W, and resp (R and B) channels 132 | .AC_MIN_WAIT_CYCLES ( 2), 133 | .AC_MAX_WAIT_CYCLES ( 15), 134 | .CR_MIN_WAIT_CYCLES ( 2), 135 | .CR_MAX_WAIT_CYCLES ( 15), 136 | .CD_MIN_WAIT_CYCLES ( 2), 137 | .CD_MAX_WAIT_CYCLES ( 15) 138 | )snoop_rand_slave_t; 139 | // ------------- 140 | // DUT signals 141 | // ------------- 142 | logic clk; 143 | // DUT signals 144 | logic rst_n; 145 | logic [TbNumMst-1:0] end_of_sim; 146 | 147 | // master structs 148 | mst_req_t [TbNumMst-1:0] masters_req; 149 | mst_resp_t [TbNumMst-1:0] masters_resp; 150 | 151 | // slave structs 152 | slv_req_t [TbNumSlv-1:0] slaves_req; 153 | slv_resp_t [TbNumSlv-1:0] slaves_resp; 154 | 155 | // snoop structs 156 | snoop_req_t [TbNumMst-1:0] snoop_req; 157 | snoop_resp_t [TbNumMst-1:0] snoop_resp; 158 | 159 | 160 | // ------------------------------- 161 | // AXI Interfaces 162 | // ------------------------------- 163 | ACE_BUS #( 164 | .AXI_ADDR_WIDTH ( AxiAddrWidth ), 165 | .AXI_DATA_WIDTH ( AxiDataWidth ), 166 | .AXI_ID_WIDTH ( AxiIdWidthMasters ), 167 | .AXI_USER_WIDTH ( AxiUserWidth ) 168 | ) master [TbNumMst-1:0] (); 169 | ACE_BUS_DV #( 170 | .AXI_ADDR_WIDTH ( AxiAddrWidth ), 171 | .AXI_DATA_WIDTH ( AxiDataWidth ), 172 | .AXI_ID_WIDTH ( AxiIdWidthMasters ), 173 | .AXI_USER_WIDTH ( AxiUserWidth ) 174 | ) master_dv [TbNumMst-1:0] (clk); 175 | ACE_BUS_DV #( 176 | .AXI_ADDR_WIDTH ( AxiAddrWidth ), 177 | .AXI_DATA_WIDTH ( AxiDataWidth ), 178 | .AXI_ID_WIDTH ( AxiIdWidthMasters ), 179 | .AXI_USER_WIDTH ( AxiUserWidth ) 180 | ) master_monitor_dv [TbNumMst-1:0] (clk); 181 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_conn_dv_masters 182 | `ACE_ASSIGN (master[i], master_dv[i]) 183 | `ACE_ASSIGN_TO_REQ(masters_req[i], master[i]) 184 | `ACE_ASSIGN_TO_RESP(masters_resp[i], master[i]) 185 | end 186 | 187 | AXI_BUS #( 188 | .AXI_ADDR_WIDTH ( AxiAddrWidth ), 189 | .AXI_DATA_WIDTH ( AxiDataWidth ), 190 | .AXI_ID_WIDTH ( AxiIdWidthSlaves ), 191 | .AXI_USER_WIDTH ( AxiUserWidth ) 192 | ) slave [TbNumSlv-1:0] (); 193 | AXI_BUS_DV #( 194 | .AXI_ADDR_WIDTH ( AxiAddrWidth ), 195 | .AXI_DATA_WIDTH ( AxiDataWidth ), 196 | .AXI_ID_WIDTH ( AxiIdWidthSlaves ), 197 | .AXI_USER_WIDTH ( AxiUserWidth ) 198 | ) slave_dv [TbNumSlv-1:0](clk); 199 | AXI_BUS_DV #( 200 | .AXI_ADDR_WIDTH ( AxiAddrWidth ), 201 | .AXI_DATA_WIDTH ( AxiDataWidth ), 202 | .AXI_ID_WIDTH ( AxiIdWidthSlaves ), 203 | .AXI_USER_WIDTH ( AxiUserWidth ) 204 | ) slave_monitor_dv [TbNumSlv-1:0](clk); 205 | for (genvar i = 0; i < TbNumSlv; i++) begin : gen_conn_dv_slaves 206 | `AXI_ASSIGN(slave_dv[i], slave[i]) 207 | `AXI_ASSIGN_TO_REQ(slaves_req[i], slave[i]) 208 | `AXI_ASSIGN_TO_RESP(slaves_resp[i], slave[i]) 209 | end 210 | 211 | SNOOP_BUS #( 212 | .SNOOP_ADDR_WIDTH ( AxiAddrWidth ), 213 | .SNOOP_DATA_WIDTH ( AxiDataWidth ) 214 | ) snoop [TbNumMst-1:0] (); 215 | SNOOP_BUS_DV #( 216 | .SNOOP_ADDR_WIDTH ( AxiAddrWidth ), 217 | .SNOOP_DATA_WIDTH ( AxiDataWidth ) 218 | ) snoop_dv [TbNumMst-1:0](clk); 219 | SNOOP_BUS_DV #( 220 | .SNOOP_ADDR_WIDTH ( AxiAddrWidth ), 221 | .SNOOP_DATA_WIDTH ( AxiDataWidth ) 222 | ) snoop_monitor_dv [TbNumMst-1:0](clk); 223 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_conn_dv_snoop 224 | `SNOOP_ASSIGN(snoop_dv[i], snoop[i]) 225 | `SNOOP_ASSIGN_TO_REQ(snoop_req[i], snoop[i]) 226 | `SNOOP_ASSIGN_TO_RESP(snoop_resp[i], snoop[i]) 227 | end 228 | 229 | // ------------------------------- 230 | // AXI and SNOOP Rand Masters and Slaves 231 | // ------------------------------- 232 | // Masters control simulation run time 233 | ace_rand_master_t ace_rand_master [TbNumMst]; 234 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_rand_master 235 | initial begin 236 | ace_rand_master[i] = new( master_dv[i] ); 237 | end_of_sim[i] <= 1'b0; 238 | ace_rand_master[i].add_memory_region(32'h0000_0000, 32'h0000_3000, 239 | axi_pkg::DEVICE_NONBUFFERABLE); 240 | ace_rand_master[i].reset(); 241 | @(posedge rst_n); 242 | ace_rand_master[i].run(NoReads, NoWrites); 243 | end_of_sim[i] <= 1'b1; 244 | end 245 | end 246 | 247 | snoop_rand_slave_t snoop_rand_slave [TbNumMst]; 248 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_rand_snoop 249 | initial begin 250 | snoop_rand_slave[i] = new( snoop_dv[i] ); 251 | snoop_rand_slave[i].reset(); 252 | @(posedge rst_n); 253 | snoop_rand_slave[i].run(); 254 | end 255 | end 256 | 257 | 258 | axi_rand_slave_t axi_rand_slave [1]; 259 | for (genvar i = 0; i < TbNumSlv; i++) begin : gen_rand_slave 260 | initial begin 261 | axi_rand_slave[i] = new( slave_dv[i] ); 262 | axi_rand_slave[i].reset(); 263 | @(posedge rst_n); 264 | axi_rand_slave[i].run(); 265 | end 266 | end 267 | 268 | 269 | 270 | 271 | initial begin : proc_monitor 272 | static tb_ace_ccu_pkg::ace_ccu_monitor #( 273 | .AxiAddrWidth ( AxiAddrWidth ), 274 | .AxiDataWidth ( AxiDataWidth ), 275 | .AxiIdWidthMasters ( AxiIdWidthMasters ), 276 | .AxiIdWidthSlaves ( AxiIdWidthSlaves ), 277 | .AxiUserWidth ( AxiUserWidth ), 278 | .NoMasters ( TbNumMst ), 279 | .NoSlaves ( TbNumSlv ), 280 | .TimeTest ( TestTime ) 281 | ) monitor = new( master_monitor_dv, slave_monitor_dv, snoop_monitor_dv ); 282 | fork 283 | monitor.run(); 284 | do begin 285 | #TestTime; 286 | if(end_of_sim == '1) begin 287 | monitor.print_result(); 288 | $stop(); 289 | end 290 | @(posedge clk); 291 | end while (1'b1); 292 | join 293 | end 294 | 295 | //----------------------------------- 296 | // Clock generator 297 | //----------------------------------- 298 | clk_rst_gen #( 299 | .ClkPeriod ( CyclTime ), 300 | .RstClkCycles ( 5 ) 301 | ) i_clk_gen ( 302 | .clk_o (clk), 303 | .rst_no(rst_n) 304 | ); 305 | 306 | //----------------------------------- 307 | // DUT 308 | //----------------------------------- 309 | ace_ccu_top_intf #( 310 | .AXI_USER_WIDTH ( AxiUserWidth ), 311 | .Cfg ( ccu_cfg ) 312 | ) i_ccu_dut ( 313 | .clk_i ( clk ), 314 | .rst_ni ( rst_n ), 315 | .test_i ( 1'b0 ), 316 | .snoop_ports ( snoop ), 317 | .slv_ports ( master ), 318 | .mst_ports ( slave[0] ) 319 | ); 320 | 321 | // logger for master modules 322 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_master_logger 323 | ace_chan_logger #( 324 | .TestTime ( TestTime ), // Time after clock, where sampling happens 325 | .LoggerName( $sformatf("axi_logger_master_%0d", i)), 326 | .aw_chan_t ( aw_chan_mst_t ), // axi AW type 327 | .w_chan_t ( w_chan_t ), // axi W type 328 | .b_chan_t ( b_chan_mst_t ), // axi B type 329 | .ar_chan_t ( ar_chan_mst_t ), // axi AR type 330 | .r_chan_t ( r_chan_mst_t ) // axi R type 331 | ) i_mst_channel_logger ( 332 | .clk_i ( clk ), // Clock 333 | .rst_ni ( rst_n ), // Asynchronous reset active low, when `1'b0` no sampling 334 | .end_sim_i ( &end_of_sim ), 335 | // AW channel 336 | .aw_chan_i ( masters_req[i].aw ), 337 | .aw_valid_i ( masters_req[i].aw_valid ), 338 | .aw_ready_i ( masters_resp[i].aw_ready ), 339 | // W channel 340 | .w_chan_i ( masters_req[i].w ), 341 | .w_valid_i ( masters_req[i].w_valid ), 342 | .w_ready_i ( masters_resp[i].w_ready ), 343 | // B channel 344 | .b_chan_i ( masters_resp[i].b ), 345 | .b_valid_i ( masters_resp[i].b_valid ), 346 | .b_ready_i ( masters_req[i].b_ready ), 347 | // AR channel 348 | .ar_chan_i ( masters_req[i].ar ), 349 | .ar_valid_i ( masters_req[i].ar_valid ), 350 | .ar_ready_i ( masters_resp[i].ar_ready ), 351 | // R channel 352 | .r_chan_i ( masters_resp[i].r ), 353 | .r_valid_i ( masters_resp[i].r_valid ), 354 | .r_ready_i ( masters_req[i].r_ready ) 355 | ); 356 | end 357 | // logger for slave modules 358 | for (genvar i = 0; i < 1; i++) begin : gen_slave_logger 359 | axi_chan_logger #( 360 | .TestTime ( TestTime ), // Time after clock, where sampling happens 361 | .LoggerName( $sformatf("axi_logger_slave_%0d",i)), 362 | .aw_chan_t ( aw_chan_slv_t ), // axi AW type 363 | .w_chan_t ( w_chan_t ), // axi W type 364 | .b_chan_t ( b_chan_slv_t ), // axi B type 365 | .ar_chan_t ( ar_chan_slv_t ), // axi AR type 366 | .r_chan_t ( r_chan_slv_t ) // axi R type 367 | ) i_slv_channel_logger ( 368 | .clk_i ( clk ), // Clock 369 | .rst_ni ( rst_n ), // Asynchronous reset active low, when `1'b0` no sampling 370 | .end_sim_i ( &end_of_sim ), 371 | // AW channel 372 | .aw_chan_i ( slaves_req[i].aw ), 373 | .aw_valid_i ( slaves_req[i].aw_valid ), 374 | .aw_ready_i ( slaves_resp[i].aw_ready ), 375 | // W channel 376 | .w_chan_i ( slaves_req[i].w ), 377 | .w_valid_i ( slaves_req[i].w_valid ), 378 | .w_ready_i ( slaves_resp[i].w_ready ), 379 | // B channel 380 | .b_chan_i ( slaves_resp[i].b ), 381 | .b_valid_i ( slaves_resp[i].b_valid ), 382 | .b_ready_i ( slaves_req[i].b_ready ), 383 | // AR channel 384 | .ar_chan_i ( slaves_req[i].ar ), 385 | .ar_valid_i ( slaves_req[i].ar_valid ), 386 | .ar_ready_i ( slaves_resp[i].ar_ready ), 387 | // R channel 388 | .r_chan_i ( slaves_resp[i].r ), 389 | .r_valid_i ( slaves_resp[i].r_valid ), 390 | .r_ready_i ( slaves_req[i].r_ready ) 391 | ); 392 | end 393 | 394 | // logger for snoop modules 395 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_snoop_logger 396 | snoop_chan_logger #( 397 | .TestTime ( TestTime ), // Time after clock, where sampling happens 398 | .LoggerName( $sformatf("axi_logger_snoop_%0d",i)), 399 | .ac_chan_t ( snoop_ac_t ), // AW type 400 | .cr_chan_t ( snoop_cr_t ), // CR type 401 | .cd_chan_t ( snoop_cd_t ) // CD type 402 | ) i_snoop_channel_logger ( 403 | .clk_i ( clk ), // Clock 404 | .rst_ni ( rst_n ), // Asynchronous reset active low, when `1'b0` no sampling 405 | .end_sim_i ( &end_of_sim ), 406 | // AC channel 407 | .ac_chan_i ( snoop_req[i].ac ), 408 | .ac_valid_i ( snoop_req[i].ac_valid ), 409 | .ac_ready_i ( snoop_resp[i].ac_ready ), 410 | // CR channel 411 | .cr_chan_i ( snoop_resp[i].cr_resp ), 412 | .cr_valid_i ( snoop_resp[i].cr_valid), 413 | .cr_ready_i ( snoop_req[i].cr_ready ), 414 | // CR channel 415 | .cd_chan_i ( snoop_resp[i].cd ), 416 | .cd_valid_i ( snoop_resp[i].cd_valid), 417 | .cd_ready_i ( snoop_req[i].cd_ready ) 418 | ); 419 | end 420 | 421 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_connect_master_monitor 422 | assign master_monitor_dv[i].aw_id = master[i].aw_id ; 423 | assign master_monitor_dv[i].aw_addr = master[i].aw_addr ; 424 | assign master_monitor_dv[i].aw_len = master[i].aw_len ; 425 | assign master_monitor_dv[i].aw_size = master[i].aw_size ; 426 | assign master_monitor_dv[i].aw_burst = master[i].aw_burst ; 427 | assign master_monitor_dv[i].aw_lock = master[i].aw_lock ; 428 | assign master_monitor_dv[i].aw_cache = master[i].aw_cache ; 429 | assign master_monitor_dv[i].aw_prot = master[i].aw_prot ; 430 | assign master_monitor_dv[i].aw_qos = master[i].aw_qos ; 431 | assign master_monitor_dv[i].aw_region = master[i].aw_region; 432 | assign master_monitor_dv[i].aw_atop = master[i].aw_atop ; 433 | assign master_monitor_dv[i].aw_user = master[i].aw_user ; 434 | assign master_monitor_dv[i].aw_valid = master[i].aw_valid ; 435 | assign master_monitor_dv[i].aw_ready = master[i].aw_ready ; 436 | assign master_monitor_dv[i].aw_snoop = master[i].aw_snoop; 437 | assign master_monitor_dv[i].aw_bar = master[i].aw_bar ; 438 | assign master_monitor_dv[i].aw_domain = master[i].aw_domain ; 439 | assign master_monitor_dv[i].aw_awunique = master[i].aw_awunique ; 440 | assign master_monitor_dv[i].w_data = master[i].w_data ; 441 | assign master_monitor_dv[i].w_strb = master[i].w_strb ; 442 | assign master_monitor_dv[i].w_last = master[i].w_last ; 443 | assign master_monitor_dv[i].w_user = master[i].w_user ; 444 | assign master_monitor_dv[i].w_valid = master[i].w_valid ; 445 | assign master_monitor_dv[i].w_ready = master[i].w_ready ; 446 | assign master_monitor_dv[i].b_id = master[i].b_id ; 447 | assign master_monitor_dv[i].b_resp = master[i].b_resp ; 448 | assign master_monitor_dv[i].b_user = master[i].b_user ; 449 | assign master_monitor_dv[i].b_valid = master[i].b_valid ; 450 | assign master_monitor_dv[i].b_ready = master[i].b_ready ; 451 | assign master_monitor_dv[i].ar_id = master[i].ar_id ; 452 | assign master_monitor_dv[i].ar_addr = master[i].ar_addr ; 453 | assign master_monitor_dv[i].ar_len = master[i].ar_len ; 454 | assign master_monitor_dv[i].ar_size = master[i].ar_size ; 455 | assign master_monitor_dv[i].ar_burst = master[i].ar_burst ; 456 | assign master_monitor_dv[i].ar_lock = master[i].ar_lock ; 457 | assign master_monitor_dv[i].ar_cache = master[i].ar_cache ; 458 | assign master_monitor_dv[i].ar_prot = master[i].ar_prot ; 459 | assign master_monitor_dv[i].ar_qos = master[i].ar_qos ; 460 | assign master_monitor_dv[i].ar_region = master[i].ar_region; 461 | assign master_monitor_dv[i].ar_user = master[i].ar_user ; 462 | assign master_monitor_dv[i].ar_valid = master[i].ar_valid ; 463 | assign master_monitor_dv[i].ar_ready = master[i].ar_ready ; 464 | assign master_monitor_dv[i].ar_snoop = master[i].ar_snoop ; 465 | assign master_monitor_dv[i].ar_bar = master[i].ar_bar ; 466 | assign master_monitor_dv[i].ar_domain = master[i].ar_domain ; 467 | assign master_monitor_dv[i].r_id = master[i].r_id ; 468 | assign master_monitor_dv[i].r_data = master[i].r_data ; 469 | assign master_monitor_dv[i].r_resp = master[i].r_resp ; 470 | assign master_monitor_dv[i].r_last = master[i].r_last ; 471 | assign master_monitor_dv[i].r_user = master[i].r_user ; 472 | assign master_monitor_dv[i].r_valid = master[i].r_valid ; 473 | assign master_monitor_dv[i].r_ready = master[i].r_ready ; 474 | end 475 | for (genvar i = 0; i < TbNumSlv; i++) begin : gen_connect_slave_monitor 476 | assign slave_monitor_dv[i].aw_id = slave[i].aw_id ; 477 | assign slave_monitor_dv[i].aw_addr = slave[i].aw_addr ; 478 | assign slave_monitor_dv[i].aw_len = slave[i].aw_len ; 479 | assign slave_monitor_dv[i].aw_size = slave[i].aw_size ; 480 | assign slave_monitor_dv[i].aw_burst = slave[i].aw_burst ; 481 | assign slave_monitor_dv[i].aw_lock = slave[i].aw_lock ; 482 | assign slave_monitor_dv[i].aw_cache = slave[i].aw_cache ; 483 | assign slave_monitor_dv[i].aw_prot = slave[i].aw_prot ; 484 | assign slave_monitor_dv[i].aw_qos = slave[i].aw_qos ; 485 | assign slave_monitor_dv[i].aw_region = slave[i].aw_region; 486 | assign slave_monitor_dv[i].aw_atop = slave[i].aw_atop ; 487 | assign slave_monitor_dv[i].aw_user = slave[i].aw_user ; 488 | assign slave_monitor_dv[i].aw_valid = slave[i].aw_valid ; 489 | assign slave_monitor_dv[i].aw_ready = slave[i].aw_ready ; 490 | assign slave_monitor_dv[i].w_data = slave[i].w_data ; 491 | assign slave_monitor_dv[i].w_strb = slave[i].w_strb ; 492 | assign slave_monitor_dv[i].w_last = slave[i].w_last ; 493 | assign slave_monitor_dv[i].w_user = slave[i].w_user ; 494 | assign slave_monitor_dv[i].w_valid = slave[i].w_valid ; 495 | assign slave_monitor_dv[i].w_ready = slave[i].w_ready ; 496 | assign slave_monitor_dv[i].b_id = slave[i].b_id ; 497 | assign slave_monitor_dv[i].b_resp = slave[i].b_resp ; 498 | assign slave_monitor_dv[i].b_user = slave[i].b_user ; 499 | assign slave_monitor_dv[i].b_valid = slave[i].b_valid ; 500 | assign slave_monitor_dv[i].b_ready = slave[i].b_ready ; 501 | assign slave_monitor_dv[i].ar_id = slave[i].ar_id ; 502 | assign slave_monitor_dv[i].ar_addr = slave[i].ar_addr ; 503 | assign slave_monitor_dv[i].ar_len = slave[i].ar_len ; 504 | assign slave_monitor_dv[i].ar_size = slave[i].ar_size ; 505 | assign slave_monitor_dv[i].ar_burst = slave[i].ar_burst ; 506 | assign slave_monitor_dv[i].ar_lock = slave[i].ar_lock ; 507 | assign slave_monitor_dv[i].ar_cache = slave[i].ar_cache ; 508 | assign slave_monitor_dv[i].ar_prot = slave[i].ar_prot ; 509 | assign slave_monitor_dv[i].ar_qos = slave[i].ar_qos ; 510 | assign slave_monitor_dv[i].ar_region = slave[i].ar_region; 511 | assign slave_monitor_dv[i].ar_user = slave[i].ar_user ; 512 | assign slave_monitor_dv[i].ar_valid = slave[i].ar_valid ; 513 | assign slave_monitor_dv[i].ar_ready = slave[i].ar_ready ; 514 | assign slave_monitor_dv[i].r_id = slave[i].r_id ; 515 | assign slave_monitor_dv[i].r_data = slave[i].r_data ; 516 | assign slave_monitor_dv[i].r_resp = slave[i].r_resp ; 517 | assign slave_monitor_dv[i].r_last = slave[i].r_last ; 518 | assign slave_monitor_dv[i].r_user = slave[i].r_user ; 519 | assign slave_monitor_dv[i].r_valid = slave[i].r_valid ; 520 | assign slave_monitor_dv[i].r_ready = slave[i].r_ready ; 521 | end 522 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_connect_snoop_monitor 523 | assign snoop_monitor_dv[i].ac_valid = snoop[i].ac_valid; 524 | assign snoop_monitor_dv[i].ac_ready = snoop[i].ac_ready; 525 | assign snoop_monitor_dv[i].ac_snoop = snoop[i].ac_snoop; 526 | assign snoop_monitor_dv[i].ac_addr = snoop[i].ac_addr; 527 | assign snoop_monitor_dv[i].ac_prot = snoop[i].ac_prot; 528 | assign snoop_monitor_dv[i].cr_valid = snoop[i].cr_valid; 529 | assign snoop_monitor_dv[i].cr_ready = snoop[i].cr_ready; 530 | assign snoop_monitor_dv[i].cr_resp = snoop[i].cr_resp; 531 | assign snoop_monitor_dv[i].cd_valid = snoop[i].cd_valid; 532 | assign snoop_monitor_dv[i].cd_ready = snoop[i].cd_ready; 533 | assign snoop_monitor_dv[i].cd_data = snoop[i].cd_data; 534 | assign snoop_monitor_dv[i].cd_last = snoop[i].cd_last; 535 | end 536 | endmodule -------------------------------------------------------------------------------- /test/tb_ace_ccu_top_sanity.sv: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 ETH Zurich and University of Bologna. 2 | // Copyright (c) 2022 PlanV GmbH 3 | // 4 | // Copyright and related rights are licensed under the Solderpad Hardware 5 | // License, Version 0.51 (the "License"); you may not use this file except in 6 | // compliance with the License. You may obtain a copy of the License at 7 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 8 | // or agreed to in writing, software, hardware and materials distributed under 9 | // this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 11 | // specific language governing permissions and limitations under the License. 12 | // 13 | // Authors: 14 | // - Florian Zaruba 15 | // - Andreas Kurth 16 | 17 | // Directed Random Verification Testbench for `axi_xbar`: The crossbar is instantiated with 18 | // a number of random axi master and slave modules. Each random master executes a fixed number of 19 | // writes and reads over the whole addess map. All masters simultaneously issue transactions 20 | // through the crossbar, thereby saturating it. A monitor, which snoops the transactions of each 21 | // master and slave port and models the crossbar with a network of FIFOs, checks whether each 22 | // transaction follows the expected route. 23 | 24 | `include "ace/typedef.svh" 25 | `include "ace/assign.svh" 26 | 27 | module tb_ace_ccu_top #( 28 | parameter bit TbEnAtop = 1'b1, // enable atomic operations (ATOPs) 29 | parameter bit TbEnExcl = 1'b0, // enable exclusive accesses 30 | parameter bit TbUniqueIds = 1'b0, // restrict to only unique IDs 31 | parameter int unsigned TbNumMst = 32'd4, // how many AXI masters there are 32 | parameter int unsigned TbNumSlv = 32'd1 // how many AXI slaves there are 33 | ); 34 | // Random master no Transactions 35 | localparam int unsigned NoWrites = 80; // How many writes per master 36 | localparam int unsigned NoReads = 80; // How many reads per master 37 | // timing parameters 38 | localparam time CyclTime = 10ns; 39 | localparam time ApplTime = 2ns; 40 | localparam time TestTime = 8ns; 41 | 42 | // axi configuration 43 | localparam int unsigned AxiIdWidthMasters = 4; 44 | localparam int unsigned AxiIdUsed = 3; // Has to be <= AxiIdWidthMasters 45 | localparam int unsigned AxiIdWidthSlaves = AxiIdWidthMasters + $clog2(TbNumMst)+$clog2(TbNumMst+1); 46 | localparam int unsigned AxiAddrWidth = 32; // Axi Address Width 47 | localparam int unsigned AxiDataWidth = 64; // Axi Data Width 48 | localparam int unsigned AxiStrbWidth = AxiDataWidth / 8; 49 | localparam int unsigned AxiUserWidth = 5; 50 | 51 | // in the bench can change this variables which are set here freely 52 | localparam ace_pkg::ccu_cfg_t ccu_cfg = '{ 53 | NoSlvPorts: TbNumMst, 54 | MaxMstTrans: 10, 55 | MaxSlvTrans: 6, 56 | FallThrough: 1'b1, 57 | LatencyMode: ace_pkg::NO_LATENCY, 58 | AxiIdWidthSlvPorts: AxiIdWidthMasters, 59 | AxiIdUsedSlvPorts: AxiIdUsed, 60 | UniqueIds: TbUniqueIds, 61 | AxiAddrWidth: AxiAddrWidth, 62 | AxiDataWidth: AxiDataWidth 63 | }; 64 | 65 | 66 | typedef logic [AxiIdWidthMasters-1:0] id_mst_t; 67 | typedef logic [AxiIdWidthSlaves-1:0] id_slv_t; 68 | typedef logic [AxiAddrWidth-1:0] addr_t; 69 | typedef logic [AxiDataWidth-1:0] data_t; 70 | typedef logic [AxiStrbWidth-1:0] strb_t; 71 | typedef logic [AxiUserWidth-1:0] user_t; 72 | 73 | `ACE_TYPEDEF_AW_CHAN_T(aw_chan_mst_t, addr_t, id_mst_t, user_t) 74 | `AXI_TYPEDEF_AW_CHAN_T(aw_chan_slv_t, addr_t, id_slv_t, user_t) 75 | `AXI_TYPEDEF_W_CHAN_T(w_chan_t, data_t, strb_t, user_t) 76 | `AXI_TYPEDEF_B_CHAN_T(b_chan_mst_t, id_mst_t, user_t) 77 | `AXI_TYPEDEF_B_CHAN_T(b_chan_slv_t, id_slv_t, user_t) 78 | 79 | `ACE_TYPEDEF_AR_CHAN_T(ar_chan_mst_t, addr_t, id_mst_t, user_t) 80 | `AXI_TYPEDEF_AR_CHAN_T(ar_chan_slv_t, addr_t, id_slv_t, user_t) 81 | `ACE_TYPEDEF_R_CHAN_T(r_chan_mst_t, data_t, id_mst_t, user_t) 82 | `AXI_TYPEDEF_R_CHAN_T(r_chan_slv_t, data_t, id_slv_t, user_t) 83 | 84 | `ACE_TYPEDEF_REQ_T(mst_req_t, aw_chan_mst_t, w_chan_t, ar_chan_mst_t) 85 | `ACE_TYPEDEF_RESP_T(mst_resp_t, b_chan_mst_t, r_chan_mst_t) 86 | `AXI_TYPEDEF_REQ_T(slv_req_t, aw_chan_slv_t, w_chan_t, ar_chan_slv_t) 87 | `AXI_TYPEDEF_RESP_T(slv_resp_t, b_chan_slv_t, r_chan_slv_t) 88 | 89 | `SNOOP_TYPEDEF_AC_CHAN_T(snoop_ac_t, addr_t) 90 | `SNOOP_TYPEDEF_CD_CHAN_T(snoop_cd_t, data_t) 91 | `SNOOP_TYPEDEF_CR_CHAN_T(snoop_cr_t) 92 | `SNOOP_TYPEDEF_REQ_T(snoop_req_t, snoop_ac_t) 93 | `SNOOP_TYPEDEF_RESP_T(snoop_resp_t, snoop_cd_t, snoop_cr_t) 94 | 95 | 96 | typedef ace_test::ace_rand_master #( 97 | // AXI interface parameters 98 | .AW ( AxiAddrWidth ), 99 | .DW ( AxiDataWidth ), 100 | .IW ( AxiIdWidthMasters ), 101 | .UW ( AxiUserWidth ), 102 | // Stimuli application and test time 103 | .TA ( ApplTime ), 104 | .TT ( TestTime ), 105 | // Maximum number of read and write transactions in flight 106 | .MAX_READ_TXNS ( 20 ), 107 | .MAX_WRITE_TXNS ( 20 ), 108 | .AXI_EXCLS ( TbEnExcl ), 109 | .AXI_ATOPS ( TbEnAtop ), 110 | .UNIQUE_IDS ( TbUniqueIds ) 111 | ) ace_rand_master_t; 112 | typedef axi_test::axi_rand_slave #( 113 | // AXI interface parameters 114 | .AW ( AxiAddrWidth ), 115 | .DW ( AxiDataWidth ), 116 | .IW ( AxiIdWidthSlaves ), 117 | .UW ( AxiUserWidth ), 118 | // Stimuli application and test time 119 | .TA ( ApplTime ), 120 | .TT ( TestTime ) 121 | ) axi_rand_slave_t; 122 | 123 | typedef snoop_test::snoop_rand_slave #( 124 | // ADDR and Data interface parameters 125 | .AW ( AxiAddrWidth ), 126 | .DW ( AxiDataWidth ), 127 | // Stimuli application and test time 128 | .TA ( ApplTime), 129 | .TT ( TestTime), 130 | .RAND_RESP ( '0), 131 | // Upper and lower bounds on wait cycles on Ax, W, and resp (R and B) channels 132 | .AC_MIN_WAIT_CYCLES ( 2), 133 | .AC_MAX_WAIT_CYCLES ( 15), 134 | .CR_MIN_WAIT_CYCLES ( 2), 135 | .CR_MAX_WAIT_CYCLES ( 15), 136 | .CD_MIN_WAIT_CYCLES ( 2), 137 | .CD_MAX_WAIT_CYCLES ( 15) 138 | )snoop_rand_slave_t; 139 | // ------------- 140 | // DUT signals 141 | // ------------- 142 | logic clk; 143 | // DUT signals 144 | logic rst_n; 145 | logic [TbNumMst-1:0] end_of_sim; 146 | 147 | // master structs 148 | mst_req_t [TbNumMst-1:0] masters_req; 149 | mst_resp_t [TbNumMst-1:0] masters_resp; 150 | 151 | // slave structs 152 | slv_req_t [TbNumSlv-1:0] slaves_req; 153 | slv_resp_t [TbNumSlv-1:0] slaves_resp; 154 | 155 | // snoop structs 156 | snoop_req_t [TbNumMst-1:0] snoop_req; 157 | snoop_resp_t [TbNumMst-1:0] snoop_resp; 158 | 159 | 160 | // ------------------------------- 161 | // AXI Interfaces 162 | // ------------------------------- 163 | ACE_BUS #( 164 | .AXI_ADDR_WIDTH ( AxiAddrWidth ), 165 | .AXI_DATA_WIDTH ( AxiDataWidth ), 166 | .AXI_ID_WIDTH ( AxiIdWidthMasters ), 167 | .AXI_USER_WIDTH ( AxiUserWidth ) 168 | ) master [TbNumMst-1:0] (); 169 | ACE_BUS_DV #( 170 | .AXI_ADDR_WIDTH ( AxiAddrWidth ), 171 | .AXI_DATA_WIDTH ( AxiDataWidth ), 172 | .AXI_ID_WIDTH ( AxiIdWidthMasters ), 173 | .AXI_USER_WIDTH ( AxiUserWidth ) 174 | ) master_dv [TbNumMst-1:0] (clk); 175 | ACE_BUS_DV #( 176 | .AXI_ADDR_WIDTH ( AxiAddrWidth ), 177 | .AXI_DATA_WIDTH ( AxiDataWidth ), 178 | .AXI_ID_WIDTH ( AxiIdWidthMasters ), 179 | .AXI_USER_WIDTH ( AxiUserWidth ) 180 | ) master_monitor_dv [TbNumMst-1:0] (clk); 181 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_conn_dv_masters 182 | `ACE_ASSIGN (master[i], master_dv[i]) 183 | `ACE_ASSIGN_TO_REQ(masters_req[i], master[i]) 184 | `ACE_ASSIGN_TO_RESP(masters_resp[i], master[i]) 185 | end 186 | 187 | AXI_BUS #( 188 | .AXI_ADDR_WIDTH ( AxiAddrWidth ), 189 | .AXI_DATA_WIDTH ( AxiDataWidth ), 190 | .AXI_ID_WIDTH ( AxiIdWidthSlaves ), 191 | .AXI_USER_WIDTH ( AxiUserWidth ) 192 | ) slave [TbNumSlv-1:0] (); 193 | AXI_BUS_DV #( 194 | .AXI_ADDR_WIDTH ( AxiAddrWidth ), 195 | .AXI_DATA_WIDTH ( AxiDataWidth ), 196 | .AXI_ID_WIDTH ( AxiIdWidthSlaves ), 197 | .AXI_USER_WIDTH ( AxiUserWidth ) 198 | ) slave_dv [TbNumSlv-1:0](clk); 199 | AXI_BUS_DV #( 200 | .AXI_ADDR_WIDTH ( AxiAddrWidth ), 201 | .AXI_DATA_WIDTH ( AxiDataWidth ), 202 | .AXI_ID_WIDTH ( AxiIdWidthSlaves ), 203 | .AXI_USER_WIDTH ( AxiUserWidth ) 204 | ) slave_monitor_dv [TbNumSlv-1:0](clk); 205 | for (genvar i = 0; i < TbNumSlv; i++) begin : gen_conn_dv_slaves 206 | `AXI_ASSIGN(slave_dv[i], slave[i]) 207 | `AXI_ASSIGN_TO_REQ(slaves_req[i], slave[i]) 208 | `AXI_ASSIGN_TO_RESP(slaves_resp[i], slave[i]) 209 | end 210 | 211 | SNOOP_BUS #( 212 | .SNOOP_ADDR_WIDTH ( AxiAddrWidth ), 213 | .SNOOP_DATA_WIDTH ( AxiDataWidth ) 214 | ) snoop [TbNumMst-1:0] (); 215 | SNOOP_BUS_DV #( 216 | .SNOOP_ADDR_WIDTH ( AxiAddrWidth ), 217 | .SNOOP_DATA_WIDTH ( AxiDataWidth ) 218 | ) snoop_dv [TbNumMst-1:0](clk); 219 | SNOOP_BUS_DV #( 220 | .SNOOP_ADDR_WIDTH ( AxiAddrWidth ), 221 | .SNOOP_DATA_WIDTH ( AxiDataWidth ) 222 | ) snoop_monitor_dv [TbNumMst-1:0](clk); 223 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_conn_dv_snoop 224 | `SNOOP_ASSIGN(snoop_dv[i], snoop[i]) 225 | `SNOOP_ASSIGN_TO_REQ(snoop_req[i], snoop[i]) 226 | `SNOOP_ASSIGN_TO_RESP(snoop_resp[i], snoop[i]) 227 | end 228 | 229 | // ------------------------------- 230 | // AXI and SNOOP Rand Masters and Slaves 231 | // ------------------------------- 232 | // Masters control simulation run time 233 | ace_rand_master_t ace_rand_master [TbNumMst]; 234 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_rand_master 235 | initial begin 236 | ace_rand_master[i] = new( master_dv[i] ); 237 | end_of_sim[i] <= 1'b0; 238 | ace_rand_master[i].add_memory_region(32'h0000_0000, 32'h0000_3000, 239 | axi_pkg::DEVICE_NONBUFFERABLE); 240 | ace_rand_master[i].reset(); 241 | @(posedge rst_n); 242 | ace_rand_master[i].run(NoReads, NoWrites); 243 | end_of_sim[i] <= 1'b1; 244 | end 245 | end 246 | 247 | snoop_rand_slave_t snoop_rand_slave [TbNumMst]; 248 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_rand_snoop 249 | initial begin 250 | snoop_rand_slave[i] = new( snoop_dv[i] ); 251 | snoop_rand_slave[i].reset(); 252 | @(posedge rst_n); 253 | snoop_rand_slave[i].run(); 254 | end 255 | end 256 | 257 | 258 | axi_rand_slave_t axi_rand_slave [1]; 259 | for (genvar i = 0; i < TbNumSlv; i++) begin : gen_rand_slave 260 | initial begin 261 | axi_rand_slave[i] = new( slave_dv[i] ); 262 | axi_rand_slave[i].reset(); 263 | @(posedge rst_n); 264 | axi_rand_slave[i].run(); 265 | end 266 | end 267 | 268 | 269 | 270 | 271 | initial begin : proc_monitor 272 | static tb_ace_ccu_pkg::ace_ccu_monitor #( 273 | .AxiAddrWidth ( AxiAddrWidth ), 274 | .AxiDataWidth ( AxiDataWidth ), 275 | .AxiIdWidthMasters ( AxiIdWidthMasters ), 276 | .AxiIdWidthSlaves ( AxiIdWidthSlaves ), 277 | .AxiUserWidth ( AxiUserWidth ), 278 | .NoMasters ( TbNumMst ), 279 | .NoSlaves ( TbNumSlv ), 280 | .TimeTest ( TestTime ) 281 | ) monitor = new( master_monitor_dv, slave_monitor_dv, snoop_monitor_dv ); 282 | fork 283 | monitor.run(); 284 | do begin 285 | #TestTime; 286 | if(end_of_sim == '1) begin 287 | monitor.print_result(); 288 | $stop(); 289 | end 290 | @(posedge clk); 291 | end while (1'b1); 292 | join 293 | end 294 | 295 | //----------------------------------- 296 | // Clock generator 297 | //----------------------------------- 298 | clk_rst_gen #( 299 | .ClkPeriod ( CyclTime ), 300 | .RstClkCycles ( 5 ) 301 | ) i_clk_gen ( 302 | .clk_o (clk), 303 | .rst_no(rst_n) 304 | ); 305 | 306 | //----------------------------------- 307 | // DUT 308 | //----------------------------------- 309 | ace_ccu_top_intf #( 310 | .AXI_USER_WIDTH ( AxiUserWidth ), 311 | .Cfg ( ccu_cfg ) 312 | ) i_ccu_dut ( 313 | .clk_i ( clk ), 314 | .rst_ni ( rst_n ), 315 | .test_i ( 1'b0 ), 316 | .snoop_ports ( snoop ), 317 | .slv_ports ( master ), 318 | .mst_ports ( slave[0] ) 319 | ); 320 | 321 | // logger for master modules 322 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_master_logger 323 | ace_chan_logger #( 324 | .TestTime ( TestTime ), // Time after clock, where sampling happens 325 | .LoggerName( $sformatf("axi_logger_master_%0d", i)), 326 | .aw_chan_t ( aw_chan_mst_t ), // axi AW type 327 | .w_chan_t ( w_chan_t ), // axi W type 328 | .b_chan_t ( b_chan_mst_t ), // axi B type 329 | .ar_chan_t ( ar_chan_mst_t ), // axi AR type 330 | .r_chan_t ( r_chan_mst_t ) // axi R type 331 | ) i_mst_channel_logger ( 332 | .clk_i ( clk ), // Clock 333 | .rst_ni ( rst_n ), // Asynchronous reset active low, when `1'b0` no sampling 334 | .end_sim_i ( &end_of_sim ), 335 | // AW channel 336 | .aw_chan_i ( masters_req[i].aw ), 337 | .aw_valid_i ( masters_req[i].aw_valid ), 338 | .aw_ready_i ( masters_resp[i].aw_ready ), 339 | // W channel 340 | .w_chan_i ( masters_req[i].w ), 341 | .w_valid_i ( masters_req[i].w_valid ), 342 | .w_ready_i ( masters_resp[i].w_ready ), 343 | // B channel 344 | .b_chan_i ( masters_resp[i].b ), 345 | .b_valid_i ( masters_resp[i].b_valid ), 346 | .b_ready_i ( masters_req[i].b_ready ), 347 | // AR channel 348 | .ar_chan_i ( masters_req[i].ar ), 349 | .ar_valid_i ( masters_req[i].ar_valid ), 350 | .ar_ready_i ( masters_resp[i].ar_ready ), 351 | // R channel 352 | .r_chan_i ( masters_resp[i].r ), 353 | .r_valid_i ( masters_resp[i].r_valid ), 354 | .r_ready_i ( masters_req[i].r_ready ) 355 | ); 356 | end 357 | // logger for slave modules 358 | for (genvar i = 0; i < 1; i++) begin : gen_slave_logger 359 | axi_chan_logger #( 360 | .TestTime ( TestTime ), // Time after clock, where sampling happens 361 | .LoggerName( $sformatf("axi_logger_slave_%0d",i)), 362 | .aw_chan_t ( aw_chan_slv_t ), // axi AW type 363 | .w_chan_t ( w_chan_t ), // axi W type 364 | .b_chan_t ( b_chan_slv_t ), // axi B type 365 | .ar_chan_t ( ar_chan_slv_t ), // axi AR type 366 | .r_chan_t ( r_chan_slv_t ) // axi R type 367 | ) i_slv_channel_logger ( 368 | .clk_i ( clk ), // Clock 369 | .rst_ni ( rst_n ), // Asynchronous reset active low, when `1'b0` no sampling 370 | .end_sim_i ( &end_of_sim ), 371 | // AW channel 372 | .aw_chan_i ( slaves_req[i].aw ), 373 | .aw_valid_i ( slaves_req[i].aw_valid ), 374 | .aw_ready_i ( slaves_resp[i].aw_ready ), 375 | // W channel 376 | .w_chan_i ( slaves_req[i].w ), 377 | .w_valid_i ( slaves_req[i].w_valid ), 378 | .w_ready_i ( slaves_resp[i].w_ready ), 379 | // B channel 380 | .b_chan_i ( slaves_resp[i].b ), 381 | .b_valid_i ( slaves_resp[i].b_valid ), 382 | .b_ready_i ( slaves_req[i].b_ready ), 383 | // AR channel 384 | .ar_chan_i ( slaves_req[i].ar ), 385 | .ar_valid_i ( slaves_req[i].ar_valid ), 386 | .ar_ready_i ( slaves_resp[i].ar_ready ), 387 | // R channel 388 | .r_chan_i ( slaves_resp[i].r ), 389 | .r_valid_i ( slaves_resp[i].r_valid ), 390 | .r_ready_i ( slaves_req[i].r_ready ) 391 | ); 392 | end 393 | 394 | // logger for snoop modules 395 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_snoop_logger 396 | snoop_chan_logger #( 397 | .TestTime ( TestTime ), // Time after clock, where sampling happens 398 | .LoggerName( $sformatf("axi_logger_snoop_%0d",i)), 399 | .ac_chan_t ( snoop_ac_t ), // AW type 400 | .cr_chan_t ( snoop_cr_t ), // CR type 401 | .cd_chan_t ( snoop_cd_t ) // CD type 402 | ) i_snoop_channel_logger ( 403 | .clk_i ( clk ), // Clock 404 | .rst_ni ( rst_n ), // Asynchronous reset active low, when `1'b0` no sampling 405 | .end_sim_i ( &end_of_sim ), 406 | // AC channel 407 | .ac_chan_i ( snoop_req[i].ac ), 408 | .ac_valid_i ( snoop_req[i].ac_valid ), 409 | .ac_ready_i ( snoop_resp[i].ac_ready ), 410 | // CR channel 411 | .cr_chan_i ( snoop_resp[i].cr_resp ), 412 | .cr_valid_i ( snoop_resp[i].cr_valid), 413 | .cr_ready_i ( snoop_req[i].cr_ready ), 414 | // CR channel 415 | .cd_chan_i ( snoop_resp[i].cd ), 416 | .cd_valid_i ( snoop_resp[i].cd_valid), 417 | .cd_ready_i ( snoop_req[i].cd_ready ) 418 | ); 419 | end 420 | 421 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_connect_master_monitor 422 | assign master_monitor_dv[i].aw_id = master[i].aw_id ; 423 | assign master_monitor_dv[i].aw_addr = master[i].aw_addr ; 424 | assign master_monitor_dv[i].aw_len = master[i].aw_len ; 425 | assign master_monitor_dv[i].aw_size = master[i].aw_size ; 426 | assign master_monitor_dv[i].aw_burst = master[i].aw_burst ; 427 | assign master_monitor_dv[i].aw_lock = master[i].aw_lock ; 428 | assign master_monitor_dv[i].aw_cache = master[i].aw_cache ; 429 | assign master_monitor_dv[i].aw_prot = master[i].aw_prot ; 430 | assign master_monitor_dv[i].aw_qos = master[i].aw_qos ; 431 | assign master_monitor_dv[i].aw_region = master[i].aw_region; 432 | assign master_monitor_dv[i].aw_atop = master[i].aw_atop ; 433 | assign master_monitor_dv[i].aw_user = master[i].aw_user ; 434 | assign master_monitor_dv[i].aw_valid = master[i].aw_valid ; 435 | assign master_monitor_dv[i].aw_ready = master[i].aw_ready ; 436 | assign master_monitor_dv[i].aw_snoop = master[i].aw_snoop; 437 | assign master_monitor_dv[i].aw_bar = master[i].aw_bar ; 438 | assign master_monitor_dv[i].aw_domain = master[i].aw_domain ; 439 | assign master_monitor_dv[i].aw_awunique = master[i].aw_awunique ; 440 | assign master_monitor_dv[i].w_data = master[i].w_data ; 441 | assign master_monitor_dv[i].w_strb = master[i].w_strb ; 442 | assign master_monitor_dv[i].w_last = master[i].w_last ; 443 | assign master_monitor_dv[i].w_user = master[i].w_user ; 444 | assign master_monitor_dv[i].w_valid = master[i].w_valid ; 445 | assign master_monitor_dv[i].w_ready = master[i].w_ready ; 446 | assign master_monitor_dv[i].b_id = master[i].b_id ; 447 | assign master_monitor_dv[i].b_resp = master[i].b_resp ; 448 | assign master_monitor_dv[i].b_user = master[i].b_user ; 449 | assign master_monitor_dv[i].b_valid = master[i].b_valid ; 450 | assign master_monitor_dv[i].b_ready = master[i].b_ready ; 451 | assign master_monitor_dv[i].ar_id = master[i].ar_id ; 452 | assign master_monitor_dv[i].ar_addr = master[i].ar_addr ; 453 | assign master_monitor_dv[i].ar_len = master[i].ar_len ; 454 | assign master_monitor_dv[i].ar_size = master[i].ar_size ; 455 | assign master_monitor_dv[i].ar_burst = master[i].ar_burst ; 456 | assign master_monitor_dv[i].ar_lock = master[i].ar_lock ; 457 | assign master_monitor_dv[i].ar_cache = master[i].ar_cache ; 458 | assign master_monitor_dv[i].ar_prot = master[i].ar_prot ; 459 | assign master_monitor_dv[i].ar_qos = master[i].ar_qos ; 460 | assign master_monitor_dv[i].ar_region = master[i].ar_region; 461 | assign master_monitor_dv[i].ar_user = master[i].ar_user ; 462 | assign master_monitor_dv[i].ar_valid = master[i].ar_valid ; 463 | assign master_monitor_dv[i].ar_ready = master[i].ar_ready ; 464 | assign master_monitor_dv[i].ar_snoop = master[i].ar_snoop ; 465 | assign master_monitor_dv[i].ar_bar = master[i].ar_bar ; 466 | assign master_monitor_dv[i].ar_domain = master[i].ar_domain ; 467 | assign master_monitor_dv[i].r_id = master[i].r_id ; 468 | assign master_monitor_dv[i].r_data = master[i].r_data ; 469 | assign master_monitor_dv[i].r_resp = master[i].r_resp ; 470 | assign master_monitor_dv[i].r_last = master[i].r_last ; 471 | assign master_monitor_dv[i].r_user = master[i].r_user ; 472 | assign master_monitor_dv[i].r_valid = master[i].r_valid ; 473 | assign master_monitor_dv[i].r_ready = master[i].r_ready ; 474 | end 475 | for (genvar i = 0; i < TbNumSlv; i++) begin : gen_connect_slave_monitor 476 | assign slave_monitor_dv[i].aw_id = slave[i].aw_id ; 477 | assign slave_monitor_dv[i].aw_addr = slave[i].aw_addr ; 478 | assign slave_monitor_dv[i].aw_len = slave[i].aw_len ; 479 | assign slave_monitor_dv[i].aw_size = slave[i].aw_size ; 480 | assign slave_monitor_dv[i].aw_burst = slave[i].aw_burst ; 481 | assign slave_monitor_dv[i].aw_lock = slave[i].aw_lock ; 482 | assign slave_monitor_dv[i].aw_cache = slave[i].aw_cache ; 483 | assign slave_monitor_dv[i].aw_prot = slave[i].aw_prot ; 484 | assign slave_monitor_dv[i].aw_qos = slave[i].aw_qos ; 485 | assign slave_monitor_dv[i].aw_region = slave[i].aw_region; 486 | assign slave_monitor_dv[i].aw_atop = slave[i].aw_atop ; 487 | assign slave_monitor_dv[i].aw_user = slave[i].aw_user ; 488 | assign slave_monitor_dv[i].aw_valid = slave[i].aw_valid ; 489 | assign slave_monitor_dv[i].aw_ready = slave[i].aw_ready ; 490 | assign slave_monitor_dv[i].w_data = slave[i].w_data ; 491 | assign slave_monitor_dv[i].w_strb = slave[i].w_strb ; 492 | assign slave_monitor_dv[i].w_last = slave[i].w_last ; 493 | assign slave_monitor_dv[i].w_user = slave[i].w_user ; 494 | assign slave_monitor_dv[i].w_valid = slave[i].w_valid ; 495 | assign slave_monitor_dv[i].w_ready = slave[i].w_ready ; 496 | assign slave_monitor_dv[i].b_id = slave[i].b_id ; 497 | assign slave_monitor_dv[i].b_resp = slave[i].b_resp ; 498 | assign slave_monitor_dv[i].b_user = slave[i].b_user ; 499 | assign slave_monitor_dv[i].b_valid = slave[i].b_valid ; 500 | assign slave_monitor_dv[i].b_ready = slave[i].b_ready ; 501 | assign slave_monitor_dv[i].ar_id = slave[i].ar_id ; 502 | assign slave_monitor_dv[i].ar_addr = slave[i].ar_addr ; 503 | assign slave_monitor_dv[i].ar_len = slave[i].ar_len ; 504 | assign slave_monitor_dv[i].ar_size = slave[i].ar_size ; 505 | assign slave_monitor_dv[i].ar_burst = slave[i].ar_burst ; 506 | assign slave_monitor_dv[i].ar_lock = slave[i].ar_lock ; 507 | assign slave_monitor_dv[i].ar_cache = slave[i].ar_cache ; 508 | assign slave_monitor_dv[i].ar_prot = slave[i].ar_prot ; 509 | assign slave_monitor_dv[i].ar_qos = slave[i].ar_qos ; 510 | assign slave_monitor_dv[i].ar_region = slave[i].ar_region; 511 | assign slave_monitor_dv[i].ar_user = slave[i].ar_user ; 512 | assign slave_monitor_dv[i].ar_valid = slave[i].ar_valid ; 513 | assign slave_monitor_dv[i].ar_ready = slave[i].ar_ready ; 514 | assign slave_monitor_dv[i].r_id = slave[i].r_id ; 515 | assign slave_monitor_dv[i].r_data = slave[i].r_data ; 516 | assign slave_monitor_dv[i].r_resp = slave[i].r_resp ; 517 | assign slave_monitor_dv[i].r_last = slave[i].r_last ; 518 | assign slave_monitor_dv[i].r_user = slave[i].r_user ; 519 | assign slave_monitor_dv[i].r_valid = slave[i].r_valid ; 520 | assign slave_monitor_dv[i].r_ready = slave[i].r_ready ; 521 | end 522 | for (genvar i = 0; i < TbNumMst; i++) begin : gen_connect_snoop_monitor 523 | assign snoop_monitor_dv[i].ac_valid = snoop[i].ac_valid; 524 | assign snoop_monitor_dv[i].ac_ready = snoop[i].ac_ready; 525 | assign snoop_monitor_dv[i].ac_snoop = snoop[i].ac_snoop; 526 | assign snoop_monitor_dv[i].ac_addr = snoop[i].ac_addr; 527 | assign snoop_monitor_dv[i].ac_prot = snoop[i].ac_prot; 528 | assign snoop_monitor_dv[i].cr_valid = snoop[i].cr_valid; 529 | assign snoop_monitor_dv[i].cr_ready = snoop[i].cr_ready; 530 | assign snoop_monitor_dv[i].cr_resp = snoop[i].cr_resp; 531 | assign snoop_monitor_dv[i].cd_valid = snoop[i].cd_valid; 532 | assign snoop_monitor_dv[i].cd_ready = snoop[i].cd_ready; 533 | assign snoop_monitor_dv[i].cd_data = snoop[i].cd_data; 534 | assign snoop_monitor_dv[i].cd_last = snoop[i].cd_last; 535 | end 536 | endmodule --------------------------------------------------------------------------------