Skip to content

Commit cefaf9a

Browse files
authored
Merge pull request #277 from krcb197/276-optimise-test_field_encoding_properties
optimise `test field encoding` properties main field test
2 parents 6f08aca + f4eee76 commit cefaf9a

5 files changed

Lines changed: 108 additions & 68 deletions

File tree

src/peakrdl_python/__about__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@
1717
1818
Variables that describes the peakrdl-python Package
1919
"""
20-
__version__ = "3.0.0rc6"
20+
__version__ = "3.0.0rc7"

src/peakrdl_python/lib_test/_common_base_test_class.py

Lines changed: 93 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -41,20 +41,23 @@
4141
from ..lib.base_register import BaseReg
4242
from ..lib import Node
4343
from ..lib import Base
44+
from ..lib import SystemRDLEnum
4445
from .utilities import get_field_bitmask_int, get_field_inv_bitmask
4546
from ..sim_lib.simulator import BaseSimulator
4647

48+
4749
class NodeIterators:
4850
"""
4951
The Node Iterator class is intended to an efficient way to define the iterators of particular
5052
type that are present on a node
5153
"""
5254
__slots__ = ['__node_descriptions']
53-
def __init__(self, *args:Union[str, tuple[str, list[int]]]):
55+
56+
def __init__(self, *args: Union[str, tuple[str, list[int]]]):
5457
self.__node_descriptions = args
5558

5659
@staticmethod
57-
def __rolled_item(item:Union[str, tuple[str, list[int]]]) -> str:
60+
def __rolled_item(item: Union[str, tuple[str, list[int]]]) -> str:
5861
if isinstance(item, tuple):
5962
return item[0]
6063
return item
@@ -64,7 +67,7 @@ def rolled(self) -> set[str]:
6467
"""
6568
name of all the rolled nodes in a set
6669
"""
67-
return { self.__rolled_item(item) for item in self.__node_descriptions }
70+
return {self.__rolled_item(item) for item in self.__node_descriptions}
6871

6972
@property
7073
def unrolled(self) -> set[str]:
@@ -74,7 +77,7 @@ def unrolled(self) -> set[str]:
7477
return_list = []
7578
for item in self.__node_descriptions:
7679
if isinstance(item, tuple):
77-
dim_set = list(product(*[range(dim) for dim in item[1]]))
80+
dim_set = list(product(*[range(dim) for dim in item[1]]))
7881
for dim in dim_set:
7982
# to match the systemrdl compiler dimension put into the inst name of
8083
# the array, the name must be item[x][y]
@@ -84,6 +87,7 @@ def unrolled(self) -> set[str]:
8487
return_list.append(item)
8588
return set(return_list)
8689

90+
8791
class CommonTestBase(unittest.TestCase, ABC):
8892
"""
8993
Base Test class for the autogenerated register test to be used for the async and
@@ -107,17 +111,17 @@ def legacy_block_access(self) -> bool:
107111
# pylint:disable-next=too-many-arguments
108112
def _single_field_property_test(self, *,
109113
fut: Union[FieldReadWrite,
110-
FieldReadOnly,
111-
FieldWriteOnly,
112-
FieldEnumReadWrite,
113-
FieldEnumReadOnly,
114-
FieldEnumWriteOnly,
115-
FieldAsyncReadOnly,
116-
FieldAsyncWriteOnly,
117-
FieldAsyncReadWrite,
118-
FieldEnumAsyncReadOnly,
119-
FieldEnumAsyncWriteOnly,
120-
FieldEnumAsyncReadWrite],
114+
FieldReadOnly,
115+
FieldWriteOnly,
116+
FieldEnumReadWrite,
117+
FieldEnumReadOnly,
118+
FieldEnumWriteOnly,
119+
FieldAsyncReadOnly,
120+
FieldAsyncWriteOnly,
121+
FieldAsyncReadWrite,
122+
FieldEnumAsyncReadOnly,
123+
FieldEnumAsyncWriteOnly,
124+
FieldEnumAsyncReadWrite],
121125
lsb: int,
122126
msb: int,
123127
low: int,
@@ -137,7 +141,7 @@ def _single_field_property_test(self, *,
137141
self.assertEqual(fut.inverse_bitmask, get_field_inv_bitmask(fut))
138142
width = (fut.high - fut.low) + 1
139143
self.assertEqual(fut.width, width)
140-
self.assertEqual(fut.max_value, (2**width) - 1)
144+
self.assertEqual(fut.max_value, (2 ** width) - 1)
141145
self.assertEqual(fut.is_volatile, is_volatile)
142146

143147
if default is None:
@@ -284,9 +288,9 @@ def _single_regfile_property_test(self, *,
284288
self.__bad_attribute_test(dut=dut)
285289

286290
def __single_node_rdl_name_and_desc_test(self,
287-
dut: Base,
288-
rdl_name: Optional[str],
289-
rdl_desc: Optional[str]) -> None:
291+
dut: Base,
292+
rdl_name: Optional[str],
293+
rdl_desc: Optional[str]) -> None:
290294
"""
291295
Check the SystemRDL Name and Desc properties for a node
292296
"""
@@ -302,8 +306,8 @@ def __single_node_rdl_name_and_desc_test(self,
302306

303307
def __test_node_inst_name(self,
304308
dut: Base,
305-
parent_full_inst_name:Optional[str],
306-
inst_name:str) -> None:
309+
parent_full_inst_name: Optional[str],
310+
inst_name: str) -> None:
307311
"""
308312
Test the `inst_name` and `full_inst_name` attributes of a node
309313
"""
@@ -337,11 +341,11 @@ def __test_name_map(self, dut: Node, child_names: set[str]) -> None:
337341

338342
def _test_field_iterators(self, *,
339343
rut: Union[RegReadOnly,
340-
RegReadWrite,
341-
RegWriteOnly,
342-
RegAsyncReadOnly,
343-
RegAsyncReadWrite,
344-
RegAsyncWriteOnly],
344+
RegReadWrite,
345+
RegWriteOnly,
346+
RegAsyncReadOnly,
347+
RegAsyncReadWrite,
348+
RegAsyncWriteOnly],
345349
has_sw_readable: bool,
346350
has_sw_writable: bool,
347351
readable_fields: set[str],
@@ -354,7 +358,7 @@ def _test_field_iterators(self, *,
354358
)):
355359
raise TypeError(f'Register was expected to readable, got {type(rut)}')
356360

