| #!/usr/bin/env python3 |
| import pytrellis |
| import nets |
| import tiles |
| import database |
| import readline |
| import re |
| |
| # Interactive connectivity explorer |
| # All netnames here are canonical |
| |
| |
| # Key |
| # <-- net driven by mux |
| # <== net driven by fixed conn |
| # --> net drives mux input |
| # ==> net drives net by fixed conn |
| |
| def main(): |
| pytrellis.load_database(database.get_db_root()) |
| c = pytrellis.Chip("LFE5U-45F") |
| chip_size = (c.get_max_row(), c.get_max_col()) |
| # Get fan-in to a net |
| # Returns (source, configurable, loc) |
| def get_fanin(net): |
| drivers = [] |
| 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, 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, 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, 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, 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, chip_size, 0) |
| for tile in c.get_all_tiles(): |
| tinf = tile.info |
| tname = tinf.name |
| 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, 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, 0), True, tname)) |
| for fc in tdb.get_fixed_conns(): |
| if fc.source == tnet: |
| drivers.append((nets.canonicalise_name(chip_size, tname, fc.sink, 0), False, tname)) |
| return drivers |
| |
| |
| # Get all nets at a location |
| net_tile_cache = {} |
| non_tile_re = re.compile(r"^([NS]\d+)?([EW]\d+)?[GLR]?_.*") |
| |
| def get_nets_at(loc): |
| if loc in net_tile_cache: |
| return net_tile_cache[loc] |
| row, col = loc |
| nets = set() |
| for tile in c.get_tiles_by_position(row, col): |
| tinf = tile.info |
| tdb = pytrellis.get_tile_bitdata(pytrellis.TileLocator(c.info.family, c.info.name, tinf.type)) |
| for sink in tdb.get_sinks(): |
| if not non_tile_re.match(sink): |
| nets.add(sink) |
| mux = tdb.get_mux_data_for_sink(sink) |
| for src in mux.get_sources(): |
| if not non_tile_re.match(src): |
| nets.add(src) |
| for fc in tdb.get_fixed_conns(): |
| if not non_tile_re.match(fc.sink): |
| nets.add(fc.sink) |
| if not non_tile_re.match(fc.source): |
| nets.add(fc.source) |
| nets = list(sorted((["R{}C{}_{}".format(row, col, _) for _ in nets]))) |
| net_tile_cache[loc] = nets |
| return nets |
| |
| tile_net_re = re.compile(r"^R\d+C\d+_.*") |
| def completer(str, idx): |
| if not tile_net_re.match(str): |
| return None |
| loc = tiles.pos_from_name(str, chip_size, 0) |
| nets = get_nets_at(loc) |
| for n in nets: |
| if n.startswith(str): |
| if idx > 0: |
| idx -= 1 |
| else: |
| return n |
| return None |
| |
| readline.parse_and_bind("tab: complete") |
| readline.set_completer(completer) |
| |
| hist_buf = [] |
| while True: |
| net = input("> ") |
| if net.strip() == "": |
| continue |
| if net == "quit": |
| return |
| if net.isdigit(): |
| idx = int(net) |
| if idx >= len(hist_buf): |
| print("Invalid index into last result") |
| continue |
| else: |
| net = hist_buf[idx] |
| if not tile_net_re.match(net): |
| print("Bad netname, expected RyCx_...") |
| continue |
| hist_buf = [] |
| fi = get_fanin(net) |
| for drv in fi: |
| finet, conf, tile = drv |
| if finet is None: continue |
| arrow = "<--" if conf else "<==" |
| print("[{:3d}] {} {} {:25s} [in {}]".format(len(hist_buf), net, arrow, finet, tile)) |
| hist_buf.append(finet) |
| print() |
| fo = get_fanout(net) |
| for src in fo: |
| fonet, conf, tile = src |
| if fonet is None: continue |
| arrow = "-->" if conf else "==>" |
| print("[{:3d}] {} {} {:25s} [in {}]".format(len(hist_buf), net, arrow, fonet, tile)) |
| hist_buf.append(fonet) |
| |
| if __name__ == "__main__": |
| main() |