revamp docs

This commit is contained in:
Arnav Sacheti
2026-02-03 08:47:18 +00:00
parent bad845d15e
commit 244bd8d773
24 changed files with 178 additions and 1584 deletions

View File

@@ -15,10 +15,11 @@ implementation from SystemRDL source.
.. code-block:: python .. code-block:: python
:emphasize-lines: 2-4, 29-33 :emphasize-lines: 2-4, 29-33
import sys
from systemrdl import RDLCompiler, RDLCompileError from systemrdl import RDLCompiler, RDLCompileError
from peakrdl_busdecoder import BusDecoderExporter from peakrdl_busdecoder import BusDecoderExporter
from peakrdl_busdecoder.cpuif.axi4lite import AXI4Lite_Cpuif from peakrdl_busdecoder.cpuif.axi4lite import AXI4LiteCpuif
from peakrdl_busdecoder.udps import ALL_UDPS
input_files = [ input_files = [
"PATH/TO/my_register_block.rdl" "PATH/TO/my_register_block.rdl"
@@ -27,10 +28,6 @@ implementation from SystemRDL source.
# Create an instance of the compiler # Create an instance of the compiler
rdlc = RDLCompiler() rdlc = RDLCompiler()
# Register all UDPs that 'busdecoder' requires
for udp in ALL_UDPS:
rdlc.register_udp(udp)
try: try:
# Compile your RDL files # Compile your RDL files
for input_file in input_files: for input_file in input_files:
@@ -46,5 +43,5 @@ implementation from SystemRDL source.
exporter = BusDecoderExporter() exporter = BusDecoderExporter()
exporter.export( exporter.export(
root, "path/to/output_dir", root, "path/to/output_dir",
cpuif_cls=AXI4Lite_Cpuif cpuif_cls=AXI4LiteCpuif
) )

View File

@@ -1,64 +1,54 @@
Register Block Architecture Bus Decoder Architecture
=========================== ========================
The generated bus decoder RTL is organized into several sections. The generated RTL is a pure bus-routing layer. It accepts a single CPU interface
Each section is automatically generated based on the source register model and on the slave side and fans transactions out to a set of child interfaces on the
is rendered into the output SystemVerilog RTL module. The bus decoder serves as master side. No register storage or field logic is generated.
an address decode and routing layer that splits a single CPU interface into
multiple sub-address spaces corresponding to child addrmaps in your SystemRDL design.
.. figure:: diagrams/arch.png Although you do not need to know the inner workings to use the exporter, the
sections below explain the structure of the generated module and how it maps to
Although it is not completely necessary to know the inner workings of the SystemRDL hierarchy.
generated RTL, it can be helpful to understand the implications of various
exporter configuration options.
CPU Interface CPU Interface Adapter
------------- ---------------------
The CPU interface logic layer provides an abstraction between the Each supported CPU interface protocol (APB3, APB4, AXI4-Lite) provides a small
application-specific bus protocol and the internal register file logic. adapter that translates the external bus protocol into internal request/response
This logic layer normalizes external CPU read & write transactions into a common signals. These internal signals are then used by the address decoder and fanout
:ref:`cpuif_protocol` that is used to interact with the register file. When the logic.
design contains multiple child addrmaps, the CPU interface handles fanout of
transactions to the appropriate sub-address space. If you write a custom CPU interface, it must implement the internal signals
described in :ref:`cpuif_protocol`.
Address Decode Address Decode
-------------- --------------
A common address decode operation is generated which computes individual access The address decoder computes per-child select signals based on address ranges.
strobes for each software-accessible register or child addrmap in the design. The decode boundary is controlled by ``max_decode_depth``:
This operation is performed completely combinationally. The decoder determines
which sub-address space should handle each transaction based on the address range. * ``0``: Decode all the way down to leaf registers
* ``1`` (default): Decode only top-level children
* ``N``: Decode down to depth ``N`` from the top-level
This allows you to choose whether the bus decoder routes to large blocks (e.g.,
child addrmaps) or to smaller sub-blocks.
Field Logic Fanout to Child Interfaces
----------- --------------------------
This layer of the register block implements the storage elements and state-change For each decoded child, the bus decoder drives a master-side CPU interface.
logic for every field in the design. Field state is updated based on address All address, data, and control signals are forwarded to the selected child.
decode strobes from software read/write actions, as well as events from the
hardware interface input struct. Arrayed children can be kept as arrays or unrolled into discrete interfaces using
This section also assigns any hardware interface outputs. ``--unroll``. This only affects port structure and naming; decode semantics are
unchanged.
Readback Fanin and Error Handling
-------- ------------------------
The readback layer aggregates and reduces all readable registers into a single Read and write responses are muxed back from the selected child to the slave
read response. During a read operation, the same address decode strobes are used interface. If no child is selected for a transaction, the decoder generates an
to select the active register that is being accessed. error response on the slave interface.
This allows for a simple OR-reduction operation to be used to compute the read
data response.
For designs with a large number of software-readable registers, an optional The exact error signaling depends on the chosen CPU interface protocol (e.g.,
fanin re-timing stage can be enabled. This stage is automatically inserted at a ``PSLVERR`` for APB, ``RRESP/BRESP`` for AXI4-Lite).
balanced point in the read-data reduction so that fanin and logic-levels are
optimally reduced.
.. figure:: diagrams/readback.png
:width: 65%
:align: center
A second optional read response retiming register can be enabled in-line with the
path back to the CPU interface layer. This can be useful if the CPU interface protocol
used has a fully combinational response path, and the design's complexity requires
this path to be retimed further.

View File

@@ -32,9 +32,7 @@ author = "Arnav Sacheti"
extensions = [ extensions = [
"sphinx.ext.autodoc", "sphinx.ext.autodoc",
"sphinx.ext.napoleon", "sphinx.ext.napoleon",
"sphinxcontrib.wavedrom",
] ]
render_using_wavedrompy = True
# Add any paths that contain templates here, relative to this directory. # Add any paths that contain templates here, relative to this directory.
templates_path = ["_templates"] templates_path = ["_templates"]
@@ -42,7 +40,7 @@ templates_path = ["_templates"]
# List of patterns, relative to source directory, that match files and # List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files. # directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path. # 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", "dev_notes", "dev_notes/**"]
# -- Options for HTML output ------------------------------------------------- # -- Options for HTML output -------------------------------------------------

View File

@@ -4,10 +4,10 @@ Configuring PeakRDL-BusDecoder
============================== ==============================
If using the `PeakRDL command line tool <https://peakrdl.readthedocs.io/>`_, If using the `PeakRDL command line tool <https://peakrdl.readthedocs.io/>`_,
some aspects of the ``busdecoder`` command have additional configuration options some aspects of the ``busdecoder`` command can be configured via the PeakRDL
available via the PeakRDL TOML file. TOML file.
All busdecoder-specific options are defined under the ``[busdecoder]`` TOML heading. All busdecoder-specific options are defined under the ``[busdecoder]`` heading.
.. data:: cpuifs .. data:: cpuifs
@@ -24,22 +24,15 @@ All busdecoder-specific options are defined under the ``[busdecoder]`` TOML head
cpuifs.my-cpuif-name = "my_cpuif_module:MyCPUInterfaceClass" cpuifs.my-cpuif-name = "my_cpuif_module:MyCPUInterfaceClass"
.. data:: default_reset Command-Line Options
--------------------
Choose the default style of reset signal if not explicitly The following options are available on the ``peakrdl busdecoder`` command:
specified by the SystemRDL design. If unspecified, the default reset
is active-high and synchronous.
Choice of: * ``--cpuif``: Select the CPU interface (``apb3``, ``apb3-flat``, ``apb4``,
``apb4-flat``, ``axi4-lite``, ``axi4-lite-flat``)
* ``rst`` (default) * ``--module-name``: Override the generated module name
* ``rst_n`` * ``--package-name``: Override the generated package name
* ``arst`` * ``--addr-width``: Override the slave address width
* ``arst_n`` * ``--unroll``: Unroll arrayed children into discrete interfaces
* ``--max-decode-depth``: Control how far the decoder descends into hierarchy
For example:
.. code-block:: toml
[busdecoder]
default_reset = "arst"

View File

@@ -20,7 +20,7 @@ Both APB3 and APB4 standards are supported.
APB3 APB3
---- ----
Implements the register block using an Implements the bus decoder using an
`AMBA 3 APB <https://developer.arm.com/documentation/ihi0024/b/Introduction/About-the-AMBA-3-APB>`_ `AMBA 3 APB <https://developer.arm.com/documentation/ihi0024/b/Introduction/About-the-AMBA-3-APB>`_
CPU interface. CPU interface.
@@ -29,19 +29,19 @@ The APB3 CPU interface comes in two i/o port flavors:
SystemVerilog Interface SystemVerilog Interface
* Command line: ``--cpuif apb3`` * Command line: ``--cpuif apb3``
* Interface Definition: :download:`apb3_intf.sv <../../hdl-src/apb3_intf.sv>` * Interface Definition: :download:`apb3_intf.sv <../../hdl-src/apb3_intf.sv>`
* Class: :class:`peakrdl_busdecoder.cpuif.apb3.APB3_Cpuif` * Class: :class:`peakrdl_busdecoder.cpuif.apb3.APB3Cpuif`
Flattened inputs/outputs Flattened inputs/outputs
Flattens the interface into discrete input and output ports. Flattens the interface into discrete input and output ports.
* Command line: ``--cpuif apb3-flat`` * Command line: ``--cpuif apb3-flat``
* Class: :class:`peakrdl_busdecoder.cpuif.apb3.APB3_Cpuif_flattened` * Class: :class:`peakrdl_busdecoder.cpuif.apb3.APB3CpuifFlat`
APB4 APB4
---- ----
Implements the register block using an Implements the bus decoder using an
`AMBA 4 APB <https://developer.arm.com/documentation/ihi0024/d/?lang=en>`_ `AMBA 4 APB <https://developer.arm.com/documentation/ihi0024/d/?lang=en>`_
CPU interface. CPU interface.
@@ -50,10 +50,10 @@ The APB4 CPU interface comes in two i/o port flavors:
SystemVerilog Interface SystemVerilog Interface
* Command line: ``--cpuif apb4`` * Command line: ``--cpuif apb4``
* Interface Definition: :download:`apb4_intf.sv <../../hdl-src/apb4_intf.sv>` * Interface Definition: :download:`apb4_intf.sv <../../hdl-src/apb4_intf.sv>`
* Class: :class:`peakrdl_busdecoder.cpuif.apb4.APB4_Cpuif` * Class: :class:`peakrdl_busdecoder.cpuif.apb4.APB4Cpuif`
Flattened inputs/outputs Flattened inputs/outputs
Flattens the interface into discrete input and output ports. Flattens the interface into discrete input and output ports.
* Command line: ``--cpuif apb4-flat`` * Command line: ``--cpuif apb4-flat``
* Class: :class:`peakrdl_busdecoder.cpuif.apb4.APB4_Cpuif_flattened` * Class: :class:`peakrdl_busdecoder.cpuif.apb4.APB4CpuifFlat`

View File

@@ -1,33 +0,0 @@
Intel Avalon
============
Implements the register block using an
`Intel Avalon MM <https://www.intel.com/content/www/us/en/docs/programmable/683091/22-3/memory-mapped-interfaces.html>`_
CPU interface.
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_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_busdecoder.cpuif.avalon.Avalon_Cpuif_flattened`
Implementation Details
----------------------
This implementation of the Avalon protocol has the following features:
* Interface uses word addressing.
* Supports `pipelined transfers <https://www.intel.com/content/www/us/en/docs/programmable/683091/22-3/pipelined-transfers.html>`_
* Responses may have variable latency
In most cases, latency is fixed and is determined by how many retiming
stages are enabled in your design.
However if your design contains external components, access latency is
not guaranteed to be uniform.

View File

@@ -3,7 +3,7 @@
AMBA AXI4-Lite AMBA AXI4-Lite
============== ==============
Implements the register block using an Implements the bus decoder using an
`AMBA AXI4-Lite <https://developer.arm.com/documentation/ihi0022/e/AMBA-AXI4-Lite-Interface-Specification>`_ `AMBA AXI4-Lite <https://developer.arm.com/documentation/ihi0022/e/AMBA-AXI4-Lite-Interface-Specification>`_
CPU interface. CPU interface.
@@ -12,21 +12,22 @@ The AXI4-Lite CPU interface comes in two i/o port flavors:
SystemVerilog Interface SystemVerilog Interface
* Command line: ``--cpuif axi4-lite`` * Command line: ``--cpuif axi4-lite``
* Interface Definition: :download:`axi4lite_intf.sv <../../hdl-src/axi4lite_intf.sv>` * Interface Definition: :download:`axi4lite_intf.sv <../../hdl-src/axi4lite_intf.sv>`
* Class: :class:`peakrdl_busdecoder.cpuif.axi4lite.AXI4Lite_Cpuif` * Class: :class:`peakrdl_busdecoder.cpuif.axi4lite.AXI4LiteCpuif`
Flattened inputs/outputs Flattened inputs/outputs
Flattens the interface into discrete input and output ports. Flattens the interface into discrete input and output ports.
* Command line: ``--cpuif axi4-lite-flat`` * Command line: ``--cpuif axi4-lite-flat``
* Class: :class:`peakrdl_busdecoder.cpuif.axi4lite.AXI4Lite_Cpuif_flattened` * Class: :class:`peakrdl_busdecoder.cpuif.axi4lite.AXI4LiteCpuifFlat`
Pipelined Performance Protocol Notes
--------------------- --------------
This implementation of the AXI4-Lite interface supports transaction pipelining The AXI4-Lite adapter is intentionally simplified:
which can significantly improve performance of back-to-back transfers.
In order to support transaction pipelining, the CPU interface will accept multiple * AW and W channels must be asserted together for writes. The adapter does not
concurrent transactions. The number of outstanding transactions allowed is automatically support decoupled address/data for writes.
determined based on the register file pipeline depth (affected by retiming options), * Only a single outstanding transaction is supported. Masters should wait for
and influences the depth of the internal transaction response skid buffer. the corresponding response before issuing the next request.
* Burst transfers are not supported (single-beat transfers only), consistent
with AXI4-Lite.

View File

@@ -29,15 +29,15 @@ Rather than rewriting a new CPU interface definition, you can extend and adjust
.. code-block:: python .. code-block:: python
from peakrdl_busdecoder.cpuif.axi4lite import AXI4Lite_Cpuif from peakrdl_busdecoder.cpuif.axi4lite import AXI4LiteCpuif
class My_AXI4Lite(AXI4Lite_Cpuif): class My_AXI4Lite(AXI4LiteCpuif):
@property @property
def port_declaration(self) -> str: def port_declaration(self) -> str:
# Override the port declaration text to use the alternate interface name and modport style # Override the port declaration text to use the alternate interface name and modport style
return "axi4_lite_interface.Slave_mp s_axil" return "axi4_lite_interface.Slave_mp s_axil"
def signal(self, name:str) -> str: def signal(self, name: str, node=None, indexer=None) -> str:
# Override the signal names to be lowercase instead # Override the signal names to be lowercase instead
return "s_axil." + name.lower() return "s_axil." + name.lower()
@@ -72,7 +72,7 @@ you can define your own.
2. Create a Python class that defines your CPUIF 2. Create a Python class that defines your CPUIF
Extend your class from :class:`peakrdl_busdecoder.cpuif.CpuifBase`. Extend your class from :class:`peakrdl_busdecoder.cpuif.BaseCpuif`.
Define the port declaration string, and provide a reference to your template file. Define the port declaration string, and provide a reference to your template file.
3. Use your new CPUIF definition when exporting. 3. Use your new CPUIF definition when exporting.

View File

@@ -3,10 +3,10 @@
Internal CPUIF Protocol Internal CPUIF Protocol
======================= =======================
Internally, the busdecoder generator uses a common CPU interface handshake Internally, the bus decoder uses a small set of common request/response signals
protocol. This strobe-based protocol is designed to add minimal overhead to the that each CPU interface adapter must drive. This protocol is intentionally simple
busdecoder implementation, while also being flexible enough to support advanced and supports a single outstanding transaction at a time. The CPU interface logic
features of a variety of bus interface standards. is responsible for holding request signals stable until the transaction completes.
Signal Descriptions Signal Descriptions
@@ -15,62 +15,49 @@ Signal Descriptions
Request Request
^^^^^^^ ^^^^^^^
cpuif_req cpuif_req
When asserted, a read or write transfer will be initiated. When asserted, a read or write transfer is in progress. Request signals must
Denotes that the following signals are valid: ``cpuif_addr``, remain stable until the transfer completes.
``cpuif_req_is_wr``, and ``cpuif_wr_data``.
A transfer will only initiate if the relevant stall signal is not asserted. cpuif_wr_en
If stalled, the request shall be held until accepted. A request's parameters When asserted alongside ``cpuif_req``, denotes a write transfer.
(type, address, etc) shall remain static throughout the stall.
cpuif_addr cpuif_rd_en
Byte-address of the transfer. When asserted alongside ``cpuif_req``, denotes a read transfer.
cpuif_req_is_wr cpuif_wr_addr / cpuif_rd_addr
If ``1``, denotes that the current transfer is a write. Otherwise transfer is Byte address of the write or read transfer, respectively.
a read.
cpuif_wr_data cpuif_wr_data
Data to be written for the write transfer. This signal is ignored for read Data to be written for the write transfer.
transfers.
cpuif_wr_biten cpuif_wr_byte_en
Active-high bit-level write-enable strobes. Active-high byte-enable strobes for writes. Some CPU interfaces do not
Only asserted bit positions will change the register value during a write provide byte enables and may drive this as all-ones.
transfer.
cpuif_req_stall_rd
If asserted, and the next pending request is a read operation, then the
transfer will not be accepted until this signal is deasserted.
cpuif_req_stall_wr
If asserted, and the next pending request is a write operation, then the
transfer will not be accepted until this signal is deasserted.
Read Response Read Response
^^^^^^^^^^^^^ ^^^^^^^^^^^^^
cpuif_rd_ack cpuif_rd_ack
Single-cycle strobe indicating a read transfer has completed. Single-cycle strobe indicating a read transfer has completed.
Qualifies that the following signals are valid: ``cpuif_rd_err`` and Qualifies ``cpuif_rd_err`` and ``cpuif_rd_data``.
``cpuif_rd_data``
cpuif_rd_err cpuif_rd_err
If set, indicates that the read transaction failed and the CPUIF logic Indicates that the read transaction failed. The CPU interface should return
should return an error response if possible. an error response if possible.
cpuif_rd_data cpuif_rd_data
Read data. Is sampled on the same cycle that ``cpuif_rd_ack`` is asserted. Read data. Sampled on the same cycle that ``cpuif_rd_ack`` is asserted.
Write Response Write Response
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
cpuif_wr_ack cpuif_wr_ack
Single-cycle strobe indicating a write transfer has completed. Single-cycle strobe indicating a write transfer has completed.
Qualifies that the ``cpuif_wr_err`` signal is valid. Qualifies ``cpuif_wr_err``.
cpuif_wr_err cpuif_wr_err
If set, indicates that the write transaction failed and the CPUIF logic Indicates that the write transaction failed. The CPU interface should return
should return an error response if possible. an error response if possible.
Transfers Transfers
@@ -78,155 +65,7 @@ Transfers
Transfers have the following characteristics: Transfers have the following characteristics:
* Only one transfer can be initiated per clock-cycle. This is implicit as there * Only one outstanding transaction is supported.
is only one set of request signals. * The CPU interface must hold ``cpuif_req`` and request parameters stable until
* The register block implementation shall guarantee that only one response can be the corresponding ``cpuif_*_ack`` is asserted.
asserted in a given clock cycle. Only one ``cpuif_*_ack`` signal can be * Responses shall arrive in the same order as requests.
asserted at a time.
* Responses shall arrive in the same order as their corresponding request was
dispatched.
Basic Transfer
^^^^^^^^^^^^^^
Depending on the configuration of the exported register block, transfers can be
fully combinational or they may require one or more clock cycles to complete.
Both are valid and CPU interface logic shall be designed to anticipate either.
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p...."},
{"name": "cpuif_req", "wave": "010.."},
{"name": "cpuif_req_is_wr", "wave": "x2x.."},
{"name": "cpuif_addr", "wave": "x2x..", "data": ["A"]},
{},
{"name": "cpuif_*_ack", "wave": "010.."},
{"name": "cpuif_*_err", "wave": "x2x.."}
],
"foot": {
"text": "Zero-latency transfer"
}
}
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p..|..."},
{"name": "cpuif_req", "wave": "010|..."},
{"name": "cpuif_req_is_wr", "wave": "x2x|..."},
{"name": "cpuif_addr", "wave": "x2x|...", "data": ["A"]},
{},
{"name": "cpuif_*_ack", "wave": "0..|10."},
{"name": "cpuif_*_err", "wave": "x..|2x."}
],
"foot": {
"text": "Transfer with non-zero latency"
}
}
Read & Write Transactions
-------------------------
Waveforms below show the timing relationship of simple read/write transactions.
For brevity, only showing non-zero latency transfers.
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p..|..."},
{"name": "cpuif_req", "wave": "010|..."},
{"name": "cpuif_req_is_wr", "wave": "x0x|..."},
{"name": "cpuif_addr", "wave": "x3x|...", "data": ["A"]},
{},
{"name": "cpuif_rd_ack", "wave": "0..|10."},
{"name": "cpuif_rd_err", "wave": "x..|0x."},
{"name": "cpuif_rd_data", "wave": "x..|5x.", "data": ["D"]}
],
"foot": {
"text": "Read Transaction"
}
}
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p..|..."},
{"name": "cpuif_req", "wave": "010|..."},
{"name": "cpuif_req_is_wr", "wave": "x1x|..."},
{"name": "cpuif_addr", "wave": "x3x|...", "data": ["A"]},
{"name": "cpuif_wr_data", "wave": "x5x|...", "data": ["D"]},
{},
{"name": "cpuif_wr_ack", "wave": "0..|10."},
{"name": "cpuif_wr_err", "wave": "x..|0x."}
],
"foot": {
"text": "Write Transaction"
}
}
Transaction Pipelining & Stalls
-------------------------------
If the CPU interface supports it, read and write operations can be pipelined.
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p......"},
{"name": "cpuif_req", "wave": "01..0.."},
{"name": "cpuif_req_is_wr", "wave": "x0..x.."},
{"name": "cpuif_addr", "wave": "x333x..", "data": ["A1", "A2", "A3"]},
{},
{"name": "cpuif_rd_ack", "wave": "0.1..0."},
{"name": "cpuif_rd_err", "wave": "x.0..x."},
{"name": "cpuif_rd_data", "wave": "x.555x.", "data": ["D1", "D2", "D3"]}
]
}
It is very likely that the transfer latency of a read transaction will not
be the same as a write for a given register block configuration. Typically read
operations will be more deeply pipelined. This latency asymmetry would create a
hazard for response collisions.
In order to eliminate this hazard, additional stall signals (``cpuif_req_stall_rd``
and ``cpuif_req_stall_wr``) are provided to delay the next incoming transfer
request if necessary. When asserted, the CPU interface shall hold the next pending
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 busdecoder is configured such that:
* A read transaction takes 1 clock cycle to complete
* A write transaction takes 0 clock cycles to complete
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p......."},
{"name": "cpuif_req", "wave": "01.....0"},
{"name": "cpuif_req_is_wr", "wave": "x1.0.1.x"},
{"name": "cpuif_addr", "wave": "x33443.x", "data": ["W1", "W2", "R1", "R2", "W3"]},
{"name": "cpuif_req_stall_wr", "wave": "0...1.0."},
{},
{"name": "cpuif_rd_ack", "wave": "0...220.", "data": ["R1", "R2"]},
{"name": "cpuif_wr_ack", "wave": "0220..20", "data": ["W1", "W2", "W3"]}
]
}
In the above waveform, observe that:
* The ``R2`` read request is not affected by the assertion of the write stall,
since the write stall only applies to write requests.
* The ``W3`` write request is stalled for one cycle, and is accepted once the stall is cleared.

