blob: 3c1f83441e2558fa888f81e7c479a3f01eb289f7 [file] [log] [blame] [edit]
#!/usr/bin/env python3
"""
Import the top level tile interconnect information from Project X-Ray database
files.
The Project X-Ray specifies the connections between tiles and the connect
between tiles and their sites. prjxray_tile_import generates a VPR pb_type
that has the correct tile pin names to connect to the routing fabric, and
connects those tile pins to each site within the tile.
"""
from __future__ import print_function
import argparse
import os
import sys
import prjxray.db
import prjxray.site_type
import os.path
import simplejson as json
import re
import sqlite3
import lxml.etree as ET
from lib.pb_type_xml import (
start_pb_type, start_tile, add_vpr_tile_prefix, add_tile_direct,
object_ref, add_switchblock_locations, write_xml, ModelXml, add_direct,
XI_INCLUDE, XI_URL
)
def find_port(pin_name, ports):
if pin_name in ports:
return {
'pin_name': pin_name,
'pin_idx': None,
}
# Find trailing digits, which are assumed to be pin indicies, example:
# ADDRARDADDR13
m = re.search('([0-9]+)$', pin_name)
if m is None:
return None
prefix = pin_name[:-len(m.group(1))]
prefix_pin_idx = int(m.group(1))
if prefix in ports and prefix_pin_idx < ports[prefix]:
return {
'pin_name': prefix,
'pin_idx': prefix_pin_idx,
}
else:
return None
def parse_site_type_instance(site_types):
""" Convert site_types argument into map.
Parameters
----------
site_types : str
Returns
-------
site_type_instances : map of str to list of str
Maps site type to array of site type instances. First instance of
site should use first element, second instance should use second
element, etc.
"""
site_type_instances = {}
for s in site_types.split(','):
site_type, site_type_instance = s.split('/')
if site_type not in site_type_instances:
site_type_instances[site_type] = []
site_type_instances[site_type].append(site_type_instance)
return site_type_instances
def expand_nodes_in_tile_type(conn, tile_type_pkey):
cur = conn.cursor()
cur.execute(
"""
CREATE TEMP TABLE phy_tiles AS
SELECT tile_map.phy_tile_pkey
FROM tile_map
INNER JOIN phy_tile
ON phy_tile.pkey = tile_map.phy_tile_pkey
WHERE tile_map.tile_pkey IN (
SELECT pkey FROM tile WHERE tile_type_pkey = ?
)
GROUP BY phy_tile.tile_type_pkey;""", (tile_type_pkey, )
)
# Set of node pkeys to expand
cur.execute(
"""
SELECT DISTINCT node_pkey
FROM wire
WHERE phy_tile_pkey IN (SELECT phy_tile_pkey FROM phy_tiles);"""
)
nodes_to_expand = set(node_pkey for (node_pkey, ) in cur)
nodes_to_set = {}
while len(nodes_to_expand) > 0:
node_pkey = nodes_to_expand.pop()
node_set = nodes_to_set.get(node_pkey, set((node_pkey, )))
nodes_to_set[node_pkey] = node_set
cur.execute(
"""
WITH
other_wires(phy_tile_pkey, pip_in_tile_pkey, other_wire_in_tile_pkey) AS (
SELECT
wire.phy_tile_pkey,
undirected_pips.pip_in_tile_pkey,
undirected_pips.other_wire_in_tile_pkey
FROM undirected_pips
INNER JOIN wire
ON wire.wire_in_tile_pkey = undirected_pips.wire_in_tile_pkey
INNER JOIN pip_in_tile
ON pip_in_tile.pkey = undirected_pips.pip_in_tile_pkey
WHERE
wire.node_pkey = ?
AND
NOT pip_in_tile.is_pseudo
)
SELECT wire.node_pkey
FROM wire
INNER JOIN other_wires
ON
wire.wire_in_tile_pkey = other_wires.other_wire_in_tile_pkey
AND
wire.phy_tile_pkey = other_wires.phy_tile_pkey
WHERE
wire.phy_tile_pkey IN (SELECT phy_tile_pkey FROM phy_tiles);""",
(node_pkey, )
)
# Update node sets
for (other_node_pkey, ) in cur:
node_set |= nodes_to_set.get(
other_node_pkey, set((other_node_pkey, ))
)
# Merge node sets
for node_pkey in node_set:
nodes_to_set[node_pkey] = node_set
unique_node_sets = {}
for node_set in nodes_to_set.values():
if id(node_set) not in unique_node_sets:
unique_node_sets[id(node_set)] = node_set
if False:
# Print node sets for debugging and inspection.
for node_set in unique_node_sets.values():
print()
print(id(node_set), len(node_set))
for node_pkey in node_set:
cur.execute(
"""
SELECT name
FROM wire_in_tile
WHERE pkey IN (
SELECT wire.wire_in_tile_pkey
FROM wire
WHERE node_pkey = ?
)""", (node_pkey, )
)
print(node_pkey, ' '.join(name for (name, ) in cur))
cur.execute("""DROP TABLE phy_tiles""")
return unique_node_sets.values()
def find_connections(conn, input_wires, output_wires, tile_type_pkey):
""" Remove top-level ports only connected to internal sources and generates
tile internal connections."""
# Create connected node sets
node_sets = list(expand_nodes_in_tile_type(conn, tile_type_pkey))
# Number of site external connections for ports
is_top_level_pin_external = {}
for wire in input_wires:
is_top_level_pin_external[wire] = False
for wire in output_wires:
is_top_level_pin_external[wire] = False
internal_connections = {}
top_level_connections = {}
wire_to_site_pin = {}
cur = conn.cursor()
for node_set in node_sets:
ipin_count = 0
opin_count = 0
node_set_has_external = False
pins_used_in_node_sets = set()
input_pins = set()
output_pins = set()
for node_pkey in node_set:
cur.execute(
"""
SELECT
tile.tile_type_pkey,
wire_in_tile.name,
site_type.name,
site_pin.name,
site_pin.direction,
count()
FROM wire
INNER JOIN wire_in_tile
ON wire.wire_in_tile_pkey = wire_in_tile.pkey
INNER JOIN site_pin
ON site_pin.pkey = wire_in_tile.site_pin_pkey
INNER JOIN tile
ON wire.tile_pkey = tile.pkey
INNER JOIN site_type
ON site_type.pkey = site_pin.site_type_pkey
WHERE
wire.node_pkey = ?
AND
wire_in_tile.site_pin_pkey IS NOT NULL
GROUP BY site_pin.direction;
""", (node_pkey, )
)
for (wire_tile_type_pkey, wire_name, site_type_name, site_pin_name,
direction, count) in cur:
if wire_tile_type_pkey == tile_type_pkey:
value = (site_type_name, site_pin_name)
if wire_name in wire_to_site_pin:
assert value == wire_to_site_pin[wire_name], (
wire_name, value, wire_to_site_pin[wire_name]
)
else:
wire_to_site_pin[wire_name] = value
pins_used_in_node_sets.add(wire_name)
direction = prjxray.site_type.SitePinDirection(direction)
if direction == prjxray.site_type.SitePinDirection.IN:
output_pins.add(wire_name)
opin_count += count
elif direction == prjxray.site_type.SitePinDirection.OUT:
input_pins.add(wire_name)
ipin_count += count
else:
assert False, (node_pkey, direction)
else:
node_set_has_external = True
assert len(input_pins) in [0, 1], input_pins
if ipin_count == 0 or opin_count == 0 or node_set_has_external:
# This node set is connected externally, mark as such
for wire_name in pins_used_in_node_sets:
is_top_level_pin_external[wire_name] = True
if ipin_count > 0 and opin_count > 0:
# TODO: Add check that pips and site pins on these internal
# connections are 0 delay.
assert len(input_pins) == 1
input_wire = input_pins.pop()
for wire_name in output_pins:
if wire_name in internal_connections:
assert input_wire == internal_connections[wire_name]
else:
internal_connections[wire_name] = input_wire
for wire in sorted(is_top_level_pin_external):
if not is_top_level_pin_external[wire]:
if wire in input_wires:
input_wires.remove(wire)
elif wire in output_wires:
output_wires.remove(wire)
else:
assert False, wire
else:
top_level_connections[wire] = wire_to_site_pin[wire]
output_internal_connections = {}
for output_wire in internal_connections:
output_internal_connections[wire_to_site_pin[output_wire]] = \
wire_to_site_pin[internal_connections[output_wire]]
return top_level_connections, output_internal_connections
NORMALIZED_TILE_TYPES = {
"RIOI3": "IOI3_TILE",
"RIOI3_SING": "IOI3_TILE",
"RIOI3_TBYTESRC": "IOI3_TILE",
"RIOI3_TBYTETERM": "IOI3_TILE",
"LIOI3": "IOI3_TILE",
"LIOI3_SING": "IOI3_TILE",
"LIOI3_TBYTESRC": "IOI3_TILE",
"LIOI3_TBYTETERM": "IOI3_TILE",
"LIOB33": "IOB_TILE",
"LIOB33_SING": "IOB_TILE",
"RIOB33": "IOB_TILE",
"RIOB33_SING": "IOB_TILE",
"CMT_TOP_R_UPPER_T": "CMT_TOP_UPPER_T",
"CMT_TOP_L_UPPER_T": "CMT_TOP_UPPER_T",
}
NORMALIZED_SITE_TYPES = {
"IOB33M": "IOB",
"IOB33S": "IOB",
"IOB33": "IOB",
"ILOGICE3": "ILOGIC",
"OLOGICE3": "OLOGIC",
"IDELAYE2": "IDELAY",
}
def get_tile_prefixes(conn, tile_type_pkeys, site_types, site_remap):
cur = conn.cursor()
tile_prefixes = {}
for tile_type_pkey in tile_type_pkeys:
cur.execute(
"""
SELECT
DISTINCT tile_type.name, site_type.pkey, site_type.name
FROM
wire_in_tile
INNER JOIN tile_type ON tile_type.pkey = wire_in_tile.phy_tile_type_pkey
INNER JOIN site ON site.pkey = wire_in_tile.site_pkey
INNER JOIN site_type ON site_type.pkey = site.site_type_pkey
WHERE
wire_in_tile.tile_type_pkey = ?
AND site_pin_pkey IS NOT NULL;
""", (tile_type_pkey, )
)
for tile_type_name, site_type_pkey, site_type_name in cur:
norm_tile = NORMALIZED_TILE_TYPES.get(
tile_type_name, tile_type_name
)
if site_type_pkey not in site_types:
new_site_type_pkey = site_remap[site_type_pkey]
assert new_site_type_pkey in site_types
site_type_pkey = new_site_type_pkey
norm_site = NORMALIZED_SITE_TYPES.get(
site_type_name, site_type_name
)
prefix = '{' + norm_tile + '}.{' + norm_site + '}'
if site_type_pkey in tile_prefixes:
assert prefix == tile_prefixes[site_type_pkey], (
prefix, tile_prefixes[site_type_pkey]
)
else:
tile_prefixes[site_type_pkey] = prefix
return tile_prefixes
def sites_in_tile_type(conn, tile_type_pkey):
cur = conn.cursor()
# Find instances of sites, sorted by their original tile type.
# Then choice the first of each site type as the wire set.
# This ensures a unique and internally consistent site set for analyzing
# connectivity.
#
# Note: This does assume that only one instance of each site is present
# in each tile, which is checked.
sites = {}
sites_in_tiles = set()
cur.execute(
"""
SELECT
site.site_type_pkey, wire_in_tile.site_pkey, wire_in_tile.phy_tile_type_pkey
FROM wire_in_tile
INNER JOIN site
ON site.pkey = wire_in_tile.site_pkey
WHERE
wire_in_tile.tile_type_pkey = ?
GROUP BY site.site_type_pkey, wire_in_tile.phy_tile_type_pkey
ORDER BY wire_in_tile.phy_tile_type_pkey;""", (tile_type_pkey, )
)
for site_type_pkey, site_pkey, phy_tile_type_pkey in cur:
if site_type_pkey not in sites:
sites[site_type_pkey] = site_pkey
# Verify that assumption that each site type is only used once per tile
# is true.
key = (site_type_pkey, phy_tile_type_pkey)
assert key not in sites_in_tiles, key
sites_in_tiles.add(key)
return sites, sites_in_tiles
def yield_mapped_site_sets(site_remaps, site_type_pkeys):
yield frozenset(
site_remaps.get(site_type_pkey, site_type_pkey)
for site_type_pkey in site_type_pkeys
)
def check_site_equiv(conn, general_site_type_pkey, specific_site_type_pkey):
""" Verify assumption that site pin names on specific site are subset of general site.
E.g. every pin on the specific site should be present on the generic site.
"""
cur = conn.cursor()
cur.execute(
"SELECT name FROM site_pin WHERE site_type_pkey = ?",
(general_site_type_pkey, )
)
general_site_pins = set(name for (name, ) in cur)
cur.execute(
"SELECT name FROM site_pin WHERE site_type_pkey = ?",
(specific_site_type_pkey, )
)
for (name, ) in cur:
assert name in general_site_pins, (
general_site_pins, name, specific_site_type_pkey
)
def create_pb_type(
conn, pin_assignments, site_directory, output_directory, pb_type,
site_type_pkeys, tile_type_pkeys, site_remaps, site_name_remaps,
node_tile_map
):
cur = conn.cursor()
cur2 = conn.cursor()
wire_to_site_pin = {}
internal_connections = {}
top_level_pin_external = set()
top_level_wire_external = set()
all_pb_type_input_pins = None
all_pb_type_output_pins = None
for tile_type_pkey in tile_type_pkeys:
pb_type_input_pins = set()
pb_type_output_pins = set()
for node_set in node_tile_map[tile_type_pkey]:
ipin_count = 0
opin_count = 0
node_set_has_external = False
pins_used_in_node_sets = set()
input_pins = set()
output_pins = set()
for node_pkey in node_set:
cur.execute(
"""
SELECT
tile.tile_type_pkey,
wire_in_tile.name,
site_type.pkey,
site_type.name,
site_pin.name,
site_pin.direction,
count()
FROM wire
INNER JOIN wire_in_tile
ON wire.wire_in_tile_pkey = wire_in_tile.pkey
INNER JOIN site_pin
ON site_pin.pkey = wire_in_tile.site_pin_pkey
INNER JOIN tile
ON wire.tile_pkey = tile.pkey
INNER JOIN site_type
ON site_type.pkey = site_pin.site_type_pkey
WHERE
wire.node_pkey = ?
AND
wire_in_tile.site_pin_pkey IS NOT NULL
GROUP BY site_pin.direction;
""", (node_pkey, )
)
for (wire_tile_type_pkey, wire_name, site_type_pkey,
site_type_name, site_pin_name, direction, count) in cur:
if wire_tile_type_pkey == tile_type_pkey:
if site_type_pkey not in site_type_pkeys:
# Remap if a mapping exists
site_type_name = site_name_remaps.get(
site_type_name, site_type_name
)
cur2.execute(
"SELECT pkey FROM site_type WHERE name = ?",
(site_type_name, )
)
new_site_type_pkey = cur2.fetchone()[0]
assert new_site_type_pkey in site_type_pkeys, (
pb_type, tile_type_pkey, node_pkey,
site_type_pkey, new_site_type_pkey,
site_type_pkeys, site_type_name
)
direction = prjxray.site_type.SitePinDirection(
direction
)
value = (site_type_name, site_pin_name, direction)
if wire_name in wire_to_site_pin:
assert value == wire_to_site_pin[wire_name], (
wire_name, value, wire_to_site_pin[wire_name]
)
else:
wire_to_site_pin[wire_name] = value
pins_used_in_node_sets.add(
(wire_name, site_type_name, site_pin_name)
)
if direction == prjxray.site_type.SitePinDirection.IN:
output_pins.add(wire_name)
pb_type_output_pins.add(
(site_type_name, site_pin_name)
)
opin_count += count
elif direction == prjxray.site_type.SitePinDirection.OUT:
input_pins.add(wire_name)
pb_type_input_pins.add(
(site_type_name, site_pin_name)
)
ipin_count += count
else:
assert False, (node_pkey, direction)
else:
node_set_has_external = True
assert len(input_pins) in [0, 1], input_pins
if ipin_count == 0 or opin_count == 0 or node_set_has_external or len(
site_type_pkeys) == 1:
# This node set is connected externally, mark as such
for wire_name, site_type_name, site_pin_name in pins_used_in_node_sets:
top_level_wire_external.add(wire_name)
top_level_pin_external.add((site_type_name, site_pin_name))
if len(site_type_pkeys) == 1:
continue
if ipin_count > 0 and opin_count > 0:
# TODO: Add check that pips and site pins on these internal
# connections are 0 delay.
assert len(input_pins) == 1
input_wire = input_pins.pop()
for wire_name in output_pins:
k = wire_to_site_pin[wire_name]
v = wire_to_site_pin[input_wire]
if k in internal_connections:
assert v == internal_connections[k], (
v, internal_connections[k]
)
else:
internal_connections[k] = v
pb_type_input_pins = set(
v for v in pb_type_input_pins if v in top_level_pin_external
)
pb_type_output_pins = set(
v for v in pb_type_output_pins if v in top_level_pin_external
)
if all_pb_type_input_pins is None:
all_pb_type_input_pins = pb_type_input_pins
all_pb_type_output_pins = pb_type_output_pins
else:
all_pb_type_input_pins &= pb_type_input_pins
all_pb_type_output_pins &= pb_type_output_pins
##########################################################################
# Generate the model.xml file #
##########################################################################
model = ModelXml(
f=os.path.join(
output_directory, pb_type.lower(),
'{}.model.xml'.format(pb_type.lower())
),
site_directory=site_directory
)
for site_type_pkey in site_type_pkeys:
cur.execute(
"SELECT name FROM site_type WHERE pkey = ?", (site_type_pkey, )
)
site_type = cur.fetchone()[0]
model.add_model_include(site_type, site_type)
model.write_model()
##########################################################################
# Generate the pb_type.xml file #
##########################################################################
pb_type_xml = start_pb_type(
pb_type,
pin_assignments,
['{}_{}'.format(site, pin) for site, pin in all_pb_type_output_pins],
['{}_{}'.format(site, pin) for site, pin in all_pb_type_input_pins],
)
interconnect_xml = ET.Element('interconnect')
site_pbtype = site_directory + "/{0}/{1}.pb_type.xml"
site_prefixes = get_tile_prefixes(
conn, tile_type_pkeys, site_type_pkeys, site_remaps
)
cell_names = {}
site_type_ports = {}
for site_type_pkey in site_type_pkeys:
cur.execute(
"SELECT name FROM site_type WHERE pkey = ?", (site_type_pkey, )
)
site_type = cur.fetchone()[0]
site_prefix = site_prefixes[site_type_pkey]
site_type_path = site_pbtype.format(
site_type.lower(), site_type.lower()
)
cell_pb_type = ET.ElementTree()
root_element = cell_pb_type.parse(site_type_path)
cell_names[site_type] = root_element.attrib['name']
ports = {}
for inputs in root_element.iter('input'):
ports[inputs.attrib['name']] = int(inputs.attrib['num_pins'])
for clocks in root_element.iter('clock'):
ports[clocks.attrib['name']] = int(clocks.attrib['num_pins'])
for outputs in root_element.iter('output'):
ports[outputs.attrib['name']] = int(outputs.attrib['num_pins'])
assert site_type not in site_type_ports, (
site_type, site_type_ports.keys()
)
site_type_ports[site_type] = ports
attrib = dict(root_element.attrib)
include_xml = ET.SubElement(pb_type_xml, 'pb_type', attrib)
ET.SubElement(
include_xml, XI_INCLUDE, {
'href':
site_type_path,
'xpointer':
"xpointer(pb_type/child::node()[local-name()!='metadata'])",
}
)
metadata_xml = ET.SubElement(include_xml, 'metadata')
if len(site_type_pkeys) > 1:
ET.SubElement(
metadata_xml, 'meta', {
'name': 'fasm_prefix',
}
).text = site_prefix
# Import pb_type metadata if it exists.
if any(child.tag == 'metadata' for child in root_element):
ET.SubElement(
metadata_xml, XI_INCLUDE, {
'href': site_type_path,
'xpointer': "xpointer(pb_type/metadata/child::node())",
}
)
for site_type, site_pin_name in top_level_pin_external:
port = find_port(site_pin_name, site_type_ports[site_type])
if port is None:
print(
"*** WARNING *** Didn't find port for name {} for site type {}"
.format(site_pin_name, site_type),
file=sys.stderr
)
continue
site_name = cell_names[site_type]
is_input = (site_type, site_pin_name) in all_pb_type_input_pins
is_output = (site_type, site_pin_name) in all_pb_type_output_pins
if not is_input and not is_output:
continue
if is_input:
add_direct(
interconnect_xml,
input=object_ref(site_name, **port),
output=object_ref(
add_vpr_tile_prefix(pb_type),
'{}_{}'.format(site_type, site_pin_name),
),
)
for site_type, site_pin_name in top_level_pin_external:
port = find_port(site_pin_name, site_type_ports[site_type])
if port is None:
continue
site_name = cell_names[site_type]
is_input = (site_type, site_pin_name) in all_pb_type_input_pins
is_output = (site_type, site_pin_name) in all_pb_type_output_pins
if not is_input and not is_output:
continue
if is_output:
add_direct(
interconnect_xml,
input=object_ref(
add_vpr_tile_prefix(pb_type),
'{}_{}'.format(site_type, site_pin_name)
),
output=object_ref(site_name, **port),
)
for (dest_site_type, dest_site_pin_name, _), (src_site_type, src_site_pin_name, _) in \
sorted(internal_connections.items(), key=lambda x: (x[1], x[0])):
src_port = find_port(src_site_pin_name, site_type_ports[src_site_type])
src_site_name = cell_names[src_site_type]
if src_port is None:
print(
"*** WARNING *** Didn't find port for name {} for site type {}"
.format(src_site_pin_name, src_site_type),
file=sys.stderr
)
continue
dest_port = find_port(
dest_site_pin_name, site_type_ports[dest_site_type]
)
dest_site_name = cell_names[dest_site_type]
if dest_port is None:
print(
"*** WARNING *** Didn't find port for name {} for site type {}"
.format(dest_site_pin_name, dest_site_type),
file=sys.stderr
)
continue
add_direct(
interconnect_xml,
input=object_ref(src_site_name, **src_port),
output=object_ref(dest_site_name, **dest_port),
)
pb_type_xml.append(interconnect_xml)
write_xml(
os.path.join(
output_directory, pb_type.lower(),
'{}.pb_type.xml'.format(pb_type.lower())
), pb_type_xml
)
top_level_connections = {}
for wire in sorted(top_level_wire_external):
site_type, site_pin_name, _ = wire_to_site_pin[wire]
is_input = (site_type, site_pin_name) in all_pb_type_input_pins
is_output = (site_type, site_pin_name) in all_pb_type_output_pins
if not is_input and not is_output:
continue
top_level_connections[wire] = wire_to_site_pin[wire]
return top_level_connections
def create_tile(
conn, tile_type, tile_type_pkey, tile_connections, pb_types,
pin_assignments, output_directory
):
cur = conn.cursor()
input_wires = set()
output_wires = set()
cur.execute(
"""
SELECT DISTINCT wire_in_tile.name
FROM wire_in_tile
WHERE
wire_in_tile.tile_type_pkey = ?
AND
wire_in_tile.site_pin_pkey IS NOT NULL;
""", (tile_type_pkey, )
)
for (wire_name, ) in cur:
for pb_type in pb_types:
if wire_name in tile_connections[pb_type]:
site_type_name, site_pin_name, direction = tile_connections[
pb_type][wire_name]
if direction == prjxray.site_type.SitePinDirection.IN:
input_wires.add(wire_name)
elif direction == prjxray.site_type.SitePinDirection.OUT:
output_wires.add(wire_name)
else:
assert False, (wire_name, direction)
tile_xml = start_tile(
tile_type,
pin_assignments,
input_wires,
output_wires,
)
equivalent_sites_xml = ET.Element('equivalent_sites')
for pb_type in pb_types:
site_xml = ET.Element(
'site', {
'pb_type': add_vpr_tile_prefix(pb_type),
'pin_mapping': 'custom'
}
)
equivalent_sites_xml.append(site_xml)
for wire_name in input_wires | output_wires:
if wire_name in tile_connections[pb_type]:
site_type_name, site_pin_name, direction = tile_connections[
pb_type][wire_name]
add_tile_direct(
site_xml,
tile=object_ref(
add_vpr_tile_prefix(tile_type),
wire_name,
),
pb_type=object_ref(
add_vpr_tile_prefix(pb_type),
'{}_{}'.format(site_type_name, site_pin_name)
),
)
sub_tile_xml = tile_xml.find('./sub_tile')
sub_tile_xml.append(equivalent_sites_xml)
add_switchblock_locations(tile_xml)
write_xml(
os.path.join(
output_directory, tile_type.lower(),
'{}.tile.xml'.format(tile_type.lower())
), tile_xml
)
def main():
parser = argparse.ArgumentParser(
description=__doc__, fromfile_prefix_chars='@', prefix_chars='-~'
)
parser.add_argument(
'--site_directory',
required=True,
help="""Diretory where sites are defined"""
)
parser.add_argument(
'--output_directory',
required=True,
help="Directory to write output XML too.",
)
parser.add_argument(
'--pin_assignments',
required=True,
)
parser.add_argument(
'--connection_database',
required=True,
help=(
"Location of connection database to define this tile type. " +
"The tile will be defined by the sites and wires from the " +
"connection database in lue of Project X-Ray."
)
)
parser.add_argument(
'--tile_types',
required=True,
help="Comma seperated list of tiles to create equivilance between."
)
parser.add_argument('--pb_types', nargs='+', required=True, help="")
parser.add_argument(
'--site_equivilances',
help="Comma seperated list of site equivilances to apply."
)
args = parser.parse_args()
with open(args.pin_assignments) as f:
pin_assignments = json.load(f)
ET.register_namespace('xi', XI_URL)
with sqlite3.connect("file:{}?mode=ro".format(args.connection_database),
uri=True) as conn:
cur = conn.cursor()
tile_types = {}
node_tile_map = {}
sites = {}
sites_in_tiles = {}
pb_types = {}
site_remaps = {}
site_name_remaps = {}
if args.site_equivilances is not None:
for site_remap in args.site_equivilances.split(','):
general_site, specific_site = site_remap.split('=')
assert general_site not in site_name_remaps, general_site
site_name_remaps[general_site] = specific_site
cur.execute(
"SELECT pkey FROM site_type WHERE name = ?",
(general_site, )
)
general_site_type_pkey = cur.fetchone()[0]
cur.execute(
"SELECT pkey FROM site_type WHERE name = ?",
(specific_site, )
)
specific_site_type_pkey = cur.fetchone()[0]
site_remaps[general_site_type_pkey] = specific_site_type_pkey
check_site_equiv(
conn, general_site_type_pkey, specific_site_type_pkey
)
site_collections_to_pb_type = {}
for pb_type_def_string in args.pb_types:
pb_type_name, pb_type_sites = pb_type_def_string.split('=')
pb_type_sites = pb_type_sites.split(',')
assert pb_type_name not in pb_types, pb_type_name
pb_types[pb_type_name] = []
for site in pb_type_sites:
cur.execute(
"SELECT pkey FROM site_type WHERE name = ?", (site, )
)
result = cur.fetchone()
assert result is not None, site
site_type_pkey = result[0]
pb_types[pb_type_name].append(site_type_pkey)
pb_types[pb_type_name] = frozenset(pb_types[pb_type_name])
assert pb_types[pb_type_name] not in site_collections_to_pb_type, (
pb_type_name, pb_types[pb_type_name]
)
site_collections_to_pb_type[pb_types[pb_type_name]] = pb_type_name
pb_types_in_tile = {}
tiles_that_instance_pb_type = {}
for tile_type in args.tile_types.split(','):
cur.execute(
"SELECT pkey FROM tile_type WHERE name = ?", (tile_type, )
)
tile_type_pkey = cur.fetchone()[0]
tile_types[tile_type] = tile_type_pkey
node_tile_map[tile_type_pkey] = expand_nodes_in_tile_type(
conn, tile_type_pkey
)
sites[tile_type_pkey], sites_in_tiles[
tile_type_pkey] = sites_in_tile_type(conn, tile_type_pkey)
seen_sets = set()
site_type_pkeys = frozenset(sites[tile_type_pkey].keys())
seen_sets.add(site_type_pkeys)
pb_types_in_tile[tile_type_pkey] = [
site_collections_to_pb_type[site_type_pkeys]
]
for site_set in yield_mapped_site_sets(site_remaps,
site_type_pkeys):
if site_set in seen_sets:
continue
pb_types_in_tile[tile_type_pkey].append(
site_collections_to_pb_type[site_set]
)
for pb_type in pb_types_in_tile[tile_type_pkey]:
if pb_type not in tiles_that_instance_pb_type:
tiles_that_instance_pb_type[pb_type] = []
tiles_that_instance_pb_type[pb_type].append(tile_type_pkey)
tile_connections = {}
for pb_type in tiles_that_instance_pb_type:
tile_connections[pb_type] = create_pb_type(
conn=conn,
pin_assignments=pin_assignments,
site_directory=args.site_directory,
output_directory=args.output_directory,
pb_type=pb_type,
site_type_pkeys=pb_types[pb_type],
tile_type_pkeys=tiles_that_instance_pb_type[pb_type],
site_remaps=site_remaps,
site_name_remaps=site_name_remaps,
node_tile_map=node_tile_map
)
for tile_type in tile_types:
tile_type_pkey = tile_types[tile_type]
create_tile(
conn=conn,
tile_type=tile_type,
tile_type_pkey=tile_type_pkey,
tile_connections=tile_connections,
pb_types=pb_types_in_tile[tile_type_pkey],
output_directory=args.output_directory,
pin_assignments=pin_assignments,
)
if __name__ == '__main__':
main()