blob: 5235c6a9c6bdd21a026da526ace8f06491817f15 [file] [edit]
""" Generate grid from database dump """
from __future__ import print_function
import argparse
import pyjson5 as json5
import multiprocessing
import progressbar
import os.path
import json
import datetime
import pickle
import sys
from collections import namedtuple
from utils import util, lib, tile_sizes, connections
from utils.xjson import extract_numbers
TileConnection = namedtuple('TileConnection', 'grid_deltas tile_types wire_pair')
def get_tile_grid_info(fname):
with open(fname, 'r') as f:
tile = json5.load(f)
tile_type = tile['type']
return {
tile['tile']: {
'type': tile_type,
'grid_x': tile['x'],
'grid_y': tile['y'],
'sites': dict(
(site['site'], site['type']) for site in tile['sites']),
'wires': set((wire['wire'] for wire in tile['wires']))
},
}
def read_json5(fname):
with open(fname, 'r') as f:
return json5.load(f)
def is_edge_shared(edge1, edge2):
""" Returns true if edge1 or edge2 overlap
>>> is_edge_shared((0, 1), (0, 1))
True
>>> is_edge_shared((0, 2), (0, 1))
True
>>> is_edge_shared((0, 1), (0, 2))
True
>>> is_edge_shared((1, 2), (0, 3))
True
>>> is_edge_shared((0, 3), (1, 2))
True
>>> is_edge_shared((1, 2), (0, 2))
True
>>> is_edge_shared((0, 2), (1, 2))
True
>>> is_edge_shared((0, 2), (1, 3))
True
>>> is_edge_shared((1, 3), (0, 2))
True
>>> is_edge_shared((0, 1), (1, 2))
False
>>> is_edge_shared((1, 2), (0, 1))
False
>>> is_edge_shared((0, 1), (2, 3))
False
>>> is_edge_shared((2, 3), (0, 1))
False
"""
assert edge1[0] < edge1[1], edge1
assert edge2[0] < edge2[1], edge2
if edge1[0] <= edge2[0]:
return edge2[0] < edge1[1]
else:
return edge1[0] < edge2[1]
def share_edge(a, b):
""" Returns true if box defined by a and b share any edge.
Box is defined as (x-min, y-min, x-max, y-max).
>>> share_edge((0, 0, 1, 1), (1, 0, 2, 1))
True
>>> share_edge((1, 0, 2, 1), (0, 0, 1, 1))
True
>>> share_edge((0, 0, 1, 1), (0, 1, 1, 2))
True
>>> share_edge((0, 1, 1, 2), (0, 0, 1, 1))
True
>>> share_edge((0, 0, 1, 3), (1, 0, 2, 1))
True
>>> share_edge((1, 0, 2, 1), (0, 0, 1, 3))
True
>>> share_edge((0, 0, 3, 1), (0, 1, 1, 2))
True
>>> share_edge((0, 1, 1, 2), (0, 0, 3, 1))
True
>>> share_edge((0, 0, 1, 1), (1, 1, 2, 2))
False
>>> share_edge((1, 1, 2, 2), (0, 0, 1, 1))
False
>>> share_edge((0, 0, 1, 3), (1, 3, 2, 4))
False
>>> share_edge((0, 0, 1, 3), (1, 2, 2, 4))
True
"""
a_x_min, a_y_min, a_x_max, a_y_max = a
b_x_min, b_y_min, b_x_max, b_y_max = b
if a_x_min == b_x_max or a_x_max == b_x_min:
return is_edge_shared((a_y_min, a_y_max), (b_y_min, b_y_max))
if a_y_min == b_y_max or a_y_max == b_y_min:
return is_edge_shared((a_x_min, a_x_max), (b_x_min, b_x_max))
def next_wire_in_dimension(wire1, tile1, wire2, tile2, tiles, x_wires, y_wires,
wire_map, wires_in_node):
""" next_wire_in_dimension returns true if tile1 and tile2 are in the same
row and column, and must be adjcent.
"""
tile1_info = tiles[tile1]
tile2_info = tiles[tile2]
tile1_x = tile1_info['grid_x']
tile2_x = tile2_info['grid_x']
tile1_y = tile1_info['grid_y']
tile2_y = tile2_info['grid_y']
# All wires are in the same row or column or if the each wire lies in its own
# row or column.
if len(y_wires) == 1 or len(x_wires) == len(wires_in_node) or abs(
tile1_y - tile2_y) == 0:
ordered_wires = sorted(x_wires.keys())
idx1 = ordered_wires.index(tile1_x)
idx2 = ordered_wires.index(tile2_x)
if len(x_wires[tile1_x]) == 1 and len(x_wires[tile2_x]) == 1:
return abs(idx1 - idx2) == 1
if len(x_wires) == 1 or len(y_wires) == len(wires_in_node) or abs(
tile1_x - tile2_x) == 0:
ordered_wires = sorted(y_wires.keys())
idx1 = ordered_wires.index(tile1_y)
idx2 = ordered_wires.index(tile2_y)
if len(y_wires[tile1_y]) == 1 and len(y_wires[tile2_y]) == 1:
return abs(idx1 - idx2) == 1
return None
def only_wire(tile1, tile2, tiles, x_wires, y_wires):
""" only_wire returns true if tile1 and tile2 only have 1 wire in their respective x or y dimension.
"""
tile1_info = tiles[tile1]
tile2_info = tiles[tile2]
tile1_x = tile1_info['grid_x']
tile2_x = tile2_info['grid_x']
tiles_x_adjacent = abs(tile1_x - tile2_x) == 1
if tiles_x_adjacent and len(x_wires[tile1_x]) == 1 and len(
x_wires[tile2_x]) == 1:
return True
tile1_y = tile1_info['grid_y']
tile2_y = tile2_info['grid_y']
tiles_y_adjacent = abs(tile1_y - tile2_y) == 1
if tiles_y_adjacent and len(y_wires[tile1_y]) == 1 and len(
y_wires[tile2_y]) == 1:
return True
return None
def is_directly_connected(node, node_tree, wire1, wire2):
if 'wires' in node_tree:
node_tree_wires = node_tree['wires']
else:
if len(node_tree['edges']) == 1 and len(node_tree['joins']) == 0:
node_tree_wires = node_tree['edges'][0]
else:
return None
if wire1 not in node_tree_wires:
return None
if wire2 not in node_tree_wires:
return None
# Is there than edge that has wire1 next to wire2?
for edge in node_tree['edges']:
idx1 = None
idx2 = None
try:
idx1 = edge.index(wire1)
except ValueError:
pass
try:
idx2 = edge.index(wire2)
except ValueError:
pass
if idx1 is not None and idx2 is not None:
return abs(idx1 - idx2) == 1
if idx1 is not None and (idx1 != 0 and idx1 != len(edge) - 1):
return False
if idx2 is not None and (idx2 != 0 and idx2 != len(edge) - 1):
return False
# Is there a join of nodes between wire1 and wire2?
if wire1 in node_tree['joins']:
return wire2 in node_tree['joins'][wire1]
if wire2 in node_tree['joins']:
assert wire1 not in node_tree['joins'][wire2]
return None
def is_connected(wire1, tile1, wire2, tile2, node, wires_in_tiles, wire_map,
node_tree, tiles, x_wires, y_wires, wires_in_node):
""" Check if two wires are directly connected. """
# Because there are multiple possible wire connections between these two
# tiles, consult the node_tree to determine if the two wires are actually connected.
#
# Warning: The node_tree is incomplete because it is not know how to extract
# ordered wire information from the node.
#
# Example node CLK_BUFG_REBUF_X60Y142/CLK_BUFG_REBUF_R_CK_GCLK0_BOT
# It does not appear to be possible to get ordered wire connection information
# for the first two wires connected to PIP
# CLK_BUFG_REBUF_X60Y117/CLK_BUFG_REBUF.CLK_BUFG_REBUF_R_CK_GCLK0_BOT<<->>CLK_BUFG_REBUF_R_CK_GCLK0_TOP
#
# However, it happens to be that theses wires are the only wires in their
# tiles, so the earlier "only wires in tile" check will pass.
connected = is_directly_connected(node['node'], node_tree[node['node']],
wire1, wire2)
if connected is not None:
return connected
is_only_wire = only_wire(tile1, tile2, tiles, x_wires, y_wires)
if is_only_wire is not None:
return is_only_wire
# The node_tree didn't specify these wires, and the wires are not
# unambiguously connected.
return None
def process_node(tileconn, key_history, node, wire_map, node_tree, tiles, tile_type_sizes, revisit_list):
wires = [wire['wire'] for wire in node['wires']]
wires_in_tiles = {}
x_wires = {}
y_wires = {}
for wire in wires:
wire_info = wire_map[wire]
if wire_info['tile'] not in wires_in_tiles:
wires_in_tiles[wire_info['tile']] = []
wires_in_tiles[wire_info['tile']].append(wire)
grid_x = tiles[wire_info['tile']]['grid_x']
if grid_x not in x_wires:
x_wires[grid_x] = []
x_wires[grid_x].append(wire)
grid_y = tiles[wire_info['tile']]['grid_y']
if grid_y not in y_wires:
y_wires[grid_y] = []
y_wires[grid_y].append(wire)
if len(wires) == 2:
wire1 = wires[0]
wire_info1 = wire_map[wire1]
wire2 = wires[1]
wire_info2 = wire_map[wire2]
update_tile_conn(tileconn, key_history, wire1, wire_info1, wire2,
wire_info2, tiles)
return
for idx, wire1 in enumerate(wires):
wire_info1 = wire_map[wire1]
for wire2 in wires[idx + 1:]:
wire_info2 = wire_map[wire2]
tile1 = tiles[wire_info1['tile']]
tile2 = tiles[wire_info2['tile']]
result = is_connected(wire1, wire_info1['tile'], wire2,
wire_info2['tile'], node, wires_in_tiles,
wire_map, node_tree, tiles, x_wires, y_wires,
wires)
if result is not None:
if not result:
continue
else:
# This wire is an unknown, come back to it
dx = tile2['grid_x'] - tile1['grid_x']
dy = tile2['grid_y'] - tile1['grid_y']
same_tile = dx == 0 and dy == 0
if same_tile or tile_sizes.tiles_are_adjcent(tile1, tile2, tile_type_sizes):
revisit_list.append((wire1, wire2))
continue
update_tile_conn(tileconn, key_history, wire1, wire_info1, wire2,
wire_info2, tiles)
def update_tile_conn(tileconn, key_history, wirename1, wire1, wirename2, wire2,
tiles):
# Ensure that (wire1, wire2) is sorted, so we can easy check if a connection
# already exists.
tile1 = tiles[wire1['tile']]
tile2 = tiles[wire2['tile']]
if ((wire1['type'], wire1['shortname'], tile1['grid_x'], tile1['grid_y']) >
(wire2['type'], wire2['shortname'], tile2['grid_x'], tile2['grid_y'])):
wire1, tile1, wire2, tile2 = wire2, tile2, wire1, tile1
tileconn.append(TileConnection(
grid_deltas=(
tile2['grid_x'] - tile1['grid_x'],
tile2['grid_y'] - tile1['grid_y'],
),
tile_types=(
tile1['type'],
tile2['type'],
),
wire_pair=(
wire1['shortname'],
wire2['shortname'],
),
))
def flatten_tile_conn(tileconn):
""" Convert tileconn that is key'd to identify specific wire pairs between tiles
key (tile1_type, wire1_name, tile2_type, wire2_name) to flat tile connect list
that relates tile types and relative coordinates and a full list of wires to
connect. """
flat_tileconn = {}
for conn in tileconn:
key = (tuple(conn.tile_types), tuple(conn.grid_deltas))
if key not in flat_tileconn:
flat_tileconn[key] = {
'tile_types': conn.tile_types,
'grid_deltas': conn.grid_deltas,
'wire_pairs': set()
}
flat_tileconn[key]['wire_pairs'].add(tuple(conn.wire_pair))
def inner():
for output in flat_tileconn.values():
yield {
'tile_types': output['tile_types'],
'grid_deltas': output['grid_deltas'],
'wire_pairs': tuple(output['wire_pairs']),
}
return tuple(inner())
def is_tile_type(tiles, coord_to_tile, coord, tile_type):
if coord not in coord_to_tile:
return False
target_tile = tiles[coord_to_tile[coord]]
return target_tile['type'] == tile_type
def get_connections(wire, wire_info, conn, idx, coord_to_tile, tiles):
""" Yields (tile_coord, wire) for each wire that should be connected to specified wire. """
pair = conn['wire_pairs'][idx]
wire_tile_type = wire_info['type']
tile_types = conn['tile_types']
shortname = wire_info['shortname']
grid_deltas = conn['grid_deltas']
wire1 = tile_types[0] == wire_tile_type and shortname == pair[0]
wire2 = tile_types[1] == wire_tile_type and shortname == pair[1]
assert wire1 or wire2, (wire, conn)
tile_of_wire = wire_info['tile']
start_coord_x = tiles[tile_of_wire]['grid_x']
start_coord_y = tiles[tile_of_wire]['grid_y']
if wire1:
target_coord_x = start_coord_x + grid_deltas[0]
target_coord_y = start_coord_y + grid_deltas[1]
target_tile_type = tile_types[1]
target_wire = pair[1]
target_tile = (target_coord_x, target_coord_y)
if is_tile_type(tiles, coord_to_tile, target_tile, target_tile_type):
yield target_tile, target_wire
if wire2:
target_coord_x = start_coord_x - grid_deltas[0]
target_coord_y = start_coord_y - grid_deltas[1]
target_tile_type = tile_types[0]
target_wire = pair[0]
target_tile = (target_coord_x, target_coord_y)
if is_tile_type(tiles, coord_to_tile, target_tile, target_tile_type):
yield target_tile, target_wire
def make_connection(wire_nodes, wire1, wire2):
if wire_nodes[wire1] is wire_nodes[wire2]:
assert wire1 in wire_nodes[wire1]
assert wire2 in wire_nodes[wire2]
return
new_node = wire_nodes[wire1] | wire_nodes[wire2]
for wire in new_node:
wire_nodes[wire] = new_node
def create_coord_to_tile(tiles):
coord_to_tile = {}
for tile, tileinfo in tiles.items():
coord_to_tile[(tileinfo['grid_x'], tileinfo['grid_y'])] = tile
return coord_to_tile
def connect_wires(tiles, tileconn, wire_map):
""" Connect individual wires into groups of wires called nodes. """
# Map of tile type to list of wires in tile type
tile_wires = {}
for tile_info in tiles.values():
tile_wires[tile_info['type']] = set()
for wire, wire_info in wire_map.items():
tile = tiles[wire_info['tile']]
tile_type = tile['type']
tile_wires[tile_type].add(wire_info['shortname'])
# Initialize all nodes to originally only contain the wire by itself.
wire_nodes = {}
for wire in wire_map:
wire_nodes[wire] = set([wire])
conns = connections.Connections(tiles, tileconn, tile_wires)
for wire_a, wire_b in conns.get_connections():
full_wire_a = wire_a.tile + '/' + wire_a.wire
full_wire_b = wire_b.tile + '/' + wire_b.wire
make_connection(wire_nodes, full_wire_a, full_wire_b)
# Find unique nodes
nodes = {}
for node in wire_nodes.values():
nodes[id(node)] = node
# Flatten to list of lists.
return tuple(tuple(node) for node in nodes.values())
def generate_tilegrid(pool, tiles):
wire_map = {}
grid = {}
num_tiles = 0
for tile_type in tiles:
num_tiles += len(tiles[tile_type])
idx = 0
with progressbar.ProgressBar(max_value=num_tiles) as bar:
for tile_type in tiles:
for tile in pool.imap_unordered(
get_tile_grid_info,
tiles[tile_type],
chunksize=20,
):
bar.update(idx)
assert len(tile) == 1, tile
tilename = tuple(tile.keys())[0]
for wire in tile[tilename]['wires']:
assert wire not in wire_map, (wire, wire_map)
assert wire.startswith(tilename + '/'), (wire, tilename)
wire_map[wire] = {
'tile': tilename,
'type': tile[tilename]['type'],
'shortname': wire[len(tilename) + 1:],
}
del tile[tilename]['wires']
grid.update(tile)
idx += 1
bar.update(idx)
return grid, wire_map
def revisit_wires(tileconn, nodes, revisit_list, key_history, wire_map, grid):
interesting_wires = {}
for wire1, wire2 in revisit_list:
wire_info1 = wire_map[wire1]
wire_info2 = wire_map[wire2]
tile1 = grid[wire_info1['tile']]
tile2 = grid[wire_info2['tile']]
interesting_wires[tile1['type'], wire_info1['shortname']] = set()
interesting_wires[tile2['type'], wire_info2['shortname']] = set()
for conn in tileconn:
for idx, k in enumerate(zip(conn.tile_types, conn.wire_pair)):
k = tuple(k)
if k in interesting_wires:
if sum(map(abs, conn.grid_deltas)) != 1:
continue
if idx == 0:
interesting_wires[k].add(conn.grid_deltas)
else:
interesting_wires[k].add((-conn.grid_deltas[0], -conn.grid_deltas[1]))
print('{} 1. Remaining {} revisit pairs'.format(datetime.datetime.now(), len(revisit_list)))
revisit_list2 = []
for wire1, wire2 in revisit_list:
wire_info1 = wire_map[wire1]
wire_info2 = wire_map[wire2]
tile1 = grid[wire_info1['tile']]
tile2 = grid[wire_info2['tile']]
key1 = tile1['type'], wire_info1['shortname']
key2 = tile2['type'], wire_info2['shortname']
wire1_directions = interesting_wires[key1]
wire2_directions = interesting_wires[key2]
dx = tile2['grid_x'] - tile1['grid_x']
dy = tile2['grid_y'] - tile1['grid_y']
paired_wires = False
if (dx, dy) in wire1_directions and len(wire2_directions) == 0:
interesting_wires[key2].add((-dx, -dy))
paired_wires = True
if (-dx, -dy) in wire2_directions and len(wire1_directions) == 0:
interesting_wires[key1].add((dx, dy))
paired_wires = True
if (dx, dy) in wire1_directions and (-dx, -dy) in wire2_directions:
paired_wires = True
if paired_wires:
update_tile_conn(
tileconn, key_history,
wire1, wire_info1,
wire2, wire_info2,
grid)
else:
revisit_list2.append((wire1, wire2))
print('{} 2. Remaining {} revisit pairs'.format(datetime.datetime.now(), len(revisit_list2)))
tileconn = list(set(tileconn))
print('{} Pruning bad connections, have {} connections'.format(datetime.datetime.now(), len(tileconn)))
# Construct map from (tile_type, wire) -> list of tiles
tile_type_instances = {}
tile_at_loc = {}
for tile, gridinfo in grid.items():
if gridinfo['type'] not in tile_type_instances:
tile_type_instances[gridinfo['type']] = []
tile_type_instances[gridinfo['type']].append(tile)
loc = gridinfo['grid_x'], gridinfo['grid_y']
assert loc not in tile_at_loc
tile_at_loc[loc] = tile
# Prune bad connections
bad_connections = set()
for idx, conn in enumerate(progressbar.progressbar(tileconn)):
tile1_type, tile2_type = conn.tile_types
wire1, wire2 = conn.wire_pair
for tile1 in tile_type_instances[tile1_type]:
tile1_info = grid[tile1]
assert tile1_info['type'] == tile1_type
dx, dy = conn.grid_deltas
tile2_grid_x = tile1_info['grid_x'] + dx
tile2_grid_y = tile1_info['grid_y'] + dy
loc = tile2_grid_x, tile2_grid_y
if loc not in tile_at_loc:
continue
tile2 = tile_at_loc[loc]
tile2_info = grid[tile2]
if tile2_info['type'] != tile2_type:
continue
fullwire1 = tile1 + '/' + wire1
fullwire2 = tile2 + '/' + wire2
if fullwire1 not in nodes or fullwire2 not in nodes:
bad_connections.add(idx)
continue
# tileconn says these two wires should form a node. If these wires
# are a node, they will have the same set object representing
# the node.
if nodes[fullwire1] is not nodes[fullwire2]:
bad_connections.add(idx)
print('{} Found {} bad connections'.format(datetime.datetime.now(), len(bad_connections)))
# Delete from highest index to lowest index to preverse deletion order
for idx in sorted(bad_connections, reverse=True):
del tileconn[idx]
print('{} Removed {} bad connections'.format(datetime.datetime.now(), len(bad_connections)))
return tileconn
def generate_tileconn(pool, node_tree, nodes, wire_map, grid, tile_type_sizes):
tileconn = []
key_history = {}
raw_node_data = []
revisit_list = []
wire_nodes = {}
with progressbar.ProgressBar(max_value=len(nodes)) as bar:
for idx, node in enumerate(
pool.imap_unordered(
read_json5,
nodes,
chunksize=20,
)):
bar.update(idx)
raw_node_data.append(node)
process_node(tileconn, key_history, node, wire_map, node_tree,
grid, tile_type_sizes, revisit_list)
bar.update(idx + 1)
node = set(wire['wire'] for wire in node['wires'])
for wire in node:
assert wire not in wire_nodes
wire_nodes[wire] = node
tileconn = revisit_wires(tileconn, wire_nodes, revisit_list, key_history, wire_map, grid)
tileconn = flatten_tile_conn(tileconn)
return tileconn, raw_node_data
def main():
parser = argparse.ArgumentParser(
description=
"Reduces raw database dump into prototype tiles, grid, and connections."
)
parser.add_argument('--root_dir', required=True)
parser.add_argument('--output_dir', required=True)
parser.add_argument('--verify_only', action='store_true')
parser.add_argument('--ignored_wires')
parser.add_argument('--max_cpu', type=int, default=10)
args = parser.parse_args()
tiles, nodes = lib.read_root_csv(args.root_dir)
processes = min(multiprocessing.cpu_count(), args.max_cpu)
print('{} Running {} processes'.format(datetime.datetime.now(), processes))
pool = multiprocessing.Pool(processes=processes)
node_tree_file = os.path.join(args.output_dir, 'node_tree.json')
tileconn_file = os.path.join(args.output_dir, 'tileconn.json')
wire_map_file = os.path.join(args.output_dir, 'wiremap.pickle')
print('{} Reading tilegrid'.format(datetime.datetime.now()))
with open(
os.path.join(util.get_db_root(), util.get_part(),
'tilegrid.json')) as f:
grid = json.load(f)
if not args.verify_only:
print('{} Creating tile map'.format(datetime.datetime.now()))
grid2, wire_map = generate_tilegrid(pool, tiles)
# Make sure tilegrid from 005-tilegrid matches tilegrid from
# generate_tilegrid.
db_grid_keys = set(grid.keys())
generated_grid_keys = set(grid2.keys())
assert db_grid_keys == generated_grid_keys, (
db_grid_keys ^ generated_grid_keys)
for tile in db_grid_keys:
for k in grid2[tile]:
assert k in grid[tile], k
assert grid[tile][k] == grid2[tile][k], (tile, k,
grid[tile][k],
grid2[tile][k])
with open(wire_map_file, 'wb') as f:
pickle.dump(wire_map, f)
print('{} Reading node tree'.format(datetime.datetime.now()))
with open(node_tree_file) as f:
node_tree = json.load(f)
tile_type_sizes = tile_sizes.guess_tile_type_sizes(grid)
print('{} Creating tile connections'.format(datetime.datetime.now()))
tileconn, raw_node_data = generate_tileconn(pool, node_tree, nodes,
wire_map, grid, tile_type_sizes)
for data in tileconn:
data['wire_pairs'] = tuple(
sorted(
data['wire_pairs'],
key=lambda x: tuple(extract_numbers(s) for s in x)))
tileconn = tuple(
sorted(
tileconn, key=lambda x: (x['tile_types'], x['grid_deltas'])))
print('{} Writing tileconn'.format(datetime.datetime.now()))
with open(tileconn_file, 'w') as f:
json.dump(tileconn, f, indent=2, sort_keys=True)
else:
with open(wire_map_file, 'rb') as f:
wire_map = pickle.load(f)
print('{} Reading raw_node_data'.format(datetime.datetime.now()))
raw_node_data = []
with progressbar.ProgressBar(max_value=len(nodes)) as bar:
for idx, node in enumerate(
pool.imap_unordered(
read_json5,
nodes,
chunksize=20,
)):
bar.update(idx)
raw_node_data.append(node)
bar.update(idx + 1)
print('{} Reading tileconn'.format(datetime.datetime.now()))
with open(tileconn_file) as f:
tileconn = json.load(f)
wire_nodes_file = os.path.join(args.output_dir, 'wire_nodes.pickle')
if os.path.exists(wire_nodes_file) and args.verify_only:
with open(wire_nodes_file, 'rb') as f:
wire_nodes = pickle.load(f)
else:
print("{} Connecting wires to verify tileconn".format(
datetime.datetime.now()))
wire_nodes = connect_wires(grid, tileconn, wire_map)
with open(wire_nodes_file, 'wb') as f:
pickle.dump(wire_nodes, f)
print('{} Verifing tileconn'.format(datetime.datetime.now()))
error_nodes = []
lib.verify_nodes(
[(node['node'], tuple(wire['wire'] for wire in node['wires']))
for node in raw_node_data], wire_nodes, error_nodes)
if len(error_nodes) > 0:
error_nodes_file = os.path.join(args.output_dir, 'error_nodes.json')
with open(error_nodes_file, 'w') as f:
json.dump(error_nodes, f, indent=2, sort_keys=True)
ignored_wires = []
ignored_wires_file = args.ignored_wires
if os.path.exists(ignored_wires_file):
with open(ignored_wires_file) as f:
ignored_wires = set(l.strip() for l in f)
if not lib.check_errors(error_nodes, ignored_wires):
print('{} errors detected, see {} for details.'.format(
len(error_nodes), error_nodes_file))
sys.exit(1)
else:
print(
'{} errors ignored because of {}\nSee {} for details.'.format(
len(error_nodes), ignored_wires_file, error_nodes_file))
if __name__ == '__main__':
main()