Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/peakrdl_python/__about__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@

Variables that describes the peakrdl-python Package
"""
__version__ = "3.0.0rc6"
__version__ = "3.0.0rc7"
130 changes: 93 additions & 37 deletions src/peakrdl_python/lib_test/_common_base_test_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,23 @@
from ..lib.base_register import BaseReg
from ..lib import Node
from ..lib import Base
from ..lib import SystemRDLEnum
from .utilities import get_field_bitmask_int, get_field_inv_bitmask
from ..sim_lib.simulator import BaseSimulator


class NodeIterators:
"""
The Node Iterator class is intended to an efficient way to define the iterators of particular
type that are present on a node
"""
__slots__ = ['__node_descriptions']
def __init__(self, *args:Union[str, tuple[str, list[int]]]):

def __init__(self, *args: Union[str, tuple[str, list[int]]]):
self.__node_descriptions = args

@staticmethod
def __rolled_item(item:Union[str, tuple[str, list[int]]]) -> str:
def __rolled_item(item: Union[str, tuple[str, list[int]]]) -> str:
if isinstance(item, tuple):
return item[0]
return item
Expand All @@ -64,7 +67,7 @@ def rolled(self) -> set[str]:
"""
name of all the rolled nodes in a set
"""
return { self.__rolled_item(item) for item in self.__node_descriptions }
return {self.__rolled_item(item) for item in self.__node_descriptions}

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


class CommonTestBase(unittest.TestCase, ABC):
"""
Base Test class for the autogenerated register test to be used for the async and
Expand All @@ -107,17 +111,17 @@ def legacy_block_access(self) -> bool:
# pylint:disable-next=too-many-arguments
def _single_field_property_test(self, *,
fut: Union[FieldReadWrite,
FieldReadOnly,
FieldWriteOnly,
FieldEnumReadWrite,
FieldEnumReadOnly,
FieldEnumWriteOnly,
FieldAsyncReadOnly,
FieldAsyncWriteOnly,
FieldAsyncReadWrite,
FieldEnumAsyncReadOnly,
FieldEnumAsyncWriteOnly,
FieldEnumAsyncReadWrite],
FieldReadOnly,
FieldWriteOnly,
FieldEnumReadWrite,
FieldEnumReadOnly,
FieldEnumWriteOnly,
FieldAsyncReadOnly,
FieldAsyncWriteOnly,
FieldAsyncReadWrite,
FieldEnumAsyncReadOnly,
FieldEnumAsyncWriteOnly,
FieldEnumAsyncReadWrite],
lsb: int,
msb: int,
low: int,
Expand All @@ -137,7 +141,7 @@ def _single_field_property_test(self, *,
self.assertEqual(fut.inverse_bitmask, get_field_inv_bitmask(fut))
width = (fut.high - fut.low) + 1
self.assertEqual(fut.width, width)
self.assertEqual(fut.max_value, (2**width) - 1)
self.assertEqual(fut.max_value, (2 ** width) - 1)
self.assertEqual(fut.is_volatile, is_volatile)

if default is None:
Expand Down Expand Up @@ -284,9 +288,9 @@ def _single_regfile_property_test(self, *,
self.__bad_attribute_test(dut=dut)

def __single_node_rdl_name_and_desc_test(self,
dut: Base,
rdl_name: Optional[str],
rdl_desc: Optional[str]) -> None:
dut: Base,
rdl_name: Optional[str],
rdl_desc: Optional[str]) -> None:
"""
Check the SystemRDL Name and Desc properties for a node
"""
Expand All @@ -302,8 +306,8 @@ def __single_node_rdl_name_and_desc_test(self,

def __test_node_inst_name(self,
dut: Base,
parent_full_inst_name:Optional[str],
inst_name:str) -> None:
parent_full_inst_name: Optional[str],
inst_name: str) -> None:
"""
Test the `inst_name` and `full_inst_name` attributes of a node
"""
Expand Down Expand Up @@ -337,11 +341,11 @@ def __test_name_map(self, dut: Node, child_names: set[str]) -> None:

def _test_field_iterators(self, *,
rut: Union[RegReadOnly,
RegReadWrite,
RegWriteOnly,
RegAsyncReadOnly,
RegAsyncReadWrite,
RegAsyncWriteOnly],
RegReadWrite,
RegWriteOnly,
RegAsyncReadOnly,
RegAsyncReadWrite,
RegAsyncWriteOnly],
has_sw_readable: bool,
has_sw_writable: bool,
readable_fields: set[str],
Expand All @@ -354,7 +358,7 @@ def _test_field_iterators(self, *,
)):
raise TypeError(f'Register was expected to readable, got {type(rut)}')

child_readable_field_names = { field.inst_name for field in rut.readable_fields}
child_readable_field_names = {field.inst_name for field in rut.readable_fields}

