Add signed/fixedpoint properties (#140)

* declared intwidth, fracwidth, and is_signed UDPs

* fix boolean type name in UDP definition

* generate hwif fields with fixedpoint indices

* make "counter" and "encode" properties mutualy exclusive with signed/fixedpoint

* add signed/unsigned to hwif

* improved fixedpoint error messages, added validation tests

* added fixedpoint tests

* fixedpoint/signed not allowed for signal components

* added signed/fixedpoint UDP docs

* handle single-bit fixedpoint numbers

* fix too many positional arguments lint

* changed spelling of fixedpoint to fixed-point

* use "logic" in place of "unsigned logic"

* split signed and fixedpoint docs, added examples

* allow enums with is_signed=false

* split signed and fixedpoint implementations

* assorted nits picked

* updated is_signed validation unit test
This commit is contained in:
Dana Sorensen
2025-05-15 09:48:44 -06:00
committed by GitHub
parent 62f66fb7ff
commit d2b4911d5f
20 changed files with 585 additions and 10 deletions

103
docs/udps/fixedpoint.rst Normal file
View File

@@ -0,0 +1,103 @@
.. _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 regblock.
Properties
----------
Fields can be declared as fixed-point numbers using the following two properties:
.. literalinclude:: ../../hdl-src/regblock_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-regblock, can be
enabled by compiling the following file along with your design:
:download:`regblock_udps.rdl <../../hdl-src/regblock_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.

View File

@@ -60,3 +60,26 @@ To enable these UDPs, compile this RDL file prior to the rest of your design:
- Enables an output strobe that is asserted on sw writes.
See: :ref:`extended_swacc`.
* - is_signed
- field
- boolean
- Defines the signedness of a field.
See: :ref:`signed`.
* - intwidth
- field
- unsigned integer
- Defines the number of integer bits in the fixed-point representation
of a field.
See: :ref:`fixedpoint`.
* - fracwidth
- field
- unsigned integer
- Defines the number of fractional bits in the fixed-point representation
of a field.
See: :ref:`fixedpoint`.

74
docs/udps/signed.rst Normal file
View File

@@ -0,0 +1,74 @@
.. _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 regblock.
Properties
----------
A field can be marked as signed using the following user-defined property:
.. literalinclude:: ../../hdl-src/regblock_udps.rdl
:lines: 40-44
This UDP definition, along with others supported by PeakRDL-regblock, can be
enabled by compiling the following file along with your design:
:download:`regblock_udps.rdl <../../hdl-src/regblock_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;