Esempio n. 1
0
def elaborate(top_docs, scope, max_depth=None):
    """ Elaborate described design from a top-level tag downwards.

    Run elaboration, starting from a Phhidle YAML schema object. Depending on the
    type of the schema object, different elaboration pathways are followed. All
    results are returned as a DesignFormat DFProject.

    Args:
        top_docs : The top level document to elaborate from
        scope    : An instance of ElaboratorScope that includes all documents
                 : parsed into the tool, allows references to be evaluated.
        max_depth: The maximum depth to elaborate to (optional, by default
                   performs a full depth elaboration - max_depth=None)

    Returns:
        DFProject: A DesignFormat project describing the elaborated design
    """
    # Separate !Config and !Group tags as these need special handling
    other_tags = [x for x in top_docs if type(x) not in [Group, Config, Reg]]
    reg_tags = [x for x in top_docs if type(x) in [Group, Config, Reg]]

    # Create a single project to return
    project = DFProject()

    # Work through all of the non-register tags
    for doc in other_tags:
        if type(doc) in ignored:
            report.debug(
                f"Ignoring top-level tag of type {type(doc).__name__}",
                item=doc)
            continue
        elif not type(doc).__name__ in elaborators:
            raise ElaborationError(
                report.error(
                    f"Unsupported top level type {type(doc).__name__}",
                    item=doc))
        df_obj = elaborators[type(doc).__name__](doc,
                                                 scope,
                                                 max_depth=max_depth)
        if isinstance(df_obj, DFProject):
            project.mergeProject(df_obj)
        else:
            project.addPrincipalNode(df_obj)

    # Special handling for !Config and !Group tags
    if len(reg_tags) > 0:
        configs = [x for x in reg_tags if isinstance(x, Config)]
        if len(configs) == 0:
            config = Config(
                [Register(x.name) for x in reg_tags if isinstance(x, Group)])
            configs.append(config)
        for reg_group in elaborate_registers(configs[0], scope):
            project.addPrincipalNode(reg_group)

    # Return the project
    return project
Esempio n. 2
0
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
Esempio n. 3
0
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