self.assertEqual(readable_fields, child_readable_field_names)
else:
Expand Down Expand Up @@ -382,16 +386,16 @@ def _test_field_iterators(self, *,
self.assertEqual(readable_fields | writeable_fields, child_field_names)

# Check the child name map
self.__test_name_map(dut=rut, child_names= readable_fields | writeable_fields)
self.__test_name_map(dut=rut, child_names=readable_fields | writeable_fields)

def _test_register_iterators(self,
dut: Union[AddressMap, AsyncAddressMap, RegFile, AsyncRegFile,
MemoryReadOnly, MemoryReadOnlyLegacy,
MemoryWriteOnly, MemoryWriteOnlyLegacy,
MemoryReadWrite, MemoryReadWriteLegacy,
MemoryAsyncReadOnly, MemoryAsyncReadOnlyLegacy,
MemoryAsyncWriteOnly, MemoryAsyncWriteOnlyLegacy,
MemoryAsyncReadWrite, MemoryAsyncReadWriteLegacy],
MemoryReadOnly, MemoryReadOnlyLegacy,
MemoryWriteOnly, MemoryWriteOnlyLegacy,
MemoryReadWrite, MemoryReadWriteLegacy,
MemoryAsyncReadOnly, MemoryAsyncReadOnlyLegacy,
MemoryAsyncWriteOnly, MemoryAsyncWriteOnlyLegacy,
MemoryAsyncReadWrite, MemoryAsyncReadWriteLegacy],
readable_registers: NodeIterators,
writeable_registers: NodeIterators) -> None:

Expand All @@ -400,8 +404,8 @@ def _test_register_iterators(self,
MemoryReadWrite, MemoryReadWriteLegacy,
MemoryAsyncReadOnly, MemoryAsyncReadOnlyLegacy,
MemoryAsyncReadWrite, MemoryAsyncReadWriteLegacy)):
child_readable_reg_names = { reg.inst_name for reg in
dut.get_readable_registers(unroll=True)}
child_readable_reg_names = {reg.inst_name for reg in
dut.get_readable_registers(unroll=True)}
self.assertEqual(readable_registers.unrolled, child_readable_reg_names)
child_readable_reg_names = {reg.inst_name for reg in
dut.get_readable_registers(unroll=False)}
Expand Down Expand Up @@ -443,7 +447,6 @@ def _test_register_iterators(self,
child_names=readable_registers.rolled |
writeable_registers.rolled)


