Esempio n. 1
0
    df_root = None
    with open(args.input, 'r') as fh:
        df_root = DFProject().loadObject(json.load(fh))
    if not df_root:
        print(f"Failed to open blob from path: {args.input}")
        sys.exit(1)
    print(f"Blob loaded: {df_root.id}")

    # Keep track of all of the nodes we want to preserve
    to_preserve = []

    # For every preserved tree, attempt to resolve it
    print("Preserving tree")
    for path in args.preserve_tree:
        # Resolve this path to a block
        node = df_root.getAllPrincipalNodes()[0].resolvePath(path)
        assert isinstance(node, DFBlock)
        # Add every unique block into the preserve list
        while isinstance(node, DFBlock) and node.parent != None:
            if node not in to_preserve:
                to_preserve.append(node)
            node = node.parent

    # For every preserved port attempt to resolve it
    print("Preserving connectivity")
    for path in args.preserve_connectivity:
        # Resolve this path to a port
        node = df_root.getAllPrincipalNodes()[0].resolvePath(path)
        assert isinstance(node, DFPort)

        def chase_port(port, index):
Esempio n. 2
0
def main():
    # Get arguments
    args = get_args()

    # Read in the DFBlob file
    if not os.path.isfile(args.blob):
        print(f"ERROR: Could not read file at path: {args.blob}")
        sys.exit(255)

    df_root = None
    with open(args.blob, 'r') as fh:
        df_root = DFProject().loadObject(json.load(fh))

    # Identify the first principal node
    try:
        principal = [
            x for x in df_root.getAllPrincipalNodes()
            if isinstance(x, DFBlock)
        ][0]
    except:
        print("ERROR: Failed to locate a principal node")
        sys.exit(1)

    # Dump a list of DFInterconnect types
    if args.top_interconnects or args.interconnects:
        intcs = []
        # Dump interconnects only used in the top-level
        if args.top_interconnects:
            block = df_root.getAllPrincipalNodes()[0]
            if not isinstance(block, DFBlock):
                print("ERROR: Failed to locate a principal node")
                sys.exit(1)
            intcs += block.getInterconnectTypes(depth=0)
        # Dump all interconnects included in the DFProject (not just top-level)
        elif args.interconnects:
            intcs = [
                x for x in df_root.nodes.values()
                if isinstance(x, DFInterconnect)
            ]
        # If test mode is enabled, filter the interconnects
        if args.test:
            intcs = [
                x for x in intcs if run_attribute_test(x,
                                                       args.test,
                                                       args.false,
                                                       args.value,
                                                       None,
                                                       None,
                                                       use_exitcode=False,
                                                       use_print=False)
            ]
        # Chase each interconnect so that we also have all of it's components
        def chase_intc(intc):
            for comp in (x for x in intc.components if x.isComplex()):
                comp_intc = comp.getReference()
                if not comp_intc in intcs:
                    intcs.append(comp_intc)
                chase_intc(comp_intc)

        for intc in intcs[:]:
            chase_intc(intc)
        # Print out all of the interconnects using spaces or newlines
        print((" " if args.spaced else "\n").join([x.id for x in intcs]))

    # Dump the list of root DFBlocks
    elif args.blocks:
        blocks = [x for x in df_root.nodes.values() if isinstance(x, DFBlock)]
        print((" " if args.spaced else "\n").join([x.id for x in blocks]))

    # Dump an address map from a named entry-point
    elif args.address_map:
        entrypoint = df_root.getAllPrincipalNodes()[0].resolvePath(
            args.address_map)
        if not entrypoint:
            print("ERROR: Failed to identify entrypoint: " + entrypoint)
            sys.exit(1)
        # Declare a function to recursively find all address maps
        def find_maps(port, index=0, maps=None, depth=0):
            maps = [] if not maps else maps
            prefix = " | ".join(["" for x in range(depth - 1)])
            # If this is a newly encountered address map, look through all the targets
            if port.block.address_map and port.block.address_map not in maps:
                maps.append(port.block.address_map)
                # Check this port is actually accessible
                rel_addr = entrypoint.getRelativeAddress(port,
                                                         remote_index=index)
                if rel_addr == None: return
                # Print out this address
                print(
                    f"{prefix}{' |- ' if (depth > 0) else ''}{port.block.hierarchicalPath()}: {hex(rel_addr)}"
                )
                for target in port.block.address_map.targets:
                    find_maps(target.port,
                              index=target.port_index,
                              maps=maps,
                              depth=(depth + 1))
            # Else, if we have a output, chase it
            elif len(port.getOutboundConnections()) > 0:
                pathways = port.chaseConnection(index=index)
                for path in pathways:
                    # Look at the last entry in the path (which is the endpoint)
                    find_maps(path[-1][0],
                              index=path[-1][1],
                              maps=maps,
                              depth=depth)
            # Else this is a termination
            else:
                # Check this port is actually accessible
                rel_addr = entrypoint.getRelativeAddress(port,
                                                         remote_index=index)
                if rel_addr == None: return
                # Print out this address
                print(
                    f"{prefix}{' |- ' if (depth > 0) else ''}{port.hierarchicalPath()}[{index}]: {hex(rel_addr)}"
                )

        find_maps(entrypoint)

    # If 'present' or 'absent' lists were provided
    elif len(args.present) > 0 or len(args.absent) > 0:
        missing = [
            x for x in args.present if principal.getAttribute(x) == None
        ]
        extra = [x for x in args.absent if principal.getAttribute(x) != None]
        # Allow either AND or OR operations for a list of 'present' tags
        present_result = ((len(missing) == 0)
                          or (len(missing) < len(args.present)
                              and args.present_or))
        # Allow either AND or OR operations for a list of 'absent' tags
        absent_result = ((len(extra) == 0)
                         or (len(extra) < len(args.absent) and args.absent_or))
        if (present_result and absent_result) ^ args.false:
            result_pass(args.if_true, 0 if args.exitcode else None, True)
        else:
            result_fail(args.if_false, 1 if args.exitcode else None, True)
    # If attribute test mode enabled, then run an attribute comparison
    elif args.test:
        run_attribute_test(principal, args.test, args.false, args.value,
                           args.if_true, args.if_false, args.exitcode)
