#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # Copyright (C) 2017-2020 The Project X-Ray Authors. # # Use of this source code is governed by a ISC-style # license that can be found in the LICENSE file or at # https://opensource.org/licenses/ISC # # SPDX-License-Identifier: ISC import sys, os, json import pickle class MergeFind: def __init__(self): self.db = dict() def merge(self, a, b): a = self.find(a) b = self.find(b) if a != b: self.db[a] = b def find(self, a): if a in self.db: c = self.find(self.db[a]) self.db[a] = c return c return a def db_gen(): print("Reading database..") with open("%s/%s/tilegrid.json" % (os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE")), "r") as f: tilegrid = json.load(f) with open("%s/%s/tileconn.json" % (os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE")), "r") as f: tileconn = json.load(f) type_to_tiles = dict() grid_to_tile = dict() nodes = MergeFind() for tile, tiledata in tilegrid.items(): if tiledata["type"] not in type_to_tiles: type_to_tiles[tiledata["type"]] = list() type_to_tiles[tiledata["type"]].append(tile) grid_to_tile[(tiledata["grid_x"], tiledata["grid_y"])] = tile print("Processing tileconn..") for entry in tileconn: type_a, type_b = entry["tile_types"] for tile_a in type_to_tiles[type_a]: tiledata_a = tilegrid[tile_a] grid_a = (tiledata_a["grid_x"], tiledata_a["grid_y"]) grid_b = ( grid_a[0] + entry["grid_deltas"][0], grid_a[1] + entry["grid_deltas"][1]) if grid_b not in grid_to_tile: continue tile_b = grid_to_tile[grid_b] tiledata_b = tilegrid[tile_b] if tiledata_b["type"] != type_b: continue for pair in entry["wire_pairs"]: nodes.merge((tile_a, pair[0]), (tile_b, pair[1])) print("Processing PIPs..") node_node_pip = dict() reverse_node_node = dict() for tile_type in ["int_l", "int_r"]: with open("%s/%s/segbits_%s.db" % (os.getenv("XRAY_DATABASE_DIR"), os.getenv("XRAY_DATABASE"), tile_type), "r") as f: for line in f: _, dst, src = line.split()[0].split(".") for tile in type_to_tiles[tile_type.upper()]: src_node = nodes.find((tile, src)) dst_node = nodes.find((tile, dst)) if src_node not in node_node_pip: node_node_pip[src_node] = dict() if dst_node not in reverse_node_node: reverse_node_node[dst_node] = set() node_node_pip[src_node][dst_node] = "%s.%s.%s" % ( tile, dst, src) reverse_node_node[dst_node].add(src_node) return type_to_tiles, grid_to_tile, nodes, node_node_pip, reverse_node_node def db_load(): # Takes a while. Speed things up picklef = os.getenv('XRAY_DIR') + '/tools/simpleroute.p' if os.path.exists(picklef): #print('Pickle: load') db_res = pickle.load(open(picklef, 'rb')) else: #print('Pickle: rebuilding') db_res = db_gen() #print('Pickle: save') pickle.dump(db_res, open(picklef, 'wb')) return db_res def route(args): type_to_tiles, grid_to_tile, nodes, node_node_pip, reverse_node_node = db_load( ) active_pips = set() blocked_nodes = set() for argidx in range((len(args)) // 2): src_tile, src_wire = args[2 * argidx].split("/") dst_tile, dst_wire = args[2 * argidx + 1].split("/") src_node = nodes.find((src_tile, src_wire)) dst_node = nodes.find((dst_tile, dst_wire)) print("Routing %s -> %s:" % (src_node, dst_node)) node_scores = dict() def write_scores(nodes, count): next_nodes = set() for n in nodes: if n in node_scores: continue node_scores[n] = count if n == src_node: return if n in reverse_node_node: for nn in reverse_node_node[n]: if nn not in node_scores and nn not in blocked_nodes: next_nodes.add(nn) write_scores(next_nodes, count + 1) try: write_scores(set([dst_node]), 1) except RecursionError as e: raise Exception( "Could not find route for node %s" % (dst_node, )) from None print(" route length: %d" % node_scores[src_node]) count = 0 c = src_node blocked_nodes.add(c) print(" %4d: %s" % (count, c)) score = node_scores[src_node] while c != dst_node: nn = None for n in node_node_pip[c].keys(): if n in node_scores and node_scores[n] < score: nn, score = n, node_scores[n] pip = node_node_pip[c][nn] active_pips.add(pip) print(" %s" % pip) count += 1 c = nn blocked_nodes.add(c) print(" %4d: %s" % (count, c)) print("====") pipnames = list() for pip in sorted(active_pips): tile, dst, src = pip.split(".") pipnames.append("%s/%s.%s->>%s" % (tile, tile[0:5], src, dst)) print( "highlight_objects -color orange [get_nodes -of_objects [get_wires {%s}]]" % " ".join(["%s/%s" % n for n in sorted(blocked_nodes)])) print( "highlight_objects -color orange [get_pips {%s}]" % " ".join(pipnames)) print("====") for pip in sorted(active_pips): print(pip) return active_pips if __name__ == '__main__': if len(sys.argv) == 1 or (len(sys.argv) % 2) != 1: print() print("Usage: %s src1 dst1 [src2 dst2 [...]]" % sys.argv[0]) print("Where entires as tile/wire") print() print( "Example: %s VBRK_X29Y140/VBRK_ER1BEG2 VFRAME_X47Y113/VFRAME_EL1BEG2" % sys.argv[0]) print() sys.exit(1) route(sys.argv[1:])