130 lines
4.5 KiB
Python
130 lines
4.5 KiB
Python
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
|
|
|
|
|
|
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 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)
|
|
)
|
|
|
|
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 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
|
|
|
|
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
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
ALL_UDPS = [
|
|
BufferWrites,
|
|
WBufferTrigger,
|
|
BufferReads,
|
|
RBufferTrigger,
|
|
]
|