View File

@@ -2,16 +2,17 @@ Introduction
============ ============
The CPU interface logic layer provides an abstraction between the The CPU interface logic layer provides an abstraction between the
application-specific bus protocol and the internal register file logic. application-specific bus protocol and the internal bus decoder logic.
When exporting a design, you can select from a variety of popular CPU interface When exporting a design, you can select from supported CPU interface protocols.
protocols. These are described in more detail in the pages that follow. These are described in more detail in the pages that follow.
Bus Width Bus Width
^^^^^^^^^ ^^^^^^^^^
The CPU interface bus width is automatically determined from the contents of the The CPU interface bus width is inferred from the contents of the design.
design being exported. The bus width is equal to the widest ``accesswidth`` It is intended to be equal to the widest ``accesswidth`` encountered in the
encountered in the design. design. If the exported addrmap contains only external components, the width
cannot be inferred and will default to 32 bits.
Addressing Addressing
@@ -32,5 +33,6 @@ For example, consider a fictional AXI4-Lite device that:
- If care is taken to align the global address offset to the size of the device, - If care is taken to align the global address offset to the size of the device,
creating a relative address is as simple as pruning down address bits. creating a relative address is as simple as pruning down address bits.
By default, the bit-width of the address bus will be the minimum size to span the contents By default, the bit-width of the address bus will be the minimum size to span the
of the register block. If needed, the address width can be overridden to a larger range. contents of the decoded address space. If needed, the address width can be
overridden to a larger range using ``--addr-width``.

