def pos_mode(args): pytrellis.load_database("../../../database") cfg = FuzzConfig(job="FINDNETS_R{}C{}".format(args.row, args.col), family="MachXO2", device="LCMXO2-1200HC", ncl="plc2route.ncl", tiles=[]) cfg.setup() netdata = isptcl.get_wires_at_position(cfg.ncd_prf, (args.row, args.col)) netnames = [x[0] for x in netdata] arcs = isptcl.get_arcs_on_wires(cfg.ncd_prf, netnames, False, defaultdict(lambda: str("mark"))) with open( "r{}c{}_{}out.txt".format(args.row, args.col, "a_" if args.a else ""), "w") as fp: for (k, v) in arcs.items(): print("{}:".format(k), file=fp) for c in v: if isinstance(c, isptcl.AmbiguousArc): print(str(c), file=fp) else: if not args.a: print("{} --> {}".format(c[0], c[1]), file=fp) fp.flush() print("", file=fp)
def net_mode(args): pytrellis.load_database("../../../database") cfg = FuzzConfig(job="FINDNETS_NETS_{}".format(args.nets[0]), family="MachXO2", device="LCMXO2-1200HC", ncl="plc2route.ncl", tiles=[]) cfg.setup() arcs = isptcl.get_arcs_on_wires(cfg.ncd_prf, args.nets, False, defaultdict(lambda: str("mark"))) with open("{}_out.txt".format(args.nets[0]), "w") as fp: for (k, v) in arcs.items(): print("{}:".format(k), file=fp) for c in v: if isinstance(c, isptcl.AmbiguousArc): print(str(c), file=fp) else: print("{} --> {}".format(c[0], c[1]), file=fp) fp.flush() print("", file=fp)
def fuzz_interconnect_with_netnames( config, netnames, netname_predicate=lambda x, nets: True, arc_predicate=lambda x, nets: True, fc_predicate=lambda x, nets: True, bidir=False, netname_filter_union=False, full_mux_style=False, fc_prefix="", nonlocal_prefix=""): """ Fuzz interconnect given a list of netnames to analyse. Arcs associated these netnames will be found using the Tcl API and bits identified as described above. :param config: FuzzConfig instance containing target device and tile(s) of interest :param netnames: A list of netnames in Lattice (un-normalised) format to analyse :param netname_predicate: a predicate function which should return True if a netname is of interest, given the netname and the set of all nets :param arc_predicate: a predicate function which should return True if an arc, given the arc as a (source, sink) tuple and the set of all netnames, is of interest :param bidir: if True, arcs driven by as well as driving the given netnames will be considered during analysis :param netname_filter_union: if True, arcs will be included if either net passes netname_predicate, if False both nets much pass the predicate. :param full_mux_style: if True, is a full mux, and all 0s is considered a valid config bit possibility :param fc_prefix: add a prefix to non-global fixed connections for device-specific fuzzers """ net_arcs = isptcl.get_arcs_on_wires(config.ncd_prf, netnames, not bidir) baseline_bitf = config.build_design(config.ncl, {}, "base_") baseline_chip = pytrellis.Bitstream.read_bit(baseline_bitf).deserialise_chip() max_row = baseline_chip.get_max_row() max_col = baseline_chip.get_max_col() def normalise_arc_in_tile(tile, arc): return tuple(nets.normalise_name((max_row, max_col), tile, x) for x in arc) def add_nonlocal_prefix(wire): if wire.startswith("G_"): return wire m = re.match(r'([NS]\d+)?([EW]\d+)?_.*', wire) if m: for g in m.groups(): if g is not None and int(g[1:]) >= 3: return nonlocal_prefix + wire return wire 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() fuzzloops.parallel_foreach(netnames, per_netname)
def filter_mode(args): span1_re = re.compile(r'R\d+C\d+_[VH]01[NESWTLBR]\d{4}') location = (args.row, args.col) def netname_predicate(net, netnames): """ Match nets that are: in the tile according to Tcl, global nets, or span-1 nets that are accidentally left out by Tcl""" return net in netnames or nets.machxo2.is_global( net) or span1_re.match(net) def arc_predicate(arc, netnames): return True def fc_predicate(arc, netnames): return True pytrellis.load_database("../../../database") cfg = FuzzConfig(job="FINDNETS_FILTER_R{}C{}".format(args.row, args.col), family="MachXO2", device="LCMXO2-1200HC", ncl="plc2route.ncl", tiles=[]) cfg.setup() # fuzz_interconnect netdata = isptcl.get_wires_at_position(cfg.ncd_prf, (args.row, args.col)) netnames = [x[0] for x in netdata] extra_netnames = [] if args.s: for net in netnames: m = re.match("R(\d+)C(\d+)_V01N(\d{4})", net) if m: row = int(m.group(1)) col = int(m.group(2)) idn = m.group(3) if row == location[0] + 1 and col == location[1]: fixednet = "R{}C{}_V01N{}".format(location[0] - 1, col, idn) print("added {}".format(fixednet)) extra_netnames.append(fixednet) netnames = extra_netnames + netnames if args.f and not args.n: netnames = list( filter(lambda x: netname_predicate(x, netnames), netnames)) # fuzz_interconnect_with_netnames arcs = isptcl.get_arcs_on_wires(cfg.ncd_prf, netnames, not args.f, defaultdict(lambda: str("mark"))) def per_netname(net): assoc_arcs = arcs[net] if args.n: filt_net_pred = list( itertools.filterfalse( lambda x: netname_predicate(x[0], netnames) and netname_predicate(x[1], netnames), assoc_arcs.copy())) assoc_arcs = list( filter( lambda x: netname_predicate(x[0], netnames) and netname_predicate(x[1], netnames), assoc_arcs)) else: filt_net_pred = list( itertools.filterfalse( lambda x: netname_predicate(x[0], netnames) or netname_predicate(x[1], netnames), assoc_arcs.copy())) assoc_arcs = list( filter( lambda x: netname_predicate(x[0], netnames) or netname_predicate(x[1], netnames), assoc_arcs)) filt_arcs_pred = list( itertools.filterfalse(lambda x: arc_predicate(x, netnames), assoc_arcs.copy())) fuzz_arcs = list( filter(lambda x: arc_predicate(x, netnames), assoc_arcs)) filt_fc_pred = list( itertools.filterfalse(lambda x: fc_predicate(x, netnames), fuzz_arcs.copy())) return (fuzz_arcs, filt_net_pred, filt_arcs_pred, filt_fc_pred) # Write to file, describing which nets did/didn't make the cut. with open("r{}c{}_filter.txt".format(args.row, args.col), "w") as fp: def print_arc(arc): if isinstance(arc, isptcl.AmbiguousArc): print(str(arc), file=fp) else: print("{} --> {}".format(arc[0], arc[1]), file=fp) print("Args: {}".format(vars(args)), file=fp) print("", file=fp) print("Extra nets (span 1s):", file=fp) for net in extra_netnames: print("{}:".format(net), file=fp) print("", file=fp) print("Filters:", file=fp) print("Netname:\n{}".format(inspect.getsource(netname_predicate)), file=fp) print("Arc:\n{}".format(inspect.getsource(arc_predicate)), file=fp) print("FC:\n{}".format(inspect.getsource(fc_predicate)), file=fp) print("", file=fp) for net in netnames: print("{}:".format(net), file=fp) (fuzz, filt_net, filt_arc, filt_fc) = per_netname(net) print("Arcs to fuzz:", file=fp) for f in fuzz: print_arc(f) print("Arcs filtered by netname_predicate:", file=fp) for f in filt_net: print_arc(f) print("Arcs filtered by arc_predicate:", file=fp) for f in filt_arc: print_arc(f) print("Would be filtered by fc_predicate (if fixed connection):", file=fp) for f in filt_fc: print_arc(f) fp.flush() print("", file=fp)