This commit is contained in:
Arnav Sacheti
2025-10-23 22:33:36 -07:00
parent 4b87556135
commit 0ce469eb73
11 changed files with 17 additions and 291 deletions

View File

@@ -12,15 +12,15 @@ class APB3Cpuif(BaseCpuif):
def _port_declaration(self, child: AddressableNode) -> str:
base = f"apb3_intf.master m_apb_{child.inst_name}"
# When unrolled, current_idx is set - append it to the name
if child.current_idx is not None:
base = f"{base}_{'_'.join(map(str, child.current_idx))}"
# Only add array dimensions if this should be treated as an array
if self.check_is_array(child):
return f"{base} {''.join(f'[{dim}]' for dim in child.array_dimensions)}"
return base
@property

View File

@@ -12,15 +12,15 @@ class APB4Cpuif(BaseCpuif):
def _port_declaration(self, child: AddressableNode) -> str:
base = f"apb4_intf.master m_apb_{child.inst_name}"
# When unrolled, current_idx is set - append it to the name
if child.current_idx is not None:
base = f"{base}_{'_'.join(map(str, child.current_idx))}"
# Only add array dimensions if this should be treated as an array
if self.check_is_array(child):
return f"{base} {''.join(f'[{dim}]' for dim in child.array_dimensions)}"
return base
@property

View File

@@ -12,15 +12,15 @@ class AXI4LiteCpuif(BaseCpuif):
def _port_declaration(self, child: AddressableNode) -> str:
base = f"axi4lite_intf.master m_axil_{child.inst_name}"
# When unrolled, current_idx is set - append it to the name
if child.current_idx is not None:
base = f"{base}_{'_'.join(map(str, child.current_idx))}"
# Only add array dimensions if this should be treated as an array
if self.check_is_array(child):
return f"{base} {''.join(f'[{dim}]' for dim in child.array_dimensions)}"
return base
@property

View File

@@ -73,7 +73,7 @@ class BaseCpuif:
def check_is_array(self, node: AddressableNode) -> bool:
# When unrolling is enabled, children(unroll=True) returns individual
# array elements with current_idx set. These should NOT be treated as arrays.
if self.unroll and hasattr(node, 'current_idx') and node.current_idx is not None:
if self.unroll and hasattr(node, "current_idx") and node.current_idx is not None:
return False
return node.is_array

View File

@@ -34,7 +34,7 @@ class FanoutGenerator(BusDecoderListener):
if action == WalkerAction.Continue:
self._stack[-1] += self._cpuif.fanout(node)
return action
def exit_AddressableComponent(self, node: AddressableNode) -> None:

View File