View File

@@ -1,10 +0,0 @@
CPUIF Passthrough
=================
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_busdecoder.cpuif.passthrough.PassthroughCpuif`
For more details on the protocol itself, see: :ref:`cpuif_protocol`.

View File

@@ -1,131 +0,0 @@
Frequently Asked Questions
==========================
Why isn't there an option for a flat non-struct hardware interface?
-------------------------------------------------------------------
SystemRDL is inherently a very hierarchical language.
For small register blocks, flattening the hardware interface may be acceptable,
but this ends up scaling very poorly as the design becomes larger and has more
complex hierarchy.
Using struct compositions for the hardware interface has the benefit of
preserving conceptual hierarchy and arrays exactly as defined in the original
SystemRDL.
How do I know I connected everything? Structs are harder to review
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Initially this can be daunting, but fortunately the tool has an option to generate a
flattened hardware interface report upon export. Try using the ``--hwif-report``
command line option when exporting. This is the easiest way to quickly
understand the structure of the hardware interface.
Why does the tool generate un-packed structs? I prefer packed structs.
----------------------------------------------------------------------
Packed structs are great when describing vectors that have bit-level structure.
In this tool, the use of un-packed structs is intentional since the hardware
interface is not something that is meant to be bit-accessible. In the case of
the hardware interface structs, using a packed struct is semantically inappropriate.
... Then how can I initialize the struct?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We get this request most often because designers want to initialize the ``hwif_in``
struct with a simple assignment:
.. code:: systemverilog
always_comb begin
hwif_in = '0;
end
Of course since the struct actually is **unpacked**, this will result in a
compile error which usually leads to the inappropriate assumption that it ought
to be packed. (See this amusing blog post about `X/Y problems <https://xyproblem.info>`_)
If your goal is to initialize the packed struct, fortunately SystemVerilog already
has syntax to do this:
.. code:: systemverilog
always_comb begin
hwif_in = '{default: '0};
end
This is lesser-known syntax, but still very well supported by synthesis
tools, and is the recommended way to handle this.
... What if I want to assign it to a bit-vector?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Assigning the hwif struct to a bit-vector is strongly discouraged. This tool makes
no guarantees regarding the field ordering of the hwif structure, so doing so
should be considered functionally dangerous.
That said, if you still need to do this, it is still trivially possible to
without requiring packed structs. Instead, use the SystemVerilog streaming operator:
.. code:: systemverilog
my_packed_vector = {<<{hwif_out}};
... Why are unpacked structs preferred?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In the case of the hardware interface ports, unpacked structs help prevent
mistakes that are very easy to make.
Consider the following situation - a designer has a field that sets the following
properties: ``sw=rw; hw=rw; we;``, and wants to assign the hardware input value,
so they erroneously do the following assignment in Verilog:
.. code:: systemverilog
assign hwif_in.my_register.my_field = <some value>;
This is actually a bug since the ``my_field`` member is actually a struct that
has two members: ``we`` and ``next``. If this were a packed struct, this would
silently compile and you would potentially have a bug that may not be noticed
(depending on how thorough the test campaign is).
With an unpacked struct, this gets flagged immediately as a compile error since
the assignment is invalid.
The designer may have simply forgotten that the field is an aggregate of multiple
members and intended to do the following:
.. code:: systemverilog
assign hwif.my_register.my_field.next = <some value>;
assign hwif.my_register.my_field.we = <some control signal>;
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-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.
In general, we strive to follow the
`SystemVerilog style guide by lowRISC <https://github.com/lowRISC/style-guides/blob/master/VerilogCodingStyle.md>`_,
but may deviate in some areas if not practical or would impose excessive complexity on the code generator.
The lint tool I am using is flagging violations in generated code
-----------------------------------------------------------------
Code linting tools are a great way to check for user-error, flag inconsistencies,
and enforce best-practices within an organization. In many cases, linter tools
may be configured to also enforce stylistic preferences.
Unfortunately just like coding styles, lint rules can often be more
opinionated than practical.
In general, we will not address lint violations unless they flag actual
structural issues or semantically dangerous code.
Stylistic violations that pose no actual danger to the correctness of the design
will rarely be addressed, especially if the change would add unreasonable
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 <https://github.com/arnavsacheti/PeakRDL-BusDecoder/issues>`_
that describes the problem.

