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