357-
child_readable_field_names = { field.inst_name for field in rut.readable_fields}
361+
child_readable_field_names = {field.inst_name for field in rut.readable_fields}
358362

359363
self.assertEqual(readable_fields, child_readable_field_names)
360364
else:
@@ -382,16 +386,16 @@ def _test_field_iterators(self, *,
382386
self.assertEqual(readable_fields | writeable_fields, child_field_names)
383387

384388
# Check the child name map
385-
self.__test_name_map(dut=rut, child_names= readable_fields | writeable_fields)
389+
self.__test_name_map(dut=rut, child_names=readable_fields | writeable_fields)
386390

387391
def _test_register_iterators(self,
388392
dut: Union[AddressMap, AsyncAddressMap, RegFile, AsyncRegFile,
389-
MemoryReadOnly, MemoryReadOnlyLegacy,
390-
MemoryWriteOnly, MemoryWriteOnlyLegacy,
391-
MemoryReadWrite, MemoryReadWriteLegacy,
392-
MemoryAsyncReadOnly, MemoryAsyncReadOnlyLegacy,
393-
MemoryAsyncWriteOnly, MemoryAsyncWriteOnlyLegacy,
394-
MemoryAsyncReadWrite, MemoryAsyncReadWriteLegacy],
393+
MemoryReadOnly, MemoryReadOnlyLegacy,
394+
MemoryWriteOnly, MemoryWriteOnlyLegacy,
395+
MemoryReadWrite, MemoryReadWriteLegacy,
396+
MemoryAsyncReadOnly, MemoryAsyncReadOnlyLegacy,
397+
MemoryAsyncWriteOnly, MemoryAsyncWriteOnlyLegacy,
398+
MemoryAsyncReadWrite, MemoryAsyncReadWriteLegacy],
395399
readable_registers: NodeIterators,
396400
writeable_registers: NodeIterators) -> None:
397401

@@ -400,8 +404,8 @@ def _test_register_iterators(self,
400404
MemoryReadWrite, MemoryReadWriteLegacy,
401405
MemoryAsyncReadOnly, MemoryAsyncReadOnlyLegacy,
402406
MemoryAsyncReadWrite, MemoryAsyncReadWriteLegacy)):
403-
child_readable_reg_names = { reg.inst_name for reg in
404-
dut.get_readable_registers(unroll=True)}
407+
child_readable_reg_names = {reg.inst_name for reg in
408+
dut.get_readable_registers(unroll=True)}
405409
self.assertEqual(readable_registers.unrolled, child_readable_reg_names)
406410
child_readable_reg_names = {reg.inst_name for reg in
407411
dut.get_readable_registers(unroll=False)}
@@ -443,7 +447,6 @@ def _test_register_iterators(self,
443447
child_names=readable_registers.rolled |
444448
writeable_registers.rolled)
445449