View File

@@ -1,61 +0,0 @@
Hardware Interface
------------------
The generated register block will present the entire hardware interface to the user
using two struct ports:
* ``hwif_in``
* ``hwif_out``
All field inputs and outputs as well as signals are consolidated into these
struct ports. The presence of each depends on the specific contents of the design
being exported.
Using structs for the hardware interface has the following benefits:
* Preserves register map component grouping, arrays, and hierarchy.
* Avoids naming collisions and cumbersome signal name flattening.
* Allows for more natural mapping and distribution of register block signals to a design's hardware components.
* Use of unpacked arrays/structs prevents common assignment mistakes as they are enforced by the compiler.
Structs are organized as follows: ``hwif_out.<heir_path>.<feature>``
For example, a simple design such as:
.. code-block:: systemrdl
addrmap my_design {
reg {
field {
sw = rw;
hw = rw;
we;
} my_field;
} my_reg[2];
};
... results in the following struct members:
.. code-block:: text
hwif_out.my_reg[0].my_field.value
hwif_in.my_reg[0].my_field.next
hwif_in.my_reg[0].my_field.we
hwif_out.my_reg[1].my_field.value
hwif_in.my_reg[1].my_field.next
hwif_in.my_reg[1].my_field.we
For brevity in this documentation, hwif features will be described using shorthand
notation that omits the hierarchical path: ``hwif_out..<feature>``
.. important::
The PeakRDL tool makes no guarantees on the field order of the hwif structs.
For this reason, it is strongly recommended to always access struct members
directly, by name.
If using the SystemVerilog streaming operator to assign the hwif struct to a
packed vector, be extremely careful to avoid assumptions on the resulting bit-position of a field.

