def elaborate_interconnect(his, scope, max_depth=None, project=None): """ Evaluate top-level !His and every interconnect type it references, returning a DFProject. The top-level !His will be a principal node, whilst referenced interconnects will be reference nodes. Args: his : The top-level !His to evaluate scope : The ElaboratorScope object containing all referenced documents max_depth: Ignored at present, provided for compatibility (optional) project : Project to append to, else a new one is created (optional) Returns: DFProject: Project containing the elaborated interconnect """ # Build the top level interconnect df_intc = build_interconnect(his, scope) # If no project, create one and add the interconnect as principal if not project: project = DFProject(his.name, his.source.path) project.addPrincipalNode(df_intc) else: project.addReferenceNode(df_intc) # For any referenced interconnect types, build those as reference nodes for component in df_intc.components: if component.type == DFConstants.COMPONENT.COMPLEX: ref_his = scope.get_document(component.ref, expected=His) if not ref_his: raise ElaborationError( report.error(f"Failed to resolve His {component.ref}")) elaborate_interconnect(ref_his, scope, project=project) # Return the project return project
def elaborate_module(top, scope, max_depth=None): """ Elaborate a !Mod tag instance, expanding hierarchy and resolving connections up to the maximum requested depth. Args: top : The top-level !Mod to elaborate from scope : An ElaboratorScope object containing all documents included directly or indirectly by the top module. max_depth: The maximum depth to elaborate to (optional, by default performs a full depth elaboration - max_depth=None) Returns: DFProject: Contains the elaborated block and all interconnects used """ # Build a new project project = DFProject(top.name, top.source.path) # Build the tree for the root block block = build_tree( top, # The top-level !Mod to evaluate top.name, # Name to use for the top-level !Mod instance None, # No parent exists scope, # Scope to use for elaboration max_depth = max_depth # Maximum depth to elaborate to ) # Attach the block as a principal node to the project project.addPrincipalNode(block) # Get a list of all of the interconnection types directly used by the design def list_interconnects(block): types = [x.type for x in block.getAllPorts()] for child in block.children: types += list_interconnects(child) return types used_types = [] for block in (x for x in project.nodes.values() if isinstance(x, DFBlock)): used_types += list_interconnects(block) # Expand the directly used types to include all referenced types def chase_his(his_ref): his = scope.get_document(his_ref, His) if not his: raise ElaborationError(report.error(f"Could not locate His {his_ref}")) sub_his = [x for x in his.ports if isinstance(x, HisRef)] required = [his] + [scope.get_document(x.ref, His) for x in sub_his] for item in sub_his: required += chase_his(item.ref) return required all_required = [] for his_type in used_types: all_required += chase_his(his_type) # Ensure the list of His types is unique all_required = list(set(all_required)) # Build and attach descriptions of each interconnect type for his in all_required: project.addReferenceNode(build_interconnect(his, scope)) # Log all of the interconnect types that were detected report.info( f"Identified {len(all_required)} interconnect types in the design", body="\n".join((x.name for x in all_required)) ) # Log the design hierarchy def chase_hierarchy(block, depth=0): intro = "" if depth > 0: intro += (" | " * (depth - 1)) + " |-" intro += block.id lines = [intro] for child in block.children: lines += chase_hierarchy(child, depth+1) return lines txt_hier = chase_hierarchy(block) report.info( f"Design hierarchy contains {len(txt_hier)} nodes", body="\n".join(txt_hier) ) # Return the project return project