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)
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])
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)
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
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)
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
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()
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()
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()
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()
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)
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
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
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
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)
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()
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()
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
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
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()
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()