Add double-buffer UDP definitions

This commit is contained in:
Alex Mykyta
2022-10-03 21:36:49 -07:00
parent 1aa9d8b603
commit 21a4e5a41c
7 changed files with 160 additions and 3 deletions

View File

@@ -0,0 +1,120 @@
from typing import Any
from systemrdl.udp import UDPDefinition
from systemrdl.component import Reg
from systemrdl.rdltypes.references import RefType, PropertyReference
from systemrdl.node import Node, RegNode, VectorNode
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 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 it's 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)
)
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 it's 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
default_assignment = True
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)
)
# TODO: Should I limit the use of other properties on double-buffered registers?
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
class BufferReads(UDPDefinition):
name = "buffer_reads"
valid_components = {Reg}
valid_type = bool
default_assignment = True
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)
)
# TODO: Should I limit the use of other properties on double-buffered registers?
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
ALL_UDPS = [
BufferWrites,
WBufferTrigger,
BufferReads,
RBufferTrigger,
]