Exemplo n.º 1
0
def expand_entry(entry, ignore_xs=0x0):
    """Turn all Xs which are not marked in `ignore_xs` into ``0``\ s and
    ``1``\ s.

    The following will expand any Xs in bits ``1..3``\ ::

        >>> entry = RoutingTableEntry(set(), 0b0100, 0xfffffff0 | 0b1100)
        >>> list(expand_entry(entry, 0xfffffff1)) == [
        ...     RoutingTableEntry(set(), 0b0100, 0xfffffff0 | 0b1110),  # 010X
        ...     RoutingTableEntry(set(), 0b0110, 0xfffffff0 | 0b1110),  # 011X
        ... ]
        True

    Parameters
    ----------
    entry : :py:class:`~rig.routing_table.RoutingTableEntry` or similar
        The entry to expand.
    ignore_xs : int
        Bit-mask of Xs which should not be expanded.

    Yield
    -----
    :py:class:`~rig.routing_table.RoutingTableEntry`
        Routing table entries which represent the original entry but with all
        Xs not masked off by `ignore_xs` replaced with 1s and 0s.
    """
    # Get all the Xs in the entry that are not ignored
    xs = (~entry.key & ~entry.mask) & ~ignore_xs

    # Find the most significant X
    for bit in (1 << i for i in range(31, -1, -1)):
        if bit & xs:
            # Yield all the entries with this bit set as 0
            entry_0 = RoutingTableEntry(entry.route, entry.key,
                                        entry.mask | bit, entry.sources)
            for new_entry in expand_entry(entry_0, ignore_xs):
                yield new_entry

            # And yield all the entries with this bit set as 1
            entry_1 = RoutingTableEntry(entry.route, entry.key | bit,
                                        entry.mask | bit, entry.sources)
            for new_entry in expand_entry(entry_1, ignore_xs):
                yield new_entry

            # Stop looking for Xs
            break
    else:
        # If there are no Xs then yield the entry we were given.
        yield entry
Exemplo n.º 2
0
def read_routing_tables(fp):
    """Read routing tables from a file."""
    tables = dict()

    data = fp.read()
    offset = 0
    while offset < len(data):
        # Read the header
        x, y, n_entries = struct.unpack_from("<2BH", data, offset)
        offset += 4

        # Prepare the entries
        entries = [None for _ in range(n_entries)]

        # Read the entries
        for i in range(n_entries):
            key, mask, source_word, route_word = \
                struct.unpack_from("<4I", data, offset)
            offset += 16

            route = {r for r in Routes if route_word & (1 << r)}
            source = {s for s in Routes if source_word & (1 << s)}
            entries[i] = RoutingTableEntry(route, key, mask, source)

        # Store the table
        tables[(x, y)] = entries

    return tables
Exemplo n.º 3
0
def minimise(table):
    """Minimise a routing table."""
    # Remove default entries
    table_ = rde_minimise(table, None)

    # Split the table into sub-tables with the same route.
    subtables = defaultdict(list)
    for entry in table_:
        subtables[entry.route].append((entry.key, entry.mask))

    # Minimise each subtable in turn
    mintables = dict()
    for i, (route, keymasks) in enumerate(iteritems(subtables)):
        trie = Node()

        for key, mask in keymasks:
            insert(trie, key, mask)

        mintables[route] = list(trie.get_keys_and_masks())

    # Return to routing table form
    return [
        RoutingTableEntry(r, k, m) for r, kms in iteritems(mintables)
        for k, m in kms
    ]
Exemplo n.º 4
0
def unpack_table(data):
    # Unpack the header
    length, _ = struct.unpack_from("<2I", data)

    # Unpack the table
    table = [None for __ in range(length)]
    for i in range(length):
        key, mask, route = struct.unpack_from("<3I", data, i * 12 + 8)
        routes = {r for r in Routes if (1 << r) & route}
        table[i] = RoutingTableEntry(routes, key, mask)

    return table
