-
Notifications
You must be signed in to change notification settings - Fork 152
/
simpleroute.py
executable file
·208 lines (166 loc) · 6.35 KB
/
simpleroute.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#!/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
from prjxray.util import OpenSafeFile
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 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)
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 OpenSafeFile("%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:])