From b4f9eaff71567147979aa2821ba4bd413743101e Mon Sep 17 00:00:00 2001 From: Arnav Sacheti <36746504+arnavsacheti@users.noreply.github.com> Date: Fri, 10 Oct 2025 22:30:59 -0700 Subject: [PATCH] regblock -> busdecoder --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- .github/pull_request_template.md | 2 +- .github/workflows/build.yml | 6 +- CONTRIBUTING.md | 6 +- MANIFEST.in | 2 +- README.md | 12 +- docs/api.rst | 14 +- docs/conf.py | 19 +- docs/configuring.rst | 10 +- docs/cpuif/apb.rst | 8 +- docs/cpuif/avalon.rst | 4 +- docs/cpuif/axi4lite.rst | 4 +- docs/cpuif/customizing.rst | 12 +- docs/cpuif/internal_protocol.rst | 6 +- docs/cpuif/introduction.rst | 4 +- docs/cpuif/passthrough.rst | 2 +- .../template-layers/1.1.hardware-interface | 4 +- docs/faq.rst | 4 +- docs/index.rst | 20 +- docs/licensing.rst | 12 +- docs/limitations.rst | 2 +- docs/props/addrmap.rst | 2 +- docs/props/field.rst | 2 +- docs/props/reg.rst | 2 +- docs/props/signal.rst | 4 +- docs/rdl_features/external.rst | 8 +- docs/udps/extended_swacc.rst | 4 +- docs/udps/fixedpoint.rst | 8 +- docs/udps/intro.rst | 4 +- docs/udps/read_buffering.rst | 6 +- docs/udps/signed.rst | 8 +- docs/udps/write_buffering.rst | 10 +- hdl-src/regblock_udps.rdl | 4 +- pyproject.toml | 44 +-- src/peakrdl_regblock/__init__.py | 2 +- src/peakrdl_regblock/__peakrdl__.py | 64 ++-- src/peakrdl_regblock/addr_decode.py | 73 ++--- .../cpuif/axi4lite/__init__.py | 23 +- src/peakrdl_regblock/cpuif/base.py | 7 +- src/peakrdl_regblock/dereferencer.py | 85 +++--- src/peakrdl_regblock/exporter.py | 102 ++++--- src/peakrdl_regblock/external_acks.py | 18 +- src/peakrdl_regblock/field_logic/__init__.py | 279 +++++++++++------- src/peakrdl_regblock/field_logic/bases.py | 22 +- src/peakrdl_regblock/hwif/__init__.py | 70 ++--- src/peakrdl_regblock/module_tmpl.sv | 4 +- src/peakrdl_regblock/package_tmpl.sv | 4 +- src/peakrdl_regblock/parity.py | 10 +- .../read_buffering/__init__.py | 18 +- src/peakrdl_regblock/readback/__init__.py | 29 +- src/peakrdl_regblock/readback/generators.py | 180 +++++++---- src/peakrdl_regblock/scan_design.py | 49 +-- src/peakrdl_regblock/validate_design.py | 91 +++--- .../write_buffering/__init__.py | 26 +- tests/.coveragerc | 6 +- tests/README.md | 6 +- tests/conftest.py | 11 +- tests/lib/base_testcase.py | 31 +- tests/lib/cpuifs/apb3/__init__.py | 4 +- tests/lib/cpuifs/apb4/__init__.py | 4 +- tests/lib/cpuifs/avalon/__init__.py | 4 +- tests/lib/cpuifs/axi4lite/__init__.py | 4 +- tests/lib/cpuifs/base.py | 27 +- tests/lib/cpuifs/passthrough/__init__.py | 3 +- tests/lib/simulators/base.py | 9 +- tests/lib/synth_testcase.py | 6 +- tests/lib/synthesizers/vivado_scripts/run.tcl | 2 +- tests/lib/tb_base.sv | 6 +- tests/run.sh | 6 +- tests/test_enum/tb_template.sv | 10 +- tests/test_external/tb_template.sv | 4 +- tests/test_map_size/tb_template.sv | 2 +- tests/test_pipelined_cpuif/regblock.rdl | 2 +- tests/test_pkg_params/tb_template.sv | 6 +- tests/test_structural_sw_rw/regblock.rdl | 2 +- tests/test_user_cpuif/testcase.py | 25 +- tests/test_validation_errors/testcase.py | 10 +- 78 files changed, 904 insertions(+), 705 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 18f9e56..f034cad 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,7 +7,7 @@ assignees: '' --- -- [ ] I have reviewed this project's [contribution guidelines](https://github.com/SystemRDL/PeakRDL-regblock/blob/main/CONTRIBUTING.md) +- [ ] I have reviewed this project's [contribution guidelines](https://github.com/SystemRDL/PeakRDL-busdecoder/blob/main/CONTRIBUTING.md) **Describe the bug** A clear and concise description of what the bug is. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 34f370a..1fb98ac 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -7,7 +7,7 @@ assignees: '' --- -- [ ] I have reviewed this project's [contribution guidelines](https://github.com/SystemRDL/PeakRDL-regblock/blob/main/CONTRIBUTING.md) +- [ ] I have reviewed this project's [contribution guidelines](https://github.com/SystemRDL/PeakRDL-busdecoder/blob/main/CONTRIBUTING.md) **Describe the problem/limitation you think should be addressed** A clear and concise description of what the problem is. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 6f0db28..38461b1 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -6,6 +6,6 @@ this change. # Checklist -- [ ] I have reviewed this project's [contribution guidelines](https://github.com/SystemRDL/PeakRDL-regblock/blob/main/CONTRIBUTING.md) +- [ ] I have reviewed this project's [contribution guidelines](https://github.com/SystemRDL/PeakRDL-busdecoder/blob/main/CONTRIBUTING.md) - [ ] This change has been tested and does not break any of the existing unit tests. (if unable to run the tests, let us know) - [ ] If this change adds new features, I have added new unit tests that cover them. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1111ec1..377f3cc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -56,7 +56,7 @@ jobs: - name: Test run: | cd tests - pytest --cov=peakrdl_regblock --synth-tool skip --sim-tool stub + pytest --cov=peakrdl_busdecoder --synth-tool skip --sim-tool stub - name: Coveralls env: @@ -103,7 +103,7 @@ jobs: - name: Run Lint run: | - pylint --rcfile tests/pylint.rc peakrdl_regblock + pylint --rcfile tests/pylint.rc peakrdl_busdecoder #------------------------------------------------------------------------------- mypy: @@ -125,7 +125,7 @@ jobs: - name: Type Check run: | - mypy --config-file tests/mypy.ini src/peakrdl_regblock + mypy --config-file tests/mypy.ini src/peakrdl_busdecoder #------------------------------------------------------------------------------- build: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b82b0d8..e5a0712 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# Contributing to the PeakRDL-regblock code generator +# Contributing to the PeakRDL-busdecoder code generator We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's: @@ -9,9 +9,9 @@ transparent as possible, whether it's: - Becoming a maintainer -## Open an issue using the [Issue Tracker](https://github.com/SystemRDL/PeakRDL-regblock/issues) +## Open an issue using the [Issue Tracker](https://github.com/SystemRDL/PeakRDL-busdecoder/issues) Talking to us is the easiest way to contribute! Report a bug or feature request by -[opening a new issue](https://github.com/SystemRDL/PeakRDL-regblock/issues). +[opening a new issue](https://github.com/SystemRDL/PeakRDL-busdecoder/issues). Issue submission expectations: * Please keep each issue submission limited to one topic. This helps us stay organized. diff --git a/MANIFEST.in b/MANIFEST.in index eafe2d0..5566091 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1,2 @@ -recursive-include src/peakrdl_regblock *.sv +recursive-include src/peakrdl_busdecoder *.sv prune tests diff --git a/README.md b/README.md index 8b554c1..7ab1d71 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -[![Documentation Status](https://readthedocs.org/projects/peakrdl-regblock/badge/?version=latest)](http://peakrdl-regblock.readthedocs.io) -[![build](https://github.com/SystemRDL/PeakRDL-regblock/workflows/build/badge.svg)](https://github.com/SystemRDL/PeakRDL-regblock/actions?query=workflow%3Abuild+branch%3Amain) -[![Coverage Status](https://coveralls.io/repos/github/SystemRDL/PeakRDL-regblock/badge.svg?branch=main)](https://coveralls.io/github/SystemRDL/PeakRDL-regblock?branch=main) -[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/peakrdl-regblock.svg)](https://pypi.org/project/peakrdl-regblock) +[![Documentation Status](https://readthedocs.org/projects/peakrdl-busdecoder/badge/?version=latest)](http://peakrdl-busdecoder.readthedocs.io) +[![build](https://github.com/SystemRDL/PeakRDL-busdecoder/workflows/build/badge.svg)](https://github.com/SystemRDL/PeakRDL-busdecoder/actions?query=workflow%3Abuild+branch%3Amain) +[![Coverage Status](https://coveralls.io/repos/github/SystemRDL/PeakRDL-busdecoder/badge.svg?branch=main)](https://coveralls.io/github/SystemRDL/PeakRDL-busdecoder?branch=main) +[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/peakrdl-busdecoder.svg)](https://pypi.org/project/peakrdl-busdecoder) -# PeakRDL-regblock +# PeakRDL-busdecoder Compile SystemRDL into a SystemVerilog control/status register (CSR) block. For the command line tool, see the [PeakRDL project](https://peakrdl.readthedocs.io). ## Documentation -See the [PeakRDL-regblock Documentation](https://peakrdl-regblock.readthedocs.io) for more details +See the [PeakRDL-busdecoder Documentation](https://peakrdl-busdecoder.readthedocs.io) for more details diff --git a/docs/api.rst b/docs/api.rst index 69b809d..5da2c00 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -2,9 +2,9 @@ Exporter API ============ If you are not using the `PeakRDL command-line tool `_, -you can still generate regblocks programmatically using the exporter API: +you can still generate busdecoders programmatically using the exporter API: -.. autoclass:: peakrdl_regblock.RegblockExporter +.. autoclass:: peakrdl_busdecoder.BusDecoderExporter :members: Example @@ -16,9 +16,9 @@ implementation from SystemRDL source. :emphasize-lines: 2-4, 29-33 from systemrdl import RDLCompiler, RDLCompileError - from peakrdl_regblock import RegblockExporter - from peakrdl_regblock.cpuif.axi4lite import AXI4Lite_Cpuif - from peakrdl_regblock.udps import ALL_UDPS + from peakrdl_busdecoder import BusDecoderExporter + from peakrdl_busdecoder.cpuif.axi4lite import AXI4Lite_Cpuif + from peakrdl_busdecoder.udps import ALL_UDPS input_files = [ "PATH/TO/my_register_block.rdl" @@ -27,7 +27,7 @@ implementation from SystemRDL source. # Create an instance of the compiler rdlc = RDLCompiler() - # Register all UDPs that 'regblock' requires + # Register all UDPs that 'busdecoder' requires for udp in ALL_UDPS: rdlc.register_udp(udp) @@ -43,7 +43,7 @@ implementation from SystemRDL source. sys.exit(1) # Export a SystemVerilog implementation - exporter = RegblockExporter() + exporter = BusDecoderExporter() exporter.export( root, "path/to/output_dir", cpuif_cls=AXI4Lite_Cpuif diff --git a/docs/conf.py b/docs/conf.py index 6a3f472..7070bb7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,15 +12,16 @@ # import os import sys -sys.path.insert(0, os.path.abspath('../src/')) + +sys.path.insert(0, os.path.abspath("../src/")) import datetime # -- Project information ----------------------------------------------------- -project = 'PeakRDL-regblock' -copyright = '%d, Alex Mykyta' % datetime.datetime.now().year -author = 'Alex Mykyta' +project = "PeakRDL-busdecoder" +copyright = "%d, Alex Mykyta" % datetime.datetime.now().year +author = "Alex Mykyta" # -- General configuration --------------------------------------------------- @@ -29,19 +30,19 @@ author = 'Alex Mykyta' # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.napoleon', + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", "sphinxcontrib.wavedrom", ] render_using_wavedrompy = True # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # -- Options for HTML output ------------------------------------------------- @@ -52,7 +53,7 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] html_theme = "sphinx_book_theme" html_theme_options = { - "repository_url": "https://github.com/SystemRDL/PeakRDL-regblock", + "repository_url": "https://github.com/SystemRDL/PeakRDL-busdecoder", "path_to_docs": "docs", "use_download_button": False, "use_source_button": True, diff --git a/docs/configuring.rst b/docs/configuring.rst index 6be6f63..8bfc542 100644 --- a/docs/configuring.rst +++ b/docs/configuring.rst @@ -1,13 +1,13 @@ .. _peakrdl_cfg: -Configuring PeakRDL-regblock +Configuring PeakRDL-busdecoder ============================ If using the `PeakRDL command line tool `_, -some aspects of the ``regblock`` command have additional configuration options +some aspects of the ``busdecoder`` command have additional configuration options available via the PeakRDL TOML file. -All regblock-specific options are defined under the ``[regblock]`` TOML heading. +All busdecoder-specific options are defined under the ``[busdecoder]`` TOML heading. .. data:: cpuifs @@ -20,7 +20,7 @@ All regblock-specific options are defined under the ``[regblock]`` TOML heading. .. code-block:: toml - [regblock] + [busdecoder] cpuifs.my-cpuif-name = "my_cpuif_module:MyCPUInterfaceClass" @@ -41,5 +41,5 @@ All regblock-specific options are defined under the ``[regblock]`` TOML heading. .. code-block:: toml - [regblock] + [busdecoder] default_reset = "arst" diff --git a/docs/cpuif/apb.rst b/docs/cpuif/apb.rst index efec7d8..e5d9998 100644 --- a/docs/cpuif/apb.rst +++ b/docs/cpuif/apb.rst @@ -29,13 +29,13 @@ The APB3 CPU interface comes in two i/o port flavors: SystemVerilog Interface * Command line: ``--cpuif apb3`` * Interface Definition: :download:`apb3_intf.sv <../../hdl-src/apb3_intf.sv>` - * Class: :class:`peakrdl_regblock.cpuif.apb3.APB3_Cpuif` + * Class: :class:`peakrdl_busdecoder.cpuif.apb3.APB3_Cpuif` Flattened inputs/outputs Flattens the interface into discrete input and output ports. * Command line: ``--cpuif apb3-flat`` - * Class: :class:`peakrdl_regblock.cpuif.apb3.APB3_Cpuif_flattened` + * Class: :class:`peakrdl_busdecoder.cpuif.apb3.APB3_Cpuif_flattened` APB4 @@ -50,10 +50,10 @@ The APB4 CPU interface comes in two i/o port flavors: SystemVerilog Interface * Command line: ``--cpuif apb4`` * Interface Definition: :download:`apb4_intf.sv <../../hdl-src/apb4_intf.sv>` - * Class: :class:`peakrdl_regblock.cpuif.apb4.APB4_Cpuif` + * Class: :class:`peakrdl_busdecoder.cpuif.apb4.APB4_Cpuif` Flattened inputs/outputs Flattens the interface into discrete input and output ports. * Command line: ``--cpuif apb4-flat`` - * Class: :class:`peakrdl_regblock.cpuif.apb4.APB4_Cpuif_flattened` + * Class: :class:`peakrdl_busdecoder.cpuif.apb4.APB4_Cpuif_flattened` diff --git a/docs/cpuif/avalon.rst b/docs/cpuif/avalon.rst index 2ae8a04..7455d0a 100644 --- a/docs/cpuif/avalon.rst +++ b/docs/cpuif/avalon.rst @@ -10,13 +10,13 @@ The Avalon interface comes in two i/o port flavors: SystemVerilog Interface * Command line: ``--cpuif avalon-mm`` * Interface Definition: :download:`avalon_mm_intf.sv <../../hdl-src/avalon_mm_intf.sv>` - * Class: :class:`peakrdl_regblock.cpuif.avalon.Avalon_Cpuif` + * Class: :class:`peakrdl_busdecoder.cpuif.avalon.Avalon_Cpuif` Flattened inputs/outputs Flattens the interface into discrete input and output ports. * Command line: ``--cpuif avalon-mm-flat`` - * Class: :class:`peakrdl_regblock.cpuif.avalon.Avalon_Cpuif_flattened` + * Class: :class:`peakrdl_busdecoder.cpuif.avalon.Avalon_Cpuif_flattened` Implementation Details diff --git a/docs/cpuif/axi4lite.rst b/docs/cpuif/axi4lite.rst index 255be14..0fc68cb 100644 --- a/docs/cpuif/axi4lite.rst +++ b/docs/cpuif/axi4lite.rst @@ -12,13 +12,13 @@ The AXI4-Lite CPU interface comes in two i/o port flavors: SystemVerilog Interface * Command line: ``--cpuif axi4-lite`` * Interface Definition: :download:`axi4lite_intf.sv <../../hdl-src/axi4lite_intf.sv>` - * Class: :class:`peakrdl_regblock.cpuif.axi4lite.AXI4Lite_Cpuif` + * Class: :class:`peakrdl_busdecoder.cpuif.axi4lite.AXI4Lite_Cpuif` Flattened inputs/outputs Flattens the interface into discrete input and output ports. * Command line: ``--cpuif axi4-lite-flat`` - * Class: :class:`peakrdl_regblock.cpuif.axi4lite.AXI4Lite_Cpuif_flattened` + * Class: :class:`peakrdl_busdecoder.cpuif.axi4lite.AXI4Lite_Cpuif_flattened` Pipelined Performance diff --git a/docs/cpuif/customizing.rst b/docs/cpuif/customizing.rst index dc806c5..8bd3c31 100644 --- a/docs/cpuif/customizing.rst +++ b/docs/cpuif/customizing.rst @@ -29,7 +29,7 @@ Rather than rewriting a new CPU interface definition, you can extend and adjust .. code-block:: python - from peakrdl_regblock.cpuif.axi4lite import AXI4Lite_Cpuif + from peakrdl_busdecoder.cpuif.axi4lite import AXI4Lite_Cpuif class My_AXI4Lite(AXI4Lite_Cpuif): @property @@ -45,7 +45,7 @@ Then use your custom CPUIF during export: .. code-block:: python - exporter = RegblockExporter() + exporter = BusDecoderExporter() exporter.export( root, "path/to/output_dir", cpuif_cls=My_AXI4Lite @@ -72,7 +72,7 @@ you can define your own. 2. Create a Python class that defines your CPUIF - Extend your class from :class:`peakrdl_regblock.cpuif.CpuifBase`. + Extend your class from :class:`peakrdl_busdecoder.cpuif.CpuifBase`. Define the port declaration string, and provide a reference to your template file. 3. Use your new CPUIF definition when exporting. @@ -94,17 +94,17 @@ Via a package's entry point definition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you are publishing a collection of PeakRDL plugins as an installable Python package, you can advertise them to PeakRDL using an entry point. -This advertises your custom CPUIF class to the PeakRDL-regblock tool as a plugin +This advertises your custom CPUIF class to the PeakRDL-busdecoder tool as a plugin that should be loaded, and made available as a command-line option in PeakRDL. .. code-block:: toml - [project.entry-points."peakrdl_regblock.cpuif"] + [project.entry-points."peakrdl_busdecoder.cpuif"] my-cpuif = "my_package.my_module:MyCPUIF" * ``my_package``: The name of your installable Python module -* ``peakrdl-regblock.cpuif``: This is the namespace that PeakRDL-regblock will +* ``peakrdl-busdecoder.cpuif``: This is the namespace that PeakRDL-busdecoder will search. Any cpuif plugins you create must be enclosed in this namespace in order to be discovered. * ``my_package.my_module:MyCPUIF``: This is the import path that diff --git a/docs/cpuif/internal_protocol.rst b/docs/cpuif/internal_protocol.rst index 75f4515..a47face 100644 --- a/docs/cpuif/internal_protocol.rst +++ b/docs/cpuif/internal_protocol.rst @@ -3,9 +3,9 @@ Internal CPUIF Protocol ======================= -Internally, the regblock generator uses a common CPU interface handshake +Internally, the busdecoder generator uses a common CPU interface handshake protocol. This strobe-based protocol is designed to add minimal overhead to the -regblock implementation, while also being flexible enough to support advanced +busdecoder implementation, while also being flexible enough to support advanced features of a variety of bus interface standards. @@ -205,7 +205,7 @@ request until the stall is cleared. For non-pipelined CPU interfaces that only allow one outstanding transaction at a time, these stall signals can be safely ignored. -In the following example, the regblock is configured such that: +In the following example, the busdecoder is configured such that: * A read transaction takes 1 clock cycle to complete * A write transaction takes 0 clock cycles to complete diff --git a/docs/cpuif/introduction.rst b/docs/cpuif/introduction.rst index 126bc0e..cc34574 100644 --- a/docs/cpuif/introduction.rst +++ b/docs/cpuif/introduction.rst @@ -17,9 +17,9 @@ encountered in the design. Addressing ^^^^^^^^^^ -The regblock exporter will always generate its address decoding logic using local +The busdecoder exporter will always generate its address decoding logic using local address offsets. The absolute address offset of your device shall be -handled by your system interconnect, and present addresses to the regblock that +handled by your system interconnect, and present addresses to the busdecoder that only include the local offset. For example, consider a fictional AXI4-Lite device that: diff --git a/docs/cpuif/passthrough.rst b/docs/cpuif/passthrough.rst index 0bfb2d7..9426e06 100644 --- a/docs/cpuif/passthrough.rst +++ b/docs/cpuif/passthrough.rst @@ -5,6 +5,6 @@ This CPUIF mode bypasses the protocol converter stage and directly exposes the internal CPUIF handshake signals to the user. * Command line: ``--cpuif passthrough`` -* Class: :class:`peakrdl_regblock.cpuif.passthrough.PassthroughCpuif` +* Class: :class:`peakrdl_busdecoder.cpuif.passthrough.PassthroughCpuif` For more details on the protocol itself, see: :ref:`cpuif_protocol`. diff --git a/docs/dev_notes/template-layers/1.1.hardware-interface b/docs/dev_notes/template-layers/1.1.hardware-interface index e23442a..61473ff 100644 --- a/docs/dev_notes/template-layers/1.1.hardware-interface +++ b/docs/dev_notes/template-layers/1.1.hardware-interface @@ -42,14 +42,14 @@ Naming Scheme ================================================================================ hwif_out - .my_regblock + .my_busdecoder .my_reg[X][Y] .my_field .value .anded hwif_in - .my_regblock + .my_busdecoder .my_reg[X][Y] .my_field .value diff --git a/docs/faq.rst b/docs/faq.rst index 751de34..1e35b6b 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -101,7 +101,7 @@ The generated output does not match our organization's coding style SystemVerilog coding styles vary wildly, and unfortunately there is little consensus on this topic within the digital design community. -The output generated by PeakRDL-regblock strives to be as human-readable as possible, +The output generated by PeakRDL-busdecoder strives to be as human-readable as possible, and follow consistent indentation and styling. We do our best to use the most widely accepted coding style, but since this is a very opinionated space, it is impossible to satisfy everyone. @@ -127,5 +127,5 @@ complexity to the tool. If you encounter a lint violation, please carefully review and consider waiving it if it does not pose an actual danger. If you still believe it is a problem, -please let us know by `submitting an issue `_ +please let us know by `submitting an issue `_ that describes the problem. diff --git a/docs/index.rst b/docs/index.rst index e21236a..cb5e2d6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,7 +1,7 @@ Introduction ============ -PeakRDL-regblock is a free and open-source control & status register (CSR) compiler. +PeakRDL-busdecoder is a free and open-source control & status register (CSR) compiler. This code generator translates your SystemRDL register description into a synthesizable SystemVerilog RTL module that can be easily instantiated into your hardware design. @@ -14,31 +14,31 @@ your hardware design. Quick Start ----------- -The easiest way to use PeakRDL-regblock is via the `PeakRDL command line tool `_: +The easiest way to use PeakRDL-busdecoder is via the `PeakRDL command line tool `_: .. code-block:: bash - # Install PeakRDL-regblock along with the command-line tool - python3 -m pip install peakrdl-regblock[cli] + # Install PeakRDL-busdecoder along with the command-line tool + python3 -m pip install peakrdl-busdecoder[cli] # Export! - peakrdl regblock atxmega_spi.rdl -o regblock/ --cpuif axi4-lite + peakrdl busdecoder atxmega_spi.rdl -o busdecoder/ --cpuif axi4-lite Looking for VHDL? ----------------- This project generates SystemVerilog RTL. If you prefer using VHDL, check out the sister project which aims to be a feature-equivalent fork of -PeakRDL-regblock: `PeakRDL-regblock-VHDL `_ +PeakRDL-busdecoder: `PeakRDL-busdecoder-VHDL `_ Links ----- -- `Source repository `_ -- `Release Notes `_ -- `Issue tracker `_ -- `PyPi `_ +- `Source repository `_ +- `Release Notes `_ +- `Issue tracker `_ +- `PyPi `_ - `SystemRDL Specification `_ diff --git a/docs/licensing.rst b/docs/licensing.rst index c9424b6..acc9d2a 100644 --- a/docs/licensing.rst +++ b/docs/licensing.rst @@ -1,9 +1,9 @@ Licensing ========= -Re-distribution of the PeakRDL-regblock code generator tool shall adhere to the +Re-distribution of the PeakRDL-busdecoder code generator tool shall adhere to the terms outlined by the GNU LGPL v3 license. For a copy of the license, see: -https://github.com/SystemRDL/PeakRDL-regblock/blob/main/LICENSE +https://github.com/SystemRDL/PeakRDL-busdecoder/blob/main/LICENSE Why LGPLv3? @@ -23,19 +23,19 @@ explicitly mentioned in the exemptions below. What is exempt from the LGPLv3 license? --------------------------------------- -Don't worry. Not everything that the PeakRDL-regblock project touches is +Don't worry. Not everything that the PeakRDL-busdecoder project touches is considered LGPLv3 code. The following are exempt and are free to use with no restrictions: -* Any code that is generated using PeakRDL-regblock is 100% yours. Since it - was derived from your regblock definition, it remains yours. You can +* Any code that is generated using PeakRDL-busdecoder is 100% yours. Since it + was derived from your busdecoder definition, it remains yours. You can distribute it freely, use it in a proprietary ASIC, sell it as part of an IP, whatever. * Any code snippets in this documentation can be freely copy/pasted. These are examples that are intended for this purpose. * All reference files that are downloadable from this documentation, which are - also available in the `hdl-src folder in the repository `_ + also available in the `hdl-src folder in the repository `_ Can I use this as part of my company's internally developed tools? diff --git a/docs/limitations.rst b/docs/limitations.rst index 2ae08b9..2f0afc4 100644 --- a/docs/limitations.rst +++ b/docs/limitations.rst @@ -15,7 +15,7 @@ Unaligned Registers ------------------- All address offsets & strides shall be a multiple of the cpuif bus width used. Specifically: -* Bus width is inferred by the maximum accesswidth used in the regblock. +* Bus width is inferred by the maximum accesswidth used in the busdecoder. * Each component's address and array stride shall be aligned to the bus width. diff --git a/docs/props/addrmap.rst b/docs/props/addrmap.rst index 770cd3f..888056a 100644 --- a/docs/props/addrmap.rst +++ b/docs/props/addrmap.rst @@ -2,7 +2,7 @@ Addrmap/Regfile Properties ========================== .. note:: Any properties not explicitly listed here are either implicitly - supported, or are not relevant to the regblock exporter and are ignored. + supported, or are not relevant to the busdecoder exporter and are ignored. errextbus diff --git a/docs/props/field.rst b/docs/props/field.rst index fc8e35a..2e869ad 100644 --- a/docs/props/field.rst +++ b/docs/props/field.rst @@ -2,7 +2,7 @@ Field Properties ================ .. note:: Any properties not explicitly listed here are either implicitly - supported, or are not relevant to the regblock exporter and are ignored. + supported, or are not relevant to the busdecoder exporter and are ignored. Software Access Properties -------------------------- diff --git a/docs/props/reg.rst b/docs/props/reg.rst index bbef409..8472f07 100644 --- a/docs/props/reg.rst +++ b/docs/props/reg.rst @@ -2,7 +2,7 @@ Register Properties =================== .. note:: Any properties not explicitly listed here are either implicitly - supported, or are not relevant to the regblock exporter and are ignored. + supported, or are not relevant to the busdecoder exporter and are ignored. accesswidth ----------- diff --git a/docs/props/signal.rst b/docs/props/signal.rst index 7171019..2a34ead 100644 --- a/docs/props/signal.rst +++ b/docs/props/signal.rst @@ -2,7 +2,7 @@ Signal Properties ================= .. note:: Any properties not explicitly listed here are either implicitly - supported, or are not relevant to the regblock exporter and are ignored. + supported, or are not relevant to the busdecoder exporter and are ignored. activehigh/activelow @@ -19,7 +19,7 @@ Ignored in all other contexts. cpuif_reset ----------- Specify that this signal shall be used as alternate reset signal for the CPU -interface for this regblock. +interface for this busdecoder. field_reset diff --git a/docs/rdl_features/external.rst b/docs/rdl_features/external.rst index 15d275e..ee12f39 100644 --- a/docs/rdl_features/external.rst +++ b/docs/rdl_features/external.rst @@ -1,9 +1,9 @@ External Components =================== SystemRDL allows some component instances to be defined as "external" elements -of an address space definition. In the context of this regblock generator, +of an address space definition. In the context of this busdecoder generator, the implementation of an external component is left up to the designer. When -generating the RTL for a regblock, the implementations of external components +generating the RTL for a busdecoder, the implementations of external components are omitted and instead a user-interface is presented on the ``hwif_in``/``hwif_out`` i/o structs. @@ -16,7 +16,7 @@ Things you should know * By default external ``hwif_out`` signals are driven combinationally. An optional output retiming stage can be enabled if needed. -* Due to the uncertain access latency of external components, the regblock will +* Due to the uncertain access latency of external components, the busdecoder will only issue one outstanding transaction to an external component at a time. This is enforced even if the CPUIF is capable of pipelined accesses such as AXI4-Lite. @@ -109,7 +109,7 @@ Broader external address regions can be represented by external block-like components such as ``addrmap``, ``regfile`` or ``mem`` elements. To ensure address decoding for external blocks is simple (only requires simple bit-pruning), -blocks that are external to an exported regblock shall be aligned to their size. +blocks that are external to an exported busdecoder shall be aligned to their size. Request ^^^^^^^ diff --git a/docs/udps/extended_swacc.rst b/docs/udps/extended_swacc.rst index f760275..5182cfd 100644 --- a/docs/udps/extended_swacc.rst +++ b/docs/udps/extended_swacc.rst @@ -15,9 +15,9 @@ functionality. Properties ---------- -These UDP definitions, along with others supported by PeakRDL-regblock can be +These UDP definitions, along with others supported by PeakRDL-busdecoder can be enabled by compiling the following file along with your design: -:download:`regblock_udps.rdl <../../hdl-src/regblock_udps.rdl>`. +:download:`busdecoder_udps.rdl <../../hdl-src/busdecoder_udps.rdl>`. .. describe:: rd_swacc diff --git a/docs/udps/fixedpoint.rst b/docs/udps/fixedpoint.rst index bbcd990..f3e313a 100644 --- a/docs/udps/fixedpoint.rst +++ b/docs/udps/fixedpoint.rst @@ -11,21 +11,21 @@ for each number, unlike for floating-point numbers. For this SystemVerilog exporter, these properties only affect the signal type in the the ``hwif`` structs. There is no special handling in the internals of -the regblock. +the busdecoder. Properties ---------- Fields can be declared as fixed-point numbers using the following two properties: -.. literalinclude:: ../../hdl-src/regblock_udps.rdl +.. literalinclude:: ../../hdl-src/busdecoder_udps.rdl :lines: 46-54 The :ref:`is_signed` property can be used in conjunction with these properties to declare signed fixed-point fields. -These UDP definitions, along with others supported by PeakRDL-regblock, can be +These UDP definitions, along with others supported by PeakRDL-busdecoder, can be enabled by compiling the following file along with your design: -:download:`regblock_udps.rdl <../../hdl-src/regblock_udps.rdl>`. +:download:`busdecoder_udps.rdl <../../hdl-src/busdecoder_udps.rdl>`. .. describe:: intwidth diff --git a/docs/udps/intro.rst b/docs/udps/intro.rst index 63658ca..46da909 100644 --- a/docs/udps/intro.rst +++ b/docs/udps/intro.rst @@ -5,11 +5,11 @@ Although the official SystemRDL spec defines numerous properties that allow you to define complex register map structures, sometimes they are not enough to accurately describe a necessary feature. Fortunately the SystemRDL spec allows the language to be extended using "User Defined Properties" (UDPs). The -PeakRDL-regblock tool understands several UDPs that are described in this +PeakRDL-busdecoder tool understands several UDPs that are described in this section. To enable these UDPs, compile this RDL file prior to the rest of your design: -:download:`regblock_udps.rdl <../../hdl-src/regblock_udps.rdl>`. +:download:`busdecoder_udps.rdl <../../hdl-src/busdecoder_udps.rdl>`. .. list-table:: Summary of UDPs :header-rows: 1 diff --git a/docs/udps/read_buffering.rst b/docs/udps/read_buffering.rst index 41a175e..43aa1e9 100644 --- a/docs/udps/read_buffering.rst +++ b/docs/udps/read_buffering.rst @@ -24,12 +24,12 @@ Properties The behavior of read-buffered registers is defined using the following two properties: -.. literalinclude:: ../../hdl-src/regblock_udps.rdl +.. literalinclude:: ../../hdl-src/busdecoder_udps.rdl :lines: 10-18 -These UDP definitions, along with others supported by PeakRDL-regblock can be +These UDP definitions, along with others supported by PeakRDL-busdecoder can be enabled by compiling the following file along with your design: -:download:`regblock_udps.rdl <../../hdl-src/regblock_udps.rdl>`. +:download:`busdecoder_udps.rdl <../../hdl-src/busdecoder_udps.rdl>`. .. describe:: buffer_reads diff --git a/docs/udps/signed.rst b/docs/udps/signed.rst index b2c710c..39ffebf 100644 --- a/docs/udps/signed.rst +++ b/docs/udps/signed.rst @@ -8,18 +8,18 @@ The ``is_signed`` user-defined property fills this need. For this SystemVerilog exporter, marking a field as signed only affects the signal type in the ``hwif`` structs. There is no special handling in the internals -of the regblock. +of the busdecoder. Properties ---------- A field can be marked as signed using the following user-defined property: -.. literalinclude:: ../../hdl-src/regblock_udps.rdl +.. literalinclude:: ../../hdl-src/busdecoder_udps.rdl :lines: 40-44 -This UDP definition, along with others supported by PeakRDL-regblock, can be +This UDP definition, along with others supported by PeakRDL-busdecoder, can be enabled by compiling the following file along with your design: -:download:`regblock_udps.rdl <../../hdl-src/regblock_udps.rdl>`. +:download:`busdecoder_udps.rdl <../../hdl-src/busdecoder_udps.rdl>`. .. describe:: is_signed diff --git a/docs/udps/write_buffering.rst b/docs/udps/write_buffering.rst index 1d5d2ba..529d08a 100644 --- a/docs/udps/write_buffering.rst +++ b/docs/udps/write_buffering.rst @@ -4,8 +4,8 @@ Write-buffered Registers ======================== In order to support larger software write accesses that are atomic, the -regblock generator understands several UDPs that implement write-buffering to -specific registers. This causes the regblock to delay the effect of a software +busdecoder generator understands several UDPs that implement write-buffering to +specific registers. This causes the busdecoder to delay the effect of a software write operation until a defined trigger event. Some examples of when this is useful: @@ -30,12 +30,12 @@ Properties The behavior of write-buffered registers is defined using the following two properties: -.. literalinclude:: ../../hdl-src/regblock_udps.rdl +.. literalinclude:: ../../hdl-src/busdecoder_udps.rdl :lines: 20-28 -These UDP definitions, along with others supported by PeakRDL-regblock can be +These UDP definitions, along with others supported by PeakRDL-busdecoder can be enabled by compiling the following file along with your design: -:download:`regblock_udps.rdl <../../hdl-src/regblock_udps.rdl>`. +:download:`busdecoder_udps.rdl <../../hdl-src/busdecoder_udps.rdl>`. .. describe:: buffer_writes diff --git a/hdl-src/regblock_udps.rdl b/hdl-src/regblock_udps.rdl index f6ded7b..e11418c 100644 --- a/hdl-src/regblock_udps.rdl +++ b/hdl-src/regblock_udps.rdl @@ -1,10 +1,10 @@ /* * This file defines several property extensions that are understood by the - * PeakRDL-Regblock SystemVerilog code generator. + * PeakRDL-BusDecoder SystemVerilog code generator. * * Compile this file prior to your other SystemRDL sources. * - * For more details, see: https://peakrdl-regblock.readthedocs.io/en/latest/udps/intro.html + * For more details, see: https://peakrdl-busdecoder.readthedocs.io/en/latest/udps/intro.html */ property buffer_reads { diff --git a/pyproject.toml b/pyproject.toml index db6f4f1..eb3b8b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,24 +3,28 @@ requires = ["setuptools", "setuptools-scm"] build-backend = "setuptools.build_meta" [project] -name = "peakrdl-regblock" +name = "peakrdl-busdecoder" dynamic = ["version"] requires-python = ">=3.7" -dependencies = [ - "systemrdl-compiler ~= 1.29", - "Jinja2>=2.11", -] +dependencies = ["systemrdl-compiler ~= 1.29", "Jinja2>=2.11"] -authors = [ - {name="Alex Mykyta"}, -] +authors = [{ name = "Alex Mykyta" }] description = "Compile SystemRDL into a SystemVerilog control/status register (CSR) block" readme = "README.md" -license = {text = "LGPLv3"} +license = { text = "LGPLv3" } keywords = [ - "SystemRDL", "PeakRDL", "CSR", "compiler", "tool", "registers", "generator", - "Verilog", "SystemVerilog", "register abstraction layer", - "FPGA", "ASIC", + "SystemRDL", + "PeakRDL", + "CSR", + "compiler", + "tool", + "registers", + "generator", + "Verilog", + "SystemVerilog", + "register abstraction layer", + "FPGA", + "ASIC", ] classifiers = [ "Development Status :: 5 - Production/Stable", @@ -34,18 +38,16 @@ classifiers = [ ] [project.optional-dependencies] -cli = [ - "peakrdl-cli >= 1.2.3", -] +cli = ["peakrdl-cli >= 1.2.3"] [project.urls] -Source = "https://github.com/SystemRDL/PeakRDL-regblock" -Tracker = "https://github.com/SystemRDL/PeakRDL-regblock/issues" -Changelog = "https://github.com/SystemRDL/PeakRDL-regblock/releases" -Documentation = "https://peakrdl-regblock.readthedocs.io/" +Source = "https://github.com/SystemRDL/PeakRDL-busdecoder" +Tracker = "https://github.com/SystemRDL/PeakRDL-busdecoder/issues" +Changelog = "https://github.com/SystemRDL/PeakRDL-busdecoder/releases" +Documentation = "https://peakrdl-busdecoder.readthedocs.io/" [tool.setuptools.dynamic] -version = {attr = "peakrdl_regblock.__about__.__version__"} +version = { attr = "peakrdl_busdecoder.__about__.__version__" } [project.entry-points."peakrdl.exporters"] -regblock = "peakrdl_regblock.__peakrdl__:Exporter" +busdecoder = "peakrdl_busdecoder.__peakrdl__:Exporter" diff --git a/src/peakrdl_regblock/__init__.py b/src/peakrdl_regblock/__init__.py index c64c756..20efd41 100644 --- a/src/peakrdl_regblock/__init__.py +++ b/src/peakrdl_regblock/__init__.py @@ -1,3 +1,3 @@ from .__about__ import __version__ -from .exporter import RegblockExporter +from .exporter import BusDecoderExporter diff --git a/src/peakrdl_regblock/__peakrdl__.py b/src/peakrdl_regblock/__peakrdl__.py index c67bdb5..5b7087a 100644 --- a/src/peakrdl_regblock/__peakrdl__.py +++ b/src/peakrdl_regblock/__peakrdl__.py @@ -6,7 +6,7 @@ from peakrdl.plugins.exporter import ExporterSubcommandPlugin from peakrdl.config import schema from peakrdl.plugins.entry_points import get_entry_points -from .exporter import RegblockExporter +from .exporter import BusDecoderExporter from .cpuif import CpuifBase, apb3, apb4, axi4lite, passthrough, avalon from .udps import ALL_UDPS @@ -14,6 +14,7 @@ if TYPE_CHECKING: import argparse from systemrdl.node import AddrmapNode + class Exporter(ExporterSubcommandPlugin): short_desc = "Generate a SystemVerilog control/status register (CSR) block" @@ -26,7 +27,6 @@ class Exporter(ExporterSubcommandPlugin): @functools.lru_cache() def get_cpuifs(self) -> Dict[str, Type[CpuifBase]]: - # All built-in CPUIFs cpuifs = { "passthrough": passthrough.PassthroughCpuif, @@ -41,67 +41,74 @@ class Exporter(ExporterSubcommandPlugin): } # Load any cpuifs specified via entry points - for ep, dist in get_entry_points("peakrdl_regblock.cpuif"): + for ep, dist in get_entry_points("peakrdl_busdecoder.cpuif"): name = ep.name cpuif = ep.load() if name in cpuifs: - raise RuntimeError(f"A plugin for 'peakrdl-regblock' tried to load cpuif '{name}' but it already exists") + raise RuntimeError( + f"A plugin for 'peakrdl-busdecoder' tried to load cpuif '{name}' but it already exists" + ) if not issubclass(cpuif, CpuifBase): - raise RuntimeError(f"A plugin for 'peakrdl-regblock' tried to load cpuif '{name}' but it not a CpuifBase class") + raise RuntimeError( + f"A plugin for 'peakrdl-busdecoder' tried to load cpuif '{name}' but it not a CpuifBase class" + ) cpuifs[name] = cpuif # Load any CPUIFs via config import - for name, cpuif in self.cfg['cpuifs'].items(): + for name, cpuif in self.cfg["cpuifs"].items(): if name in cpuifs: - raise RuntimeError(f"A plugin for 'peakrdl-regblock' tried to load cpuif '{name}' but it already exists") + raise RuntimeError( + f"A plugin for 'peakrdl-busdecoder' tried to load cpuif '{name}' but it already exists" + ) if not issubclass(cpuif, CpuifBase): - raise RuntimeError(f"A plugin for 'peakrdl-regblock' tried to load cpuif '{name}' but it not a CpuifBase class") + raise RuntimeError( + f"A plugin for 'peakrdl-busdecoder' tried to load cpuif '{name}' but it not a CpuifBase class" + ) cpuifs[name] = cpuif return cpuifs - - def add_exporter_arguments(self, arg_group: 'argparse._ActionsContainer') -> None: + def add_exporter_arguments(self, arg_group: "argparse._ActionsContainer") -> None: cpuifs = self.get_cpuifs() arg_group.add_argument( "--cpuif", choices=cpuifs.keys(), default="apb3", - help="Select the CPU interface protocol to use [apb3]" + help="Select the CPU interface protocol to use [apb3]", ) arg_group.add_argument( "--module-name", metavar="NAME", default=None, - help="Override the SystemVerilog module name" + help="Override the SystemVerilog module name", ) arg_group.add_argument( "--package-name", metavar="NAME", default=None, - help="Override the SystemVerilog package name" + help="Override the SystemVerilog package name", ) arg_group.add_argument( "--type-style", dest="type_style", - choices=['lexical', 'hier'], + choices=["lexical", "hier"], default="lexical", help="""Choose how HWIF struct type names are generated. The 'lexical' style will use RDL lexical scope & type names where possible and attempt to re-use equivalent type definitions. The 'hier' style uses component's hierarchy as the struct type name. [lexical] - """ + """, ) arg_group.add_argument( "--hwif-report", action="store_true", default=False, - help="Generate a HWIF report file" + help="Generate a HWIF report file", ) arg_group.add_argument( @@ -109,25 +116,25 @@ class Exporter(ExporterSubcommandPlugin): type=int, default=None, help="""Override the CPU interface's address width. By default, - address width is sized to the contents of the regblock. - """ + address width is sized to the contents of the busdecoder. + """, ) arg_group.add_argument( "--rt-read-fanin", action="store_true", default=False, - help="Enable additional read path retiming. Good for register blocks with large readback fan-in" + help="Enable additional read path retiming. Good for register blocks with large readback fan-in", ) arg_group.add_argument( "--rt-read-response", action="store_true", default=False, - help="Enable additional retiming stage between readback fan-in and cpu interface" + help="Enable additional retiming stage between readback fan-in and cpu interface", ) arg_group.add_argument( "--rt-external", - help="Retime outputs to external components. Specify a comma-separated list of: reg,regfile,mem,addrmap,all" + help="Retime outputs to external components. Specify a comma-separated list of: reg,regfile,mem,addrmap,all", ) arg_group.add_argument( @@ -136,11 +143,10 @@ class Exporter(ExporterSubcommandPlugin): default=None, help="""Choose the default style of reset signal if not explicitly specified by the SystemRDL design. If unspecified, the default reset - is active-high and synchronous [rst]""" + is active-high and synchronous [rst]""", ) - - def do_export(self, top_node: 'AddrmapNode', options: 'argparse.Namespace') -> None: + def do_export(self, top_node: "AddrmapNode", options: "argparse.Namespace") -> None: cpuifs = self.get_cpuifs() retime_external_reg = False @@ -164,10 +170,13 @@ class Exporter(ExporterSubcommandPlugin): retime_external_mem = True retime_external_addrmap = True else: - print("error: invalid option for --rt-external: '%s'" % key, file=sys.stderr) + print( + "error: invalid option for --rt-external: '%s'" % key, + file=sys.stderr, + ) # Get default reset. Favor command-line over cfg. Fall back to 'rst' - default_rst = options.default_reset or self.cfg['default_reset'] or "rst" + default_rst = options.default_reset or self.cfg["default_reset"] or "rst" if default_rst == "rst": default_reset_activelow = False default_reset_async = False @@ -183,8 +192,7 @@ class Exporter(ExporterSubcommandPlugin): else: raise RuntimeError - - x = RegblockExporter() + x = BusDecoderExporter() x.export( top_node, options.output, diff --git a/src/peakrdl_regblock/addr_decode.py b/src/peakrdl_regblock/addr_decode.py index 1390192..d44965a 100644 --- a/src/peakrdl_regblock/addr_decode.py +++ b/src/peakrdl_regblock/addr_decode.py @@ -10,22 +10,23 @@ from .identifier_filter import kw_filter as kwf from .sv_int import SVInt if TYPE_CHECKING: - from .exporter import RegblockExporter + from .exporter import BusDecoderExporter from systemrdl.node import AddrmapNode, AddressableNode from systemrdl.node import RegfileNode, MemNode + class AddressDecode: - def __init__(self, exp:'RegblockExporter'): + def __init__(self, exp: "BusDecoderExporter"): self.exp = exp @property - def top_node(self) -> 'AddrmapNode': + def top_node(self) -> "AddrmapNode": return self.exp.ds.top_node def get_strobe_struct(self) -> str: struct_gen = DecodeStructGenerator() s = struct_gen.get_struct(self.top_node, "decoded_reg_strb_t") - assert s is not None # guaranteed to have at least one reg + assert s is not None # guaranteed to have at least one reg return s def get_implementation(self) -> str: @@ -34,7 +35,9 @@ class AddressDecode: assert s is not None return s - def get_access_strobe(self, node: Union[RegNode, FieldNode], reduce_substrobes: bool=True) -> str: + def get_access_strobe( + self, node: Union[RegNode, FieldNode], reduce_substrobes: bool = True + ) -> str: """ Returns the Verilog string that represents the register/field's access strobe. """ @@ -42,8 +45,8 @@ class AddressDecode: field = node path = get_indexed_path(self.top_node, node.parent) - regwidth = node.parent.get_property('regwidth') - accesswidth = node.parent.get_property('accesswidth') + regwidth = node.parent.get_property("regwidth") + accesswidth = node.parent.get_property("accesswidth") if regwidth > accesswidth: # Is wide register. # Determine the substrobe(s) relevant to this field @@ -63,7 +66,7 @@ class AddressDecode: return "decoded_reg_strb." + path - def get_external_block_access_strobe(self, node: 'AddressableNode') -> str: + def get_external_block_access_strobe(self, node: "AddressableNode") -> str: assert node.external assert not isinstance(node, RegNode) path = get_indexed_path(self.top_node, node) @@ -71,42 +74,41 @@ class AddressDecode: class DecodeStructGenerator(RDLStructGenerator): - - def _enter_external_block(self, node: 'AddressableNode') -> None: + def _enter_external_block(self, node: "AddressableNode") -> None: self.add_member( kwf(node.inst_name), array_dimensions=node.array_dimensions, ) - def enter_Addrmap(self, node: 'AddrmapNode') -> Optional[WalkerAction]: + def enter_Addrmap(self, node: "AddrmapNode") -> Optional[WalkerAction]: assert node.external self._enter_external_block(node) return WalkerAction.SkipDescendants - def exit_Addrmap(self, node: 'AddrmapNode') -> None: + def exit_Addrmap(self, node: "AddrmapNode") -> None: assert node.external - def enter_Regfile(self, node: 'RegfileNode') -> Optional[WalkerAction]: + def enter_Regfile(self, node: "RegfileNode") -> Optional[WalkerAction]: if node.external: self._enter_external_block(node) return WalkerAction.SkipDescendants super().enter_Regfile(node) return WalkerAction.Continue - def exit_Regfile(self, node: 'RegfileNode') -> None: + def exit_Regfile(self, node: "RegfileNode") -> None: if node.external: return super().exit_Regfile(node) - def enter_Mem(self, node: 'MemNode') -> Optional[WalkerAction]: + def enter_Mem(self, node: "MemNode") -> Optional[WalkerAction]: assert node.external self._enter_external_block(node) return WalkerAction.SkipDescendants - def exit_Mem(self, node: 'MemNode') -> None: + def exit_Mem(self, node: "MemNode") -> None: assert node.external - def enter_Reg(self, node: 'RegNode') -> None: + def enter_Reg(self, node: "RegNode") -> None: # if register is "wide", expand the strobe to be able to access the sub-words n_subwords = node.get_property("regwidth") // node.get_property("accesswidth") @@ -117,23 +119,24 @@ class DecodeStructGenerator(RDLStructGenerator): ) # Stub out - def exit_Reg(self, node: 'RegNode') -> None: + def exit_Reg(self, node: "RegNode") -> None: pass - def enter_Field(self, node: 'FieldNode') -> None: + + def enter_Field(self, node: "FieldNode") -> None: pass class DecodeLogicGenerator(RDLForLoopGenerator): - def __init__(self, addr_decode: AddressDecode) -> None: self.addr_decode = addr_decode super().__init__() # List of address strides for each dimension - self._array_stride_stack = [] # type: List[int] + self._array_stride_stack = [] # type: List[int] - - def enter_AddressableComponent(self, node: 'AddressableNode') -> Optional[WalkerAction]: + def enter_AddressableComponent( + self, node: "AddressableNode" + ) -> Optional[WalkerAction]: super().enter_AddressableComponent(node) if node.array_dimensions: @@ -158,21 +161,23 @@ class DecodeLogicGenerator(RDLForLoopGenerator): return WalkerAction.Continue - - def _get_address_str(self, node: 'AddressableNode', subword_offset: int=0) -> str: + def _get_address_str(self, node: "AddressableNode", subword_offset: int = 0) -> str: expr_width = self.addr_decode.exp.ds.addr_width - a = str(SVInt( - node.raw_absolute_address - self.addr_decode.top_node.raw_absolute_address + subword_offset, - expr_width - )) + a = str( + SVInt( + node.raw_absolute_address + - self.addr_decode.top_node.raw_absolute_address + + subword_offset, + expr_width, + ) + ) for i, stride in enumerate(self._array_stride_stack): a += f" + ({expr_width})'(i{i}) * {SVInt(stride, expr_width)}" return a - def enter_Reg(self, node: RegNode) -> None: - regwidth = node.get_property('regwidth') - accesswidth = node.get_property('accesswidth') + regwidth = node.get_property("regwidth") + accesswidth = node.get_property("accesswidth") if regwidth == accesswidth: rhs = f"cpuif_req_masked & (cpuif_addr == {self._get_address_str(node)})" @@ -194,7 +199,7 @@ class DecodeLogicGenerator(RDLForLoopGenerator): n_subwords = regwidth // accesswidth subword_stride = accesswidth // 8 for i in range(n_subwords): - rhs = f"cpuif_req_masked & (cpuif_addr == {self._get_address_str(node, subword_offset=(i*subword_stride))})" + rhs = f"cpuif_req_masked & (cpuif_addr == {self._get_address_str(node, subword_offset=(i * subword_stride))})" s = f"{self.addr_decode.get_access_strobe(node)}[{i}] = {rhs};" self.add_content(s) if node.external: @@ -209,7 +214,7 @@ class DecodeLogicGenerator(RDLForLoopGenerator): else: raise RuntimeError - def exit_AddressableComponent(self, node: 'AddressableNode') -> None: + def exit_AddressableComponent(self, node: "AddressableNode") -> None: super().exit_AddressableComponent(node) if not node.array_dimensions: diff --git a/src/peakrdl_regblock/cpuif/axi4lite/__init__.py b/src/peakrdl_regblock/cpuif/axi4lite/__init__.py index 65dead5..25376d1 100644 --- a/src/peakrdl_regblock/cpuif/axi4lite/__init__.py +++ b/src/peakrdl_regblock/cpuif/axi4lite/__init__.py @@ -1,5 +1,6 @@ from ..base import CpuifBase + class AXI4Lite_Cpuif(CpuifBase): template_path = "axi4lite_tmpl.sv" is_interface = True @@ -8,11 +9,11 @@ class AXI4Lite_Cpuif(CpuifBase): def port_declaration(self) -> str: return "axi4lite_intf.slave s_axil" - def signal(self, name:str) -> str: + def signal(self, name: str) -> str: return "s_axil." + name.upper() @property - def regblock_latency(self) -> int: + def busdecoder_latency(self) -> int: return max(self.exp.ds.min_read_latency, self.exp.ds.min_write_latency) @property @@ -23,7 +24,7 @@ class AXI4Lite_Cpuif(CpuifBase): Anything beyond that does not have any effect, aside from adding unnecessary logic and additional buffer-bloat latency. """ - return self.regblock_latency + 2 + return self.busdecoder_latency + 2 @property def resp_buffer_size(self) -> int: @@ -42,29 +43,25 @@ class AXI4Lite_Cpuif_flattened(AXI4Lite_Cpuif): lines = [ "output logic " + self.signal("awready"), "input wire " + self.signal("awvalid"), - f"input wire [{self.addr_width-1}:0] " + self.signal("awaddr"), + f"input wire [{self.addr_width - 1}:0] " + self.signal("awaddr"), "input wire [2:0] " + self.signal("awprot"), - "output logic " + self.signal("wready"), "input wire " + self.signal("wvalid"), - f"input wire [{self.data_width-1}:0] " + self.signal("wdata"), - f"input wire [{self.data_width_bytes-1}:0]" + self.signal("wstrb"), - + f"input wire [{self.data_width - 1}:0] " + self.signal("wdata"), + f"input wire [{self.data_width_bytes - 1}:0]" + self.signal("wstrb"), "input wire " + self.signal("bready"), "output logic " + self.signal("bvalid"), "output logic [1:0] " + self.signal("bresp"), - "output logic " + self.signal("arready"), "input wire " + self.signal("arvalid"), - f"input wire [{self.addr_width-1}:0] " + self.signal("araddr"), + f"input wire [{self.addr_width - 1}:0] " + self.signal("araddr"), "input wire [2:0] " + self.signal("arprot"), - "input wire " + self.signal("rready"), "output logic " + self.signal("rvalid"), - f"output logic [{self.data_width-1}:0] " + self.signal("rdata"), + f"output logic [{self.data_width - 1}:0] " + self.signal("rdata"), "output logic [1:0] " + self.signal("rresp"), ] return ",\n".join(lines) - def signal(self, name:str) -> str: + def signal(self, name: str) -> str: return "s_axil_" + name diff --git a/src/peakrdl_regblock/cpuif/base.py b/src/peakrdl_regblock/cpuif/base.py index 2031a71..66935c8 100644 --- a/src/peakrdl_regblock/cpuif/base.py +++ b/src/peakrdl_regblock/cpuif/base.py @@ -7,14 +7,14 @@ import jinja2 as jj from ..utils import clog2, is_pow2, roundup_pow2 if TYPE_CHECKING: - from ..exporter import RegblockExporter + from ..exporter import BusDecoderExporter + class CpuifBase: - # Path is relative to the location of the class that assigns this variable template_path = "" - def __init__(self, exp:'RegblockExporter'): + def __init__(self, exp: "BusDecoderExporter"): self.exp = exp self.reset = exp.ds.top_node.cpuif_reset @@ -53,7 +53,6 @@ class CpuifBase: return class_dir raise RuntimeError - def get_implementation(self) -> str: class_dir = self._get_template_path_class_dir() loader = jj.FileSystemLoader(class_dir) diff --git a/src/peakrdl_regblock/dereferencer.py b/src/peakrdl_regblock/dereferencer.py index d80e6ed..42c73ea 100644 --- a/src/peakrdl_regblock/dereferencer.py +++ b/src/peakrdl_regblock/dereferencer.py @@ -5,40 +5,46 @@ from systemrdl.rdltypes import PropertyReference from .sv_int import SVInt if TYPE_CHECKING: - from .exporter import RegblockExporter, DesignState + from .exporter import BusDecoderExporter, DesignState from .hwif import Hwif from .field_logic import FieldLogic from .addr_decode import AddressDecode + class Dereferencer: """ This class provides an interface to convert conceptual SystemRDL references into Verilog identifiers """ - def __init__(self, exp:'RegblockExporter'): + + def __init__(self, exp: "BusDecoderExporter"): self.exp = exp @property - def hwif(self) -> 'Hwif': + def hwif(self) -> "Hwif": return self.exp.hwif @property - def address_decode(self) -> 'AddressDecode': + def address_decode(self) -> "AddressDecode": return self.exp.address_decode @property - def field_logic(self) -> 'FieldLogic': + def field_logic(self) -> "FieldLogic": return self.exp.field_logic @property - def ds(self) -> 'DesignState': + def ds(self) -> "DesignState": return self.exp.ds @property def top_node(self) -> AddrmapNode: return self.exp.ds.top_node - def get_value(self, obj: Union[int, FieldNode, SignalNode, PropertyReference], width: Optional[int] = None) -> Union[SVInt, str]: + def get_value( + self, + obj: Union[int, FieldNode, SignalNode, PropertyReference], + width: Optional[int] = None, + ) -> Union[SVInt, str]: """ Returns the Verilog string that represents the readable value associated with the object. @@ -63,14 +69,14 @@ class Dereferencer: # Field does not have a storage element, nor does it have a HW input # must be a constant value as defined by its reset value - reset_value = obj.get_property('reset') + reset_value = obj.get_property("reset") if reset_value is not None: return self.get_value(reset_value, obj.width) else: # No reset value defined! obj.env.msg.warning( f"Field '{obj.inst_name}' is a constant but does not have a known value (missing reset). Assigning it a value of X.", - obj.inst.inst_src_ref + obj.inst.inst_src_ref, ) return "'X" @@ -88,7 +94,6 @@ class Dereferencer: raise RuntimeError(f"Unhandled reference to: {obj}") - def get_field_propref_value( self, field: FieldNode, @@ -109,16 +114,16 @@ class Dereferencer: # references that directly access a property value if prop_name in { - 'decrvalue', - 'enable', - 'haltenable', - 'haltmask', - 'hwenable', - 'hwmask', - 'incrvalue', - 'mask', - 'reset', - 'resetsignal', + "decrvalue", + "enable", + "haltenable", + "haltmask", + "hwenable", + "hwmask", + "incrvalue", + "mask", + "reset", + "resetsignal", }: return self.get_value(field.get_property(prop_name), width) @@ -132,7 +137,7 @@ class Dereferencer: return self.get_value(prop_value, width) # References to another component value, or an implied input - if prop_name in {'hwclr', 'hwset'}: + if prop_name in {"hwclr", "hwset"}: prop_value = field.get_property(prop_name) if prop_value is True: # Points to inferred hwif input @@ -175,7 +180,6 @@ class Dereferencer: if prop_name == "swmod": return self.field_logic.get_swmod_identifier(field) - # translate aliases aliases = { "saturate": "incrsaturate", @@ -184,37 +188,37 @@ class Dereferencer: prop_name = aliases.get(prop_name, prop_name) # Counter properties - if prop_name == 'incr': + if prop_name == "incr": return self.field_logic.get_counter_incr_strobe(field) - if prop_name == 'decr': + if prop_name == "decr": return self.field_logic.get_counter_decr_strobe(field) if prop_name in { - 'decrsaturate', - 'decrthreshold', - 'incrsaturate', - 'incrthreshold', - 'overflow', - 'underflow', + "decrsaturate", + "decrthreshold", + "incrsaturate", + "incrthreshold", + "overflow", + "underflow", }: return self.field_logic.get_field_combo_identifier(field, prop_name) raise RuntimeError(f"Unhandled reference to: {field}->{prop_name}") - def get_reg_propref_value(self, reg: RegNode, prop_name: str) -> str: - if prop_name in {'halt', 'intr'}: + if prop_name in {"halt", "intr"}: return self.hwif.get_implied_prop_output_identifier(reg, prop_name) raise NotImplementedError - - def get_access_strobe(self, obj: Union[RegNode, FieldNode], reduce_substrobes: bool=True) -> str: + def get_access_strobe( + self, obj: Union[RegNode, FieldNode], reduce_substrobes: bool = True + ) -> str: """ Returns the Verilog string that represents the register's access strobe """ return self.address_decode.get_access_strobe(obj, reduce_substrobes) - def get_external_block_access_strobe(self, obj: 'AddressableNode') -> str: + def get_external_block_access_strobe(self, obj: "AddressableNode") -> str: """ Returns the Verilog string that represents the external block's access strobe """ @@ -229,14 +233,13 @@ class Dereferencer: s = f"{s}_n" return s - def get_resetsignal(self, obj: Optional[SignalNode] = None) -> str: """ Returns a normalized active-high reset signal """ if isinstance(obj, SignalNode): s = self.get_value(obj) - if obj.get_property('activehigh'): + if obj.get_property("activehigh"): return str(s) else: return f"~{s}" @@ -257,8 +260,12 @@ class Dereferencer: return f"@(posedge clk or posedge {self.default_resetsignal_name})" else: return "@(posedge clk)" - elif resetsignal.get_property('async') and resetsignal.get_property('activehigh'): + elif resetsignal.get_property("async") and resetsignal.get_property( + "activehigh" + ): return f"@(posedge clk or posedge {self.get_value(resetsignal)})" - elif resetsignal.get_property('async') and not resetsignal.get_property('activehigh'): + elif resetsignal.get_property("async") and not resetsignal.get_property( + "activehigh" + ): return f"@(posedge clk or negedge {self.get_value(resetsignal)})" return "@(posedge clk)" diff --git a/src/peakrdl_regblock/exporter.py b/src/peakrdl_regblock/exporter.py index b2c5f29..1c9cd5a 100644 --- a/src/peakrdl_regblock/exporter.py +++ b/src/peakrdl_regblock/exporter.py @@ -26,7 +26,8 @@ if TYPE_CHECKING: from systemrdl.node import SignalNode from systemrdl.rdltypes import UserEnum -class RegblockExporter: + +class BusDecoderExporter: hwif: Hwif cpuif: CpuifBase address_decode: AddressDecode @@ -35,28 +36,35 @@ class RegblockExporter: write_buffering: WriteBuffering read_buffering: ReadBuffering dereferencer: Dereferencer - ds: 'DesignState' + ds: "DesignState" def __init__(self, **kwargs: Any) -> None: # Check for stray kwargs if kwargs: - raise TypeError(f"got an unexpected keyword argument '{list(kwargs.keys())[0]}'") + raise TypeError( + f"got an unexpected keyword argument '{list(kwargs.keys())[0]}'" + ) - - loader = jj.ChoiceLoader([ - jj.FileSystemLoader(os.path.dirname(__file__)), - jj.PrefixLoader({ - 'base': jj.FileSystemLoader(os.path.dirname(__file__)), - }, delimiter=":") - ]) + loader = jj.ChoiceLoader( + [ + jj.FileSystemLoader(os.path.dirname(__file__)), + jj.PrefixLoader( + { + "base": jj.FileSystemLoader(os.path.dirname(__file__)), + }, + delimiter=":", + ), + ] + ) self.jj_env = jj.Environment( loader=loader, undefined=jj.StrictUndefined, ) - - def export(self, node: Union[RootNode, AddrmapNode], output_dir:str, **kwargs: Any) -> None: + def export( + self, node: Union[RootNode, AddrmapNode], output_dir: str, **kwargs: Any + ) -> None: """ Parameters ---------- @@ -65,7 +73,7 @@ class RegblockExporter: output_dir: str Path to the output directory where generated SystemVerilog will be written. Output includes two files: a module definition and package definition. - cpuif_cls: :class:`peakrdl_regblock.cpuif.CpuifBase` + cpuif_cls: :class:`peakrdl_busdecoder.cpuif.CpuifBase` Specify the class type that implements the CPU interface of your choice. Defaults to AMBA APB4. module_name: str @@ -115,7 +123,7 @@ class RegblockExporter: the contents of the ``hwif_in`` and ``hwif_out`` structures. address_width: int Override the CPU interface's address width. By default, address width - is sized to the contents of the regblock. + is sized to the contents of the busdecoder. default_reset_activelow: bool If overriden to True, default reset is active-low instead of active-high. default_reset_async: bool @@ -129,16 +137,18 @@ class RegblockExporter: self.ds = DesignState(top_node, kwargs) - cpuif_cls = kwargs.pop("cpuif_cls", None) or APB4_Cpuif # type: Type[CpuifBase] - generate_hwif_report = kwargs.pop("generate_hwif_report", False) # type: bool + cpuif_cls = kwargs.pop("cpuif_cls", None) or APB4_Cpuif # type: Type[CpuifBase] + generate_hwif_report = kwargs.pop("generate_hwif_report", False) # type: bool # Check for stray kwargs if kwargs: - raise TypeError(f"got an unexpected keyword argument '{list(kwargs.keys())[0]}'") + raise TypeError( + f"got an unexpected keyword argument '{list(kwargs.keys())[0]}'" + ) if generate_hwif_report: path = os.path.join(output_dir, f"{self.ds.module_name}_hwif.rpt") - hwif_report_file = open(path, "w", encoding='utf-8') # pylint: disable=consider-using-with + hwif_report_file = open(path, "w", encoding="utf-8") # pylint: disable=consider-using-with else: hwif_report_file = None @@ -181,7 +191,7 @@ class RegblockExporter: "get_always_ff_event": self.dereferencer.get_always_ff_event, "ds": self.ds, "kwf": kwf, - "SVInt" : SVInt, + "SVInt": SVInt, } # Write out design @@ -210,34 +220,38 @@ class DesignState: self.top_node = top_node msg = top_node.env.msg - #------------------------ + # ------------------------ # Extract compiler args - #------------------------ - self.reuse_hwif_typedefs = kwargs.pop("reuse_hwif_typedefs", True) # type: bool - self.module_name = kwargs.pop("module_name", None) or kwf(self.top_node.inst_name) # type: str - self.package_name = kwargs.pop("package_name", None) or (self.module_name + "_pkg") # type: str - user_addr_width = kwargs.pop("address_width", None) # type: Optional[int] + # ------------------------ + self.reuse_hwif_typedefs = kwargs.pop("reuse_hwif_typedefs", True) # type: bool + self.module_name = kwargs.pop("module_name", None) or kwf( + self.top_node.inst_name + ) # type: str + self.package_name = kwargs.pop("package_name", None) or ( + self.module_name + "_pkg" + ) # type: str + user_addr_width = kwargs.pop("address_width", None) # type: Optional[int] # Pipelining options - self.retime_read_fanin = kwargs.pop("retime_read_fanin", False) # type: bool - self.retime_read_response = kwargs.pop("retime_read_response", False) # type: bool - self.retime_external_reg = kwargs.pop("retime_external_reg", False) # type: bool - self.retime_external_regfile = kwargs.pop("retime_external_regfile", False) # type: bool - self.retime_external_mem = kwargs.pop("retime_external_mem", False) # type: bool - self.retime_external_addrmap = kwargs.pop("retime_external_addrmap", False) # type: bool + self.retime_read_fanin = kwargs.pop("retime_read_fanin", False) # type: bool + self.retime_read_response = kwargs.pop("retime_read_response", False) # type: bool + self.retime_external_reg = kwargs.pop("retime_external_reg", False) # type: bool + self.retime_external_regfile = kwargs.pop("retime_external_regfile", False) # type: bool + self.retime_external_mem = kwargs.pop("retime_external_mem", False) # type: bool + self.retime_external_addrmap = kwargs.pop("retime_external_addrmap", False) # type: bool # Default reset type - self.default_reset_activelow = kwargs.pop("default_reset_activelow", False) # type: bool - self.default_reset_async = kwargs.pop("default_reset_async", False) # type: bool + self.default_reset_activelow = kwargs.pop("default_reset_activelow", False) # type: bool + self.default_reset_async = kwargs.pop("default_reset_async", False) # type: bool - #------------------------ + # ------------------------ # Info about the design - #------------------------ + # ------------------------ self.cpuif_data_width = 0 # Collections of signals that were actually referenced by the design - self.in_hier_signal_paths = set() # type: Set[str] - self.out_of_hier_signals = OrderedDict() # type: OrderedDict[str, SignalNode] + self.in_hier_signal_paths = set() # type: Set[str] + self.out_of_hier_signals = OrderedDict() # type: OrderedDict[str, SignalNode] self.has_writable_msb0_fields = False self.has_buffered_write_regs = False @@ -249,7 +263,7 @@ class DesignState: self.has_paritycheck = False # Track any referenced enums - self.user_enums = [] # type: List[Type[UserEnum]] + self.user_enums = [] # type: List[Type[UserEnum]] # Scan the design to fill in above variables DesignScanner(self).do_scan() @@ -260,17 +274,21 @@ class DesignState: # Assume 32-bits msg.warning( "Addrmap being exported only contains external components. Unable to infer the CPUIF bus width. Assuming 32-bits.", - self.top_node.inst.def_src_ref + self.top_node.inst.def_src_ref, ) self.cpuif_data_width = 32 - #------------------------ + # ------------------------ # Min address width encloses the total size AND at least 1 useful address bit - self.addr_width = max(clog2(self.top_node.size), clog2(self.cpuif_data_width//8) + 1) + self.addr_width = max( + clog2(self.top_node.size), clog2(self.cpuif_data_width // 8) + 1 + ) if user_addr_width is not None: if user_addr_width < self.addr_width: - msg.fatal(f"User-specified address width shall be greater than or equal to {self.addr_width}.") + msg.fatal( + f"User-specified address width shall be greater than or equal to {self.addr_width}." + ) self.addr_width = user_addr_width @property diff --git a/src/peakrdl_regblock/external_acks.py b/src/peakrdl_regblock/external_acks.py index 9a6c044..d23f9ae 100644 --- a/src/peakrdl_regblock/external_acks.py +++ b/src/peakrdl_regblock/external_acks.py @@ -6,12 +6,12 @@ from systemrdl.node import RegNode from .forloop_generator import RDLForLoopGenerator if TYPE_CHECKING: - from .exporter import RegblockExporter + from .exporter import BusDecoderExporter from systemrdl.node import AddressableNode class ExternalWriteAckGenerator(RDLForLoopGenerator): - def __init__(self, exp: 'RegblockExporter') -> None: + def __init__(self, exp: "BusDecoderExporter") -> None: super().__init__() self.exp = exp @@ -21,19 +21,21 @@ class ExternalWriteAckGenerator(RDLForLoopGenerator): return "" return content - def enter_AddressableComponent(self, node: 'AddressableNode') -> WalkerAction: + def enter_AddressableComponent(self, node: "AddressableNode") -> WalkerAction: super().enter_AddressableComponent(node) if node.external: if not isinstance(node, RegNode) or node.has_sw_writable: - self.add_content(f"wr_ack |= {self.exp.hwif.get_external_wr_ack(node)};") + self.add_content( + f"wr_ack |= {self.exp.hwif.get_external_wr_ack(node)};" + ) return WalkerAction.SkipDescendants return WalkerAction.Continue class ExternalReadAckGenerator(RDLForLoopGenerator): - def __init__(self, exp: 'RegblockExporter') -> None: + def __init__(self, exp: "BusDecoderExporter") -> None: super().__init__() self.exp = exp @@ -43,12 +45,14 @@ class ExternalReadAckGenerator(RDLForLoopGenerator): return "" return content - def enter_AddressableComponent(self, node: 'AddressableNode') -> WalkerAction: + def enter_AddressableComponent(self, node: "AddressableNode") -> WalkerAction: super().enter_AddressableComponent(node) if node.external: if not isinstance(node, RegNode) or node.has_sw_readable: - self.add_content(f"rd_ack |= {self.exp.hwif.get_external_rd_ack(node)};") + self.add_content( + f"rd_ack |= {self.exp.hwif.get_external_rd_ack(node)};" + ) return WalkerAction.SkipDescendants return WalkerAction.Continue diff --git a/src/peakrdl_regblock/field_logic/__init__.py b/src/peakrdl_regblock/field_logic/__init__.py index b44c7f6..bd5e28b 100644 --- a/src/peakrdl_regblock/field_logic/__init__.py +++ b/src/peakrdl_regblock/field_logic/__init__.py @@ -14,28 +14,33 @@ from . import hw_interrupts_with_write from ..utils import get_indexed_path from ..sv_int import SVInt -from .generators import CombinationalStructGenerator, FieldStorageStructGenerator, FieldLogicGenerator +from .generators import ( + CombinationalStructGenerator, + FieldStorageStructGenerator, + FieldLogicGenerator, +) if TYPE_CHECKING: from typing import Dict, List from systemrdl.node import AddrmapNode, FieldNode - from ..exporter import RegblockExporter, DesignState + from ..exporter import BusDecoderExporter, DesignState + class FieldLogic: - def __init__(self, exp:'RegblockExporter'): + def __init__(self, exp: "BusDecoderExporter"): self.exp = exp - self._hw_conditionals = {} # type: Dict[int, List[NextStateConditional]] - self._sw_conditionals = {} # type: Dict[int, List[NextStateConditional]] + self._hw_conditionals = {} # type: Dict[int, List[NextStateConditional]] + self._sw_conditionals = {} # type: Dict[int, List[NextStateConditional]] self.init_conditionals() @property - def ds(self) -> 'DesignState': + def ds(self) -> "DesignState": return self.exp.ds @property - def top_node(self) -> 'AddrmapNode': + def top_node(self) -> "AddrmapNode": return self.exp.ds.top_node def get_storage_struct(self) -> str: @@ -65,10 +70,10 @@ class FieldLogic: return "" return s - #--------------------------------------------------------------------------- + # --------------------------------------------------------------------------- # Field utility functions - #--------------------------------------------------------------------------- - def get_storage_identifier(self, field: 'FieldNode') -> str: + # --------------------------------------------------------------------------- + def get_storage_identifier(self, field: "FieldNode") -> str: """ Returns the Verilog string that represents the storage register element for the referenced field @@ -77,7 +82,7 @@ class FieldLogic: path = get_indexed_path(self.top_node, field) return f"field_storage.{path}.value" - def get_next_q_identifier(self, field: 'FieldNode') -> str: + def get_next_q_identifier(self, field: "FieldNode") -> str: """ Returns the Verilog string that represents the storage register element for the delayed 'next' input value @@ -86,7 +91,7 @@ class FieldLogic: path = get_indexed_path(self.top_node, field) return f"field_storage.{path}.next_q" - def get_field_combo_identifier(self, field: 'FieldNode', name: str) -> str: + def get_field_combo_identifier(self, field: "FieldNode", name: str) -> str: """ Returns a Verilog string that represents a field's internal combinational signal. @@ -95,94 +100,94 @@ class FieldLogic: path = get_indexed_path(self.top_node, field) return f"field_combo.{path}.{name}" - def get_counter_incr_strobe(self, field: 'FieldNode') -> str: + def get_counter_incr_strobe(self, field: "FieldNode") -> str: """ Return the Verilog string that represents the field's incr strobe signal. """ - prop_value = field.get_property('incr') + prop_value = field.get_property("incr") if prop_value: return str(self.exp.dereferencer.get_value(prop_value)) # unset by the user, points to the implied input signal return self.exp.hwif.get_implied_prop_input_identifier(field, "incr") - def get_counter_incrvalue(self, field: 'FieldNode') -> Union[SVInt, str]: + def get_counter_incrvalue(self, field: "FieldNode") -> Union[SVInt, str]: """ Return the string that represents the field's increment value """ - incrvalue = field.get_property('incrvalue') + incrvalue = field.get_property("incrvalue") if incrvalue is not None: return self.exp.dereferencer.get_value(incrvalue, field.width) - if field.get_property('incrwidth'): + if field.get_property("incrwidth"): return self.exp.hwif.get_implied_prop_input_identifier(field, "incrvalue") return "1'b1" - def get_counter_incrsaturate_value(self, field: 'FieldNode') -> Union[SVInt, str]: - prop_value = field.get_property('incrsaturate') + def get_counter_incrsaturate_value(self, field: "FieldNode") -> Union[SVInt, str]: + prop_value = field.get_property("incrsaturate") if prop_value is True: return self.exp.dereferencer.get_value(2**field.width - 1, field.width) return self.exp.dereferencer.get_value(prop_value, field.width) - def counter_incrsaturates(self, field: 'FieldNode') -> bool: + def counter_incrsaturates(self, field: "FieldNode") -> bool: """ Returns True if the counter saturates """ - return field.get_property('incrsaturate') is not False + return field.get_property("incrsaturate") is not False - def get_counter_incrthreshold_value(self, field: 'FieldNode') -> Union[SVInt, str]: - prop_value = field.get_property('incrthreshold') + def get_counter_incrthreshold_value(self, field: "FieldNode") -> Union[SVInt, str]: + prop_value = field.get_property("incrthreshold") if isinstance(prop_value, bool): # No explicit value set. use max return self.exp.dereferencer.get_value(2**field.width - 1, field.width) return self.exp.dereferencer.get_value(prop_value, field.width) - def get_counter_decr_strobe(self, field: 'FieldNode') -> str: + def get_counter_decr_strobe(self, field: "FieldNode") -> str: """ Return the Verilog string that represents the field's incr strobe signal. """ - prop_value = field.get_property('decr') + prop_value = field.get_property("decr") if prop_value: return str(self.exp.dereferencer.get_value(prop_value)) # unset by the user, points to the implied input signal return self.exp.hwif.get_implied_prop_input_identifier(field, "decr") - def get_counter_decrvalue(self, field: 'FieldNode') -> Union[SVInt, str]: + def get_counter_decrvalue(self, field: "FieldNode") -> Union[SVInt, str]: """ Return the string that represents the field's decrement value """ - decrvalue = field.get_property('decrvalue') + decrvalue = field.get_property("decrvalue") if decrvalue is not None: return self.exp.dereferencer.get_value(decrvalue, field.width) - if field.get_property('decrwidth'): + if field.get_property("decrwidth"): return self.exp.hwif.get_implied_prop_input_identifier(field, "decrvalue") return "1'b1" - def get_counter_decrsaturate_value(self, field: 'FieldNode') -> Union[SVInt, str]: - prop_value = field.get_property('decrsaturate') + def get_counter_decrsaturate_value(self, field: "FieldNode") -> Union[SVInt, str]: + prop_value = field.get_property("decrsaturate") if prop_value is True: return f"{field.width}'d0" return self.exp.dereferencer.get_value(prop_value, field.width) - def counter_decrsaturates(self, field: 'FieldNode') -> bool: + def counter_decrsaturates(self, field: "FieldNode") -> bool: """ Returns True if the counter saturates """ - return field.get_property('decrsaturate') is not False + return field.get_property("decrsaturate") is not False - def get_counter_decrthreshold_value(self, field: 'FieldNode') -> Union[SVInt, str]: - prop_value = field.get_property('decrthreshold') + def get_counter_decrthreshold_value(self, field: "FieldNode") -> Union[SVInt, str]: + prop_value = field.get_property("decrthreshold") if isinstance(prop_value, bool): # No explicit value set. use min return f"{field.width}'d0" return self.exp.dereferencer.get_value(prop_value, field.width) - def get_swacc_identifier(self, field: 'FieldNode') -> str: + def get_swacc_identifier(self, field: "FieldNode") -> str: """ Asserted when field is software accessed (read or write) """ - buffer_reads = field.parent.get_property('buffer_reads') - buffer_writes = field.parent.get_property('buffer_writes') + buffer_reads = field.parent.get_property("buffer_reads") + buffer_writes = field.parent.get_property("buffer_writes") if buffer_reads and buffer_writes: rstrb = self.exp.read_buffering.get_trigger(field.parent) wstrb = self.exp.write_buffering.get_write_strobe(field) @@ -199,11 +204,11 @@ class FieldLogic: strb = self.exp.dereferencer.get_access_strobe(field) return strb - def get_rd_swacc_identifier(self, field: 'FieldNode') -> str: + def get_rd_swacc_identifier(self, field: "FieldNode") -> str: """ Asserted when field is software accessed (read) """ - buffer_reads = field.parent.get_property('buffer_reads') + buffer_reads = field.parent.get_property("buffer_reads") if buffer_reads: rstrb = self.exp.read_buffering.get_trigger(field.parent) return rstrb @@ -211,11 +216,11 @@ class FieldLogic: strb = self.exp.dereferencer.get_access_strobe(field) return f"{strb} && !decoded_req_is_wr" - def get_wr_swacc_identifier(self, field: 'FieldNode') -> str: + def get_wr_swacc_identifier(self, field: "FieldNode") -> str: """ Asserted when field is software accessed (write) """ - buffer_writes = field.parent.get_property('buffer_writes') + buffer_writes = field.parent.get_property("buffer_writes") if buffer_writes: wstrb = self.exp.write_buffering.get_write_strobe(field) return wstrb @@ -223,18 +228,17 @@ class FieldLogic: strb = self.exp.dereferencer.get_access_strobe(field) return f"{strb} && decoded_req_is_wr" - def get_swmod_identifier(self, field: 'FieldNode') -> str: + def get_swmod_identifier(self, field: "FieldNode") -> str: """ Asserted when field is modified by software (written or read with a set or clear side effect). """ w_modifiable = field.is_sw_writable - r_modifiable = field.get_property('onread') is not None - buffer_writes = field.parent.get_property('buffer_writes') - buffer_reads = field.parent.get_property('buffer_reads') + r_modifiable = field.get_property("onread") is not None + buffer_writes = field.parent.get_property("buffer_writes") + buffer_reads = field.parent.get_property("buffer_reads") accesswidth = field.parent.get_property("accesswidth") - astrb = self.exp.dereferencer.get_access_strobe(field) conditions = [] @@ -267,43 +271,42 @@ class FieldLogic: else: return " || ".join(conditions) - - def get_parity_identifier(self, field: 'FieldNode') -> str: + def get_parity_identifier(self, field: "FieldNode") -> str: """ Returns the identifier for the stored 'golden' parity value of the field """ path = get_indexed_path(self.top_node, field) return f"field_storage.{path}.parity" - def get_parity_error_identifier(self, field: 'FieldNode') -> str: + def get_parity_error_identifier(self, field: "FieldNode") -> str: """ Returns the identifier for whether the field currently has a parity error """ path = get_indexed_path(self.top_node, field) return f"field_combo.{path}.parity_error" - def has_next_q(self, field: 'FieldNode') -> bool: + def has_next_q(self, field: "FieldNode") -> bool: """ Some fields require a delayed version of their 'next' input signal in order to do edge-detection. Returns True if this is the case. """ - if field.get_property('intr type') in { + if field.get_property("intr type") in { InterruptType.posedge, InterruptType.negedge, - InterruptType.bothedge + InterruptType.bothedge, }: return True return False - def get_wbus_bitslice(self, field: 'FieldNode', subword_idx: int = 0) -> str: + def get_wbus_bitslice(self, field: "FieldNode", subword_idx: int = 0) -> str: """ Get the bitslice range string of the internal cpuif's data/biten bus that corresponds to this field """ - if field.parent.get_property('buffer_writes'): + if field.parent.get_property("buffer_writes"): # register is buffered. # write buffer is the full width of the register. no need to deal with subwords high = field.high @@ -311,7 +314,7 @@ class FieldLogic: if field.msb < field.lsb: # slice is for an msb0 field. # mirror it - regwidth = field.parent.get_property('regwidth') + regwidth = field.parent.get_property("regwidth") low = regwidth - 1 - low high = regwidth - 1 - high low, high = high, low @@ -321,7 +324,7 @@ class FieldLogic: # values unchanged. # For fields within a wide register (accesswidth < regwidth), low/high # may be shifted down and clamped depending on which sub-word is being accessed - accesswidth = field.parent.get_property('accesswidth') + accesswidth = field.parent.get_property("accesswidth") # Shift based on subword high = field.high - (subword_idx * accesswidth) @@ -341,11 +344,11 @@ class FieldLogic: return f"[{high}:{low}]" - def get_wr_biten(self, field: 'FieldNode', subword_idx: int=0) -> str: + def get_wr_biten(self, field: "FieldNode", subword_idx: int = 0) -> str: """ Get the bit-enable slice that corresponds to this field """ - if field.parent.get_property('buffer_writes'): + if field.parent.get_property("buffer_writes"): # Is buffered. Use value from write buffer # No need to check msb0 ordering. Bus is pre-swapped, and bitslice # accounts for it @@ -363,11 +366,11 @@ class FieldLogic: value = "decoded_wr_biten" + bslice return value - def get_wr_data(self, field: 'FieldNode', subword_idx: int=0) -> str: + def get_wr_data(self, field: "FieldNode", subword_idx: int = 0) -> str: """ Get the write data slice that corresponds to this field """ - if field.parent.get_property('buffer_writes'): + if field.parent.get_property("buffer_writes"): # Is buffered. Use value from write buffer # No need to check msb0 ordering. Bus is pre-swapped, and bitslice # accounts for it @@ -385,10 +388,12 @@ class FieldLogic: value = "decoded_wr_data" + bslice return value - #--------------------------------------------------------------------------- + # --------------------------------------------------------------------------- # Field Logic Conditionals - #--------------------------------------------------------------------------- - def add_hw_conditional(self, conditional: NextStateConditional, precedence: AssignmentPrecedence) -> None: + # --------------------------------------------------------------------------- + def add_hw_conditional( + self, conditional: NextStateConditional, precedence: AssignmentPrecedence + ) -> None: """ Register a NextStateConditional action for hardware-triggered field updates. Categorizing conditionals correctly by hw/sw ensures that the RDL precedence @@ -404,8 +409,9 @@ class FieldLogic: self._hw_conditionals[precedence] = [] self._hw_conditionals[precedence].append(conditional) - - def add_sw_conditional(self, conditional: NextStateConditional, precedence: AssignmentPrecedence) -> None: + def add_sw_conditional( + self, conditional: NextStateConditional, precedence: AssignmentPrecedence + ) -> None: """ Register a NextStateConditional action for software-triggered field updates. Categorizing conditionals correctly by hw/sw ensures that the RDL precedence @@ -421,7 +427,6 @@ class FieldLogic: self._sw_conditionals[precedence] = [] self._sw_conditionals[precedence].append(conditional) - def init_conditionals(self) -> None: """ Initialize all possible conditionals here. @@ -430,46 +435,117 @@ class FieldLogic: same assignment precedence. """ - self.add_sw_conditional(sw_onread.ClearOnRead(self.exp), AssignmentPrecedence.SW_ONREAD) - self.add_sw_conditional(sw_onread.SetOnRead(self.exp), AssignmentPrecedence.SW_ONREAD) + self.add_sw_conditional( + sw_onread.ClearOnRead(self.exp), AssignmentPrecedence.SW_ONREAD + ) + self.add_sw_conditional( + sw_onread.SetOnRead(self.exp), AssignmentPrecedence.SW_ONREAD + ) - self.add_sw_conditional(sw_onwrite.Write(self.exp), AssignmentPrecedence.SW_ONWRITE) - self.add_sw_conditional(sw_onwrite.WriteSet(self.exp), AssignmentPrecedence.SW_ONWRITE) - self.add_sw_conditional(sw_onwrite.WriteClear(self.exp), AssignmentPrecedence.SW_ONWRITE) - self.add_sw_conditional(sw_onwrite.WriteZeroToggle(self.exp), AssignmentPrecedence.SW_ONWRITE) - self.add_sw_conditional(sw_onwrite.WriteZeroClear(self.exp), AssignmentPrecedence.SW_ONWRITE) - self.add_sw_conditional(sw_onwrite.WriteZeroSet(self.exp), AssignmentPrecedence.SW_ONWRITE) - self.add_sw_conditional(sw_onwrite.WriteOneToggle(self.exp), AssignmentPrecedence.SW_ONWRITE) - self.add_sw_conditional(sw_onwrite.WriteOneClear(self.exp), AssignmentPrecedence.SW_ONWRITE) - self.add_sw_conditional(sw_onwrite.WriteOneSet(self.exp), AssignmentPrecedence.SW_ONWRITE) + self.add_sw_conditional( + sw_onwrite.Write(self.exp), AssignmentPrecedence.SW_ONWRITE + ) + self.add_sw_conditional( + sw_onwrite.WriteSet(self.exp), AssignmentPrecedence.SW_ONWRITE + ) + self.add_sw_conditional( + sw_onwrite.WriteClear(self.exp), AssignmentPrecedence.SW_ONWRITE + ) + self.add_sw_conditional( + sw_onwrite.WriteZeroToggle(self.exp), AssignmentPrecedence.SW_ONWRITE + ) + self.add_sw_conditional( + sw_onwrite.WriteZeroClear(self.exp), AssignmentPrecedence.SW_ONWRITE + ) + self.add_sw_conditional( + sw_onwrite.WriteZeroSet(self.exp), AssignmentPrecedence.SW_ONWRITE + ) + self.add_sw_conditional( + sw_onwrite.WriteOneToggle(self.exp), AssignmentPrecedence.SW_ONWRITE + ) + self.add_sw_conditional( + sw_onwrite.WriteOneClear(self.exp), AssignmentPrecedence.SW_ONWRITE + ) + self.add_sw_conditional( + sw_onwrite.WriteOneSet(self.exp), AssignmentPrecedence.SW_ONWRITE + ) - self.add_sw_conditional(sw_singlepulse.Singlepulse(self.exp), AssignmentPrecedence.SW_SINGLEPULSE) + self.add_sw_conditional( + sw_singlepulse.Singlepulse(self.exp), AssignmentPrecedence.SW_SINGLEPULSE + ) - self.add_hw_conditional(hw_interrupts_with_write.PosedgeStickybitWE(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts_with_write.PosedgeStickybitWEL(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts_with_write.NegedgeStickybitWE(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts_with_write.NegedgeStickybitWEL(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts_with_write.BothedgeStickybitWE(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts_with_write.BothedgeStickybitWEL(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts_with_write.StickyWE(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts_with_write.StickyWEL(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts_with_write.StickybitWE(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts_with_write.StickybitWEL(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts.PosedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts.NegedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts.BothedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts.Sticky(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_interrupts.Stickybit(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_write.WEWrite(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_write.WELWrite(self.exp), AssignmentPrecedence.HW_WRITE) - self.add_hw_conditional(hw_write.AlwaysWrite(self.exp), AssignmentPrecedence.HW_WRITE) + self.add_hw_conditional( + hw_interrupts_with_write.PosedgeStickybitWE(self.exp), + AssignmentPrecedence.HW_WRITE, + ) + self.add_hw_conditional( + hw_interrupts_with_write.PosedgeStickybitWEL(self.exp), + AssignmentPrecedence.HW_WRITE, + ) + self.add_hw_conditional( + hw_interrupts_with_write.NegedgeStickybitWE(self.exp), + AssignmentPrecedence.HW_WRITE, + ) + self.add_hw_conditional( + hw_interrupts_with_write.NegedgeStickybitWEL(self.exp), + AssignmentPrecedence.HW_WRITE, + ) + self.add_hw_conditional( + hw_interrupts_with_write.BothedgeStickybitWE(self.exp), + AssignmentPrecedence.HW_WRITE, + ) + self.add_hw_conditional( + hw_interrupts_with_write.BothedgeStickybitWEL(self.exp), + AssignmentPrecedence.HW_WRITE, + ) + self.add_hw_conditional( + hw_interrupts_with_write.StickyWE(self.exp), AssignmentPrecedence.HW_WRITE + ) + self.add_hw_conditional( + hw_interrupts_with_write.StickyWEL(self.exp), AssignmentPrecedence.HW_WRITE + ) + self.add_hw_conditional( + hw_interrupts_with_write.StickybitWE(self.exp), + AssignmentPrecedence.HW_WRITE, + ) + self.add_hw_conditional( + hw_interrupts_with_write.StickybitWEL(self.exp), + AssignmentPrecedence.HW_WRITE, + ) + self.add_hw_conditional( + hw_interrupts.PosedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE + ) + self.add_hw_conditional( + hw_interrupts.NegedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE + ) + self.add_hw_conditional( + hw_interrupts.BothedgeStickybit(self.exp), AssignmentPrecedence.HW_WRITE + ) + self.add_hw_conditional( + hw_interrupts.Sticky(self.exp), AssignmentPrecedence.HW_WRITE + ) + self.add_hw_conditional( + hw_interrupts.Stickybit(self.exp), AssignmentPrecedence.HW_WRITE + ) + self.add_hw_conditional( + hw_write.WEWrite(self.exp), AssignmentPrecedence.HW_WRITE + ) + self.add_hw_conditional( + hw_write.WELWrite(self.exp), AssignmentPrecedence.HW_WRITE + ) + self.add_hw_conditional( + hw_write.AlwaysWrite(self.exp), AssignmentPrecedence.HW_WRITE + ) - self.add_hw_conditional(hw_set_clr.HWClear(self.exp), AssignmentPrecedence.HWCLR) + self.add_hw_conditional( + hw_set_clr.HWClear(self.exp), AssignmentPrecedence.HWCLR + ) self.add_hw_conditional(hw_set_clr.HWSet(self.exp), AssignmentPrecedence.HWSET) - - def _get_X_conditionals(self, conditionals: 'Dict[int, List[NextStateConditional]]', field: 'FieldNode') -> 'List[NextStateConditional]': + def _get_X_conditionals( + self, conditionals: "Dict[int, List[NextStateConditional]]", field: "FieldNode" + ) -> "List[NextStateConditional]": result = [] precedences = sorted(conditionals.keys(), reverse=True) for precedence in precedences: @@ -479,15 +555,14 @@ class FieldLogic: break return result - - def get_conditionals(self, field: 'FieldNode') -> 'List[NextStateConditional]': + def get_conditionals(self, field: "FieldNode") -> "List[NextStateConditional]": """ Get a list of NextStateConditional objects that apply to the given field. The returned list is sorted in priority order - the conditional with highest precedence is first in the list. """ - sw_precedence = field.get_property('precedence') == PrecedenceType.sw + sw_precedence = field.get_property("precedence") == PrecedenceType.sw result = [] if sw_precedence: diff --git a/src/peakrdl_regblock/field_logic/bases.py b/src/peakrdl_regblock/field_logic/bases.py index 2a13676..d126df8 100644 --- a/src/peakrdl_regblock/field_logic/bases.py +++ b/src/peakrdl_regblock/field_logic/bases.py @@ -6,7 +6,8 @@ from ..utils import get_indexed_path if TYPE_CHECKING: from systemrdl.node import FieldNode - from ..exporter import RegblockExporter + from ..exporter import BusDecoderExporter + class AssignmentPrecedence(enum.IntEnum): """ @@ -29,16 +30,15 @@ class AssignmentPrecedence(enum.IntEnum): # Hardware access assignment groups HW_WRITE = 3000 HWSET = 2000 - HWCLR = 1000 + HWCLR = 1000 COUNTER_INCR_DECR = 0 - - class SVLogic: """ Represents a SystemVerilog logic signal """ + def __init__(self, name: str, width: int, default_assignment: str) -> None: self.name = name self.width = width @@ -67,10 +67,10 @@ class NextStateConditional: # Optional comment to emit next to the conditional comment = "" - def __init__(self, exp:'RegblockExporter'): + def __init__(self, exp: "BusDecoderExporter"): self.exp = exp - def is_match(self, field: 'FieldNode') -> bool: + def is_match(self, field: "FieldNode") -> bool: """ Returns True if this conditional is relevant to the field. If so, it instructs the FieldBuilder that Verilog for this conditional shall @@ -78,17 +78,16 @@ class NextStateConditional: """ raise NotImplementedError - def get_field_path(self, field:'FieldNode') -> str: + def get_field_path(self, field: "FieldNode") -> str: return get_indexed_path(self.exp.ds.top_node, field) - def get_predicate(self, field: 'FieldNode') -> str: + def get_predicate(self, field: "FieldNode") -> str: """ Returns the rendered conditional text """ raise NotImplementedError - - def get_assignments(self, field: 'FieldNode') -> List[str]: + def get_assignments(self, field: "FieldNode") -> List[str]: """ Returns a list of rendered assignment strings This will basically always be two: @@ -97,13 +96,14 @@ class NextStateConditional: """ raise NotImplementedError - def get_extra_combo_signals(self, field: 'FieldNode') -> List[SVLogic]: + def get_extra_combo_signals(self, field: "FieldNode") -> List[SVLogic]: """ Return any additional combinational signals that this conditional will assign if present. """ return [] + class NextStateUnconditional(NextStateConditional): """ Use this class if predicate can never evaluate to false. diff --git a/src/peakrdl_regblock/hwif/__init__.py b/src/peakrdl_regblock/hwif/__init__.py index 1462264..3f040f0 100644 --- a/src/peakrdl_regblock/hwif/__init__.py +++ b/src/peakrdl_regblock/hwif/__init__.py @@ -12,7 +12,8 @@ from .generators import InputStructGenerator_TypeScope, OutputStructGenerator_Ty from .generators import EnumGenerator if TYPE_CHECKING: - from ..exporter import RegblockExporter, DesignState + from ..exporter import BusDecoderExporter, DesignState + class Hwif: """ @@ -22,10 +23,7 @@ class Hwif: - Signal inputs (except those that are promoted to the top) """ - def __init__( - self, exp: 'RegblockExporter', - hwif_report_file: Optional[TextIO] - ): + def __init__(self, exp: "BusDecoderExporter", hwif_report_file: Optional[TextIO]): self.exp = exp self.has_input_struct = False @@ -41,31 +39,25 @@ class Hwif: self._gen_out_cls = OutputStructGenerator_TypeScope @property - def ds(self) -> 'DesignState': + def ds(self) -> "DesignState": return self.exp.ds @property def top_node(self) -> AddrmapNode: return self.exp.ds.top_node - def get_extra_package_params(self) -> str: lines = [""] for param in self.top_node.inst.parameters: value = param.get_value() if isinstance(value, int): - lines.append( - f"localparam {param.name} = {SVInt(value)};" - ) + lines.append(f"localparam {param.name} = {SVInt(value)};") elif isinstance(value, str): - lines.append( - f"localparam {param.name} = {value};" - ) + lines.append(f"localparam {param.name} = {value};") return "\n".join(lines) - def get_package_contents(self) -> str: """ If this hwif requires a package, generate the string @@ -74,8 +66,7 @@ class Hwif: gen_in = self._gen_in_cls(self) structs_in = gen_in.get_struct( - self.top_node, - f"{self.top_node.inst_name}__in_t" + self.top_node, f"{self.top_node.inst_name}__in_t" ) if structs_in is not None: self.has_input_struct = True @@ -85,8 +76,7 @@ class Hwif: gen_out = self._gen_out_cls(self) structs_out = gen_out.get_struct( - self.top_node, - f"{self.top_node.inst_name}__out_t" + self.top_node, f"{self.top_node.inst_name}__out_t" ) if structs_out is not None: self.has_output_struct = True @@ -101,7 +91,6 @@ class Hwif: return "\n\n".join(lines) - @property def port_declaration(self) -> str: """ @@ -122,9 +111,9 @@ class Hwif: return ",\n".join(lines) - #--------------------------------------------------------------------------- + # --------------------------------------------------------------------------- # hwif utility functions - #--------------------------------------------------------------------------- + # --------------------------------------------------------------------------- def has_value_input(self, obj: Union[FieldNode, SignalNode]) -> bool: """ Returns True if the object infers an input wire in the hwif @@ -137,14 +126,12 @@ class Hwif: else: raise RuntimeError - def has_value_output(self, obj: FieldNode) -> bool: """ Returns True if the object infers an output wire in the hwif """ return obj.is_hw_readable - def get_input_identifier( self, obj: Union[FieldNode, SignalNode, PropertyReference], @@ -162,7 +149,7 @@ class Hwif: raises an exception if obj is invalid """ if isinstance(obj, FieldNode): - next_value = obj.get_property('next') + next_value = obj.get_property("next") if next_value is not None: # 'next' property replaces the inferred input signal return self.exp.dereferencer.get_value(next_value, width) @@ -203,13 +190,20 @@ class Hwif: def get_implied_prop_input_identifier(self, field: FieldNode, prop: str) -> str: assert prop in { - 'hwclr', 'hwset', 'swwe', 'swwel', 'we', 'wel', - 'incr', 'decr', 'incrvalue', 'decrvalue' + "hwclr", + "hwset", + "swwe", + "swwel", + "we", + "wel", + "incr", + "decr", + "incrvalue", + "decrvalue", } path = get_indexed_path(self.top_node, field) return "hwif_in." + path + "." + prop - def get_output_identifier(self, obj: Union[FieldNode, PropertyReference]) -> str: """ Returns the identifier string that best represents the output object. @@ -233,17 +227,27 @@ class Hwif: raise RuntimeError(f"Unhandled reference to: {obj}") - - def get_implied_prop_output_identifier(self, node: Union[FieldNode, RegNode], prop: str) -> str: + def get_implied_prop_output_identifier( + self, node: Union[FieldNode, RegNode], prop: str + ) -> str: if isinstance(node, FieldNode): assert prop in { - "anded", "ored", "xored", "swmod", "swacc", - "incrthreshold", "decrthreshold", "overflow", "underflow", - "rd_swacc", "wr_swacc", + "anded", + "ored", + "xored", + "swmod", + "swacc", + "incrthreshold", + "decrthreshold", + "overflow", + "underflow", + "rd_swacc", + "wr_swacc", } elif isinstance(node, RegNode): assert prop in { - "intr", "halt", + "intr", + "halt", } path = get_indexed_path(self.top_node, node) return "hwif_out." + path + "." + prop diff --git a/src/peakrdl_regblock/module_tmpl.sv b/src/peakrdl_regblock/module_tmpl.sv index bad1c21..246ead1 100644 --- a/src/peakrdl_regblock/module_tmpl.sv +++ b/src/peakrdl_regblock/module_tmpl.sv @@ -1,5 +1,5 @@ -// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator -// https://github.com/SystemRDL/PeakRDL-regblock +// Generated by PeakRDL-busdecoder - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-busdecoder module {{ds.module_name}} {%- if cpuif.parameters %} #( diff --git a/src/peakrdl_regblock/package_tmpl.sv b/src/peakrdl_regblock/package_tmpl.sv index b665495..eb001d4 100644 --- a/src/peakrdl_regblock/package_tmpl.sv +++ b/src/peakrdl_regblock/package_tmpl.sv @@ -1,5 +1,5 @@ -// Generated by PeakRDL-regblock - A free and open-source SystemVerilog generator -// https://github.com/SystemRDL/PeakRDL-regblock +// Generated by PeakRDL-busdecoder - A free and open-source SystemVerilog generator +// https://github.com/SystemRDL/PeakRDL-busdecoder package {{ds.package_name}}; diff --git a/src/peakrdl_regblock/parity.py b/src/peakrdl_regblock/parity.py index 980a2c7..7687423 100644 --- a/src/peakrdl_regblock/parity.py +++ b/src/peakrdl_regblock/parity.py @@ -6,12 +6,12 @@ from systemrdl.walker import WalkerAction from .forloop_generator import RDLForLoopGenerator if TYPE_CHECKING: - from .exporter import RegblockExporter + from .exporter import BusDecoderExporter from systemrdl.node import FieldNode, AddressableNode class ParityErrorReduceGenerator(RDLForLoopGenerator): - def __init__(self, exp: 'RegblockExporter') -> None: + def __init__(self, exp: "BusDecoderExporter") -> None: super().__init__() self.exp = exp @@ -21,14 +21,14 @@ class ParityErrorReduceGenerator(RDLForLoopGenerator): return "" return content - def enter_AddressableComponent(self, node: 'AddressableNode') -> WalkerAction: + def enter_AddressableComponent(self, node: "AddressableNode") -> WalkerAction: super().enter_AddressableComponent(node) if node.external: return WalkerAction.SkipDescendants return WalkerAction.Continue - def enter_Field(self, node: 'FieldNode') -> None: - if node.get_property('paritycheck') and node.implements_storage: + def enter_Field(self, node: "FieldNode") -> None: + if node.get_property("paritycheck") and node.implements_storage: self.add_content( f"err |= {self.exp.field_logic.get_parity_error_identifier(node)};" ) diff --git a/src/peakrdl_regblock/read_buffering/__init__.py b/src/peakrdl_regblock/read_buffering/__init__.py index 65ccc94..d6554c4 100644 --- a/src/peakrdl_regblock/read_buffering/__init__.py +++ b/src/peakrdl_regblock/read_buffering/__init__.py @@ -8,15 +8,15 @@ from ..utils import get_indexed_path from ..sv_int import SVInt if TYPE_CHECKING: - from ..exporter import RegblockExporter + from ..exporter import BusDecoderExporter class ReadBuffering: - def __init__(self, exp:'RegblockExporter'): + def __init__(self, exp: "BusDecoderExporter"): self.exp = exp @property - def top_node(self) -> 'AddrmapNode': + def top_node(self) -> "AddrmapNode": return self.exp.ds.top_node def get_storage_struct(self) -> str: @@ -32,14 +32,16 @@ class ReadBuffering: return s def get_trigger(self, node: RegNode) -> str: - trigger = node.get_property('rbuffer_trigger') + trigger = node.get_property("rbuffer_trigger") if isinstance(trigger, RegNode): # Trigger is a register. # trigger when lowermost address of the register is written - regwidth = trigger.get_property('regwidth') - accesswidth = trigger.get_property('accesswidth') - strb_prefix = self.exp.dereferencer.get_access_strobe(trigger, reduce_substrobes=False) + regwidth = trigger.get_property("regwidth") + accesswidth = trigger.get_property("accesswidth") + strb_prefix = self.exp.dereferencer.get_access_strobe( + trigger, reduce_substrobes=False + ) if accesswidth < regwidth: return f"{strb_prefix}[0] && !decoded_req_is_wr" @@ -47,7 +49,7 @@ class ReadBuffering: return f"{strb_prefix} && !decoded_req_is_wr" elif isinstance(trigger, SignalNode): s = self.exp.dereferencer.get_value(trigger) - if trigger.get_property('activehigh'): + if trigger.get_property("activehigh"): return str(s) else: return f"~{s}" diff --git a/src/peakrdl_regblock/readback/__init__.py b/src/peakrdl_regblock/readback/__init__.py index dafb1e0..5e24d3b 100644 --- a/src/peakrdl_regblock/readback/__init__.py +++ b/src/peakrdl_regblock/readback/__init__.py @@ -4,19 +4,20 @@ import math from .generators import ReadbackAssignmentGenerator if TYPE_CHECKING: - from ..exporter import RegblockExporter, DesignState + from ..exporter import BusDecoderExporter, DesignState from systemrdl.node import AddrmapNode + class Readback: - def __init__(self, exp:'RegblockExporter'): + def __init__(self, exp: "BusDecoderExporter"): self.exp = exp @property - def ds(self) -> 'DesignState': + def ds(self) -> "DesignState": return self.exp.ds @property - def top_node(self) -> 'AddrmapNode': + def top_node(self) -> "AddrmapNode": return self.exp.ds.top_node def get_implementation(self) -> str: @@ -30,10 +31,10 @@ class Readback: self.ds.retime_read_fanin = False context = { - "array_assignments" : array_assignments, - "array_size" : array_size, - 'get_always_ff_event': self.exp.dereferencer.get_always_ff_event, - 'get_resetsignal': self.exp.dereferencer.get_resetsignal, + "array_assignments": array_assignments, + "array_size": array_size, + "get_always_ff_event": self.exp.dereferencer.get_always_ff_event, + "get_resetsignal": self.exp.dereferencer.get_resetsignal, "cpuif": self.exp.cpuif, "ds": self.ds, } @@ -61,12 +62,10 @@ class Readback: else: fanin_loop_iter = fanin_array_size - context['fanin_stride'] = fanin_stride - context['fanin_array_size'] = fanin_array_size - context['fanin_residual_stride'] = fanin_residual_stride - context['fanin_loop_iter'] = fanin_loop_iter + context["fanin_stride"] = fanin_stride + context["fanin_array_size"] = fanin_array_size + context["fanin_residual_stride"] = fanin_residual_stride + context["fanin_loop_iter"] = fanin_loop_iter - template = self.exp.jj_env.get_template( - "readback/templates/readback.sv" - ) + template = self.exp.jj_env.get_template("readback/templates/readback.sv") return template.render(context) diff --git a/src/peakrdl_regblock/readback/generators.py b/src/peakrdl_regblock/readback/generators.py index 87f2969..7bfa1f3 100644 --- a/src/peakrdl_regblock/readback/generators.py +++ b/src/peakrdl_regblock/readback/generators.py @@ -8,7 +8,8 @@ from ..forloop_generator import RDLForLoopGenerator, LoopBody from ..utils import do_bitswap, do_slice if TYPE_CHECKING: - from ..exporter import RegblockExporter + from ..exporter import BusDecoderExporter + class ReadbackLoopBody(LoopBody): def __init__(self, dim: int, iterator: str, i_type: str) -> None: @@ -22,11 +23,12 @@ class ReadbackLoopBody(LoopBody): s = s.replace(token, str(self.n_regs)) return s + class ReadbackAssignmentGenerator(RDLForLoopGenerator): i_type = "genvar" loop_body_cls = ReadbackLoopBody - def __init__(self, exp:'RegblockExporter') -> None: + def __init__(self, exp: "BusDecoderExporter") -> None: super().__init__() self.exp = exp @@ -34,8 +36,8 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): # array. The array width is equal to the CPUIF bus width. Each entry in # the array represents an aligned read access. self.current_offset = 0 - self.start_offset_stack = [] # type: List[int] - self.dim_stack = [] # type: List[int] + self.start_offset_stack = [] # type: List[int] + self.dim_stack = [] # type: List[int] @property def current_offset_str(self) -> str: @@ -72,22 +74,23 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): # Number of registers enclosed in this loop n_regs = self.current_offset - start_offset - self.current_loop.n_regs = n_regs # type: ignore + self.current_loop.n_regs = n_regs # type: ignore super().pop_loop() # Advance current scope's offset to account for loop's contents self.current_offset = start_offset + n_regs * dim - - def enter_AddressableComponent(self, node: 'AddressableNode') -> WalkerAction: + def enter_AddressableComponent(self, node: "AddressableNode") -> WalkerAction: super().enter_AddressableComponent(node) if node.external and not isinstance(node, RegNode): # External block strb = self.exp.hwif.get_external_rd_ack(node) data = self.exp.hwif.get_external_rd_data(node) - self.add_content(f"assign readback_array[{self.current_offset_str}] = {strb} ? {data} : '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}] = {strb} ? {data} : '0;" + ) self.current_offset += 1 return WalkerAction.SkipDescendants @@ -101,12 +104,12 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): self.process_external_reg(node) return WalkerAction.SkipDescendants - accesswidth = node.get_property('accesswidth') - regwidth = node.get_property('regwidth') - rbuf = node.get_property('buffer_reads') + accesswidth = node.get_property("accesswidth") + regwidth = node.get_property("regwidth") + rbuf = node.get_property("buffer_reads") if rbuf: - trigger = node.get_property('rbuffer_trigger') - is_own_trigger = (isinstance(trigger, RegNode) and trigger == node) + trigger = node.get_property("rbuffer_trigger") + is_own_trigger = isinstance(trigger, RegNode) and trigger == node if is_own_trigger: if accesswidth < regwidth: self.process_buffered_reg_with_bypass(node, regwidth, accesswidth) @@ -125,18 +128,26 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): def process_external_reg(self, node: RegNode) -> None: strb = self.exp.hwif.get_external_rd_ack(node) data = self.exp.hwif.get_external_rd_data(node) - regwidth = node.get_property('regwidth') + regwidth = node.get_property("regwidth") if regwidth < self.exp.cpuif.data_width: - self.add_content(f"assign readback_array[{self.current_offset_str}][{self.exp.cpuif.data_width-1}:{regwidth}] = '0;") - self.add_content(f"assign readback_array[{self.current_offset_str}][{regwidth-1}:0] = {strb} ? {data} : '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{self.exp.cpuif.data_width - 1}:{regwidth}] = '0;" + ) + self.add_content( + f"assign readback_array[{self.current_offset_str}][{regwidth - 1}:0] = {strb} ? {data} : '0;" + ) else: - self.add_content(f"assign readback_array[{self.current_offset_str}] = {strb} ? {data} : '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}] = {strb} ? {data} : '0;" + ) self.current_offset += 1 def process_reg(self, node: RegNode) -> None: current_bit = 0 - rd_strb = f"({self.exp.dereferencer.get_access_strobe(node)} && !decoded_req_is_wr)" + rd_strb = ( + f"({self.exp.dereferencer.get_access_strobe(node)} && !decoded_req_is_wr)" + ) # Fields are sorted by ascending low bit for field in node.fields(): if not field.is_sw_readable: @@ -144,51 +155,67 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): # insert reserved assignment before this field if needed if field.low != current_bit: - self.add_content(f"assign readback_array[{self.current_offset_str}][{field.low-1}:{current_bit}] = '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{field.low - 1}:{current_bit}] = '0;" + ) value = self.exp.dereferencer.get_value(field) if field.msb < field.lsb: # Field gets bitswapped since it is in [low:high] orientation value = do_bitswap(value) - self.add_content(f"assign readback_array[{self.current_offset_str}][{field.high}:{field.low}] = {rd_strb} ? {value} : '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{field.high}:{field.low}] = {rd_strb} ? {value} : '0;" + ) current_bit = field.high + 1 # Insert final reserved assignment if needed bus_width = self.exp.cpuif.data_width if current_bit < bus_width: - self.add_content(f"assign readback_array[{self.current_offset_str}][{bus_width-1}:{current_bit}] = '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{bus_width - 1}:{current_bit}] = '0;" + ) self.current_offset += 1 - - def process_buffered_reg(self, node: RegNode, regwidth: int, accesswidth: int) -> None: + def process_buffered_reg( + self, node: RegNode, regwidth: int, accesswidth: int + ) -> None: rbuf = self.exp.read_buffering.get_rbuf_data(node) if accesswidth < regwidth: # Is wide reg n_subwords = regwidth // accesswidth - astrb = self.exp.dereferencer.get_access_strobe(node, reduce_substrobes=False) + astrb = self.exp.dereferencer.get_access_strobe( + node, reduce_substrobes=False + ) for i in range(n_subwords): rd_strb = f"({astrb}[{i}] && !decoded_req_is_wr)" - bslice = f"[{(i + 1) * accesswidth - 1}:{i*accesswidth}]" - self.add_content(f"assign readback_array[{self.current_offset_str}] = {rd_strb} ? {rbuf}{bslice} : '0;") + bslice = f"[{(i + 1) * accesswidth - 1}:{i * accesswidth}]" + self.add_content( + f"assign readback_array[{self.current_offset_str}] = {rd_strb} ? {rbuf}{bslice} : '0;" + ) self.current_offset += 1 else: # Is regular reg rd_strb = f"({self.exp.dereferencer.get_access_strobe(node)} && !decoded_req_is_wr)" - self.add_content(f"assign readback_array[{self.current_offset_str}][{regwidth-1}:0] = {rd_strb} ? {rbuf} : '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{regwidth - 1}:0] = {rd_strb} ? {rbuf} : '0;" + ) bus_width = self.exp.cpuif.data_width if regwidth < bus_width: - self.add_content(f"assign readback_array[{self.current_offset_str}][{bus_width-1}:{regwidth}] = '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{bus_width - 1}:{regwidth}] = '0;" + ) self.current_offset += 1 - - def process_buffered_reg_with_bypass(self, node: RegNode, regwidth: int, accesswidth: int) -> None: + def process_buffered_reg_with_bypass( + self, node: RegNode, regwidth: int, accesswidth: int + ) -> None: """ Special case for a buffered register when the register is its own trigger. First sub-word shall bypass the read buffer and assign directly. @@ -210,7 +237,9 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): if bidx < field.low: # insert padding before - self.add_content(f"assign readback_array[{self.current_offset_str}][{field.low - 1}:{bidx}] = '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{field.low - 1}:{bidx}] = '0;" + ) if field.high >= accesswidth: # field gets truncated @@ -225,11 +254,17 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): f_low = field.width - 1 - f_low f_high = field.width - 1 - f_high f_low, f_high = f_high, f_low - value = do_bitswap(do_slice(self.exp.dereferencer.get_value(field), f_high, f_low)) + value = do_bitswap( + do_slice(self.exp.dereferencer.get_value(field), f_high, f_low) + ) else: - value = do_slice(self.exp.dereferencer.get_value(field), f_high, f_low) + value = do_slice( + self.exp.dereferencer.get_value(field), f_high, f_low + ) - self.add_content(f"assign readback_array[{self.current_offset_str}][{r_high}:{r_low}] = {rd_strb} ? {value} : '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{r_high}:{r_low}] = {rd_strb} ? {value} : '0;" + ) bidx = accesswidth else: # field fits in subword @@ -237,12 +272,16 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): if field.msb < field.lsb: # Field gets bitswapped since it is in [low:high] orientation value = do_bitswap(value) - self.add_content(f"assign readback_array[{self.current_offset_str}][{field.high}:{field.low}] = {rd_strb} ? {value} : '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{field.high}:{field.low}] = {rd_strb} ? {value} : '0;" + ) bidx = field.high + 1 # pad up remainder of subword if bidx < accesswidth: - self.add_content(f"assign readback_array[{self.current_offset_str}][{accesswidth-1}:{bidx}] = '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{accesswidth - 1}:{bidx}] = '0;" + ) self.current_offset += 1 # Assign remainder of subwords from read buffer @@ -250,29 +289,35 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): rbuf = self.exp.read_buffering.get_rbuf_data(node) for i in range(1, n_subwords): rd_strb = f"({astrb}[{i}] && !decoded_req_is_wr)" - bslice = f"[{(i + 1) * accesswidth - 1}:{i*accesswidth}]" - self.add_content(f"assign readback_array[{self.current_offset_str}] = {rd_strb} ? {rbuf}{bslice} : '0;") + bslice = f"[{(i + 1) * accesswidth - 1}:{i * accesswidth}]" + self.add_content( + f"assign readback_array[{self.current_offset_str}] = {rd_strb} ? {rbuf}{bslice} : '0;" + ) self.current_offset += 1 def process_wide_reg(self, node: RegNode, accesswidth: int) -> None: bus_width = self.exp.cpuif.data_width subword_idx = 0 - current_bit = 0 # Bit-offset within the wide register - access_strb = self.exp.dereferencer.get_access_strobe(node, reduce_substrobes=False) + current_bit = 0 # Bit-offset within the wide register + access_strb = self.exp.dereferencer.get_access_strobe( + node, reduce_substrobes=False + ) # Fields are sorted by ascending low bit for field in node.fields(): if not field.is_sw_readable: continue # insert zero assignment before this field if needed - if field.low >= accesswidth*(subword_idx+1): + if field.low >= accesswidth * (subword_idx + 1): # field does not start in this subword if current_bit > accesswidth * subword_idx: # current subword had content. Assign remainder low = current_bit % accesswidth high = bus_width - 1 - self.add_content(f"assign readback_array[{self.current_offset_str}][{high}:{low}] = '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{high}:{low}] = '0;" + ) self.current_offset += 1 # Advance to subword that contains the start of the field @@ -283,17 +328,20 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): # assign zero up to start of this field low = current_bit % accesswidth high = (field.low % accesswidth) - 1 - self.add_content(f"assign readback_array[{self.current_offset_str}][{high}:{low}] = '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{high}:{low}] = '0;" + ) current_bit = field.low - # Assign field # loop until the entire field's assignments have been generated field_pos = field.low while current_bit <= field.high: # Assign the field rd_strb = f"({access_strb}[{subword_idx}] && !decoded_req_is_wr)" - if (field_pos == field.low) and (field.high < accesswidth*(subword_idx+1)): + if (field_pos == field.low) and ( + field.high < accesswidth * (subword_idx + 1) + ): # entire field fits into this subword low = field.low - accesswidth * subword_idx high = field.high - accesswidth * subword_idx @@ -303,15 +351,17 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): # Field gets bitswapped since it is in [low:high] orientation value = do_bitswap(value) - self.add_content(f"assign readback_array[{self.current_offset_str}][{high}:{low}] = {rd_strb} ? {value} : '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{high}:{low}] = {rd_strb} ? {value} : '0;" + ) current_bit = field.high + 1 - if current_bit == accesswidth*(subword_idx+1): + if current_bit == accesswidth * (subword_idx + 1): # Field ends at the subword boundary subword_idx += 1 self.current_offset += 1 - elif field.high >= accesswidth*(subword_idx+1): + elif field.high >= accesswidth * (subword_idx + 1): # only a subset of the field can fit into this subword # high end gets truncated @@ -330,11 +380,19 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): f_high = field.width - 1 - f_high f_low, f_high = f_high, f_low - value = do_bitswap(do_slice(self.exp.dereferencer.get_value(field), f_high, f_low)) + value = do_bitswap( + do_slice( + self.exp.dereferencer.get_value(field), f_high, f_low + ) + ) else: - value = do_slice(self.exp.dereferencer.get_value(field), f_high, f_low) + value = do_slice( + self.exp.dereferencer.get_value(field), f_high, f_low + ) - self.add_content(f"assign readback_array[{self.current_offset_str}][{r_high}:{r_low}] = {rd_strb} ? {value} : '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{r_high}:{r_low}] = {rd_strb} ? {value} : '0;" + ) # advance to the next subword subword_idx += 1 @@ -360,14 +418,22 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): f_high = field.width - 1 - f_high f_low, f_high = f_high, f_low - value = do_bitswap(do_slice(self.exp.dereferencer.get_value(field), f_high, f_low)) + value = do_bitswap( + do_slice( + self.exp.dereferencer.get_value(field), f_high, f_low + ) + ) else: - value = do_slice(self.exp.dereferencer.get_value(field), f_high, f_low) + value = do_slice( + self.exp.dereferencer.get_value(field), f_high, f_low + ) - self.add_content(f"assign readback_array[{self.current_offset_str}][{r_high}:{r_low}] = {rd_strb} ? {value} : '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{r_high}:{r_low}] = {rd_strb} ? {value} : '0;" + ) current_bit = field.high + 1 - if current_bit == accesswidth*(subword_idx+1): + if current_bit == accesswidth * (subword_idx + 1): # Field ends at the subword boundary subword_idx += 1 self.current_offset += 1 @@ -377,5 +443,7 @@ class ReadbackAssignmentGenerator(RDLForLoopGenerator): # current subword had content. Assign remainder low = current_bit % accesswidth high = bus_width - 1 - self.add_content(f"assign readback_array[{self.current_offset_str}][{high}:{low}] = '0;") + self.add_content( + f"assign readback_array[{self.current_offset_str}][{high}:{low}] = '0;" + ) self.current_offset += 1 diff --git a/src/peakrdl_regblock/scan_design.py b/src/peakrdl_regblock/scan_design.py index c3bea91..785b34f 100644 --- a/src/peakrdl_regblock/scan_design.py +++ b/src/peakrdl_regblock/scan_design.py @@ -15,12 +15,13 @@ class DesignScanner(RDLListener): Also collects any information that is required prior to the start of the export process. """ - def __init__(self, ds:'DesignState') -> None: + + def __init__(self, ds: "DesignState") -> None: self.ds = ds self.msg = self.top_node.env.msg @property - def top_node(self) -> 'AddrmapNode': + def top_node(self) -> "AddrmapNode": return self.ds.top_node def _get_out_of_hier_field_reset(self) -> None: @@ -28,7 +29,7 @@ class DesignScanner(RDLListener): current_node = self.top_node.parent while current_node is not None: for signal in current_node.signals(): - if signal.get_property('field_reset'): + if signal.get_property("field_reset"): path = signal.get_path() self.ds.out_of_hier_signals[path] = signal return @@ -50,19 +51,19 @@ class DesignScanner(RDLListener): # Ensure addrmap is not a bridge. This concept does not make sense for # terminal components. - if self.top_node.get_property('bridge'): + if self.top_node.get_property("bridge"): self.msg.error( - "Regblock generator does not support exporting bridge address maps", - self.top_node.inst.property_src_ref.get('bridge', self.top_node.inst.inst_src_ref) + "BusDecoder generator does not support exporting bridge address maps", + self.top_node.inst.property_src_ref.get( + "bridge", self.top_node.inst.inst_src_ref + ), ) RDLWalker().walk(self.top_node, self) if self.msg.had_error: - self.msg.fatal( - "Unable to export due to previous errors" - ) + self.msg.fatal("Unable to export due to previous errors") - def enter_Component(self, node: 'Node') -> Optional[WalkerAction]: + def enter_Component(self, node: "Node") -> Optional[WalkerAction]: if node.external and (node != self.top_node): # Do not inspect external components. None of my business return WalkerAction.SkipDescendants @@ -84,36 +85,42 @@ class DesignScanner(RDLListener): return WalkerAction.Continue - def enter_AddressableComponent(self, node: 'AddressableNode') -> None: + def enter_AddressableComponent(self, node: "AddressableNode") -> None: if node.external and node != self.top_node: self.ds.has_external_addressable = True if not isinstance(node, RegNode): self.ds.has_external_block = True - def enter_Reg(self, node: 'RegNode') -> None: + def enter_Reg(self, node: "RegNode") -> None: # The CPUIF's bus width is sized according to the largest accesswidth in the design - accesswidth = node.get_property('accesswidth') + accesswidth = node.get_property("accesswidth") self.ds.cpuif_data_width = max(self.ds.cpuif_data_width, accesswidth) - self.ds.has_buffered_write_regs = self.ds.has_buffered_write_regs or bool(node.get_property('buffer_writes')) - self.ds.has_buffered_read_regs = self.ds.has_buffered_read_regs or bool(node.get_property('buffer_reads')) + self.ds.has_buffered_write_regs = self.ds.has_buffered_write_regs or bool( + node.get_property("buffer_writes") + ) + self.ds.has_buffered_read_regs = self.ds.has_buffered_read_regs or bool( + node.get_property("buffer_reads") + ) - def enter_Signal(self, node: 'SignalNode') -> None: - if node.get_property('field_reset'): + def enter_Signal(self, node: "SignalNode") -> None: + if node.get_property("field_reset"): path = node.get_path() self.ds.in_hier_signal_paths.add(path) - def enter_Field(self, node: 'FieldNode') -> None: + def enter_Field(self, node: "FieldNode") -> None: if node.is_sw_writable and (node.msb < node.lsb): self.ds.has_writable_msb0_fields = True - if node.get_property('paritycheck') and node.implements_storage: + if node.get_property("paritycheck") and node.implements_storage: self.ds.has_paritycheck = True - if node.get_property('reset') is None: + if node.get_property("reset") is None: self.msg.warning( f"Field '{node.inst_name}' includes parity check logic, but " "its reset value was not defined. Will result in an undefined " "value on the module's 'parity_error' output.", - self.top_node.inst.property_src_ref.get('paritycheck', self.top_node.inst.inst_src_ref) + self.top_node.inst.property_src_ref.get( + "paritycheck", self.top_node.inst.inst_src_ref + ), ) diff --git a/src/peakrdl_regblock/validate_design.py b/src/peakrdl_regblock/validate_design.py index 7b8e9f8..2f4e432 100644 --- a/src/peakrdl_regblock/validate_design.py +++ b/src/peakrdl_regblock/validate_design.py @@ -10,33 +10,33 @@ from .utils import roundup_pow2, is_pow2 from .utils import ref_is_internal if TYPE_CHECKING: - from .exporter import RegblockExporter + from .exporter import BusDecoderExporter + class DesignValidator(RDLListener): """ Performs additional rule-checks on the design that check for limitations imposed by this exporter. """ - def __init__(self, exp:'RegblockExporter') -> None: + + def __init__(self, exp: "BusDecoderExporter") -> None: self.exp = exp self.ds = exp.ds self.msg = self.top_node.env.msg - self._contains_external_block_stack = [] # type: List[bool] + self._contains_external_block_stack = [] # type: List[bool] self.contains_external_block = False @property - def top_node(self) -> 'AddrmapNode': + def top_node(self) -> "AddrmapNode": return self.exp.ds.top_node def do_validate(self) -> None: RDLWalker().walk(self.top_node, self) if self.msg.had_error: - self.msg.fatal( - "Unable to export due to previous errors" - ) + self.msg.fatal("Unable to export due to previous errors") - def enter_Component(self, node: 'Node') -> Optional[WalkerAction]: + def enter_Component(self, node: "Node") -> Optional[WalkerAction]: if node.external and (node != self.top_node): # Do not inspect external components. None of my business return WalkerAction.SkipDescendants @@ -49,39 +49,41 @@ class DesignValidator(RDLListener): if isinstance(value, PropertyReference): src_ref = value.src_ref else: - src_ref = node.inst.property_src_ref.get(prop_name, node.inst.inst_src_ref) + src_ref = node.inst.property_src_ref.get( + prop_name, node.inst.inst_src_ref + ) self.msg.error( - "Property is assigned a reference that points to a component not internal to the regblock being exported.", - src_ref + "Property is assigned a reference that points to a component not internal to the busdecoder being exported.", + src_ref, ) return None - def enter_Signal(self, node: 'SignalNode') -> None: + def enter_Signal(self, node: "SignalNode") -> None: # If encountering a CPUIF reset that is nested within the register model, # warn that it will be ignored. # Only cpuif resets in the top-level node or above will be honored - if node.get_property('cpuif_reset') and (node.parent != self.top_node): + if node.get_property("cpuif_reset") and (node.parent != self.top_node): self.msg.warning( "Only cpuif_reset signals that are instantiated in the top-level " "addrmap or above will be honored. Any cpuif_reset signals nested " "within children of the addrmap being exported will be ignored.", - node.inst.inst_src_ref + node.inst.inst_src_ref, ) - def enter_AddressableComponent(self, node: 'AddressableNode') -> None: + def enter_AddressableComponent(self, node: "AddressableNode") -> None: # All registers must be aligned to the internal data bus width alignment = self.exp.cpuif.data_width_bytes if (node.raw_address_offset % alignment) != 0: self.msg.error( "Unaligned registers are not supported. Address offset of " f"instance '{node.inst_name}' must be a multiple of {alignment}", - node.inst.inst_src_ref + node.inst.inst_src_ref, ) - if node.is_array and (node.array_stride % alignment) != 0: # type: ignore # is_array implies stride is not none + if node.is_array and (node.array_stride % alignment) != 0: # type: ignore # is_array implies stride is not none self.msg.error( "Unaligned registers are not supported. Address stride of " f"instance array '{node.inst_name}' must be a multiple of {alignment}", - node.inst.inst_src_ref + node.inst.inst_src_ref, ) if not isinstance(node, RegNode): @@ -99,49 +101,49 @@ class DesignValidator(RDLListener): self._check_sharedextbus(node) def _check_sharedextbus(self, node: Union[RegfileNode, AddrmapNode]) -> None: - if node.get_property('sharedextbus'): + if node.get_property("sharedextbus"): self.msg.error( "This exporter does not support enabling the 'sharedextbus' property yet.", - node.inst.property_src_ref.get('sharedextbus', node.inst.inst_src_ref) + node.inst.property_src_ref.get("sharedextbus", node.inst.inst_src_ref), ) - def enter_Reg(self, node: 'RegNode') -> None: + def enter_Reg(self, node: "RegNode") -> None: # accesswidth of wide registers must be consistent within the register block - accesswidth = node.get_property('accesswidth') - regwidth = node.get_property('regwidth') + accesswidth = node.get_property("accesswidth") + regwidth = node.get_property("regwidth") if accesswidth < regwidth: # register is 'wide' if accesswidth != self.exp.cpuif.data_width: self.msg.error( f"Multi-word registers that have an accesswidth ({accesswidth}) " - "that are inconsistent with this regblock's CPU bus width " + "that are inconsistent with this busdecoder's CPU bus width " f"({self.exp.cpuif.data_width}) are not supported.", - node.inst.inst_src_ref + node.inst.inst_src_ref, ) - - def enter_Field(self, node: 'FieldNode') -> None: - parent_accesswidth = node.parent.get_property('accesswidth') - parent_regwidth = node.parent.get_property('regwidth') - if ( - (parent_accesswidth < parent_regwidth) - and (node.lsb // parent_accesswidth) != (node.msb // parent_accesswidth) - ): + def enter_Field(self, node: "FieldNode") -> None: + parent_accesswidth = node.parent.get_property("accesswidth") + parent_regwidth = node.parent.get_property("regwidth") + if (parent_accesswidth < parent_regwidth) and ( + node.lsb // parent_accesswidth + ) != (node.msb // parent_accesswidth): # field spans multiple sub-words - if node.is_sw_writable and not node.parent.get_property('buffer_writes'): + if node.is_sw_writable and not node.parent.get_property("buffer_writes"): # ... and is writable without the protection of double-buffering # Enforce 10.6.1-f self.msg.error( f"Software-writable field '{node.inst_name}' shall not span" " multiple software-accessible subwords. Consider enabling" " write double-buffering.\n" - "For more details, see: https://peakrdl-regblock.readthedocs.io/en/latest/udps/write_buffering.html", - node.inst.inst_src_ref + "For more details, see: https://peakrdl-busdecoder.readthedocs.io/en/latest/udps/write_buffering.html", + node.inst.inst_src_ref, ) - if node.get_property('onread') is not None and not node.parent.get_property('buffer_reads'): + if node.get_property("onread") is not None and not node.parent.get_property( + "buffer_reads" + ): # ... is modified by an onread action without the atomicity of read buffering # Enforce 10.6.1-f self.msg.error( @@ -149,8 +151,8 @@ class DesignValidator(RDLListener): " subwords and is modified on-read, making it impossible to" " access its value correctly. Consider enabling read" " double-buffering. \n" - "For more details, see: https://peakrdl-regblock.readthedocs.io/en/latest/udps/read_buffering.html", - node.inst.inst_src_ref + "For more details, see: https://peakrdl-busdecoder.readthedocs.io/en/latest/udps/read_buffering.html", + node.inst.inst_src_ref, ) # Check for unsynthesizable reset @@ -166,10 +168,9 @@ class DesignValidator(RDLListener): if is_async_reset: self.msg.error( "A field that uses an asynchronous reset cannot use a dynamic reset value. This is not synthesizable.", - node.inst.inst_src_ref + node.inst.inst_src_ref, ) - def exit_AddressableComponent(self, node: AddressableNode) -> None: if not isinstance(node, RegNode): # Exiting block-like node @@ -194,14 +195,14 @@ class DesignValidator(RDLListener): if (node.raw_address_offset % req_align) != 0: self.msg.error( f"Address offset +0x{node.raw_address_offset:x} of instance '{node.inst_name}' is not a power of 2 multiple of its size 0x{node.size:x}. " - f"This is required by the regblock exporter if a component {err_suffix}.", - node.inst.inst_src_ref + f"This is required by the busdecoder exporter if a component {err_suffix}.", + node.inst.inst_src_ref, ) if node.is_array: assert node.array_stride is not None if not is_pow2(node.array_stride): self.msg.error( f"Address stride of instance array '{node.inst_name}' is not a power of 2" - f"This is required by the regblock exporter if a component {err_suffix}.", - node.inst.inst_src_ref + f"This is required by the busdecoder exporter if a component {err_suffix}.", + node.inst.inst_src_ref, ) diff --git a/src/peakrdl_regblock/write_buffering/__init__.py b/src/peakrdl_regblock/write_buffering/__init__.py index a03ddcb..934b5e6 100644 --- a/src/peakrdl_regblock/write_buffering/__init__.py +++ b/src/peakrdl_regblock/write_buffering/__init__.py @@ -8,25 +8,23 @@ from ..utils import get_indexed_path from ..sv_int import SVInt if TYPE_CHECKING: - from ..exporter import RegblockExporter + from ..exporter import BusDecoderExporter class WriteBuffering: - def __init__(self, exp:'RegblockExporter'): + def __init__(self, exp: "BusDecoderExporter"): self.exp = exp @property - def top_node(self) -> 'AddrmapNode': + def top_node(self) -> "AddrmapNode": return self.exp.ds.top_node - def get_storage_struct(self) -> str: struct_gen = WBufStorageStructGenerator(self) s = struct_gen.get_struct(self.top_node, "wbuf_storage_t") assert s is not None return s + "\nwbuf_storage_t wbuf_storage;" - def get_implementation(self) -> str: gen = WBufLogicGenerator(self) s = gen.get_content(self.top_node) @@ -43,24 +41,26 @@ class WriteBuffering: prefix = self.get_wbuf_prefix(node) return f"{prefix}.pending && {self.get_trigger(node)}" - def get_raw_trigger(self, node: 'RegNode') -> Union[SVInt, str]: - trigger = node.get_property('wbuffer_trigger') + def get_raw_trigger(self, node: "RegNode") -> Union[SVInt, str]: + trigger = node.get_property("wbuffer_trigger") if isinstance(trigger, RegNode): # Trigger is a register. # trigger when uppermost address of the register is written - regwidth = trigger.get_property('regwidth') - accesswidth = trigger.get_property('accesswidth') - strb_prefix = self.exp.dereferencer.get_access_strobe(trigger, reduce_substrobes=False) + regwidth = trigger.get_property("regwidth") + accesswidth = trigger.get_property("accesswidth") + strb_prefix = self.exp.dereferencer.get_access_strobe( + trigger, reduce_substrobes=False + ) if accesswidth < regwidth: n_subwords = regwidth // accesswidth - return f"{strb_prefix}[{n_subwords-1}] && decoded_req_is_wr" + return f"{strb_prefix}[{n_subwords - 1}] && decoded_req_is_wr" else: return f"{strb_prefix} && decoded_req_is_wr" elif isinstance(trigger, SignalNode): s = self.exp.dereferencer.get_value(trigger) - if trigger.get_property('activehigh'): + if trigger.get_property("activehigh"): return s else: return f"~{s}" @@ -71,7 +71,7 @@ class WriteBuffering: def get_trigger(self, node: Union[RegNode, FieldNode]) -> Union[SVInt, str]: if isinstance(node, FieldNode): node = node.parent - trigger = node.get_property('wbuffer_trigger') + trigger = node.get_property("wbuffer_trigger") if isinstance(trigger, RegNode) and trigger == node: # register is its own trigger diff --git a/tests/.coveragerc b/tests/.coveragerc index 05e3012..91631bc 100644 --- a/tests/.coveragerc +++ b/tests/.coveragerc @@ -8,9 +8,9 @@ omit = [paths] source = - ../src/peakrdl_regblock/ - */site-packages/*/peakrdl_regblock - */site-packages/peakrdl_regblock + ../src/peakrdl_busdecoder/ + */site-packages/*/peakrdl_busdecoder + */site-packages/peakrdl_busdecoder [report] exclude_lines = diff --git a/tests/README.md b/tests/README.md index bb3996c..95311f5 100644 --- a/tests/README.md +++ b/tests/README.md @@ -104,8 +104,8 @@ Each testcase group has its own folder and contains the following: `test_*/__init__.py` : Empty file required for test discovery. -`test_*/regblock.rdl` -: Testcase RDL file. Testcase infrastructure will automatically compile this and generate the regblock output SystemVerilog. +`test_*/busdecoder.rdl` +: Testcase RDL file. Testcase infrastructure will automatically compile this and generate the busdecoder output SystemVerilog. `test_*/tb_template.sv` : Jinja template that defines the testcase-specific sequence. @@ -116,4 +116,4 @@ Each testcase group has its own folder and contains the following: ## Parameterization -Testcase classes can be parameterized using the [parameterized](https://github.com/wolever/parameterized) extension. This allows the same testcase to be run against multiple permutations of regblock export modes such as CPU interfaces, retiming flop stages, or even RDL parameterizations. +Testcase classes can be parameterized using the [parameterized](https://github.com/wolever/parameterized) extension. This allows the same testcase to be run against multiple permutations of busdecoder export modes such as CPU interfaces, retiming flop stages, or even RDL parameterizations. diff --git a/tests/conftest.py b/tests/conftest.py index 13dcb5d..4f77678 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,7 +9,7 @@ def pytest_addoption(parser): stub: run the testcase using a no-op simulator stub skip: skip all the simulation tests auto: choose the best simulator based on what is installed - """ + """, ) parser.addoption( @@ -20,19 +20,18 @@ def pytest_addoption(parser): Launch sim tool in GUI mode Only use this option when running a single test - """ + """, ) - parser.addoption( "--rerun", default=False, action="store_true", help=""", - Re-run simulation in-place without re-exporting regblock + Re-run simulation in-place without re-exporting busdecoder Useful if hand-editing a testcase interactively. - """ + """, ) parser.addoption( @@ -44,5 +43,5 @@ def pytest_addoption(parser): skip: skip all the simulation tests auto: choose the best tool based on what is installed - """ + """, ) diff --git a/tests/lib/base_testcase.py b/tests/lib/base_testcase.py index 6c9d4b8..eb99916 100644 --- a/tests/lib/base_testcase.py +++ b/tests/lib/base_testcase.py @@ -9,8 +9,8 @@ import pathlib import pytest from systemrdl import RDLCompiler -from peakrdl_regblock import RegblockExporter -from peakrdl_regblock.udps import ALL_UDPS +from peakrdl_busdecoder import BusDecoderExporter +from peakrdl_busdecoder.udps import ALL_UDPS from .cpuifs.base import CpuifTestMode from .cpuifs.apb4 import APB4 @@ -20,17 +20,17 @@ class BaseTestCase(unittest.TestCase): #: Path to the testcase's RDL file. #: Relative to the testcase's dir. If unset, the first RDL file found in the #: testcase dir will be used - rdl_file = None # type: Optional[str] + rdl_file = None # type: Optional[str] #: RDL type name to elaborate. If unset, compiler will automatically choose #: the top. - rdl_elab_target = None # type: Optional[str] + rdl_elab_target = None # type: Optional[str] #: Parameters to pass into RDL elaboration rdl_elab_params = {} #: Define what CPUIF to use for this testcase - cpuif = APB4() # type: CpuifTestMode + cpuif = APB4() # type: CpuifTestMode # Other exporter args: retime_read_fanin = False @@ -41,9 +41,9 @@ class BaseTestCase(unittest.TestCase): default_reset_async = False #: this gets auto-loaded via the _load_request autouse fixture - request = None # type: pytest.FixtureRequest + request = None # type: pytest.FixtureRequest - exporter = RegblockExporter() + exporter = BusDecoderExporter() @pytest.fixture(autouse=True) def _load_request(self, request): @@ -72,16 +72,15 @@ class BaseTestCase(unittest.TestCase): """ path = os.path.join(self.get_run_dir(), "params.txt") - with open(path, 'w') as f: + with open(path, "w") as f: for k, v in self.__class__.__dict__.items(): if k.startswith("_") or callable(v): continue f.write(f"{k}: {repr(v)}\n") - - def export_regblock(self): + def export_busdecoder(self): """ - Call the peakrdl_regblock exporter to generate the DUT + Call the peakrdl_busdecoder exporter to generate the DUT """ this_dir = self.get_testcase_dir() @@ -97,17 +96,17 @@ class BaseTestCase(unittest.TestCase): for udp in ALL_UDPS: rdlc.register_udp(udp) # ... including the definition - udp_file = os.path.join(this_dir, "../../hdl-src/regblock_udps.rdl") + udp_file = os.path.join(this_dir, "../../hdl-src/busdecoder_udps.rdl") rdlc.compile_file(udp_file) rdlc.compile_file(rdl_file) - root = rdlc.elaborate(self.rdl_elab_target, "regblock", self.rdl_elab_params) + root = rdlc.elaborate(self.rdl_elab_target, "busdecoder", self.rdl_elab_params) self.exporter.export( root, self.get_run_dir(), - module_name="regblock", - package_name="regblock_pkg", + module_name="busdecoder", + package_name="busdecoder_pkg", cpuif_cls=self.cpuif.cpuif_cls, retime_read_fanin=self.retime_read_fanin, retime_read_response=self.retime_read_response, @@ -137,4 +136,4 @@ class BaseTestCase(unittest.TestCase): self._write_params() # Convert testcase RDL file --> SV - self.export_regblock() + self.export_busdecoder() diff --git a/tests/lib/cpuifs/apb3/__init__.py b/tests/lib/cpuifs/apb3/__init__.py index fffb098..f52a820 100644 --- a/tests/lib/cpuifs/apb3/__init__.py +++ b/tests/lib/cpuifs/apb3/__init__.py @@ -1,6 +1,7 @@ from ..base import CpuifTestMode -from peakrdl_regblock.cpuif.apb3 import APB3_Cpuif, APB3_Cpuif_flattened +from peakrdl_busdecoder.cpuif.apb3 import APB3_Cpuif, APB3_Cpuif_flattened + class APB3(CpuifTestMode): cpuif_cls = APB3_Cpuif @@ -13,6 +14,7 @@ class APB3(CpuifTestMode): ] tb_template = "tb_inst.sv" + class FlatAPB3(APB3): cpuif_cls = APB3_Cpuif_flattened rtl_files = [] diff --git a/tests/lib/cpuifs/apb4/__init__.py b/tests/lib/cpuifs/apb4/__init__.py index 4a93b67..09857a2 100644 --- a/tests/lib/cpuifs/apb4/__init__.py +++ b/tests/lib/cpuifs/apb4/__init__.py @@ -1,6 +1,7 @@ from ..base import CpuifTestMode -from peakrdl_regblock.cpuif.apb4 import APB4_Cpuif, APB4_Cpuif_flattened +from peakrdl_busdecoder.cpuif.apb4 import APB4_Cpuif, APB4_Cpuif_flattened + class APB4(CpuifTestMode): cpuif_cls = APB4_Cpuif @@ -13,6 +14,7 @@ class APB4(CpuifTestMode): ] tb_template = "tb_inst.sv" + class FlatAPB4(APB4): cpuif_cls = APB4_Cpuif_flattened rtl_files = [] diff --git a/tests/lib/cpuifs/avalon/__init__.py b/tests/lib/cpuifs/avalon/__init__.py index 79672ab..00d7743 100644 --- a/tests/lib/cpuifs/avalon/__init__.py +++ b/tests/lib/cpuifs/avalon/__init__.py @@ -1,6 +1,7 @@ from ..base import CpuifTestMode -from peakrdl_regblock.cpuif.avalon import Avalon_Cpuif, Avalon_Cpuif_flattened +from peakrdl_busdecoder.cpuif.avalon import Avalon_Cpuif, Avalon_Cpuif_flattened + class Avalon(CpuifTestMode): cpuif_cls = Avalon_Cpuif @@ -13,6 +14,7 @@ class Avalon(CpuifTestMode): ] tb_template = "tb_inst.sv" + class FlatAvalon(Avalon): cpuif_cls = Avalon_Cpuif_flattened rtl_files = [] diff --git a/tests/lib/cpuifs/axi4lite/__init__.py b/tests/lib/cpuifs/axi4lite/__init__.py index ef3147c..5d774d1 100644 --- a/tests/lib/cpuifs/axi4lite/__init__.py +++ b/tests/lib/cpuifs/axi4lite/__init__.py @@ -1,6 +1,7 @@ from ..base import CpuifTestMode -from peakrdl_regblock.cpuif.axi4lite import AXI4Lite_Cpuif, AXI4Lite_Cpuif_flattened +from peakrdl_busdecoder.cpuif.axi4lite import AXI4Lite_Cpuif, AXI4Lite_Cpuif_flattened + class AXI4Lite(CpuifTestMode): cpuif_cls = AXI4Lite_Cpuif @@ -13,6 +14,7 @@ class AXI4Lite(CpuifTestMode): ] tb_template = "tb_inst.sv" + class FlatAXI4Lite(AXI4Lite): cpuif_cls = AXI4Lite_Cpuif_flattened rtl_files = [] diff --git a/tests/lib/cpuifs/base.py b/tests/lib/cpuifs/base.py index c53358f..8dac707 100644 --- a/tests/lib/cpuifs/base.py +++ b/tests/lib/cpuifs/base.py @@ -4,16 +4,17 @@ import inspect import jinja2 as jj -from peakrdl_regblock.cpuif.base import CpuifBase +from peakrdl_busdecoder.cpuif.base import CpuifBase from ..sv_line_anchor import SVLineAnchor if TYPE_CHECKING: - from peakrdl_regblock import RegblockExporter + from peakrdl_busdecoder import BusDecoderExporter from ..sim_testcase import SimTestCase + class CpuifTestMode: - cpuif_cls = None # type: CpuifBase + cpuif_cls = None # type: CpuifBase # Files required by the DUT # Paths are relative to the class that assigns this @@ -21,13 +22,12 @@ class CpuifTestMode: # Files required by the sim testbench # Paths are relative to the class that assigns this - tb_files = [] # type: List[str] + tb_files = [] # type: List[str] # Path is relative to the class that assigns this tb_template = "" - - def _get_class_dir_of_variable(self, varname:str) -> str: + def _get_class_dir_of_variable(self, varname: str) -> str: """ Traverse up the MRO and find the first class that explicitly assigns the variable of name varname. Returns the directory that contains the @@ -39,34 +39,29 @@ class CpuifTestMode: return class_dir raise RuntimeError - - def _get_file_paths(self, varname:str) -> List[str]: + def _get_file_paths(self, varname: str) -> List[str]: class_dir = self._get_class_dir_of_variable(varname) files = getattr(self, varname) cwd = os.getcwd() new_files = [] for file in files: - relpath = os.path.relpath( - os.path.join(class_dir, file), - cwd - ) + relpath = os.path.relpath(os.path.join(class_dir, file), cwd) new_files.append(relpath) return new_files - def get_sim_files(self) -> List[str]: files = self._get_file_paths("rtl_files") + self._get_file_paths("tb_files") unique_files = [] [unique_files.append(f) for f in files if f not in unique_files] return unique_files - def get_synth_files(self) -> List[str]: return self._get_file_paths("rtl_files") - - def get_tb_inst(self, testcase: 'SimTestCase', exporter: 'RegblockExporter') -> str: + def get_tb_inst( + self, testcase: "SimTestCase", exporter: "BusDecoderExporter" + ) -> str: class_dir = self._get_class_dir_of_variable("tb_template") loader = jj.FileSystemLoader(class_dir) jj_env = jj.Environment( diff --git a/tests/lib/cpuifs/passthrough/__init__.py b/tests/lib/cpuifs/passthrough/__init__.py index 04ee62f..5688e52 100644 --- a/tests/lib/cpuifs/passthrough/__init__.py +++ b/tests/lib/cpuifs/passthrough/__init__.py @@ -1,6 +1,7 @@ from ..base import CpuifTestMode -from peakrdl_regblock.cpuif.passthrough import PassthroughCpuif +from peakrdl_busdecoder.cpuif.passthrough import PassthroughCpuif + class Passthrough(CpuifTestMode): cpuif_cls = PassthroughCpuif diff --git a/tests/lib/simulators/base.py b/tests/lib/simulators/base.py index 115f6d5..7906358 100644 --- a/tests/lib/simulators/base.py +++ b/tests/lib/simulators/base.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING, List if TYPE_CHECKING: from ..sim_testcase import SimTestCase + class Simulator: name = "" @@ -10,7 +11,7 @@ class Simulator: def is_installed(cls) -> bool: raise NotImplementedError - def __init__(self, testcase: 'SimTestCase' = None) -> None: + def __init__(self, testcase: "SimTestCase" = None) -> None: self.testcase = testcase @property @@ -22,8 +23,8 @@ class Simulator: files = [] files.extend(self.testcase.cpuif.get_sim_files()) files.extend(self.testcase.get_extra_tb_files()) - files.append("regblock_pkg.sv") - files.append("regblock.sv") + files.append("busdecoder_pkg.sv") + files.append("busdecoder.sv") files.append("tb.sv") return files @@ -31,5 +32,5 @@ class Simulator: def compile(self) -> None: raise NotImplementedError - def run(self, plusargs:List[str] = None) -> None: + def run(self, plusargs: List[str] = None) -> None: raise NotImplementedError diff --git a/tests/lib/synth_testcase.py b/tests/lib/synth_testcase.py index 552902d..6472319 100644 --- a/tests/lib/synth_testcase.py +++ b/tests/lib/synth_testcase.py @@ -6,13 +6,13 @@ import pytest from .base_testcase import BaseTestCase from .synthesizers import get_synthesizer_cls -class SynthTestCase(BaseTestCase): +class SynthTestCase(BaseTestCase): def _get_synth_files(self) -> List[str]: files = [] files.extend(self.cpuif.get_synth_files()) - files.append("regblock_pkg.sv") - files.append("regblock.sv") + files.append("busdecoder_pkg.sv") + files.append("busdecoder.sv") return files diff --git a/tests/lib/synthesizers/vivado_scripts/run.tcl b/tests/lib/synthesizers/vivado_scripts/run.tcl index db793b7..5d401cf 100644 --- a/tests/lib/synthesizers/vivado_scripts/run.tcl +++ b/tests/lib/synthesizers/vivado_scripts/run.tcl @@ -25,7 +25,7 @@ set_msg_config -severity {CRITICAL WARNING} -new_severity "ERROR" set_part [lindex [get_parts] 0] read_verilog -sv $files read_xdc $this_dir/constr.xdc -synth_design -top regblock -mode out_of_context +synth_design -top busdecoder -mode out_of_context #write_checkpoint -force synth.dcp diff --git a/tests/lib/tb_base.sv b/tests/lib/tb_base.sv index a6c93d6..a064311 100644 --- a/tests/lib/tb_base.sv +++ b/tests/lib/tb_base.sv @@ -28,11 +28,11 @@ module tb; // DUT Signal declarations //-------------------------------------------------------------------------- {%- if exporter.hwif.has_input_struct %} - regblock_pkg::regblock__in_t hwif_in; + busdecoder_pkg::busdecoder__in_t hwif_in; {%- endif %} {%- if exporter.hwif.has_output_struct %} - regblock_pkg::regblock__out_t hwif_out; + busdecoder_pkg::busdecoder__out_t hwif_out; {%- endif %} {%- if exporter.ds.has_paritycheck %} @@ -76,7 +76,7 @@ module tb; // DUT //-------------------------------------------------------------------------- {% sv_line_anchor %} - regblock dut (.*); + busdecoder dut (.*); {%- if exporter.hwif.has_output_struct %} {% sv_line_anchor %} diff --git a/tests/run.sh b/tests/run.sh index b8106f7..b28ec2b 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -16,13 +16,13 @@ pip install -r requirements.txt pip install -e "../[cli]" # Run lint -pylint --rcfile pylint.rc ../src/peakrdl_regblock +pylint --rcfile pylint.rc ../src/peakrdl_busdecoder # Run static type checking -mypy ../src/peakrdl_regblock +mypy ../src/peakrdl_busdecoder # Run unit tests -pytest --workers auto --cov=peakrdl_regblock --synth-tool skip +pytest --workers auto --cov=peakrdl_busdecoder --synth-tool skip # Generate coverage report coverage html -i -d htmlcov diff --git a/tests/test_enum/tb_template.sv b/tests/test_enum/tb_template.sv index 457bd2b..be7209a 100644 --- a/tests/test_enum/tb_template.sv +++ b/tests/test_enum/tb_template.sv @@ -7,16 +7,16 @@ ##1; // check enum values - assert(regblock_pkg::top__my_enum__val_1 == 'd3); - assert(regblock_pkg::top__my_enum__val_2 == 'd4); + assert(busdecoder_pkg::top__my_enum__val_1 == 'd3); + assert(busdecoder_pkg::top__my_enum__val_2 == 'd4); // check initial conditions - cpuif.assert_read('h0, regblock_pkg::top__my_enum__val_2); + cpuif.assert_read('h0, busdecoder_pkg::top__my_enum__val_2); //--------------------------------- // set r0 = val_1 - cpuif.write('h0, regblock_pkg::top__my_enum__val_1); + cpuif.write('h0, busdecoder_pkg::top__my_enum__val_1); - cpuif.assert_read('h0, regblock_pkg::top__my_enum__val_1); + cpuif.assert_read('h0, busdecoder_pkg::top__my_enum__val_1); {% endblock %} diff --git a/tests/test_external/tb_template.sv b/tests/test_external/tb_template.sv index f5a047e..ae286ee 100644 --- a/tests/test_external/tb_template.sv +++ b/tests/test_external/tb_template.sv @@ -296,8 +296,8 @@ // Check register struct bit-order repeat(32) begin - regblock_pkg::top__my_reg_alt__external__fields__in_t fields_in; - regblock_pkg::top__my_reg_alt__external__fields__out_t fields_out; + busdecoder_pkg::top__my_reg_alt__external__fields__in_t fields_in; + busdecoder_pkg::top__my_reg_alt__external__fields__out_t fields_out; fields_in = $urandom(); fields_out = $urandom(); diff --git a/tests/test_map_size/tb_template.sv b/tests/test_map_size/tb_template.sv index d86780a..d84237b 100644 --- a/tests/test_map_size/tb_template.sv +++ b/tests/test_map_size/tb_template.sv @@ -7,6 +7,6 @@ ##1; // check block size - assert(regblock_pkg::REGBLOCK_SIZE == {{exporter.ds.top_node.size}}); + assert(busdecoder_pkg::REGBLOCK_SIZE == {{exporter.ds.top_node.size}}); {% endblock %} diff --git a/tests/test_pipelined_cpuif/regblock.rdl b/tests/test_pipelined_cpuif/regblock.rdl index a208e43..c9e4d3b 100644 --- a/tests/test_pipelined_cpuif/regblock.rdl +++ b/tests/test_pipelined_cpuif/regblock.rdl @@ -1,4 +1,4 @@ -addrmap regblock { +addrmap busdecoder { default sw=rw; default hw=r; diff --git a/tests/test_pkg_params/tb_template.sv b/tests/test_pkg_params/tb_template.sv index b33b3d2..17b97ff 100644 --- a/tests/test_pkg_params/tb_template.sv +++ b/tests/test_pkg_params/tb_template.sv @@ -2,7 +2,7 @@ {% block seq %} {% sv_line_anchor %} - assert(regblock_pkg::N_REGS == {{testcase.n_regs}}); - assert(regblock_pkg::REGWIDTH == {{testcase.regwidth}}); - assert(regblock_pkg::NAME == "{{testcase.name}}"); + assert(busdecoder_pkg::N_REGS == {{testcase.n_regs}}); + assert(busdecoder_pkg::REGWIDTH == {{testcase.regwidth}}); + assert(busdecoder_pkg::NAME == "{{testcase.name}}"); {% endblock %} diff --git a/tests/test_structural_sw_rw/regblock.rdl b/tests/test_structural_sw_rw/regblock.rdl index 30488d1..84770bb 100644 --- a/tests/test_structural_sw_rw/regblock.rdl +++ b/tests/test_structural_sw_rw/regblock.rdl @@ -1,4 +1,4 @@ -addrmap regblock { +addrmap busdecoder { default sw=rw; default hw=r; diff --git a/tests/test_user_cpuif/testcase.py b/tests/test_user_cpuif/testcase.py index 3e8465e..86b0cf9 100644 --- a/tests/test_user_cpuif/testcase.py +++ b/tests/test_user_cpuif/testcase.py @@ -1,17 +1,19 @@ import os -from peakrdl_regblock.cpuif.apb3 import APB3_Cpuif +from peakrdl_busdecoder.cpuif.apb3 import APB3_Cpuif from ..lib.cpuifs.apb3 import APB3 from ..lib.base_testcase import BaseTestCase -#------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------- + class ClassOverride_Cpuif(APB3_Cpuif): @property def port_declaration(self) -> str: return "user_apb3_intf.slave s_apb" + class ClassOverride_cpuiftestmode(APB3): cpuif_cls = ClassOverride_Cpuif @@ -20,19 +22,19 @@ class Test_class_override(BaseTestCase): cpuif = ClassOverride_cpuiftestmode() def test_override_success(self): - output_file = os.path.join(self.get_run_dir(), "regblock.sv") + output_file = os.path.join(self.get_run_dir(), "busdecoder.sv") with open(output_file, "r") as f: - self.assertIn( - "user_apb3_intf.slave s_apb", - f.read() - ) + self.assertIn("user_apb3_intf.slave s_apb", f.read()) + + +# ------------------------------------------------------------------------------- -#------------------------------------------------------------------------------- class TemplateOverride_Cpuif(APB3_Cpuif): # contains the text "USER TEMPLATE OVERRIDE" template_path = "user_apb3_tmpl.sv" + class TemplateOverride_cpuiftestmode(APB3): cpuif_cls = TemplateOverride_Cpuif @@ -41,9 +43,6 @@ class Test_template_override(BaseTestCase): cpuif = TemplateOverride_cpuiftestmode() def test_override_success(self): - output_file = os.path.join(self.get_run_dir(), "regblock.sv") + output_file = os.path.join(self.get_run_dir(), "busdecoder.sv") with open(output_file, "r") as f: - self.assertIn( - "USER TEMPLATE OVERRIDE", - f.read() - ) + self.assertIn("USER TEMPLATE OVERRIDE", f.read()) diff --git a/tests/test_validation_errors/testcase.py b/tests/test_validation_errors/testcase.py index 3267dac..b8ccfd0 100644 --- a/tests/test_validation_errors/testcase.py +++ b/tests/test_validation_errors/testcase.py @@ -5,6 +5,7 @@ from systemrdl.messages import RDLCompileError from ..lib.base_testcase import BaseTestCase + class TestValidationErrors(BaseTestCase): def setUp(self) -> None: # Stub usual pre-test setup @@ -19,11 +20,10 @@ class TestValidationErrors(BaseTestCase): f = io.StringIO() with contextlib.redirect_stderr(f): with self.assertRaises(RDLCompileError): - self.export_regblock() + self.export_busdecoder() stderr = f.getvalue() self.assertRegex(stderr, err_regex) - def test_unaligned_reg(self) -> None: self.assert_validate_error( "unaligned_reg.rdl", @@ -39,7 +39,7 @@ class TestValidationErrors(BaseTestCase): def test_bad_external_ref(self) -> None: self.assert_validate_error( "external_ref.rdl", - "Property is assigned a reference that points to a component not internal to the regblock being exported", + "Property is assigned a reference that points to a component not internal to the busdecoder being exported", ) def test_sharedextbus_not_supported(self) -> None: @@ -51,7 +51,7 @@ class TestValidationErrors(BaseTestCase): def test_inconsistent_accesswidth(self) -> None: self.assert_validate_error( "inconsistent_accesswidth.rdl", - r"Multi-word registers that have an accesswidth \(16\) that are inconsistent with this regblock's CPU bus width \(32\) are not supported", + r"Multi-word registers that have an accesswidth \(16\) that are inconsistent with this busdecoder's CPU bus width \(32\) are not supported", ) def test_unbuffered_wide_w_fields(self) -> None: @@ -117,5 +117,5 @@ class TestValidationErrors(BaseTestCase): def test_signed_enum(self) -> None: self.assert_validate_error( "signed_enum.rdl", - "The property is_signed=true is not supported for fields encoded as an enum." + "The property is_signed=true is not supported for fields encoded as an enum.", )