Exemplo n.º 5
0
    def apply(self, aliases):
        """Apply the merge to the routing table it is defined against and get a
        new routing table and alias dictionary.

        Returns
        -------
        [:py:class:`~rig.routing_table.RoutingTableEntry`, ...]
            A new routing table which may be minimised further.
        {(key, mask): {(key, mask), ...}}
            A new aliases dictionary.
        """
        # Create a new routing table of the correct size
        new_size = len(self.routing_table) - len(self.entries) + 1
        new_table = [None for _ in range(new_size)]

        # Create a copy of the aliases dictionary
        aliases = dict(aliases)

        # Get the new entry
        new_entry = RoutingTableEntry(route=self.routing_table[next(
            iter(self.entries))].route,
                                      key=self.key,
                                      mask=self.mask,
                                      sources=self.sources)
        aliases[(self.key, self.mask)] = our_aliases = set([])

        # Iterate through the old table copying entries acrosss
        insert = 0
        for i, entry in enumerate(self.routing_table):
            # If this is the insertion point then insert
            if i == self.insertion_index:
                new_table[insert] = new_entry
                insert += 1

            if i not in self.entries:
                # If this entry isn't to be removed then copy it across to the
                # new table.
                new_table[insert] = entry
                insert += 1
            else:
                # If this entry is to be removed then add it to the aliases
                # dictionary.
                km = (entry.key, entry.mask)
                our_aliases.update(aliases.pop(km, {km}))

        # If inserting beyond the end of the old table then insert at the end
        # of the new table.
        if self.insertion_index == len(self.routing_table):
            new_table[insert] = new_entry

        return new_table, aliases
Exemplo n.º 6
0
def use_espresso(table, times, provide_offset=True):
    """Call Espresso with appropriate arguments to minimise a routing table."""
    # Begin by breaking entries up into sets of unique routes
    route_entries = defaultdict(set)
    for entry in table:
        route_entries[frozenset(entry.route)].add((entry.key, entry.mask))

    # Sort these groups into ascending order of length
    groups = sorted(route_entries.items(), key=lambda kv: len(kv[1]))

    # Prepare to create a new table
    new_table = list()

    # Minimise each group individually using all the groups later on in the
    # table as the off-set.
    for i, (route, entries) in enumerate(groups):
        with tempfile.NamedTemporaryFile() as f:
            if provide_offset:
                f.write(b".i 32\n.o 1\n.type fr\n")
            else:
                f.write(b".i 32\n.o 1\n.type f\n")

            # Write the "on-set"
            for key, mask in entries:
                f.write(key_mask_to_espresso(key, mask) + b" 1\n")

            # Write the offset
            if provide_offset:
                for _, entries in groups[i+1:]:
                    for key, mask in entries:
                        f.write(key_mask_to_espresso(key, mask) + b" 0\n")

            f.write(b".e")
            f.flush()

            # Perform the minimisation and read back the result
            with tempfile.TemporaryFile() as g:
                t = time.time()
                subprocess.call(["espresso", f.name], stdout=g)
                times.append(time.time() - t)

                # Read back from g()
                g.seek(0)
                for line in g:
                    if b'.' not in line:
                        key, mask = espresso_to_key_mask(
                            line.decode("utf-8").strip().split()[0])
                        new_table.append(RoutingTableEntry(route, key, mask))

    return new_table
