| #!/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 | 
 | # | 
 | # Produces a complete database of wires in the ROI and their connections and tests if each | 
 | # routing node is a tree (i.e. fails with an error when a loop is found). | 
 |  | 
 | import os, sys, json | 
 |  | 
 | from prjxray.util import OpenSafeFile | 
 |  | 
 | def main(): | 
 |     with OpenSafeFile("%s/%s/tilegrid.json" % (os.getenv("XRAY_DATABASE_DIR"), | 
 |                                        os.getenv("XRAY_DATABASE")), "r") as f: | 
 |         tilegrid = json.load(f) | 
 |  | 
 |     with OpenSafeFile("%s/%s/tileconn.json" % (os.getenv("XRAY_DATABASE_DIR"), | 
 |                                        os.getenv("XRAY_DATABASE")), "r") as f: | 
 |         tileconn = json.load(f) | 
 |  | 
 |     grid = dict() | 
 |     wirepairs = dict() | 
 |     remwires = set() | 
 |  | 
 |     for tilename, tiledata in tilegrid.items(): | 
 |         key = (tiledata["grid_x"], tiledata["grid_y"]) | 
 |         grid[key] = tilename | 
 |  | 
 |     def check_tileconn_entry(tilename, tiledata, entry, idx): | 
 |         if idx == 0: | 
 |             otheridx = 1 | 
 |             otherxy = ( | 
 |                 tiledata["grid_x"] + entry["grid_deltas"][0], | 
 |                 tiledata["grid_y"] + entry["grid_deltas"][1]) | 
 |         else: | 
 |             otheridx = 0 | 
 |             otherxy = ( | 
 |                 tiledata["grid_x"] - entry["grid_deltas"][0], | 
 |                 tiledata["grid_y"] - entry["grid_deltas"][1]) | 
 |  | 
 |         if otherxy not in grid: | 
 |             return | 
 |  | 
 |         othertilename = grid[otherxy] | 
 |         othertiledata = tilegrid[othertilename] | 
 |  | 
 |         if othertiledata["type"] != entry["tile_types"][otheridx]: | 
 |             return | 
 |  | 
 |         print( | 
 |             "  Found relevant entry (%s %s %d %d): %s" % ( | 
 |                 entry["tile_types"][0], entry["tile_types"][1], | 
 |                 entry["grid_deltas"][0], entry["grid_deltas"][1], | 
 |                 othertilename)) | 
 |  | 
 |         for pair in entry["wire_pairs"]: | 
 |             wirename = "%s/%s" % (tilename, pair[idx]) | 
 |             otherwirename = "%s/%s" % (othertilename, pair[otheridx]) | 
 |  | 
 |             remwires.add(wirename) | 
 |             remwires.add(otherwirename) | 
 |  | 
 |             if wirename not in wirepairs: | 
 |                 wirepairs[wirename] = set() | 
 |             wirepairs[wirename].add(otherwirename) | 
 |  | 
 |             if otherwirename not in wirepairs: | 
 |                 wirepairs[otherwirename] = set() | 
 |             wirepairs[otherwirename].add(wirename) | 
 |  | 
 |     for tilename, tiledata in tilegrid.items(): | 
 |         print("Connecting wires in tile %s." % tilename) | 
 |         for entry in tileconn: | 
 |             if entry["tile_types"][0] == tiledata["type"]: | 
 |                 check_tileconn_entry(tilename, tiledata, entry, 0) | 
 |             if entry["tile_types"][1] == tiledata["type"]: | 
 |                 check_tileconn_entry(tilename, tiledata, entry, 1) | 
 |  | 
 |     def check_wire(wire, source): | 
 |         for next_wire in wirepairs[wire]: | 
 |             if next_wire == source: | 
 |                 continue | 
 |             print("  %s" % next_wire) | 
 |             if next_wire not in remwires: | 
 |                 print("  ** FOUND LOOP IN THIS NODE **") | 
 |                 sys.exit(1) | 
 |             remwires.remove(next_wire) | 
 |             check_wire(next_wire, wire) | 
 |  | 
 |     while len(remwires): | 
 |         wire = remwires.pop() | 
 |         print("Checking %s:" % wire) | 
 |         check_wire(wire, None) | 
 |  | 
 |     print("NO LOOP FOUND: OK") | 
 |  | 
 |  | 
 | if __name__ == "__main__": | 
 |     main() |