Rework interpretation of accesswidth/regwidth. accesswidth determines bus width

This commit is contained in:
Alex Mykyta
2022-09-12 21:09:52 -07:00
parent f3d932ccdf
commit e2d6fc1c60
3 changed files with 30 additions and 23 deletions

View File

@@ -7,6 +7,13 @@ When exporting a design, you can select from a variety of popular CPU interface
protocols. These are described in more detail in the pages that follow. protocols. These are described in more detail in the pages that follow.
Bus Width
^^^^^^^^^
The CPU interface bus width is automatically determined from the contents of the
design being exported. The bus width is equal to the widest ``accesswidth``
encountered in the deisgn.
Addressing Addressing
^^^^^^^^^^ ^^^^^^^^^^

View File

@@ -18,10 +18,10 @@ Registers instantiated using the ``alias`` keyword are not supported yet.
Unaligned Registers Unaligned Registers
------------------- -------------------
All address offsets & strides shall be a multiple of the regwidth used. Specifically: All address offsets & strides shall be a multiple of the accesswidth used. Specifically:
* Each register's address and array stride shall be aligned to it's regwidth. * Each register's address and array stride shall be aligned to it's accesswidth.
* Each regfile or addrmap shall use an offset and stride that is a multiple of the largest regwidth it encloses. * Each regfile or addrmap shall use an offset and stride that is a multiple of the largest accesswidth it encloses.
No partial writes No partial writes
@@ -38,6 +38,5 @@ and the resulting CPU bus width has some limitations:
* All registers shall have ``regwidth`` == ``accesswidth`` * All registers shall have ``regwidth`` == ``accesswidth``
* ``regwidth`` shall be the same across all registers within the block being exported. * ``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. I have plans to remove these restrictions and allow for more flexibility in the future.

View File

@@ -1,7 +1,7 @@
from typing import TYPE_CHECKING, Set, List from typing import TYPE_CHECKING, Set, List, Optional
from collections import OrderedDict from collections import OrderedDict
from systemrdl.walker import RDLListener, RDLWalker from systemrdl.walker import RDLListener, RDLWalker, WalkerAction
from systemrdl.node import SignalNode, AddressableNode from systemrdl.node import SignalNode, AddressableNode
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -21,8 +21,8 @@ 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 # Keep track of max accesswidth encountered in a given block
self.max_regwidth_stack = [] # type: List[int] self.max_accesswidth_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]
@@ -68,37 +68,36 @@ 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') accesswidth = node.get_property('accesswidth')
self.max_regwidth_stack[-1] = max(self.max_regwidth_stack[-1], regwidth) self.max_accesswidth_stack[-1] = max(self.max_accesswidth_stack[-1], accesswidth)
# 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 accesswidth in the design
# TODO: make this user-overridable once more flexible regwidth/accesswidths are supported self.cpuif_data_width = max(self.cpuif_data_width, accesswidth)
self.cpuif_data_width = max(self.cpuif_data_width, regwidth)
# TODO: remove this limitation eventually # TODO: remove this limitation eventually
if regwidth != self.cpuif_data_width: if accesswidth != self.cpuif_data_width:
self.msg.error( self.msg.error(
"register blocks with non-uniform regwidths are not supported yet", "register blocks with non-uniform accesswidth are not supported yet",
node.inst.property_src_ref.get('regwidth', node.inst.inst_src_ref) node.inst.property_src_ref.get('accesswidth', node.inst.inst_src_ref)
) )
# TODO: remove this limitation eventually # TODO: remove this limitation eventually
if regwidth != node.get_property('accesswidth'): if accesswidth != node.get_property('regwidth'):
self.msg.error( self.msg.error(
"Registers that have an accesswidth different from the register width are not supported yet", "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) node.inst.property_src_ref.get('accesswidth', node.inst.inst_src_ref)
) )
def enter_AddressableComponent(self, node: AddressableNode) -> None: def enter_AddressableComponent(self, node: AddressableNode) -> None:
self.max_regwidth_stack.append(0) self.max_accesswidth_stack.append(0)
def exit_AddressableComponent(self, node: AddressableNode) -> None: def exit_AddressableComponent(self, node: AddressableNode) -> None:
max_block_regwidth = self.max_regwidth_stack.pop() max_block_accesswidth = self.max_accesswidth_stack.pop()
if self.max_regwidth_stack: if self.max_accesswidth_stack:
self.max_regwidth_stack[-1] = max(self.max_regwidth_stack[-1], max_block_regwidth) self.max_accesswidth_stack[-1] = max(self.max_accesswidth_stack[-1], max_block_accesswidth)
alignment = int(max_block_regwidth / 8) alignment = int(max_block_accesswidth / 8)
if (node.raw_address_offset % alignment) != 0: if (node.raw_address_offset % alignment) != 0:
self.msg.error( self.msg.error(
f"Unaligned registers are not supported. Address offset of instance '{node.inst_name}' must be a multiple of {alignment}", f"Unaligned registers are not supported. Address offset of instance '{node.inst_name}' must be a multiple of {alignment}",
@@ -111,12 +110,14 @@ class DesignScanner(RDLListener):
node.inst.inst_src_ref node.inst.inst_src_ref
) )
def enter_Component(self, node: 'Node') -> None: def enter_Component(self, node: 'Node') -> Optional[WalkerAction]:
if node.external and (node != self.exp.top_node): 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
) )
# Do not inspect external components. None of my business
return WalkerAction.SkipDescendants
def enter_Signal(self, node: 'SignalNode') -> None: def enter_Signal(self, node: 'SignalNode') -> None:
# If encountering a CPUIF reset that is nested within the register model, # If encountering a CPUIF reset that is nested within the register model,