Esempio n. 1
0
def copy_conns_with_predicate(family, device, source, dest, predicate):
    srcdb = pytrellis.get_tile_bitdata(
        pytrellis.TileLocator(family, device, source))
    dstdb = pytrellis.get_tile_bitdata(
        pytrellis.TileLocator(family, device, dest))

    fcs = srcdb.get_fixed_conns()
    for conn in fcs:
        if predicate(conn):
            dstdb.add_fixed_conn(conn)
Esempio n. 2
0
def copy_muxes_with_predicate(family, device, source, dest, predicate):
    srcdb = pytrellis.get_tile_bitdata(
        pytrellis.TileLocator(family, device, source))
    dstdb = pytrellis.get_tile_bitdata(
        pytrellis.TileLocator(family, device, dest))

    sinks = srcdb.get_sinks()
    for sink in sinks:
        mux = srcdb.get_mux_data_for_sink(sink)
        for src in mux.get_sources():
            if predicate((src, sink)):
                dstdb.add_mux_arc(mux.arcs[src])
Esempio n. 3
0
def dbcopy(family,
           device,
           source,
           dest,
           copy_muxes=True,
           copy_words=True,
           copy_enums=True,
           copy_conns=True):
    """
    Copy the bit database from one tile type to another

    :param family: database family
    :param device: database device
    :param source: tiletype to copy from
    :param dest: tiletype to copy to
    :param copy_muxes: include muxes in copy
    :param copy_words: include settings words in copy
    :param copy_enums: include settings enums in copy
    :param copy_conns: include fixed connections in copy
    """
    srcdb = pytrellis.get_tile_bitdata(
        pytrellis.TileLocator(family, device, source))
    dstdb = pytrellis.get_tile_bitdata(
        pytrellis.TileLocator(family, device, dest))

    if copy_muxes:
        sinks = srcdb.get_sinks()
        for sink in sinks:
            mux = srcdb.get_mux_data_for_sink(sink)
            for src in mux.get_sources():
                dstdb.add_mux_arc(mux.arcs[src])

    if copy_words:
        cwords = srcdb.get_settings_words()
        for cword in cwords:
            wd = srcdb.get_data_for_setword(cword)
            dstdb.add_setting_word(wd)

    if copy_enums:
        cenums = srcdb.get_settings_enums()
        for cenum in cenums:
            ed = srcdb.get_data_for_enum(cenum)
            dstdb.add_setting_enum(ed)

    if copy_conns:
        fcs = srcdb.get_fixed_conns()
        for conn in fcs:
            dstdb.add_fixed_conn(conn)
Esempio n. 4
0
 def get_fanin(net):
     drivers = []
     npos = tiles.pos_from_name(net, chip_size, bias)
     for tile in c.get_all_tiles():
         tinf = tile.info
         tname = tinf.name
         pos = tiles.pos_from_name(tname, chip_size, bias)
         if abs(pos[0] - npos[0]) >= 10 or abs(pos[1] - npos[1]) >= 10:
             continue
         if net.startswith("G_"):
             tnet = net
         else:
             tnet = nets.normalise_name(chip_size, tname, net, bias)
         tdb = pytrellis.get_tile_bitdata(
             pytrellis.TileLocator(c.info.family, c.info.name, tinf.type))
         try:
             mux = tdb.get_mux_data_for_sink(tnet)
             for src in mux.get_sources():
                 drivers.append(
                     (nets.canonicalise_name(chip_size, tname, src,
                                             bias), True, tname))
         except IndexError:
             pass
         for fc in tdb.get_fixed_conns():
             if fc.sink == tnet:
                 drivers.append(
                     (nets.canonicalise_name(chip_size, tname, fc.source,
                                             bias), False, tname))
     return drivers
