diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e7430c4..56b9a29 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -25,18 +25,54 @@ jobs: Copyright (\d{4}(-\d{4})?\s)?(ETH Zurich and University of Bologna|lowRISC contributors). exclude_paths: | .dir-locals.el + .python-version + uv.lock + LICENSES/ - name: Check license string run: | - N_FILES_WITHOUT_LICENCE=$(grep -Lr -E "SPDX-License-Identifier: (SHL-0.51|Apache-2.0)" --exclude-dir=".git" --include \*.yml --include \*.sv --include \*.hjson . | wc -l ) + N_FILES_WITHOUT_LICENCE=$(grep -Lr -E "SPDX-License-Identifier: (SHL-0.51|Apache-2.0)" --exclude-dir=".git" --include \*.yml --include \*.sv --include \*.rdl . | wc -l ) if [[ ${N_FILES_WITHOUT_LICENCE} -eq 0 ]]; then echo "All files contain SPDX-License-Identifier" else echo "Files missing SPDX-License-Identifier:" - grep -Lr -E "SPDX-License-Identifier: (SHL-0.51|Apache-2.0)" --exclude-dir=".git" --include \*.yml --include \*.sv --include \*.hjson . + grep -Lr -E "SPDX-License-Identifier: (SHL-0.51|Apache-2.0)" --exclude-dir=".git" --include \*.yml --include \*.sv --include \*.rdl . false fi + # The register blocks in src/ are generated from rdl/ and checked in, so they + # can silently drift from their source. Regenerate them and require the result + # to match. PeakRDL embeds no timestamp, path or version in its output, and + # --locked pins the generator, so this is a content comparison and not a + # source of flakes. + regs-up-to-date: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v7 + - + name: Install uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: true + - + name: Regenerate register blocks + run: make regs PEAKRDL="uv run --locked --group regs peakrdl" + - + name: Check the checked-in files match + run: | + if ! git diff --exit-code -- src/; then + echo "::error::Generated register files are out of date. Run 'make regs' and commit the result." + exit 1 + fi + - + name: Check the memory map still elaborates + # rdl/clic.rdl produces no checked-in artefact, so nothing above compiles + # it. Exporting it here catches errors the leaf blocks cannot, such as + # windows overlapping at the maximum configuration. + run: make clic-defs clic-hdr PEAKRDL="uv run --locked --group regs peakrdl" + lint-sv: runs-on: ubuntu-latest steps: @@ -79,4 +115,4 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} reviewdog-name: slang-elaboration - slang-flags: '-f slang.f --top clic_apb' + slang-flags: '-f slang.f --top clic' diff --git a/.gitignore b/.gitignore index 9fb01f3..da6b2ea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .bender/ test/verilator/ test/vsim/ +.venv/ +test/clic_reg_defs.svh diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..e4fba21 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/Bender.lock b/Bender.lock index fdac466..a392c1b 100644 --- a/Bender.lock +++ b/Bender.lock @@ -6,15 +6,6 @@ packages: Git: https://github.com/pulp-platform/apb.git dependencies: - common_cells - axi: - revision: a8c53cee2520d328d390c507c88818e8ac144c8c - version: 0.39.10 - source: - Git: https://github.com/pulp-platform/axi.git - dependencies: - - common_cells - - common_verification - - tech_cells_generic common_cells: revision: 1281545696eb3fcba50ec5b4275993476a3c710e version: 1.40.0 @@ -29,16 +20,6 @@ packages: source: Git: https://github.com/pulp-platform/common_verification.git dependencies: [] - register_interface: - revision: d6e1d4cdaab7870f4faf3f88a1c788eaf5ac129d - version: 0.4.7 - source: - Git: https://github.com/pulp-platform/register_interface.git - dependencies: - - apb - - axi - - common_cells - - common_verification tech_cells_generic: revision: 3a3de73632a06826b1bd9c65a0a2e92b32016845 version: 0.2.14 diff --git a/Bender.yml b/Bender.yml index abab04b..5fe4ce8 100644 --- a/Bender.yml +++ b/Bender.yml @@ -25,26 +25,27 @@ remotes: pulp: "https://github.com/pulp-platform" dependencies: + apb: { version: 0.2.4 } common_cells: { version: 1.40.0 } common_verification: { version: 0.2.5 } - register_interface: { version: 0.4.7 } sources: - src/clic_pkg.sv - src/clicint_reg_pkg.sv - - src/clicint_reg_top.sv + - src/clicint_reg.sv - src/clicintv_reg_pkg.sv - - src/clicintv_reg_top.sv + - src/clicintv_reg.sv - src/clicvs_reg_pkg.sv - - src/clicvs_reg_top.sv - - src/mclic_reg_pkg.sv - - src/mclic_reg_top.sv + - src/clicvs_reg.sv + - src/cliccfg_reg_pkg.sv + - src/cliccfg_reg.sv - src/clic_reg_adapter.sv - src/clic_gateway.sv - src/clic_target.sv - - src/clic_apb.sv - src/clic.sv - target: test_clic + include_dirs: + - test files: - test/tb_clic.sv diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSES/Apache-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/LICENSES/SHL-0.51.txt b/LICENSES/SHL-0.51.txt new file mode 100644 index 0000000..548639d --- /dev/null +++ b/LICENSES/SHL-0.51.txt @@ -0,0 +1,65 @@ +SOLDERPAD HARDWARE LICENSE version 0.51 + +This license is based closely on the Apache License Version 2.0, but is not approved or endorsed by the Apache Foundation. A copy of the non-modified Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0. + +As this license is not currently OSI or FSF approved, the Licensor permits any Work licensed under this License, at the option of the Licensee, to be treated as licensed under the Apache License Version 2.0 (which is so approved). + +This License is licensed under the terms of this License and in particular clause 7 below (Disclaimer of Warranties) applies in relation to its use. + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the Rights owner or entity authorized by the Rights owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Rights" means copyright and any similar right including design right (whether registered or unregistered), semiconductor topography (mask) rights and database rights (but excluding Patents and Trademarks). + +"Source" form shall mean the preferred form for making modifications, including but not limited to source code, net lists, board layouts, CAD files, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, the instantiation of a hardware design and conversions to other media types, including intermediate forms such as bytecodes, FPGA bitstreams, artwork and semiconductor topographies (mask works). + +"Work" shall mean the work of authorship, whether in Source form or other Object form, made available under the License, as indicated by a Rights notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) or physically connect to or interoperate with the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any design or work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the Rights owner or by an individual or Legal Entity authorized to submit on behalf of the Rights owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the Rights owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable license under the Rights to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form and do anything in relation to the Work as if the Rights did not exist. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and + + 2. You must cause any modified files to carry prominent notices stating that You changed the files; and + + 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply this license to your work + +To apply this license to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] Copyright and related rights are licensed under the Solderpad Hardware License, Version 0.51 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law or agreed to in writing, software, hardware and materials distributed under this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. diff --git a/Makefile b/Makefile index 472d77a..584f29c 100644 --- a/Makefile +++ b/Makefile @@ -20,8 +20,15 @@ VERILATOR ?= $(OSEDA) verilator QUESTA ?= questa-2025.3 VSIM ?= $(QUESTA) vsim +# clic.mk defaults PEAKRDL to a bare `peakrdl`, since an importing project +# supplies its own. Standalone, this repository provisions the pinned version +# with uv. Set before the include so the fragment's ?= does not override it. +PEAKRDL ?= uv run --group regs peakrdl + TB := tb_clic +RDL_DIR := rdl +SRC_DIR := src TEST_DIR := test VLT_DIR := $(TEST_DIR)/verilator VSIM_DIR := $(TEST_DIR)/vsim @@ -44,22 +51,62 @@ TB_PARAMS := N_SOURCE INTCTLBITS SSCLIC USCLIC VSCLIC N_VSCTXTS VSPRIO VSPRIO_W PARAM_FLAGS := $(foreach p,$(TB_PARAMS),-G$(p)=$($(p))) -.PHONY: all vlt-sim vsim-sim checkout clean +.PHONY: all vlt-sim vsim-sim checkout regs clean all: vlt-sim checkout: $(BENDER) checkout +############## +# Registers # +############## + +# Memory-map views come from clic.mk, the fragment a superproject imports. Here +# it only serves the testbench, so CLIC_ROOT is this repository. + +CLIC_ROOT := . +CLIC_NUM_SOURCES := 4096 +CLIC_NUM_VSCTXTS := 64 +CLIC_VSCLIC := 1 +# 2**ceil(log2((2 + 64) * 32KiB)) = 4MiB, matching ADDR_W in clic.sv at 64 contexts. +CLIC_WINDOW_SIZE := 0x400000 +CLIC_DEFS := $(TEST_DIR)/clic_reg_defs.svh + +include clic.mk + +# RTL register block generation. This is a maintainer target, not part of +# clic.mk: the blocks take no elaboration-time parameters, so they are identical +# for every configuration and are checked into src/. A superproject consumes +# them through Bender and never regenerates them; only a change to a .rdl file +# requires running this. +# +# --cpuif apb4-flat individual APB4 ports rather than a SystemVerilog +# interface, so clic.sv can fan the channel out itself +# --default-reset arst_n match the asynchronous active-low rst_ni used +# throughout the IP +REGBLOCK_FLAGS ?= --cpuif apb4-flat --default-reset arst_n + +REG_BLOCKS := cliccfg clicint clicintv clicvs +REG_SRCS := $(foreach b,$(REG_BLOCKS),$(SRC_DIR)/$(b)_reg.sv $(SRC_DIR)/$(b)_reg_pkg.sv) + +# PeakRDL emits no license header and regblock has no option for one, so it is +# prepended afterwards. +REG_LICENSE := // Copyright 2026 ETH Zurich and University of Bologna.\n// Licensed under the Apache License, Version 2.0, see LICENSE for details.\n// SPDX-License-Identifier: Apache-2.0\n + +regs: $(REG_SRCS) + +$(SRC_DIR)/%_reg.sv $(SRC_DIR)/%_reg_pkg.sv: $(RDL_DIR)/%.rdl $(RDL_DIR)/clic_regs.rdl + $(PEAKRDL) regblock $< -o $(SRC_DIR) -I $(RDL_DIR) $(REGBLOCK_FLAGS) \ + --module-name $*_reg --package-name $*_reg_pkg + @sed -i '1i$(REG_LICENSE)' $(SRC_DIR)/$*_reg.sv $(SRC_DIR)/$*_reg_pkg.sv + ############## # Verilator # ############## # Verilator resolves parameters at compile time, so every distinct parameter set -# needs its own build. Keying the object directory on all of them means `make -# vlt-sim N_SOURCE=256` rebuilds instead of silently re-running the previous -# binary. The tag is the parameter values joined in TB_PARAMS order, so the -# defaults give obj_16_8_1_0_1_4_1_1. +# needs its own build. empty := space := $(empty) $(empty) VLT_OBJ := obj_$(subst $(space),_,$(strip $(foreach p,$(TB_PARAMS),$($(p))))) @@ -83,7 +130,7 @@ $(VLT_DIR): $(VLT_DIR)/sources.f: Bender.yml Bender.lock | $(VLT_DIR) $(BENDER) script verilator $(BENDER_TARGETS) > $@ -$(VLT_BIN): $(VLT_DIR)/sources.f $(wildcard src/*.sv) $(wildcard test/*.sv) +$(VLT_BIN): $(VLT_DIR)/sources.f $(CLIC_DEFS) $(wildcard src/*.sv) $(wildcard test/*.sv) @echo "verilating $(TB) ($(PARAM_FLAGS))..." @mkdir -p $(VLT_DIR)/$(VLT_OBJ) @$(VERILATOR) $(VLT_FLAGS) -f $(VLT_DIR)/sources.f > $(VLT_BUILD_LOG) 2>&1 || \ @@ -104,7 +151,7 @@ $(VSIM_DIR): $(VSIM_DIR)/compile.tcl: Bender.yml Bender.lock | $(VSIM_DIR) $(BENDER) script vsim $(BENDER_TARGETS) -t simulation > $@ -$(VSIM_DIR)/compiled.stamp: $(VSIM_DIR)/compile.tcl $(wildcard src/*.sv) $(wildcard test/*.sv) +$(VSIM_DIR)/compiled.stamp: $(VSIM_DIR)/compile.tcl $(CLIC_DEFS) $(wildcard src/*.sv) $(wildcard test/*.sv) cd $(VSIM_DIR) && $(VSIM) -c -do "source compile.tcl; quit" | tee compile.log @if grep -qE "^# Errors: [1-9]" $(VSIM_DIR)/compile.log; then \ echo "COMPILATION FAILED"; grep -E "^# \*\* Error" $(VSIM_DIR)/compile.log; false; \ @@ -116,5 +163,5 @@ vsim-sim: $(VSIM_DIR)/compiled.stamp -sv_seed $(SEED) $(TB) -do "run -all; quit" | tee sim.log @grep -q " result : PASS" $(VSIM_DIR)/sim.log || (echo "SIMULATION FAILED"; false) -clean: +clean: clic-clean rm -rf $(VLT_DIR) $(VSIM_DIR) diff --git a/README.md b/README.md index 524f116..c88917c 100644 --- a/README.md +++ b/README.md @@ -54,16 +54,16 @@ CLICXCSW 0-1 (depends on core) Has xscratchcsw/xscratchcswl This IP requires - [common_cells](https://github.com/pulp-platform/common_cells) -- [register_interface](https://github.com/pulp-platform/register_interface) and a suitably modified core (see sections below). The [bender](https://github.com/pulp-platform/bender) and legacy [IPApproX](https://github.com/pulp-platform/IPApproX) flow are supported. -Besides the native -[register_interface](https://github.com/pulp-platform/register_interface) there -is an APB wrapper available. +`clic.sv` is an APB4 device: it exposes `psel_i`, `penable_i`, `pwrite_i`, +`pprot_i`, `paddr_i`, `pwdata_i`, `pstrb_i`, `pready_o`, `prdata_o` and +`pslverr_o` directly, and there is no separate bus wrapper. Byte strobes are +honoured, so sub-word writes work. ## CLIC and CV32E40P @@ -95,36 +95,130 @@ complete level/priority implementation in the works. ## Register interface The CLIC's register files are generated with -[regtool](https://docs.opentitan.org/doc/rm/register_tool/) and checked into -`src/`, so by default they require no attention of the user. - -To regenerate them, go to `src/gen/` and call `make all` with the environment -variable `REGTOOL` pointing to `regtool.py` of the -[register_interface](https://github.com/pulp-platform/register_interface) -repository, e.g. +[PeakRDL-regblock](https://github.com/SystemRDL/PeakRDL-regblock) from the +SystemRDL descriptions in `rdl/`, and are checked into `src/`, so by default +they require no attention of the user. + +`rdl/clic_regs.rdl` defines the register *types* and instantiates nothing, so +the bit layout of every register exists in exactly one place. Everything else +only chooses how to instantiate those types: + +- the four leaf wrappers put one register at offset 0 and are fed to + `peakrdl regblock` to produce the RTL in `src/`; +- `rdl/clic.rdl` puts the same types at their real addresses to describe the + software-visible memory map, and is never fed to `regblock`. + +Each leaf wrapper yields one module, instantiated as follows: + +- `cliccfg.rdl` -> `cliccfg_reg`, instantiated once. This is the `cliccfg` + register of the specification; the decoder aliases the single instance into + both the M-mode window (`0x0000`) and the S-mode window (`0x8000`), which is + why it is not named after either privilege mode. +- `clicint.rdl` -> `clicint_reg`, one instance per interrupt line. The field bit + positions match the specification's four byte-wide registers: `clicintip` at + bit 0, `clicintie` at bit 8, `clicintattr` at bits 23:16 and `clicintctl` at + bits 31:24. +- `clicintv.rdl` -> `clicintv_reg`, one instance per four interrupt lines + (vCLIC extension, not part of the specification snapshot in `doc/`). +- `clicvs.rdl` -> `clicvs_reg`, one instance per four VS contexts (likewise a + vCLIC extension). + +To regenerate them after editing a `.rdl` file: ```console - make REGTOOL=/path/to/register_interface/vendor/lowrisc_opentitan/util/regtool.py + make regs ``` -This generates the SystemVerilog register files and the corresponding C headers -from the memory map descriptions in `src/gen/*.hjson`. Afterwards, `make -install` copies the generated SystemVerilog files into `src/`, where -`Bender.yml` and `src_files.yml` pick them up. +PeakRDL is pinned in `pyproject.toml` and provisioned by +[uv](https://docs.astral.sh/uv/) on demand, so no manual setup is needed. The +generated blocks are written straight into `src/`, where `Bender.yml` and +`src_files.yml` pick them up. Note that the number of interrupt lines is not baked into the generated -register files: the CLIC instantiates one register block per interrupt and -scales with the `N_SOURCE` parameter of `clic.sv`. +register files: each leaf `.rdl` describes a single 32-bit register, the CLIC +instantiates one such block per interrupt line, and the whole array scales with +the `N_SOURCE` parameter of `clic.sv`. The RTL blocks therefore carry no +elaboration-time parameters, and regenerating them never depends on how the IP +is configured. Only the software views do. + +### Using this from a superproject +The memory-map export rules live in `clic.mk`, which is meant to be imported: + +```make + CLIC_ROOT ?= $(shell bender path clic) + include $(CLIC_ROOT)/clic.mk +``` + +It provides two targets, both views of the same memory map: + +- `clic-hdr` writes a C header to `$(CLIC_HDR)`. +- `clic-defs` writes a SystemVerilog `` `define `` header to `$(CLIC_DEFS)`. + +Neither is checked in, because both depend on how the IP is configured. Set +`CLIC_NUM_SOURCES`, `CLIC_NUM_VSCTXTS` and `CLIC_VSCLIC` to match your +instantiation and point `CLIC_HDR` / `CLIC_DEFS` wherever you want the output. + +`PEAKRDL` defaults to a bare `peakrdl` on `PATH`, as in `cheshire.mk` and +`clint.mk`: the importing project supplies the tool, so everything it generates +comes from one PeakRDL rather than this IP quietly running a second one. To use +the version pinned here instead, set +`PEAKRDL := uv run --project $(CLIC_ROOT) --group regs peakrdl`. + +There is deliberately no RTL generation target in the fragment. The register +blocks take no elaboration-time parameters, so they are identical for every +configuration and are checked into `src/`: a superproject consumes them through +Bender and never regenerates them. `make regs` in this repository's top-level +Makefile covers that, and is only needed when a `.rdl` file changes. + +To pull the register definitions into a larger address map instead, include +`rdl/clic_regs.rdl` (for the register types) or `rdl/clic.rdl` (for the whole +CLIC map) from your own SystemRDL and pass `-I $(CLIC_ROOT)/rdl`. Both files +are include-guarded. This is how a SoC-level address map can describe the CLIC +without restating any of its registers. + +This repository eats its own dog food: `tb_clic.sv` takes every register +address from a generated `clic_reg_defs.svh` rather than restating them, so a +disagreement between `rdl/clic.rdl` and the decoder in `clic.sv` shows up as a +test failure. + +### What is deliberately not in the register description +SystemRDL has no notion of the address window an access arrived through, so +everything that depends on it lives in the decoder in `clic.sv` rather than in +the generated blocks: + +- the same `clicint` storage is aliased into the M-mode window, the S-mode + window and one window per VS context; +- whether an access is permitted depends on the *contents* of other registers + (`attr_mode`, and for the VS windows also the `v` and `vsid` fields), so an + S-mode or VS-mode access to a line above its privilege is dropped and reads + back as zero; +- `clicint` bit 23 is forced low outside the M-mode window, so a line cannot be + promoted to M-mode from a less privileged window. + +This was equally true of the previous regtool-based flow; the register +generator never owned any of it. ## Directory Structure ``` . ├── doc CLIC spec, Blockdiagrams -├── src RTL -├── src/gen Register map descriptions (hjson) and generation Makefile +├── rdl Register map descriptions (SystemRDL) +├── src RTL, including the generated register blocks +├── test Testbench +├── clic.mk Register generation rules, importable by a superproject ``` ## License -This project uses sourcecode from lowRISC licensed under Apache 2.0. The changes -and additions are being made available using Apache 2.0 see LICENSE for more -details. +This project is licensed under a mix of Apache 2.0 and the Solderpad Hardware +License 0.51, with the applicable license recorded in each file's +`SPDX-License-Identifier` tag. Full texts are in `LICENSES/`. + +- **Apache 2.0** covers everything derived from lowRISC sources (`clic.sv`, + `clic_gateway.sv`, `clic_target.sv`, which carry the lowRISC copyright and + are upstream Apache 2.0), the register blocks generated from `rdl/`, the + SystemRDL descriptions themselves, and all build and tooling files. +- **Solderpad 0.51** covers the hardware written entirely at ETH Zurich and the + University of Bologna (`clic_pkg.sv`, `clic_reg_adapter.sv`, `tb_clic.sv`). + +The root `LICENSE` file remains Apache 2.0, which is the license of the +majority of the project and of the lowRISC code it builds on. diff --git a/clic.mk b/clic.mk new file mode 100644 index 0000000..bd8229e --- /dev/null +++ b/clic.mk @@ -0,0 +1,82 @@ +# Copyright 2026 ETH Zurich and University of Bologna. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# Import this GNU Make fragment in your project's makefile to derive views of +# the CLIC memory map for your configuration: +# +# CLIC_ROOT ?= $(shell bender path clic) +# include $(CLIC_ROOT)/clic.mk +# +# Targets: +# clic-hdr generate a C header for the CLIC memory map -> $(CLIC_HDR) +# clic-defs generate a SystemVerilog `define header for it -> $(CLIC_DEFS) +# +# Both are generated from rdl/clic.rdl and describe the same thing in different +# formats. They are not checked in, because they depend on how the IP is +# configured: set CLIC_NUM_SOURCES, CLIC_NUM_VSCTXTS and CLIC_VSCLIC to match +# your instantiation, and CLIC_HDR / CLIC_DEFS to where you want the output. +# +# To pull the register definitions into a larger address map instead of +# exporting a header, include rdl/clic_regs.rdl (register types) or rdl/clic.rdl +# (the whole CLIC map) from your own SystemRDL and pass -I $(CLIC_ROOT)/rdl. + +BENDER ?= bender +CLIC_ROOT ?= $(shell $(BENDER) path clic) + +# Supplied by the importing project, so that everything it generates comes from +# one PeakRDL rather than this IP quietly running a second one. To use the +# version pinned in this repository's pyproject.toml instead, set +# PEAKRDL := uv run --project $(CLIC_ROOT) --group regs peakrdl +PEAKRDL ?= peakrdl + +# Must match the parameters the CLIC is instantiated with. +CLIC_NUM_SOURCES ?= 256 +CLIC_NUM_VSCTXTS ?= 4 +CLIC_VSCLIC ?= 1 + +# Size of the address window the CLIC claims, which is larger than the registers +# in it: clic.sv decodes paddr[ADDR_W-1:0] with +# ADDR_W = $clog2((N_VSCTXTS + 2) * 32 * 1024) +# so this must be 2**ADDR_W. SystemRDL has no clog2, so it cannot be derived +# from CLIC_NUM_VSCTXTS here. The default covers 1..6 VS contexts; raise it in +# step with CLIC_NUM_VSCTXTS (64 contexts need 0x400000). Too small a value is +# reported by PeakRDL as an overlap rather than silently truncating. +CLIC_WINDOW_SIZE ?= 0x40000 + +CLIC_RDL_DIR := $(CLIC_ROOT)/rdl + +# Where the generated views land. Override from the superproject. +CLIC_HDR ?= $(CLIC_ROOT)/clic_regs.h +CLIC_DEFS ?= $(CLIC_ROOT)/test/clic_reg_defs.svh + +# Every description shares the register definitions in clic_regs.rdl, so a +# change there must regenerate everything. +CLIC_RDL_DEPS := $(CLIC_RDL_DIR)/clic_regs.rdl + +CLIC_MAP_FLAGS := -P NumSources=$(CLIC_NUM_SOURCES) -P NumVsCtxts=$(CLIC_NUM_VSCTXTS) +CLIC_MAP_FLAGS += -P WindowSize=$(CLIC_WINDOW_SIZE) +ifeq ($(CLIC_VSCLIC),1) +CLIC_MAP_FLAGS += -D CLIC_VSCLIC +endif + +CLIC_LICENSE_STR := Copyright 2026 ETH Zurich and University of Bologna.\nLicensed under the Apache License, Version 2.0, see LICENSE for details.\nSPDX-License-Identifier: Apache-2.0 + +.PHONY: clic-hdr clic-defs clic-clean + +clic-hdr: $(CLIC_HDR) + +clic-defs: $(CLIC_DEFS) + +$(CLIC_HDR): $(CLIC_RDL_DIR)/clic.rdl $(CLIC_RDL_DEPS) + @mkdir -p $(dir $@) + $(PEAKRDL) raw-header $< -o $@ -I $(CLIC_RDL_DIR) --format c $(CLIC_MAP_FLAGS) \ + --license_str "$(CLIC_LICENSE_STR)" + +$(CLIC_DEFS): $(CLIC_RDL_DIR)/clic.rdl $(CLIC_RDL_DEPS) + @mkdir -p $(dir $@) + $(PEAKRDL) raw-header $< -o $@ -I $(CLIC_RDL_DIR) --format svh $(CLIC_MAP_FLAGS) \ + --license_str "$(CLIC_LICENSE_STR)" + +clic-clean: + rm -f $(CLIC_HDR) $(CLIC_DEFS) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..6d532e4 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,38 @@ +# Copyright 2026 ETH Zurich and University of Bologna. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +# This repository ships no Python code; this project exists only to pin the +# Python tooling used by the register generation flow. The generated register +# files are checked into src/, so this is only needed when regenerating them: +# run `make regs`. + +[project] +name = "clic" +version = "0" +description = "Tooling environment for the RISC-V CLIC hardware IP" +requires-python = ">=3.12" +dependencies = [] + +[dependency-groups] +regs = [ + "peakrdl==1.5.0", + "peakrdl-regblock==1.3.1", + "peakrdl-rawheader==0.2.2", +] + +[tool.uv] +# Nothing here is importable or installable, so do not try to build a wheel. +package = false diff --git a/rdl/clic.rdl b/rdl/clic.rdl new file mode 100644 index 0000000..596c1a6 --- /dev/null +++ b/rdl/clic.rdl @@ -0,0 +1,115 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// CLIC software-visible memory map. +// +// This describes what software sees, not how the RTL is built. The RTL +// instantiates one single-register block per interrupt line and resolves the +// windows below in the decoder of clic.sv, which is why this file is never fed +// to `peakrdl regblock`. It exists so that headers, documentation and +// superproject address maps are generated from the same register definitions +// as the RTL (see clic_regs.rdl) rather than restating them. +// +// The address range is divided into blocks of 32KiB: one for M-mode, one for +// S-mode, and up to 64 more, one per guest VS context. +// +// M_MODE : [0x000000 - 0x007fff] +// S_MODE : [0x008000 - 0x00ffff] +// VS_1 : [0x010000 - 0x017fff] +// VS_2 : [0x018000 - 0x01ffff] +// : +// VS_64 : [0x208000 - 0x20ffff] +// +// The same clicint storage is reachable through the M-mode window, the S-mode +// window and every VS window. Those are genuine aliases in hardware, but they +// are modelled here as separate instances because software really does address +// them separately and the access rules differ per window: an S-mode or VS-mode +// access to a line configured above its privilege is dropped and reads back as +// zero. That filtering depends on the contents of other registers and cannot be +// expressed in SystemRDL at all -- see the README. +// +// Parameters: +// NumSources number of implemented interrupt lines (N_SOURCE in clic.sv) +// NumVsCtxts number of implemented VS contexts (N_VSCTXTS in clic.sv) +// +// Define CLIC_VSCLIC to include the virtualization registers and VS windows, +// matching the VSCLIC parameter of clic.sv. + +`ifndef CLIC_RDL +`define CLIC_RDL + +`include "clic_regs.rdl" + +// Machine-mode window: configuration plus the interrupt control registers. +regfile clic_m_window_t #( longint unsigned NumSources = 256 ) { + desc = "CLIC machine mode window"; + cliccfg_t cliccfg @ 0x0000; + clicint_t clicint[NumSources] @ 0x1000 += 0x4; +}; + +// Supervisor-mode window: the same configuration and interrupt control +// registers, plus the vCLIC virtualization and VS priority registers, which are +// reachable only from here. +regfile clic_s_window_t #( + longint unsigned NumSources = 256, + longint unsigned NumIntv = 64, + longint unsigned NumVsPrio = 16 +) { + desc = "CLIC supervisor mode window"; + cliccfg_t cliccfg @ 0x0000; + clicint_t clicint[NumSources] @ 0x1000 += 0x4; +`ifdef CLIC_VSCLIC + clicintv_t clicintv[NumIntv] @ 0x5000 += 0x4; + vsprio_t vsprio[NumVsPrio] @ 0x6000 += 0x4; +`endif +}; + +`ifdef CLIC_VSCLIC +// Virtual-supervisor window: interrupt control registers only. One per guest. +regfile clic_vs_window_t #( longint unsigned NumSources = 256 ) { + desc = "CLIC virtual supervisor window"; + clicint_t clicint[NumSources] @ 0x1000 += 0x4; +}; +`endif + +addrmap clic #( + longint unsigned NumSources = 256, + longint unsigned NumVsCtxts = 4, + longint unsigned WindowSize = 0x40000 +) { + name = "CLIC"; + desc = "RISC-V Core Local Interrupt Controller"; + + default regwidth = 32; + default accesswidth = 32; + + clic_m_window_t #( .NumSources(NumSources) ) m @ 0x0000; + + // NumIntv is ceil(NumSources / 4): one clicintv register per four lines. + clic_s_window_t #( + .NumSources(NumSources), + .NumIntv((NumSources + 3) / 4), + .NumVsPrio(16) + ) s @ 0x8000; + +`ifdef CLIC_VSCLIC + clic_vs_window_t #( .NumSources(NumSources) ) vs[NumVsCtxts] @ 0x10000 += 0x8000; +`endif + + // The windows above occupy (2 + NumVsCtxts) * 32KiB, but the RTL decodes a + // power-of-two window: clic.sv slices paddr[ADDR_W-1:0] with + // ADDR_W = $clog2((N_VSCTXTS + 2) * 32 * 1024) + // and answers anything in that slice, returning zero above the last window. + // WindowSize must equal 2**ADDR_W so this map describes the range the + // hardware really claims. SystemRDL has no clog2, so it cannot be derived + // here: an integrator changing NumVsCtxts must set it too. The default suits + // 1..6 VS contexts, which is the common case and matches the per-hart stride + // an SoC needs when instantiating one CLIC per hart. A value smaller than the + // windows above is rejected by the compiler as an overlap. + // + // The sentinel is what fixes the size; it is not a real register. + external reg { field {} _end[31:0] = 0; } _end @ (WindowSize - 4); +}; + +`endif // CLIC_RDL diff --git a/rdl/clic_regs.rdl b/rdl/clic_regs.rdl new file mode 100644 index 0000000..567573c --- /dev/null +++ b/rdl/clic_regs.rdl @@ -0,0 +1,156 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// CLIC register type definitions. +// +// This file defines register *types* and instantiates nothing, so it is the +// single source of truth for the bit layout of every CLIC register. It is +// included by two kinds of consumer: +// +// - the leaf wrappers in this directory (cliccfg.rdl, clicint.rdl, ...), +// each of which instantiates one type at offset 0 and is fed to +// `peakrdl regblock` to produce the RTL in src/; +// - clic.rdl, which instantiates the same types at their real addresses to +// describe the software-visible memory map. +// +// A superproject (Cheshire, for example) can include this file directly to +// reuse the register definitions without pulling in either topology. + +`ifndef CLIC_REGS_RDL +`define CLIC_REGS_RDL + +// CLIC interrupt pending, enable, attribute and control. +// +// The field positions mirror the four byte-wide registers of the +// specification: clicintip at bit 0, clicintie at bit 8, clicintattr at bits +// 23:16 and clicintctl at bits 31:24. +reg clicint_t { + name = "CLICINT"; + desc = "CLIC interrupt pending, enable, attribute and control"; + + regwidth = 32; + accesswidth = 32; + + // Pending is driven by the gateway every cycle (`we` is tied high in + // clic_reg_adapter), but a software write in the same cycle must win so that + // writing IP can raise a software interrupt. `precedence = sw` is what the + // OpenTitan prim_subreg arbiter did with SWACCESS="RW": + // wr_data = we ? wd : d // SW higher priority + field { + desc = "interrupt pending for interrupt"; + sw = rw; + hw = rw; + we; + precedence = sw; + } ip[0:0] = 0; + + field { + desc = "interrupt enable for interrupt"; + sw = rw; + hw = r; + } ie[8:8] = 0; + + field { + desc = "enable hardware vectoring for this interrupt"; + sw = rw; + hw = r; + } attr_shv[16:16] = 0; + + field { + desc = "specify trigger type for this interrupt"; + sw = rw; + hw = r; + } attr_trig[18:17] = 0; + + field { + desc = "privilege mode of this interrupt"; + sw = rw; + hw = r; + } attr_mode[23:22] = 3; + + field { + desc = "interrupt control for interrupt"; + sw = rw; + hw = r; + } ctl[31:24] = 0; +}; + +// CLIC configuration (`cliccfg` in the specification). +// +// Note: the hjson this replaces carried an explicit read-only "reserved" field +// over bits 31:28 to work around regtool rejecting full 32-bit writes to a +// register whose fields did not cover the whole word. PeakRDL drops writes to +// unmapped bits and reads them as zero, so no such placeholder is needed. +reg cliccfg_t { + name = "CLICCFG"; + desc = "CLIC configuration"; + + regwidth = 32; + accesswidth = 32; + + field { + desc = "number of interrupt level bits in machine mode"; + sw = rw; + hw = r; + } mnlbits[3:0] = 0; + + field { + desc = "number of privilege mode bits"; + sw = rw; + hw = r; + } nmbits[5:4] = 0; + + field { + desc = "number of interrupt level bits in supervisor mode"; + sw = rw; + hw = r; + } snlbits[19:16] = 0; + + field { + desc = "number of interrupt level bits in user mode"; + sw = rw; + hw = r; + } unlbits[27:24] = 0; +}; + +// CLIC interrupt virtualization (vCLIC extension). +// +// One register covers four interrupt lines, one per byte lane. Per-lane access +// filtering is applied by the decoder in clic.sv, not here. +reg clicintv_t { + name = "CLICINTV"; + desc = "CLIC interrupt virtualization"; + + regwidth = 32; + accesswidth = 32; + + field { desc = "interrupt delegated to VS-mode"; sw = rw; hw = r; } v0[0:0] = 0; + field { desc = "interrupt VS id"; sw = rw; hw = r; } vsid0[7:2] = 0; + field { desc = "interrupt delegated to VS-mode"; sw = rw; hw = r; } v1[8:8] = 0; + field { desc = "interrupt VS id"; sw = rw; hw = r; } vsid1[15:10] = 0; + field { desc = "interrupt delegated to VS-mode"; sw = rw; hw = r; } v2[16:16] = 0; + field { desc = "interrupt VS id"; sw = rw; hw = r; } vsid2[23:18] = 0; + field { desc = "interrupt delegated to VS-mode"; sw = rw; hw = r; } v3[24:24] = 0; + field { desc = "interrupt VS id"; sw = rw; hw = r; } vsid3[31:26] = 0; +}; + +// CLIC virtual supervisor priority (vCLIC extension). +// +// One register covers four VS contexts, one per byte lane. The field width +// here fixes the usable range of the VSPRIO_W parameter of clic.sv: widening a +// priority field means widening it here too. +reg vsprio_t { + name = "VSPRIO"; + desc = "CLIC virtual supervisor priority"; + + regwidth = 32; + accesswidth = 32; + + field { desc = "VS0 priority"; sw = rw; hw = r; } prio0[0:0] = 0; + field { desc = "VS1 priority"; sw = rw; hw = r; } prio1[8:8] = 0; + field { desc = "VS2 priority"; sw = rw; hw = r; } prio2[16:16] = 0; + field { desc = "VS3 priority"; sw = rw; hw = r; } prio3[24:24] = 0; +}; + +`endif // CLIC_REGS_RDL diff --git a/rdl/cliccfg.rdl b/rdl/cliccfg.rdl new file mode 100644 index 0000000..46497bc --- /dev/null +++ b/rdl/cliccfg.rdl @@ -0,0 +1,14 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Leaf wrapper: one cliccfg_t at offset 0, fed to `peakrdl regblock` to produce +// src/cliccfg_reg.sv. The block decodes nothing above bit 1; selecting which +// interrupt line or VS context an access targets is done by clic.sv. See +// clic_regs.rdl for the register definition and clic.rdl for the memory map. + +`include "clic_regs.rdl" + +addrmap cliccfg { + cliccfg_t cliccfg @ 0x0; +}; diff --git a/rdl/clicint.rdl b/rdl/clicint.rdl new file mode 100644 index 0000000..86a990b --- /dev/null +++ b/rdl/clicint.rdl @@ -0,0 +1,14 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Leaf wrapper: one clicint_t at offset 0, fed to `peakrdl regblock` to produce +// src/clicint_reg.sv. The block decodes nothing above bit 1; selecting which +// interrupt line or VS context an access targets is done by clic.sv. See +// clic_regs.rdl for the register definition and clic.rdl for the memory map. + +`include "clic_regs.rdl" + +addrmap clicint { + clicint_t clicint @ 0x0; +}; diff --git a/rdl/clicintv.rdl b/rdl/clicintv.rdl new file mode 100644 index 0000000..4823812 --- /dev/null +++ b/rdl/clicintv.rdl @@ -0,0 +1,14 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Leaf wrapper: one clicintv_t at offset 0, fed to `peakrdl regblock` to produce +// src/clicintv_reg.sv. The block decodes nothing above bit 1; selecting which +// interrupt line or VS context an access targets is done by clic.sv. See +// clic_regs.rdl for the register definition and clic.rdl for the memory map. + +`include "clic_regs.rdl" + +addrmap clicintv { + clicintv_t clicintv @ 0x0; +}; diff --git a/rdl/clicvs.rdl b/rdl/clicvs.rdl new file mode 100644 index 0000000..69cda70 --- /dev/null +++ b/rdl/clicvs.rdl @@ -0,0 +1,14 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Leaf wrapper: one vsprio_t at offset 0, fed to `peakrdl regblock` to produce +// src/clicvs_reg.sv. The block decodes nothing above bit 1; selecting which +// interrupt line or VS context an access targets is done by clic.sv. See +// clic_regs.rdl for the register definition and clic.rdl for the memory map. + +`include "clic_regs.rdl" + +addrmap clicvs { + vsprio_t vsprio @ 0x0; +}; diff --git a/src/clic.sv b/src/clic.sv index dd6fe9d..cf7d58a 100644 --- a/src/clic.sv +++ b/src/clic.sv @@ -1,5 +1,5 @@ // Copyright lowRISC contributors. -// Copyright 2025 ETH Zurich and University of Bologna. +// Copyright 2026 ETH Zurich and University of Bologna. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,14 +19,12 @@ module clic import clic_pkg::*; - import mclic_reg_pkg::*; + import cliccfg_reg_pkg::*; import clicint_reg_pkg::*; import clicintv_reg_pkg::*; import clicvs_reg_pkg::*; import cf_math_pkg::*; #( - parameter type reg_req_t = logic, - parameter type reg_rsp_t = logic, parameter int N_SOURCE = 256, parameter int INTCTLBITS = 8, parameter bit SSCLIC = 0, @@ -40,15 +38,19 @@ module clic parameter bit VSPRIO = 0, // Enable VS prioritization (requires VSCLIC) parameter int VSPRIO_W = 1, // N of VS priority bits (must be set accordingly to the `clicvs` register width) + // APB4 request and response types + parameter type apb_req_t = logic, + parameter type apb_rsp_t = logic, + // do not edit below, these are derived localparam int SRC_W = $clog2(N_SOURCE) )( input logic clk_i, input logic rst_ni, - // Bus Interface (device) - input reg_req_t reg_req_i, - output reg_rsp_t reg_rsp_o, + // Bus Interface (APB4 device) + input apb_req_t apb_req_i, + output apb_rsp_t apb_rsp_o, // Interrupt Sources input [N_SOURCE-1:0] intr_src_i, @@ -83,6 +85,9 @@ module clic localparam logic [1:0] S_MODE = 2'b01; localparam logic [1:0] M_MODE = 2'b11; + localparam int unsigned N_INTV = ceil_div(N_SOURCE, 4); + localparam int unsigned N_VS = MAX_VSCTXTS / 4; + /////////////////////////////////////////////////// // CLIC internal addressing // /////////////////////////////////////////////////// @@ -102,6 +107,13 @@ module clic // Some value between 16 (VSCLIC = 0) and 22 (64 VS contexts) localparam int unsigned ADDR_W = $clog2((N_VSCTXTS + 2) * 32 * 1024); + // A wider APB address bus is fine, the extra bits are simply never decoded, + // but a narrower one would silently drop part of the window offset. + if ($bits(apb_req_i.paddr) < ADDR_W) + $fatal(1, "apb_req_t address field is too narrow for the configured number of VS contexts"); + if ($bits(apb_req_i.pwdata) != 32) + $fatal(1, "the CLIC is a 32-bit register block; apb_req_t must have 32-bit pwdata"); + // Each privilege mode address space is aligned to a 32KiB physical memory region localparam logic [ADDR_W-1:0] MCLICCFG_START = 'h00000; localparam logic [ADDR_W-1:0] MCLICINT_START = 'h01000; @@ -320,15 +332,15 @@ module clic VSCLICCFG_START[63] + 'h04fff }; - mclic_reg2hw_t mclic_reg2hw; + // Hardware interfaces of the generated register blocks + cliccfg_reg_pkg::cliccfg__out_t cliccfg_hwif_out; - clicint_reg2hw_t [N_SOURCE-1:0] clicint_reg2hw; - clicint_hw2reg_t [N_SOURCE-1:0] clicint_hw2reg; + clicint_reg_pkg::clicint__in_t clicint_hwif_in [N_SOURCE]; + clicint_reg_pkg::clicint__out_t clicint_hwif_out [N_SOURCE]; - clicintv_reg2hw_t [ceil_div(N_SOURCE, 4)-1:0] clicintv_reg2hw; - - clicvs_reg2hw_t [(MAX_VSCTXTS/4)-1:0] clicvs_reg2hw; + clicintv_reg_pkg::clicintv__out_t clicintv_hwif_out [N_INTV]; + clicvs_reg_pkg::clicvs__out_t clicvs_hwif_out [N_VS]; logic [7:0] intctl [N_SOURCE]; logic [7:0] irq_max; @@ -349,6 +361,25 @@ module clic logic [N_SOURCE-1:0] claim; + // Unpacked once here so the decoder below can keep working on flat signals. + logic psel, penable, pwrite; + logic [2:0] pprot; + logic [31:0] pwdata; + logic [3:0] pstrb; + logic pready, pslverr; + logic [31:0] prdata; + + assign psel = apb_req_i.psel; + assign penable = apb_req_i.penable; + assign pwrite = apb_req_i.pwrite; + assign pprot = apb_req_i.pprot; + assign pwdata = apb_req_i.pwdata; + assign pstrb = apb_req_i.pstrb; + + assign apb_rsp_o.pready = pready; + assign apb_rsp_o.prdata = prdata; + assign apb_rsp_o.pslverr = pslverr; + // handle incoming interrupts clic_gateway #( .N_SOURCE (N_SOURCE) @@ -403,314 +434,411 @@ module clic .irq_kill_ack_i ); - // configuration registers - // 0x0000 (machine mode) - reg_req_t reg_mclic_req; - reg_rsp_t reg_mclic_rsp; - - mclic_reg_top #( - .reg_req_t (reg_req_t), - .reg_rsp_t (reg_rsp_t) - ) i_mclic_reg_top ( - .clk_i, - .rst_ni, - - .reg_req_i (reg_mclic_req), - .reg_rsp_o (reg_mclic_rsp), - - .reg2hw (mclic_reg2hw), - - .devmode_i (1'b1) + /////////////////////////////////////////////////// + // Bus fan-out // + /////////////////////////////////////////////////// + // + // Every generated block is a leaf holding a single 32-bit register, so all of + // them share one APB channel and are distinguished only by their select line. + // The decoder below drives at most one select at a time and picks the + // matching response. + // + // Two things are rewritten on the way down rather than being expressed in the + // register description, because SystemRDL has no notion of which address + // window an access arrived through: + // - CLICINT bit 23 is forced low outside the M-mode window, so a line + // cannot be promoted to M-mode from a less privileged window. + // - CLICINTV lanes belonging to a line above S-mode are zeroed on write and + // read back as zero. + // + // The permission inputs (intmode, intv, vsid) are software-writable only and + // there is a single bus port, so they cannot change underneath a transfer + // that is already in progress. + + // Leaves only ever see the two byte-offset bits; the register index is + // resolved here into a one-hot select. + logic [2:0] leaf_paddr; + assign leaf_paddr = {1'b0, apb_req_i.paddr[1:0]}; + + // cliccfg + logic cliccfg_psel; + logic [31:0] cliccfg_prdata; + logic cliccfg_pready, cliccfg_pslverr; + + // clicint + logic int_psel; + logic [ADDR_W-1:0] int_idx; + logic int_idx_ok; + logic [31:0] int_pwdata; + logic [N_SOURCE-1:0] int_psel_oh; + logic [N_SOURCE-1:0][31:0] int_prdata; + logic [N_SOURCE-1:0] int_pready; + logic [N_SOURCE-1:0] int_pslverr; + logic [31:0] int_sel_prdata; + logic int_sel_pready, int_sel_pslverr; + + // clicintv + logic v_psel; + logic [ADDR_W-1:0] v_idx; + logic v_idx_ok; + logic [31:0] v_pwdata; + logic [3:0] v_lane_ok; // lane belongs to an existing S-mode-or-below line + logic [N_INTV-1:0] v_psel_oh; + logic [N_INTV-1:0][31:0] v_prdata; + logic [N_INTV-1:0] v_pready; + logic [N_INTV-1:0] v_pslverr; + logic [31:0] v_sel_prdata; + logic v_sel_pready, v_sel_pslverr; + + // clicvs + logic vs_psel; + logic [ADDR_W-1:0] vs_idx; + logic vs_idx_ok; + logic [N_VS-1:0] vs_psel_oh; + logic [N_VS-1:0][31:0] vs_prdata; + logic [N_VS-1:0] vs_pready; + logic [N_VS-1:0] vs_pslverr; + logic [31:0] vs_sel_prdata; + logic vs_sel_pready, vs_sel_pslverr; + + // configuration register, aliased into the M-mode and S-mode windows + // 0x0000 (machine mode) and 0x8000 (supervisor mode) + cliccfg_reg i_cliccfg_reg ( + .clk (clk_i), + .arst_n (rst_ni), + + .s_apb_psel (cliccfg_psel), + .s_apb_penable (penable), + .s_apb_pwrite (pwrite), + .s_apb_pprot (pprot), + .s_apb_paddr (leaf_paddr), + .s_apb_pwdata (pwdata), + .s_apb_pstrb (pstrb), + .s_apb_pready (cliccfg_pready), + .s_apb_prdata (cliccfg_prdata), + .s_apb_pslverr (cliccfg_pslverr), + + .hwif_out (cliccfg_hwif_out) ); // interrupt control and status registers (per interrupt line) // 0x1000 - 0x4fff (machine mode) - reg_req_t reg_all_int_req; - reg_rsp_t reg_all_int_rsp; - logic [ADDR_W-1:0] int_addr; - - reg_req_t [N_SOURCE-1:0] reg_int_req; - reg_rsp_t [N_SOURCE-1:0] reg_int_rsp; - - // Check that the address is withing the range of implemented interrupt lines - logic int_addr_ok; - - assign int_addr = reg_all_int_req.addr[ADDR_W-1:2]; - assign int_addr_ok = (int_addr < N_SOURCE); + assign int_idx_ok = (int_idx < N_SOURCE); always_comb begin - reg_int_req = '0; - if (int_addr_ok) reg_int_req[int_addr] = reg_all_int_req; + int_psel_oh = '0; + if (int_psel && int_idx_ok) int_psel_oh[int_idx] = 1'b1; end - always_comb begin - reg_all_int_rsp = '0; - reg_all_int_rsp.ready = 1'b1; - if (int_addr_ok) reg_all_int_rsp = reg_int_rsp[int_addr]; - end + assign int_sel_prdata = int_idx_ok ? int_prdata[int_idx] : 32'h0; + assign int_sel_pready = int_idx_ok ? int_pready[int_idx] : 1'b1; + assign int_sel_pslverr = int_idx_ok ? int_pslverr[int_idx] : 1'b0; for (genvar i = 0; i < N_SOURCE; i++) begin : gen_clic_int - clicint_reg_top #( - .reg_req_t (reg_req_t), - .reg_rsp_t (reg_rsp_t) - ) i_clicint_reg_top ( - .clk_i, - .rst_ni, - - .reg_req_i (reg_int_req[i]), - .reg_rsp_o (reg_int_rsp[i]), - - .reg2hw (clicint_reg2hw[i]), - .hw2reg (clicint_hw2reg[i]), - - .devmode_i (1'b1) + clicint_reg i_clicint_reg ( + .clk (clk_i), + .arst_n (rst_ni), + + .s_apb_psel (int_psel_oh[i]), + .s_apb_penable (penable), + .s_apb_pwrite (pwrite), + .s_apb_pprot (pprot), + .s_apb_paddr (leaf_paddr), + .s_apb_pwdata (int_pwdata), + .s_apb_pstrb (pstrb), + .s_apb_pready (int_pready[i]), + .s_apb_prdata (int_prdata[i]), + .s_apb_pslverr (int_pslverr[i]), + + .hwif_in (clicint_hwif_in[i]), + .hwif_out (clicint_hwif_out[i]) ); end - // interrupt control and status registers (per interrupt line) - // 0x???? - 0x???? (machine mode) - reg_req_t reg_all_v_req; - reg_rsp_t reg_all_v_rsp; - logic [ADDR_W-1:0] v_addr; - logic v_addr_ok; - - reg_req_t [ceil_div(N_SOURCE, 4)-1:0] reg_v_req; - reg_rsp_t [ceil_div(N_SOURCE, 4)-1:0] reg_v_rsp; - - // VSPRIO register interface signals - reg_req_t reg_all_vs_req; - reg_rsp_t reg_all_vs_rsp; - logic [ADDR_W-1:0] vs_addr; - logic vs_addr_ok; - - reg_req_t [(MAX_VSCTXTS/4)-1:0] reg_vs_req; - reg_rsp_t [(MAX_VSCTXTS/4)-1:0] reg_vs_rsp; - - if (VSCLIC) begin - - assign v_addr = reg_all_v_req.addr[ADDR_W-1:2]; - // Check that the address is withing the range of implemented interrupt lines - assign v_addr_ok = (v_addr < ceil_div(N_SOURCE, 4)); + // interrupt virtualization registers (one per four interrupt lines) + // 0xd000 - 0xdfff (supervisor mode) + if (VSCLIC) begin : gen_clic_intv - always_comb begin - reg_v_req = '0; - if (v_addr_ok) reg_v_req[v_addr] = reg_all_v_req; - end + assign v_idx_ok = (v_idx < N_INTV); always_comb begin - reg_all_v_rsp = '0; - reg_all_v_rsp.ready = 1'b1; - if (v_addr_ok) reg_all_v_rsp = reg_v_rsp[v_addr]; + v_psel_oh = '0; + if (v_psel && v_idx_ok) v_psel_oh[v_idx] = 1'b1; end - for (genvar i = 0; i < ceil_div(N_SOURCE, 4); i++) begin : gen_clic_intv - clicintv_reg_top #( - .reg_req_t (reg_req_t), - .reg_rsp_t (reg_rsp_t) - ) i_clicintv_reg_top ( - .clk_i, - .rst_ni, - - .reg_req_i (reg_v_req[i]), - .reg_rsp_o (reg_v_rsp[i]), - - .reg2hw (clicintv_reg2hw[i]), - // .hw2reg (clicintv_hw2reg[i]), - - .devmode_i (1'b1) + assign v_sel_prdata = v_idx_ok ? v_prdata[v_idx] : 32'h0; + assign v_sel_pready = v_idx_ok ? v_pready[v_idx] : 1'b1; + assign v_sel_pslverr = v_idx_ok ? v_pslverr[v_idx] : 1'b0; + + for (genvar i = 0; i < N_INTV; i++) begin : gen_clic_intv_blk + clicintv_reg i_clicintv_reg ( + .clk (clk_i), + .arst_n (rst_ni), + + .s_apb_psel (v_psel_oh[i]), + .s_apb_penable (penable), + .s_apb_pwrite (pwrite), + .s_apb_pprot (pprot), + .s_apb_paddr (leaf_paddr), + .s_apb_pwdata (v_pwdata), + .s_apb_pstrb (pstrb), + .s_apb_pready (v_pready[i]), + .s_apb_prdata (v_prdata[i]), + .s_apb_pslverr (v_pslverr[i]), + + .hwif_out (clicintv_hwif_out[i]) ); end - if (VSPRIO) begin + // VS priority registers (one per four VS contexts) + // 0xe000 - 0xefff (supervisor mode) + if (VSPRIO) begin : gen_clic_vs - assign vs_addr = reg_all_vs_req.addr[ADDR_W-1:2]; - // Check that the address is withing the range of implemented interrupt lines - assign vs_addr_ok = (vs_addr < (MAX_VSCTXTS/4)); + assign vs_idx_ok = (vs_idx < N_VS); always_comb begin - reg_vs_req = '0; - if (vs_addr_ok) reg_vs_req[vs_addr] = reg_all_vs_req; + vs_psel_oh = '0; + if (vs_psel && vs_idx_ok) vs_psel_oh[vs_idx] = 1'b1; end - always_comb begin - reg_all_vs_rsp = '0; - reg_all_vs_rsp.ready = 1'b1; - if (vs_addr_ok) reg_all_vs_rsp = reg_vs_rsp[vs_addr]; - end - - for(genvar i = 0; i < (MAX_VSCTXTS/4); i++) begin : gen_clic_vs - - clicvs_reg_top #( - .reg_req_t (reg_req_t), - .reg_rsp_t (reg_rsp_t) - ) i_clicvs_reg_top ( - .clk_i, - .rst_ni, - - .reg_req_i (reg_vs_req[i]), - .reg_rsp_o (reg_vs_rsp[i]), - - .reg2hw (clicvs_reg2hw[i]), - // .hw2reg (clicvs_hw2reg[i]), - - .devmode_i (1'b1) + assign vs_sel_prdata = vs_idx_ok ? vs_prdata[vs_idx] : 32'h0; + assign vs_sel_pready = vs_idx_ok ? vs_pready[vs_idx] : 1'b1; + assign vs_sel_pslverr = vs_idx_ok ? vs_pslverr[vs_idx] : 1'b0; + + for (genvar i = 0; i < N_VS; i++) begin : gen_clic_vs_blk + clicvs_reg i_clicvs_reg ( + .clk (clk_i), + .arst_n (rst_ni), + + .s_apb_psel (vs_psel_oh[i]), + .s_apb_penable (penable), + .s_apb_pwrite (pwrite), + .s_apb_pprot (pprot), + .s_apb_paddr (leaf_paddr), + .s_apb_pwdata (pwdata), + .s_apb_pstrb (pstrb), + .s_apb_pready (vs_pready[i]), + .s_apb_prdata (vs_prdata[i]), + .s_apb_pslverr (vs_pslverr[i]), + + .hwif_out (clicvs_hwif_out[i]) ); - end - end else begin - assign clicvs_reg2hw = '0; - // assign clicvs_hw2reg = '0; - assign reg_vs_req = '0; - assign reg_vs_rsp = '0; - assign vs_addr = '0; - assign vs_addr_ok = 1'b0; - assign reg_all_vs_rsp = '0; + end else begin : gen_no_clic_vs + for (genvar i = 0; i < N_VS; i++) begin : gen_tie_vs + assign clicvs_hwif_out[i] = '{default: '0}; + end + assign vs_psel_oh = '0; + assign vs_prdata = '0; + assign vs_pready = '0; + assign vs_pslverr = '0; + assign vs_idx_ok = 1'b0; + assign vs_sel_prdata = 32'h0; + assign vs_sel_pready = 1'b1; + assign vs_sel_pslverr = 1'b0; end - end else begin - assign clicintv_reg2hw = '0; - // assign clicintv_hw2reg = '0; - assign reg_v_req = '0; - assign reg_v_rsp = '0; - assign v_addr = '0; - assign v_addr_ok = 1'b0; - assign reg_all_v_rsp = '0; + end else begin : gen_no_clic_intv + for (genvar i = 0; i < N_INTV; i++) begin : gen_tie_intv + assign clicintv_hwif_out[i] = '{default: '0}; + end + for (genvar i = 0; i < N_VS; i++) begin : gen_tie_vs + assign clicvs_hwif_out[i] = '{default: '0}; + end + assign v_psel_oh = '0; + assign v_prdata = '0; + assign v_pready = '0; + assign v_pslverr = '0; + assign v_idx_ok = 1'b0; + assign v_sel_prdata = 32'h0; + assign v_sel_pready = 1'b1; + assign v_sel_pslverr = 1'b0; + + assign vs_psel_oh = '0; + assign vs_prdata = '0; + assign vs_pready = '0; + assign vs_pslverr = '0; + assign vs_idx_ok = 1'b0; + assign vs_sel_prdata = 32'h0; + assign vs_sel_pready = 1'b1; + assign vs_sel_pslverr = 1'b0; end - // top level address decoding and bus muxing + /////////////////////////////////////////////////// + // Top level address decoding // + /////////////////////////////////////////////////// // Helper signal used to store intermediate address logic [ADDR_W-1:0] addr_tmp; + // The access decoded to a window but is not permitted or not implemented: + // terminate it immediately, returning zeros without an error. + logic void_access; + always_comb begin : clic_addr_decode - reg_mclic_req = '0; - reg_all_int_req = '0; - reg_all_v_req = '0; - reg_all_vs_req = '0; - reg_rsp_o = '0; + // Index of the interrupt line an access refers to. Every window is larger + // than the number of lines behind it, so the index is range-checked before + // it reaches intmode/intv/vsid: without the clamp an access to the unused + // top of a window would read those arrays out of bounds. + automatic logic [ADDR_W-1:0] line_idx; + automatic logic line_ok; + automatic logic [ADDR_W-1:0] line_idx_safe; + + line_idx = '0; + line_ok = 1'b0; + line_idx_safe = '0; + + cliccfg_psel = 1'b0; + + int_psel = 1'b0; + int_idx = '0; + int_pwdata = pwdata; - addr_tmp = '0; + v_psel = 1'b0; + v_idx = '0; + v_pwdata = pwdata; + v_lane_ok = 4'b1111; - unique case(reg_req_i.addr[ADDR_W-1:0]) inside + vs_psel = 1'b0; + vs_idx = '0; + + void_access = 1'b0; + + addr_tmp = '0; + + unique case(apb_req_i.paddr[ADDR_W-1:0]) inside MCLICCFG_START: begin - reg_mclic_req = reg_req_i; - reg_rsp_o = reg_mclic_rsp; + cliccfg_psel = psel; end [MCLICINT_START:MCLICINT_END]: begin - reg_all_int_req = reg_req_i; - reg_all_int_req.addr = reg_req_i.addr - MCLICINT_START; - reg_rsp_o = reg_all_int_rsp; + addr_tmp = apb_req_i.paddr[ADDR_W-1:0] - MCLICINT_START; + int_psel = psel; + int_idx = {2'b0, addr_tmp[ADDR_W-1:2]}; end SCLICCFG_START: begin if (SSCLIC) begin - reg_mclic_req = reg_req_i; - reg_rsp_o = reg_mclic_rsp; + cliccfg_psel = psel; + end else begin + void_access = 1'b1; end end [SCLICINT_START:SCLICINT_END]: begin if (SSCLIC) begin - addr_tmp = reg_req_i.addr[ADDR_W-1:0] - SCLICINT_START; - if (intmode[addr_tmp[ADDR_W-1:2]] <= S_MODE) begin - // check whether the irq we want to access is s-mode or lower - reg_all_int_req = reg_req_i; - reg_all_int_req.addr = addr_tmp; - // Prevent setting interrupt mode to m-mode . This is currently a - // bit ugly but will be nicer once we do away with auto generated - // clicint registers - reg_all_int_req.wdata[23] = 1'b0; - reg_rsp_o = reg_all_int_rsp; + addr_tmp = apb_req_i.paddr[ADDR_W-1:0] - SCLICINT_START; + line_idx = {2'b0, addr_tmp[ADDR_W-1:2]}; + line_ok = (line_idx < N_SOURCE); + line_idx_safe = line_ok ? line_idx : '0; + // check whether the irq we want to access is s-mode or lower + if (line_ok && (intmode[line_idx_safe] <= S_MODE)) begin + int_psel = psel; + int_idx = line_idx; + // Prevent setting interrupt mode to m-mode + int_pwdata[23] = 1'b0; end else begin - // inaccesible (all zero) - reg_rsp_o.rdata = '0; - reg_rsp_o.error = '0; - reg_rsp_o.ready = 1'b1; + void_access = 1'b1; end + end else begin + void_access = 1'b1; end end [SCLICINTV_START:SCLICINTV_END]: begin if (VSCLIC) begin - addr_tmp = reg_req_i.addr[ADDR_W-1:0] - SCLICINTV_START; - reg_all_v_req = reg_req_i; - reg_all_v_req.addr = addr_tmp; - addr_tmp = {addr_tmp[ADDR_W-1:2], 2'b0}; - reg_rsp_o = reg_all_v_rsp; - if(intmode[addr_tmp + 0] > S_MODE) begin - reg_all_v_req.wdata[7:0] = 8'b0; - reg_rsp_o.rdata[7:0] = 8'b0; - end - if(intmode[addr_tmp + 1] > S_MODE) begin - reg_all_v_req.wdata[15:8] = 8'b0; - reg_rsp_o.rdata[15:8] = 8'b0; - end - if(intmode[addr_tmp + 2] > S_MODE) begin - reg_all_v_req.wdata[23:16] = 8'b0; - reg_rsp_o.rdata[23:16] = 8'b0; - end - if(intmode[addr_tmp + 3] > S_MODE) begin - reg_all_v_req.wdata[31:24] = 8'b0; - reg_rsp_o.rdata[31:24] = 8'b0; + addr_tmp = apb_req_i.paddr[ADDR_W-1:0] - SCLICINTV_START; + v_psel = psel; + v_idx = {2'b0, addr_tmp[ADDR_W-1:2]}; + // One lane per interrupt line. A lane whose line does not exist, or + // is configured above S-mode, has no virtualization state: it is + // written as zero and reads back as zero. + for (int unsigned k = 0; k < 4; k++) begin + line_idx = ({2'b0, addr_tmp[ADDR_W-1:2]} << 2) + k[ADDR_W-1:0]; + line_ok = (line_idx < N_SOURCE); + line_idx_safe = line_ok ? line_idx : '0; + v_lane_ok[k] = line_ok && (intmode[line_idx_safe] <= S_MODE); + if (!v_lane_ok[k]) v_pwdata[8*k +: 8] = 8'b0; end end else begin - // VSCLIC disabled - reg_rsp_o.rdata = '0; - reg_rsp_o.error = '0; - reg_rsp_o.ready = 1'b1; + void_access = 1'b1; end end [VSCLICPRIO_START:VSCLICPRIO_END]: begin - if(VSCLIC && VSPRIO) begin - addr_tmp = reg_req_i.addr[ADDR_W-1:0] - VSCLICPRIO_START; - reg_all_vs_req = reg_req_i; - reg_all_vs_req.addr = addr_tmp; - reg_rsp_o = reg_all_vs_rsp; + if (VSCLIC && VSPRIO) begin + addr_tmp = apb_req_i.paddr[ADDR_W-1:0] - VSCLICPRIO_START; + vs_psel = psel; + vs_idx = {2'b0, addr_tmp[ADDR_W-1:2]}; end else begin - reg_rsp_o.rdata = '0; - reg_rsp_o.error = '0; - reg_rsp_o.ready = 1'b1; + void_access = 1'b1; end end default: begin - // inaccesible (all zero) - reg_rsp_o.rdata = '0; - reg_rsp_o.error = '0; - reg_rsp_o.ready = 1'b1; + void_access = 1'b1; end - endcase // unique case (reg_req_i.addr) + endcase // unique case (apb_req_i.paddr) // Match VS address space if (VSCLIC) begin for (int i = 0; i < N_VSCTXTS; i++) begin - if (reg_req_i.addr[ADDR_W-1:0] == VSCLICCFG_START[i]) begin - // inaccesible (all zero) - reg_rsp_o.rdata = '0; - reg_rsp_o.error = '0; - reg_rsp_o.ready = 1'b1; - end else if (VSCLICINT_START[i] <= reg_req_i.addr[ADDR_W-1:0] && - reg_req_i.addr[ADDR_W-1:0] <= VSCLICINT_END[i]) begin - addr_tmp = reg_req_i.addr[ADDR_W-1:0] - VSCLICINT_START[i]; - if ((intmode[addr_tmp[ADDR_W-1:2]] == S_MODE) && - (intv[addr_tmp[ADDR_W-1:2]]) && - (vsid[addr_tmp[ADDR_W-1:2]] == (i + 1))) begin - // check whether the irq we want to access is s-mode and its v bit is set and the VSID corresponds - reg_all_int_req = reg_req_i; - reg_all_int_req.addr = addr_tmp; - // Prevent setting interrupt mode to m-mode. This is currently a - // bit ugly but will be nicer once we do away with auto generated - // clicint registers - reg_all_int_req.wdata[23] = 1'b0; - reg_rsp_o = reg_all_int_rsp; + if (apb_req_i.paddr[ADDR_W-1:0] == VSCLICCFG_START[i]) begin + void_access = 1'b1; + end else if (VSCLICINT_START[i] <= apb_req_i.paddr[ADDR_W-1:0] && + apb_req_i.paddr[ADDR_W-1:0] <= VSCLICINT_END[i]) begin + addr_tmp = apb_req_i.paddr[ADDR_W-1:0] - VSCLICINT_START[i]; + line_idx = {2'b0, addr_tmp[ADDR_W-1:2]}; + line_ok = (line_idx < N_SOURCE); + line_idx_safe = line_ok ? line_idx : '0; + // check whether the irq we want to access is s-mode and its v bit is + // set and the VSID corresponds + if (line_ok && + (intmode[line_idx_safe] == S_MODE) && + intv[line_idx_safe] && + (vsid[line_idx_safe] == VSID_W'(i + 1))) begin + int_psel = psel; + int_idx = line_idx; + // Prevent setting interrupt mode to m-mode + int_pwdata[23] = 1'b0; + void_access = 1'b0; end else begin - // inaccesible (all zero) - reg_rsp_o.rdata = '0; - reg_rsp_o.error = '0; - reg_rsp_o.ready = 1'b1; + void_access = 1'b1; end end end end end + // Response mux: at most one group is selected at a time. + always_comb begin : clic_rsp_mux + prdata = 32'h0; + pready = 1'b1; + pslverr = 1'b0; + + if (void_access) begin + // inaccesible (all zero) + prdata = 32'h0; + pready = 1'b1; + pslverr = 1'b0; + end else if (cliccfg_psel) begin + prdata = cliccfg_prdata; + pready = cliccfg_pready; + pslverr = cliccfg_pslverr; + end else if (int_psel) begin + prdata = int_sel_prdata; + pready = int_sel_pready; + pslverr = int_sel_pslverr; + end else if (v_psel) begin + prdata = v_sel_prdata; + pready = v_sel_pready; + pslverr = v_sel_pslverr; + // Lanes without virtualization state read back as zero. + for (int unsigned k = 0; k < 4; k++) begin + if (!v_lane_ok[k]) prdata[8*k +: 8] = 8'b0; + end + end else if (vs_psel) begin + prdata = vs_sel_prdata; + pready = vs_sel_pready; + pslverr = vs_sel_pslverr; + end + end + // adapter clic_reg_adapter #( .N_SOURCE (N_SOURCE), @@ -721,16 +849,14 @@ module clic .clk_i, .rst_ni, - .mclic_reg2hw, + .cliccfg_hwif_out, - .clicint_reg2hw, - .clicint_hw2reg, + .clicint_hwif_out, + .clicint_hwif_in, - .clicintv_reg2hw, - // .clicintv_hw2reg, + .clicintv_hwif_out, - .clicvs_reg2hw, - // .clicvs_hw2reg, + .clicvs_hwif_out, .intctl_o (intctl), .intmode_o (intmode), @@ -752,8 +878,8 @@ module clic always_comb begin // Saturate nlbits if nlbits > clicintctlbits (nlbits > 0 && nlbits <= 8) mnlbits = INTCTLBITS; - if (mclic_reg2hw.mcliccfg.mnlbits.q <= INTCTLBITS) - mnlbits = mclic_reg2hw.mcliccfg.mnlbits.q; + if (cliccfg_hwif_out.cliccfg.mnlbits.value <= INTCTLBITS) + mnlbits = cliccfg_hwif_out.cliccfg.mnlbits.value; end logic [7:0] irq_level_tmp; @@ -802,10 +928,10 @@ module clic nmbits = 2'b0; if (VSCLIC || SSCLIC || USCLIC) - nmbits[0] = mclic_reg2hw.mcliccfg.nmbits.q[0]; + nmbits[0] = cliccfg_hwif_out.cliccfg.nmbits.value[0]; if ((VSCLIC || SSCLIC) && USCLIC) - nmbits[1] = mclic_reg2hw.mcliccfg.nmbits.q[1]; + nmbits[1] = cliccfg_hwif_out.cliccfg.nmbits.value[1]; end logic [1:0] irq_mode_tmp; diff --git a/src/clic_apb.sv b/src/clic_apb.sv deleted file mode 100644 index 0fa7aee..0000000 --- a/src/clic_apb.sv +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2025 ETH Zurich and University of Bologna. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Author: Robert Balas (balasr@iis.ee.ethz.ch) - -// SPDX-License-Identifier: Apache-2.0 - -`include "register_interface/typedef.svh" -`include "register_interface/assign.svh" - -module clic_apb - import clic_pkg::*; -#( - parameter int N_SOURCE = 256, - parameter int INTCTLBITS = 8, - parameter bit SSCLIC = 0, - parameter bit USCLIC = 0, - parameter bit VSCLIC = 0, // enable vCLIC (requires SSCLIC) - // vCLIC dependent parameters - parameter int unsigned N_VSCTXTS = 0, // Number of Virtual Contexts supported. - // This implementation assumes CLIC is mapped to an address - // range that allows up to 64 contexts (at least 512KiB) - parameter bit VSPRIO = 0, // Enable VS prioritization (requires VSCLIC) - parameter int VSPRIO_W = 1, // N of VS priority bits (must be set accordingly to the `clicvs` register width) - // do not edit below, these are derived - localparam int unsigned REG_BUS_ADDR_WIDTH = 32, - localparam int unsigned REG_BUS_DATA_WIDTH = 32, - localparam int SrcW = $clog2(N_SOURCE) -)( - input logic clk_i, - input logic rst_ni, - - // Bus Interface (device) - input logic penable_i, - input logic pwrite_i, - input logic [REG_BUS_ADDR_WIDTH-1:0] paddr_i, - input logic psel_i, - input logic [REG_BUS_DATA_WIDTH-1:0] pwdata_i, - output logic [REG_BUS_DATA_WIDTH-1:0] prdata_o, - output logic pready_o, - output logic pslverr_o, - - // Interrupt Sources - input [N_SOURCE-1:0] intr_src_i, - - // Interrupt notification to core - output irq_valid_o, - input irq_ready_i, - output [SrcW-1:0] irq_id_o, - output [7:0] irq_level_o, - output logic irq_shv_o, - output logic [1:0] irq_priv_o, - output logic [VSID_W-1:0] irq_vsid_o, - output logic irq_v_o, - output logic irq_kill_req_o, - input logic irq_kill_ack_i - -); - - typedef logic [REG_BUS_ADDR_WIDTH -1:0] addr_t; - typedef logic [REG_BUS_DATA_WIDTH -1:0] data_t; - typedef logic [REG_BUS_DATA_WIDTH/8-1:0] strb_t; - - `REG_BUS_TYPEDEF_REQ(reg_req_t, addr_t, data_t, strb_t) - `REG_BUS_TYPEDEF_RSP(reg_rsp_t, data_t) - - reg_req_t clic_req; - reg_rsp_t clic_rsp; - - // NOTE: `Feedthrough` must currently stay 0 for bug inside apb_to_reg_v2 adapter - apb_to_reg_v2 #( - .Feedthrough ( 1'b0 ), - .reg_req_t ( reg_req_t ), - .reg_rsp_t ( reg_rsp_t ) - ) i_apb_to_reg ( - .clk_i, - .rst_ni, - .penable_i, - .pwrite_i, - .paddr_i, - .psel_i, - .pwdata_i, - .prdata_o, - .pready_o, - .pslverr_o, - .reg_req_o ( clic_req ), - .reg_rsp_i ( clic_rsp ) - ); - - clic #( - .N_SOURCE ( N_SOURCE ), - .INTCTLBITS( INTCTLBITS ), - .SSCLIC ( SSCLIC ), - .USCLIC ( USCLIC ), - .VSCLIC ( VSCLIC ), - .N_VSCTXTS ( N_VSCTXTS ), - .VSPRIO ( VSPRIO ), - .VSPRIO_W ( VSPRIO_W ), - .reg_req_t ( reg_req_t ), - .reg_rsp_t ( reg_rsp_t ) - ) i_clic ( - .clk_i, - .rst_ni, - // Bus Interface - .reg_req_i ( clic_req ), - .reg_rsp_o ( clic_rsp ), - // Interrupt Sources - .intr_src_i, - // Interrupt notification to core - .irq_valid_o, - .irq_ready_i, - .irq_id_o, - .irq_level_o, - .irq_shv_o, - .irq_priv_o, - .irq_vsid_o, - .irq_v_o, - .irq_kill_req_o, - .irq_kill_ack_i - ); - -endmodule // clic_apb diff --git a/src/clic_gateway.sv b/src/clic_gateway.sv index af034f7..71043f3 100644 --- a/src/clic_gateway.sv +++ b/src/clic_gateway.sv @@ -1,5 +1,5 @@ // Copyright lowRISC contributors. -// Copyright 2022 ETH Zurich University of Bologna +// Copyright 2022 ETH Zurich and University of Bologna. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/src/clic_pkg.sv b/src/clic_pkg.sv index b8bc865..2a2bf1a 100644 --- a/src/clic_pkg.sv +++ b/src/clic_pkg.sv @@ -1,18 +1,6 @@ // Copyright 2025 ETH Zurich and University of Bologna. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 +// Solderpad Hardware License, Version 0.51, see LICENSES/SHL-0.51.txt for details. +// SPDX-License-Identifier: SHL-0.51 package clic_pkg; diff --git a/src/clic_reg_adapter.sv b/src/clic_reg_adapter.sv index 7b7f021..45de5cf 100644 --- a/src/clic_reg_adapter.sv +++ b/src/clic_reg_adapter.sv @@ -1,25 +1,12 @@ -// Copyright 2025 ETH Zurich and University of Bologna. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// SPDX-License-Identifier: Apache-2.0 +// Copyright 2026 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSES/SHL-0.51.txt for details. +// SPDX-License-Identifier: SHL-0.51 + +// Flattens the per-block PeakRDL hardware interfaces into the per-source +// arrays consumed by clic_gateway and clic_target. module clic_reg_adapter import clic_pkg::*; - import mclic_reg_pkg::*; - import clicint_reg_pkg::*; - import clicintv_reg_pkg::*; - import clicvs_reg_pkg::*; import cf_math_pkg::*; #( parameter int N_SOURCE = 32, @@ -30,14 +17,14 @@ module clic_reg_adapter input logic clk_i, input logic rst_ni, - input mclic_reg_pkg::mclic_reg2hw_t mclic_reg2hw, + input cliccfg_reg_pkg::cliccfg__out_t cliccfg_hwif_out, - input clicint_reg_pkg::clicint_reg2hw_t [N_SOURCE-1:0] clicint_reg2hw, - output clicint_reg_pkg::clicint_hw2reg_t [N_SOURCE-1:0] clicint_hw2reg, + input clicint_reg_pkg::clicint__out_t clicint_hwif_out [N_SOURCE], + output clicint_reg_pkg::clicint__in_t clicint_hwif_in [N_SOURCE], - input clicintv_reg_pkg::clicintv_reg2hw_t [ceil_div(N_SOURCE, 4)-1:0] clicintv_reg2hw, + input clicintv_reg_pkg::clicintv__out_t clicintv_hwif_out [ceil_div(N_SOURCE, 4)], - input clicvs_reg_pkg::clicvs_reg2hw_t [(MAX_VSCTXTS/4)-1:0] clicvs_reg2hw, + input clicvs_reg_pkg::clicvs__out_t clicvs_hwif_out [MAX_VSCTXTS/4], output logic [7:0] intctl_o [N_SOURCE], output logic [1:0] intmode_o [N_SOURCE], @@ -57,48 +44,53 @@ module clic_reg_adapter // We only support positive edge triggered and positive level triggered // interrupts atm. Either we hardware the trig.q[1] bit correctly or we // implement all modes + // + // `we` is tied high so the gateway drives pending every cycle. A software + // write to IP in the same cycle still wins: the register block resolves the + // conflict with `precedence = sw` (see src/gen/clicint.rdl), which is what + // makes a software-triggered interrupt possible. for (genvar i = 0; i < N_SOURCE; i++) begin : gen_reghw - assign intctl_o[i] = clicint_reg2hw[i].clicint.ctl.q; - assign intmode_o[i] = clicint_reg2hw[i].clicint.attr_mode.q; - assign shv_o[i] = clicint_reg2hw[i].clicint.attr_shv.q; - assign ip_sw_o[i] = clicint_reg2hw[i].clicint.ip.q; - assign ie_o[i] = clicint_reg2hw[i].clicint.ie.q; - assign clicint_hw2reg[i].clicint.ip.de = 1'b1; // Always write - assign clicint_hw2reg[i].clicint.ip.d = ip_i[i]; - assign le_o[i] = clicint_reg2hw[i].clicint.attr_trig.q[0]; + assign intctl_o[i] = clicint_hwif_out[i].clicint.ctl.value; + assign intmode_o[i] = clicint_hwif_out[i].clicint.attr_mode.value; + assign shv_o[i] = clicint_hwif_out[i].clicint.attr_shv.value; + assign ip_sw_o[i] = clicint_hwif_out[i].clicint.ip.value; + assign ie_o[i] = clicint_hwif_out[i].clicint.ie.value; + assign clicint_hwif_in[i].clicint.ip.we = 1'b1; // Always write + assign clicint_hwif_in[i].clicint.ip.next = ip_i[i]; + assign le_o[i] = clicint_hwif_out[i].clicint.attr_trig.value[0]; end for (genvar i = 0; i < rounddown(N_SOURCE, 4); i = i + 4) begin : gen_reghw_v - assign vsid_o[i+0] = clicintv_reg2hw[i/4].clicintv.vsid0.q; - assign intv_o[i+0] = clicintv_reg2hw[i/4].clicintv.v0.q; - assign vsid_o[i+1] = clicintv_reg2hw[i/4].clicintv.vsid1.q; - assign intv_o[i+1] = clicintv_reg2hw[i/4].clicintv.v1.q; - assign vsid_o[i+2] = clicintv_reg2hw[i/4].clicintv.vsid2.q; - assign intv_o[i+2] = clicintv_reg2hw[i/4].clicintv.v2.q; - assign vsid_o[i+3] = clicintv_reg2hw[i/4].clicintv.vsid3.q; - assign intv_o[i+3] = clicintv_reg2hw[i/4].clicintv.v3.q; + assign vsid_o[i+0] = clicintv_hwif_out[i/4].clicintv.vsid0.value; + assign intv_o[i+0] = clicintv_hwif_out[i/4].clicintv.v0.value; + assign vsid_o[i+1] = clicintv_hwif_out[i/4].clicintv.vsid1.value; + assign intv_o[i+1] = clicintv_hwif_out[i/4].clicintv.v1.value; + assign vsid_o[i+2] = clicintv_hwif_out[i/4].clicintv.vsid2.value; + assign intv_o[i+2] = clicintv_hwif_out[i/4].clicintv.v2.value; + assign vsid_o[i+3] = clicintv_hwif_out[i/4].clicintv.vsid3.value; + assign intv_o[i+3] = clicintv_hwif_out[i/4].clicintv.v3.value; end - if ((N_SOURCE%4) > 0) begin - assign vsid_o[N_SOURCE_ALIGNED+0] = clicintv_reg2hw[N_SOURCE/4].clicintv.vsid0.q; - assign intv_o[N_SOURCE_ALIGNED+0] = clicintv_reg2hw[N_SOURCE/4].clicintv.v0.q; + if ((N_SOURCE%4) > 0) begin : gen_reghw_v_rem0 + assign vsid_o[N_SOURCE_ALIGNED+0] = clicintv_hwif_out[N_SOURCE/4].clicintv.vsid0.value; + assign intv_o[N_SOURCE_ALIGNED+0] = clicintv_hwif_out[N_SOURCE/4].clicintv.v0.value; end - if ((N_SOURCE%4) > 1) begin - assign vsid_o[N_SOURCE_ALIGNED+1] = clicintv_reg2hw[N_SOURCE/4].clicintv.vsid1.q; - assign intv_o[N_SOURCE_ALIGNED+1] = clicintv_reg2hw[N_SOURCE/4].clicintv.v1.q; + if ((N_SOURCE%4) > 1) begin : gen_reghw_v_rem1 + assign vsid_o[N_SOURCE_ALIGNED+1] = clicintv_hwif_out[N_SOURCE/4].clicintv.vsid1.value; + assign intv_o[N_SOURCE_ALIGNED+1] = clicintv_hwif_out[N_SOURCE/4].clicintv.v1.value; end - if ((N_SOURCE%4) > 2) begin - assign vsid_o[N_SOURCE_ALIGNED+2] = clicintv_reg2hw[N_SOURCE/4].clicintv.vsid2.q; - assign intv_o[N_SOURCE_ALIGNED+2] = clicintv_reg2hw[N_SOURCE/4].clicintv.v2.q; + if ((N_SOURCE%4) > 2) begin : gen_reghw_v_rem2 + assign vsid_o[N_SOURCE_ALIGNED+2] = clicintv_hwif_out[N_SOURCE/4].clicintv.vsid2.value; + assign intv_o[N_SOURCE_ALIGNED+2] = clicintv_hwif_out[N_SOURCE/4].clicintv.v2.value; end for (genvar i = 0; i < MAX_VSCTXTS; i = i + 4) begin : gen_reghw_vs - assign vsprio_o[i+0] = clicvs_reg2hw[i/4].vsprio.prio0.q; - assign vsprio_o[i+1] = clicvs_reg2hw[i/4].vsprio.prio1.q; - assign vsprio_o[i+2] = clicvs_reg2hw[i/4].vsprio.prio2.q; - assign vsprio_o[i+3] = clicvs_reg2hw[i/4].vsprio.prio3.q; + assign vsprio_o[i+0] = clicvs_hwif_out[i/4].vsprio.prio0.value; + assign vsprio_o[i+1] = clicvs_hwif_out[i/4].vsprio.prio1.value; + assign vsprio_o[i+2] = clicvs_hwif_out[i/4].vsprio.prio2.value; + assign vsprio_o[i+3] = clicvs_hwif_out[i/4].vsprio.prio3.value; end endmodule // clic_reg_adapter diff --git a/src/clic_target.sv b/src/clic_target.sv index 529ea0e..e22d792 100644 --- a/src/clic_target.sv +++ b/src/clic_target.sv @@ -1,5 +1,5 @@ // Copyright lowRISC contributors. -// Copyright 2022 ETH Zurich +// Copyright 2022 ETH Zurich and University of Bologna. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/src/cliccfg_reg.sv b/src/cliccfg_reg.sv new file mode 100644 index 0000000..afbfb72 --- /dev/null +++ b/src/cliccfg_reg.sv @@ -0,0 +1,289 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-regblock + +module cliccfg_reg ( + input wire clk, + input wire arst_n, + + input wire s_apb_psel, + input wire s_apb_penable, + input wire s_apb_pwrite, + input wire [2:0] s_apb_pprot, + input wire [2:0] s_apb_paddr, + input wire [31:0] s_apb_pwdata, + input wire [3:0] s_apb_pstrb, + output logic s_apb_pready, + output logic [31:0] s_apb_prdata, + output logic s_apb_pslverr, + + output cliccfg_reg_pkg::cliccfg__out_t hwif_out + ); + + //-------------------------------------------------------------------------- + // CPU Bus interface logic + //-------------------------------------------------------------------------- + logic cpuif_req; + logic cpuif_req_is_wr; + logic [2:0] cpuif_addr; + logic [31:0] cpuif_wr_data; + logic [31:0] cpuif_wr_biten; + logic cpuif_req_stall_wr; + logic cpuif_req_stall_rd; + + logic cpuif_rd_ack; + logic cpuif_rd_err; + logic [31:0] cpuif_rd_data; + + logic cpuif_wr_ack; + logic cpuif_wr_err; + + // Request + logic is_active; + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + is_active <= '0; + cpuif_req <= '0; + cpuif_req_is_wr <= '0; + cpuif_addr <= '0; + cpuif_wr_data <= '0; + cpuif_wr_biten <= '0; + end else begin + if(~is_active) begin + if(s_apb_psel) begin + is_active <= '1; + cpuif_req <= '1; + cpuif_req_is_wr <= s_apb_pwrite; + cpuif_addr <= {s_apb_paddr[2:2], 2'b0}; + cpuif_wr_data <= s_apb_pwdata; + for(int i=0; i<4; i++) begin + cpuif_wr_biten[i*8 +: 8] <= {8{s_apb_pstrb[i]}}; + end + end + end else begin + cpuif_req <= '0; + if(cpuif_rd_ack || cpuif_wr_ack) begin + is_active <= '0; + end + end + end + end + + // Response + assign s_apb_pready = cpuif_rd_ack | cpuif_wr_ack; + assign s_apb_prdata = cpuif_rd_data; + assign s_apb_pslverr = cpuif_rd_err | cpuif_wr_err; + + logic cpuif_req_masked; + + // Read & write latencies are balanced. Stalls not required + assign cpuif_req_stall_rd = '0; + assign cpuif_req_stall_wr = '0; + assign cpuif_req_masked = cpuif_req + & !(!cpuif_req_is_wr & cpuif_req_stall_rd) + & !(cpuif_req_is_wr & cpuif_req_stall_wr); + + //-------------------------------------------------------------------------- + // Address Decode + //-------------------------------------------------------------------------- + typedef struct { + logic cliccfg; + } decoded_reg_strb_t; + decoded_reg_strb_t decoded_reg_strb; + logic decoded_err; + logic [2:0] decoded_addr; + logic decoded_req; + logic decoded_req_is_wr; + logic [31:0] decoded_wr_data; + logic [31:0] decoded_wr_biten; + + always_comb begin + automatic logic is_valid_addr; + automatic logic is_valid_rw; + is_valid_addr = '1; // No valid address check + is_valid_rw = '1; // No valid RW check + decoded_reg_strb.cliccfg = cpuif_req_masked & (cpuif_addr == 3'h0); + decoded_err = '0; + end + + // Pass down signals to next stage + assign decoded_addr = cpuif_addr; + assign decoded_req = cpuif_req_masked; + assign decoded_req_is_wr = cpuif_req_is_wr; + assign decoded_wr_data = cpuif_wr_data; + assign decoded_wr_biten = cpuif_wr_biten; + + //-------------------------------------------------------------------------- + // Field logic + //-------------------------------------------------------------------------- + typedef struct { + struct { + struct { + logic [3:0] next; + logic load_next; + } mnlbits; + struct { + logic [1:0] next; + logic load_next; + } nmbits; + struct { + logic [3:0] next; + logic load_next; + } snlbits; + struct { + logic [3:0] next; + logic load_next; + } unlbits; + } cliccfg; + } field_combo_t; + field_combo_t field_combo; + + typedef struct { + struct { + struct { + logic [3:0] value; + } mnlbits; + struct { + logic [1:0] value; + } nmbits; + struct { + logic [3:0] value; + } snlbits; + struct { + logic [3:0] value; + } unlbits; + } cliccfg; + } field_storage_t; + field_storage_t field_storage; + + // Field: cliccfg.cliccfg.mnlbits + always_comb begin + automatic logic [3:0] next_c; + automatic logic load_next_c; + next_c = field_storage.cliccfg.mnlbits.value; + load_next_c = '0; + if(decoded_reg_strb.cliccfg && decoded_req_is_wr) begin // SW write + next_c = (field_storage.cliccfg.mnlbits.value & ~decoded_wr_biten[3:0]) | (decoded_wr_data[3:0] & decoded_wr_biten[3:0]); + load_next_c = '1; + end + field_combo.cliccfg.mnlbits.next = next_c; + field_combo.cliccfg.mnlbits.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.cliccfg.mnlbits.value <= 4'h0; + end else begin + if(field_combo.cliccfg.mnlbits.load_next) begin + field_storage.cliccfg.mnlbits.value <= field_combo.cliccfg.mnlbits.next; + end + end + end + assign hwif_out.cliccfg.mnlbits.value = field_storage.cliccfg.mnlbits.value; + // Field: cliccfg.cliccfg.nmbits + always_comb begin + automatic logic [1:0] next_c; + automatic logic load_next_c; + next_c = field_storage.cliccfg.nmbits.value; + load_next_c = '0; + if(decoded_reg_strb.cliccfg && decoded_req_is_wr) begin // SW write + next_c = (field_storage.cliccfg.nmbits.value & ~decoded_wr_biten[5:4]) | (decoded_wr_data[5:4] & decoded_wr_biten[5:4]); + load_next_c = '1; + end + field_combo.cliccfg.nmbits.next = next_c; + field_combo.cliccfg.nmbits.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.cliccfg.nmbits.value <= 2'h0; + end else begin + if(field_combo.cliccfg.nmbits.load_next) begin + field_storage.cliccfg.nmbits.value <= field_combo.cliccfg.nmbits.next; + end + end + end + assign hwif_out.cliccfg.nmbits.value = field_storage.cliccfg.nmbits.value; + // Field: cliccfg.cliccfg.snlbits + always_comb begin + automatic logic [3:0] next_c; + automatic logic load_next_c; + next_c = field_storage.cliccfg.snlbits.value; + load_next_c = '0; + if(decoded_reg_strb.cliccfg && decoded_req_is_wr) begin // SW write + next_c = (field_storage.cliccfg.snlbits.value & ~decoded_wr_biten[19:16]) | (decoded_wr_data[19:16] & decoded_wr_biten[19:16]); + load_next_c = '1; + end + field_combo.cliccfg.snlbits.next = next_c; + field_combo.cliccfg.snlbits.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.cliccfg.snlbits.value <= 4'h0; + end else begin + if(field_combo.cliccfg.snlbits.load_next) begin + field_storage.cliccfg.snlbits.value <= field_combo.cliccfg.snlbits.next; + end + end + end + assign hwif_out.cliccfg.snlbits.value = field_storage.cliccfg.snlbits.value; + // Field: cliccfg.cliccfg.unlbits + always_comb begin + automatic logic [3:0] next_c; + automatic logic load_next_c; + next_c = field_storage.cliccfg.unlbits.value; + load_next_c = '0; + if(decoded_reg_strb.cliccfg && decoded_req_is_wr) begin // SW write + next_c = (field_storage.cliccfg.unlbits.value & ~decoded_wr_biten[27:24]) | (decoded_wr_data[27:24] & decoded_wr_biten[27:24]); + load_next_c = '1; + end + field_combo.cliccfg.unlbits.next = next_c; + field_combo.cliccfg.unlbits.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.cliccfg.unlbits.value <= 4'h0; + end else begin + if(field_combo.cliccfg.unlbits.load_next) begin + field_storage.cliccfg.unlbits.value <= field_combo.cliccfg.unlbits.next; + end + end + end + assign hwif_out.cliccfg.unlbits.value = field_storage.cliccfg.unlbits.value; + + //-------------------------------------------------------------------------- + // Write response + //-------------------------------------------------------------------------- + assign cpuif_wr_ack = decoded_req & decoded_req_is_wr; + // Writes are always granted with no error response + assign cpuif_wr_err = '0; + + //-------------------------------------------------------------------------- + // Readback + //-------------------------------------------------------------------------- + + logic [2:0] rd_mux_addr; + assign rd_mux_addr = decoded_addr; + + logic readback_err; + logic readback_done; + logic [31:0] readback_data; + always_comb begin + automatic logic [31:0] readback_data_var; + readback_data_var = '0; + if(rd_mux_addr == 3'h0) begin + readback_data_var[3:0] = field_storage.cliccfg.mnlbits.value; + readback_data_var[5:4] = field_storage.cliccfg.nmbits.value; + readback_data_var[19:16] = field_storage.cliccfg.snlbits.value; + readback_data_var[27:24] = field_storage.cliccfg.unlbits.value; + end + readback_data = readback_data_var; + readback_done = decoded_req & ~decoded_req_is_wr; + readback_err = '0; + end + + assign cpuif_rd_ack = readback_done; + assign cpuif_rd_data = readback_data; + assign cpuif_rd_err = readback_err; +endmodule diff --git a/src/cliccfg_reg_pkg.sv b/src/cliccfg_reg_pkg.sv new file mode 100644 index 0000000..0719734 --- /dev/null +++ b/src/cliccfg_reg_pkg.sv @@ -0,0 +1,40 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-regblock + +package cliccfg_reg_pkg; + + localparam CLICCFG_REG_DATA_WIDTH = 32; + localparam CLICCFG_REG_MIN_ADDR_WIDTH = 3; + localparam CLICCFG_REG_SIZE = 'h4; + + typedef struct { + logic [3:0] value; + } cliccfg_t__mnlbits__out_t; + + typedef struct { + logic [1:0] value; + } cliccfg_t__nmbits__out_t; + + typedef struct { + logic [3:0] value; + } cliccfg_t__snlbits__out_t; + + typedef struct { + logic [3:0] value; + } cliccfg_t__unlbits__out_t; + + typedef struct { + cliccfg_t__mnlbits__out_t mnlbits; + cliccfg_t__nmbits__out_t nmbits; + cliccfg_t__snlbits__out_t snlbits; + cliccfg_t__unlbits__out_t unlbits; + } cliccfg_t__out_t; + + typedef struct { + cliccfg_t__out_t cliccfg; + } cliccfg__out_t; +endpackage diff --git a/src/clicint_reg.sv b/src/clicint_reg.sv new file mode 100644 index 0000000..669524a --- /dev/null +++ b/src/clicint_reg.sv @@ -0,0 +1,355 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-regblock + +module clicint_reg ( + input wire clk, + input wire arst_n, + + input wire s_apb_psel, + input wire s_apb_penable, + input wire s_apb_pwrite, + input wire [2:0] s_apb_pprot, + input wire [2:0] s_apb_paddr, + input wire [31:0] s_apb_pwdata, + input wire [3:0] s_apb_pstrb, + output logic s_apb_pready, + output logic [31:0] s_apb_prdata, + output logic s_apb_pslverr, + + input clicint_reg_pkg::clicint__in_t hwif_in, + output clicint_reg_pkg::clicint__out_t hwif_out + ); + + //-------------------------------------------------------------------------- + // CPU Bus interface logic + //-------------------------------------------------------------------------- + logic cpuif_req; + logic cpuif_req_is_wr; + logic [2:0] cpuif_addr; + logic [31:0] cpuif_wr_data; + logic [31:0] cpuif_wr_biten; + logic cpuif_req_stall_wr; + logic cpuif_req_stall_rd; + + logic cpuif_rd_ack; + logic cpuif_rd_err; + logic [31:0] cpuif_rd_data; + + logic cpuif_wr_ack; + logic cpuif_wr_err; + + // Request + logic is_active; + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + is_active <= '0; + cpuif_req <= '0; + cpuif_req_is_wr <= '0; + cpuif_addr <= '0; + cpuif_wr_data <= '0; + cpuif_wr_biten <= '0; + end else begin + if(~is_active) begin + if(s_apb_psel) begin + is_active <= '1; + cpuif_req <= '1; + cpuif_req_is_wr <= s_apb_pwrite; + cpuif_addr <= {s_apb_paddr[2:2], 2'b0}; + cpuif_wr_data <= s_apb_pwdata; + for(int i=0; i<4; i++) begin + cpuif_wr_biten[i*8 +: 8] <= {8{s_apb_pstrb[i]}}; + end + end + end else begin + cpuif_req <= '0; + if(cpuif_rd_ack || cpuif_wr_ack) begin + is_active <= '0; + end + end + end + end + + // Response + assign s_apb_pready = cpuif_rd_ack | cpuif_wr_ack; + assign s_apb_prdata = cpuif_rd_data; + assign s_apb_pslverr = cpuif_rd_err | cpuif_wr_err; + + logic cpuif_req_masked; + + // Read & write latencies are balanced. Stalls not required + assign cpuif_req_stall_rd = '0; + assign cpuif_req_stall_wr = '0; + assign cpuif_req_masked = cpuif_req + & !(!cpuif_req_is_wr & cpuif_req_stall_rd) + & !(cpuif_req_is_wr & cpuif_req_stall_wr); + + //-------------------------------------------------------------------------- + // Address Decode + //-------------------------------------------------------------------------- + typedef struct { + logic clicint; + } decoded_reg_strb_t; + decoded_reg_strb_t decoded_reg_strb; + logic decoded_err; + logic [2:0] decoded_addr; + logic decoded_req; + logic decoded_req_is_wr; + logic [31:0] decoded_wr_data; + logic [31:0] decoded_wr_biten; + + always_comb begin + automatic logic is_valid_addr; + automatic logic is_valid_rw; + is_valid_addr = '1; // No valid address check + is_valid_rw = '1; // No valid RW check + decoded_reg_strb.clicint = cpuif_req_masked & (cpuif_addr == 3'h0); + decoded_err = '0; + end + + // Pass down signals to next stage + assign decoded_addr = cpuif_addr; + assign decoded_req = cpuif_req_masked; + assign decoded_req_is_wr = cpuif_req_is_wr; + assign decoded_wr_data = cpuif_wr_data; + assign decoded_wr_biten = cpuif_wr_biten; + + //-------------------------------------------------------------------------- + // Field logic + //-------------------------------------------------------------------------- + typedef struct { + struct { + struct { + logic next; + logic load_next; + } ip; + struct { + logic next; + logic load_next; + } ie; + struct { + logic next; + logic load_next; + } attr_shv; + struct { + logic [1:0] next; + logic load_next; + } attr_trig; + struct { + logic [1:0] next; + logic load_next; + } attr_mode; + struct { + logic [7:0] next; + logic load_next; + } ctl; + } clicint; + } field_combo_t; + field_combo_t field_combo; + + typedef struct { + struct { + struct { + logic value; + } ip; + struct { + logic value; + } ie; + struct { + logic value; + } attr_shv; + struct { + logic [1:0] value; + } attr_trig; + struct { + logic [1:0] value; + } attr_mode; + struct { + logic [7:0] value; + } ctl; + } clicint; + } field_storage_t; + field_storage_t field_storage; + + // Field: clicint.clicint.ip + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicint.ip.value; + load_next_c = '0; + if(decoded_reg_strb.clicint && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicint.ip.value & ~decoded_wr_biten[0:0]) | (decoded_wr_data[0:0] & decoded_wr_biten[0:0]); + load_next_c = '1; + end else if(hwif_in.clicint.ip.we) begin // HW Write - we + next_c = hwif_in.clicint.ip.next; + load_next_c = '1; + end + field_combo.clicint.ip.next = next_c; + field_combo.clicint.ip.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicint.ip.value <= 1'h0; + end else begin + if(field_combo.clicint.ip.load_next) begin + field_storage.clicint.ip.value <= field_combo.clicint.ip.next; + end + end + end + assign hwif_out.clicint.ip.value = field_storage.clicint.ip.value; + // Field: clicint.clicint.ie + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicint.ie.value; + load_next_c = '0; + if(decoded_reg_strb.clicint && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicint.ie.value & ~decoded_wr_biten[8:8]) | (decoded_wr_data[8:8] & decoded_wr_biten[8:8]); + load_next_c = '1; + end + field_combo.clicint.ie.next = next_c; + field_combo.clicint.ie.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicint.ie.value <= 1'h0; + end else begin + if(field_combo.clicint.ie.load_next) begin + field_storage.clicint.ie.value <= field_combo.clicint.ie.next; + end + end + end + assign hwif_out.clicint.ie.value = field_storage.clicint.ie.value; + // Field: clicint.clicint.attr_shv + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicint.attr_shv.value; + load_next_c = '0; + if(decoded_reg_strb.clicint && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicint.attr_shv.value & ~decoded_wr_biten[16:16]) | (decoded_wr_data[16:16] & decoded_wr_biten[16:16]); + load_next_c = '1; + end + field_combo.clicint.attr_shv.next = next_c; + field_combo.clicint.attr_shv.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicint.attr_shv.value <= 1'h0; + end else begin + if(field_combo.clicint.attr_shv.load_next) begin + field_storage.clicint.attr_shv.value <= field_combo.clicint.attr_shv.next; + end + end + end + assign hwif_out.clicint.attr_shv.value = field_storage.clicint.attr_shv.value; + // Field: clicint.clicint.attr_trig + always_comb begin + automatic logic [1:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicint.attr_trig.value; + load_next_c = '0; + if(decoded_reg_strb.clicint && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicint.attr_trig.value & ~decoded_wr_biten[18:17]) | (decoded_wr_data[18:17] & decoded_wr_biten[18:17]); + load_next_c = '1; + end + field_combo.clicint.attr_trig.next = next_c; + field_combo.clicint.attr_trig.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicint.attr_trig.value <= 2'h0; + end else begin + if(field_combo.clicint.attr_trig.load_next) begin + field_storage.clicint.attr_trig.value <= field_combo.clicint.attr_trig.next; + end + end + end + assign hwif_out.clicint.attr_trig.value = field_storage.clicint.attr_trig.value; + // Field: clicint.clicint.attr_mode + always_comb begin + automatic logic [1:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicint.attr_mode.value; + load_next_c = '0; + if(decoded_reg_strb.clicint && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicint.attr_mode.value & ~decoded_wr_biten[23:22]) | (decoded_wr_data[23:22] & decoded_wr_biten[23:22]); + load_next_c = '1; + end + field_combo.clicint.attr_mode.next = next_c; + field_combo.clicint.attr_mode.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicint.attr_mode.value <= 2'h3; + end else begin + if(field_combo.clicint.attr_mode.load_next) begin + field_storage.clicint.attr_mode.value <= field_combo.clicint.attr_mode.next; + end + end + end + assign hwif_out.clicint.attr_mode.value = field_storage.clicint.attr_mode.value; + // Field: clicint.clicint.ctl + always_comb begin + automatic logic [7:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicint.ctl.value; + load_next_c = '0; + if(decoded_reg_strb.clicint && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicint.ctl.value & ~decoded_wr_biten[31:24]) | (decoded_wr_data[31:24] & decoded_wr_biten[31:24]); + load_next_c = '1; + end + field_combo.clicint.ctl.next = next_c; + field_combo.clicint.ctl.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicint.ctl.value <= 8'h0; + end else begin + if(field_combo.clicint.ctl.load_next) begin + field_storage.clicint.ctl.value <= field_combo.clicint.ctl.next; + end + end + end + assign hwif_out.clicint.ctl.value = field_storage.clicint.ctl.value; + + //-------------------------------------------------------------------------- + // Write response + //-------------------------------------------------------------------------- + assign cpuif_wr_ack = decoded_req & decoded_req_is_wr; + // Writes are always granted with no error response + assign cpuif_wr_err = '0; + + //-------------------------------------------------------------------------- + // Readback + //-------------------------------------------------------------------------- + + logic [2:0] rd_mux_addr; + assign rd_mux_addr = decoded_addr; + + logic readback_err; + logic readback_done; + logic [31:0] readback_data; + always_comb begin + automatic logic [31:0] readback_data_var; + readback_data_var = '0; + if(rd_mux_addr == 3'h0) begin + readback_data_var[0] = field_storage.clicint.ip.value; + readback_data_var[8] = field_storage.clicint.ie.value; + readback_data_var[16] = field_storage.clicint.attr_shv.value; + readback_data_var[18:17] = field_storage.clicint.attr_trig.value; + readback_data_var[23:22] = field_storage.clicint.attr_mode.value; + readback_data_var[31:24] = field_storage.clicint.ctl.value; + end + readback_data = readback_data_var; + readback_done = decoded_req & ~decoded_req_is_wr; + readback_err = '0; + end + + assign cpuif_rd_ack = readback_done; + assign cpuif_rd_data = readback_data; + assign cpuif_rd_err = readback_err; +endmodule diff --git a/src/clicint_reg_pkg.sv b/src/clicint_reg_pkg.sv index b88579b..91f40b9 100644 --- a/src/clicint_reg_pkg.sv +++ b/src/clicint_reg_pkg.sv @@ -1,68 +1,63 @@ -// Copyright lowRISC contributors. +// Copyright 2026 ETH Zurich and University of Bologna. // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -// -// Register Package auto-generated by `reggen` containing data structure -package clicint_reg_pkg; - - // Address widths within the block - parameter int BlockAw = 2; - - //////////////////////////// - // Typedefs for registers // - //////////////////////////// - - typedef struct packed { - struct packed { - logic q; - } ip; - struct packed { - logic q; - } ie; - struct packed { - logic q; - } attr_shv; - struct packed { - logic [1:0] q; - } attr_trig; - struct packed { - logic [1:0] q; - } attr_mode; - struct packed { - logic [7:0] q; - } ctl; - } clicint_reg2hw_clicint_reg_t; - - typedef struct packed { - struct packed { - logic d; - logic de; - } ip; - } clicint_hw2reg_clicint_reg_t; - - // Register -> HW type - typedef struct packed { - clicint_reg2hw_clicint_reg_t clicint; // [14:0] - } clicint_reg2hw_t; +// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-regblock - // HW -> register type - typedef struct packed { - clicint_hw2reg_clicint_reg_t clicint; // [1:0] - } clicint_hw2reg_t; - - // Register offsets - parameter logic [BlockAw-1:0] CLICINT_CLICINT_OFFSET = 2'h 0; - - // Register index - typedef enum int { - CLICINT_CLICINT - } clicint_id_e; - - // Register width information to check illegal writes - parameter logic [3:0] CLICINT_PERMIT [1] = '{ - 4'b 1111 // index[0] CLICINT_CLICINT - }; +package clicint_reg_pkg; + localparam CLICINT_REG_DATA_WIDTH = 32; + localparam CLICINT_REG_MIN_ADDR_WIDTH = 3; + localparam CLICINT_REG_SIZE = 'h4; + + typedef struct { + logic next; + logic we; + } clicint_t__ip__in_t; + + typedef struct { + clicint_t__ip__in_t ip; + } clicint_t__in_t; + + typedef struct { + clicint_t__in_t clicint; + } clicint__in_t; + + typedef struct { + logic value; + } clicint_t__ip__out_t; + + typedef struct { + logic value; + } clicint_t__ie__out_t; + + typedef struct { + logic value; + } clicint_t__attr_shv__out_t; + + typedef struct { + logic [1:0] value; + } clicint_t__attr_trig__out_t; + + typedef struct { + logic [1:0] value; + } clicint_t__attr_mode__out_t; + + typedef struct { + logic [7:0] value; + } clicint_t__ctl__out_t; + + typedef struct { + clicint_t__ip__out_t ip; + clicint_t__ie__out_t ie; + clicint_t__attr_shv__out_t attr_shv; + clicint_t__attr_trig__out_t attr_trig; + clicint_t__attr_mode__out_t attr_mode; + clicint_t__ctl__out_t ctl; + } clicint_t__out_t; + + typedef struct { + clicint_t__out_t clicint; + } clicint__out_t; endpackage - diff --git a/src/clicint_reg_top.sv b/src/clicint_reg_top.sv deleted file mode 100644 index 6552ea0..0000000 --- a/src/clicint_reg_top.sv +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// Register Top module auto-generated by `reggen` - - -`include "common_cells/assertions.svh" - -module clicint_reg_top #( - parameter type reg_req_t = logic, - parameter type reg_rsp_t = logic, - parameter int AW = 2 -) ( - input logic clk_i, - input logic rst_ni, - input reg_req_t reg_req_i, - output reg_rsp_t reg_rsp_o, - // To HW - output clicint_reg_pkg::clicint_reg2hw_t reg2hw, // Write - input clicint_reg_pkg::clicint_hw2reg_t hw2reg, // Read - - - // Config - input devmode_i // If 1, explicit error return for unmapped register access -); - - import clicint_reg_pkg::* ; - - localparam int DW = 32; - localparam int DBW = DW/8; // Byte Width - - // register signals - logic reg_we; - logic reg_re; - logic [BlockAw-1:0] reg_addr; - logic [DW-1:0] reg_wdata; - logic [DBW-1:0] reg_be; - logic [DW-1:0] reg_rdata; - logic reg_error; - - logic addrmiss, wr_err; - - logic [DW-1:0] reg_rdata_next; - - // Below register interface can be changed - reg_req_t reg_intf_req; - reg_rsp_t reg_intf_rsp; - - - assign reg_intf_req = reg_req_i; - assign reg_rsp_o = reg_intf_rsp; - - - assign reg_we = reg_intf_req.valid & reg_intf_req.write; - assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; - assign reg_addr = reg_intf_req.addr[BlockAw-1:0]; - assign reg_wdata = reg_intf_req.wdata; - assign reg_be = reg_intf_req.wstrb; - assign reg_intf_rsp.rdata = reg_rdata; - assign reg_intf_rsp.error = reg_error; - assign reg_intf_rsp.ready = 1'b1; - - assign reg_rdata = reg_rdata_next ; - assign reg_error = (devmode_i & addrmiss) | wr_err; - - - // Define SW related signals - // Format: __{wd|we|qs} - // or _{wd|we|qs} if field == 1 or 0 - logic clicint_ip_qs; - logic clicint_ip_wd; - logic clicint_ip_we; - logic clicint_ie_qs; - logic clicint_ie_wd; - logic clicint_ie_we; - logic clicint_attr_shv_qs; - logic clicint_attr_shv_wd; - logic clicint_attr_shv_we; - logic [1:0] clicint_attr_trig_qs; - logic [1:0] clicint_attr_trig_wd; - logic clicint_attr_trig_we; - logic [1:0] clicint_attr_mode_qs; - logic [1:0] clicint_attr_mode_wd; - logic clicint_attr_mode_we; - logic [7:0] clicint_ctl_qs; - logic [7:0] clicint_ctl_wd; - logic clicint_ctl_we; - - // Register instances - // R[clicint]: V(False) - - // F[ip]: 0:0 - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_clicint_ip ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicint_ip_we), - .wd (clicint_ip_wd), - - // from internal hardware - .de (hw2reg.clicint.ip.de), - .d (hw2reg.clicint.ip.d ), - - // to internal hardware - .qe (), - .q (reg2hw.clicint.ip.q ), - - // to register interface (read) - .qs (clicint_ip_qs) - ); - - - // F[ie]: 8:8 - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_clicint_ie ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicint_ie_we), - .wd (clicint_ie_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicint.ie.q ), - - // to register interface (read) - .qs (clicint_ie_qs) - ); - - - // F[attr_shv]: 16:16 - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_clicint_attr_shv ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicint_attr_shv_we), - .wd (clicint_attr_shv_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicint.attr_shv.q ), - - // to register interface (read) - .qs (clicint_attr_shv_qs) - ); - - - // F[attr_trig]: 18:17 - prim_subreg #( - .DW (2), - .SWACCESS("RW"), - .RESVAL (2'h0) - ) u_clicint_attr_trig ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicint_attr_trig_we), - .wd (clicint_attr_trig_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicint.attr_trig.q ), - - // to register interface (read) - .qs (clicint_attr_trig_qs) - ); - - - // F[attr_mode]: 23:22 - prim_subreg #( - .DW (2), - .SWACCESS("RW"), - .RESVAL (2'h3) - ) u_clicint_attr_mode ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicint_attr_mode_we), - .wd (clicint_attr_mode_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicint.attr_mode.q ), - - // to register interface (read) - .qs (clicint_attr_mode_qs) - ); - - - // F[ctl]: 31:24 - prim_subreg #( - .DW (8), - .SWACCESS("RW"), - .RESVAL (8'h0) - ) u_clicint_ctl ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicint_ctl_we), - .wd (clicint_ctl_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicint.ctl.q ), - - // to register interface (read) - .qs (clicint_ctl_qs) - ); - - - - - logic [0:0] addr_hit; - always_comb begin - addr_hit = '0; - addr_hit[0] = (reg_addr == CLICINT_CLICINT_OFFSET); - end - - assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; - - // Check sub-word write is permitted - always_comb begin - wr_err = (reg_we & - ((addr_hit[0] & (|(CLICINT_PERMIT[0] & ~reg_be))))); - end - - assign clicint_ip_we = addr_hit[0] & reg_we & !reg_error; - assign clicint_ip_wd = reg_wdata[0]; - - assign clicint_ie_we = addr_hit[0] & reg_we & !reg_error; - assign clicint_ie_wd = reg_wdata[8]; - - assign clicint_attr_shv_we = addr_hit[0] & reg_we & !reg_error; - assign clicint_attr_shv_wd = reg_wdata[16]; - - assign clicint_attr_trig_we = addr_hit[0] & reg_we & !reg_error; - assign clicint_attr_trig_wd = reg_wdata[18:17]; - - assign clicint_attr_mode_we = addr_hit[0] & reg_we & !reg_error; - assign clicint_attr_mode_wd = reg_wdata[23:22]; - - assign clicint_ctl_we = addr_hit[0] & reg_we & !reg_error; - assign clicint_ctl_wd = reg_wdata[31:24]; - - // Read data return - always_comb begin - reg_rdata_next = '0; - unique case (1'b1) - addr_hit[0]: begin - reg_rdata_next[0] = clicint_ip_qs; - reg_rdata_next[8] = clicint_ie_qs; - reg_rdata_next[16] = clicint_attr_shv_qs; - reg_rdata_next[18:17] = clicint_attr_trig_qs; - reg_rdata_next[23:22] = clicint_attr_mode_qs; - reg_rdata_next[31:24] = clicint_ctl_qs; - end - - default: begin - reg_rdata_next = '1; - end - endcase - end - - // Unused signal tieoff - - // wdata / byte enable are not always fully used - // add a blanket unused statement to handle lint waivers - logic unused_wdata; - logic unused_be; - assign unused_wdata = ^reg_wdata; - assign unused_be = ^reg_be; - - // Assertions for Register Interface - `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) - -endmodule - -module clicint_reg_top_intf -#( - parameter int AW = 2, - localparam int DW = 32 -) ( - input logic clk_i, - input logic rst_ni, - REG_BUS.in regbus_slave, - // To HW - output clicint_reg_pkg::clicint_reg2hw_t reg2hw, // Write - input clicint_reg_pkg::clicint_hw2reg_t hw2reg, // Read - // Config - input devmode_i // If 1, explicit error return for unmapped register access -); - localparam int unsigned STRB_WIDTH = DW/8; - -`include "register_interface/typedef.svh" -`include "register_interface/assign.svh" - - // Define structs for reg_bus - typedef logic [AW-1:0] addr_t; - typedef logic [DW-1:0] data_t; - typedef logic [STRB_WIDTH-1:0] strb_t; - `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t) - - reg_bus_req_t s_reg_req; - reg_bus_rsp_t s_reg_rsp; - - // Assign SV interface to structs - `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave) - `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp) - - - - clicint_reg_top #( - .reg_req_t(reg_bus_req_t), - .reg_rsp_t(reg_bus_rsp_t), - .AW(AW) - ) i_regs ( - .clk_i, - .rst_ni, - .reg_req_i(s_reg_req), - .reg_rsp_o(s_reg_rsp), - .reg2hw, // Write - .hw2reg, // Read - .devmode_i - ); - -endmodule - - diff --git a/src/clicintv_reg.sv b/src/clicintv_reg.sv new file mode 100644 index 0000000..068eabb --- /dev/null +++ b/src/clicintv_reg.sv @@ -0,0 +1,413 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-regblock + +module clicintv_reg ( + input wire clk, + input wire arst_n, + + input wire s_apb_psel, + input wire s_apb_penable, + input wire s_apb_pwrite, + input wire [2:0] s_apb_pprot, + input wire [2:0] s_apb_paddr, + input wire [31:0] s_apb_pwdata, + input wire [3:0] s_apb_pstrb, + output logic s_apb_pready, + output logic [31:0] s_apb_prdata, + output logic s_apb_pslverr, + + output clicintv_reg_pkg::clicintv__out_t hwif_out + ); + + //-------------------------------------------------------------------------- + // CPU Bus interface logic + //-------------------------------------------------------------------------- + logic cpuif_req; + logic cpuif_req_is_wr; + logic [2:0] cpuif_addr; + logic [31:0] cpuif_wr_data; + logic [31:0] cpuif_wr_biten; + logic cpuif_req_stall_wr; + logic cpuif_req_stall_rd; + + logic cpuif_rd_ack; + logic cpuif_rd_err; + logic [31:0] cpuif_rd_data; + + logic cpuif_wr_ack; + logic cpuif_wr_err; + + // Request + logic is_active; + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + is_active <= '0; + cpuif_req <= '0; + cpuif_req_is_wr <= '0; + cpuif_addr <= '0; + cpuif_wr_data <= '0; + cpuif_wr_biten <= '0; + end else begin + if(~is_active) begin + if(s_apb_psel) begin + is_active <= '1; + cpuif_req <= '1; + cpuif_req_is_wr <= s_apb_pwrite; + cpuif_addr <= {s_apb_paddr[2:2], 2'b0}; + cpuif_wr_data <= s_apb_pwdata; + for(int i=0; i<4; i++) begin + cpuif_wr_biten[i*8 +: 8] <= {8{s_apb_pstrb[i]}}; + end + end + end else begin + cpuif_req <= '0; + if(cpuif_rd_ack || cpuif_wr_ack) begin + is_active <= '0; + end + end + end + end + + // Response + assign s_apb_pready = cpuif_rd_ack | cpuif_wr_ack; + assign s_apb_prdata = cpuif_rd_data; + assign s_apb_pslverr = cpuif_rd_err | cpuif_wr_err; + + logic cpuif_req_masked; + + // Read & write latencies are balanced. Stalls not required + assign cpuif_req_stall_rd = '0; + assign cpuif_req_stall_wr = '0; + assign cpuif_req_masked = cpuif_req + & !(!cpuif_req_is_wr & cpuif_req_stall_rd) + & !(cpuif_req_is_wr & cpuif_req_stall_wr); + + //-------------------------------------------------------------------------- + // Address Decode + //-------------------------------------------------------------------------- + typedef struct { + logic clicintv; + } decoded_reg_strb_t; + decoded_reg_strb_t decoded_reg_strb; + logic decoded_err; + logic [2:0] decoded_addr; + logic decoded_req; + logic decoded_req_is_wr; + logic [31:0] decoded_wr_data; + logic [31:0] decoded_wr_biten; + + always_comb begin + automatic logic is_valid_addr; + automatic logic is_valid_rw; + is_valid_addr = '1; // No valid address check + is_valid_rw = '1; // No valid RW check + decoded_reg_strb.clicintv = cpuif_req_masked & (cpuif_addr == 3'h0); + decoded_err = '0; + end + + // Pass down signals to next stage + assign decoded_addr = cpuif_addr; + assign decoded_req = cpuif_req_masked; + assign decoded_req_is_wr = cpuif_req_is_wr; + assign decoded_wr_data = cpuif_wr_data; + assign decoded_wr_biten = cpuif_wr_biten; + + //-------------------------------------------------------------------------- + // Field logic + //-------------------------------------------------------------------------- + typedef struct { + struct { + struct { + logic next; + logic load_next; + } v0; + struct { + logic [5:0] next; + logic load_next; + } vsid0; + struct { + logic next; + logic load_next; + } v1; + struct { + logic [5:0] next; + logic load_next; + } vsid1; + struct { + logic next; + logic load_next; + } v2; + struct { + logic [5:0] next; + logic load_next; + } vsid2; + struct { + logic next; + logic load_next; + } v3; + struct { + logic [5:0] next; + logic load_next; + } vsid3; + } clicintv; + } field_combo_t; + field_combo_t field_combo; + + typedef struct { + struct { + struct { + logic value; + } v0; + struct { + logic [5:0] value; + } vsid0; + struct { + logic value; + } v1; + struct { + logic [5:0] value; + } vsid1; + struct { + logic value; + } v2; + struct { + logic [5:0] value; + } vsid2; + struct { + logic value; + } v3; + struct { + logic [5:0] value; + } vsid3; + } clicintv; + } field_storage_t; + field_storage_t field_storage; + + // Field: clicintv.clicintv.v0 + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicintv.v0.value; + load_next_c = '0; + if(decoded_reg_strb.clicintv && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicintv.v0.value & ~decoded_wr_biten[0:0]) | (decoded_wr_data[0:0] & decoded_wr_biten[0:0]); + load_next_c = '1; + end + field_combo.clicintv.v0.next = next_c; + field_combo.clicintv.v0.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicintv.v0.value <= 1'h0; + end else begin + if(field_combo.clicintv.v0.load_next) begin + field_storage.clicintv.v0.value <= field_combo.clicintv.v0.next; + end + end + end + assign hwif_out.clicintv.v0.value = field_storage.clicintv.v0.value; + // Field: clicintv.clicintv.vsid0 + always_comb begin + automatic logic [5:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicintv.vsid0.value; + load_next_c = '0; + if(decoded_reg_strb.clicintv && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicintv.vsid0.value & ~decoded_wr_biten[7:2]) | (decoded_wr_data[7:2] & decoded_wr_biten[7:2]); + load_next_c = '1; + end + field_combo.clicintv.vsid0.next = next_c; + field_combo.clicintv.vsid0.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicintv.vsid0.value <= 6'h0; + end else begin + if(field_combo.clicintv.vsid0.load_next) begin + field_storage.clicintv.vsid0.value <= field_combo.clicintv.vsid0.next; + end + end + end + assign hwif_out.clicintv.vsid0.value = field_storage.clicintv.vsid0.value; + // Field: clicintv.clicintv.v1 + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicintv.v1.value; + load_next_c = '0; + if(decoded_reg_strb.clicintv && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicintv.v1.value & ~decoded_wr_biten[8:8]) | (decoded_wr_data[8:8] & decoded_wr_biten[8:8]); + load_next_c = '1; + end + field_combo.clicintv.v1.next = next_c; + field_combo.clicintv.v1.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicintv.v1.value <= 1'h0; + end else begin + if(field_combo.clicintv.v1.load_next) begin + field_storage.clicintv.v1.value <= field_combo.clicintv.v1.next; + end + end + end + assign hwif_out.clicintv.v1.value = field_storage.clicintv.v1.value; + // Field: clicintv.clicintv.vsid1 + always_comb begin + automatic logic [5:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicintv.vsid1.value; + load_next_c = '0; + if(decoded_reg_strb.clicintv && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicintv.vsid1.value & ~decoded_wr_biten[15:10]) | (decoded_wr_data[15:10] & decoded_wr_biten[15:10]); + load_next_c = '1; + end + field_combo.clicintv.vsid1.next = next_c; + field_combo.clicintv.vsid1.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicintv.vsid1.value <= 6'h0; + end else begin + if(field_combo.clicintv.vsid1.load_next) begin + field_storage.clicintv.vsid1.value <= field_combo.clicintv.vsid1.next; + end + end + end + assign hwif_out.clicintv.vsid1.value = field_storage.clicintv.vsid1.value; + // Field: clicintv.clicintv.v2 + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicintv.v2.value; + load_next_c = '0; + if(decoded_reg_strb.clicintv && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicintv.v2.value & ~decoded_wr_biten[16:16]) | (decoded_wr_data[16:16] & decoded_wr_biten[16:16]); + load_next_c = '1; + end + field_combo.clicintv.v2.next = next_c; + field_combo.clicintv.v2.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicintv.v2.value <= 1'h0; + end else begin + if(field_combo.clicintv.v2.load_next) begin + field_storage.clicintv.v2.value <= field_combo.clicintv.v2.next; + end + end + end + assign hwif_out.clicintv.v2.value = field_storage.clicintv.v2.value; + // Field: clicintv.clicintv.vsid2 + always_comb begin + automatic logic [5:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicintv.vsid2.value; + load_next_c = '0; + if(decoded_reg_strb.clicintv && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicintv.vsid2.value & ~decoded_wr_biten[23:18]) | (decoded_wr_data[23:18] & decoded_wr_biten[23:18]); + load_next_c = '1; + end + field_combo.clicintv.vsid2.next = next_c; + field_combo.clicintv.vsid2.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicintv.vsid2.value <= 6'h0; + end else begin + if(field_combo.clicintv.vsid2.load_next) begin + field_storage.clicintv.vsid2.value <= field_combo.clicintv.vsid2.next; + end + end + end + assign hwif_out.clicintv.vsid2.value = field_storage.clicintv.vsid2.value; + // Field: clicintv.clicintv.v3 + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicintv.v3.value; + load_next_c = '0; + if(decoded_reg_strb.clicintv && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicintv.v3.value & ~decoded_wr_biten[24:24]) | (decoded_wr_data[24:24] & decoded_wr_biten[24:24]); + load_next_c = '1; + end + field_combo.clicintv.v3.next = next_c; + field_combo.clicintv.v3.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicintv.v3.value <= 1'h0; + end else begin + if(field_combo.clicintv.v3.load_next) begin + field_storage.clicintv.v3.value <= field_combo.clicintv.v3.next; + end + end + end + assign hwif_out.clicintv.v3.value = field_storage.clicintv.v3.value; + // Field: clicintv.clicintv.vsid3 + always_comb begin + automatic logic [5:0] next_c; + automatic logic load_next_c; + next_c = field_storage.clicintv.vsid3.value; + load_next_c = '0; + if(decoded_reg_strb.clicintv && decoded_req_is_wr) begin // SW write + next_c = (field_storage.clicintv.vsid3.value & ~decoded_wr_biten[31:26]) | (decoded_wr_data[31:26] & decoded_wr_biten[31:26]); + load_next_c = '1; + end + field_combo.clicintv.vsid3.next = next_c; + field_combo.clicintv.vsid3.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.clicintv.vsid3.value <= 6'h0; + end else begin + if(field_combo.clicintv.vsid3.load_next) begin + field_storage.clicintv.vsid3.value <= field_combo.clicintv.vsid3.next; + end + end + end + assign hwif_out.clicintv.vsid3.value = field_storage.clicintv.vsid3.value; + + //-------------------------------------------------------------------------- + // Write response + //-------------------------------------------------------------------------- + assign cpuif_wr_ack = decoded_req & decoded_req_is_wr; + // Writes are always granted with no error response + assign cpuif_wr_err = '0; + + //-------------------------------------------------------------------------- + // Readback + //-------------------------------------------------------------------------- + + logic [2:0] rd_mux_addr; + assign rd_mux_addr = decoded_addr; + + logic readback_err; + logic readback_done; + logic [31:0] readback_data; + always_comb begin + automatic logic [31:0] readback_data_var; + readback_data_var = '0; + if(rd_mux_addr == 3'h0) begin + readback_data_var[0] = field_storage.clicintv.v0.value; + readback_data_var[7:2] = field_storage.clicintv.vsid0.value; + readback_data_var[8] = field_storage.clicintv.v1.value; + readback_data_var[15:10] = field_storage.clicintv.vsid1.value; + readback_data_var[16] = field_storage.clicintv.v2.value; + readback_data_var[23:18] = field_storage.clicintv.vsid2.value; + readback_data_var[24] = field_storage.clicintv.v3.value; + readback_data_var[31:26] = field_storage.clicintv.vsid3.value; + end + readback_data = readback_data_var; + readback_done = decoded_req & ~decoded_req_is_wr; + readback_err = '0; + end + + assign cpuif_rd_ack = readback_done; + assign cpuif_rd_data = readback_data; + assign cpuif_rd_err = readback_err; +endmodule diff --git a/src/clicintv_reg_pkg.sv b/src/clicintv_reg_pkg.sv index e59878e..061ee04 100644 --- a/src/clicintv_reg_pkg.sv +++ b/src/clicintv_reg_pkg.sv @@ -1,62 +1,60 @@ -// Copyright lowRISC contributors. +// Copyright 2026 ETH Zurich and University of Bologna. // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -// -// Register Package auto-generated by `reggen` containing data structure -package clicintv_reg_pkg; +// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-regblock - // Address widths within the block - parameter int BlockAw = 2; - - //////////////////////////// - // Typedefs for registers // - //////////////////////////// - - typedef struct packed { - struct packed { - logic q; - } v0; - struct packed { - logic [5:0] q; - } vsid0; - struct packed { - logic q; - } v1; - struct packed { - logic [5:0] q; - } vsid1; - struct packed { - logic q; - } v2; - struct packed { - logic [5:0] q; - } vsid2; - struct packed { - logic q; - } v3; - struct packed { - logic [5:0] q; - } vsid3; - } clicintv_reg2hw_clicintv_reg_t; - - // Register -> HW type - typedef struct packed { - clicintv_reg2hw_clicintv_reg_t clicintv; // [27:0] - } clicintv_reg2hw_t; - - // Register offsets - parameter logic [BlockAw-1:0] CLICINTV_CLICINTV_OFFSET = 2'h 0; - - // Register index - typedef enum int { - CLICINTV_CLICINTV - } clicintv_id_e; - - // Register width information to check illegal writes - parameter logic [3:0] CLICINTV_PERMIT [1] = '{ - 4'b 1111 // index[0] CLICINTV_CLICINTV - }; +package clicintv_reg_pkg; + localparam CLICINTV_REG_DATA_WIDTH = 32; + localparam CLICINTV_REG_MIN_ADDR_WIDTH = 3; + localparam CLICINTV_REG_SIZE = 'h4; + + typedef struct { + logic value; + } clicintv_t__v0__out_t; + + typedef struct { + logic [5:0] value; + } clicintv_t__vsid0__out_t; + + typedef struct { + logic value; + } clicintv_t__v1__out_t; + + typedef struct { + logic [5:0] value; + } clicintv_t__vsid1__out_t; + + typedef struct { + logic value; + } clicintv_t__v2__out_t; + + typedef struct { + logic [5:0] value; + } clicintv_t__vsid2__out_t; + + typedef struct { + logic value; + } clicintv_t__v3__out_t; + + typedef struct { + logic [5:0] value; + } clicintv_t__vsid3__out_t; + + typedef struct { + clicintv_t__v0__out_t v0; + clicintv_t__vsid0__out_t vsid0; + clicintv_t__v1__out_t v1; + clicintv_t__vsid1__out_t vsid1; + clicintv_t__v2__out_t v2; + clicintv_t__vsid2__out_t vsid2; + clicintv_t__v3__out_t v3; + clicintv_t__vsid3__out_t vsid3; + } clicintv_t__out_t; + + typedef struct { + clicintv_t__out_t clicintv; + } clicintv__out_t; endpackage - diff --git a/src/clicintv_reg_top.sv b/src/clicintv_reg_top.sv deleted file mode 100644 index 3d2e599..0000000 --- a/src/clicintv_reg_top.sv +++ /dev/null @@ -1,429 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// Register Top module auto-generated by `reggen` - - -`include "common_cells/assertions.svh" - -module clicintv_reg_top #( - parameter type reg_req_t = logic, - parameter type reg_rsp_t = logic, - parameter int AW = 2 -) ( - input logic clk_i, - input logic rst_ni, - input reg_req_t reg_req_i, - output reg_rsp_t reg_rsp_o, - // To HW - output clicintv_reg_pkg::clicintv_reg2hw_t reg2hw, // Write - - - // Config - input devmode_i // If 1, explicit error return for unmapped register access -); - - import clicintv_reg_pkg::* ; - - localparam int DW = 32; - localparam int DBW = DW/8; // Byte Width - - // register signals - logic reg_we; - logic reg_re; - logic [BlockAw-1:0] reg_addr; - logic [DW-1:0] reg_wdata; - logic [DBW-1:0] reg_be; - logic [DW-1:0] reg_rdata; - logic reg_error; - - logic addrmiss, wr_err; - - logic [DW-1:0] reg_rdata_next; - - // Below register interface can be changed - reg_req_t reg_intf_req; - reg_rsp_t reg_intf_rsp; - - - assign reg_intf_req = reg_req_i; - assign reg_rsp_o = reg_intf_rsp; - - - assign reg_we = reg_intf_req.valid & reg_intf_req.write; - assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; - assign reg_addr = reg_intf_req.addr[BlockAw-1:0]; - assign reg_wdata = reg_intf_req.wdata; - assign reg_be = reg_intf_req.wstrb; - assign reg_intf_rsp.rdata = reg_rdata; - assign reg_intf_rsp.error = reg_error; - assign reg_intf_rsp.ready = 1'b1; - - assign reg_rdata = reg_rdata_next ; - assign reg_error = (devmode_i & addrmiss) | wr_err; - - - // Define SW related signals - // Format: __{wd|we|qs} - // or _{wd|we|qs} if field == 1 or 0 - logic clicintv_v0_qs; - logic clicintv_v0_wd; - logic clicintv_v0_we; - logic [5:0] clicintv_vsid0_qs; - logic [5:0] clicintv_vsid0_wd; - logic clicintv_vsid0_we; - logic clicintv_v1_qs; - logic clicintv_v1_wd; - logic clicintv_v1_we; - logic [5:0] clicintv_vsid1_qs; - logic [5:0] clicintv_vsid1_wd; - logic clicintv_vsid1_we; - logic clicintv_v2_qs; - logic clicintv_v2_wd; - logic clicintv_v2_we; - logic [5:0] clicintv_vsid2_qs; - logic [5:0] clicintv_vsid2_wd; - logic clicintv_vsid2_we; - logic clicintv_v3_qs; - logic clicintv_v3_wd; - logic clicintv_v3_we; - logic [5:0] clicintv_vsid3_qs; - logic [5:0] clicintv_vsid3_wd; - logic clicintv_vsid3_we; - - // Register instances - // R[clicintv]: V(False) - - // F[v0]: 0:0 - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_clicintv_v0 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintv_v0_we), - .wd (clicintv_v0_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintv.v0.q ), - - // to register interface (read) - .qs (clicintv_v0_qs) - ); - - - // F[vsid0]: 7:2 - prim_subreg #( - .DW (6), - .SWACCESS("RW"), - .RESVAL (6'h0) - ) u_clicintv_vsid0 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintv_vsid0_we), - .wd (clicintv_vsid0_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintv.vsid0.q ), - - // to register interface (read) - .qs (clicintv_vsid0_qs) - ); - - - // F[v1]: 8:8 - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_clicintv_v1 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintv_v1_we), - .wd (clicintv_v1_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintv.v1.q ), - - // to register interface (read) - .qs (clicintv_v1_qs) - ); - - - // F[vsid1]: 15:10 - prim_subreg #( - .DW (6), - .SWACCESS("RW"), - .RESVAL (6'h0) - ) u_clicintv_vsid1 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintv_vsid1_we), - .wd (clicintv_vsid1_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintv.vsid1.q ), - - // to register interface (read) - .qs (clicintv_vsid1_qs) - ); - - - // F[v2]: 16:16 - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_clicintv_v2 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintv_v2_we), - .wd (clicintv_v2_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintv.v2.q ), - - // to register interface (read) - .qs (clicintv_v2_qs) - ); - - - // F[vsid2]: 23:18 - prim_subreg #( - .DW (6), - .SWACCESS("RW"), - .RESVAL (6'h0) - ) u_clicintv_vsid2 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintv_vsid2_we), - .wd (clicintv_vsid2_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintv.vsid2.q ), - - // to register interface (read) - .qs (clicintv_vsid2_qs) - ); - - - // F[v3]: 24:24 - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_clicintv_v3 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintv_v3_we), - .wd (clicintv_v3_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintv.v3.q ), - - // to register interface (read) - .qs (clicintv_v3_qs) - ); - - - // F[vsid3]: 31:26 - prim_subreg #( - .DW (6), - .SWACCESS("RW"), - .RESVAL (6'h0) - ) u_clicintv_vsid3 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (clicintv_vsid3_we), - .wd (clicintv_vsid3_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.clicintv.vsid3.q ), - - // to register interface (read) - .qs (clicintv_vsid3_qs) - ); - - - - - logic [0:0] addr_hit; - always_comb begin - addr_hit = '0; - addr_hit[0] = (reg_addr == CLICINTV_CLICINTV_OFFSET); - end - - assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; - - // Check sub-word write is permitted - always_comb begin - wr_err = (reg_we & - ((addr_hit[0] & (|(CLICINTV_PERMIT[0] & ~reg_be))))); - end - - assign clicintv_v0_we = addr_hit[0] & reg_we & !reg_error; - assign clicintv_v0_wd = reg_wdata[0]; - - assign clicintv_vsid0_we = addr_hit[0] & reg_we & !reg_error; - assign clicintv_vsid0_wd = reg_wdata[7:2]; - - assign clicintv_v1_we = addr_hit[0] & reg_we & !reg_error; - assign clicintv_v1_wd = reg_wdata[8]; - - assign clicintv_vsid1_we = addr_hit[0] & reg_we & !reg_error; - assign clicintv_vsid1_wd = reg_wdata[15:10]; - - assign clicintv_v2_we = addr_hit[0] & reg_we & !reg_error; - assign clicintv_v2_wd = reg_wdata[16]; - - assign clicintv_vsid2_we = addr_hit[0] & reg_we & !reg_error; - assign clicintv_vsid2_wd = reg_wdata[23:18]; - - assign clicintv_v3_we = addr_hit[0] & reg_we & !reg_error; - assign clicintv_v3_wd = reg_wdata[24]; - - assign clicintv_vsid3_we = addr_hit[0] & reg_we & !reg_error; - assign clicintv_vsid3_wd = reg_wdata[31:26]; - - // Read data return - always_comb begin - reg_rdata_next = '0; - unique case (1'b1) - addr_hit[0]: begin - reg_rdata_next[0] = clicintv_v0_qs; - reg_rdata_next[7:2] = clicintv_vsid0_qs; - reg_rdata_next[8] = clicintv_v1_qs; - reg_rdata_next[15:10] = clicintv_vsid1_qs; - reg_rdata_next[16] = clicintv_v2_qs; - reg_rdata_next[23:18] = clicintv_vsid2_qs; - reg_rdata_next[24] = clicintv_v3_qs; - reg_rdata_next[31:26] = clicintv_vsid3_qs; - end - - default: begin - reg_rdata_next = '1; - end - endcase - end - - // Unused signal tieoff - - // wdata / byte enable are not always fully used - // add a blanket unused statement to handle lint waivers - logic unused_wdata; - logic unused_be; - assign unused_wdata = ^reg_wdata; - assign unused_be = ^reg_be; - - // Assertions for Register Interface - `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) - -endmodule - -module clicintv_reg_top_intf -#( - parameter int AW = 2, - localparam int DW = 32 -) ( - input logic clk_i, - input logic rst_ni, - REG_BUS.in regbus_slave, - // To HW - output clicintv_reg_pkg::clicintv_reg2hw_t reg2hw, // Write - // Config - input devmode_i // If 1, explicit error return for unmapped register access -); - localparam int unsigned STRB_WIDTH = DW/8; - -`include "register_interface/typedef.svh" -`include "register_interface/assign.svh" - - // Define structs for reg_bus - typedef logic [AW-1:0] addr_t; - typedef logic [DW-1:0] data_t; - typedef logic [STRB_WIDTH-1:0] strb_t; - `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t) - - reg_bus_req_t s_reg_req; - reg_bus_rsp_t s_reg_rsp; - - // Assign SV interface to structs - `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave) - `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp) - - - - clicintv_reg_top #( - .reg_req_t(reg_bus_req_t), - .reg_rsp_t(reg_bus_rsp_t), - .AW(AW) - ) i_regs ( - .clk_i, - .rst_ni, - .reg_req_i(s_reg_req), - .reg_rsp_o(s_reg_rsp), - .reg2hw, // Write - .devmode_i - ); - -endmodule - - diff --git a/src/clicvs_reg.sv b/src/clicvs_reg.sv new file mode 100644 index 0000000..0a4857b --- /dev/null +++ b/src/clicvs_reg.sv @@ -0,0 +1,289 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-regblock + +module clicvs_reg ( + input wire clk, + input wire arst_n, + + input wire s_apb_psel, + input wire s_apb_penable, + input wire s_apb_pwrite, + input wire [2:0] s_apb_pprot, + input wire [2:0] s_apb_paddr, + input wire [31:0] s_apb_pwdata, + input wire [3:0] s_apb_pstrb, + output logic s_apb_pready, + output logic [31:0] s_apb_prdata, + output logic s_apb_pslverr, + + output clicvs_reg_pkg::clicvs__out_t hwif_out + ); + + //-------------------------------------------------------------------------- + // CPU Bus interface logic + //-------------------------------------------------------------------------- + logic cpuif_req; + logic cpuif_req_is_wr; + logic [2:0] cpuif_addr; + logic [31:0] cpuif_wr_data; + logic [31:0] cpuif_wr_biten; + logic cpuif_req_stall_wr; + logic cpuif_req_stall_rd; + + logic cpuif_rd_ack; + logic cpuif_rd_err; + logic [31:0] cpuif_rd_data; + + logic cpuif_wr_ack; + logic cpuif_wr_err; + + // Request + logic is_active; + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + is_active <= '0; + cpuif_req <= '0; + cpuif_req_is_wr <= '0; + cpuif_addr <= '0; + cpuif_wr_data <= '0; + cpuif_wr_biten <= '0; + end else begin + if(~is_active) begin + if(s_apb_psel) begin + is_active <= '1; + cpuif_req <= '1; + cpuif_req_is_wr <= s_apb_pwrite; + cpuif_addr <= {s_apb_paddr[2:2], 2'b0}; + cpuif_wr_data <= s_apb_pwdata; + for(int i=0; i<4; i++) begin + cpuif_wr_biten[i*8 +: 8] <= {8{s_apb_pstrb[i]}}; + end + end + end else begin + cpuif_req <= '0; + if(cpuif_rd_ack || cpuif_wr_ack) begin + is_active <= '0; + end + end + end + end + + // Response + assign s_apb_pready = cpuif_rd_ack | cpuif_wr_ack; + assign s_apb_prdata = cpuif_rd_data; + assign s_apb_pslverr = cpuif_rd_err | cpuif_wr_err; + + logic cpuif_req_masked; + + // Read & write latencies are balanced. Stalls not required + assign cpuif_req_stall_rd = '0; + assign cpuif_req_stall_wr = '0; + assign cpuif_req_masked = cpuif_req + & !(!cpuif_req_is_wr & cpuif_req_stall_rd) + & !(cpuif_req_is_wr & cpuif_req_stall_wr); + + //-------------------------------------------------------------------------- + // Address Decode + //-------------------------------------------------------------------------- + typedef struct { + logic vsprio; + } decoded_reg_strb_t; + decoded_reg_strb_t decoded_reg_strb; + logic decoded_err; + logic [2:0] decoded_addr; + logic decoded_req; + logic decoded_req_is_wr; + logic [31:0] decoded_wr_data; + logic [31:0] decoded_wr_biten; + + always_comb begin + automatic logic is_valid_addr; + automatic logic is_valid_rw; + is_valid_addr = '1; // No valid address check + is_valid_rw = '1; // No valid RW check + decoded_reg_strb.vsprio = cpuif_req_masked & (cpuif_addr == 3'h0); + decoded_err = '0; + end + + // Pass down signals to next stage + assign decoded_addr = cpuif_addr; + assign decoded_req = cpuif_req_masked; + assign decoded_req_is_wr = cpuif_req_is_wr; + assign decoded_wr_data = cpuif_wr_data; + assign decoded_wr_biten = cpuif_wr_biten; + + //-------------------------------------------------------------------------- + // Field logic + //-------------------------------------------------------------------------- + typedef struct { + struct { + struct { + logic next; + logic load_next; + } prio0; + struct { + logic next; + logic load_next; + } prio1; + struct { + logic next; + logic load_next; + } prio2; + struct { + logic next; + logic load_next; + } prio3; + } vsprio; + } field_combo_t; + field_combo_t field_combo; + + typedef struct { + struct { + struct { + logic value; + } prio0; + struct { + logic value; + } prio1; + struct { + logic value; + } prio2; + struct { + logic value; + } prio3; + } vsprio; + } field_storage_t; + field_storage_t field_storage; + + // Field: clicvs.vsprio.prio0 + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.vsprio.prio0.value; + load_next_c = '0; + if(decoded_reg_strb.vsprio && decoded_req_is_wr) begin // SW write + next_c = (field_storage.vsprio.prio0.value & ~decoded_wr_biten[0:0]) | (decoded_wr_data[0:0] & decoded_wr_biten[0:0]); + load_next_c = '1; + end + field_combo.vsprio.prio0.next = next_c; + field_combo.vsprio.prio0.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.vsprio.prio0.value <= 1'h0; + end else begin + if(field_combo.vsprio.prio0.load_next) begin + field_storage.vsprio.prio0.value <= field_combo.vsprio.prio0.next; + end + end + end + assign hwif_out.vsprio.prio0.value = field_storage.vsprio.prio0.value; + // Field: clicvs.vsprio.prio1 + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.vsprio.prio1.value; + load_next_c = '0; + if(decoded_reg_strb.vsprio && decoded_req_is_wr) begin // SW write + next_c = (field_storage.vsprio.prio1.value & ~decoded_wr_biten[8:8]) | (decoded_wr_data[8:8] & decoded_wr_biten[8:8]); + load_next_c = '1; + end + field_combo.vsprio.prio1.next = next_c; + field_combo.vsprio.prio1.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.vsprio.prio1.value <= 1'h0; + end else begin + if(field_combo.vsprio.prio1.load_next) begin + field_storage.vsprio.prio1.value <= field_combo.vsprio.prio1.next; + end + end + end + assign hwif_out.vsprio.prio1.value = field_storage.vsprio.prio1.value; + // Field: clicvs.vsprio.prio2 + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.vsprio.prio2.value; + load_next_c = '0; + if(decoded_reg_strb.vsprio && decoded_req_is_wr) begin // SW write + next_c = (field_storage.vsprio.prio2.value & ~decoded_wr_biten[16:16]) | (decoded_wr_data[16:16] & decoded_wr_biten[16:16]); + load_next_c = '1; + end + field_combo.vsprio.prio2.next = next_c; + field_combo.vsprio.prio2.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.vsprio.prio2.value <= 1'h0; + end else begin + if(field_combo.vsprio.prio2.load_next) begin + field_storage.vsprio.prio2.value <= field_combo.vsprio.prio2.next; + end + end + end + assign hwif_out.vsprio.prio2.value = field_storage.vsprio.prio2.value; + // Field: clicvs.vsprio.prio3 + always_comb begin + automatic logic [0:0] next_c; + automatic logic load_next_c; + next_c = field_storage.vsprio.prio3.value; + load_next_c = '0; + if(decoded_reg_strb.vsprio && decoded_req_is_wr) begin // SW write + next_c = (field_storage.vsprio.prio3.value & ~decoded_wr_biten[24:24]) | (decoded_wr_data[24:24] & decoded_wr_biten[24:24]); + load_next_c = '1; + end + field_combo.vsprio.prio3.next = next_c; + field_combo.vsprio.prio3.load_next = load_next_c; + end + always_ff @(posedge clk or negedge arst_n) begin + if(~arst_n) begin + field_storage.vsprio.prio3.value <= 1'h0; + end else begin + if(field_combo.vsprio.prio3.load_next) begin + field_storage.vsprio.prio3.value <= field_combo.vsprio.prio3.next; + end + end + end + assign hwif_out.vsprio.prio3.value = field_storage.vsprio.prio3.value; + + //-------------------------------------------------------------------------- + // Write response + //-------------------------------------------------------------------------- + assign cpuif_wr_ack = decoded_req & decoded_req_is_wr; + // Writes are always granted with no error response + assign cpuif_wr_err = '0; + + //-------------------------------------------------------------------------- + // Readback + //-------------------------------------------------------------------------- + + logic [2:0] rd_mux_addr; + assign rd_mux_addr = decoded_addr; + + logic readback_err; + logic readback_done; + logic [31:0] readback_data; + always_comb begin + automatic logic [31:0] readback_data_var; + readback_data_var = '0; + if(rd_mux_addr == 3'h0) begin + readback_data_var[0] = field_storage.vsprio.prio0.value; + readback_data_var[8] = field_storage.vsprio.prio1.value; + readback_data_var[16] = field_storage.vsprio.prio2.value; + readback_data_var[24] = field_storage.vsprio.prio3.value; + end + readback_data = readback_data_var; + readback_done = decoded_req & ~decoded_req_is_wr; + readback_err = '0; + end + + assign cpuif_rd_ack = readback_done; + assign cpuif_rd_data = readback_data; + assign cpuif_rd_err = readback_err; +endmodule diff --git a/src/clicvs_reg_pkg.sv b/src/clicvs_reg_pkg.sv index ea3f6e7..2e47318 100644 --- a/src/clicvs_reg_pkg.sv +++ b/src/clicvs_reg_pkg.sv @@ -1,50 +1,40 @@ -// Copyright lowRISC contributors. +// Copyright 2026 ETH Zurich and University of Bologna. // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 -// -// Register Package auto-generated by `reggen` containing data structure + +// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-regblock package clicvs_reg_pkg; - // Address widths within the block - parameter int BlockAw = 2; - - //////////////////////////// - // Typedefs for registers // - //////////////////////////// - - typedef struct packed { - struct packed { - logic q; - } prio0; - struct packed { - logic q; - } prio1; - struct packed { - logic q; - } prio2; - struct packed { - logic q; - } prio3; - } clicvs_reg2hw_vsprio_reg_t; - - // Register -> HW type - typedef struct packed { - clicvs_reg2hw_vsprio_reg_t vsprio; // [3:0] - } clicvs_reg2hw_t; - - // Register offsets - parameter logic [BlockAw-1:0] CLICVS_VSPRIO_OFFSET = 2'h 0; - - // Register index - typedef enum int { - CLICVS_VSPRIO - } clicvs_id_e; - - // Register width information to check illegal writes - parameter logic [3:0] CLICVS_PERMIT [1] = '{ - 4'b 1111 // index[0] CLICVS_VSPRIO - }; + localparam CLICVS_REG_DATA_WIDTH = 32; + localparam CLICVS_REG_MIN_ADDR_WIDTH = 3; + localparam CLICVS_REG_SIZE = 'h4; -endpackage + typedef struct { + logic value; + } vsprio_t__prio0__out_t; + + typedef struct { + logic value; + } vsprio_t__prio1__out_t; + + typedef struct { + logic value; + } vsprio_t__prio2__out_t; + typedef struct { + logic value; + } vsprio_t__prio3__out_t; + + typedef struct { + vsprio_t__prio0__out_t prio0; + vsprio_t__prio1__out_t prio1; + vsprio_t__prio2__out_t prio2; + vsprio_t__prio3__out_t prio3; + } vsprio_t__out_t; + + typedef struct { + vsprio_t__out_t vsprio; + } clicvs__out_t; +endpackage diff --git a/src/clicvs_reg_top.sv b/src/clicvs_reg_top.sv deleted file mode 100644 index f836899..0000000 --- a/src/clicvs_reg_top.sv +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// Register Top module auto-generated by `reggen` - - -`include "common_cells/assertions.svh" - -module clicvs_reg_top #( - parameter type reg_req_t = logic, - parameter type reg_rsp_t = logic, - parameter int AW = 2 -) ( - input logic clk_i, - input logic rst_ni, - input reg_req_t reg_req_i, - output reg_rsp_t reg_rsp_o, - // To HW - output clicvs_reg_pkg::clicvs_reg2hw_t reg2hw, // Write - - - // Config - input devmode_i // If 1, explicit error return for unmapped register access -); - - import clicvs_reg_pkg::* ; - - localparam int DW = 32; - localparam int DBW = DW/8; // Byte Width - - // register signals - logic reg_we; - logic reg_re; - logic [BlockAw-1:0] reg_addr; - logic [DW-1:0] reg_wdata; - logic [DBW-1:0] reg_be; - logic [DW-1:0] reg_rdata; - logic reg_error; - - logic addrmiss, wr_err; - - logic [DW-1:0] reg_rdata_next; - - // Below register interface can be changed - reg_req_t reg_intf_req; - reg_rsp_t reg_intf_rsp; - - - assign reg_intf_req = reg_req_i; - assign reg_rsp_o = reg_intf_rsp; - - - assign reg_we = reg_intf_req.valid & reg_intf_req.write; - assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; - assign reg_addr = reg_intf_req.addr[BlockAw-1:0]; - assign reg_wdata = reg_intf_req.wdata; - assign reg_be = reg_intf_req.wstrb; - assign reg_intf_rsp.rdata = reg_rdata; - assign reg_intf_rsp.error = reg_error; - assign reg_intf_rsp.ready = 1'b1; - - assign reg_rdata = reg_rdata_next ; - assign reg_error = (devmode_i & addrmiss) | wr_err; - - - // Define SW related signals - // Format: __{wd|we|qs} - // or _{wd|we|qs} if field == 1 or 0 - logic vsprio_prio0_qs; - logic vsprio_prio0_wd; - logic vsprio_prio0_we; - logic vsprio_prio1_qs; - logic vsprio_prio1_wd; - logic vsprio_prio1_we; - logic vsprio_prio2_qs; - logic vsprio_prio2_wd; - logic vsprio_prio2_we; - logic vsprio_prio3_qs; - logic vsprio_prio3_wd; - logic vsprio_prio3_we; - - // Register instances - // R[vsprio]: V(False) - - // F[prio0]: 0:0 - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_vsprio_prio0 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (vsprio_prio0_we), - .wd (vsprio_prio0_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.vsprio.prio0.q ), - - // to register interface (read) - .qs (vsprio_prio0_qs) - ); - - - // F[prio1]: 8:8 - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_vsprio_prio1 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (vsprio_prio1_we), - .wd (vsprio_prio1_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.vsprio.prio1.q ), - - // to register interface (read) - .qs (vsprio_prio1_qs) - ); - - - // F[prio2]: 16:16 - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_vsprio_prio2 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (vsprio_prio2_we), - .wd (vsprio_prio2_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.vsprio.prio2.q ), - - // to register interface (read) - .qs (vsprio_prio2_qs) - ); - - - // F[prio3]: 24:24 - prim_subreg #( - .DW (1), - .SWACCESS("RW"), - .RESVAL (1'h0) - ) u_vsprio_prio3 ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (vsprio_prio3_we), - .wd (vsprio_prio3_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.vsprio.prio3.q ), - - // to register interface (read) - .qs (vsprio_prio3_qs) - ); - - - - - logic [0:0] addr_hit; - always_comb begin - addr_hit = '0; - addr_hit[0] = (reg_addr == CLICVS_VSPRIO_OFFSET); - end - - assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; - - // Check sub-word write is permitted - always_comb begin - wr_err = (reg_we & - ((addr_hit[0] & (|(CLICVS_PERMIT[0] & ~reg_be))))); - end - - assign vsprio_prio0_we = addr_hit[0] & reg_we & !reg_error; - assign vsprio_prio0_wd = reg_wdata[0]; - - assign vsprio_prio1_we = addr_hit[0] & reg_we & !reg_error; - assign vsprio_prio1_wd = reg_wdata[8]; - - assign vsprio_prio2_we = addr_hit[0] & reg_we & !reg_error; - assign vsprio_prio2_wd = reg_wdata[16]; - - assign vsprio_prio3_we = addr_hit[0] & reg_we & !reg_error; - assign vsprio_prio3_wd = reg_wdata[24]; - - // Read data return - always_comb begin - reg_rdata_next = '0; - unique case (1'b1) - addr_hit[0]: begin - reg_rdata_next[0] = vsprio_prio0_qs; - reg_rdata_next[8] = vsprio_prio1_qs; - reg_rdata_next[16] = vsprio_prio2_qs; - reg_rdata_next[24] = vsprio_prio3_qs; - end - - default: begin - reg_rdata_next = '1; - end - endcase - end - - // Unused signal tieoff - - // wdata / byte enable are not always fully used - // add a blanket unused statement to handle lint waivers - logic unused_wdata; - logic unused_be; - assign unused_wdata = ^reg_wdata; - assign unused_be = ^reg_be; - - // Assertions for Register Interface - `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) - -endmodule - -module clicvs_reg_top_intf -#( - parameter int AW = 2, - localparam int DW = 32 -) ( - input logic clk_i, - input logic rst_ni, - REG_BUS.in regbus_slave, - // To HW - output clicvs_reg_pkg::clicvs_reg2hw_t reg2hw, // Write - // Config - input devmode_i // If 1, explicit error return for unmapped register access -); - localparam int unsigned STRB_WIDTH = DW/8; - -`include "register_interface/typedef.svh" -`include "register_interface/assign.svh" - - // Define structs for reg_bus - typedef logic [AW-1:0] addr_t; - typedef logic [DW-1:0] data_t; - typedef logic [STRB_WIDTH-1:0] strb_t; - `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t) - - reg_bus_req_t s_reg_req; - reg_bus_rsp_t s_reg_rsp; - - // Assign SV interface to structs - `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave) - `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp) - - - - clicvs_reg_top #( - .reg_req_t(reg_bus_req_t), - .reg_rsp_t(reg_bus_rsp_t), - .AW(AW) - ) i_regs ( - .clk_i, - .rst_ni, - .reg_req_i(s_reg_req), - .reg_rsp_o(s_reg_rsp), - .reg2hw, // Write - .devmode_i - ); - -endmodule - - diff --git a/src/gen/Makefile b/src/gen/Makefile deleted file mode 100644 index bf1dd65..0000000 --- a/src/gen/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2025 ETH Zurich and University of Bologna. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# SPDX-License-Identifier: Apache-2.0 -# Author: Robert Balas - -# Generate C header and SystemVerilog files - -REGTOOL ?= regtool.py - -SRCS = clicvs_reg_pkg.sv clicvs_reg_top.sv clicintv_reg_pkg.sv clicintv_reg_top.sv clicint_reg_pkg.sv clicint_reg_top.sv mclic_reg_pkg.sv mclic_reg_top.sv -HDRS = clic.h clicint.h clicintv.h clicvs.h - -all: headers srcs - -srcs: $(SRCS) - -clicvs_reg_pkg.sv clicvs_reg_top.sv: clicvs.hjson - $(REGTOOL) -r $< -t . - -clicintv_reg_pkg.sv clicintv_reg_top.sv: clicintv.hjson - $(REGTOOL) -r $< -t . - -clicint_reg_pkg.sv clicint_reg_top.sv: clicint.hjson - $(REGTOOL) -r $< -t . - -mclic_reg_pkg.sv mclic_reg_top.sv: mclic.hjson - $(REGTOOL) -r $< -t . - -headers: $(HDRS) - -clic.h: mclic.hjson - $(REGTOOL) --cdefines mclic.hjson > $@ - -clicint.h: clicint.hjson - $(REGTOOL) --cdefines clicint.hjson > $@ - -clicintv.h: clicintv.hjson - $(REGTOOL) --cdefines clicintv.hjson > $@ - -clicvs.h: clicvs.hjson - $(REGTOOL) --cdefines clicvs.hjson > $@ - -.PHONY: install -install: - cp $(SRCS) .. - -.PHONY: clean -clean: - rm $(HDRS) $(SRCS) - diff --git a/src/gen/clicint.hjson b/src/gen/clicint.hjson deleted file mode 100644 index b8f128c..0000000 --- a/src/gen/clicint.hjson +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2022 ETH Zurich and University of Bologna. -// Copyright and related rights are licensed under the Solderpad Hardware -// License, Version 0.51 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law -// or agreed to in writing, software, hardware and materials distributed under -// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -// SPDX-License-Identifier: Apache-2.0 - -// CLIC interrupt register -{ - name: "CLICINT", - clock_primary: "clk_i", - bus_interfaces: [ - { protocol: "reg_iface", direction: "device" } - ], - - regwidth: "32", - registers: [ - { name: "CLICINT", - desc: "CLIC interrupt pending, enable, attribute and control", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:24", name: "CTL", desc: "interrupt control for interrupt" }, - { bits: "23:22", name: "ATTR_MODE", desc: "privilege mode of this interrupt", resval: 3}, - //{ bits: "21:19", name: "reserved" }, - { bits: "18:17", name: "ATTR_TRIG", desc: "specify trigger type for this interrupt" }, - { bits: "16", name: "ATTR_SHV", desc: "enable hardware vectoring for this interrupt" }, - - { bits: "8", name: "IE", desc: "interrupt enable for interrupt" }, - - { bits: "0", name: "IP", desc: "interrupt pending for interrupt", hwaccess: "hrw" }, - ], - } - ] -} diff --git a/src/gen/clicintv.hjson b/src/gen/clicintv.hjson deleted file mode 100644 index f31c500..0000000 --- a/src/gen/clicintv.hjson +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2022 ETH Zurich and University of Bologna. -// Copyright and related rights are licensed under the Solderpad Hardware -// License, Version 0.51 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law -// or agreed to in writing, software, hardware and materials distributed under -// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -// SPDX-License-Identifier: Apache-2.0 - -// CLIC virtual supervisor interrupt register -{ - name: "CLICINTV", - clock_primary: "clk_i", - bus_interfaces: [ - { protocol: "reg_iface", direction: "device" } - ], - - regwidth: "32", - registers: [ - { name: "CLICINTV", - desc: "CLIC interrupt virtualization", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:26", name: "VSID3", desc: "interrupt VS id" }, - { bits: "24", name: "V3", desc: "interrupt delegated to VS-mode"}, - { bits: "23:18", name: "VSID2", desc: "interrupt VS id" }, - { bits: "16", name: "V2", desc: "interrupt delegated to VS-mode"}, - { bits: "15:10", name: "VSID1", desc: "interrupt VS id" }, - { bits: "8", name: "V1", desc: "interrupt delegated to VS-mode"}, - { bits: "7:2", name: "VSID0", desc: "interrupt VS id" }, - { bits: "0", name: "V0", desc: "interrupt delegated to VS-mode"}, - ], - } - ] -} diff --git a/src/gen/clicvs.hjson b/src/gen/clicvs.hjson deleted file mode 100644 index fccc122..0000000 --- a/src/gen/clicvs.hjson +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2022 ETH Zurich and University of Bologna. -// Copyright and related rights are licensed under the Solderpad Hardware -// License, Version 0.51 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law -// or agreed to in writing, software, hardware and materials distributed under -// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -// SPDX-License-Identifier: Apache-2.0 - -// CLIC virtual supervisor configuration register -{ - name: "CLICVS", - clock_primary: "clk_i", - bus_interfaces: [ - { protocol: "reg_iface", direction: "device" } - ], - - regwidth: "32", - registers: [ - { name: "vsprio", - desc: "CLIC virtual supervisor priority", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "24", name: "prio3", desc: "VS3 priority" }, - { bits: "16", name: "prio2", desc: "VS2 priority" }, - { bits: "8", name: "prio1", desc: "VS1 priority" }, - { bits: "0", name: "prio0", desc: "VS0 priority" }, - ], - } - ] -} diff --git a/src/gen/mclic.hjson b/src/gen/mclic.hjson deleted file mode 100644 index bd1b79a..0000000 --- a/src/gen/mclic.hjson +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2022 ETH Zurich and University of Bologna. -// Copyright and related rights are licensed under the Solderpad Hardware -// License, Version 0.51 (the "License"); you may not use this file except in -// compliance with the License. You may obtain a copy of the License at -// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law -// or agreed to in writing, software, hardware and materials distributed under -// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the -// specific language governing permissions and limitations under the License. - -// SPDX-License-Identifier: Apache-2.0 - -# CLIC m-mode registers -{ - name: "MCLIC", - clock_primary: "clk_i", - bus_interfaces: [ - { protocol: "reg_iface", direction: "device" } - ], - - regwidth: "32", - registers: [ - { name: "MCLICCFG", - desc: "CLIC configuration", - swaccess: "rw", - hwaccess: "hro", - fields: [ - { bits: "31:28", name: "reserved", desc: "reserved", swaccess: "ro", hwaccess: "none" }, # workaround for full 32-bit access - { bits: "27:24", name: "unlbits", desc: "number of privilege mode bits in user mode" }, - //{ bits: "23:20", name: "reserved" }, - { bits: "19:16", name: "snlbits", desc: "number of privilege mode bits in supervisor mode" }, - //{ bits: "15:6", name: "reserved" }, - { bits: "5:4", name: "nmbits", desc: "number of privilege mode bits" }, - { bits: "3:0", name: "mnlbits", desc: "number of interrupt level bits in machine mode" }, - ], - }, - ] -} - diff --git a/src/mclic_reg_pkg.sv b/src/mclic_reg_pkg.sv deleted file mode 100644 index a194e30..0000000 --- a/src/mclic_reg_pkg.sv +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// Register Package auto-generated by `reggen` containing data structure - -package mclic_reg_pkg; - - // Address widths within the block - parameter int BlockAw = 2; - - //////////////////////////// - // Typedefs for registers // - //////////////////////////// - - typedef struct packed { - struct packed { - logic [3:0] q; - } mnlbits; - struct packed { - logic [1:0] q; - } nmbits; - struct packed { - logic [3:0] q; - } snlbits; - struct packed { - logic [3:0] q; - } unlbits; - } mclic_reg2hw_mcliccfg_reg_t; - - // Register -> HW type - typedef struct packed { - mclic_reg2hw_mcliccfg_reg_t mcliccfg; // [13:0] - } mclic_reg2hw_t; - - // Register offsets - parameter logic [BlockAw-1:0] MCLIC_MCLICCFG_OFFSET = 2'h 0; - - // Register index - typedef enum int { - MCLIC_MCLICCFG - } mclic_id_e; - - // Register width information to check illegal writes - parameter logic [3:0] MCLIC_PERMIT [1] = '{ - 4'b 1111 // index[0] MCLIC_MCLICCFG - }; - -endpackage - diff --git a/src/mclic_reg_top.sv b/src/mclic_reg_top.sv deleted file mode 100644 index 93560ed..0000000 --- a/src/mclic_reg_top.sv +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 -// -// Register Top module auto-generated by `reggen` - - -`include "common_cells/assertions.svh" - -module mclic_reg_top #( - parameter type reg_req_t = logic, - parameter type reg_rsp_t = logic, - parameter int AW = 2 -) ( - input logic clk_i, - input logic rst_ni, - input reg_req_t reg_req_i, - output reg_rsp_t reg_rsp_o, - // To HW - output mclic_reg_pkg::mclic_reg2hw_t reg2hw, // Write - - - // Config - input devmode_i // If 1, explicit error return for unmapped register access -); - - import mclic_reg_pkg::* ; - - localparam int DW = 32; - localparam int DBW = DW/8; // Byte Width - - // register signals - logic reg_we; - logic reg_re; - logic [BlockAw-1:0] reg_addr; - logic [DW-1:0] reg_wdata; - logic [DBW-1:0] reg_be; - logic [DW-1:0] reg_rdata; - logic reg_error; - - logic addrmiss, wr_err; - - logic [DW-1:0] reg_rdata_next; - - // Below register interface can be changed - reg_req_t reg_intf_req; - reg_rsp_t reg_intf_rsp; - - - assign reg_intf_req = reg_req_i; - assign reg_rsp_o = reg_intf_rsp; - - - assign reg_we = reg_intf_req.valid & reg_intf_req.write; - assign reg_re = reg_intf_req.valid & ~reg_intf_req.write; - assign reg_addr = reg_intf_req.addr[BlockAw-1:0]; - assign reg_wdata = reg_intf_req.wdata; - assign reg_be = reg_intf_req.wstrb; - assign reg_intf_rsp.rdata = reg_rdata; - assign reg_intf_rsp.error = reg_error; - assign reg_intf_rsp.ready = 1'b1; - - assign reg_rdata = reg_rdata_next ; - assign reg_error = (devmode_i & addrmiss) | wr_err; - - - // Define SW related signals - // Format: __{wd|we|qs} - // or _{wd|we|qs} if field == 1 or 0 - logic [3:0] mcliccfg_mnlbits_qs; - logic [3:0] mcliccfg_mnlbits_wd; - logic mcliccfg_mnlbits_we; - logic [1:0] mcliccfg_nmbits_qs; - logic [1:0] mcliccfg_nmbits_wd; - logic mcliccfg_nmbits_we; - logic [3:0] mcliccfg_snlbits_qs; - logic [3:0] mcliccfg_snlbits_wd; - logic mcliccfg_snlbits_we; - logic [3:0] mcliccfg_unlbits_qs; - logic [3:0] mcliccfg_unlbits_wd; - logic mcliccfg_unlbits_we; - logic [3:0] mcliccfg_reserved_qs; - - // Register instances - // R[mcliccfg]: V(False) - - // F[mnlbits]: 3:0 - prim_subreg #( - .DW (4), - .SWACCESS("RW"), - .RESVAL (4'h0) - ) u_mcliccfg_mnlbits ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (mcliccfg_mnlbits_we), - .wd (mcliccfg_mnlbits_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.mcliccfg.mnlbits.q ), - - // to register interface (read) - .qs (mcliccfg_mnlbits_qs) - ); - - - // F[nmbits]: 5:4 - prim_subreg #( - .DW (2), - .SWACCESS("RW"), - .RESVAL (2'h0) - ) u_mcliccfg_nmbits ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (mcliccfg_nmbits_we), - .wd (mcliccfg_nmbits_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.mcliccfg.nmbits.q ), - - // to register interface (read) - .qs (mcliccfg_nmbits_qs) - ); - - - // F[snlbits]: 19:16 - prim_subreg #( - .DW (4), - .SWACCESS("RW"), - .RESVAL (4'h0) - ) u_mcliccfg_snlbits ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (mcliccfg_snlbits_we), - .wd (mcliccfg_snlbits_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.mcliccfg.snlbits.q ), - - // to register interface (read) - .qs (mcliccfg_snlbits_qs) - ); - - - // F[unlbits]: 27:24 - prim_subreg #( - .DW (4), - .SWACCESS("RW"), - .RESVAL (4'h0) - ) u_mcliccfg_unlbits ( - .clk_i (clk_i ), - .rst_ni (rst_ni ), - - // from register interface - .we (mcliccfg_unlbits_we), - .wd (mcliccfg_unlbits_wd), - - // from internal hardware - .de (1'b0), - .d ('0 ), - - // to internal hardware - .qe (), - .q (reg2hw.mcliccfg.unlbits.q ), - - // to register interface (read) - .qs (mcliccfg_unlbits_qs) - ); - - - // F[reserved]: 31:28 - // constant-only read - assign mcliccfg_reserved_qs = 4'h0; - - - - - logic [0:0] addr_hit; - always_comb begin - addr_hit = '0; - addr_hit[0] = (reg_addr == MCLIC_MCLICCFG_OFFSET); - end - - assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; - - // Check sub-word write is permitted - always_comb begin - wr_err = (reg_we & - ((addr_hit[0] & (|(MCLIC_PERMIT[0] & ~reg_be))))); - end - - assign mcliccfg_mnlbits_we = addr_hit[0] & reg_we & !reg_error; - assign mcliccfg_mnlbits_wd = reg_wdata[3:0]; - - assign mcliccfg_nmbits_we = addr_hit[0] & reg_we & !reg_error; - assign mcliccfg_nmbits_wd = reg_wdata[5:4]; - - assign mcliccfg_snlbits_we = addr_hit[0] & reg_we & !reg_error; - assign mcliccfg_snlbits_wd = reg_wdata[19:16]; - - assign mcliccfg_unlbits_we = addr_hit[0] & reg_we & !reg_error; - assign mcliccfg_unlbits_wd = reg_wdata[27:24]; - - // Read data return - always_comb begin - reg_rdata_next = '0; - unique case (1'b1) - addr_hit[0]: begin - reg_rdata_next[3:0] = mcliccfg_mnlbits_qs; - reg_rdata_next[5:4] = mcliccfg_nmbits_qs; - reg_rdata_next[19:16] = mcliccfg_snlbits_qs; - reg_rdata_next[27:24] = mcliccfg_unlbits_qs; - reg_rdata_next[31:28] = mcliccfg_reserved_qs; - end - - default: begin - reg_rdata_next = '1; - end - endcase - end - - // Unused signal tieoff - - // wdata / byte enable are not always fully used - // add a blanket unused statement to handle lint waivers - logic unused_wdata; - logic unused_be; - assign unused_wdata = ^reg_wdata; - assign unused_be = ^reg_be; - - // Assertions for Register Interface - `ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit)) - -endmodule - -module mclic_reg_top_intf -#( - parameter int AW = 2, - localparam int DW = 32 -) ( - input logic clk_i, - input logic rst_ni, - REG_BUS.in regbus_slave, - // To HW - output mclic_reg_pkg::mclic_reg2hw_t reg2hw, // Write - // Config - input devmode_i // If 1, explicit error return for unmapped register access -); - localparam int unsigned STRB_WIDTH = DW/8; - -`include "register_interface/typedef.svh" -`include "register_interface/assign.svh" - - // Define structs for reg_bus - typedef logic [AW-1:0] addr_t; - typedef logic [DW-1:0] data_t; - typedef logic [STRB_WIDTH-1:0] strb_t; - `REG_BUS_TYPEDEF_ALL(reg_bus, addr_t, data_t, strb_t) - - reg_bus_req_t s_reg_req; - reg_bus_rsp_t s_reg_rsp; - - // Assign SV interface to structs - `REG_BUS_ASSIGN_TO_REQ(s_reg_req, regbus_slave) - `REG_BUS_ASSIGN_FROM_RSP(regbus_slave, s_reg_rsp) - - - - mclic_reg_top #( - .reg_req_t(reg_bus_req_t), - .reg_rsp_t(reg_bus_rsp_t), - .AW(AW) - ) i_regs ( - .clk_i, - .rst_ni, - .reg_req_i(s_reg_req), - .reg_rsp_o(s_reg_rsp), - .reg2hw, // Write - .devmode_i - ); - -endmodule - - diff --git a/src_files.yml b/src_files.yml index 8cf5164..417b363 100644 --- a/src_files.yml +++ b/src_files.yml @@ -20,16 +20,14 @@ clic: files: - src/clic_pkg.sv - src/clicint_reg_pkg.sv - - src/clicint_reg_top.sv + - src/clicint_reg.sv - src/clicintv_reg_pkg.sv - - src/clicintv_reg_top.sv + - src/clicintv_reg.sv - src/clicvs_reg_pkg.sv - - src/clicvs_reg_top.sv - - src/mclic_reg_pkg.sv - - src/mclic_reg_top.sv + - src/clicvs_reg.sv + - src/cliccfg_reg_pkg.sv + - src/cliccfg_reg.sv - src/clic_reg_adapter.sv - src/clic_gateway.sv - src/clic_target.sv - src/clic.sv - vlog_opts: - - -L register_interface_lib, diff --git a/test/tb_clic.sv b/test/tb_clic.sv index 6d3280f..fdeb13d 100644 --- a/test/tb_clic.sv +++ b/test/tb_clic.sv @@ -1,25 +1,19 @@ // Copyright 2026 ETH Zurich and University of Bologna. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// SPDX-License-Identifier: Apache-2.0 -// +// Solderpad Hardware License, Version 0.51, see LICENSES/SHL-0.51.txt for details. +// SPDX-License-Identifier: SHL-0.51 + // Self-checking testbench for the CLIC. // -// The DUT is clic_apb. Stimulus is black-box: interrupt sources are driven on -// `intr_src_i` and all configuration goes over APB. Observation is white-box +// The DUT is clic. Stimulus is black-box: interrupt sources are driven on +// `intr_src_i` and all configuration goes over APB4. Observation is white-box // where the boundary does not expose enough (`claim`, `ip`), because the claim // pulse is what closes the claim -> ip -> selection-tree loop. +// +// The register addresses come from clic_reg_defs.svh, generated from +// rdl/clic.rdl. + +`include "apb/typedef.svh" +`include "clic_reg_defs.svh" module tb_clic #( parameter int unsigned N_SOURCE = 16, @@ -51,11 +45,12 @@ module tb_clic #( localparam logic [1:0] S_MODE = 2'b01; localparam logic [1:0] M_MODE = 2'b11; - // Register map, mirrored from clic.sv - localparam logic [31:0] MCLICCFG_ADDR = 32'h0_0000; - localparam logic [31:0] MCLICINT_BASE = 32'h0_1000; - localparam logic [31:0] SCLICINTV_BASE = 32'h0_d000; - localparam logic [31:0] VSCLICPRIO_BASE = 32'h0_e000; + // Register map, taken from the generated memory map rather than restated. + // The base of each array is its element 0; none of these depend on N_SOURCE. + localparam logic [31:0] MCLICCFG_ADDR = 32'(`CLIC_M_CLICCFG_BASE_ADDR); + localparam logic [31:0] MCLICINT_BASE = 32'(`CLIC_M_CLICINT_BASE_ADDR(0)); + localparam logic [31:0] SCLICINTV_BASE = 32'(`CLIC_S_CLICINTV_BASE_ADDR(0)); + localparam logic [31:0] VSCLICPRIO_BASE = 32'(`CLIC_S_VSPRIO_BASE_ADDR(0)); ////////////////// // Clock, reset // @@ -77,9 +72,32 @@ module tb_clic #( // DUT and ports // /////////////////// - // APB request/response + // APB4 request/response. The CLIC takes the request and response as structs, + // so the driver below builds them from these flat signals. logic psel, penable, pwrite, pready, pslverr; logic [31:0] paddr, pwdata, prdata; + logic [3:0] pstrb; + logic [2:0] pprot; + + `APB_TYPEDEF_ALL(clic_apb, logic [31:0], logic [31:0], logic [3:0]) + + clic_apb_req_t apb_req; + clic_apb_resp_t apb_rsp; + + always_comb begin + apb_req = '0; + apb_req.psel = psel; + apb_req.penable = penable; + apb_req.pwrite = pwrite; + apb_req.pprot = pprot; + apb_req.paddr = paddr; + apb_req.pwdata = pwdata; + apb_req.pstrb = pstrb; + end + + assign pready = apb_rsp.pready; + assign prdata = apb_rsp.prdata; + assign pslverr = apb_rsp.pslverr; logic [N_SOURCE-1:0] intr_src; @@ -91,9 +109,10 @@ module tb_clic #( logic [VSID_W-1:0] irq_vsid; logic irq_kill_req, irq_kill_ack; - // The DUT is the APB-wrapped CLIC, so the bus adapter is inside the verified - // scope rather than bypassed. - clic_apb #( + // The CLIC is an APB4 device directly, so there is no bus adapter to bypass. + clic #( + .apb_req_t (clic_apb_req_t), + .apb_rsp_t (clic_apb_resp_t), .N_SOURCE (N_SOURCE), .INTCTLBITS (INTCTLBITS), .SSCLIC (SSCLIC), @@ -105,14 +124,8 @@ module tb_clic #( ) dut ( .clk_i (clk), .rst_ni (rst_n), - .penable_i (penable), - .pwrite_i (pwrite), - .paddr_i (paddr), - .psel_i (psel), - .pwdata_i (pwdata), - .prdata_o (prdata), - .pready_o (pready), - .pslverr_o (pslverr), + .apb_req_i (apb_req), + .apb_rsp_o (apb_rsp), .intr_src_i (intr_src), .irq_valid_o (irq_valid), .irq_ready_i (irq_ready), @@ -128,8 +141,8 @@ module tb_clic #( // Internals reached hierarchically: `ip` and `claim` are not on the boundary, // and the claim -> ip loop is exactly what the selection checks depend on. - `define CLIC_IP dut.i_clic.ip - `define CLIC_CLAIM dut.i_clic.claim + `define CLIC_IP dut.ip + `define CLIC_CLAIM dut.claim /////////////////////////// // Error bookkeeping // @@ -187,6 +200,7 @@ module tb_clic #( task automatic cfg_write(input logic [31:0] addr, input logic [31:0] data); @(posedge clk); psel <= 1'b1; penable <= 1'b0; pwrite <= 1'b1; paddr <= addr; pwdata <= data; + pstrb <= 4'hf; pprot <= 3'b0; @(posedge clk); penable <= 1'b1; forever begin @@ -200,6 +214,7 @@ module tb_clic #( task automatic cfg_read(input logic [31:0] addr, output logic [31:0] data); @(posedge clk); psel <= 1'b1; penable <= 1'b0; pwrite <= 1'b0; paddr <= addr; + pstrb <= 4'h0; pprot <= 3'b0; @(posedge clk); penable <= 1'b1; forever begin @@ -276,7 +291,7 @@ module tb_clic #( cfg_write(VSCLICPRIO_BASE + 4*(vs/4), w); endtask - task automatic set_mcliccfg(input logic [3:0] mnlbits, input logic [1:0] nmbits); + task automatic set_cliccfg(input logic [3:0] mnlbits, input logic [1:0] nmbits); logic [31:0] w; cfg_mnlbits = mnlbits; cfg_nmbits = nmbits; @@ -288,7 +303,7 @@ module tb_clic #( // Disable every source and clear all attributes. task automatic reset_config(); - set_mcliccfg(4'd8, 2'd2); + set_cliccfg(4'd8, 2'd2); for (int unsigned i = 0; i < N_SOURCE; i++) begin set_int(i, 8'h00, M_MODE, 1'b0, 1'b0, 1'b0); end @@ -745,6 +760,7 @@ module tb_clic #( int unsigned waited; @(posedge clk); psel <= 1'b1; penable <= 1'b0; pwrite <= 1'b0; paddr <= addr; + pstrb <= 4'h0; pprot <= 3'b0; @(posedge clk); penable <= 1'b1; waited = 0; @@ -863,6 +879,8 @@ module tb_clic #( pwrite = 1'b0; paddr = '0; pwdata = '0; + pstrb = '0; + pprot = '0; intr_src = '0; irq_ready = 1'b0; kill_ack_en = 1'b1; diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..2810b98 --- /dev/null +++ b/uv.lock @@ -0,0 +1,350 @@ +version = 1 +revision = 3 +requires-python = ">=3.12" + +[[package]] +name = "antlr4-python3-runtime" +version = "4.13.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/33/5f/2cdf6f7aca3b20d3f316e9f505292e1f256a32089bd702034c29ebde6242/antlr4_python3_runtime-4.13.2.tar.gz", hash = "sha256:909b647e1d2fc2b70180ac586df3933e38919c85f98ccc656a96cd3f25ef3916", size = 117467, upload-time = "2024-08-03T19:00:12.757Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/03/a851e84fcbb85214dc637b6378121ef9a0dd61b4c65264675d8a5c9b1ae7/antlr4_python3_runtime-4.13.2-py3-none-any.whl", hash = "sha256:fe3835eb8d33daece0e799090eda89719dbccee7aa39ef94eed3818cafa5a7e8", size = 144462, upload-time = "2024-08-03T19:00:11.134Z" }, +] + +[[package]] +name = "clic" +version = "0" +source = { virtual = "." } + +[package.dev-dependencies] +regs = [ + { name = "peakrdl" }, + { name = "peakrdl-rawheader" }, + { name = "peakrdl-regblock" }, +] + +[package.metadata] + +[package.metadata.requires-dev] +regs = [ + { name = "peakrdl", specifier = "==1.5.0" }, + { name = "peakrdl-rawheader", specifier = "==0.2.2" }, + { name = "peakrdl-regblock", specifier = "==1.3.1" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "git-me-the-url" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "gitpython" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/69/36/e58975894d84387432ca9c5f221d4f05f1f07296c5488c1115a964bdef62/git_me_the_url-2.2.0.tar.gz", hash = "sha256:fc000b2c67171f45da263760a75dbce21a08aeb428ee5021cd8ab29330297dc3", size = 423769, upload-time = "2025-11-21T03:15:50.167Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/a8/16ff25e716248b4433a81c429a51996eb2c263199c1777ea1d5424b5c673/git_me_the_url-2.2.0-py3-none-any.whl", hash = "sha256:bd759ddde7d21ebe1d85558f00d6822b74b7e5907adcaeb9fc4d72203a34264b", size = 12945, upload-time = "2025-11-21T03:15:48.831Z" }, +] + +[[package]] +name = "gitdb" +version = "4.0.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "smmap" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, +] + +[[package]] +name = "gitpython" +version = "3.1.58" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "gitdb" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/26/d6/5f358ff283325580c2003a6d953aea18cfe10ae87b46f5ebc80fa3a386dc/gitpython-3.1.58.tar.gz", hash = "sha256:621416df10ef3fd0e19fabf9172ddeed0fa704d353d04f194eec56a625a95b22", size = 228498, upload-time = "2026-08-04T15:05:49.47Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/0c/9d8752098bc442f0726e64aa6135940b3a96809915d1aa4206c1bb97881d/gitpython-3.1.58-py3-none-any.whl", hash = "sha256:d331e722577f0fd7fc1f857419b3ecc07af66282b933d2a4d95f84a042fdd50f", size = 220183, upload-time = "2026-08-04T15:05:48.025Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "mako" +version = "1.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2a/12/b5fa2353e2754cd67fb9f83793fa48ff42c213a5da7e719869d2301f6ab8/mako-1.4.1.tar.gz", hash = "sha256:d7904710b662996425a21627710c4777c45053146942cf8a7aebf757c92b8c27", size = 410165, upload-time = "2026-08-05T06:10:56.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/54/12ed58d458474aaab5c3d180173e745a4fe131bb330370596876d19ff60f/mako-1.4.1-py3-none-any.whl", hash = "sha256:a359d9a94a541213958742b2698d0a7757bb83551767bc468a74b9905aba9617", size = 80010, upload-time = "2026-08-05T06:10:58.248Z" }, +] + +[[package]] +name = "markdown" +version = "3.10.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/29/6f/da4c6aea59b3001f2e8c0ec7497475aadaf3b021c10cab5b2858f0f32b26/markdown-3.10.3.tar.gz", hash = "sha256:3589362618f743188b4d955b874402bc814f4f83f544dc207719f4baa7d9c45f", size = 372596, upload-time = "2026-07-30T19:05:29.005Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/69/4a5af2bc115a9a33fefe51709749de8262be3f9ba063d1753a837cdbc49c/markdown-3.10.3-py3-none-any.whl", hash = "sha256:fa6c92a00a4a3c98b22728c64a935ae1928250ae65058a6ded814d2cc29a4cea", size = 110757, upload-time = "2026-07-30T19:05:27.883Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" }, + { url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" }, + { url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" }, + { url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" }, + { url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" }, + { url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" }, + { url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/2f/907b9c7bbba283e68f20259574b13d005c121a0fa4c175f9bed27c4597ff/markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795", size = 11622, upload-time = "2025-09-27T18:36:41.777Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d9/5f7756922cdd676869eca1c4e3c0cd0df60ed30199ffd775e319089cb3ed/markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219", size = 12029, upload-time = "2025-09-27T18:36:43.257Z" }, + { url = "https://files.pythonhosted.org/packages/00/07/575a68c754943058c78f30db02ee03a64b3c638586fba6a6dd56830b30a3/markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6", size = 24374, upload-time = "2025-09-27T18:36:44.508Z" }, + { url = "https://files.pythonhosted.org/packages/a9/21/9b05698b46f218fc0e118e1f8168395c65c8a2c750ae2bab54fc4bd4e0e8/markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676", size = 22980, upload-time = "2025-09-27T18:36:45.385Z" }, + { url = "https://files.pythonhosted.org/packages/7f/71/544260864f893f18b6827315b988c146b559391e6e7e8f7252839b1b846a/markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9", size = 21990, upload-time = "2025-09-27T18:36:46.916Z" }, + { url = "https://files.pythonhosted.org/packages/c2/28/b50fc2f74d1ad761af2f5dcce7492648b983d00a65b8c0e0cb457c82ebbe/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1", size = 23784, upload-time = "2025-09-27T18:36:47.884Z" }, + { url = "https://files.pythonhosted.org/packages/ed/76/104b2aa106a208da8b17a2fb72e033a5a9d7073c68f7e508b94916ed47a9/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc", size = 21588, upload-time = "2025-09-27T18:36:48.82Z" }, + { url = "https://files.pythonhosted.org/packages/b5/99/16a5eb2d140087ebd97180d95249b00a03aa87e29cc224056274f2e45fd6/markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12", size = 23041, upload-time = "2025-09-27T18:36:49.797Z" }, + { url = "https://files.pythonhosted.org/packages/19/bc/e7140ed90c5d61d77cea142eed9f9c303f4c4806f60a1044c13e3f1471d0/markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed", size = 14543, upload-time = "2025-09-27T18:36:51.584Z" }, + { url = "https://files.pythonhosted.org/packages/05/73/c4abe620b841b6b791f2edc248f556900667a5a1cf023a6646967ae98335/markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5", size = 15113, upload-time = "2025-09-27T18:36:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3a/fa34a0f7cfef23cf9500d68cb7c32dd64ffd58a12b09225fb03dd37d5b80/markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485", size = 13911, upload-time = "2025-09-27T18:36:53.513Z" }, + { url = "https://files.pythonhosted.org/packages/e4/d7/e05cd7efe43a88a17a37b3ae96e79a19e846f3f456fe79c57ca61356ef01/markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73", size = 11658, upload-time = "2025-09-27T18:36:54.819Z" }, + { url = "https://files.pythonhosted.org/packages/99/9e/e412117548182ce2148bdeacdda3bb494260c0b0184360fe0d56389b523b/markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37", size = 12066, upload-time = "2025-09-27T18:36:55.714Z" }, + { url = "https://files.pythonhosted.org/packages/bc/e6/fa0ffcda717ef64a5108eaa7b4f5ed28d56122c9a6d70ab8b72f9f715c80/markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19", size = 25639, upload-time = "2025-09-27T18:36:56.908Z" }, + { url = "https://files.pythonhosted.org/packages/96/ec/2102e881fe9d25fc16cb4b25d5f5cde50970967ffa5dddafdb771237062d/markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025", size = 23569, upload-time = "2025-09-27T18:36:57.913Z" }, + { url = "https://files.pythonhosted.org/packages/4b/30/6f2fce1f1f205fc9323255b216ca8a235b15860c34b6798f810f05828e32/markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6", size = 23284, upload-time = "2025-09-27T18:36:58.833Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/4a0ccea4ab9f5dcb6f79c0236d954acb382202721e704223a8aafa38b5c8/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f", size = 24801, upload-time = "2025-09-27T18:36:59.739Z" }, + { url = "https://files.pythonhosted.org/packages/6a/70/3780e9b72180b6fecb83a4814d84c3bf4b4ae4bf0b19c27196104149734c/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb", size = 22769, upload-time = "2025-09-27T18:37:00.719Z" }, + { url = "https://files.pythonhosted.org/packages/98/c5/c03c7f4125180fc215220c035beac6b9cb684bc7a067c84fc69414d315f5/markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009", size = 23642, upload-time = "2025-09-27T18:37:01.673Z" }, + { url = "https://files.pythonhosted.org/packages/80/d6/2d1b89f6ca4bff1036499b1e29a1d02d282259f3681540e16563f27ebc23/markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354", size = 14612, upload-time = "2025-09-27T18:37:02.639Z" }, + { url = "https://files.pythonhosted.org/packages/2b/98/e48a4bfba0a0ffcf9925fe2d69240bfaa19c6f7507b8cd09c70684a53c1e/markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218", size = 15200, upload-time = "2025-09-27T18:37:03.582Z" }, + { url = "https://files.pythonhosted.org/packages/0e/72/e3cc540f351f316e9ed0f092757459afbc595824ca724cbc5a5d4263713f/markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287", size = 13973, upload-time = "2025-09-27T18:37:04.929Z" }, + { url = "https://files.pythonhosted.org/packages/33/8a/8e42d4838cd89b7dde187011e97fe6c3af66d8c044997d2183fbd6d31352/markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe", size = 11619, upload-time = "2025-09-27T18:37:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/b5/64/7660f8a4a8e53c924d0fa05dc3a55c9cee10bbd82b11c5afb27d44b096ce/markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026", size = 12029, upload-time = "2025-09-27T18:37:07.213Z" }, + { url = "https://files.pythonhosted.org/packages/da/ef/e648bfd021127bef5fa12e1720ffed0c6cbb8310c8d9bea7266337ff06de/markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737", size = 24408, upload-time = "2025-09-27T18:37:09.572Z" }, + { url = "https://files.pythonhosted.org/packages/41/3c/a36c2450754618e62008bf7435ccb0f88053e07592e6028a34776213d877/markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97", size = 23005, upload-time = "2025-09-27T18:37:10.58Z" }, + { url = "https://files.pythonhosted.org/packages/bc/20/b7fdf89a8456b099837cd1dc21974632a02a999ec9bf7ca3e490aacd98e7/markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d", size = 22048, upload-time = "2025-09-27T18:37:11.547Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a7/591f592afdc734f47db08a75793a55d7fbcc6902a723ae4cfbab61010cc5/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda", size = 23821, upload-time = "2025-09-27T18:37:12.48Z" }, + { url = "https://files.pythonhosted.org/packages/7d/33/45b24e4f44195b26521bc6f1a82197118f74df348556594bd2262bda1038/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf", size = 21606, upload-time = "2025-09-27T18:37:13.485Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0e/53dfaca23a69fbfbbf17a4b64072090e70717344c52eaaaa9c5ddff1e5f0/markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe", size = 23043, upload-time = "2025-09-27T18:37:14.408Z" }, + { url = "https://files.pythonhosted.org/packages/46/11/f333a06fc16236d5238bfe74daccbca41459dcd8d1fa952e8fbd5dccfb70/markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9", size = 14747, upload-time = "2025-09-27T18:37:15.36Z" }, + { url = "https://files.pythonhosted.org/packages/28/52/182836104b33b444e400b14f797212f720cbc9ed6ba34c800639d154e821/markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581", size = 15341, upload-time = "2025-09-27T18:37:16.496Z" }, + { url = "https://files.pythonhosted.org/packages/6f/18/acf23e91bd94fd7b3031558b1f013adfa21a8e407a3fdb32745538730382/markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4", size = 14073, upload-time = "2025-09-27T18:37:17.476Z" }, + { url = "https://files.pythonhosted.org/packages/3c/f0/57689aa4076e1b43b15fdfa646b04653969d50cf30c32a102762be2485da/markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab", size = 11661, upload-time = "2025-09-27T18:37:18.453Z" }, + { url = "https://files.pythonhosted.org/packages/89/c3/2e67a7ca217c6912985ec766c6393b636fb0c2344443ff9d91404dc4c79f/markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175", size = 12069, upload-time = "2025-09-27T18:37:19.332Z" }, + { url = "https://files.pythonhosted.org/packages/f0/00/be561dce4e6ca66b15276e184ce4b8aec61fe83662cce2f7d72bd3249d28/markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634", size = 25670, upload-time = "2025-09-27T18:37:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/50/09/c419f6f5a92e5fadde27efd190eca90f05e1261b10dbd8cbcb39cd8ea1dc/markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50", size = 23598, upload-time = "2025-09-27T18:37:21.177Z" }, + { url = "https://files.pythonhosted.org/packages/22/44/a0681611106e0b2921b3033fc19bc53323e0b50bc70cffdd19f7d679bb66/markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e", size = 23261, upload-time = "2025-09-27T18:37:22.167Z" }, + { url = "https://files.pythonhosted.org/packages/5f/57/1b0b3f100259dc9fffe780cfb60d4be71375510e435efec3d116b6436d43/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5", size = 24835, upload-time = "2025-09-27T18:37:23.296Z" }, + { url = "https://files.pythonhosted.org/packages/26/6a/4bf6d0c97c4920f1597cc14dd720705eca0bf7c787aebc6bb4d1bead5388/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523", size = 22733, upload-time = "2025-09-27T18:37:24.237Z" }, + { url = "https://files.pythonhosted.org/packages/14/c7/ca723101509b518797fedc2fdf79ba57f886b4aca8a7d31857ba3ee8281f/markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc", size = 23672, upload-time = "2025-09-27T18:37:25.271Z" }, + { url = "https://files.pythonhosted.org/packages/fb/df/5bd7a48c256faecd1d36edc13133e51397e41b73bb77e1a69deab746ebac/markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d", size = 14819, upload-time = "2025-09-27T18:37:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8a/0402ba61a2f16038b48b39bccca271134be00c5c9f0f623208399333c448/markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9", size = 15426, upload-time = "2025-09-27T18:37:27.316Z" }, + { url = "https://files.pythonhosted.org/packages/70/bc/6f1c2f612465f5fa89b95bead1f44dcb607670fd42891d8fdcd5d039f4f4/markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa", size = 14146, upload-time = "2025-09-27T18:37:28.327Z" }, +] + +[[package]] +name = "peakrdl" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "peakrdl-cheader" }, + { name = "peakrdl-cli" }, + { name = "peakrdl-html" }, + { name = "peakrdl-ipxact" }, + { name = "peakrdl-regblock" }, + { name = "peakrdl-systemrdl" }, + { name = "peakrdl-uvm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5f/dd/c329e3f50e0129180d2b6dffcf13e3140277ab2e929ab774d91ea84ae85c/peakrdl-1.5.0.tar.gz", hash = "sha256:7aa5abce889fd75083f860727bbf69aacb969ec3d204250e808576237ced0dec", size = 5052, upload-time = "2025-10-03T04:17:09.521Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/2a/1d7c2cf934e779caeddb72b7f22f74a86ad815a1cb48bdfa46c7b3af6110/peakrdl-1.5.0-py3-none-any.whl", hash = "sha256:819ae8fb445969d125329c9b6fc1c164a1e9bef02f0594698db5bce2aa0a0277", size = 5186, upload-time = "2025-10-03T04:17:08.255Z" }, +] + +[[package]] +name = "peakrdl-cheader" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "systemrdl-compiler" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/eb/0029f029510523277d2aea7c6a7b86f4c6a14da092c06700434d191483be/peakrdl_cheader-1.1.0.tar.gz", hash = "sha256:2e1593d68ca96608eb0b29ae3efbd5abca961050984d4ee1e4a65998237cd58b", size = 30518, upload-time = "2026-03-28T02:57:52.734Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/a4/112cc4f9c80c7c1373e38e33172d8219bf4db360b915dd856e2fb31a0cec/peakrdl_cheader-1.1.0-py3-none-any.whl", hash = "sha256:72bc5af33a0a353eacc88fd35e271a9f008176b758fdb0c7cfbff1f5144c42af", size = 19765, upload-time = "2026-03-28T02:57:51.268Z" }, +] + +[[package]] +name = "peakrdl-cli" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "systemrdl-compiler" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/12/c8/85baad7853c8995407ce04e98aaff713bc0d82de1f38721679f033c53d0b/peakrdl_cli-1.5.0.tar.gz", hash = "sha256:fb11961bc4d5636239e02b3392072025e7310afaceba34d834adbb279c770f65", size = 17559, upload-time = "2025-10-03T04:17:04.251Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/0d/8b3023ad5fe1b8fdaeb15a8a1f54dc9de384e398ebd374e234f783b4c100/peakrdl_cli-1.5.0-py3-none-any.whl", hash = "sha256:e6d86a41f8e8cdf09021e0abfdad604f6213f8d3aaf7ea6579ccbb6f047c81ca", size = 22772, upload-time = "2025-10-03T04:17:02.821Z" }, +] + +[[package]] +name = "peakrdl-html" +version = "2.12.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "git-me-the-url" }, + { name = "jinja2" }, + { name = "markdown" }, + { name = "python-markdown-math" }, + { name = "systemrdl-compiler" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/0a/069fd914b588ef1d9dbc89031d962293fa2b9255c3b1104f9de9f0891320/peakrdl_html-2.12.2.tar.gz", hash = "sha256:7be4b92dead8d296d714da5d25e71249ebf488bccdd255ed7581f32dd3a99546", size = 11255605, upload-time = "2026-03-06T04:57:29.273Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/32/8bb83251ca56366af0fcea102331b337e87b2baeca81ade16942357e172f/peakrdl_html-2.12.2-py3-none-any.whl", hash = "sha256:1b74a43579900b48fb6ebf0468b91c50d2256828d1f9751da8bfeb2f0883710c", size = 5582847, upload-time = "2026-03-06T04:57:26.857Z" }, +] + +[[package]] +name = "peakrdl-ipxact" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "systemrdl-compiler" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a0/f6/af8f79d853081ce9258c60863606291ad5aab9e12eccd050f2e3e8a3a051/peakrdl_ipxact-3.5.0.tar.gz", hash = "sha256:183b9e5412cad7734c25c710ca3722f75f8776b8c20ed38c1d4b83ac409d92d8", size = 71628, upload-time = "2024-10-15T04:45:01.901Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/81/778784087d63d004d8db431212153e635d89bd43fd05f61391090211d6f5/peakrdl_ipxact-3.5.0-py3-none-any.whl", hash = "sha256:930460f2b95cf5be52d7fadad416f040b68defbc17c372a58c581ee7195be364", size = 40804, upload-time = "2024-10-15T04:45:00.346Z" }, +] + +[[package]] +name = "peakrdl-rawheader" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mako" }, + { name = "systemrdl-compiler" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/97/36/36ade0ca25d5d4cfe1e4235aa1e38c8df7e20209fe4f30babc7a8b9ddcba/peakrdl_rawheader-0.2.2.tar.gz", hash = "sha256:bfbca17fec790a96f10362cf24a20ee4fb48abd146a1750b3d9580b00542de55", size = 10110, upload-time = "2026-01-15T15:18:40.9Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/3c/dadd8c81adc80e3adcd8279ab110be82ef82394e07a535500e30999fab65/peakrdl_rawheader-0.2.2-py3-none-any.whl", hash = "sha256:5c299845d87bdc8353cec2279a9c42000e01b026de0c7deb87635f1ecfe11ff5", size = 12831, upload-time = "2026-01-15T15:18:39.922Z" }, +] + +[[package]] +name = "peakrdl-regblock" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "systemrdl-compiler" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ca/d1/f6488f1d3ac8b3cfa7120ed9e8c586193c8372f2336ee8e94d8559261da0/peakrdl_regblock-1.3.1.tar.gz", hash = "sha256:d72803e62ff0c0feb2c17a51263e39cdee14ec6bf5dc8a7100e8a93f63306a07", size = 555526, upload-time = "2026-03-28T03:05:09.748Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/69/c35c9a4d2d461a839e9041c763fcfe6294f5399e13dc554c60ecbea67e34/peakrdl_regblock-1.3.1-py3-none-any.whl", hash = "sha256:d769306d834dea3dbd02cdd976f694d2009ef33dbb72bcfadc344b7de6cfb492", size = 83185, upload-time = "2026-03-28T03:05:08.144Z" }, +] + +[[package]] +name = "peakrdl-systemrdl" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "systemrdl-compiler" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/3e/bc15ce1445c7b80717d4babc6d1de92f857e1ff00cd8eefeb9505c9c19f2/peakrdl_systemrdl-1.0.1.tar.gz", hash = "sha256:77fe097d01d252b365f9d603e2712a85b3cf65f32c7ad52aadd1a8dea9635a5e", size = 16359, upload-time = "2025-11-07T03:30:55.24Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/b0/1ac2934d117e3e8cb59afc7f658b1dc5b2a34ede0718952ab6993990b5ca/peakrdl_systemrdl-1.0.1-py3-none-any.whl", hash = "sha256:17d72641ade637e5650a20589977a3452316ecb630f500907f4c579c0a8f7ebd", size = 10208, upload-time = "2025-11-07T03:30:53.546Z" }, +] + +[[package]] +name = "peakrdl-uvm" +version = "2.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "systemrdl-compiler" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5a/d4/de4c1e44ba589aaae7fa230266516ba67608e7dca425ccf3a7b21bb062ab/peakrdl_uvm-2.4.0.tar.gz", hash = "sha256:bebbec7ea84c76137e3e61442565d1de9a225eaf01774c65de3d10dd7096ad78", size = 15293, upload-time = "2025-11-25T01:59:54.771Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/f0/cc6f81291ce62422ca6b73efe2e032d86689dadd91a04356e199f0b915e1/peakrdl_uvm-2.4.0-py3-none-any.whl", hash = "sha256:2ec87aaac25f6597a0a0b173edae8cd81d1dd05957591013f1e6b93957de0d87", size = 16945, upload-time = "2025-11-25T01:59:53.029Z" }, +] + +[[package]] +name = "python-markdown-math" +version = "0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4c/68/fbea05ec6fb318bdcf56ea47596605614554f51d77bfd14f6fb481139ad8/python_markdown_math-0.9.tar.gz", hash = "sha256:567395553dc4941e79b3789a1096dcabb3fda9539d150d558ef3507948b264a3", size = 8680, upload-time = "2025-04-10T10:10:31.84Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/68/ecf3535c40845de2efd8ac2d092dd5fca0868219fa3684d9e58ef7abeece/python_markdown_math-0.9-py3-none-any.whl", hash = "sha256:ac9932df517a5c0f6d01c56e7a44d065eca4a420893ac45f7a6937c67cb41e86", size = 6046, upload-time = "2025-04-10T10:10:30.318Z" }, +] + +[[package]] +name = "smmap" +version = "5.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/ea/49c993d6dfdd7338c9b1000a0f36817ed7ec84577ae2e52f890d1a4ff909/smmap-5.0.3.tar.gz", hash = "sha256:4d9debb8b99007ae47165abc08670bd74cb74b5227dda7f643eccc4e9eb5642c", size = 22506, upload-time = "2026-03-09T03:43:26.1Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/d4/59e74daffcb57a07668852eeeb6035af9f32cbfd7a1d2511f17d2fe6a738/smmap-5.0.3-py3-none-any.whl", hash = "sha256:c106e05d5a61449cf6ba9a1e650227ecfb141590d2a98412103ff35d89fc7b2f", size = 24390, upload-time = "2026-03-09T03:43:24.361Z" }, +] + +[[package]] +name = "systemrdl-compiler" +version = "1.32.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "antlr4-python3-runtime" }, + { name = "colorama" }, + { name = "markdown" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/03/ac/2088114d65e191e2a057313036254fb3df6ec64aaa744929a50b1e5202cb/systemrdl_compiler-1.32.2.tar.gz", hash = "sha256:3308f5ba2db23f035c25391022c70dbaba8980fdbfdf652bd2ad79fd33aba1f2", size = 484930, upload-time = "2026-02-27T05:54:23.244Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/18/d76dc65c7a2cffb5524c018c9edd69397d94f4cd708b52fad2c8cc3f8c99/systemrdl_compiler-1.32.2-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:4870074e9d1f720f577966e107f7096e0c464772456ecd9e772fd2055216d6a4", size = 1145125, upload-time = "2026-02-27T05:54:04.031Z" }, + { url = "https://files.pythonhosted.org/packages/d8/c7/ca0aa3d315e606c584841f1929b0b9bd7d9a6f1b1c76f09164cfd3f0ee2f/systemrdl_compiler-1.32.2-cp37-abi3-macosx_11_0_x86_64.whl", hash = "sha256:69e8ce07e5435cd61dc126113734b0f5e26271f193e08c9f31326a429d857fd9", size = 1172296, upload-time = "2026-02-27T05:54:05.948Z" }, + { url = "https://files.pythonhosted.org/packages/06/18/7abeafa5b642cc9e89ed534a7a73416b77540e7234bea08cc3138e790844/systemrdl_compiler-1.32.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2777441b26f8ac880ba402c300bb2fd92d6b155aa50261715d9519a3a6e780a", size = 10973073, upload-time = "2026-02-27T05:54:07.25Z" }, + { url = "https://files.pythonhosted.org/packages/f2/97/04dc3272980a212674c9737f3c2928e49d862879843135c86da90b0c23fc/systemrdl_compiler-1.32.2-cp37-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be36bb56fdcb218e266ec7c1ae950492c6c0d9327c0c4d85912583ac6e26347b", size = 10845166, upload-time = "2026-02-27T05:54:09.59Z" }, + { url = "https://files.pythonhosted.org/packages/55/43/2ffd2c7753789e02bac7d902e847738af81f9a32098233464067a85ba92a/systemrdl_compiler-1.32.2-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9707da961e8b8b28c43ebf542b2863e2dc581d194f5c4ceb0315a45ad8883e0", size = 11020140, upload-time = "2026-02-27T05:54:11.992Z" }, + { url = "https://files.pythonhosted.org/packages/94/7b/f94162860a1a5e2ccaa707c9c4c4c5031d98f3f00251b03a75ee9147b4da/systemrdl_compiler-1.32.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:56f37930d5948da9ca77b70702d11b5b19bb9755e5fab97444aa65ce9be8d37e", size = 11049533, upload-time = "2026-02-27T05:54:14.107Z" }, + { url = "https://files.pythonhosted.org/packages/dc/3e/3596309bc436ca1ca6a8e20aee3af8b4924038fbeb422514f9b0756fbaa5/systemrdl_compiler-1.32.2-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8477c6d9fab1458c6dbd95f3d38bdb5c2a40998601a467e8e6c230cc82880b46", size = 11261692, upload-time = "2026-02-27T05:54:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/28/84/4a0369f39c5a6a960382a2a9db0b8d7f511e1941c6ef21a9fb5401ce76c4/systemrdl_compiler-1.32.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a05dd1bcd8e7c29d2fe67fb46149f503f39173e462b4bf63fbd375fc0efd3cd1", size = 11301976, upload-time = "2026-02-27T05:54:18.141Z" }, + { url = "https://files.pythonhosted.org/packages/74/a2/91435c5c8b13dc065dd28dd6e7ca4122de566157f0282126add9025e74e5/systemrdl_compiler-1.32.2-cp37-abi3-win32.whl", hash = "sha256:402620a125e11086da3e1b609a3c8bd82d207c71691f6547242a3df237eb3b30", size = 923159, upload-time = "2026-02-27T05:54:20.104Z" }, + { url = "https://files.pythonhosted.org/packages/69/43/6794d66c9aa5394376ca1ef18343ebf146f25c75ba0d4240707e6198e47c/systemrdl_compiler-1.32.2-cp37-abi3-win_amd64.whl", hash = "sha256:06d6221257251adc0ee422da2dae9748a88239d72dd6e9b6ee21788396d6c2d0", size = 955604, upload-time = "2026-02-27T05:54:21.419Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +]