106 lines
3.5 KiB
Python
106 lines
3.5 KiB
Python
import re
|
|
from typing import TYPE_CHECKING, List
|
|
|
|
from systemrdl.node import Node, AddressableNode, RegNode, FieldNode
|
|
|
|
if TYPE_CHECKING:
|
|
from ..exporter import RegblockExporter
|
|
|
|
class FieldLogic:
|
|
def __init__(self, exporter:'RegblockExporter', top_node:Node):
|
|
self.exporter = exporter
|
|
self.top_node = top_node
|
|
|
|
self._indent_level = 0
|
|
|
|
def get_storage_struct(self) -> str:
|
|
lines = []
|
|
self._do_struct(lines, self.top_node, is_top=True)
|
|
|
|
# Only declare the storage struct if it exists
|
|
if lines:
|
|
lines.append(f"{self._indent}field_storage_t field_storage;")
|
|
return "\n".join(lines)
|
|
|
|
def get_implementation(self) -> str:
|
|
return "TODO:"
|
|
|
|
#---------------------------------------------------------------------------
|
|
# Field utility functions
|
|
#---------------------------------------------------------------------------
|
|
def get_storage_identifier(self, node: FieldNode):
|
|
assert node.implements_storage
|
|
|
|
path = node.get_rel_path(self.top_node, empty_array_suffix="[!]")
|
|
|
|
# replace unknown indexes with incrementing iterators i0, i1, ...
|
|
class repl:
|
|
def __init__(self):
|
|
self.i = 0
|
|
def __call__(self, match):
|
|
s = f'i{self.i}'
|
|
self.i += 1
|
|
return s
|
|
path = re.sub(r'!', repl(), path)
|
|
|
|
return "field_storage." + path
|
|
|
|
|
|
#---------------------------------------------------------------------------
|
|
# Struct generation functions
|
|
#---------------------------------------------------------------------------
|
|
@property
|
|
def _indent(self) -> str:
|
|
return " " * self._indent_level
|
|
|
|
def _get_node_array_suffix(self, node:AddressableNode) -> str:
|
|
if node.is_array:
|
|
return "".join([f'[{dim}]' for dim in node.array_dimensions])
|
|
return ""
|
|
|
|
def _do_struct(self, lines:List[str], node:AddressableNode, is_top:bool = False) -> bool:
|
|
# Collect struct members first
|
|
contents = []
|
|
self._indent_level += 1
|
|
for child in node.children():
|
|
if isinstance(child, RegNode):
|
|
self._do_reg_struct(contents, child)
|
|
elif isinstance(child, AddressableNode):
|
|
self._do_struct(contents, child)
|
|
self._indent_level -= 1
|
|
|
|
# If struct is not empty, emit a struct!
|
|
if contents:
|
|
if is_top:
|
|
lines.append(f"{self._indent}typedef struct {{")
|
|
else:
|
|
lines.append(f"{self._indent}struct {{")
|
|
|
|
lines.extend(contents)
|
|
|
|
if is_top:
|
|
lines.append(f"{self._indent}}} field_storage_t;")
|
|
else:
|
|
lines.append(f"{self._indent}}} {node.inst_name}{self._get_node_array_suffix(node)};")
|
|
|
|
|
|
def _do_reg_struct(self, lines:List[str], node:RegNode) -> None:
|
|
|
|
fields = []
|
|
for field in node.fields():
|
|
if field.implements_storage:
|
|
fields.append(field)
|
|
|
|
if not fields:
|
|
return
|
|
|
|
lines.append(f"{self._indent}struct {{")
|
|
self._indent_level += 1
|
|
for field in fields:
|
|
if field.width == 1:
|
|
lines.append(f"{self._indent}logic {field.inst_name};")
|
|
else:
|
|
lines.append(f"{self._indent}logic [{field.width-1}:0] {field.inst_name};")
|
|
self._indent_level -= 1
|
|
lines.append(f"{self._indent}}} {node.inst_name}{self._get_node_array_suffix(node)};")
|