Esempio n. 5
0
    def per_pin(pin):
        def get_substs(sig, val):
            if val == pin:
                val = "#SIG"
            subs = {"sig": sig, "val": val}
            return subs

        if pin.startswith("JCE"):
            options = [pin, "1"]
        elif pin.startswith("JCLK") or pin.startswith("JLSR"):
            options = [pin, "0"]
        else:
            options = [pin, "0", "1"]
        # Load the EBR database and find the correct signal
        ebrdb = pytrellis.get_tile_bitdata(
            pytrellis.TileLocator(cfg.family, cfg.device, "MIB_EBR4"))
        fconns = ebrdb.get_fixed_conns()
        sig = None
        for conn in fconns:
            if conn.source.endswith(pin):
                sig = conn.sink
                break
        assert sig is not None
        # Convert net name to NCL pin name by stripping extraneous content
        if sig[0] == "J":
            sig = sig[1:]
        sig = sig.replace("_EBR", "")

        nonrouting.fuzz_enum_setting(cfg, "CIB.{}MUX".format(pin), options,
                                     lambda x: get_substs(sig=sig, val=x),
                                     empty_bitfile, False)
Esempio n. 6
0
 def get_fanout(net):
     drivers = []
     npos = tiles.pos_from_name(net)
     for tile in c.get_all_tiles():
         tinf = tile.info
         tname = tinf.name
         pos = tiles.pos_from_name(tname)
         if abs(pos[0] - npos[0]) >= 12 or abs(pos[1] - npos[1]) >= 12:
             continue
         if net.startswith("G_"):
             tnet = net
         else:
             tnet = nets.normalise_name(chip_size, tname, net)
         tdb = pytrellis.get_tile_bitdata(
             pytrellis.TileLocator(c.info.family, c.info.name, tinf.type))
         for sink in tdb.get_sinks():
             mux = tdb.get_mux_data_for_sink(sink)
             if tnet in mux.arcs:
                 drivers.append(
                     (nets.canonicalise_name(chip_size, tname,
                                             sink), True, tname))
         for fc in tdb.get_fixed_conns():
             if fc.source == tnet:
                 drivers.append(
                     (nets.canonicalise_name(chip_size, tname,
                                             fc.sink), False, tname))
     return drivers
Esempio n. 7
0
def main():
    pytrellis.load_database("../../../database")

    config = [
        (46, 1, 0),
        (48, 1, 0),
        (50, 1, 0),
        (54, 1, 0),
        (56, 1, 0),
        (58, 1, 0),
        (60, 1, 0),
        (62, 1, 0),
    ]

    tile = pytrellis.get_tile_bitdata(
        pytrellis.TileLocator("ECP5", "LFE5U-25F", "EFB1_PICB1"))
    wsb = pytrellis.WordSettingBits()
    wsb.name = "BOOTADDR"

    for bframe, bbit, inv in config:
        bg = pytrellis.BitGroup()
        cb = pytrellis.ConfigBit()
        cb.frame = bframe
        cb.bit = bbit
        cb.inv = inv
        bg.bits.add(cb)
        wsb.bits.append(bg)
        wsb.defval.append(False)

    tile.add_setting_word(wsb)
    tile.save()
Esempio n. 8
0
def fuzz_word_setting(config,
                      name,
                      length,
                      get_ncl_substs,
                      empty_bitfile=None):
    """
    Fuzz a multi-bit setting, such as LUT initialisation

    :param config: FuzzConfig instance containing target device and tile of interest
    :param name: name of the setting to store in the database
    :param length: number of bits in the setting
    :param get_ncl_substs: a callback function, that is first called with an array of bits to create a design with that setting
    :param empty_bitfile: a path to a bit file without the parameter included, optional, which is used to determine the
    default value
    """
    prefix = "thread{}_".format(threading.get_ident())
    tile_dbs = {
        tile: pytrellis.get_tile_bitdata(
            pytrellis.TileLocator(config.family, config.device,
                                  tiles.type_from_fullname(tile)))
        for tile in config.tiles
    }
    if empty_bitfile is not None:
        none_chip = pytrellis.Bitstream.read_bit(
            empty_bitfile).deserialise_chip()
    else:
        none_chip = None
    baseline_bitf = config.build_design(
        config.ncl, get_ncl_substs([False for _ in range(length)]), prefix)
    baseline_chip = pytrellis.Bitstream.read_bit(
        baseline_bitf).deserialise_chip()

    wsb = {tile: pytrellis.WordSettingBits() for tile in config.tiles}
    is_empty = {tile: True for tile in config.tiles}
    for t in config.tiles:
        wsb[t].name = name
    for i in range(length):
        bit_bitf = config.build_design(
            config.ncl, get_ncl_substs([(_ == i) for _ in range(length)]),
            prefix)
        bit_chip = pytrellis.Bitstream.read_bit(bit_bitf).deserialise_chip()
        diff = bit_chip - baseline_chip
        for tile in config.tiles:
            if tile in diff:
                wsb[tile].bits.append(pytrellis.BitGroup(diff[tile]))
                is_empty[tile] = False
            else:
                wsb[tile].bits.append(pytrellis.BitGroup())
            if none_chip is not None:
                if wsb[tile].bits[i].match(none_chip.tiles[tile].cram):
                    wsb[tile].defval.append(True)
                else:
                    wsb[tile].defval.append(False)
    for t in config.tiles:
        if not is_empty[t]:
            tile_dbs[t].add_setting_word(wsb[t])
            tile_dbs[t].save()