def _test_memory_iterators(self,
dut: Union[AddressMap, AsyncAddressMap],
memories: NodeIterators) -> None:
Expand Down Expand Up @@ -494,3 +497,56 @@ def _test_regfile_iterators(self,
self.__test_name_map(dut=dut, child_names=readable_registers.rolled |
writeable_registers.rolled |
sections.rolled)

def _full_to_reduced_enum_conversion(
self,
full_enum_def: dict[str, tuple[int, Optional[str], Optional[str]]]) -> dict[str, int]:
return {key:value[0] for key,value in full_enum_def.items() }

def _test_enum_def_rdl_name_desc_(
self,
fut: Union[FieldEnumReadOnly, FieldEnumReadOnly, FieldEnumWriteOnly,
FieldEnumAsyncReadOnly, FieldEnumAsyncReadOnly, FieldEnumAsyncWriteOnly],
full_enum_def: dict[str, tuple[int, Optional[str], Optional[str]]]) -> None:
"""
Check that the enumeration in the field matches the enumeration specifed in the
systemRDL

Args:
fut: field node
full_enum_def: definition of the enumeration a dictionary, with the of the
entry as a key and the value a tuple that has:
1. int value encoding the enumeration
2. system RDL name (or None)
3. system RDL name (or None)

Returns: None

"""

# pylint does not realise this is a class being returned rather than an object, so
# is unhappy with the name
# pylint:disable-next=invalid-name
EnumCls = fut.enum_cls
for name, value in full_enum_def.items():
enum_inst = EnumCls[name]
self.assertEqual(enum_inst.value, value[0])

if issubclass(EnumCls, SystemRDLEnum):
if value[1] is None:
self.assertIsNone(enum_inst.rdl_name)
else:
self.assertEqual(enum_inst.rdl_name, value[1])

if value[2] is None:
self.assertIsNone(enum_inst.rdl_desc)
else:
self.assertEqual(enum_inst.rdl_desc, value[2])

else:
# if using a legacy enumeration, then the systemRDL name and desc must be None
# as the legacy enum did not support these
self.assertIsNone(value[1])
self.assertIsNone(value[2])
self.assertFalse(hasattr(enum_inst, 'rdl_name'))
self.assertFalse(hasattr(enum_inst, 'rdl_desc'))
8 changes: 6 additions & 2 deletions src/peakrdl_python/lib_test/async_reg_base_test_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

import unittest
from abc import ABC, abstractmethod
from typing import Union
from typing import Union, Optional
from unittest.mock import patch, Mock, call
from itertools import product, chain, combinations
from collections.abc import Iterable
Expand Down Expand Up @@ -299,7 +299,7 @@ async def __single_enum_field_write_test(self,
async def _single_enum_field_read_and_write_test(
self,
fut: Union[FieldEnumAsyncReadOnly, FieldEnumAsyncReadOnly, FieldEnumAsyncWriteOnly],
enum_definition: dict[str, int],
full_enum_def: dict[str, tuple[int, Optional[str], Optional[str]]],
is_sw_readable: bool,
is_sw_writable: bool) -> None:
"""
Expand All @@ -314,6 +314,10 @@ async def _single_enum_field_read_and_write_test(
is_sw_readable=is_sw_readable,
is_sw_writable=is_sw_writable)

# split the enum definition from the full enum definition
self._test_enum_def_rdl_name_desc_(fut=fut, full_enum_def=full_enum_def)
enum_definition = self._full_to_reduced_enum_conversion(full_enum_def)

if is_sw_readable:
if not isinstance(fut, (FieldEnumAsyncReadOnly, FieldEnumAsyncReadWrite)):
raise TypeError('Test can not proceed as the fut is not a readable field')
Expand Down
8 changes: 6 additions & 2 deletions src/peakrdl_python/lib_test/base_reg_test_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
Python tool. It provide the base class for the autogenerated tests
"""
from abc import ABC, abstractmethod
from typing import Union
from typing import Union, Optional
from unittest.mock import patch, Mock, call
from itertools import product, chain, combinations
from collections.abc import Iterable
Expand Down Expand Up @@ -292,7 +292,7 @@ def __single_enum_field_write_test(self,
def _single_enum_field_read_and_write_test(
self,
fut: Union[FieldEnumReadOnly, FieldEnumReadOnly, FieldEnumWriteOnly],
enum_definition: dict[str, int],
full_enum_def: dict[str, tuple[int, Optional[str], Optional[str]]],
is_sw_readable: bool,
is_sw_writable: bool) -> None:
"""
Expand All @@ -307,6 +307,10 @@ def _single_enum_field_read_and_write_test(
is_sw_readable=is_sw_readable,
is_sw_writable=is_sw_writable)

# split the enum definition from the full enum definition
self._test_enum_def_rdl_name_desc_(fut=fut, full_enum_def=full_enum_def)
enum_definition = self._full_to_reduced_enum_conversion(full_enum_def)

if is_sw_readable:
if not isinstance(fut, (FieldEnumReadOnly, FieldEnumReadWrite)):
raise TypeError('Test can not proceed as the fut is not a readable field')
Expand Down
28 changes: 2 additions & 26 deletions src/peakrdl_python/templates/addrmap_tb.py.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -82,31 +82,7 @@ from ._{{top_node.inst_name}}_test_base import random_enum_reg_value

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

def test_field_encoding_properties(self) -> None:
"""
Check that enumeration has the name and desc meta data from the systemRDL
"""
{% for node in owned_elements.fields -%}
{% if 'encode' in node.list_properties() %}
with self.subTest(msg='field: {{'.'.join(node.get_path_segments())}}'):
# test properties of field: {{'.'.join(node.get_path_segments())}}
{% for encoding_entry in node.get_property('encode') %}
self.assertEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.enum_cls.{{encoding_entry.name | upper}}.value, {{encoding_entry.value}})
{% if not legacy_enum_type %}
{% if encoding_entry.rdl_name is none %}
self.assertIsNone(self.dut.{{'.'.join(get_python_path_segments(node))}}.enum_cls.{{encoding_entry.name | upper}}.rdl_name)
{% else %}
self.assertEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.enum_cls.{{encoding_entry.name | upper}}.rdl_name, {{encoding_entry.rdl_name | tojson}})
{% endif %}
{% if encoding_entry.rdl_desc is none %}
self.assertIsNone(self.dut.{{'.'.join(get_python_path_segments(node))}}.enum_cls.{{encoding_entry.name | upper}}.rdl_desc)
{% else %}
self.assertEqual(self.dut.{{'.'.join(get_python_path_segments(node))}}.enum_cls.{{encoding_entry.name | upper}}.rdl_desc, {{encoding_entry.rdl_desc | tojson}})
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}


def test_user_defined_properties(self) -> None:
"""
Expand Down Expand Up @@ -188,7 +164,7 @@ class {{fq_block_name}}_single_access({{top_node.inst_name}}_TestCase): # type:
{% 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}})
{%- else %}
{% 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]
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 %} })
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 %} })
{%- endif %}
{%- endfor %}

Expand Down