Skip to content

Commit f25ba60

Browse files
committed
Add packed struct overlay for external register bitfields. #84
1 parent 840b54c commit f25ba60

File tree

3 files changed

+100
-22
lines changed

3 files changed

+100
-22
lines changed

src/peakrdl_regblock/hwif/generators.py

Lines changed: 78 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ def __init__(self, hwif: 'Hwif', hwif_name: str) -> None:
2020

2121
self.hwif_report_stack = [hwif_name]
2222

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

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

55-
def get_typdef_name(self, node:'Node') -> str:
55+
def get_typdef_name(self, node:'Node', suffix: str = "") -> str:
5656
base = node.get_rel_path(
5757
self.top_node.parent,
5858
hier_separator="__",
5959
array_suffix="x",
6060
empty_array_suffix="x"
6161
)
62-
return f'{base}__in_t'
62+
return f'{base}{suffix}__in_t'
6363

6464
def enter_Signal(self, node: 'SignalNode') -> None:
6565
# only emit the signal if design scanner detected it is actually being used
@@ -95,15 +95,48 @@ def enter_Reg(self, node: 'RegNode') -> Optional[WalkerAction]:
9595
super().enter_Reg(node)
9696
if node.external:
9797
width = min(self.hwif.ds.cpuif_data_width, node.get_property('regwidth'))
98+
n_subwords = node.get_property("regwidth") // node.get_property("accesswidth")
9899
if node.has_sw_readable:
99100
self.add_member("rd_ack")
100-
self.add_member("rd_data", width)
101+
self.add_external_reg_rd_data(node, width, n_subwords)
101102
if node.has_sw_writable:
102103
self.add_member("wr_ack")
103104
return WalkerAction.SkipDescendants
104105

105106
return WalkerAction.Continue
106107

108+
def add_external_reg_rd_data(self, node: 'RegNode', width: int, n_subwords: int) -> None:
109+
if n_subwords == 1:
110+
# External reg is 1 sub-word. Add a packed struct to represent it
111+
type_name = self.get_typdef_name(node, "__fields")
112+
self.push_struct(type_name, "rd_data", packed=True)
113+
current_bit = 0
114+
for field in node.fields():
115+
if not field.is_sw_readable:
116+
continue
117+
if field.low > current_bit:
118+
# Add padding
119+
self.add_member(
120+
f"_reserved_{field.low - 1}_{current_bit}",
121+
field.low - current_bit
122+
)
123+
self.add_member(
124+
kwf(field.inst_name),
125+
field.width
126+
)
127+
current_bit = field.high + 1
128+
129+
# Add end padding if needed
130+
if current_bit != width:
131+
self.add_member(
132+
f"_reserved_{width - 1}_{current_bit}",
133+
width - current_bit
134+
)
135+
self.pop_struct()
136+
else:
137+
# Multiple sub-words. Cannot generate a struct
138+
self.add_member("rd_data", width)
139+
107140
def enter_Field(self, node: 'FieldNode') -> None:
108141
type_name = self.get_typdef_name(node)
109142
self.push_struct(type_name, kwf(node.inst_name))
@@ -150,14 +183,14 @@ class OutputStructGenerator_Hier(HWIFStructGenerator):
150183
def __init__(self, hwif: 'Hwif') -> None:
151184
super().__init__(hwif, "hwif_out")
152185

153-
def get_typdef_name(self, node:'Node') -> str:
186+
def get_typdef_name(self, node:'Node', suffix: str = "") -> str:
154187
base = node.get_rel_path(
155188
self.top_node.parent,
156189
hier_separator="__",
157190
array_suffix="x",
158191
empty_array_suffix="x"
159192
)
160-
return f'{base}__out_t'
193+
return f'{base}{suffix}__out_t'
161194

162195
def _add_external_block_members(self, node: 'AddressableNode') -> None:
163196
self.add_member("req")
@@ -193,12 +226,44 @@ def enter_Reg(self, node: 'RegNode') -> Optional[WalkerAction]:
193226
self.add_member("req", n_subwords)
194227
self.add_member("req_is_wr")
195228
if node.has_sw_writable:
196-
self.add_member("wr_data", width)
197-
self.add_member("wr_biten", width)
229+
self.add_external_reg_wr_data("wr_data", node, width, n_subwords)
230+
self.add_external_reg_wr_data("wr_biten", node, width, n_subwords)
198231
return WalkerAction.SkipDescendants
199232

200233
return WalkerAction.Continue
201234