Esempio n. 9
0
def main():
    pytrellis.load_database("../../../database")
    db = pytrellis.get_tile_bitdata(
        pytrellis.TileLocator("MachXO2", "LCMXO2-1200HC", "PLC"))
    fc = pytrellis.FixedConnection()
    fc.source = "FCO"
    fc.sink = "E1_HFIE0000"
    db.add_fixed_conn(fc)
    db.save()
Esempio n. 10
0
def main():
    pytrellis.load_database("../../database")
    db = pytrellis.get_tile_bitdata(
        pytrellis.TileLocator("ECP5", "LFE5U-25F", "PLC2"))
    fc = pytrellis.FixedConnection()
    fc.source = "FCO"
    fc.sink = "E1_HFIE0000"
    db.add_fixed_conn(fc)
    db.save()
Esempio n. 11
0
def main(argv):
    global bitmap, labels
    bitmap = dict(dict())
    labels = dict(dict())
    args = parser.parse_args(argv[1:])
    f = args.outfile
    print("""<html>
            <head><title>{} Bit Data</title>
        """.format(args.tile),
          file=f)
    print("""
            <script type="text/javascript">
            origClr = {};
            origClass = "";
            
            function mov(event) {
                if (event.target.className != "unknown") {
                    origClass = event.target.className;
                    var elems = document.getElementsByClassName(origClass);
                    for(var i = 0; i < elems.length; i++) {
                       if(!(elems[i].id in origClr)) {
                          origClr[elems[i].id] = elems[i].style.backgroundColor;
                       }
                       elems[i].style.backgroundColor = "white";
                    }

                }
            }
            
            function mou(event) {
                var elems = document.getElementsByClassName(origClass);
                for(var i = 0; i < elems.length; i++) {
                   elems[i].style.backgroundColor = origClr[elems[i].id] || "#ffffff";
                }
            }
            </script>
            </head>
            <body>
        """,
          file=f)
    print("""<h1>{} Bit Data</h1>
    """.format(args.tile), file=f)
    pytrellis.load_database(database.get_db_root())
    tdb = pytrellis.get_tile_bitdata(
        pytrellis.TileLocator(args.family, args.device, args.tile))
    ch = pytrellis.Chip(args.device)
    ti = ch.get_tiles_by_type(args.tile)[0].info
    find_bits(tdb)
    bit_grid_html(ti, f)
    muxes_html(tdb, f)
    setwords_html(tdb, f)
    setenums_html(tdb, f)
    fixed_conns_html(tdb, f)
    print("""</body></html>""", file=f)
