2020import os
2121from pathlib import Path
2222from shutil import copy
23- from typing import List , NoReturn , Iterable , Tuple , Dict , Any
23+ from typing import List , NoReturn , Iterable , Tuple , Dict , Any , Optional
2424
2525import jinja2 as jj
2626from systemrdl import RDLWalker # type: ignore
2929from systemrdl .node import FieldNode , MemNode , AddressableNode # type: ignore
3030from systemrdl .node import SignalNode # type: ignore
3131from systemrdl .rdltypes import OnReadType , OnWriteType , PropertyReference # type: ignore
32- from systemrdl .rdltypes .user_enum import UserEnumMeta # type: ignore
32+ from systemrdl .rdltypes .user_enum import UserEnum , UserEnumMeta # type: ignore
33+ from systemrdl .rdltypes .user_struct import UserStruct # type: ignore
3334
3435from .systemrdl_node_utility_functions import get_reg_readable_fields , get_reg_writable_fields , \
3536 get_table_block , get_dependent_component , \
3637 get_field_bitmask_hex_string , get_field_inv_bitmask_hex_string , \
3738 get_field_max_value_hex_string , get_reg_max_value_hex_string , get_fully_qualified_type_name , \
3839 uses_enum , uses_memory , \
3940 get_memory_max_entry_value_hex_string , get_memory_width_bytes , \
40- get_field_default_value , get_enum_values
41+ get_field_default_value , get_enum_values , get_properties_to_include , get_reg_fields
4142
4243from .lib import get_array_typecode
4344
@@ -291,7 +292,8 @@ def __export_reg_model(self, # pylint: disable=too-many-arguments
291292 skip_lib_copy : bool ,
292293 asyncoutput : bool ,
293294 legacy_block_access : bool ,
294- show_hidden : bool ) -> None :
295+ show_hidden : bool ,
296+ udp_to_include : Optional [List [str ]]) -> None :
295297
296298 context = {
297299 'print' : print ,
@@ -304,11 +306,14 @@ def __export_reg_model(self, # pylint: disable=too-many-arguments
304306 'systemrdlMemNode' : MemNode ,
305307 'systemrdlAddressableNode' : AddressableNode ,
306308 'systemrdlSignalNode' : SignalNode ,
309+ 'systemrdlUserEnum' : UserEnum ,
310+ 'systemrdlUserStruct' : UserStruct ,
307311 'asyncoutput' : asyncoutput ,
308312 'OnWriteType' : OnWriteType ,
309313 'OnReadType' : OnReadType ,
310314 'PropertyReference' : PropertyReference ,
311315 'isinstance' : isinstance ,
316+ 'str' : str ,
312317 'uses_enum' : uses_enum (top_block ),
313318 'uses_memory' : uses_memory (top_block ),
314319 'get_fully_qualified_type_name' : self ._lookup_type_name ,
@@ -323,6 +328,7 @@ def __export_reg_model(self, # pylint: disable=too-many-arguments
323328 'get_table_block' : get_table_block ,
324329 'get_reg_writable_fields' : get_reg_writable_fields ,
325330 'get_reg_readable_fields' : get_reg_readable_fields ,
331+ 'get_reg_fields' : get_reg_fields ,
326332 'get_memory_max_entry_value_hex_string' : get_memory_max_entry_value_hex_string ,
327333 'get_memory_width_bytes' : get_memory_width_bytes ,
328334 'get_field_default_value' : get_field_default_value ,
@@ -332,7 +338,12 @@ def __export_reg_model(self, # pylint: disable=too-many-arguments
332338 'skip_lib_copy' : skip_lib_copy ,
333339 'version' : __version__ ,
334340 'legacy_block_access' : legacy_block_access ,
335- 'show_hidden' : show_hidden
341+ 'show_hidden' : show_hidden ,
342+ 'udp_to_include' : udp_to_include ,
343+ 'get_properties_to_include' : get_properties_to_include ,
344+ 'dependent_property_enum' :
345+ self ._get_dependent_property_enum (node = top_block ,
346+ udp_to_include = udp_to_include )
336347 }
337348 if legacy_block_access is True :
338349 context ['get_array_typecode' ] = get_array_typecode
@@ -437,7 +448,8 @@ def __export_tests(self, # pylint: disable=too-many-arguments
437448 skip_lib_copy : bool ,
438449 asyncoutput : bool ,
439450 legacy_block_access : bool ,
440- show_hidden : bool ) -> None :
451+ show_hidden : bool ,
452+ udp_to_include : Optional [List [str ]]) -> None :
441453 """
442454
443455 Args:
@@ -492,7 +504,11 @@ def is_reg_array(item: RegNode) -> bool:
492504 'systemrdlMemNode' : MemNode ,
493505 'systemrdlRegfileNode' : RegfileNode ,
494506 'systemrdlAddrmapNode' : AddrmapNode ,
507+ 'systemrdlUserEnum' : UserEnum ,
508+ 'systemrdlUserStruct' : UserStruct ,
495509 'isinstance' : isinstance ,
510+ 'type' : type ,
511+ 'str' : str ,
496512 'get_python_path_segments' : get_python_path_segments ,
497513 'safe_node_name' : safe_node_name ,
498514 'uses_memory' : (len (owned_elements .memories ) > 0 ),
@@ -512,7 +528,12 @@ def is_reg_array(item: RegNode) -> bool:
512528 'version' : __version__ ,
513529 'get_array_typecode' : get_array_typecode ,
514530 'legacy_block_access' : legacy_block_access ,
515- 'show_hidden' : show_hidden
531+ 'show_hidden' : show_hidden ,
532+ 'udp_to_include' : udp_to_include ,
533+ 'get_properties_to_include' : get_properties_to_include ,
534+ 'dependent_property_enum' :
535+ self ._get_dependent_property_enum (node = top_block ,
536+ udp_to_include = udp_to_include )
516537 }
517538
518539
@@ -532,7 +553,8 @@ def export(self, node: Node, path: str, # pylint: disable=too-many-arguments
532553 delete_existing_package_content : bool = True ,
533554 skip_library_copy : bool = False ,
534555 legacy_block_access : bool = True ,
535- show_hidden : bool = False ) -> List [str ]:
556+ show_hidden : bool = False ,
557+ user_defined_properties_to_include : Optional [List [str ]] = None ) -> List [str ]:
536558 """
537559 Generated Python Code and Testbench
538560
@@ -560,6 +582,9 @@ def export(self, node: Node, path: str, # pylint: disable=too-many-arguments
560582 set to true will not be included in the generated python code.
561583 This behaviour can be overridden by setting this property to
562584 true.
585+ user_defined_properties_to_include : A list of strings of the names of user-defined
586+ properties to include. Set to None for nothing
587+ to appear.
563588
564589 Returns:
565590 List[str] : modules that have been exported:
@@ -584,11 +609,28 @@ def export(self, node: Node, path: str, # pylint: disable=too-many-arguments
584609 include_libraries = not skip_library_copy )
585610 package .create_empty_package (cleanup = delete_existing_package_content )
586611
612+ if user_defined_properties_to_include is not None :
613+ # the list of user defined properties may not include the names used by peakrdl python
614+ # for control behaviours
615+ if not isinstance (user_defined_properties_to_include , list ):
616+ raise TypeError (f'The user_defined_properties_to_include must be a list, got '
617+ f'{ type (user_defined_properties_to_include )} ' )
618+ for entry in user_defined_properties_to_include :
619+ if not isinstance (entry , str ):
620+ raise TypeError ('The entries in the user_defined_properties_to_include must '
621+ f'be a str, got { type (entry )} ' )
622+ reserved_names = ['python_hide' , 'python_name' ]
623+ for reserved_name in reserved_names :
624+ if reserved_name in user_defined_properties_to_include :
625+ raise RuntimeError ('It is not permitted to expose a property name used to'
626+ ' build the peakrdl-python wrappers: ' + reserved_name )
627+
587628 self ._build_node_type_table (top_block , show_hidden )
588629
589630 self .__export_reg_model (top_block = top_block , package = package , asyncoutput = asyncoutput ,
590631 skip_lib_copy = skip_library_copy ,
591- legacy_block_access = legacy_block_access , show_hidden = show_hidden )
632+ legacy_block_access = legacy_block_access , show_hidden = show_hidden ,
633+ udp_to_include = user_defined_properties_to_include )
592634
593635 self .__export_simulator (top_block = top_block , package = package , asyncoutput = asyncoutput ,
594636 skip_lib_copy = skip_library_copy ,
@@ -608,7 +650,8 @@ def export(self, node: Node, path: str, # pylint: disable=too-many-arguments
608650 self .__export_tests (top_block = top_block , package = package , asyncoutput = asyncoutput ,
609651 skip_lib_copy = skip_library_copy ,
610652 legacy_block_access = legacy_block_access ,
611- show_hidden = show_hidden )
653+ show_hidden = show_hidden ,
654+ udp_to_include = user_defined_properties_to_include )
612655
613656 return top_block .inst_name
614657
@@ -719,3 +762,43 @@ def _get_dependent_enum(self, node: AddressableNode, show_hidden: bool) -> \
719762 if fully_qualified_enum_name not in enum_needed :
720763 enum_needed .append (fully_qualified_enum_name )
721764 yield field_enum , child_node
765+
766+ def _get_dependent_property_enum (self , node : AddressableNode ,
767+ udp_to_include : Optional [List [str ]]) -> \
768+ List [UserEnumMeta ]:
769+ """
770+ iterable of enums which is used by a descendant of the input node,
771+ this list is de-duplicated
772+ """
773+ if udp_to_include is None :
774+ return []
775+
776+ enum_needed = []
777+
778+ def update_enum_list (node_to_process : AddressableNode ) -> None :
779+
780+ def walk_property_struct_node (value : Any ) -> None :
781+ if isinstance (value , UserEnum ) and type (value ) not in enum_needed :
782+ enum_needed .append (type (value ))
783+
784+ if isinstance (value , UserStruct ):
785+ for sub_value in value .members .values ():
786+ walk_property_struct_node (sub_value )
787+
788+ node_properties = get_properties_to_include (node = node_to_process ,
789+ udp_to_include = udp_to_include )
790+ for node_property_name in node_properties :
791+ node_property = node_to_process .get_property (node_property_name )
792+ if isinstance (node_property , UserEnum ) and type (node_property ) not in enum_needed :
793+ enum_needed .append (type (node_property ))
794+
795+ if isinstance (node_property , UserStruct ):
796+ for sub_value in node_property .members .values ():
797+ walk_property_struct_node (sub_value )
798+
799+ update_enum_list (node_to_process = node )
800+
801+ for child_node in node .descendants ():
802+ update_enum_list (node_to_process = child_node )
803+
804+ return enum_needed
0 commit comments