Skip to content

Commit

Permalink
Add packed struct overlay for external register bitfields. #84
Browse files Browse the repository at this point in the history
  • Loading branch information
amykyta3 committed Mar 30, 2024
1 parent 840b54c commit f25ba60
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 22 deletions.
91 changes: 78 additions & 13 deletions src/peakrdl_regblock/hwif/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ def __init__(self, hwif: 'Hwif', hwif_name: str) -> None:

self.hwif_report_stack = [hwif_name]

def push_struct(self, type_name: str, inst_name: str, array_dimensions: Optional[List[int]] = None) -> None: # type: ignore
super().push_struct(type_name, inst_name, array_dimensions)
def push_struct(self, type_name: str, inst_name: str, array_dimensions: Optional[List[int]] = None, packed: bool = False) -> None: # type: ignore
super().push_struct(type_name, inst_name, array_dimensions, packed)

if array_dimensions:
array_suffix = "".join([f"[0:{dim-1}]" for dim in array_dimensions])
Expand Down Expand Up @@ -52,14 +52,14 @@ class InputStructGenerator_Hier(HWIFStructGenerator):
def __init__(self, hwif: 'Hwif') -> None:
super().__init__(hwif, "hwif_in")

def get_typdef_name(self, node:'Node') -> str:
def get_typdef_name(self, node:'Node', suffix: str = "") -> str:
base = node.get_rel_path(
self.top_node.parent,
hier_separator="__",
array_suffix="x",
empty_array_suffix="x"
)
return f'{base}__in_t'
return f'{base}{suffix}__in_t'

def enter_Signal(self, node: 'SignalNode') -> None:
# only emit the signal if design scanner detected it is actually being used
Expand Down Expand Up @@ -95,15 +95,48 @@ def enter_Reg(self, node: 'RegNode') -> Optional[WalkerAction]:
super().enter_Reg(node)
if node.external:
width = min(self.hwif.ds.cpuif_data_width, node.get_property('regwidth'))
n_subwords = node.get_property("regwidth") // node.get_property("accesswidth")
if node.has_sw_readable:
self.add_member("rd_ack")
self.add_member("rd_data", width)
self.add_external_reg_rd_data(node, width, n_subwords)
if node.has_sw_writable:
self.add_member("wr_ack")
return WalkerAction.SkipDescendants

return WalkerAction.Continue

def add_external_reg_rd_data(self, node: 'RegNode', width: int, n_subwords: int) -> None:
if n_subwords == 1:
# External reg is 1 sub-word. Add a packed struct to represent it
type_name = self.get_typdef_name(node, "__fields")
self.push_struct(type_name, "rd_data", packed=True)
current_bit = 0
for field in node.fields():
if not field.is_sw_readable:
continue
if field.low > current_bit:
# Add padding
self.add_member(
f"_reserved_{field.low - 1}_{current_bit}",
field.low - current_bit
)
self.add_member(
kwf(field.inst_name),
field.width
)
current_bit = field.high + 1

# Add end padding if needed
if current_bit != width:
self.add_member(
f"_reserved_{width - 1}_{current_bit}",
width - current_bit
)
self.pop_struct()
else:
# Multiple sub-words. Cannot generate a struct
self.add_member("rd_data", width)

def enter_Field(self, node: 'FieldNode') -> None:
type_name = self.get_typdef_name(node)
self.push_struct(type_name, kwf(node.inst_name))
Expand Down Expand Up @@ -150,14 +183,14 @@ class OutputStructGenerator_Hier(HWIFStructGenerator):
def __init__(self, hwif: 'Hwif') -> None:
super().__init__(hwif, "hwif_out")

def get_typdef_name(self, node:'Node') -> str:
def get_typdef_name(self, node:'Node', suffix: str = "") -> str:
base = node.get_rel_path(
self.top_node.parent,
hier_separator="__",
array_suffix="x",
empty_array_suffix="x"
)
return f'{base}__out_t'
return f'{base}{suffix}__out_t'

def _add_external_block_members(self, node: 'AddressableNode') -> None:
self.add_member("req")
Expand Down Expand Up @@ -193,12 +226,44 @@ def enter_Reg(self, node: 'RegNode') -> Optional[WalkerAction]:
self.add_member("req", n_subwords)
self.add_member("req_is_wr")
if node.has_sw_writable:
self.add_member("wr_data", width)
self.add_member("wr_biten", width)
self.add_external_reg_wr_data("wr_data", node, width, n_subwords)
self.add_external_reg_wr_data("wr_biten", node, width, n_subwords)
return WalkerAction.SkipDescendants

return WalkerAction.Continue