Esempio n. 12
0
    def get_arcs_downhill(self, wire):
        if wire in self.dh_arc_cache:
            return self.dh_arc_cache[wire]
        else:
            drivers = []
            chip_size = (self.chip.get_max_row(), self.chip.get_max_col())
            try:
                npos = tiles.pos_from_name(wire, chip_size, self.bias)
            except AssertionError:
                return []
            wname = wire.split("_", 1)[1]
            hspan = 0
            vspan = 0
            if wname.startswith("H") and wname[1:3].isdigit():
                hspan = int(wname[1:3])
            if wname.startswith("V") and wname[1:3].isdigit():
                vspan = int(wname[1:3])
            positions = {(npos[0], npos[1]), (npos[0] + vspan, npos[1]),
                         (npos[0] - vspan, npos[1]),
                         (npos[0], npos[1] + hspan),
                         (npos[0], npos[1] - hspan)}
            for pos in positions:
                for tile in self.chip.get_tiles_by_position(pos[0], pos[1]):
                    tinf = tile.info
                    tname = tinf.name
                    if tname.startswith("TAP"):
                        continue
                    pos = tiles.pos_from_name(tname, chip_size, self.bias)

                    if abs(pos[0] - npos[0]) not in (
                            vspan, 0) or abs(pos[1] - npos[1]) not in (hspan,
                                                                       0):
                        continue
                    if wire.startswith("G_"):
                        twire = wire
                    else:
                        twire = nets.normalise_name(self.chip_size, tname,
                                                    wire, self.bias)

                    tdb = pytrellis.get_tile_bitdata(
                        pytrellis.TileLocator(self.chip.info.family,
                                              self.chip.info.name, tinf.type))
                    downhill = tdb.get_downhill_wires(twire)
                    for sink in downhill:
                        nn = nets.canonicalise_name(self.chip_size, tname,
                                                    sink.first, self.bias)
                        if nn is not None:
                            drivers.append((nn, sink.second, tname))
            self.dh_arc_cache[wire] = drivers
            return drivers
Esempio n. 13
0
def make_tiles_by_loc(chip: pytrellis.Chip) -> TilesByLoc:
    tiles_by_loc: TilesByLoc = defaultdict(list)

    for tilename, tile in chip.tiles.items():
        locator = pytrellis.TileLocator(chip.info.family, chip.info.name,
                                        tile.info.type)
        tilebitdb = pytrellis.get_tile_bitdata(locator)
        tilecfg = tilebitdb.tile_cram_to_config(tile.cram)

        rc = tile.info.get_row_col()
        row, col = rc.first, rc.second
        tileloc = pytrellis.Location(col, row)

        tiles_by_loc[tileloc.x, tileloc.y].append(TileData(tile, tilecfg))

    return tiles_by_loc
Esempio n. 14
0
    def get_zero_bit_arcs(chip: pytrellis.Chip,
                          tiletype: str) -> Dict[str, List[str]]:
        """Get configurable zero-bit arcs from the given tile.

        tile_cram_to_config ignores zero-bit arcs when generating the TileConfig,
        which means that if all bits are unset for a given mux, no connection is
        generated at all."""
        locator = pytrellis.TileLocator(chip.info.family, chip.info.name,
                                        tiletype)
        tilebitdb = pytrellis.get_tile_bitdata(locator)
        arcs: Dict[str, List[str]] = defaultdict(list)
        for sink in tilebitdb.get_sinks():
            mux_data = tilebitdb.get_mux_data_for_sink(sink)
            for arc_name, arc_data in mux_data.arcs.items():
                if len(arc_data.bits.bits) == 0:
                    arcs[sink].append(arc_name)
        return arcs
Esempio n. 15
0
    def make_bitstream(self, filename):
        # Open debug file
        debugfile = filename + ".dbg"
        with open(debugfile, 'w') as dbgf:
            for tname, tcfg in sorted(self.config.items()):
                tile = self.chip.tiles[tname]
                tinfo = tile.info
                tdb = pytrellis.get_tile_bitdata(
                    pytrellis.TileLocator(self.chip.info.family, self.chip.info.name, tinfo.type))
                tile.cram.clear()
                tdb.config_to_tile_cram(tcfg, tile.cram)
                textcfg = tcfg.to_string()
                if len(textcfg.strip()) > 0:
                    dbgf.write(".tile {}\n".format(tname))
                    dbgf.write(textcfg)
                    dbgf.write("\n")

        bs = pytrellis.Bitstream.serialise_chip(self.chip)
        bs.write_bit(filename)
Esempio n. 16
0
def dbfixup(family, device, tiletype):
    db = pytrellis.get_tile_bitdata(
        pytrellis.TileLocator(family, device, tiletype))

    fc = db.get_fixed_conns()
    # Where a wire is driven by both a mux and fixed connections, replace those fixed connections
    # with a mux arc with no config bits
    for mux in db.get_sinks():
        deleteFc = False
        for conn in fc:
            if conn.sink == mux:
                ad = pytrellis.ArcData()
                ad.source = conn.source
                ad.sink = conn.sink
                db.add_mux_arc(ad)
                deleteFc = True
        if deleteFc:
            db.remove_fixed_sink(mux)
    db.save()