446-
447450
def _test_memory_iterators(self,
448451
dut: Union[AddressMap, AsyncAddressMap],
449452
memories: NodeIterators) -> None:
@@ -494,3 +497,56 @@ def _test_regfile_iterators(self,
494497
self.__test_name_map(dut=dut, child_names=readable_registers.rolled |
495498
writeable_registers.rolled |
496499
sections.rolled)
500+
501+
def _full_to_reduced_enum_conversion(
502+
self,
503+
full_enum_def: dict[str, tuple[int, Optional[str], Optional[str]]]) -> dict[str, int]:
504+
return {key:value[0] for key,value in full_enum_def.items() }
505+
506+
def _test_enum_def_rdl_name_desc_(
507+
self,
508+
fut: Union[FieldEnumReadOnly, FieldEnumReadOnly, FieldEnumWriteOnly,
509+
FieldEnumAsyncReadOnly, FieldEnumAsyncReadOnly, FieldEnumAsyncWriteOnly],
510+
full_enum_def: dict[str, tuple[int, Optional[str], Optional[str]]]) -> None:
511+
"""
512+
Check that the enumeration in the field matches the enumeration specifed in the
513+
systemRDL
514+
515+
Args:
516+
fut: field node
517+
full_enum_def: definition of the enumeration a dictionary, with the of the
518+
entry as a key and the value a tuple that has:
519+
1. int value encoding the enumeration
520+
2. system RDL name (or None)
521+
3. system RDL name (or None)
522+
523+
Returns: None
524+
525+
"""
526+
527+
# pylint does not realise this is a class being returned rather than an object, so
528+
# is unhappy with the name
529+
# pylint:disable-next=invalid-name
530+
EnumCls = fut.enum_cls
531+
for name, value in full_enum_def.items():
532+
enum_inst = EnumCls[name]
533+
self.assertEqual(enum_inst.value, value[0])
534+
535+
if issubclass(EnumCls, SystemRDLEnum):
536+
if value[1] is None:
537+
self.assertIsNone(enum_inst.rdl_name)
538+
else:
539+
self.assertEqual(enum_inst.rdl_name, value[1])
540+
541+
if value[2] is None:
542+
self.assertIsNone(enum_inst.rdl_desc)
543+
else:
544+
self.assertEqual(enum_inst.rdl_desc, value[2])
545+
546+
else:
547+
# if using a legacy enumeration, then the systemRDL name and desc must be None
548+
# as the legacy enum did not support these
549+
self.assertIsNone(value[1])
550+
self.assertIsNone(value[2])
551+
self.assertFalse(hasattr(enum_inst, 'rdl_name'))
552+
self.assertFalse(hasattr(enum_inst, 'rdl_desc'))

src/peakrdl_python/lib_test/async_reg_base_test_class.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
import unittest
2626
from abc import ABC, abstractmethod
27-
from typing import Union
27+
from typing import Union, Optional
2828
from unittest.mock import patch, Mock, call
2929
from itertools import product, chain, combinations
3030
from collections.abc import Iterable
@@ -299,7 +299,7 @@ async def __single_enum_field_write_test(self,
299299
async def _single_enum_field_read_and_write_test(
300300
self,
301301
fut: Union[FieldEnumAsyncReadOnly, FieldEnumAsyncReadOnly, FieldEnumAsyncWriteOnly],
302-
enum_definition: dict[str, int],
302+
full_enum_def: dict[str, tuple[int, Optional[str], Optional[str]]],
303303
is_sw_readable: bool,
304304
is_sw_writable: bool) -> None:
305305
"""
@@ -314,6 +314,10 @@ async def _single_enum_field_read_and_write_test(
314314
is_sw_readable=is_sw_readable,
315315
is_sw_writable=is_sw_writable)
316316

317+
# split the enum definition from the full enum definition
318+
self._test_enum_def_rdl_name_desc_(fut=fut, full_enum_def=full_enum_def)
319+
enum_definition = self._full_to_reduced_enum_conversion(full_enum_def)
320+
317321
if is_sw_readable:
318322
if not isinstance(fut, (FieldEnumAsyncReadOnly, FieldEnumAsyncReadWrite)):
319323
raise TypeError('Test can not proceed as the fut is not a readable field')

src/peakrdl_python/lib_test/base_reg_test_class.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
Python tool. It provide the base class for the autogenerated tests
2323
"""
2424
from abc import ABC, abstractmethod
25-
from typing import Union
25+
from typing import Union, Optional
2626
from unittest.mock import patch, Mock, call
2727
from itertools import product, chain, combinations
2828
from collections.abc import Iterable
@@ -292,7 +292,7 @@ def __single_enum_field_write_test(self,
292292
def _single_enum_field_read_and_write_test(
293293
self,
294294
fut: Union[FieldEnumReadOnly, FieldEnumReadOnly, FieldEnumWriteOnly],
295-
enum_definition: dict[str, int],
295+
full_enum_def: dict[str, tuple[int, Optional[str], Optional[str]]],
296296
is_sw_readable: bool,
297297
is_sw_writable: bool) -> None:
298298
"""
@@ -307,6 +307,10 @@ def _single_enum_field_read_and_write_test(
307307
is_sw_readable=is_sw_readable,
308308
is_sw_writable=is_sw_writable)
309309

310+
# split the enum definition from the full enum definition
311+
self._test_enum_def_rdl_name_desc_(fut=fut, full_enum_def=full_enum_def)
312+
enum_definition = self._full_to_reduced_enum_conversion(full_enum_def)
313+
310314
if is_sw_readable:
311315
if not isinstance(fut, (FieldEnumReadOnly, FieldEnumReadWrite)):
312316
raise TypeError('Test can not proceed as the fut is not a readable field')

src/peakrdl_python/templates/addrmap_tb.py.jinja

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -82,31 +82,7 @@ from ._{{top_node.inst_name}}_test_base import random_enum_reg_value
8282

8383
class {{fq_block_name}}_single_access({{top_node.inst_name}}_TestCase): # type: ignore[valid-type,misc]
8484

85-
def test_field_encoding_properties(self) -> None:
86-
"""
87-
Check that enumeration has the name and desc meta data from the systemRDL
88-
"""
89-
{% for node in owned_elements.fields -%}
90-
{% if 'encode' in node.list_properties() %}
91-
with self.subTest(msg='field: {{'.'.join(node.get_path_segments())}}'):
92-
# test properties of field: {{'.'.join(node.get_path_segments())}}
93-
{% for encoding_entry in node.get_property('encode') %}
94-
self.assertEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.enum_cls.{{encoding_entry.name | upper}}.value, {{encoding_entry.value}})
95-
{% if not legacy_enum_type %}
96-
{% if encoding_entry.rdl_name is none %}
97-
self.assertIsNone(self.dut.{{'.'.join(get_python_path_segments(node))}}.enum_cls.{{encoding_entry.name | upper}}.rdl_name)
98-
{% else %}
99-
self.assertEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.enum_cls.{{encoding_entry.name | upper}}.rdl_name, {{encoding_entry.rdl_name | tojson}})
100-
{% endif %}
101-
{% if encoding_entry.rdl_desc is none %}
102-
self.assertIsNone(self.dut.{{'.'.join(get_python_path_segments(node))}}.enum_cls.{{encoding_entry.name | upper}}.rdl_desc)
103-
{% else %}
104-
self.assertEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.enum_cls.{{encoding_entry.name | upper}}.rdl_desc, {{encoding_entry.rdl_desc | tojson}})
105-
{% endif %}
106-
{% endif %}
107-
{% endfor %}
108-
{% endif %}
109-
{% endfor %}
85+
11086

11187
def test_user_defined_properties(self) -> None:
11288
"""
@@ -188,7 +164,7 @@ class {{fq_block_name}}_single_access({{top_node.inst_name}}_TestCase): # type:
188164
{% if asyncoutput %}await {%endif %}self._single_int_field_read_and_write_test(fut=self.dut.{{'.'.join(get_python_path_segments(node))}}, is_sw_readable={{node.is_sw_readable}}, is_sw_writable={{node.is_sw_writable}})
189165
{%- else %}
190166
{% if asyncoutput %}await {%endif %}self._single_enum_field_read_and_write_test(fut=self.dut.{{'.'.join(get_python_path_segments(node))}}, # type: ignore[arg-type]
191-
is_sw_readable={{node.is_sw_readable}}, is_sw_writable={{node.is_sw_writable}}, enum_definition={ {% for enum_entry in node.get_property('encode') %}'{{enum_entry.name.upper()}}':{{enum_entry.value}},{% endfor %} })
167+
is_sw_readable={{node.is_sw_readable}}, is_sw_writable={{node.is_sw_writable}}, full_enum_def={ {% for enum_entry in node.get_property('encode') %}'{{enum_entry.name.upper()}}':({{enum_entry.value}}, {% if enum_entry.rdl_name is none or legacy_enum_type or skip_systemrdl_name_and_desc_properties %}None{% else %}{{enum_entry.rdl_name | tojson}}{% endif %}, {% if enum_entry.rdl_desc is none or legacy_enum_type or skip_systemrdl_name_and_desc_properties %}None{% else %}{{enum_entry.rdl_desc | tojson}}{% endif %}),{% endfor %} })
192168
{%- endif %}
193169
{%- endfor %}
194170

0 commit comments

Comments
 (0)