def add_external_reg_wr_data(self, name: str, node: 'RegNode', width: int, n_subwords: int) -> None:
if n_subwords == 1:
# External reg is 1 sub-word. Add a packed struct to represent it
type_name = self.get_typdef_name(node, "__fields")
self.push_struct(type_name, name, packed=True)
current_bit = 0
for field in node.fields():
if not field.is_sw_writable:
continue
if field.low > current_bit:
# Add padding
self.add_member(
f"_reserved_{field.low - 1}_{current_bit}",
field.low - current_bit
)
self.add_member(
kwf(field.inst_name),
field.width
)
current_bit = field.high + 1

# Add end padding if needed
if current_bit != width:
self.add_member(
f"_reserved_{width - 1}_{current_bit}",
width - current_bit
)
self.pop_struct()
else:
# Multiple sub-words. Cannot generate a struct
self.add_member(name, width)

def enter_Field(self, node: 'FieldNode') -> None:
type_name = self.get_typdef_name(node)
self.push_struct(type_name, kwf(node.inst_name))
Expand Down Expand Up @@ -229,7 +294,7 @@ def exit_Reg(self, node: 'RegNode') -> None:

#-------------------------------------------------------------------------------
class InputStructGenerator_TypeScope(InputStructGenerator_Hier):
def get_typdef_name(self, node:'Node') -> str:
def get_typdef_name(self, node:'Node', suffix: str = "") -> str:
scope_path = node.get_global_type_name("__")
if scope_path is None:
# Unable to determine a reusable type name. Fall back to hierarchical path
Expand All @@ -242,10 +307,10 @@ def get_typdef_name(self, node:'Node') -> str:
else:
extra_suffix = ""

return f'{scope_path}{extra_suffix}__in_t'
return f'{scope_path}{extra_suffix}{suffix}__in_t'

class OutputStructGenerator_TypeScope(OutputStructGenerator_Hier):
def get_typdef_name(self, node:'Node') -> str:
def get_typdef_name(self, node:'Node', suffix: str = "") -> str:
scope_path = node.get_global_type_name("__")
if scope_path is None:
# Unable to determine a reusable type name. Fall back to hierarchical path
Expand All @@ -258,7 +323,7 @@ def get_typdef_name(self, node:'Node') -> str:
else:
extra_suffix = ""

return f'{scope_path}{extra_suffix}__out_t'
return f'{scope_path}{extra_suffix}{suffix}__out_t'

#-------------------------------------------------------------------------------
class EnumGenerator:
Expand Down
24 changes: 16 additions & 8 deletions src/peakrdl_regblock/struct_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,26 @@ def __str__(self) -> str:


class _TypedefStruct(_StructBase):
def __init__(self, type_name: str, inst_name: Optional[str] = None, array_dimensions: Optional[List[int]] = None):
def __init__(self, type_name: str, inst_name: Optional[str] = None, array_dimensions: Optional[List[int]] = None, packed: bool = False):
super().__init__()
self.type_name = type_name
self.inst_name = inst_name
self.array_dimensions = array_dimensions
self.packed = packed

def __str__(self) -> str:
return (
"typedef struct {\n"
+ super().__str__()
+ f"\n}} {self.type_name};"
)
if self.packed:
return (
"typedef struct packed {\n"
+ super().__str__()
+ f"\n}} {self.type_name};"
)
else:
return (
"typedef struct {\n"
+ super().__str__()
+ f"\n}} {self.type_name};"
)

@property
def instantiation(self) -> str:
Expand Down Expand Up @@ -167,8 +175,8 @@ def __init__(self) -> None:
super().__init__()
self.typedefs = OrderedDict() # type: OrderedDict[str, _TypedefStruct]

def push_struct(self, type_name: str, inst_name: str, array_dimensions: Optional[List[int]] = None) -> None: # type: ignore # pylint: disable=arguments-renamed
s = _TypedefStruct(type_name, inst_name, array_dimensions)
def push_struct(self, type_name: str, inst_name: str, array_dimensions: Optional[List[int]] = None, packed = False) -> None: # type: ignore # pylint: disable=arguments-renamed
s = _TypedefStruct(type_name, inst_name, array_dimensions, packed)
self._struct_stack.append(s)

def pop_struct(self) -> None:
Expand Down
7 changes: 6 additions & 1 deletion tests/test_external/regblock.rdl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ addrmap top {
reg my_reg {
field {sw=rw; hw=r;} whatever[32] = 0;
};
reg my_reg_alt {
field {sw=r; hw=w;} whatever_a[3:2] = 0;
field {sw=w; hw=r;} whatever_b[4:4] = 0;
field {sw=rw; hw=r;} whatever_c[15:8] = 0;
};
reg my_wide_reg {
regwidth = 64;
accesswidth = 32;
field {sw=rw; hw=r;} whatever = 0;
};

external my_reg ext_reg @ 0x00;
external my_reg_alt ext_reg @ 0x00;
my_reg int_reg @ 0x04;
external my_wide_reg wide_ext_reg @ 0x10;
external my_reg ext_reg_array[32] @ 0x100 += 4;
Expand Down

0 comments on commit f25ba60

Please sign in to comment.