Esempio n. 17
0
def remove_enum_bits(family, device, tiletype, lowerright, upperleft=(0, 0)):
    """
    Remove bits from enumerations in a given tile that actually belong
    to routing bits. This can happen when e.g. routing is required for Diamond
    to set certain bits in the output, as is the case for fuzzing I/O enums
    in PIC_L0 and PIC_R0.

    Bounds are (0,0)-based. Upperleft is inclusive, lowerright is exclusive.
    """
    def in_bounding_box(bit):
        (x, y) = (bit.frame, bit.bit)

        if upperleft[0] > x or upperleft[1] > y:
            return False

        if lowerright[0] <= x or lowerright[1] <= y:
            return False

        return True

    db = pytrellis.get_tile_bitdata(
        pytrellis.TileLocator(family, device, tiletype))

    for enum in db.get_settings_enums():
        fixed_enum = pytrellis.EnumSettingBits()

        for option in db.get_data_for_enum(enum).options:
            key = option.key()
            fixed_bg = pytrellis.BitGroup()

            for bit in option.data().bits:
                if in_bounding_box(bit):
                    fixed_bg.bits.add(bit)

            fixed_enum.options[key] = fixed_bg

        fixed_enum.name = db.get_data_for_enum(enum).name
        fixed_enum.defval = db.get_data_for_enum(enum).defval

        db.remove_setting_enum(enum)
        db.add_setting_enum(fixed_enum)
    db.save()
Esempio n. 18
0
 def get_nets_at(loc):
     if loc in net_tile_cache:
         return net_tile_cache[loc]
     row, col = loc
     nets = set()
     for tile in c.get_tiles_by_position(row, col):
         tinf = tile.info
         tdb = pytrellis.get_tile_bitdata(
             pytrellis.TileLocator(c.info.family, c.info.name, tinf.type))
         for sink in tdb.get_sinks():
             if not non_tile_re.match(sink):
                 nets.add(sink)
             mux = tdb.get_mux_data_for_sink(sink)
             for src in mux.get_sources():
                 if not non_tile_re.match(src):
                     nets.add(src)
         for fc in tdb.get_fixed_conns():
             if not non_tile_re.match(fc.sink):
                 nets.add(fc.sink)
             if not non_tile_re.match(fc.source):
                 nets.add(fc.source)
     nets = list(sorted((["R{}C{}_{}".format(row, col, _) for _ in nets])))
     net_tile_cache[loc] = nets
     return nets
Esempio n. 19
0
assert c.get_max_row() == 0
assert c.get_max_col() == 0

bits = {
    (0, 0),
    (0, 3),
    (1, 0),
    (1, 2),
    (2, 0),
    (5, 3)
}
for b in bits:
    c.cram.set_bit(10 + b[0], 15 + b[1], 1)

tcram = c.tiles["TEST_R0C0:TESTTILE"].cram
assert tcram.frames() == 20
assert tcram.bits() == 10

tl = pytrellis.TileLocator("test", "testdev", "TESTTILE")

