Add support for external components. (#4 & #36)

This commit is contained in:
Alex Mykyta
2023-05-03 21:57:25 -07:00
parent f1a75f8d38
commit ca9185dac7
35 changed files with 1341 additions and 78 deletions

View File

@@ -1,6 +1,7 @@
from typing import TYPE_CHECKING, Union, List
from typing import TYPE_CHECKING, Union, List, Optional
from systemrdl.node import AddrmapNode, AddressableNode, RegNode, FieldNode
from systemrdl.node import FieldNode, RegNode
from systemrdl.walker import WalkerAction
from .utils import get_indexed_path
from .struct_generator import RDLStructGenerator
@@ -9,13 +10,15 @@ from .identifier_filter import kw_filter as kwf
if TYPE_CHECKING:
from .exporter import RegblockExporter
from systemrdl.node import AddrmapNode, AddressableNode
from systemrdl.node import RegfileNode, MemNode
class AddressDecode:
def __init__(self, exp:'RegblockExporter'):
self.exp = exp
@property
def top_node(self) -> AddrmapNode:
def top_node(self) -> 'AddrmapNode':
return self.exp.top_node
def get_strobe_struct(self) -> str:
@@ -59,9 +62,57 @@ class AddressDecode:
return "decoded_reg_strb." + path
def get_external_block_access_strobe(self, node: 'AddressableNode') -> str:
assert node.external
assert not isinstance(node, RegNode)
path = get_indexed_path(self.top_node, node)
return "decoded_reg_strb." + path
class DecodeStructGenerator(RDLStructGenerator):
def _enter_external_block(self, node: 'AddressableNode') -> None:
self.add_member(
kwf(node.inst_name),
array_dimensions=node.array_dimensions,
)
def enter_Addrmap(self, node: 'AddrmapNode') -> Optional[WalkerAction]:
if node.external:
self._enter_external_block(node)
return WalkerAction.SkipDescendants
super().enter_Addrmap(node)
return WalkerAction.Continue
def exit_Addrmap(self, node: 'AddrmapNode') -> None:
if node.external:
return
super().exit_Addrmap(node)
def enter_Regfile(self, node: 'RegfileNode') -> Optional[WalkerAction]:
if node.external:
self._enter_external_block(node)
return WalkerAction.SkipDescendants
super().enter_Regfile(node)
return WalkerAction.Continue
def exit_Regfile(self, node: 'RegfileNode') -> None:
if node.external:
return
super().exit_Regfile(node)
def enter_Mem(self, node: 'MemNode') -> Optional[WalkerAction]:
if node.external:
self._enter_external_block(node)
return WalkerAction.SkipDescendants
super().enter_Mem(node)
return WalkerAction.Continue
def exit_Mem(self, node: 'MemNode') -> None:
if node.external:
return
super().exit_Mem(node)
def enter_Reg(self, node: 'RegNode') -> None:
# if register is "wide", expand the strobe to be able to access the sub-words
n_subwords = node.get_property("regwidth") // node.get_property("accesswidth")
@@ -89,23 +140,32 @@ class DecodeLogicGenerator(RDLForLoopGenerator):
self._array_stride_stack = [] # type: List[List[int]]
def enter_AddressableComponent(self, node: 'AddressableNode') -> None:
def enter_AddressableComponent(self, node: 'AddressableNode') -> Optional[WalkerAction]:
super().enter_AddressableComponent(node)
if not node.is_array:
return
if node.is_array:
# Collect strides for each array dimension
current_stride = node.array_stride
strides = []
for dim in reversed(node.array_dimensions):
strides.append(current_stride)
current_stride *= dim
strides.reverse()
self._array_stride_stack.extend(strides)
# Collect strides for each array dimension
current_stride = node.array_stride
strides = []
for dim in reversed(node.array_dimensions):
strides.append(current_stride)
current_stride *= dim
strides.reverse()
self._array_stride_stack.extend(strides)
if node.external and not isinstance(node, RegNode):
# Is an external block
addr_str = self._get_address_str(node)
strb = self.addr_decode.get_external_block_access_strobe(node)
rhs = f"cpuif_req_masked & (cpuif_addr >= {addr_str}) & (cpuif_addr <= {addr_str} + 'h{(node.size - 1):x})"
self.add_content(f"{strb} = {rhs};")
self.add_content(f"is_external |= {rhs};")
return WalkerAction.SkipDescendants
return WalkerAction.Continue
def _get_address_str(self, node:AddressableNode, subword_offset: int=0) -> str:
def _get_address_str(self, node: 'AddressableNode', subword_offset: int=0) -> str:
a = f"'h{(node.raw_absolute_address - self.addr_decode.top_node.raw_absolute_address + subword_offset):x}"
for i, stride in enumerate(self._array_stride_stack):
a += f" + i{i}*'h{stride:x}"
@@ -117,16 +177,21 @@ class DecodeLogicGenerator(RDLForLoopGenerator):
accesswidth = node.get_property('accesswidth')
if regwidth == accesswidth:
s = f"{self.addr_decode.get_access_strobe(node)} = cpuif_req_masked & (cpuif_addr == {self._get_address_str(node)});"
rhs = f"cpuif_req_masked & (cpuif_addr == {self._get_address_str(node)})"
s = f"{self.addr_decode.get_access_strobe(node)} = {rhs};"
self.add_content(s)
if node.external:
self.add_content(f"is_external |= {rhs};")
else:
# Register is wide. Create a substrobe for each subword
n_subwords = regwidth // accesswidth
subword_stride = accesswidth // 8
for i in range(n_subwords):
s = f"{self.addr_decode.get_access_strobe(node)}[{i}] = cpuif_req_masked & (cpuif_addr == {self._get_address_str(node, subword_offset=(i*subword_stride))});"
rhs = f"cpuif_req_masked & (cpuif_addr == {self._get_address_str(node, subword_offset=(i*subword_stride))})"
s = f"{self.addr_decode.get_access_strobe(node)}[{i}] = {rhs};"
self.add_content(s)
if node.external:
self.add_content(f"is_external |= {rhs};")
def exit_AddressableComponent(self, node: 'AddressableNode') -> None:
super().exit_AddressableComponent(node)