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