diff --git a/tools/connectivity.py b/tools/connectivity.py index 55b457ee..66fe964e 100755 --- a/tools/connectivity.py +++ b/tools/connectivity.py @@ -24,52 +24,52 @@ def main(): # Returns (source, configurable, loc) def get_fanin(net): drivers = [] - npos = tiles.pos_from_name(net) + npos = tiles.pos_from_name(net, chip_size, 0) for tile in c.get_all_tiles(): tinf = tile.info tname = tinf.name - pos = tiles.pos_from_name(tname) + pos = tiles.pos_from_name(tname, chip_size, 0) if abs(pos[0] - npos[0]) >= 10 or abs(pos[1] - npos[1]) >= 10: continue if net.startswith("G_"): tnet = net else: - tnet = nets.normalise_name(chip_size, tname, net) + tnet = nets.normalise_name(chip_size, tname, net, 0) tdb = pytrellis.get_tile_bitdata(pytrellis.TileLocator(c.info.family, c.info.name, tinf.type)) try: mux = tdb.get_mux_data_for_sink(tnet) for src in mux.get_sources(): - drivers.append((nets.canonicalise_name(chip_size, tname, src), True, tname)) + drivers.append((nets.canonicalise_name(chip_size, tname, src, 0), True, tname)) except IndexError: pass for fc in tdb.get_fixed_conns(): if fc.sink == tnet: - drivers.append((nets.canonicalise_name(chip_size, tname, fc.source), False, tname)) + drivers.append((nets.canonicalise_name(chip_size, tname, fc.source, 0), False, tname)) return drivers # Get fan-out of a net # Returns (dest, configurable, loc) def get_fanout(net): drivers = [] - npos = tiles.pos_from_name(net) + npos = tiles.pos_from_name(net, chip_size, 0) for tile in c.get_all_tiles(): tinf = tile.info tname = tinf.name - pos = tiles.pos_from_name(tname) + pos = tiles.pos_from_name(tname, chip_size, 0) if abs(pos[0] - npos[0]) >= 12 or abs(pos[1] - npos[1]) >= 12: continue if net.startswith("G_"): tnet = net else: - tnet = nets.normalise_name(chip_size, tname, net) + tnet = nets.normalise_name(chip_size, tname, net, 0) tdb = pytrellis.get_tile_bitdata(pytrellis.TileLocator(c.info.family, c.info.name, tinf.type)) for sink in tdb.get_sinks(): mux = tdb.get_mux_data_for_sink(sink) if tnet in mux.arcs: - drivers.append((nets.canonicalise_name(chip_size, tname, sink), True, tname)) + drivers.append((nets.canonicalise_name(chip_size, tname, sink, 0), True, tname)) for fc in tdb.get_fixed_conns(): if fc.source == tnet: - drivers.append((nets.canonicalise_name(chip_size, tname, fc.sink), False, tname)) + drivers.append((nets.canonicalise_name(chip_size, tname, fc.sink, 0), False, tname)) return drivers @@ -105,7 +105,7 @@ def get_nets_at(loc): def completer(str, idx): if not tile_net_re.match(str): return None - loc = tiles.pos_from_name(str) + loc = tiles.pos_from_name(str, chip_size, 0) nets = get_nets_at(loc) for n in nets: if n.startswith(str): diff --git a/tools/demobuilder/design.py b/tools/demobuilder/design.py index 33d8b6c7..d79f53fb 100644 --- a/tools/demobuilder/design.py +++ b/tools/demobuilder/design.py @@ -32,7 +32,8 @@ def init_bels(self): for tile in all_tiles: tinf = tile.info tname = tinf.name - pos = tiles.pos_from_name(tname) + chip_size = (self.chip.get_max_row(), self.chip.get_max_col()) + pos = tiles.pos_from_name(tname, chip_size, 0) if tinf.type == "PLC2": for loc in ("A", "B", "C", "D"): bel = "R{}C{}{}".format(pos[0], pos[1], loc) @@ -60,7 +61,8 @@ def inst_slice(self, name, a0=None, a1=None, b0=None, b1=None, c0=None, c1=None, bel = self.bel_for_cell(name, "SLICE") beltype, belloc = self.bels[bel] tile, loc = belloc - pos = tiles.pos_from_name(tile) + chip_size = (self.chip.get_max_row(), self.chip.get_max_col()) + pos = tiles.pos_from_name(tile, chip_size, 0) net_prefix = "R{}C{}".format(pos[0], pos[1]) slice_index = "ABCD".index(loc) lc0 = 2 * slice_index diff --git a/tools/demobuilder/route.py b/tools/demobuilder/route.py index 755e5332..788ad17b 100755 --- a/tools/demobuilder/route.py +++ b/tools/demobuilder/route.py @@ -22,8 +22,9 @@ def get_arcs_downhill(self, wire): return self.dh_arc_cache[wire] else: drivers = [] + chip_size = (self.chip.get_max_row(), self.chip.get_max_col()) try: - npos = tiles.pos_from_name(wire) + npos = tiles.pos_from_name(wire, chip_size, 0) except AssertionError: return [] wname = wire.split("_", 1)[1] @@ -41,20 +42,20 @@ def get_arcs_downhill(self, wire): tname = tinf.name if tname.startswith("TAP"): continue - pos = tiles.pos_from_name(tname) + pos = tiles.pos_from_name(tname, chip_size, 0) if abs(pos[0] - npos[0]) not in (vspan, 0) or abs(pos[1] - npos[1]) not in (hspan, 0): continue if wire.startswith("G_"): twire = wire else: - twire = nets.normalise_name(self.chip_size, tname, wire) + twire = nets.normalise_name(self.chip_size, tname, wire, 0) tdb = pytrellis.get_tile_bitdata( pytrellis.TileLocator(self.chip.info.family, self.chip.info.name, tinf.type)) downhill = tdb.get_downhill_wires(twire) for sink in downhill: - nn = nets.canonicalise_name(self.chip_size, tname, sink.first) + nn = nets.canonicalise_name(self.chip_size, tname, sink.first, 0) if nn is not None: drivers.append((nn, sink.second, tname)) self.dh_arc_cache[wire] = drivers @@ -72,8 +73,8 @@ def bind_arc(self, net, uphill_wire, arc, config): else: self.net_to_wire[net] = {dest_wire} if configurable and not exists: - src_wirename = nets.normalise_name(self.chip_size, tile, uphill_wire) - sink_wirename = nets.normalise_name(self.chip_size, tile, dest_wire) + src_wirename = nets.normalise_name(self.chip_size, tile, uphill_wire, 0) + sink_wirename = nets.normalise_name(self.chip_size, tile, dest_wire, 0) config[tile].add_arc(sink_wirename, src_wirename) # Bind a net to a wire (used for port connections) @@ -88,9 +89,10 @@ def bind_net_to_port(self, net, port_wire): # Route a net to a wire def route_net_to_wire(self, net, wire, config): print(" Routing net '{}' to wire/pin '{}'...".format(net, wire)) - dest_pos = tiles.pos_from_name(wire) + chip_size = (self.chip.get_max_row(), self.chip.get_max_col()) + dest_pos = tiles.pos_from_name(wire, chip_size, 0) def get_score(x_wire): - pos = tiles.pos_from_name(x_wire) + pos = tiles.pos_from_name(x_wire, chip_size, 0) score = abs(pos[0] - dest_pos[0]) + abs(pos[1] - dest_pos[1]) x_wname = x_wire.split("_", 1)[1] if x_wname[1:3].isdigit() and score > 3: diff --git a/tools/html_tilegrid.py b/tools/html_tilegrid.py index 6eba0625..cc7e6834 100755 --- a/tools/html_tilegrid.py +++ b/tools/html_tilegrid.py @@ -5,6 +5,7 @@ import sys, re import argparse import database +import tiles as tilelib parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('family', type=str, @@ -14,15 +15,6 @@ parser.add_argument('outfile', type=argparse.FileType('w'), help="output HTML file") -rc_regex = re.compile(r"[A-Za-z0-9_]*R(\d+)C(\d+)") - - -def get_rc(name): - rc = rc_regex.match(name) - row = int(rc.group(1)) - col = int(rc.group(2)) - return (row, col) - def get_colour(ttype): colour = "#FFFFFF" @@ -50,13 +42,10 @@ def get_colour(ttype): def main(argv): args = parser.parse_args(argv[1:]) tilegrid = database.get_tilegrid(args.family, args.device) + device_info = database.get_devices()["families"][args.family]["devices"][args.device] - max_row = 0 - max_col = 0 - for name in sorted(tilegrid.keys()): - row, col = get_rc(name) - if row > max_row: max_row = row - if col > max_col: max_col = col + max_row = device_info["max_row"] + max_col = device_info["max_col"] tiles = [] for i in range(max_row + 1): @@ -67,7 +56,7 @@ def main(argv): for identifier, data in sorted(tilegrid.items()): name = identifier.split(":")[0] - row, col = get_rc(name) + row, col = tilelib.pos_from_name(name, (max_row, max_col), 0) colour = get_colour(data["type"]) tiles[row][col].append((name, data["type"], colour)) diff --git a/util/common/nets.py b/util/common/nets.py index 4e97fa0a..ea9ae188 100644 --- a/util/common/nets.py +++ b/util/common/nets.py @@ -196,7 +196,7 @@ def handle_edge_name(chip_size, tile_pos, wire_pos, netname): return netname, wire_pos -def normalise_name(chip_size, tile, wire): +def normalise_name(chip_size, tile, wire, bias): """ Wire name normalisation for tile wires and fuzzing All net names that we have access too are canonical, global names @@ -224,13 +224,14 @@ def normalise_name(chip_size, tile, wire): chip_size: chip size as tuple (max_row, max_col) tile: name of the relevant tile wire: full Lattice name of the wire + bias: Use 1-based column indexing Returns the normalised netname """ upos = wire.index("_") prefix = wire[:upos] - prefix_pos = tiles.pos_from_name(prefix) - tile_pos = tiles.pos_from_name(tile) + prefix_pos = tiles.pos_from_name(prefix, chip_size, bias) + tile_pos = tiles.pos_from_name(tile, chip_size, bias) netname = wire[upos+1:] if tile.startswith("TAP") and netname.startswith("H"): if prefix_pos[1] < tile_pos[1]: @@ -269,7 +270,7 @@ def normalise_name(chip_size, tile, wire): rel_netname_re = re.compile(r'^([NS]\d+)?([EW]\d+)?_.*') -def canonicalise_name(chip_size, tile, wire): +def canonicalise_name(chip_size, tile, wire, bias): """ Convert a normalised name in a given tile back to a canonical global name :param chip_size: chip size as tuple (max_row, max_col) @@ -280,7 +281,7 @@ def canonicalise_name(chip_size, tile, wire): if wire.startswith("G_"): return wire m = rel_netname_re.match(wire) - tile_pos = tiles.pos_from_name(tile) + tile_pos = tiles.pos_from_name(tile, chip_size, bias) wire_pos = tile_pos if m: assert len(m.groups()) >= 1 @@ -314,17 +315,17 @@ def main(): assert is_cib("R47C58_H06W0003") assert is_cib("R47C61_CLK0") - assert normalise_name((95, 126), "R48C26", "R48C26_B1") == "B1" - assert normalise_name((95, 126), "R48C26", "R48C26_HPBX0600") == "G_HPBX0600" - assert normalise_name((95, 126), "R48C26", "R48C25_H02E0001") == "W1_H02E0001" - assert normalise_name((95, 126), "R48C1", "R48C1_H02E0002") == "W1_H02E0001" - assert normalise_name((95, 126), "R82C90", "R79C90_V06S0003") == "N3_V06S0003" - assert normalise_name((95, 126), "R5C95", "R3C95_V06S0004") == "N3_V06S0003" - assert normalise_name((95, 126), "R1C95", "R1C95_V06S0006") == "N3_V06S0003" - assert normalise_name((95, 126), "R3C95", "R2C95_V06S0005") == "N3_V06S0003" - assert normalise_name((95, 126), "R82C95", "R85C95_V06N0303") == "S3_V06N0303" - assert normalise_name((95, 126), "R90C95", "R92C95_V06N0304") == "S3_V06N0303" - assert normalise_name((95, 126), "R93C95", "R94C95_V06N0305") == "S3_V06N0303" + assert normalise_name((95, 126), "R48C26", "R48C26_B1", 0) == "B1" + assert normalise_name((95, 126), "R48C26", "R48C26_HPBX0600", 0) == "G_HPBX0600" + assert normalise_name((95, 126), "R48C26", "R48C25_H02E0001", 0) == "W1_H02E0001" + assert normalise_name((95, 126), "R48C1", "R48C1_H02E0002", 0) == "W1_H02E0001" + assert normalise_name((95, 126), "R82C90", "R79C90_V06S0003", 0) == "N3_V06S0003" + assert normalise_name((95, 126), "R5C95", "R3C95_V06S0004", 0) == "N3_V06S0003" + assert normalise_name((95, 126), "R1C95", "R1C95_V06S0006", 0) == "N3_V06S0003" + assert normalise_name((95, 126), "R3C95", "R2C95_V06S0005", 0) == "N3_V06S0003" + assert normalise_name((95, 126), "R82C95", "R85C95_V06N0303", 0) == "S3_V06N0303" + assert normalise_name((95, 126), "R90C95", "R92C95_V06N0304", 0) == "S3_V06N0303" + assert normalise_name((95, 126), "R93C95", "R94C95_V06N0305", 0) == "S3_V06N0303" if __name__ == "__main__": diff --git a/util/common/tiles.py b/util/common/tiles.py index 2d8890af..d4c2043f 100644 --- a/util/common/tiles.py +++ b/util/common/tiles.py @@ -1,15 +1,17 @@ import re +import pytrellis -pos_re = re.compile(r'R(\d+)C(\d+)') - -def pos_from_name(tile): +def pos_from_name(tile, chip_size, bias): """ Extract the tile position as a (row, column) tuple from its name """ - s = pos_re.search(tile) - assert s - return int(s.group(1)), int(s.group(2)) + size = pytrellis.IntPair() + size.first = chip_size[0] + size.second = chip_size[1] + + pos = pytrellis.get_row_col_pair_from_chipsize(tile, size, bias) + return int(pos.first), int(pos.second) def type_from_fullname(tile): diff --git a/util/fuzz/interconnect.py b/util/fuzz/interconnect.py index b598dfe3..e40045ba 100644 --- a/util/fuzz/interconnect.py +++ b/util/fuzz/interconnect.py @@ -27,7 +27,8 @@ def fuzz_interconnect(config, enable_span1_fix=False, func_cib=False, fc_prefix="", - nonlocal_prefix=""): + nonlocal_prefix="", + bias=0): """ The fully-automatic interconnect fuzzer function. This performs the fuzzing and updates the database with the results. It is expected that PyTrellis has already been initialised with the database prior to this function being @@ -48,6 +49,8 @@ def fuzz_interconnect(config, :param func_cib: if True, we are fuzzing a special function to CIB interconnect, enable optimisations for this :param fc_prefix: add a prefix to non-global fixed connections for device-specific fuzzers :param nonlocal_prefix: add a prefix to non-global and non-neighbour wires for device-specific fuzzers + :param bias: Apply offset correction for n-based column numbering, n > 0. Used used by Lattice + on certain families. """ netdata = isptcl.get_wires_at_position(config.ncd_prf, location) netnames = [x[0] for x in netdata] @@ -67,7 +70,7 @@ def fuzz_interconnect(config, if func_cib and not netname_filter_union: netnames = list(filter(lambda x: netname_predicate(x, netnames), netnames)) fuzz_interconnect_with_netnames(config, netnames, netname_predicate, arc_predicate, fc_predicate, func_cib, - netname_filter_union, False, fc_prefix, nonlocal_prefix) + netname_filter_union, False, fc_prefix, nonlocal_prefix, bias) def fuzz_interconnect_with_netnames( @@ -80,7 +83,8 @@ def fuzz_interconnect_with_netnames( netname_filter_union=False, full_mux_style=False, fc_prefix="", - nonlocal_prefix=""): + nonlocal_prefix="", + bias=0): """ 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. @@ -96,6 +100,8 @@ def fuzz_interconnect_with_netnames( 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 + :param bias: Apply offset correction for n-based column numbering, n > 0. Used used by Lattice + on certain families. """ net_arcs = isptcl.get_arcs_on_wires(config.ncd_prf, netnames, not bidir) baseline_bitf = config.build_design(config.ncl, {}, "base_") @@ -105,7 +111,7 @@ def fuzz_interconnect_with_netnames( 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) + return tuple(nets.normalise_name((max_row, max_col), tile, x, bias) for x in arc) def add_nonlocal_prefix(wire): if wire.startswith("G_"):