Update documentation to use correct repository name PeakRDL-BusDecoder and clarify project purpose (#7)
* Initial plan * Update documentation to use correct repository name PeakRDL-BusDecoder Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> * Update CONTRIBUTING.md and GitHub templates with correct repository name Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> * Update author to arnavsacheti and clarify bus decoder purpose in documentation Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> * Update author to 'Arnav Sacheti' and revise UDP documentation to reflect no current UDP support Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: arnavsacheti <36746504+arnavsacheti@users.noreply.github.com>
This commit is contained in:
@@ -1,49 +0,0 @@
|
||||
.. _extended_swacc:
|
||||
|
||||
Read/Write-specific swacc
|
||||
=========================
|
||||
|
||||
SystemRDL defines the ``swacc`` property, but it does not distinguish between
|
||||
read and write operations - it is asserted on *all* software accesses.
|
||||
Similarly, the spec defines ``swmod`` which gets asserted on software writes,
|
||||
but can also get asserted if the field has on-read side-effects.
|
||||
|
||||
What if you just wanted a plain and simple strobe that is asserted when software
|
||||
reads or writes a field? The ``rd_swacc`` and ``wr_swacc`` UDPs provide this
|
||||
functionality.
|
||||
|
||||
|
||||
Properties
|
||||
----------
|
||||
These UDP definitions, along with others supported by PeakRDL-busdecoder can be
|
||||
enabled by compiling the following file along with your design:
|
||||
:download:`busdecoder_udps.rdl <../../hdl-src/busdecoder_udps.rdl>`.
|
||||
|
||||
.. describe:: rd_swacc
|
||||
|
||||
If true, infers an output signal ``hwif_out..rd_swacc`` that is asserted
|
||||
when accessed by a software read operation. The output signal is asserted
|
||||
on the same clock cycle that the field is being sampled during the software
|
||||
read operation.
|
||||
|
||||
.. wavedrom::
|
||||
|
||||
{"signal": [
|
||||
{"name": "clk", "wave": "p...."},
|
||||
{"name": "hwif_in..next", "wave": "x.=x.", "data": ["D"]},
|
||||
{"name": "hwif_out..rd_swacc", "wave": "0.10."}
|
||||
]}
|
||||
|
||||
|
||||
.. describe:: wr_swacc
|
||||
|
||||
If true, infers an output signal ``hwif_out..wr_swacc`` that is asserted
|
||||
as the field is being modified by a software write operation.
|
||||
|
||||
.. wavedrom::
|
||||
|
||||
{"signal": [
|
||||
{"name": "clk", "wave": "p....."},
|
||||
{"name": "hwif_out..value", "wave": "=..=..", "data": ["old", "new"]},
|
||||
{"name": "hwif_out..wr_swacc", "wave": "0.10.."}
|
||||
]}
|
||||
@@ -1,103 +0,0 @@
|
||||
.. _fixedpoint:
|
||||
|
||||
Fixed-Point Fields
|
||||
==================
|
||||
|
||||
`Fixed-point <https://en.wikipedia.org/wiki/Fixed-point_arithmetic>`_ numbers
|
||||
can be used to efficiently represent real numbers using integers. Fixed-point
|
||||
numbers consist of some combination of integer bits and fractional bits. The
|
||||
number of integer/fractional bits is usually implicitly tracked (not stored)
|
||||
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 busdecoder.
|
||||
|
||||
Properties
|
||||
----------
|
||||
Fields can be declared as fixed-point numbers using the following two properties:
|
||||
|
||||
.. literalinclude:: ../../hdl-src/busdecoder_udps.rdl
|
||||
:lines: 46-54
|
||||
|
||||
The :ref:`is_signed<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-busdecoder, can be
|
||||
enabled by compiling the following file along with your design:
|
||||
:download:`busdecoder_udps.rdl <../../hdl-src/busdecoder_udps.rdl>`.
|
||||
|
||||
.. describe:: intwidth
|
||||
|
||||
* The ``intwidth`` property defines the number of integer bits in the
|
||||
fixed-point representation (including the sign bit, if present).
|
||||
|
||||
.. describe:: fracwidth
|
||||
|
||||
* The ``fracwidth`` property defines the number of fractional bits in the
|
||||
fixed-point representation.
|
||||
|
||||
Representable Numbers
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The range of representable real numbers is summarized in the table below.
|
||||
|
||||
.. list-table:: Representable Numbers
|
||||
:header-rows: 1
|
||||
|
||||
* - Signedness
|
||||
- Minimum Value
|
||||
- Maximum Value
|
||||
- Step Size
|
||||
|
||||
* - Unsigned
|
||||
- :math:`0`
|
||||
- :math:`2^{\mathrm{intwidth}} - 2^{-\mathrm{fracwidth}}`
|
||||
- :math:`2^{-\mathrm{fracwidth}}`
|
||||
|
||||
* - Signed
|
||||
- :math:`-2^{\mathrm{intwidth}-1}`
|
||||
- :math:`2^{\mathrm{intwidth}-1} - 2^{-\mathrm{fracwidth}}`
|
||||
- :math:`2^{-\mathrm{fracwidth}}`
|
||||
|
||||
SystemVerilog Types
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When either ``intwidth`` or ``fracwidth`` are defined for a field, that field's
|
||||
type in the generated SystemVerilog ``hwif`` struct is
|
||||
``logic (signed) [intwidth-1:-fracwidth]``. The bit at index :math:`i` contributes
|
||||
a weight of :math:`2^i` to the real number represented.
|
||||
|
||||
Other Rules
|
||||
^^^^^^^^^^^
|
||||
* Only one of ``intwidth`` or ``fracwidth`` need be defined. The other is
|
||||
inferred from the field bit width.
|
||||
* The bit width of the field shall be equal to ``intwidth`` + ``fracwidth``.
|
||||
* If both ``intwidth`` and ``fracwidth`` are defined for a field, it is an
|
||||
error if their sum does not equal the bit width of the field.
|
||||
* Either ``fracwidth`` or ``intwidth`` can be a negative integer. Because
|
||||
SystemRDL does not have a signed integer type, the only way to achieve
|
||||
this is to define one of the widths as larger than the bit width of the
|
||||
component so that the other width is inferred as a negative number.
|
||||
* The properties defined above are mutually exclusive with the ``counter``
|
||||
property.
|
||||
* The properties defined above are mutually exclusive with the ``encode``
|
||||
property.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
A 12-bit signed fixed-point field with 4 integer bits and 8 fractional bits
|
||||
can be declared with
|
||||
|
||||
.. code-block:: systemrdl
|
||||
:emphasize-lines: 3, 4
|
||||
|
||||
field {
|
||||
sw=rw; hw=r;
|
||||
intwidth = 4;
|
||||
is_signed;
|
||||
} fixedpoint_num[11:0] = 0;
|
||||
|
||||
This field can represent values from -8.0 to 7.99609375
|
||||
in steps of 0.00390625.
|
||||
@@ -4,82 +4,76 @@ 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). The
|
||||
PeakRDL-busdecoder tool understands several UDPs that are described in this
|
||||
section.
|
||||
the language to be extended using "User Defined Properties" (UDPs).
|
||||
|
||||
To enable these UDPs, compile this RDL file prior to the rest of your design:
|
||||
:download:`busdecoder_udps.rdl <../../hdl-src/busdecoder_udps.rdl>`.
|
||||
Current UDP Support
|
||||
-------------------
|
||||
|
||||
.. list-table:: Summary of UDPs
|
||||
:header-rows: 1
|
||||
**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.
|
||||
|
||||
* - Name
|
||||
- Component
|
||||
- Type
|
||||
- Description
|
||||
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.
|
||||
|
||||
* - buffer_reads
|
||||
- reg
|
||||
- boolean
|
||||
- If set, reads from the register are double-buffered.
|
||||
Extending with Custom UDPs
|
||||
---------------------------
|
||||
|
||||
See: :ref:`read_buffering`.
|
||||
If your bus decoder design requires custom User Defined Properties, you can extend
|
||||
PeakRDL-BusDecoder by:
|
||||
|
||||
* - rbuffer_trigger
|
||||
- reg
|
||||
- reference
|
||||
- Defines the buffered read load trigger.
|
||||
1. **Define your UDP in SystemRDL**
|
||||
|
||||
See: :ref:`read_buffering`.
|
||||
Create a ``.rdl`` file that defines your custom properties:
|
||||
|
||||
* - buffer_writes
|
||||
- reg
|
||||
- boolean
|
||||
- If set, writes to the register are double-buffered.
|
||||
.. code-block:: systemrdl
|
||||
|
||||
See: :ref:`write_buffering`.
|
||||
property my_custom_prop {
|
||||
component = addrmap;
|
||||
type = boolean;
|
||||
};
|
||||
|
||||
* - wbuffer_trigger
|
||||
- reg
|
||||
- reference
|
||||
- Defines the buffered write commit trigger.
|
||||
2. **Implement the UDP in Python**
|
||||
|
||||
See: :ref:`write_buffering`.
|
||||
Create a Python UDP definition class in your project:
|
||||
|
||||
* - rd_swacc
|
||||
- field
|
||||
- boolean
|
||||
- Enables an output strobe that is asserted on sw reads.
|
||||
.. code-block:: python
|
||||
|
||||
See: :ref:`extended_swacc`.
|
||||
from systemrdl.udp import UDPDefinition
|
||||
|
||||
* - wr_swacc
|
||||
- field
|
||||
- boolean
|
||||
- Enables an output strobe that is asserted on sw writes.
|
||||
class MyCustomUDP(UDPDefinition):
|
||||
name = "my_custom_prop"
|
||||
valid_components = {"addrmap"}
|
||||
valid_type = bool
|
||||
default = False
|
||||
|
||||
See: :ref:`extended_swacc`.
|
||||
3. **Register the UDP with the compiler**
|
||||
|
||||
* - is_signed
|
||||
- field
|
||||
- boolean
|
||||
- Defines the signedness of a field.
|
||||
When using PeakRDL-BusDecoder programmatically, register your UDP:
|
||||
|
||||
See: :ref:`signed`.
|
||||
.. code-block:: python
|
||||
|
||||
* - intwidth
|
||||
- field
|
||||
- unsigned integer
|
||||
- Defines the number of integer bits in the fixed-point representation
|
||||
of a field.
|
||||
from systemrdl import RDLCompiler
|
||||
from peakrdl_busdecoder import BusDecoderExporter
|
||||
|
||||
See: :ref:`fixedpoint`.
|
||||
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/")
|
||||
|
||||
* - fracwidth
|
||||
- field
|
||||
- unsigned integer
|
||||
- Defines the number of fractional bits in the fixed-point representation
|
||||
of a field.
|
||||
4. **Access UDP values in your design**
|
||||
|
||||
See: :ref:`fixedpoint`.
|
||||
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>`_.
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
.. _read_buffering:
|
||||
|
||||
Read-buffered Registers
|
||||
=======================
|
||||
|
||||
Read buffering is a mechanism that allows for software accesses to read a
|
||||
snapshot of one or more registers atomically. When enabled on a register, a
|
||||
read buffer will latch the state of its fields when triggered such that software
|
||||
can read a coherent snapshot of one or more registers' value.
|
||||
|
||||
Some examples of when this is useful:
|
||||
* A wide 64-bit status register needs to be read atomically, but the CPU
|
||||
interface is only 32-bits.
|
||||
* Software needs to be able to read the state of multiple registers
|
||||
atomically.
|
||||
* A hardware event latches the software-visible state of one or more
|
||||
registers.
|
||||
|
||||
.. figure:: ../diagrams/rbuf.png
|
||||
|
||||
|
||||
Properties
|
||||
----------
|
||||
The behavior of read-buffered registers is defined using the following two
|
||||
properties:
|
||||
|
||||
.. literalinclude:: ../../hdl-src/busdecoder_udps.rdl
|
||||
:lines: 10-18
|
||||
|
||||
These UDP definitions, along with others supported by PeakRDL-busdecoder can be
|
||||
enabled by compiling the following file along with your design:
|
||||
:download:`busdecoder_udps.rdl <../../hdl-src/busdecoder_udps.rdl>`.
|
||||
|
||||
.. describe:: buffer_reads
|
||||
|
||||
* Assigned value is a boolean.
|
||||
* If true, enables double-buffering of software reads of this register.
|
||||
* The read buffer will load the register's field values when its trigger
|
||||
event is asserted.
|
||||
* Unless specified otherwise, the buffer trigger occurs when the lowest
|
||||
address of the buffered register is read.
|
||||
* When read by software the data returned is from the buffer contents, not
|
||||
directly from the register's fields.
|
||||
|
||||
.. describe:: rbuffer_trigger
|
||||
|
||||
* Assigned value is a reference to a register, single-bit field, signal, or
|
||||
single-bit property.
|
||||
* Controls when the double-buffer loads the register's field vaues into the
|
||||
buffer storage element.
|
||||
* If reference is a single-bit value (signal, field, property reference),
|
||||
then the assertion of that value triggers the buffer to be evicted.
|
||||
* Signal references shall have either activehigh/activelow property set to
|
||||
define the polarity.
|
||||
* If the reference is a reg, then buffer is loaded when the register's
|
||||
lowest address is read.
|
||||
|
||||
Other Rules
|
||||
^^^^^^^^^^^
|
||||
* It is an error to set ``buffer_reads`` if the register does not contain any
|
||||
readable fields
|
||||
* If ``buffer_reads`` is false, then anything assigned to ``rbuffer_trigger``
|
||||
is ignored.
|
||||
* The buffered register and the trigger reference shall both be within the same
|
||||
internal device. ie: one cannot be in an external scope with respect to the
|
||||
other.
|
||||
* Unless it is a register, the reference assigned to ``rbuffer_trigger`` shall
|
||||
represent a single bit.
|
||||
* The software read operation considered to take place when the buffer is loaded.
|
||||
This influences the behavior of properties like ``swmod`` and ``swacc`` -
|
||||
they are not asserted until the register's fields are actually sampled by the
|
||||
buffer.
|
||||
* If a read-buffered register is wide (accesswidth < regwidth) and is its own
|
||||
trigger, the first sub-word's buffer is bypassed to ensure the first read
|
||||
operation is atomically coherent with the rest of the sampled register.
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
Below are several examples of what you can do with registers that are
|
||||
read-buffered.
|
||||
|
||||
Wide Atomic Register
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
In this example, a wide 64-bit read-clear counter is implemented.
|
||||
Without read-buffering, it is impossible to coherently read the state of the
|
||||
counter using a 32-bit CPU interface without risking a discontinuity. With
|
||||
read-buffering enabled, the read of the lower half of the register will trigger
|
||||
the upper half's value to be latched. A subsequent software access can then
|
||||
coherently read the rest of the register's buffered value.
|
||||
|
||||
.. code-block:: systemrdl
|
||||
:emphasize-lines: 4
|
||||
|
||||
reg {
|
||||
regwidth = 64;
|
||||
accesswidth = 32;
|
||||
buffer_reads = true;
|
||||
field {
|
||||
sw=r; hw=na;
|
||||
counter;
|
||||
incr;
|
||||
} my_counter[63:0] = 0;
|
||||
};
|
||||
|
||||
|
||||
Atomic Group of Registers
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Perhaps you have a group of registers that monitor some rapidly-changing state
|
||||
within your design. Using the ``rbuffer_trigger`` property, you can define which
|
||||
register read operation triggers the buffered registers' values to be latched.
|
||||
|
||||
.. code-block:: systemrdl
|
||||
:emphasize-lines: 11-14
|
||||
|
||||
reg my_status_reg {
|
||||
field {
|
||||
sw=r; hw=w;
|
||||
} value[31:0];
|
||||
};
|
||||
|
||||
my_status_reg status1;
|
||||
my_status_reg status2;
|
||||
my_status_reg status3;
|
||||
|
||||
status2->buffer_reads = true;
|
||||
status2->rbuffer_trigger = status1;
|
||||
status3->buffer_reads = true;
|
||||
status3->rbuffer_trigger = status1;
|
||||
|
||||
In this example, when software reads status1, this triggers status2-status3
|
||||
registers to latch their values into their respective read buffers. Subsequent
|
||||
reads to status2 and status3 return the value that these registers contained at
|
||||
the moment that status1 was read. This makes it possible for software to read
|
||||
the state of multiple registers atomically.
|
||||
|
||||
|
||||
Externally Triggered Register Sampling
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
If needed, an external trigger can be used to load a read buffer.
|
||||
This can be useful if precise timing of software's view of the register state is
|
||||
required.
|
||||
|
||||
.. code-block:: systemrdl
|
||||
:emphasize-lines: 14-15
|
||||
|
||||
reg my_status_reg {
|
||||
buffer_reads = true;
|
||||
field {
|
||||
sw=r; hw=w;
|
||||
} value[31:0];
|
||||
};
|
||||
|
||||
my_status_reg status1;
|
||||
my_status_reg status2;
|
||||
|
||||
signal {
|
||||
activehigh;
|
||||
} trigger_signal;
|
||||
status1->rbuffer_trigger = trigger_signal;
|
||||
status2->rbuffer_trigger = trigger_signal;
|
||||
|
||||
When ``hwif_in..trigger_signal`` is asserted, the state of registers ``status1``
|
||||
and ``status2`` is buffered.
|
||||
@@ -1,74 +0,0 @@
|
||||
.. _signed:
|
||||
|
||||
Signed Fields
|
||||
=============
|
||||
|
||||
SystemRDL does not natively provide a way to mark fields as signed or unsigned.
|
||||
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 busdecoder.
|
||||
|
||||
Properties
|
||||
----------
|
||||
A field can be marked as signed using the following user-defined property:
|
||||
|
||||
.. literalinclude:: ../../hdl-src/busdecoder_udps.rdl
|
||||
:lines: 40-44
|
||||
|
||||
This UDP definition, along with others supported by PeakRDL-busdecoder, can be
|
||||
enabled by compiling the following file along with your design:
|
||||
:download:`busdecoder_udps.rdl <../../hdl-src/busdecoder_udps.rdl>`.
|
||||
|
||||
.. describe:: is_signed
|
||||
|
||||
* Assigned value is a boolean.
|
||||
* If true, the hardware interface field will have the type
|
||||
``logic signed [width-1:0]``.
|
||||
* If false or not defined for a field, the hardware interface field will
|
||||
have the type ``logic [width-1:0]``, which is unsigned by definition.
|
||||
|
||||
Other Rules
|
||||
^^^^^^^^^^^
|
||||
|
||||
* ``is_signed=true`` is mutually exclusive with the ``counter`` property.
|
||||
* ``is_signed=true`` is mutually exclusive with the ``encode`` property.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Below are some examples of fields with different signedness.
|
||||
|
||||
Signed Fields
|
||||
^^^^^^^^^^^^^
|
||||
.. code-block:: systemrdl
|
||||
:emphasize-lines: 3, 8
|
||||
|
||||
field {
|
||||
sw=rw; hw=r;
|
||||
is_signed;
|
||||
} signed_num[63:0] = 0;
|
||||
|
||||
field {
|
||||
sw=r; hw=w;
|
||||
is_signed = true;
|
||||
} another_signed_num[19:0] = 20'hFFFFF; // -1
|
||||
|
||||
SystemRDL's own integer type is always unsigned. In order to specify a negative
|
||||
reset value, the two's complement value must be used as shown in the second
|
||||
example above.
|
||||
|
||||
Unsigned Fields
|
||||
^^^^^^^^^^^^^^^
|
||||
.. code-block:: systemrdl
|
||||
:emphasize-lines: 3, 8
|
||||
|
||||
field {
|
||||
sw=rw; hw=r;
|
||||
// fields are unsigned by default
|
||||
} unsigned_num[63:0] = 0;
|
||||
|
||||
field {
|
||||
sw=r; hw=w;
|
||||
is_signed = false;
|
||||
} another_unsigned_num[19:0] = 0;
|
||||
@@ -1,183 +0,0 @@
|
||||
.. _write_buffering:
|
||||
|
||||
Write-buffered Registers
|
||||
========================
|
||||
|
||||
In order to support larger software write accesses that are atomic, the
|
||||
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:
|
||||
* You need to have software update a wide 64-bit register atomically, but
|
||||
the CPU interface is only 32-bits.
|
||||
* Software needs to be able to write multiple registers such that the
|
||||
hardware is updated atomically.
|
||||
* Software can pre-load one or more registers with their next value, and
|
||||
trigger the update via an external hardware signal.
|
||||
|
||||
If a register is write-buffered, a holding buffer stage is inserted between the
|
||||
decode logic and the field logic. This effectively defers any software write
|
||||
operations to that register until a trigger event occurs that releases it.
|
||||
Write buffering storage is unique to each register that enables it.
|
||||
If a register is not write buffered, this buffer stage is bypassed.
|
||||
|
||||
.. figure:: ../diagrams/wbuf.png
|
||||
|
||||
|
||||
Properties
|
||||
----------
|
||||
The behavior of write-buffered registers is defined using the following two
|
||||
properties:
|
||||
|
||||
.. literalinclude:: ../../hdl-src/busdecoder_udps.rdl
|
||||
:lines: 20-28
|
||||
|
||||
These UDP definitions, along with others supported by PeakRDL-busdecoder can be
|
||||
enabled by compiling the following file along with your design:
|
||||
:download:`busdecoder_udps.rdl <../../hdl-src/busdecoder_udps.rdl>`.
|
||||
|
||||
.. describe:: buffer_writes
|
||||
|
||||
* Assigned value is a boolean.
|
||||
* If true, enables double-buffering of writes to this register.
|
||||
* Any software write operation to a buffered register is held back in a
|
||||
storage element unique to the register.
|
||||
* The software write operation is committed to the register once triggered
|
||||
to do so.
|
||||
* Unless specified otherwise, the buffer trigger occurs when the highest
|
||||
address of the buffered register is written.
|
||||
|
||||
.. describe:: wbuffer_trigger
|
||||
|
||||
* Assigned value is a reference to a register, single-bit field, signal,
|
||||
or single-bit property.
|
||||
* Controls when the double-buffer commits the software write operation to
|
||||
the register's fields.
|
||||
* If reference is a single-bit value (signal, field, property reference),
|
||||
then the assertion of that value triggers the buffer to be evicted.
|
||||
* Signal references shall have either activehigh/activelow property set to
|
||||
define the polarity.
|
||||
* If the reference is a reg, then buffer is evicted when the register's
|
||||
highest address is written.
|
||||
|
||||
|
||||
Other Rules
|
||||
^^^^^^^^^^^
|
||||
* It is an error to set ``buffer_writes`` if the register does not contain any
|
||||
writable fields
|
||||
* If ``buffer_writes`` is false, then anything assigned to ``wbuffer_trigger``
|
||||
is ignored.
|
||||
* The buffered register and the trigger reference shall both be within the
|
||||
same internal device. ie: one cannot be in an external scope with respect to
|
||||
the other.
|
||||
* Unless it is a register, the reference assigned to ``wbuffer_trigger`` shall
|
||||
represent a single bit.
|
||||
* If a buffered register was not written, any trigger events are ignored.
|
||||
* It is valid for a buffered register to be partially written (either via
|
||||
write strobes, or partial addressing).
|
||||
* The software write operation is not considered to take place until the
|
||||
buffer is evicted by the trigger. This influences the behavior of properties
|
||||
like ``swmod`` and ``swacc`` - they are not asserted until the register's
|
||||
fields are actually written by the buffer.
|
||||
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
Below are several examples of what you can do with registers that are
|
||||
write-buffered.
|
||||
|
||||
Wide Atomic Register
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
Without write-buffering, it is impossible to update the state of a 64-bit
|
||||
register using a 32-bit CPU interface in a single clock-cycle.
|
||||
In this example, it still requires two write-cycles to update the register, but
|
||||
the register's storage element is not updated until both sub-words are written.
|
||||
Upon writing the 2nd sub-word (the higher byte address), the write data for both
|
||||
write cycles are committed to the register's storage element together on the
|
||||
same clock cycle. The register is updated atomically.
|
||||
|
||||
.. code-block:: systemrdl
|
||||
:emphasize-lines: 4
|
||||
|
||||
reg {
|
||||
regwidth = 64;
|
||||
accesswidth = 32;
|
||||
buffer_writes = true;
|
||||
field {
|
||||
sw=rw; hw=r;
|
||||
} my_field[63:0] = 0;
|
||||
};
|
||||
|
||||
|
||||
Atomic Group of Registers
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Perhaps you have a group of registers that need their state to be updated
|
||||
atomically. Using the ``wbuffer_trigger`` property, you can define which
|
||||
register write operation triggers the group to be updated.
|
||||
|
||||
|
||||
.. code-block:: systemrdl
|
||||
:emphasize-lines: 2, 18-20
|
||||
|
||||
reg my_buffered_reg {
|
||||
buffer_writes = true;
|
||||
field {
|
||||
sw=rw; hw=r;
|
||||
} my_field[31:0] = 0;
|
||||
};
|
||||
|
||||
my_buffered_reg reg1;
|
||||
my_buffered_reg reg2;
|
||||
my_buffered_reg reg3;
|
||||
|
||||
reg {
|
||||
field {
|
||||
sw=rw; hw=r;
|
||||
} my_field[31:0] = 0;
|
||||
} reg4;
|
||||
|
||||
reg1->wbuffer_trigger = reg4;
|
||||
reg2->wbuffer_trigger = reg4;
|
||||
reg3->wbuffer_trigger = reg4;
|
||||
|
||||
|
||||
In this example software may pre-write information into reg1-reg3, but the
|
||||
register write operations do not take effect until software also writes to reg4.
|
||||
The write operation to reg4 triggers the buffered data to be committed to
|
||||
reg1-reg3. This is guaranteed to occur on the same clock-cycle.
|
||||
|
||||
|
||||
Externally Triggered Register Update
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Some applications may require precise timing for when a register (or group of
|
||||
registers) update their value. Often software cannot offer such timing
|
||||
precision.
|
||||
|
||||
In this example, the trigger event is bound to an external signal. When
|
||||
asserted, any pending write operation the buffered register will be committed.
|
||||
The hwif_out value presents the new register state on the clock cycle after the
|
||||
trigger is asserted.
|
||||
|
||||
.. code-block:: systemrdl
|
||||
:emphasize-lines: 2, 11-13
|
||||
|
||||
reg my_buffered_reg {
|
||||
buffer_writes = true;
|
||||
field {
|
||||
sw=rw; hw=r;
|
||||
} my_field[31:0] = 0;
|
||||
};
|
||||
|
||||
my_buffered_reg reg1;
|
||||
my_buffered_reg reg2;
|
||||
|
||||
signal {
|
||||
activehigh;
|
||||
} trigger_signal;
|
||||
reg1->wbuffer_trigger = trigger_signal;
|
||||
reg2->wbuffer_trigger = trigger_signal;
|
||||
|
||||
After software writes to ``reg1`` & ``reg2``, the written data is held back in
|
||||
the write buffer until ``hwif_in..trigger_signal`` is asserted by the hardware.
|
||||
Reference in New Issue
Block a user