tiledb = pytrellis.get_tile_bitdata(tl)
cfg = tiledb.tile_cram_to_config(tcram)
assert len(cfg.carcs) == 1
assert cfg.carcs[0].source == "H2" and cfg.carcs[0].sink == "A0"
assert len(cfg.cwords) == 1
assert cfg.cwords[0].name == "INIT" and list(cfg.cwords[0].value) == [0, 1, 0, 1]
assert len(cfg.cenums) == 1
assert cfg.cenums[0].name == "MODE" and cfg.cenums[0].value == "CARRY"
assert len(cfg.cunknowns) == 1
assert cfg.cunknowns[0].frame == 5 and cfg.cunknowns[0].bit == 3
Esempio n. 20
0
def fuzz_enum_setting(config,
                      name,
                      values,
                      get_ncl_substs,
                      empty_bitfile=None,
                      include_zeros=True,
                      ignore_cover=None,
                      opt_pref=None):
    """
    Fuzz a setting with multiple possible values

    :param config: FuzzConfig instance containing target device and tile of interest
    :param name: name of the setting to store in the database
    :param values: list of values taken by the enum
    :param get_ncl_substs: a callback function, that is first called with an array of bits to create a design with that setting
    :param empty_bitfile: a path to a bit file without the parameter included, optional, which is used to determine the
    default value
    :param include_zeros: if set, bits set to zero are not included in db. Needed for settings such as CEMUX which share
    bits with routing muxes to prevent conflicts.
    :param ignore_cover: these values will also be checked, and bits changing between these will be ignored
    :param opt_pref: bits exclusively set in these options will be included in all options overriding include_zeros
    """
    prefix = "thread{}_".format(threading.get_ident())
    tile_dbs = {
        tile: pytrellis.get_tile_bitdata(
            pytrellis.TileLocator(config.family, config.device,
                                  tiles.type_from_fullname(tile)))
        for tile in config.tiles
    }
    if empty_bitfile is not None:
        none_chip = pytrellis.Bitstream.read_bit(
            empty_bitfile).deserialise_chip()
    else:
        none_chip = None

    changed_bits = set()
    prev_tiles = {}
    tiles_changed = set()
    for val in values:
        print("****** Fuzzing {} = {} ******".format(name, val))
        bit_bitf = config.build_design(config.ncl, get_ncl_substs(val), prefix)
        bit_chip = pytrellis.Bitstream.read_bit(bit_bitf).deserialise_chip()
        for prev in prev_tiles.values():
            for tile in config.tiles:
                diff = bit_chip.tiles[tile].cram - prev[tile]
                if len(diff) > 0:
                    tiles_changed.add(tile)
                    for bit in diff:
                        changed_bits.add((tile, bit.frame, bit.bit))
        prev_tiles[val] = {}
        for tile in config.tiles:
            prev_tiles[val][tile] = bit_chip.tiles[tile].cram
    if ignore_cover is not None:
        ignore_changed_bits = set()
        ignore_prev_tiles = {}
        for ival in ignore_cover:
            print("****** Fuzzing {} = {} [to ignore] ******".format(
                name, ival))
            bit_bitf = config.build_design(config.ncl, get_ncl_substs(ival),
                                           prefix)
            bit_chip = pytrellis.Bitstream.read_bit(
                bit_bitf).deserialise_chip()
            for prev in ignore_prev_tiles.values():
                for tile in config.tiles:
                    diff = bit_chip.tiles[tile].cram - prev[tile]
                    if len(diff) > 0:
                        for bit in diff:
                            ignore_changed_bits.add((tile, bit.frame, bit.bit))
            ignore_prev_tiles[ival] = {}
            for tile in config.tiles:
                ignore_prev_tiles[ival][tile] = bit_chip.tiles[tile].cram
        for ibit in ignore_changed_bits:
            if ibit in changed_bits:
                changed_bits.remove(ibit)
    for tile in tiles_changed:
        esb = pytrellis.EnumSettingBits()
        esb.name = name
        pref_exclusive = {}
        if opt_pref is not None:
            for val in values:
                for (btile, bframe, bbit) in changed_bits:
                    if btile == tile:
                        state = prev_tiles[val][tile].bit(bframe, bbit)
                        if state:
                            if val in opt_pref:
                                if (btile, bframe, bbit) not in pref_exclusive:
                                    pref_exclusive[(btile, bframe,
                                                    bbit)] = True
                            else:
                                pref_exclusive[(btile, bframe, bbit)] = False
        for val in values:
            bg = pytrellis.BitGroup()
            for (btile, bframe, bbit) in changed_bits:
                if btile == tile:
                    state = prev_tiles[val][tile].bit(bframe, bbit)
                    if state == 0 and not include_zeros and (
                            none_chip is not None and not none_chip.tiles[tile].cram.bit(bframe, bbit)) \
                            and (
                            (btile, bframe, bbit) not in pref_exclusive or not pref_exclusive[(btile, bframe, bbit)]):
                        continue
                    cb = pytrellis.ConfigBit()
                    cb.frame = bframe
                    cb.bit = bbit
                    cb.inv = (state == 0)
                    bg.bits.add(cb)
            esb.options[val] = bg
            if none_chip is not None and bg.match(none_chip.tiles[tile].cram):
                esb.defval = val
        tile_dbs[tile].add_setting_enum(esb)
        tile_dbs[tile].save()
