| """ | |
| Utilities for fuzzing non-routing configuration. This is the counterpart to interconnect.py | |
| """ | |
| import threading | |
| import tiles | |
| import pytrellis | |
| 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 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() |