@@ -57,8 +57,8 @@ class BusDecoderExporter:
loader=c_loader,
undefined=jj.StrictUndefined,
)
self.jj_env.filters["kwf"] = kwf # type: ignore
self.jj_env.filters["walk"] = self.walk # type: ignore
self.jj_env.filters["kwf"] = kwf # type: ignore
self.jj_env.filters["walk"] = self.walk # type: ignore
def export(self, node: RootNode | AddrmapNode, output_dir: str, **kwargs: Unpack[ExporterKwargs]) -> None:
"""
@@ -129,7 +129,7 @@ class BusDecoderExporter:
stream = template.stream(context)
stream.dump(module_file_path)
def walk(self, listener_cls: type[BusDecoderListener], **kwargs: Any) -> str:
def walk(self, listener_cls: type[BusDecoderListener], **kwargs: dict[str, Any]) -> str:
walker = RDLSteerableWalker()
listener = listener_cls(self.ds, **kwargs)
walker.walk(self.ds.top_node, listener, skip_top=True)

View File

@@ -1,18 +1,5 @@
from systemrdl.udp import UDPDefinition
from .rw_buffering import BufferWrites, WBufferTrigger
from .rw_buffering import BufferReads, RBufferTrigger
from .extended_swacc import ReadSwacc, WriteSwacc
from .fixedpoint import IntWidth, FracWidth
from .signed import IsSigned
ALL_UDPS: list[type[UDPDefinition]] = [
BufferWrites,
WBufferTrigger,
BufferReads,
RBufferTrigger,
ReadSwacc,
WriteSwacc,
IntWidth,
FracWidth,
IsSigned,
]
ALL_UDPS: list[type[UDPDefinition]] = []
__all__ = ["ALL_UDPS"]

View File

@@ -1,25 +0,0 @@
from typing import TYPE_CHECKING, Any
from systemrdl.udp import UDPDefinition
from systemrdl.component import Field
if TYPE_CHECKING:
from systemrdl.node import Node
class ReadSwacc(UDPDefinition):
name = "rd_swacc"
valid_components = {Field}
valid_type = bool
def get_unassigned_default(self, node: "Node") -> Any:
return False
class WriteSwacc(UDPDefinition):
name = "wr_swacc"
valid_components = {Field}
valid_type = bool
def get_unassigned_default(self, node: "Node") -> Any:
return False

View File

@@ -1,69 +0,0 @@
from typing import Any
from systemrdl.component import Field
from systemrdl.node import Node, FieldNode
from systemrdl.udp import UDPDefinition
class _FixedpointWidth(UDPDefinition):
valid_components = {Field}
valid_type = int
def validate(self, node: "Node", value: Any) -> None:
assert isinstance(node, FieldNode)
intwidth = node.get_property("intwidth")
fracwidth = node.get_property("fracwidth")
assert intwidth is not None
assert fracwidth is not None
prop_ref = node.inst.property_src_ref.get(self.name)
# incompatible with "counter" fields
if node.get_property("counter"):
self.msg.error("Fixed-point representations are not supported for counter fields.", prop_ref)
# incompatible with "encode" fields
if node.get_property("encode") is not None:
self.msg.error(
"Fixed-point representations are not supported for fields encoded as an enum.", prop_ref
)
# ensure node width = fracwidth + intwidth
if intwidth + fracwidth != node.width:
self.msg.error(
f"Number of integer bits ({intwidth}) plus number of fractional bits ({fracwidth})"
f" must be equal to the width of the component ({node.width}).",
prop_ref,
)
class IntWidth(_FixedpointWidth):
name = "intwidth"
def get_unassigned_default(self, node: "Node") -> Any:
"""
If 'fracwidth' is defined, 'intwidth' is inferred from the node width.
"""
assert isinstance(node, FieldNode)
fracwidth = node.get_property("fracwidth", default=None)
if fracwidth is not None:
return node.width - fracwidth
else:
# not a fixed-point number
return None
class FracWidth(_FixedpointWidth):
name = "fracwidth"
def get_unassigned_default(self, node: "Node") -> Any:
"""
If 'intwidth' is defined, 'fracwidth' is inferred from the node width.
"""
assert isinstance(node, FieldNode)
intwidth = node.get_property("intwidth", default=None)
if intwidth is not None:
return node.width - intwidth
else:
# not a fixed-point number
return None

View File

@@ -1,134 +0,0 @@
from typing import Any
from systemrdl.udp import UDPDefinition
from systemrdl.component import Reg
from systemrdl.rdltypes.references import RefType, PropertyReference
from systemrdl.rdltypes import NoValue
from systemrdl.node import Node, RegNode, VectorNode, SignalNode, FieldNode
class xBufferTrigger(UDPDefinition):
valid_components = {Reg}
valid_type = RefType
def validate(self, node: Node, value: Any) -> None:
# TODO: Reference shall not cross an internal/external boundary
if value is NoValue:
self.msg.error(
"Double-buffer trigger property is missing a value assignment", self.get_src_ref(node)
)
elif isinstance(value, VectorNode):
# Trigger can reference a vector, but only if it is a single-bit
if value.width != 1:
self.msg.error(
"%s '%s' references %s '%s' but its width is not 1"
% (
type(node.inst).__name__.lower(),
node.inst_name,
type(value.inst).__name__.lower(),
value.inst_name,
),
self.get_src_ref(node),
)
if isinstance(value, SignalNode):
if not value.get_property("activehigh") and not value.get_property("activelow"):
self.msg.error(
"Trigger was asigned a signal, but it does not specify whether it is activehigh/activelow",
self.get_src_ref(node),
)
elif isinstance(value, PropertyReference) and value.width is not None:
# Trigger can reference a property, but only if it is a single-bit
if value.width != 1:
self.msg.error(
"%s '%s' references property '%s->%s' but its width is not 1"
% (
type(node.inst).__name__.lower(),
node.inst_name,
value.node.inst_name,
value.name,
),
self.get_src_ref(node),
)
elif isinstance(value, RegNode):
# Trigger can reference a register, which implies access of the
# 'correct half' of the register is the trigger.
# For buffered writes, it is the upper-half.
# For buffered reads, it is the lower-half.
pass
else:
# All other reference types are invalid
self.msg.error(
"Reference to a %s component is incompatible with the '%s' property."
% (type(node.inst).__name__.lower(), self.name),
self.get_src_ref(node),
)
# -------------------------------------------------------------------------------
class BufferWrites(UDPDefinition):
name = "buffer_writes"
valid_components = {Reg}
valid_type = bool
def validate(self, node: "Node", value: Any) -> None:
assert isinstance(node, RegNode)
if value:
if not node.has_sw_writable:
self.msg.error(
"'buffer_writes' is set to true, but this register does not contain any writable fields.",
self.get_src_ref(node),
)
def get_unassigned_default(self, node: "Node") -> Any:
return False
class WBufferTrigger(xBufferTrigger):
name = "wbuffer_trigger"
def get_unassigned_default(self, node: "Node") -> Any:
# If buffering is enabled, trigger is the register itself
if node.get_property("buffer_writes"):
return node
return None
def validate(self, node: Node, value: Any) -> None:
super().validate(node, value)
if isinstance(value, FieldNode):
if value.parent == node:
self.msg.error(
"Trigger for a write-buffered register cannot be a field "
"within the same register since the buffering makes it impossible to trigger."
)
class BufferReads(UDPDefinition):
name = "buffer_reads"
valid_components = {Reg}
valid_type = bool
def validate(self, node: "Node", value: Any) -> None:
assert isinstance(node, RegNode)
if value:
if not node.has_sw_readable:
self.msg.error(
"'buffer_reads' is set to true, but this register does not contain any readable fields.",
self.get_src_ref(node),
)
def get_unassigned_default(self, node: "Node") -> Any:
return False
class RBufferTrigger(xBufferTrigger):
name = "rbuffer_trigger"
def get_unassigned_default(self, node: "Node") -> Any:
# If buffering is enabled, trigger is the register itself
if node.get_property("buffer_reads"):
return node
return None

View File

@@ -1,33 +0,0 @@
from typing import Any
from systemrdl.component import Field
from systemrdl.node import Node
from systemrdl.udp import UDPDefinition
class IsSigned(UDPDefinition):
name = "is_signed"
valid_components = {Field}
valid_type = bool
default_assignment = True
def validate(self, node: "Node", value: Any) -> None:
# "counter" fields can not be signed
if value and node.get_property("counter"):
self.msg.error(
"The property is_signed=true is not supported for counter fields.",
node.inst.property_src_ref["is_signed"],
)
# incompatible with "encode" fields
if value and node.get_property("encode") is not None:
self.msg.error(
"The property is_signed=true is not supported for fields encoded as an enum.",
node.inst.property_src_ref["is_signed"],
)
def get_unassigned_default(self, node: "Node") -> Any:
"""
Unsigned by default if not specified.
"""
return False