blob: aedb27bccdc35c345e88675b05bc4eee1b285c0e [file] [log] [blame]
#!/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 argparse
import datetime
import progressbar
import os.path
import prjxray.lib
import pickle
import collections
import json
def build_node_index(fname):
node_index = {}
with open(fname, 'rb') as f:
f.seek(0, 2)
bytes = f.tell()
f.seek(0, 0)
with progressbar.ProgressBar(max_value=bytes) as bar:
end_of_line = 0
for l in f:
parts = l.decode('utf8').split(' ')
pip, node = parts[0:2]
if node not in node_index:
node_index[node] = []
node_index[node].append(end_of_line)
end_of_line = f.tell()
bar.update(end_of_line)
return node_index
def read_node(expected_node, wire_file, node_index):
with open(wire_file, 'rb') as f:
for index in node_index:
f.seek(index, 0)
parts = f.readline().decode('utf8').strip().split(' ')
pip, node = parts[0:2]
wires = parts[2:]
assert node == expected_node, repr((node, expected_node, index))
yield wires
def generate_edges(graph, root, graph_nodes):
""" Starting from root, generate an edge in dir and insert into graph.
If the tree forks, simply insert a joins to indicate the split.
"""
edge = [root]
prev_root = None
while True:
outbound_edges = graph_nodes[root]
outbound_edges -= set((prev_root, ))
if len(outbound_edges) > 1:
graph['edges'].append(edge)
if root not in graph['joins']:
graph['joins'][root] = set()
graph['joins'][root] |= outbound_edges
for element in graph_nodes[root]:
if element not in graph['joins']:
graph['joins'][element] = set()
graph['joins'][element].add(root)
break
else:
if len(outbound_edges) == 0:
graph['edges'].append(edge)
break
next_root = tuple(outbound_edges)[0]
edge.append(next_root)
prev_root, root = root, next_root
def create_ordered_wires_for_node(node, wires_in_node, downhill, uphill):
if len(wires_in_node) <= 2:
return {'edges': [wires_in_node], 'joins': {}}
downhill = set(tuple(l) for l in downhill)
uphill = set(tuple(l) for l in uphill)
roots = set()
all_wires = set()
for wire in downhill:
if len(wire) > 0:
roots |= set((wire[0], wire[-1]))
all_wires |= set(wire)
for wire in uphill:
if len(wire) > 0:
roots |= set((wire[0], wire[-1]))
all_wires |= set(wire)
assert len(wires_in_node) >= len(all_wires), (
len(wires_in_node), len(all_wires))
if len(all_wires) <= 2:
return {'edges': tuple(all_wires), 'joins': {}}
graph_nodes = dict((wire, set()) for wire in all_wires)
for wire in all_wires:
for down in downhill:
try:
idx = down.index(wire)
if idx + 1 < len(down):
graph_nodes[wire].add(down[idx + 1])
if idx - 1 >= 0:
graph_nodes[wire].add(down[idx - 1])
except ValueError:
continue
for up in uphill:
try:
idx = up.index(wire)
if idx + 1 < len(up):
graph_nodes[wire].add(up[idx + 1])
if idx - 1 >= 0:
graph_nodes[wire].add(up[idx - 1])
except ValueError:
continue
graph = {'edges': [], 'joins': {}}
while len(roots) > 0:
root = roots.pop()
if len(graph_nodes[root]) > 0:
generate_edges(graph, root, graph_nodes)
# Dedup identical edges.
final_edges = set()
for edge in graph['edges']:
edge1 = tuple(edge)
edge2 = tuple(edge[::-1])
if edge1 > edge2:
final_edges.add((edge2, edge1))
else:
final_edges.add((edge1, edge2))
edges = [edge[0] for edge in final_edges]
element_index = {}
for edge in edges:
for idx, element in enumerate(edge):
if element not in element_index:
element_index[element] = []
element_index[element].append((idx, edge))
new_edges = []
for edge in edges:
starts = element_index[edge[0]]
ends = element_index[edge[-1]]
found_any = False
for start in starts:
start_idx, other_edge = start
if other_edge is edge:
continue
for end in ends:
if other_edge is not end[1]:
continue
found_any = True
end_idx, _ = end
# check if the interior elements are the same.
if start_idx > end_idx:
step = -1
else:
step = 1
other_edge_slice = slice(
start_idx, end_idx + step if end_idx + step >= 0 else None,
step)
if edge != other_edge[other_edge_slice]:
new_edges.append(edge)
if not found_any:
new_edges.append(edge)
output = {
'edges':
new_edges,
'joins':
dict((key, tuple(value)) for key, value in graph['joins'].items()),
'wires':
wires_in_node,
}
all_wires_in_output = set()
for edge in output['edges']:
all_wires_in_output |= set(edge)
for element in output['joins']:
all_wires_in_output.add(element)
return output
def main():
parser = argparse.ArgumentParser(description="")
parser.add_argument('--dump_all_root_dir', required=True)
parser.add_argument('--ordered_wires_root_dir', required=True)
parser.add_argument('--output_dir', required=True)
args = parser.parse_args()
downhill_wires = os.path.join(
args.ordered_wires_root_dir, 'downhill_wires.txt')
uphill_wires = os.path.join(
args.ordered_wires_root_dir, 'uphill_wires.txt')
assert os.path.exists(downhill_wires)
assert os.path.exists(uphill_wires)
print('{} Reading root.csv'.format(datetime.datetime.now()))
tiles, nodes = prjxray.lib.read_root_csv(args.dump_all_root_dir)
print('{} Loading node<->wire mapping'.format(datetime.datetime.now()))
node_lookup = prjxray.lib.NodeLookup()
node_lookup_file = os.path.join(args.output_dir, 'nodes.pickle')
if os.path.exists(node_lookup_file):
node_lookup.load_from_file(node_lookup_file)
else:
node_lookup.load_from_root_csv(nodes)
node_lookup.save_to_file(node_lookup_file)
wire_index_file = os.path.join(args.output_dir, 'wire_index.pickle')
if os.path.exists(wire_index_file):
print('{} Reading wire<->node index'.format(datetime.datetime.now()))
with open(wire_index_file, 'rb') as f:
wire_index = pickle.load(f)
downhill_wire_node_index = wire_index['downhill']
uphill_wire_node_index = wire_index['uphill']
else:
print('{} Creating wire<->node index'.format(datetime.datetime.now()))
downhill_wire_node_index = build_node_index(downhill_wires)
uphill_wire_node_index = build_node_index(uphill_wires)
with open(wire_index_file, 'wb') as f:
pickle.dump(
{
'downhill': downhill_wire_node_index,
'uphill': uphill_wire_node_index,
}, f)
print('{} Creating node tree'.format(datetime.datetime.now()))
nodes = collections.OrderedDict()
for node in progressbar.progressbar(sorted(node_lookup.nodes)):
nodes[node] = create_ordered_wires_for_node(
node, tuple(wire['wire'] for wire in node_lookup.nodes[node]),
tuple(
read_node(
node, downhill_wires, downhill_wire_node_index[node]
if node in downhill_wire_node_index else [])),
tuple(
read_node(
node, uphill_wires, uphill_wire_node_index[node]
if node in uphill_wire_node_index else [])))
print('{} Writing node tree'.format(datetime.datetime.now()))
with open(os.path.join(args.output_dir, 'node_tree.json'), 'w') as f:
json.dump(nodes, f, indent=2, sort_keys=True)
if __name__ == '__main__':
main()