Esempio n. 3
0
# Import DesignFormat
from designformat import DFProject

# Check that enough arguments have been passed
if len(sys.argv) != 2 or sys.argv[1] == '-h':
    print("usage: repl_cli.py [-h] blob_path")
    print(
        "repl_cli.py: error: the following arguments are required: blob_path")
    sys.exit(0)

# Get hold of the root node
df_root = None
with open(sys.argv[1], 'r') as fh:
    df_root = DFProject().loadObject(json.load(fh))
print("Got df_root object with ID '" + df_root.id + "' of type " +
      type(df_root).__name__)
print("Access the object properties using df_root.id etc.")

# Expose all principal nodes from the root node
print("Exposing principal nodes:")
for node in df_root.getAllPrincipalNodes():
    node_var = node.id.replace(" ", "_")
    print(" - " + node_var + ": " + node.id + " of type " +
          type(node).__name__)
    globals()[node_var] = node

# Start up the REPL
import pdb
pdb.set_trace()
Esempio n. 4
0
def check_apertures(project: DFProject):
    """ Check that register maps of blocks are visible through the aperture

    Args:
        project: Project to check through

    Returns:
        list: List of any RuleViolations that have been detected
    """

    # Create storage for any detected violations
    violations = []

    # Check if the principal node is a DFBlock
    if len(project.getAllPrincipalNodes()) == 0:
        report.debug("Project contains no principal nodes - skipping check")
        return violations

    roots = [x for x in project.getAllPrincipalNodes() if type(x) == DFBlock]
    if len(roots) == 0:
        report.debug(
            "Project contains no DFBlock principal nodes - skipping check")
        return violations

    # For each root node, search out every DFBlock with attached registers
    def find_reg_blocks(block):
        found = []
        # First iterate through any child blocks
        for child in block.children:
            found += find_reg_blocks(child)
        # Check if I have registers?
        if len(block.registers) != 0:
            found.append(block)
        return found

    reg_blocks = []
    for block in roots:
        reg_blocks += find_reg_blocks(block)

    report.info(f"Found the following {len(reg_blocks)} register blocks",
                body="\n".join(
                    [" - " + x.hierarchicalPath() for x in reg_blocks]))

    # If we didn't find any register blocks, skip the check
    if len(reg_blocks) == 0:
        report.debug("Project contains no register blocks - skipping check")
        return violations

    # Iterate through every located block with registers
    curr_violations = 0
    for block in reg_blocks:
        report.debug(f"Examining block: {block.hierarchicalPath()}")

        # Keep track of how many violations have already been recorded
        curr_violations = len(violations)

        # First, try to locate which port is attached to an address map
        access_port = None
        for port in block.ports.input:
            for port_idx in range(port.count):
                # Find out who drives this port
                # NOTE: This is tuple of a DFPort and the port index (integer)
                driver = chase_driver(port, port_idx)
                # Does the driver has an address map that we can chase through?
                if not driver[0].block.address_map: continue
                # Is there a target on the address map for the driver port?
                if not driver[0].block.address_map.getTarget(
                        driver[0], driver[1]):
                    continue
                # We found our access point!
                access_port = (port, port_idx)
                break

        # If we didn't find an access port, this is a violation
        if access_port == None:
            violations.append(
                RuleViolation(
                    f"Could not establish access port for block {block.hierarchicalPath()}",
                    block))
            continue

        # Now we want to find all address maps in a direct chain
        address_maps = []

        def find_maps(port, port_idx):
            # Get the first address map in the chain
            driver = chase_driver(port, port_idx)
            addr = driver[0].block.address_map
            if not addr: return
            address_maps.append({
                "map": addr,
                "port": driver[0],
                "index": driver[1]
            })
            # Identify the target port for the driver
            tgt = addr.getTarget(driver[0], driver[1])
            if not tgt: return
            # How many initiators can access this target?
            inits = addr.getInitiatorsForTarget(tgt)
            if len(inits) == 0:
                violations.append(
                    RuleViolation(
                        f"No initiators can access port '{driver[0].name}' in address "
                        f"map of '{driver[0].block.hierarchicalPath()}'",
                        node=driver))
                return
            # If we have more than one initiator, the path has diverged - so stop
            if len(inits) > 1: return
            # So if we have exactly one initiator, chase it
            return find_maps(inits[0].port, inits[0].port_index)

        find_maps(*access_port)

        # Check no new violations have been raised
        if len(violations) > curr_violations: continue

        report.debug(
            f"Identified {len(address_maps)} address maps in driving chain for "
            f"port '{access_port[0].hierarchicalPath()}' index {access_port[1]}"
        )

        # Identify the highest address in the register map
        max_reg = None
        for reg in block.registers:
            if type(reg) == DFRegisterGroup:
                for grp_reg in reg.registers:
                    if type(grp_reg) != DFRegister:
                        raise CriticalRuleViolation(
                            f"Invalid node '{reg.id}' of type {type(reg).__name__} "
                            f"in register group", reg)
                    if not max_reg or grp_reg.getOffset() > max_reg.getOffset(
                    ):
                        max_reg = grp_reg
            elif type(reg) == DFRegister:
                if not max_reg or reg.getOffset() > max_reg.getOffset():
                    max_reg = reg
            else:
                raise CriticalRuleViolation(
                    f"Invalid node '{reg.id}' of type {type(reg).__name__} in "
                    f"block's register set", block)
        if max_reg == None:
            report.info(f"No registers found in {block.hierarchicalPath()}")
            return violations
        report.debug(
            f"Maximum register offset of {block.hierarchicalPath()} is "
            f"{hex(max_reg.getOffset())} with size {ceil(max_reg.width / 8)}")
        max_address = max_reg.getOffset() + int(ceil(max_reg.width / 8))

        # Walk each address map checking that register block is accessible
        for addr in address_maps:
            tgt = addr['map'].getTarget(addr['port'], addr['index'])
            # Check maximum address is within the aperture size
            if max_address > tgt.aperture:
                violations.append(
                    RuleViolation(
                        f"Register {block.hierarchicalPath()}.{max_reg.id} at offset "
                        f"{hex(max_reg.getOffset())} does not fit in the address map "
                        f"aperture of {tgt.aperture} bytes.\n"
                        f"Block        : {block.hierarchicalPath()}\n"
                        f"Register     : {max_reg.id} @ {hex(max_reg.getOffset())}\n"
                        f"Map          : {addr['map'].block.hierarchicalPath()}\n"
                        f"Target Offset: {hex(tgt.offset)}\n"
                        f"Aperture Size: {tgt.aperture}\n", block))
                break
            # Examine every initiator in this address map
            for init in addr['map'].initiators:
                tgt_inits = addr['map'].getInitiatorsForTarget(tgt)
                # If this initiator can't access the target, warn about it
                if init not in tgt_inits:
                    report.warning(
                        f"Restricted Access To {block.hierarchicalPath()}",
                        body=f"Register block {block.hierarchicalPath()} cannot "
                        f"be accessed from {init.port.hierarchicalPath()} "
                        f"index {init.port_index}")
                    continue
                # Check that the initiator's offset and mask are sufficient
                init_min = init.offset
                init_max = init.offset + init.mask + 1
                if tgt.offset < init_min or (tgt.offset +
                                             max_address) > init_max:
                    violations.append(
                        RuleViolation(
                            f"Not all registers of {block.id} can be accessed by {init.port.id} "
                            f"index {init.port_index}:\n"
                            f"Block         : {block.hierarchicalPath()}\n"
                            f"Address Map   : {addr['map'].block.hierarchicalPath()}\n"
                            f"Target Port   : {tgt.port.id}\n"
                            f"Target Min    : {hex(tgt.offset)}\n"
                            f"Target Max    : {hex(tgt.offset + max_address)}\n"
                            f"Initiator Port: {init.port.id}\n"
                            f"Initiator Min : {hex(init_min)}\n"
                            f"Initiator Max : {hex(init_max)}\n", block))
                    continue

        # Check we have no new violations
        if len(violations) > curr_violations: continue

    # Return the list of detected violations
    return violations