Exemplo n.º 7
0
def use_espresso_on_entire_table(table, provide_offset):
    """Call Espresso with appropriate arguments to minimise a routing table."""
    # Begin by breaking entries up into sets of unique routes
    route_indices = dict()
    bits_to_route = dict()
    for entry in table:
        if entry.route not in route_indices:
            route_indices[entry.route] = 1 << len(route_indices)
            bits_to_route[route_indices[entry.route]] = entry.route

    # Prepare to create a new table
    new_table = list()

    # Minimise the table, using the route indices as the function output
    with tempfile.NamedTemporaryFile() as f:
        if provide_offset:
            f.write(b".i 32\n.o %u\n.type fr\n" % len(route_indices))
        else:
            f.write(b".i 32\n.o %u\n.type f\n" % len(route_indices))

        # Write the "on-set"
        for entry in table:
            f.write(
                key_mask_to_espresso(entry.key, entry.mask) +
                " {1:0{0}b}\n".format(
                    len(route_indices),
                    route_indices[entry.route]).encode("utf-8")
            )

        f.write(b".e")
        f.flush()

        # Perform the minimisation and read back the result
        with tempfile.TemporaryFile() as g:
            subprocess.call(["espresso", f.name], stdout=g)

            # Read back from g()
            g.seek(0)
            for line in g:
                if b'.' not in line:
                    keymask, route_str = \
                        line.decode("utf-8").strip().split(" ", 1)
                    key, mask = espresso_to_key_mask(keymask)
                    route = bits_to_route[int(route_str, base=2)]
                    new_table.append(RoutingTableEntry(route, key, mask))

    return new_table
        #0x01, 1, # NT_CMD_SLEEP 1us
        0x02,  # NT_CMD_BARRIER
        0x00,  # NT_CMD_EXIT
    ]

    data = struct.pack("<{}I".format(len(commands) + 1),
                       len(commands) * 4, *commands)
    mem = mc.sdram_alloc_as_filelike(max(len(data),
                                         4 + num_samples * num_vals * 4),
                                     tag=1,
                                     x=0,
                                     y=0)
    mem.write(data)

    # Catch-all route
    entries = [RoutingTableEntry(set([Routes.core_1]), 0x00000000, 0x00000000)]
    mc.load_routing_table_entries(entries, x=0, y=0)

    mc.load_application(binary, {(0, 0): set([1])})
    time.sleep(1.5)
    mc.wait_for_cores_to_reach_state("sync0", 1)
    mc.send_signal("sync0")
    mem.seek(0)
    error_state = struct.unpack("<I", mem.read(4))[0]
    print("Error state: {}".format(error_state))
    print(
        struct.unpack("<{}I".format(num_samples * num_vals),
                      mem.read(4 * num_samples * num_vals)))

    if error_state:
        input("press enter to kill...")
Exemplo n.º 9
0
def routing_tree_to_tables(routes, net_keys):
    """Convert a set of
    :py:class:`~rig.place_and_route.routing_tree.RoutingTree` s into a per-chip
    set of routing tables.

    .. warning::
        A :py:exc:`rig.routing_table.MultisourceRouteError` will
        be raised if entries with identical keys and masks but with differing
        routes are generated. This is not a perfect test, entries which would
        otherwise collide are not spotted.

    .. warning::
        The routing trees provided are assumed to be correct and continuous
        (not missing any hops). If this is not the case, the output is
        undefined.

    .. note::
        If a routing tree has a terminating vertex whose route is set to None,
        that vertex is ignored.

    Parameters
    ----------
    routes : {net: :py:class:`~rig.place_and_route.routing_tree.RoutingTree`, \
              ...}
        The complete set of RoutingTrees representing all routes in the system.
        (Note: this is the same data structure produced by routers in the
        :py:mod:`~rig.place_and_route` module.)
    net_keys : {net: (key, mask), ...}
        The key and mask associated with each net.

    Returns
    -------
    {(x, y): [:py:class:`~rig.routing_table.RoutingTableEntry`, ...]
    """
    # Pairs of inbound and outbound routes.
    InOutPair = namedtuple("InOutPair", "ins, outs")

    # {(x, y): {(key, mask): _InOutPair}}
    route_sets = defaultdict(OrderedDict)

    for net, routing_tree in iteritems(routes):
        key, mask = net_keys[net]

        # The direction is the Links entry which describes the direction in
        # which we last moved to reach the node (or None for the root).
        for direction, (x, y), out_directions in routing_tree.traverse():
            # Determine the in_direction
            in_direction = direction
            if in_direction is not None:
                in_direction = direction.opposite

            # Add a routing entry
            if (key, mask) in route_sets[(x, y)]:
                # If there is an existing route set raise an error if the out
                # directions are not equivalent.
                if route_sets[(x, y)][(key, mask)].outs != out_directions:
                    raise MultisourceRouteError(key, mask, (x, y))

                # Otherwise, add the input directions as this represents a
                # merge of the routes.
                route_sets[(x, y)][(key, mask)].ins.add(in_direction)
            else:
                # Otherwise create a new route set
                route_sets[(x, y)][(key, mask)] = \
                    InOutPair({in_direction}, set(out_directions))

    # Construct the routing tables from the route sets
    routing_tables = defaultdict(list)
    for (x, y), routes in iteritems(route_sets):
        for (key, mask), route in iteritems(routes):
            # Add the route
            routing_tables[(x, y)].append(
                RoutingTableEntry(route.outs, key, mask, route.ins)
            )

    return routing_tables