Skip to content

Commit bfba654

Browse files
committed
Add readable/writable filters to RegNode.fields(). #302
1 parent 53b0e6a commit bfba654

File tree

2 files changed

+56
-18
lines changed

2 files changed

+56
-18
lines changed

src/systemrdl/node.py

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2151,18 +2151,18 @@ def get_property(self, prop_name: str, **kwargs: Any)-> Any:
21512151
return super().get_property(prop_name, **kwargs)
21522152

21532153
@overload
2154-
def fields(self, skip_not_present: bool = True, include_gaps: Literal[False] = False) -> Sequence['FieldNode']: ...
2154+
def fields(self, skip_not_present: bool = True, include_gaps: Literal[False] = False, sw_readable_only: bool = False, sw_writable_only: bool = False) -> Sequence['FieldNode']: ...
21552155

21562156
@overload
2157-
def fields(self, skip_not_present: bool, include_gaps: Literal[True]) -> Sequence[Union['FieldNode', Tuple[int, int]]]: ...
2157+
def fields(self, skip_not_present: bool, include_gaps: Literal[True], sw_readable_only: bool = False, sw_writable_only: bool = False) -> Sequence[Union['FieldNode', Tuple[int, int]]]: ...
21582158

21592159
@overload
2160-
def fields(self, skip_not_present: bool = True, *, include_gaps: Literal[True]) -> Sequence[Union['FieldNode', Tuple[int, int]]]: ...
2160+
def fields(self, skip_not_present: bool = True, *, include_gaps: Literal[True], sw_readable_only: bool = False, sw_writable_only: bool = False) -> Sequence[Union['FieldNode', Tuple[int, int]]]: ...
21612161

21622162
@overload
2163-
def fields(self, skip_not_present: bool = True, include_gaps: bool = False) -> Sequence[Union['FieldNode', Tuple[int, int]]]: ...
2163+
def fields(self, skip_not_present: bool = True, include_gaps: bool = False, sw_readable_only: bool = False, sw_writable_only: bool = False) -> Sequence[Union['FieldNode', Tuple[int, int]]]: ...
21642164

2165-
def fields(self, skip_not_present: bool = True, include_gaps: bool = False) -> Sequence[Union['FieldNode', Tuple[int, int]]]:
2165+
def fields(self, skip_not_present: bool = True, include_gaps: bool = False, sw_readable_only: bool = False, sw_writable_only: bool = False) -> Sequence[Union['FieldNode', Tuple[int, int]]]:
21662166
"""
21672167
Returns a list of all fields of this register.
21682168
@@ -2174,6 +2174,17 @@ def fields(self, skip_not_present: bool = True, include_gaps: bool = False) -> S
21742174
If True, returned list also includes information about gaps between
21752175
fields. Gaps are represented as tuples in the form of: ``(high, low)``
21762176
2177+
.. important::
2178+
Beware that SystemRDL allows fields with opposete software access
2179+
policies to overlap. Consider using this option along with
2180+
``sw_readable_only`` or ``sw_writable_only``
2181+
2182+
sw_readable_only, sw_writable_only: bool
2183+
If either is true, only returns fields that are software readable or
2184+
writable respectively.
2185+
2186+
These options are mutually exclusive and cannot be set simultaneously.
2187+
21772188
Returns
21782189
-------
21792190
:class:`~FieldNode`
@@ -2184,30 +2195,41 @@ def fields(self, skip_not_present: bool = True, include_gaps: bool = False) -> S
21842195
Returns list instead of generator.
21852196
21862197
Added ``include_gaps`` argument
2198+
2199+
2200+
.. versionchanged:: 1.31
2201+
Added ``sw_readable_only`` and ``sw_writable_only`` arguments
21872202
"""
2203+
if sw_readable_only and sw_writable_only:
2204+
raise ValueError("sw_readable_only and sw_writable_only args are mutualy exclusive")
2205+
2206+
fields = []
2207+
for child in self.children(skip_not_present=skip_not_present):
2208+
if not isinstance(child, FieldNode):
2209+
continue
2210+
if sw_readable_only and not child.is_sw_readable:
2211+
continue
2212+
if sw_writable_only and not child.is_sw_writable:
2213+
continue
2214+
fields.append(child)
2215+
21882216
if include_gaps:
21892217
fields_with_gaps: List[Union['FieldNode', Tuple[int, int]]]
21902218
fields_with_gaps = []
21912219
current_bit = 0
2192-
for child in self.children(skip_not_present=skip_not_present):
2193-
if not isinstance(child, FieldNode):
2194-
continue
2195-
if current_bit < child.low:
2220+
for field in fields:
2221+
if current_bit < field.low:
21962222
# Add gap before this field
2197-
fields_with_gaps.append((child.low - 1, current_bit))
2198-
fields_with_gaps.append(child)
2199-
current_bit = max(current_bit, child.high + 1)
2223+
fields_with_gaps.append((field.low - 1, current_bit))
2224+
fields_with_gaps.append(field)
2225+
current_bit = max(current_bit, field.high + 1)
22002226
regwidth = self.get_property('regwidth')
22012227
if current_bit != regwidth:
22022228
# Add gap at end of register
22032229
fields_with_gaps.append((regwidth - 1, current_bit))
22042230
return fields_with_gaps
2205-
else:
2206-
fields = []
2207-
for child in self.children(skip_not_present=skip_not_present):
2208-
if isinstance(child, FieldNode):
2209-
fields.append(child)
2210-
return fields
2231+
2232+
return fields
22112233

22122234

22132235
@property

test/test_node_utils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,22 @@ def tup(field: FieldNode):
585585
self.assertEqual(tup(f[5]), (23, 18))
586586
self.assertEqual( f[6], (31, 24))
587587

588+
f = e.fields(include_gaps=True, sw_readable_only=True)
589+
self.assertEqual(len(f), 5)
590+
self.assertEqual( f[0], (3, 0))
591+
self.assertEqual(tup(f[1]), (7, 4))
592+
self.assertEqual( f[2], (15, 8))
593+
self.assertEqual(tup(f[3]), (20, 16))
594+
self.assertEqual( f[4], (31, 21))
595+
596+
f = e.fields(include_gaps=True, sw_writable_only=True)
597+
self.assertEqual(len(f), 5)
598+
self.assertEqual( f[0], (3, 0))
599+
self.assertEqual(tup(f[1]), (7, 4))
600+
self.assertEqual( f[2], (17, 8))
601+
self.assertEqual(tup(f[3]), (23, 18))
602+
self.assertEqual( f[4], (31, 24))
603+
588604

589605
def test_component_type_name(self):
590606

0 commit comments

Comments
 (0)