|
4 | 4 | import os |
5 | 5 | from pathlib import Path |
6 | 6 | from shutil import copyfile |
7 | | -from typing import List, NoReturn |
| 7 | +from typing import List, NoReturn, Iterable, Tuple |
8 | 8 | from glob import glob |
9 | 9 |
|
10 | 10 | import autopep8 # type: ignore |
|
13 | 13 | from systemrdl.node import RootNode, Node, RegNode, AddrmapNode, RegfileNode # type: ignore |
14 | 14 | from systemrdl.node import FieldNode, MemNode, AddressableNode # type: ignore |
15 | 15 | from systemrdl.node import SignalNode # type: ignore |
16 | | -from systemrdl.rdltypes import OnReadType, OnWriteType, PropertyReference # type: ignore |
| 16 | +from systemrdl.rdltypes import OnReadType, OnWriteType, PropertyReference # type: ignore |
| 17 | +from systemrdl.rdltypes.user_enum import UserEnumMeta # type: ignore |
17 | 18 |
|
18 | 19 | from .systemrdl_node_utility_functions import get_reg_readable_fields, get_reg_writable_fields, \ |
19 | | - get_array_dim, get_table_block, get_dependent_enum, get_dependent_component, \ |
| 20 | + get_array_dim, get_table_block, get_dependent_component, \ |
20 | 21 | get_field_bitmask_hex_string, get_field_inv_bitmask_hex_string, \ |
21 | 22 | get_field_max_value_hex_string, get_reg_max_value_hex_string, get_fully_qualified_type_name, \ |
22 | | - uses_enum, fully_qualified_enum_type, uses_memory, \ |
| 23 | + uses_enum, uses_memory, \ |
23 | 24 | get_memory_max_entry_value_hex_string, get_memory_width_bytes, \ |
24 | | - get_field_default_value |
| 25 | + get_field_default_value, get_enum_values |
25 | 26 |
|
26 | 27 | from .lib import get_array_typecode |
27 | 28 |
|
@@ -147,8 +148,9 @@ def export(self, node: Node, path: str, |
147 | 148 | 'get_fully_qualified_type_name': self._lookup_type_name, |
148 | 149 | 'get_array_dim': get_array_dim, |
149 | 150 | 'get_dependent_component': get_dependent_component, |
150 | | - 'get_dependent_enum': get_dependent_enum, |
151 | | - 'get_fully_qualified_enum_type': fully_qualified_enum_type, |
| 151 | + 'get_dependent_enum': self._get_dependent_enum, |
| 152 | + 'get_enum_values': get_enum_values, |
| 153 | + 'get_fully_qualified_enum_type': self._fully_qualified_enum_type, |
152 | 154 | 'get_field_bitmask_hex_string': get_field_bitmask_hex_string, |
153 | 155 | 'get_field_inv_bitmask_hex_string': get_field_inv_bitmask_hex_string, |
154 | 156 | 'get_field_max_value_hex_string': get_field_max_value_hex_string, |
@@ -292,3 +294,57 @@ def _raise_template_error(self, message: str) -> NoReturn: |
292 | 294 |
|
293 | 295 | """ |
294 | 296 | raise PythonExportTemplateError(message) |
| 297 | + |
| 298 | + def _fully_qualified_enum_type(self, |
| 299 | + field_enum: UserEnumMeta, |
| 300 | + root_node: AddressableNode, |
| 301 | + owning_field: FieldNode) -> str: |
| 302 | + """ |
| 303 | + Returns the fully qualified class type name, for an enum |
| 304 | + """ |
| 305 | + if not hasattr(field_enum, '_parent_scope'): |
| 306 | + # this happens if the enum is has been declared in an IPXACT file |
| 307 | + # which is imported |
| 308 | + return self._lookup_type_name(owning_field) + '_' + field_enum.__name__ |
| 309 | + |
| 310 | + parent_scope = getattr(field_enum, '_parent_scope') |
| 311 | + |
| 312 | + if parent_scope is None: |
| 313 | + # this happens if the enum is has been declared in an IPXACT file |
| 314 | + # which is imported |
| 315 | + return self._lookup_type_name(owning_field) + '_' + field_enum.__name__ |
| 316 | + |
| 317 | + if root_node.inst.original_def == parent_scope: |
| 318 | + return field_enum.__name__ |
| 319 | + |
| 320 | + dependent_components = get_dependent_component(root_node) |
| 321 | + |
| 322 | + for component in dependent_components: |
| 323 | + if component.inst.original_def == parent_scope: |
| 324 | + return get_fully_qualified_type_name(component) + '_' + field_enum.__name__ |
| 325 | + |
| 326 | + raise RuntimeError('Failed to find parent node to reference') |
| 327 | + |
| 328 | + def _get_dependent_enum(self, node: AddressableNode) -> \ |
| 329 | + Iterable[Tuple[UserEnumMeta, FieldNode]]: |
| 330 | + """ |
| 331 | + iterable of enums which is used by a descendant of the input node, |
| 332 | + this list is de-duplicated |
| 333 | +
|
| 334 | + :param node: node to analysis |
| 335 | + :return: nodes that are dependent on the specified node |
| 336 | + """ |
| 337 | + enum_needed = [] |
| 338 | + for child_node in node.descendants(): |
| 339 | + if isinstance(child_node, FieldNode): |
| 340 | + if 'encode' in child_node.list_properties(): |
| 341 | + # found an field with an enumeration |
| 342 | + |
| 343 | + field_enum = child_node.get_property('encode') |
| 344 | + fully_qualified_enum_name = self._fully_qualified_enum_type(field_enum, |
| 345 | + node, |
| 346 | + child_node) |
| 347 | + |
| 348 | + if fully_qualified_enum_name not in enum_needed: |
| 349 | + enum_needed.append(fully_qualified_enum_name) |
| 350 | + yield field_enum, child_node |
0 commit comments