Add support for wide registers (where accesswidth < regwidth)
This commit is contained in:
99
src/peakrdl_regblock/validate_design.py
Normal file
99
src/peakrdl_regblock/validate_design.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from systemrdl.walker import RDLListener, RDLWalker, WalkerAction
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from systemrdl.node import Node, RegNode, FieldNode, SignalNode, AddressableNode
|
||||
from .exporter import RegblockExporter
|
||||
|
||||
class DesignValidator(RDLListener):
|
||||
"""
|
||||
Performs additional rule-checks on the design that check for limitations
|
||||
imposed by this exporter.
|
||||
"""
|
||||
def __init__(self, exp:'RegblockExporter') -> None:
|
||||
self.exp = exp
|
||||
self.msg = exp.top_node.env.msg
|
||||
|
||||
def do_validate(self) -> None:
|
||||
RDLWalker().walk(self.exp.top_node, self)
|
||||
if self.msg.had_error:
|
||||
self.msg.fatal(
|
||||
"Unable to export due to previous errors"
|
||||
)
|
||||
|
||||
def enter_Component(self, node: 'Node') -> Optional[WalkerAction]:
|
||||
if node.external and (node != self.exp.top_node):
|
||||
self.msg.error(
|
||||
"Exporter does not support external components",
|
||||
node.inst.inst_src_ref
|
||||
)
|
||||
# Do not inspect external components. None of my business
|
||||
return WalkerAction.SkipDescendants
|
||||
return None
|
||||
|
||||
def enter_Signal(self, node: 'SignalNode') -> None:
|
||||
# If encountering a CPUIF reset that is nested within the register model,
|
||||
# warn that it will be ignored.
|
||||
# Only cpuif resets in the top-level node or above will be honored
|
||||
if node.get_property('cpuif_reset') and (node.parent != self.exp.top_node):
|
||||
self.msg.warning(
|
||||
"Only cpuif_reset signals that are instantiated in the top-level "
|
||||
"addrmap or above will be honored. Any cpuif_reset signals nested "
|
||||
"within children of the addrmap being exported will be ignored.",
|
||||
node.inst.inst_src_ref
|
||||
)
|
||||
|
||||
def enter_AddressableComponent(self, node: 'AddressableNode') -> None:
|
||||
# All registers must be aligned to the internal data bus width
|
||||
alignment = self.exp.cpuif.data_width_bytes
|
||||
if (node.raw_address_offset % alignment) != 0:
|
||||
self.msg.error(
|
||||
"Unaligned registers are not supported. Address offset of "
|
||||
f"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(
|
||||
"Unaligned registers are not supported. Address stride of "
|
||||
f"instance array '{node.inst_name}' must be a multiple of {alignment}",
|
||||
node.inst.inst_src_ref
|
||||
)
|
||||
|
||||
def enter_Reg(self, node: 'RegNode') -> None:
|
||||
# accesswidth of wide registers must be consistent within the register block
|
||||
accesswidth = node.get_property('accesswidth')
|
||||
regwidth = node.get_property('regwidth')
|
||||
|
||||
if accesswidth < regwidth:
|
||||
# register is 'wide'
|
||||
if accesswidth != self.exp.cpuif.data_width:
|
||||
self.msg.error(
|
||||
f"Multi-word registers that have an accesswidth ({accesswidth}) "
|
||||
"that is inconsistent with this regblock's CPU bus width "
|
||||
f"({self.exp.cpuif.data_width}) are not supported.",
|
||||
node.inst.inst_src_ref
|
||||
)
|
||||
|
||||
|
||||
def enter_Field(self, node: 'FieldNode') -> None:
|
||||
# 10.6.1-f: Any field that is software-writable or clear on read shall
|
||||
# not span multiple software accessible sub-words (e.g., a 64-bit
|
||||
# register with a 32-bit access width may not have a writable field with
|
||||
# bits in both the upper and lower half of the register).
|
||||
#
|
||||
# Interpreting this further - this rule applies any time a field is
|
||||
# software-modifiable by any means, including rclr, rset, ruser
|
||||
# TODO: suppress this check for registers that have the appropriate
|
||||
# buffer_writes/buffer_reads UDP set
|
||||
parent_accesswidth = node.parent.get_property('accesswidth')
|
||||
parent_regwidth = node.parent.get_property('regwidth')
|
||||
if ((parent_accesswidth < parent_regwidth)
|
||||
and (node.lsb // parent_accesswidth) != (node.msb // parent_accesswidth)
|
||||
and (node.is_sw_writable or node.get_property('onread') is not None)):
|
||||
# Field spans across sub-words
|
||||
self.msg.error(
|
||||
f"Software-modifiable field '{node.inst_name}' shall not span "
|
||||
"multiple software-accessible subwords.",
|
||||
node.inst.inst_src_ref
|
||||
)
|
||||
Reference in New Issue
Block a user