Skip to content

Commit

Permalink
Add option to show gaps between fields in RegNode.fields() utility. #244
Browse files Browse the repository at this point in the history
  • Loading branch information
amykyta3 committed Jan 5, 2025
1 parent fb2d98b commit 3d34089
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 10 deletions.
55 changes: 45 additions & 10 deletions src/systemrdl/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import itertools
from copy import deepcopy, copy
from collections import deque
from typing import TYPE_CHECKING, Optional, Iterator, Any, List, Dict, Union, overload, TypeVar, Type
from typing import TYPE_CHECKING, Optional, Iterator, Any, List, Tuple, Dict
from typing import Sequence, Union, overload, TypeVar, Type

from typing_extensions import Literal

Expand Down Expand Up @@ -1946,15 +1947,29 @@ def get_property(self, prop_name: str, **kwargs: Any)-> Any: ...
def get_property(self, prop_name: str, **kwargs: Any)-> Any:
return super().get_property(prop_name, **kwargs)

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

@overload
def fields(self, skip_not_present: bool, include_gaps: Literal[True]) -> Sequence[Union['FieldNode', Tuple[int, int]]]: ...

@overload
def fields(self, skip_not_present: bool = True, *, include_gaps: Literal[True]) -> Sequence[Union['FieldNode', Tuple[int, int]]]: ...

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

def fields(self, skip_not_present: bool=True) -> List['FieldNode']:
def fields(self, skip_not_present: bool = True, include_gaps: bool = False) -> Sequence[Union['FieldNode', Tuple[int, int]]]:
"""
Returns a list of all immediate fields of this component.
Returns a list of all fields of this register.
Parameters
----------
skip_not_present : bool
skip_not_present: bool
If True, skips children whose 'ispresent' property is set to False
include_gaps: bool
If True, returned list also includes information about gaps between
fields. Gaps are represented as tuples in the form of: ``(high, low)``
Returns
-------
Expand All @@ -1963,13 +1978,33 @@ def fields(self, skip_not_present: bool=True) -> List['FieldNode']:
.. versionchanged:: 1.29
Returns list instead of generator
Returns list instead of generator.
Added ``include_gaps`` argument
"""
children = []
for child in self.children(skip_not_present=skip_not_present):
if isinstance(child, FieldNode):
children.append(child)
return children
if include_gaps:
fields_with_gaps: List[Union['FieldNode', Tuple[int, int]]]
fields_with_gaps = []
current_bit = 0
for child in self.children(skip_not_present=skip_not_present):
if not isinstance(child, FieldNode):
continue
if current_bit != child.low:
# Add gap before this field
fields_with_gaps.append((child.low - 1, current_bit))
fields_with_gaps.append(child)
current_bit = child.high + 1
regwidth = self.get_property('regwidth')
if current_bit != regwidth:
# Add gap at end of register
fields_with_gaps.append((regwidth - 1, current_bit))
return fields_with_gaps
else:
fields = []
for child in self.children(skip_not_present=skip_not_present):
if isinstance(child, FieldNode):
fields.append(child)
return fields


@property
Expand Down
23 changes: 23 additions & 0 deletions test/rdl_src/field_gaps.rdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
addrmap top {
reg {
field {} a[32];
} a;

reg {
field {} a[7:0];
field {} b[15:8];
field {} c[31:16];
} b;

reg {
field {} a[7:1];
field {} b[15:9];
field {} c[30:17];
} c;

reg {
field {} a[7:2];
field {} b[15:10];
field {} c[29:18];
} d;
};
46 changes: 46 additions & 0 deletions test/test_node_utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from unittest_utils import RDLSourceTestCase
from systemrdl.rdltypes import PrecedenceType
from systemrdl.node import RegNode, FieldNode

class TestNodeUtils(RDLSourceTestCase):

Expand Down Expand Up @@ -505,3 +506,48 @@ def test_field_prop_helpers(self):
self.assertEqual(f7.get_property('precedence'), PrecedenceType.hw)
self.assertEqual(f8.get_property('precedence'), PrecedenceType.sw)
self.assertEqual(f9.get_property('precedence'), PrecedenceType.sw)

def test_field_gaps(self):
root = self.compile(
["rdl_src/field_gaps.rdl"],
"top"
)
top = root.top

a: RegNode = top.get_child_by_name("a")
b: RegNode = top.get_child_by_name("b")
c: RegNode = top.get_child_by_name("c")
d: RegNode = top.get_child_by_name("d")

def tup(field: FieldNode):
return (field.high, field.low)

f = a.fields(include_gaps=True)
self.assertEqual(len(f), 1)
self.assertEqual(tup(f[0]), (31, 0))

f = b.fields(include_gaps=True)
self.assertEqual(len(f), 3)
self.assertEqual(tup(f[0]), (7, 0))
self.assertEqual(tup(f[1]), (15, 8))
self.assertEqual(tup(f[2]), (31, 16))

f = c.fields(include_gaps=True)
self.assertEqual(len(f), 7)
self.assertEqual( f[0], (0, 0))
self.assertEqual(tup(f[1]), (7, 1))
self.assertEqual( f[2], (8, 8))
self.assertEqual(tup(f[3]), (15, 9))
self.assertEqual( f[4], (16, 16))
self.assertEqual(tup(f[5]), (30, 17))
self.assertEqual( f[6], (31, 31))

f = d.fields(include_gaps=True)
self.assertEqual(len(f), 7)
self.assertEqual( f[0], (1, 0))
self.assertEqual(tup(f[1]), (7, 2))
self.assertEqual( f[2], (9, 8))
self.assertEqual(tup(f[3]), (15, 10))
self.assertEqual( f[4], (17, 16))
self.assertEqual(tup(f[5]), (29, 18))
self.assertEqual( f[6], (31, 30))

0 comments on commit 3d34089

Please sign in to comment.