View File

@@ -1,28 +1,34 @@
Introduction Introduction
============ ============
PeakRDL-BusDecoder is a free and open-source bus decoder generator for hierarchical register address maps. PeakRDL-BusDecoder is a free and open-source bus decoder generator for hierarchical
This code generator translates your SystemRDL register description into a synthesizable SystemRDL address maps. It produces a synthesizable SystemVerilog RTL module that
SystemVerilog RTL module that decodes CPU interface transactions and routes them to accepts a single CPU interface (slave side) and fans transactions out to multiple
multiple sub-address spaces (child addrmaps). This is particularly useful for: child address spaces (master side).
This tool **does not** generate register storage or field logic. It is strictly a
bus-routing layer that decodes addresses and forwards requests to child blocks.
This is particularly useful for:
* Creating hierarchical register maps with multiple sub-components * Creating hierarchical register maps with multiple sub-components
* Splitting a single CPU interface bus to serve multiple independent register blocks * Splitting a single CPU interface bus to serve multiple independent register blocks
* Organizing large register designs into logical sub-address spaces * Organizing large address spaces into logical sub-regions
* Implementing address decode logic for multi-drop bus architectures * Implementing address decode logic for multi-drop bus architectures
The generated bus decoder provides: The generated bus decoder provides:
* Fully synthesizable SystemVerilog RTL (IEEE 1800-2012) * Fully synthesizable SystemVerilog RTL (IEEE 1800-2012)
* Support for many popular CPU interface protocols (AMBA APB, AXI4-Lite, and more) * A top-level slave CPU interface and per-child master CPU interfaces
* Address decode logic that routes transactions to child address maps * Address decode logic that routes transactions to child address maps
* Configurable pipelining options for designs with fast clock rates * Support for APB3, APB4, and AXI4-Lite (plus plugin-defined CPU interfaces)
* Broad support for SystemRDL 2.0 features * Configurable decode depth and array unrolling
Quick Start Quick Start
----------- -----------
The easiest way to use PeakRDL-BusDecoder is via the `PeakRDL command line tool <https://peakrdl.readthedocs.io/>`_: The easiest way to use PeakRDL-BusDecoder is via the
`PeakRDL command line tool <https://peakrdl.readthedocs.io/>`_:
.. code-block:: bash .. code-block:: bash
@@ -32,6 +38,20 @@ The easiest way to use PeakRDL-BusDecoder is via the `PeakRDL command line tool
# Export! # Export!
peakrdl busdecoder atxmega_spi.rdl -o busdecoder/ --cpuif axi4-lite peakrdl busdecoder atxmega_spi.rdl -o busdecoder/ --cpuif axi4-lite
The exporter writes two files:
* A SystemVerilog module (the bus decoder)
* A SystemVerilog package (constants like data width and per-child address widths)
Key command-line options:
* ``--cpuif``: Select the CPU interface (``apb3``, ``apb3-flat``, ``apb4``, ``apb4-flat``, ``axi4-lite``, ``axi4-lite-flat``)
* ``--module-name``: Override the generated module name
* ``--package-name``: Override the generated package name
* ``--addr-width``: Override the slave address width
* ``--unroll``: Unroll arrayed children into discrete interfaces
* ``--max-decode-depth``: Control how far the decoder descends into hierarchy
Looking for VHDL? Looking for VHDL?
----------------- -----------------
@@ -55,10 +75,8 @@ Links
self self
architecture architecture
hwif
configuring configuring
limitations limitations
faq
licensing licensing
api api
@@ -69,29 +87,5 @@ Links
cpuif/introduction cpuif/introduction
cpuif/apb cpuif/apb
cpuif/axi4lite cpuif/axi4lite
cpuif/avalon
cpuif/passthrough
cpuif/internal_protocol cpuif/internal_protocol
cpuif/customizing cpuif/customizing
.. toctree::
:hidden:
:caption: SystemRDL Properties
props/field
props/reg
props/addrmap
props/signal
props/rhs_props
.. toctree::
:hidden:
:caption: Other SystemRDL Features
rdl_features/external
.. toctree::
:hidden:
:caption: Extended Properties
udps/intro

View File

@@ -1,53 +1,47 @@
Known Limitations Known Limitations
================= =================
Not all SystemRDL features are supported by this exporter. For a listing of The busdecoder exporter intentionally focuses on address decode and routing.
supported properties, see the appropriate property listing page in the sections Some SystemRDL features are ignored, and a few are explicitly disallowed.
that follow.
Alias Registers Address Alignment
--------------- -----------------
Registers instantiated using the ``alias`` keyword are not supported yet. All address offsets and array strides must be aligned to the CPU interface data
bus width (in bytes). Misaligned offsets/strides are rejected.
Unaligned Registers Wide Registers
------------------- --------------
All address offsets & strides shall be a multiple of the cpuif bus width used. Specifically: If a register is wider than its ``accesswidth`` (a multi-word register), its
``accesswidth`` must match the CPU interface data width. Multi-word registers
* Bus width is inferred by the maximum accesswidth used in the busdecoder. with a smaller accesswidth are not supported.
* Each component's address and array stride shall be aligned to the bus width.
Uniform accesswidth Fields Spanning Sub-Words
------------------- -------------------------
All registers within a register block shall use the same accesswidth. If a field spans multiple sub-words of a wide register:
One exception is that registers with regwidth that is narrower than the cpuif * Software-writable fields must have write buffering enabled
bus width are permitted, provided that their regwidth is equal to their accesswidth. * Fields with ``onread`` side-effects must have read buffering enabled
For example: These rules are enforced to avoid ambiguous multi-word access behavior.
.. code-block:: systemrdl
// (Largest accesswidth used is 32, therefore the CPUIF bus width is 32) External Boundary References
----------------------------
Property references are not allowed to cross the internal/external boundary of
the exported addrmap. References must point to components that are internal to
the busdecoder being generated.
reg { CPU Interface Reset Location
regwidth = 32; ----------------------------
accesswidth = 32; Only ``cpuif_reset`` signals instantiated at the top-level addrmap (or above)
} reg_a @ 0x00; // OK. Regular 32-bit register are honored. Nested ``cpuif_reset`` signals are ignored.
reg {
regwidth = 64;
accesswidth = 32;
} reg_b @ 0x08; // OK. "Wide" register of 64-bits, but is accessed using 32-bit subwords
reg { Unsupported Properties
regwidth = 8; ----------------------
accesswidth = 8; The following SystemRDL properties are explicitly rejected:
} reg_c @ 0x10; // OK. Is aligned to the cpuif bus width
reg { * ``sharedextbus`` on addrmap/regfile components
regwidth = 32;
accesswidth = 8;
} bad_reg @ 0x14; // NOT OK. accesswidth conflicts with cpuif width

View File

@@ -1,28 +0,0 @@
Addrmap/Regfile Properties
==========================
.. note:: Any properties not explicitly listed here are either implicitly
supported, or are not relevant to the busdecoder exporter and are ignored.
errextbus
---------
|NO|
sharedextbus
------------
|NO|
--------------------------------------------------------------------------------
Addrmap Properties
==================
bigendian/littleendian
----------------------
|NO|
rsvdset
-------
|NO|

View File

@@ -1,491 +0,0 @@
Field Properties
================
.. note:: Any properties not explicitly listed here are either implicitly
supported, or are not relevant to the busdecoder exporter and are ignored.
Software Access Properties
--------------------------
onread/onwrite
^^^^^^^^^^^^^^
All onread/onwrite actions are supported (except for ruser/wuser)
rclr/rset
^^^^^^^^^
See ``onread``. These are effectively aliases of the onread property.
singlepulse
^^^^^^^^^^^
If set, field will get cleared back to zero after being written.
.. wavedrom::
{"signal": [
{"name": "clk", "wave": "p....."},
{"name": "<swmod>", "wave": "0.10.."},
{"name": "hwif_out..value", "wave": "0..10."}
]}
sw
^^^
All sw access modes are supported except for ``w1`` and ``rw1``.
swacc
^^^^^
If true, infers an output signal ``hwif_out..swacc`` that is asserted when
accessed by software. Specifically, on the same clock cycle that the field is
being sampled during a software read operation, or as it is being written.
.. wavedrom::
{"signal": [
{"name": "clk", "wave": "p...."},
{"name": "hwif_in..next", "wave": "x.=x.", "data": ["D"]},
{"name": "hwif_out..swacc", "wave": "0.10."}
]}
swmod
^^^^^
If true, infers an output signal ``hwif_out..swmod`` that is asserted as the
field is being modified by software. This can be due to a software write
operation, or a software read operation that has clear/set side-effects.
.. wavedrom::
{"signal": [
{"name": "clk", "wave": "p....."},
{"name": "hwif_out..value", "wave": "=..=..", "data": ["old", "new"]},
{"name": "hwif_out..swmod", "wave": "0.10.."}
]}
swwe/swwel
^^^^^^^^^^
Provides a mechanism that allows hardware to override whether the field is
writable by software.
boolean
If True, infers an input signal ``hwif_in..swwe`` or ``hwif_in..swwel``.
reference
Single-bit reference controls field's behavior.
woclr/woset
^^^^^^^^^^^
See ``onwrite``. These are effectively aliases of the onwrite property.
--------------------------------------------------------------------------------
Hardware Access Properties
--------------------------
anded/ored/xored
^^^^^^^^^^^^^^^^
If true, infers the existence of output signal: ``hwif_out..anded``,
``hwif_out..ored``, ``hwif_out..xored``
hw
^^^
Controls hardware access to the field.
If readable, enables output signal ``hwif_out..value``. If writable, enables
input ``hwif_in..next``.
Hardware-writable fields can optionally define the ``next`` property which replaces
the inferred ``hwif_in..next`` input with an alternate reference.
hwclr/hwset
^^^^^^^^^^^
If both ``hwclr`` and ``hwset`` properties are used, and both are asserted at
the same clock cycle, then ``hwset`` will take precedence.
boolean
If true, infers the existence of input signal: ``hwif_in..hwclr``, ``hwif_in..hwset``
reference
Reference to any single-bit internal object to drive this control.
hwenable/hwmask
^^^^^^^^^^^^^^^
Reference to a component that provides bit-level control of hardware writeability.
we/wel
^^^^^^
Write-enable control from hardware interface.
If true, infers the existence of input signal: ``hwif_in..we``, ``hwif_in..wel``
.. wavedrom::
{"signal": [
{"name": "clk", "wave": "p...."},
{"name": "hwif_in..next", "wave": "x.=x.", "data": ["D"]},
{"name": "hwif_in..we", "wave": "0.10."},
{"name": "hwif_in..wel", "wave": "1.01."},
{"name": "<field value>", "wave": "x..=.", "data": ["D"]}
]}
boolean
If true, infers the existence of input signal ``hwif_in..we`` or ``hwif_in..wel``
reference
Reference to any single-bit internal object to drive this control.
--------------------------------------------------------------------------------
Counter Properties
------------------
counter
^^^^^^^
If true, marks this field as a counter. The counter direction is inferred based
based on which properties are assigned. By default, an up-counter is implemented.
If any of the properties associated with an up-counter are used, then up-counting
capabilities will be implemented. The same is true for down-counters and up/down
counters.
Unless alternate control signals are specified, the existence of input signals
``hwif_in..incr`` and ``hwif_in..decr`` will be inferred depending on the type
of counter described.
incr
^^^^
Assign a reference to an alternate control signal to increment the counter.
If assigned, the inferred ``hwif_in..incr`` input will not be generated.
incrsaturate/saturate
^^^^^^^^^^^^^^^^^^^^^
If assigned, indicates that the counter will saturate instead of wrapping.
If an alternate saturation point is specified, the counter value will be
adjusted so that it does not exceed that limit, even after non-increment actions.
boolean
If true, saturation point is at the counter's maximum count value. (2^width - 1)
integer
Specify a static saturation value.
reference
Specify a dynamic saturation value.
incrthreshold/threshold
^^^^^^^^^^^^^^^^^^^^^^^
If assigned, infers a ``hwif_out..incrthreshold`` output signal. This signal is
asserted if the counter value is greater or equal to the threshold.
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p......"},
{"name": "hwif_in..incr", "wave": "01...0."},
{"name": "<counter>", "wave": "=.=3==..", "data": [4,5,6,7,8,9]},
{"name": "hwif_out..incrthreshold", "wave": "0..1...."}
],
"foot": {
"text": "Example where incrthreshold = 6"
}
}
boolean
If true, threshold is the counter's maximum count value. (2^width - 1)
integer
Specify a static threshold value.
reference
Specify a dynamic threshold value.
incrvalue
^^^^^^^^^
Override the counter's increment step size.
integer
Specify a static increment step size.
reference
Reference a component that controls the step size.
incrwidth
^^^^^^^^^
If assigned, infers an input signal ``hwif_in..incrvalue``. The value of this
property defines the signal's width.
overflow
^^^^^^^^
If true, infers an output signal ``hwif_out..overflow`` that is asserted when
the counter is about to wrap.
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p......."},
{"name": "hwif_in..incr", "wave": "0101010."},
{"name": "<counter>", "wave": "=.=.=.=.", "data": [14,15,0,1]},
{"name": "hwif_out..overflow", "wave": "0..10..."}
],
"foot": {
"text": "A 4-bit counter overflowing"
}
}
decr
^^^^
Assign a reference to an alternate control signal to decrement the counter.
If assigned, the inferred ``hwif_in..decr`` input will not be generated.
decrsaturate
^^^^^^^^^^^^
If assigned, indicates that the counter will saturate instead of wrapping.
If an alternate saturation point is specified, the counter value will be
adjusted so that it does not exceed that limit, even after non-decrement actions.
boolean
If true, saturation point is when the counter reaches 0.
integer
Specify a static saturation value.
reference
Specify a dynamic saturation value.
decrthreshold
^^^^^^^^^^^^^
If assigned, infers a ``hwif_out..decrthreshold`` output signal. This signal is
asserted if the counter value is less than or equal to the threshold.
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p......"},
{"name": "hwif_in..decr", "wave": "01...0."},
{"name": "<counter>", "wave": "=.=3==.", "data": [9,8,7,6,5,4]},
{"name": "hwif_out..decrthreshold", "wave": "0..1..."}
],
"foot": {
"text": "Example where incrthreshold = 7"
}
}
boolean
If true, threshold is 0.
integer
Specify a static threshold value.
reference
Specify a dynamic threshold value.
decrvalue
^^^^^^^^^
Override the counter's decrement step size.
integer
Specify a static step size.
reference
Reference to a component that controls the step size.
decrwidth
^^^^^^^^^
If assigned, infers an input signal ``hwif_in..decrvalue``. The value of this
property defines the signal's width.
underflow
^^^^^^^^^
If true, infers an output signal ``hwif_out..underflow`` that is asserted when
the counter is about to wrap.
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p......."},
{"name": "hwif_in..decr", "wave": "0101010."},
{"name": "<counter>", "wave": "=.=.=.=.", "data": [1,0,15,14]},
{"name": "hwif_out..underflow", "wave": "0..10..."}
],
"foot": {
"text": "A 4-bit counter underflowing"
}
}
--------------------------------------------------------------------------------
Interrupt Properties
--------------------
intr
^^^^
If set, this field becomes an interrupt field.
The enclosing register infers an output signal ``hwif_out..intr`` which denotes
that an interrupt is active. This is an or-reduction of all interrupt fields
after applying the appropriate ``enable`` or ``mask`` to the field value.
level (default)
Interrupt is level-sensitive. If a bit on the field's ``hwif_in..next`` input
is '1', it will trigger an interrupt event.
posedge
If a bit on the field's ``hwif_in..next`` input transitions from '0' to '1',
it will trigger an interrupt event. This transition shall still be synchronous
to the register block's clock.
negedge
If a bit on the field's ``hwif_in..next`` input transitions from '1' to '0',
it will trigger an interrupt event. This transition shall still be synchronous
to the register block's clock.
bothedge
If a bit on the field's ``hwif_in..next`` input transitions from '0' to '1' or '1' to '0',
it will trigger an interrupt event. This transition shall still be synchronous
to the register block's clock.
nonsticky
Interrupt event is not sticky.
enable
^^^^^^
Reference to a field or signal that, if set to 1, define which bits in the field
are used to assert an interrupt.
mask
^^^^
Reference to a field or signal that, if set to 1, define which bits in the field
are *not* used to assert an interrupt.
haltenable
^^^^^^^^^^
Reference to a field or signal that, if set to 1, define which bits in the field
are used to assert the halt output.
If this property is set, the enclosing register will infer a ``hwif_out..halt`` output.
haltmask
^^^^^^^^
Reference to a field or signal that, if set to 1, define which bits in the field
are *not* used to assert the halt output.
If this property is set, the enclosing register will infer a ``hwif_out..halt`` output.
stickybit
^^^^^^^^^
When an interrupt trigger occurs, a stickybit field will set the corresponding
bit to '1' and hold it until it is cleared by a software access.
The interrupt trigger depends on the interrupt type. By default, interrupts are
level-sensitive, but the interrupt modifiers allow for edge-sensitive triggers as
well.
The waveform below demonstrates a level-sensitive interrupt:
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p....."},
{"name": "hwif_in..next", "wave": "010..."},
{"name": "<field value>", "wave": "0.1..."}
]
}
sticky
^^^^^^
Unlike ``stickybit`` fields, a sticky field will latch an entire value. The
value is latched as soon as ``hwif_in..next`` is nonzero, and is held until the
field contents are cleared back to 0 by a software access.
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p....."},
{"name": "hwif_in..next", "wave": "23.22.", "data": [0,10,20,30]},
{"name": "<field value>", "wave": "2.3...", "data": [0, 10]}
]
}
--------------------------------------------------------------------------------
Misc
----
encode
^^^^^^
If assigned a user-defined enumeration, the resulting package file will include
its definition. Due to limitations from type-strictness rules in SystemVerilog,
the field will remain as a ``logic`` datatype.
next
^^^^
If assigned, replaces the inferred ``hwif_in..next`` input with an explicit reference.
paritycheck
^^^^^^^^^^^
If set, enables parity checking for this field.
Adds a ``parity_error`` output signal to the module.
.. note::
If this field does not implement storage, the ``partycheck`` property is ignored.
precedence
^^^^^^^^^^
Control whether hardware or software has precedence when field value update
contention occurs. Software has precedence by default.
reset
^^^^^
Control the reset value of the field's storage element.
If not specified, the field will not be reset.
integer
Static reset value
reference
Reference to a dynamic reset value.
resetsignal
^^^^^^^^^^^
Provide an alternate reset trigger for this field.

View File

@@ -1,14 +0,0 @@
Register Properties
===================
.. note:: Any properties not explicitly listed here are either implicitly
supported, or are not relevant to the busdecoder exporter and are ignored.
accesswidth
-----------
Control the software access width. The register block's CPUIF bus width is
determined by the maximum accesswidth encountered.
regwidth
--------
Control the bit-width of the register.

View File

@@ -1,182 +0,0 @@
RHS Property References
=======================
SystemRDL allows some properties to be referenced in the righthand-side of
property assignment expressions:
.. code-block:: systemrdl
some_property = my_reg.my_field -> some_property;
The official SystemRDL spec refers to these as "Ref targets" in Table G1, but
unfortunately does not describe their semantics in much detail.
The text below describes the interpretations used for this exporter.
--------------------------------------------------------------------------------
Field
-----
field -> swacc
^^^^^^^^^^^^^^
Single-cycle strobe that indicates the field is being accessed by software
(read or write).
field -> swmod
^^^^^^^^^^^^^^^
Single-cycle strobe that indicates the field is being modified during a software
access operation.
field -> swwe/swwel
^^^^^^^^^^^^^^^^^^^
Represents the signal that controls the field's swwe/swwel behavior.
field -> anded/ored/xored
^^^^^^^^^^^^^^^^^^^^^^^^^
Represents the current and/or/xor reduction of the field's value.
field -> hwclr/hwset
^^^^^^^^^^^^^^^^^^^^
|EX|
Represents the signal that controls the field's hwclr/hwset behavior.
field -> hwenable/hwmask
^^^^^^^^^^^^^^^^^^^^^^^^
Represents the signal that controls the field's hwenable/hwmask behavior.
field -> we/wel
^^^^^^^^^^^^^^^
Represents the signal that controls the field's we/wel behavior.
field -> next
^^^^^^^^^^^^^
|EX|
field -> reset
^^^^^^^^^^^^^^
Represents the value that was assigned to this property.
field -> resetsignal
^^^^^^^^^^^^^^^^^^^^
Represents the value that was assigned to this property.
--------------------------------------------------------------------------------
Field Counter Properties
------------------------
field -> incr
^^^^^^^^^^^^^
Represents the signal that controls the field's counter increment control.
field -> incrsaturate/saturate
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Represents the internal 1-bit event signal that indicates whether the counter is saturated
at its saturation value.
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p......"},
{"name": "hwif_in..decr", "wave": "0101010"},
{"name": "<counter>", "wave": "=.=....", "data": [1,0]},
{"name": "<decrsaturate>", "wave": "0.1...."}
],
"foot": {
"text": "A 4-bit counter saturating"
}
}
field -> incrthreshold/threshold
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Represents the 1-bit event signal that indicates whether the counter has met or
exceeded its incrthreshold.
field -> incrvalue
^^^^^^^^^^^^^^^^^^
Represents the value that was assigned to this property.
field -> overflow
^^^^^^^^^^^^^^^^^
Represents the event signal that is asserted when the counter is about to wrap.
field -> decr
^^^^^^^^^^^^^
Represents the signal that controls the field's counter decrement control.
field -> decrsaturate
^^^^^^^^^^^^^^^^^^^^^
Represents the internal 1-bit event signal that indicates whether the counter is saturated
at its saturation value.
.. wavedrom::
{
"signal": [
{"name": "clk", "wave": "p......"},
{"name": "hwif_in..incr", "wave": "0101010"},
{"name": "<counter>", "wave": "=.=....", "data": [14,15]},
{"name": "<incrsaturate>", "wave": "0.1...."}
],
"foot": {
"text": "A 4-bit counter saturating"
}
}
field -> decrthreshold
^^^^^^^^^^^^^^^^^^^^^^
Represents the 1-bit event signal that indicates whether the counter has met or
exceeded its incrthreshold.
field -> decrvalue
^^^^^^^^^^^^^^^^^^
Represents the value that was assigned to this property.
field -> underflow
^^^^^^^^^^^^^^^^^^
Represents the event signal that is asserted when the counter is about to wrap.
--------------------------------------------------------------------------------
Field Interrupt Properties
--------------------------
field -> enable
^^^^^^^^^^^^^^^
Represents the value that was assigned to this property.
field -> mask
^^^^^^^^^^^^^
Represents the value that was assigned to this property.
field -> haltenable
^^^^^^^^^^^^^^^^^^^
Represents the value that was assigned to this property.
field -> haltmask
^^^^^^^^^^^^^^^^^
Represents the value that was assigned to this property.
--------------------------------------------------------------------------------
Register
--------
reg -> intr
^^^^^^^^^^^
References the register's ``hwif_out..intr`` signal.
reg -> halt
^^^^^^^^^^^
References the register's ``hwif_out..halt`` signal.

View File

@@ -1,28 +0,0 @@
Signal Properties
=================
.. note:: Any properties not explicitly listed here are either implicitly
supported, or are not relevant to the busdecoder exporter and are ignored.
activehigh/activelow
--------------------
Only relevant for signals used as resets. Defines the reset signal's polarity.
sync/async
----------
Only supported for signals used as resets to infer edge-sensitive reset.
Ignored in all other contexts.
cpuif_reset
-----------
Specify that this signal shall be used as alternate reset signal for the CPU
interface for this busdecoder.
field_reset
-----------
Specify that this signal is used as an alternate reset signal for all fields
instantiated in sub-hierarchies relative to this signal.

View File

@@ -1,155 +0,0 @@
External Components
===================
SystemRDL allows some component instances to be defined as "external" elements
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 busdecoder, the implementations of external components
are omitted and instead a user-interface is presented on the
``hwif_in``/``hwif_out`` i/o structs.
External component signals on the hardware interface closely follow the semantics
of the :ref:`cpuif_protocol`.
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 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.
External Registers
------------------
External registers can be useful if it is necessary to implement a register that
cannot easily be expressed using SystemRDL semantics. This could be a unique
access policy, or FIFO-like push/pop registers.
External registers are annotated as such by using the ``external`` keyword:
.. code-block:: systemrdl
// An internal register
my_reg int_reg;
// An external register
external my_reg ext_reg;
Request
^^^^^^^
hwif_out..req
When asserted, a read or write transfer will be initiated.
Qualifies all other request signals.
If the register is wide (``regwidth`` > ``accesswidth``), then the
``hwif_out..req`` will consist of multiple bits, representing the access
strobe for each sub-word of the register.
If the register does not contain any readable fields, this strobe will be
suppressed for read operations.
If the register does not contain any writable readable fields, this strobe
will be suppressed for write operations.
hwif_out..req_is_wr
If ``1``, denotes that the current transfer is a write. Otherwise transfer is
a read.
hwif_out..wr_data
Data to be written for the write transfer. This signal is ignored for read
transfers.
The bit-width of this signal always matches the CPUIF's bus width,
regardless of the regwidth.
If the register does not contain any writable fields, this signal is omitted.
hwif_out..wr_biten
Active-high bit-level write-enable strobes.
Only asserted bit positions will change the register value during a write
transfer.
If the register does not contain any writable fields, this signal is omitted.
Read Response
^^^^^^^^^^^^^
hwif_in..rd_ack
Single-cycle strobe indicating a read transfer has completed.
Qualifies all other read response signals.
If the transfer is always completed in the same cycle, it is acceptable to
tie this signal to ``hwif_out..req && !hwif_out..req_is_wr``.
If the register does not contain any readable fields, this signal is omitted.
hwif_in..rd_data
Read response data.
If the register does not contain any readable fields, this signal is omitted.
Write Response
^^^^^^^^^^^^^^
hwif_in..wr_ack
Single-cycle strobe indicating a write transfer has completed.
If the transfer is always completed in the same cycle, it is acceptable to
tie this signal to ``hwif_out..req && hwif_out..req_is_wr``.
If the register does not contain any writable fields, this signal is omitted.
External Blocks
---------------
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 busdecoder shall be aligned to their size.
Request
^^^^^^^
hwif_out..req
When asserted, a read or write transfer will be initiated.
Qualifies all other request signals.
hwif_out..addr
Byte-address of the transfer.
Address is always relative to the block's local addressing. i.e: The first
byte within an external block is represented as ``hwif_out..addr`` == 0,
regardless of the absolute address of the block.
hwif_out..req_is_wr
If ``1``, denotes that the current transfer is a write. Otherwise transfer is
a read.
hwif_out..wr_data
Data to be written for the write transfer. This signal is ignored for read
transfers.
The bit-width of this signal always matches the CPUIF's bus width,
regardless of the contents of the block.
hwif_out..wr_biten
Active-high bit-level write-enable strobes.
Only asserted bit positions will change the register value during a write
transfer.
Read Response
^^^^^^^^^^^^^
hwif_in..rd_ack
Single-cycle strobe indicating a read transfer has completed.
Qualifies all other read response signals.
hwif_in..rd_data
Read response data.
Write Response
^^^^^^^^^^^^^^
hwif_in..wr_ack
Single-cycle strobe indicating a write transfer has completed.

View File

@@ -1,3 +1,2 @@
pygments-systemrdl pygments-systemrdl
sphinxcontrib-wavedrom
sphinx-book-theme sphinx-book-theme

View File

@@ -1,79 +0,0 @@
Introduction
============
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).
Current UDP Support
-------------------
**Note:** PeakRDL-BusDecoder currently does not implement any User Defined Properties.
The focus of this tool is on bus decoding and address space routing rather than
field-level or register-level behavioral extensions.
If you need UDPs for field-level behaviors (such as buffering, signedness, or
fixed-point representations), consider using `PeakRDL-regblock <https://github.com/SystemRDL/PeakRDL-regblock>`_,
which is designed for comprehensive register block generation with extensive UDP support.
Extending with Custom UDPs
---------------------------
If your bus decoder design requires custom User Defined Properties, you can extend
PeakRDL-BusDecoder by:
1. **Define your UDP in SystemRDL**
Create a ``.rdl`` file that defines your custom properties:
.. code-block:: systemrdl
property my_custom_prop {
component = addrmap;
type = boolean;
};
2. **Implement the UDP in Python**
Create a Python UDP definition class in your project:
.. code-block:: python
from systemrdl.udp import UDPDefinition
class MyCustomUDP(UDPDefinition):
name = "my_custom_prop"
valid_components = {"addrmap"}
valid_type = bool
default = False
3. **Register the UDP with the compiler**
When using PeakRDL-BusDecoder programmatically, register your UDP:
.. code-block:: python
from systemrdl import RDLCompiler
from peakrdl_busdecoder import BusDecoderExporter
rdlc = RDLCompiler()
rdlc.register_udp(MyCustomUDP)
# Compile your RDL files
rdlc.compile_file("my_udp_defs.rdl")
rdlc.compile_file("my_design.rdl")
root = rdlc.elaborate()
# Export
exporter = BusDecoderExporter()
exporter.export(root, "output/")
4. **Access UDP values in your design**
UDP values can be accessed from nodes in the SystemRDL tree and used to
customize the generated bus decoder logic as needed.
For more information on creating User Defined Properties, see the
`SystemRDL Compiler documentation <https://systemrdl-compiler.readthedocs.io/en/stable/model_structure.html#user-defined-properties>`_.

View File

@@ -55,7 +55,6 @@ Documentation = "https://peakrdl-busdecoder.readthedocs.io/"
docs = [ docs = [
"pygments-systemrdl>=1.3.0", "pygments-systemrdl>=1.3.0",
"sphinx-book-theme>=1.1.4", "sphinx-book-theme>=1.1.4",
"sphinxcontrib-wavedrom>=3.0.4",
] ]
test = [ test = [
"parameterized>=0.9.0", "parameterized>=0.9.0",