Esempio n. 21
0
    def per_netname(net):
        # Get a unique prefix from the thread ID
        prefix = "thread{}_".format(threading.get_ident())
        assoc_arcs = net_arcs[net]
        # Obtain the set of databases
        tile_dbs = {tile: pytrellis.get_tile_bitdata(
            pytrellis.TileLocator(config.family, config.device, tiles.type_from_fullname(tile))) for tile in
            config.tiles}
        # First filter using netname predicate
        if netname_filter_union:
            assoc_arcs = filter(lambda x: netname_predicate(x[0], netnames) and netname_predicate(x[1], netnames),
                                assoc_arcs)
        else:
            assoc_arcs = filter(lambda x: netname_predicate(x[0], netnames) or netname_predicate(x[1], netnames),
                                assoc_arcs)
        # Then filter using the arc predicate
        fuzz_arcs = list(filter(lambda x: arc_predicate(x, netnames), assoc_arcs))

        # Ful fullmux mode only
        changed_bits = set()
        arc_tiles = {}
        tiles_changed = set()

        for arc in fuzz_arcs:
            # Route statement containing arc for NCL file
            arc_route = "route\n\t\t\t" + arc[0] + "." + arc[1] + ";"
            # Build a bitstream and load it using libtrellis
            arc_bitf = config.build_design(config.ncl, {"route": arc_route}, prefix)
            arc_chip = pytrellis.Bitstream.read_bit(arc_bitf).deserialise_chip()
            # Compare the bitstream with the arc to the baseline bitstream
            diff = arc_chip - baseline_chip
            if (not full_mux_style) or len(fuzz_arcs) == 1:
                if len(diff) == 0:
                    # No difference means fixed interconnect
                    # We consider this to be in the first tile if multiple tiles are being analysed
                    if fc_predicate(arc, netnames):
                        norm_arc = normalise_arc_in_tile(config.tiles[0], arc)
                        fc = pytrellis.FixedConnection()
                        norm_arc = [fc_prefix + _ if not _.startswith("G_") else _ for _ in norm_arc]
                        norm_arc = [add_nonlocal_prefix(_) for _ in norm_arc]
                        fc.source, fc.sink = norm_arc
                        tile_dbs[config.tiles[0]].add_fixed_conn(fc)
                else:
                    for tile in config.tiles:
                        if tile in diff:
                            # Configurable interconnect in <tile>
                            norm_arc = normalise_arc_in_tile(tile, arc)
                            norm_arc = [add_nonlocal_prefix(_) for _ in norm_arc]
                            ad = pytrellis.ArcData()
                            ad.source, ad.sink = norm_arc
                            ad.bits = pytrellis.BitGroup(diff[tile])
                            tile_dbs[tile].add_mux_arc(ad)
            else:
                arc_tiles[arc] = {}
                for tile in config.tiles:
                    if tile in diff:
                        tiles_changed.add(tile)
                        for bit in diff[tile]:
                            changed_bits.add((tile, bit.frame, bit.bit))
                    arc_tiles[arc][tile] = arc_chip.tiles[tile]

        if full_mux_style and len(fuzz_arcs) > 1:
            for tile in tiles_changed:
                for arc in arc_tiles:
                    bg = pytrellis.BitGroup()
                    for (btile, bframe, bbit) in changed_bits:
                        if btile == tile:
                            state = arc_tiles[arc][tile].cram.bit(bframe, bbit)
                            cb = pytrellis.ConfigBit()
                            cb.frame = bframe
                            cb.bit = bbit
                            cb.inv = (state == 0)
                            bg.bits.add(cb)
                    ad = pytrellis.ArcData()
                    ad.source, ad.sink = normalise_arc_in_tile(tile, arc)
                    ad.bits = bg
                    tile_dbs[tile].add_mux_arc(ad)
        # Flush database to disk
        for tile, db in tile_dbs.items():
            db.save()