@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user