Add precedence test. fixup docs

This commit is contained in:
Alex Mykyta
2022-02-28 22:05:24 -08:00
parent 404e7e8365
commit 9295cbb7c0
14 changed files with 164 additions and 55 deletions

View File

@@ -2,10 +2,6 @@
[![build](https://github.com/SystemRDL/PeakRDL-regblock/workflows/build/badge.svg)](https://github.com/SystemRDL/PeakRDL-regblock/actions?query=workflow%3Abuild+branch%3Amain) [![build](https://github.com/SystemRDL/PeakRDL-regblock/workflows/build/badge.svg)](https://github.com/SystemRDL/PeakRDL-regblock/actions?query=workflow%3Abuild+branch%3Amain)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/peakrdl-regblock.svg)](https://pypi.org/project/peakrdl-regblock) [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/peakrdl-regblock.svg)](https://pypi.org/project/peakrdl-regblock)
# IMPORTANT
This project has no official releases yet and is still under active development!
# PeakRDL-regblock # PeakRDL-regblock
Generate SystemVerilog RTL that implements a register block from compiled SystemRDL input. Generate SystemVerilog RTL that implements a register block from compiled SystemRDL input.

View File

@@ -142,10 +142,29 @@ X Warn/error on any signal with cpuif_reset set, that is not in the top-level
addrmap. At the very least, warn that it will be ignored addrmap. At the very least, warn that it will be ignored
! "bridge" addrmap not supported X "bridge" addrmap not supported
export shall refuse to process an addrmap marked as a "bridge" export shall refuse to process an addrmap marked as a "bridge"
Only need to check top-level. Compiler will enforce that child nodes arent bridges Only need to check top-level. Compiler will enforce that child nodes arent bridges
X regwidth/accesswidth is sane
X accesswidth == regwidth
Enforce this for now. Dont feel like supporting fancy modes yet
X regwidth < accesswidth
This is illegal and is enforced by the compiler.
X regwidth > accesswidth
Need to extend address decode strobes to have multiple bits
this is where looking at endianness matters to determine field placement
Dont feel like supporting this yet
X constant regwidth?
For now, probably limit to only allow the same regwidth everywhere?
X Do not allow unaligned addresses
All offsets & strides shall be a multiple of the regwidth used
X each reg needs to be aligned to its width
X each regfile/addrmap/stride shall be aligned to the largest regwidth it encloses
! async data signals ! async data signals
Only supporting async signals if they are exclusively used in resets. Only supporting async signals if they are exclusively used in resets.
Anything else declared as "async" shall emit a warning that it is ignored Anything else declared as "async" shall emit a warning that it is ignored
@@ -154,27 +173,6 @@ X Warn/error on any signal with cpuif_reset set, that is not in the top-level
! Error if a property references a non-signal component, or property reference from ! Error if a property references a non-signal component, or property reference from
outside the export hierarchy outside the export hierarchy
! regwidth/accesswidth is sane
! accesswidth == regwidth
Enforce this for now. Dont feel like supporting fancy modes yet
X regwidth < accesswidth
This is illegal and is enforced by the compiler.
! regwidth > accesswidth
Need to extend address decode strobes to have multiple bits
this is where looking at endinaness matters to determine field placement
Dont feel like supporting this yet
! constant regwidth?
For now, probably limit to only allow the same regwidth everywhere?
! Do not allow unaligned addresses
All offsets & strides shall be a multiple of the regwidth used
- each reg needs to be aligned to its width
- each regfile/addrmap/stride shall be aligned to the largest regwidth it encloses
--> Should i promote this check to the compiler? At least as a warnable condition
Currently i think I only do the more stringent case of block alignment.
! Add warning for sticky race condition ! Add warning for sticky race condition
stickybit and other similar situations generally should use hw precedence. stickybit and other similar situations generally should use hw precedence.
Emit a warning as appropriate Emit a warning as appropriate

View File

@@ -48,4 +48,4 @@ For example, a simple design such as:
hwif_in.my_reg[1].my_field.we hwif_in.my_reg[1].my_field.we
For brevity in this documentation, hwif features will be described using shorthand For brevity in this documentation, hwif features will be described using shorthand
notation that omits the hierarchcal path: ``hwif_out..<feature>`` notation that omits the hierarchical path: ``hwif_out..<feature>``

View File

@@ -2,7 +2,7 @@ Introduction
============ ============
PeakRDL-regblock is a free and open-source control & status register (CSR) compiler. PeakRDL-regblock is a free and open-source control & status register (CSR) compiler.
This code generator that will translate your SystemRDL register descripton into This code generator that will translate your SystemRDL register description into
a synthesizable SystemVerilog RTL module that can be easily instantiated into a synthesizable SystemVerilog RTL module that can be easily instantiated into
your hardware design. your hardware design.
@@ -16,16 +16,11 @@ your hardware design.
Installing Installing
---------- ----------
.. important::
This project has no official releases yet and is still under active development!
Install from `PyPi`_ using pip Install from `PyPi`_ using pip
.. code-block:: bash .. code-block:: bash
# NOT RELEASED YET python3 -m pip install peakrdl-regblock
# python3 -m pip install peakrdl-regblock
.. _PyPi: https://pypi.org/project/peakrdl-regblock .. _PyPi: https://pypi.org/project/peakrdl-regblock

View File

@@ -29,3 +29,15 @@ No partial writes
Some protocols describe byte-level write strobes. These are not supported yet. Some protocols describe byte-level write strobes. These are not supported yet.
All write transfers must access the entire register width. All write transfers must access the entire register width.
Register width, Access width and CPUIF bus width
------------------------------------------------
To keep the initial architecture simpler, currently ``regwidth``, ``accesswidth``
and the resulting CPU bus width has some limitations:
* All registers shall have ``regwidth`` == ``accesswidth``
* ``regwidth`` shall be the same across all registers within the block being exported.
* The CPU interface's bus width is statically determined by the ``regwidth`` used.
I have plans to remove these restrictions and allow for more flexibility in the future.

View File

@@ -533,7 +533,7 @@ paritycheck
precedence precedence
^^^^^^^^^^ ^^^^^^^^^^
|EX| |OK|
reset reset
^^^^^ ^^^^^

View File

@@ -7,19 +7,19 @@ Signal Properties
activehigh/activelow activehigh/activelow
-------------------- --------------------
|EX| |OK|
sync/async sync/async
---------- ----------
|EX| |OK|
Only supported for signals used as resets to infer edge-sensitive reset. Only supported for signals used as resets to infer edge-sensitive reset.
Ignored in all other contexts. Ignored in all other contexts.
cpuif_reset cpuif_reset
----------- -----------
|EX| |OK|
field_reset field_reset
----------- -----------
|EX| |OK|

View File

@@ -1 +1 @@
__version__ = "0.1.0-a1" __version__ = "0.1.0"

View File

@@ -1,11 +1,11 @@
from typing import TYPE_CHECKING, Set from typing import TYPE_CHECKING, Set, List
from collections import OrderedDict from collections import OrderedDict
from systemrdl.walker import RDLListener, RDLWalker from systemrdl.walker import RDLListener, RDLWalker
from systemrdl.node import AddrmapNode, SignalNode from systemrdl.node import SignalNode, AddressableNode
if TYPE_CHECKING: if TYPE_CHECKING:
from systemrdl.node import Node, RegNode, MemNode, FieldNode from systemrdl.node import Node, RegNode, FieldNode
from .exporter import RegblockExporter from .exporter import RegblockExporter
@@ -21,6 +21,9 @@ class DesignScanner(RDLListener):
self.cpuif_data_width = 0 self.cpuif_data_width = 0
self.msg = exp.top_node.env.msg self.msg = exp.top_node.env.msg
# Keep track of max regwidth encountered in a given block
self.max_regwidth_stack = [] # type: List[int]
# Collections of signals that were actually referenced by the design # Collections of signals that were actually referenced by the design
self.in_hier_signal_paths = set() # type: Set[str] self.in_hier_signal_paths = set() # type: Set[str]
self.out_of_hier_signals = OrderedDict() # type: OrderedDict[str, SignalNode] self.out_of_hier_signals = OrderedDict() # type: OrderedDict[str, SignalNode]
@@ -49,6 +52,14 @@ class DesignScanner(RDLListener):
# collect out-of-hier field_reset, if any # collect out-of-hier field_reset, if any
self._get_out_of_hier_field_reset() self._get_out_of_hier_field_reset()
# Ensure addrmap is not a bridge. This concept does not make sense for
# terminal components.
if self.exp.top_node.get_property('bridge'):
self.msg.error(
"Regblock generator does not support exporting bridge address maps",
self.exp.top_node.inst.property_src_ref.get('bridge', self.exp.top_node.inst.inst_src_ref)
)
RDLWalker().walk(self.exp.top_node, self) RDLWalker().walk(self.exp.top_node, self)
if self.msg.had_error: if self.msg.had_error:
self.msg.fatal( self.msg.fatal(
@@ -57,11 +68,51 @@ class DesignScanner(RDLListener):
raise ValueError raise ValueError
def enter_Reg(self, node: 'RegNode') -> None: def enter_Reg(self, node: 'RegNode') -> None:
regwidth = node.get_property('regwidth')
self.max_regwidth_stack[-1] = max(self.max_regwidth_stack[-1], regwidth)
# The CPUIF's bus width is sized according to the largest register in the design # The CPUIF's bus width is sized according to the largest register in the design
self.cpuif_data_width = max(self.cpuif_data_width, node.get_property('regwidth')) # TODO: make this user-overridable once more flexible regwidth/accesswidths are supported
self.cpuif_data_width = max(self.cpuif_data_width, regwidth)
# TODO: remove this limitation eventually
if regwidth != self.cpuif_data_width:
self.msg.error(
"register blocks with non-uniform regwidths are not supported yet",
node.inst.property_src_ref.get('regwidth', node.inst.inst_src_ref)
)
# TODO: remove this limitation eventually
if regwidth != node.get_property('accesswidth'):
self.msg.error(
"Registers that have an accesswidth different from the register width are not supported yet",
node.inst.property_src_ref.get('accesswidth', node.inst.inst_src_ref)
)
def enter_AddressableComponent(self, node: AddressableNode) -> None:
self.max_regwidth_stack.append(0)
def exit_AddressableComponent(self, node: AddressableNode) -> None:
max_block_regwidth = self.max_regwidth_stack.pop()
if self.max_regwidth_stack:
self.max_regwidth_stack[-1] = max(self.max_regwidth_stack[-1], max_block_regwidth)
alignment = int(max_block_regwidth / 8)
if (node.raw_address_offset % alignment) != 0:
self.msg.error(
f"Unaligned registers are not supported. Address offset of instance '{node.inst_name}' must be a multiple of {alignment}",
node.inst.inst_src_ref
)
if node.is_array and (node.array_stride % alignment) != 0:
self.msg.error(
f"Unaligned registers are not supported. Address stride of instance array '{node.inst_name}' must be a multiple of {alignment}",
node.inst.inst_src_ref
)
def enter_Component(self, node: 'Node') -> None: def enter_Component(self, node: 'Node') -> None:
if not isinstance(node, AddrmapNode) and node.external: if node.external and (node != self.exp.top_node):
self.msg.error( self.msg.error(
"Exporter does not support external components", "Exporter does not support external components",
node.inst.inst_src_ref node.inst.inst_src_ref
@@ -93,9 +144,3 @@ class DesignScanner(RDLListener):
self.out_of_hier_signals[path] = value self.out_of_hier_signals[path] = value
else: else:
self.in_hier_signal_paths.add(path) self.in_hier_signal_paths.add(path)
def enter_Mem(self, node: 'MemNode') -> None:
self.msg.error(
"Cannot export a register block that contains a memory",
node.inst.inst_src_ref
)

View File

@@ -6,10 +6,16 @@
Testcases require an installation of the Questa simulator, and for `vlog` & `vsim` Testcases require an installation of the Questa simulator, and for `vlog` & `vsim`
commands to be visible via the PATH environment variable. commands to be visible via the PATH environment variable.
*Questa - Intel FPGA Starter Edition* can be downloaded for free from *Questa - Intel FPGA Starter Edition* can be downloaded for free from Intel:
https://fpgasoftware.intel.com/ and is sufficient to run unit tests. You will need * Go to https://www.intel.com/content/www/us/en/collections/products/fpga/software/downloads.html?edition=pro&s=Newest
to generate a free license file to unlock the software: https://licensing.intel.com/psg/s/sales-signup-evaluationlicenses * Select latest version of *Intel Quartus Prime Pro*
* Go to the *Individual Files* tab.
* Download Questa files. (Don't forget part 2!)
* Install
* Go to https://licensing.intel.com/psg/s/sales-signup-evaluationlicenses
* Generate a free *Starter Edition* license file for Questa
* Easiest to use a *fixed* license using your NIC ID (MAC address of your network card via `ifconfig`)
* Download the license file and point the `LM_LICENSE_FILE` environment variable to the folder which contains it.
## Vivado (optional) ## Vivado (optional)

View File

View File

@@ -0,0 +1,26 @@
addrmap top {
reg {
field {
sw=rw;
hw=w; we;
precedence=sw;
} f_sw = 0;
field {
sw=rw;
hw=w; we;
precedence=hw;
} f_hw = 0;
} r1 @ 0x0;
reg {
default counter;
default sw=r;
default hw=na;
field {} f_sw_count[3:0] = 0;
field {} f_hw_count[7:4] = 0;
} r1_events @ 0x4;
r1_events.f_sw_count->incr = r1.f_sw;
r1_events.f_hw_count->incr = r1.f_hw;
};

View File

@@ -0,0 +1,26 @@
{% extends "lib/tb_base.sv" %}
{% block seq %}
{% sv_line_anchor %}
##1;
cb.rst <= '0;
##1;
// Always write both fields from hardware
cb.hwif_in.r1.f_sw.next <= '0;
cb.hwif_in.r1.f_sw.we <= '1;
cb.hwif_in.r1.f_hw.next <= '0;
cb.hwif_in.r1.f_hw.we <= '1;
@cb;
@cb;
cpuif.assert_read('h0, 'b00);
cpuif.assert_read('h4, 'h00);
cpuif.write('h0, 'b11);
cpuif.write('h0, 'b11);
cpuif.write('h0, 'b11);
cpuif.assert_read('h0, 'h00);
cpuif.assert_read('h4, 'h03);
{% endblock %}

View File

@@ -0,0 +1,5 @@
from ..lib.sim_testcase import SimTestCase
class Test(SimTestCase):
def test_dut(self):
self.run_test()