235+
def add_external_reg_wr_data(self, name: str, node: 'RegNode', width: int, n_subwords: int) -> None:
236+
if n_subwords == 1:
237+
# External reg is 1 sub-word. Add a packed struct to represent it
238+
type_name = self.get_typdef_name(node, "__fields")
239+
self.push_struct(type_name, name, packed=True)
240+
current_bit = 0
241+
for field in node.fields():
242+
if not field.is_sw_writable:
243+
continue
244+
if field.low > current_bit:
245+
# Add padding
246+
self.add_member(
247+
f"_reserved_{field.low - 1}_{current_bit}",
248+
field.low - current_bit
249+
)
250+
self.add_member(
251+
kwf(field.inst_name),
252+
field.width
253+
)
254+
current_bit = field.high + 1
255+
256+
# Add end padding if needed
257+
if current_bit != width:
258+
self.add_member(
259+
f"_reserved_{width - 1}_{current_bit}",
260+
width - current_bit
261+
)
262+
self.pop_struct()
263+
else:
264+
# Multiple sub-words. Cannot generate a struct
265+
self.add_member(name, width)
266+
202267
def enter_Field(self, node: 'FieldNode') -> None:
203268
type_name = self.get_typdef_name(node)
204269
self.push_struct(type_name, kwf(node.inst_name))
@@ -229,7 +294,7 @@ def exit_Reg(self, node: 'RegNode') -> None:
229294

230295
#-------------------------------------------------------------------------------
231296
class InputStructGenerator_TypeScope(InputStructGenerator_Hier):
232-
def get_typdef_name(self, node:'Node') -> str:
297+
def get_typdef_name(self, node:'Node', suffix: str = "") -> str:
233298
scope_path = node.get_global_type_name("__")
234299
if scope_path is None:
235300
# Unable to determine a reusable type name. Fall back to hierarchical path
@@ -242,10 +307,10 @@ def get_typdef_name(self, node:'Node') -> str:
242307
else:
243308
extra_suffix = ""
244309

245-
return f'{scope_path}{extra_suffix}__in_t'
310+
return f'{scope_path}{extra_suffix}{suffix}__in_t'
246311

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

261-
return f'{scope_path}{extra_suffix}__out_t'
326+
return f'{scope_path}{extra_suffix}{suffix}__out_t'
262327

263328
#-------------------------------------------------------------------------------
264329
class EnumGenerator:

src/peakrdl_regblock/struct_generator.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,26 @@ def __str__(self) -> str:
4141

4242

4343
class _TypedefStruct(_StructBase):
44-
def __init__(self, type_name: str, inst_name: Optional[str] = None, array_dimensions: Optional[List[int]] = None):
44+
def __init__(self, type_name: str, inst_name: Optional[str] = None, array_dimensions: Optional[List[int]] = None, packed: bool = False):
4545
super().__init__()
4646
self.type_name = type_name
4747
self.inst_name = inst_name
4848
self.array_dimensions = array_dimensions
49+
self.packed = packed
4950

5051
def __str__(self) -> str:
51-
return (
52-
"typedef struct {\n"
53-
+ super().__str__()
54-
+ f"\n}} {self.type_name};"
55-
)
52+
if self.packed:
53+
return (
54+
"typedef struct packed {\n"
55+
+ super().__str__()
56+
+ f"\n}} {self.type_name};"
57+
)
58+
else:
59+
return (
60+
"typedef struct {\n"
61+
+ super().__str__()
62+
+ f"\n}} {self.type_name};"
63+
)
5664

5765
@property
5866
def instantiation(self) -> str:
@@ -167,8 +175,8 @@ def __init__(self) -> None:
167175
super().__init__()
168176
self.typedefs = OrderedDict() # type: OrderedDict[str, _TypedefStruct]
169177

170-
def push_struct(self, type_name: str, inst_name: str, array_dimensions: Optional[List[int]] = None) -> None: # type: ignore # pylint: disable=arguments-renamed
171-
s = _TypedefStruct(type_name, inst_name, array_dimensions)
178+
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
179+
s = _TypedefStruct(type_name, inst_name, array_dimensions, packed)
172180
self._struct_stack.append(s)
173181

174182
def pop_struct(self) -> None:

tests/test_external/regblock.rdl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@ addrmap top {
22
reg my_reg {
33
field {sw=rw; hw=r;} whatever[32] = 0;
44
};
5+
reg my_reg_alt {
6+
field {sw=r; hw=w;} whatever_a[3:2] = 0;
7+
field {sw=w; hw=r;} whatever_b[4:4] = 0;
8+
field {sw=rw; hw=r;} whatever_c[15:8] = 0;
9+
};
510
reg my_wide_reg {
611
regwidth = 64;
712
accesswidth = 32;
813
field {sw=rw; hw=r;} whatever = 0;
914
};
1015

11-
external my_reg ext_reg @ 0x00;
16+
external my_reg_alt ext_reg @ 0x00;
1217
my_reg int_reg @ 0x04;
1318
external my_wide_reg wide_ext_reg @ 0x10;
1419
external my_reg ext_reg_array[32] @ 0x100 += 4;

0 commit comments

Comments
 (0)