blob: f3728dc36cc29eef4defad078b69a2a45dd41dfe [file] [log] [blame]
"""
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()