102 lines
3.0 KiB
Python
102 lines
3.0 KiB
Python
import re
|
|
from typing import TYPE_CHECKING, List, Union
|
|
|
|
from systemrdl.node import AddrmapNode, AddressableNode, RegNode, FieldNode
|
|
|
|
from .utils import get_indexed_path
|
|
from .struct_generator import RDLStructGenerator
|
|
from .forloop_generator import RDLForLoopGenerator
|
|
|
|
if TYPE_CHECKING:
|
|
from .exporter import RegblockExporter
|
|
|
|
class AddressDecode:
|
|
def __init__(self, exp:'RegblockExporter'):
|
|
self.exp = exp
|
|
|
|
@property
|
|
def top_node(self) -> AddrmapNode:
|
|
return self.exp.top_node
|
|
|
|
def get_strobe_struct(self) -> str:
|
|
struct_gen = DecodeStructGenerator()
|
|
s = struct_gen.get_struct(self.top_node, "decoded_reg_strb_t")
|
|
assert s is not None # guaranteed to have at least one reg
|
|
return s
|
|
|
|
def get_implementation(self) -> str:
|
|
gen = DecodeLogicGenerator(self)
|
|
s = gen.get_content(self.top_node)
|
|
assert s is not None
|
|
return s
|
|
|
|
def get_access_strobe(self, node: Union[RegNode, FieldNode]) -> str:
|
|
"""
|
|
Returns the Verilog string that represents the register/field's access strobe.
|
|
"""
|
|
if isinstance(node, FieldNode):
|
|
node = node.parent
|
|
|
|
path = get_indexed_path(self.top_node, node)
|
|
return "decoded_reg_strb." + path
|
|
|
|
|
|
class DecodeStructGenerator(RDLStructGenerator):
|
|
|
|
def enter_Reg(self, node: 'RegNode') -> None:
|
|
self.add_member(node.inst_name, array_dimensions=node.array_dimensions)
|
|
|
|
# Stub out
|
|
def exit_Reg(self, node: 'RegNode') -> None:
|
|
pass
|
|
def enter_Field(self, node: 'FieldNode') -> None:
|
|
pass
|
|
|
|
|
|
class DecodeLogicGenerator(RDLForLoopGenerator):
|
|
|
|
def __init__(self, addr_decode: AddressDecode) -> None:
|
|
self.addr_decode = addr_decode
|
|
super().__init__()
|
|
|
|
# List of address strides for each dimension
|
|
self._array_stride_stack = []
|
|
|
|
|
|
def enter_AddressableComponent(self, node: 'AddressableNode') -> None:
|
|
super().enter_AddressableComponent(node)
|
|
|
|
if not node.is_array:
|
|
return
|
|
|
|
# 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)
|
|
|
|
|
|
def _get_address_str(self, node:AddressableNode) -> str:
|
|
a = "'h%x" % (node.raw_absolute_address - self.addr_decode.top_node.raw_absolute_address)
|
|
for i, stride in enumerate(self._array_stride_stack):
|
|
a += f" + i{i}*'h{stride:x}"
|
|
return a
|
|
|
|
|
|
def enter_Reg(self, node: RegNode) -> None:
|
|
s = f"{self.addr_decode.get_access_strobe(node)} = cpuif_req_masked & (cpuif_addr == {self._get_address_str(node)});"
|
|
self.add_content(s)
|
|
|
|
|
|
def exit_AddressableComponent(self, node: 'AddressableNode') -> None:
|
|
super().exit_AddressableComponent(node)
|
|
|
|
if not node.is_array:
|
|
return
|
|
|
|
for _ in node.array_dimensions:
|
|
self._array_stride_stack.pop()
|