blob: 01c6fdbe0deee93ecad8773ef3d0269fdff9f698 [file] [log] [blame]
import argparse
import prjxray.db
from prjxray.roi import Roi
import simplejson as json
from prjxray_db_cache import DatabaseCache
def map_tile_to_vpr_coord(conn, tile):
""" Converts prjxray tile name into VPR tile coordinates.
It is assumed that this tile should only have one mapped tile.
"""
c = conn.cursor()
c.execute("SELECT pkey FROM phy_tile WHERE name = ?;", (tile, ))
phy_tile_pkey = c.fetchone()[0]
# Filters NULL tiles to prevent selecting two tiles that point
# to the same phy_tile
c.execute(
"""
SELECT tile_map.tile_pkey FROM tile_map INNER JOIN tile
ON tile_map.tile_pkey = tile.pkey INNER JOIN tile_type
ON tile.tile_type_pkey = tile_type.pkey
WHERE tile_map.phy_tile_pkey = ? AND tile_type.name != 'NULL'
""", (phy_tile_pkey, )
)
mapped_tiles = c.fetchall()
assert len(mapped_tiles) == 1, tile
tile_pkey = mapped_tiles[0][0]
c.execute("SELECT grid_x, grid_y FROM tile WHERE pkey = ?", (tile_pkey, ))
grid_x, grid_y = c.fetchone()
return grid_x, grid_y
def tile_in_roi(conn, g, roi, tile_pkey):
"""
Checks if the given tile_pkey is at a location within the specified roi
"""
c = conn.cursor()
c.execute(
"""
SELECT name FROM phy_tile WHERE pkey =
(SELECT phy_tile_pkey FROM tile WHERE pkey = ?)
""", (tile_pkey, )
)
tile, = c.fetchone()
loc = g.loc_of_tilename(tile)
return roi.tile_in_roi(loc)
def wire_in_roi(conn, g, roi, wire_pkey):
"""
Checks if the given wire_pkey is at a location within the specified roi
"""
c = conn.cursor()
c.execute("""
SELECT tile_pkey FROM wire WHERE pkey = ?
""", (wire_pkey, ))
tile_pkey, = c.fetchone()
return tile_in_roi(conn, g, roi, tile_pkey)
def wire_manhattan_distance(conn, wire_pkey1, wire_pkey2):
"""
Determines the manhattan distance between two tiles containing
the given wire_pkeys
"""
c = conn.cursor()
c.execute(
"""
SELECT grid_x, grid_y FROM tile WHERE pkey = (SELECT tile_pkey FROM wire WHERE pkey = ?)
""", (wire_pkey1, )
)
x1, y1 = c.fetchone()
c.execute(
"""
SELECT grid_x, grid_y FROM tile WHERE pkey = (SELECT tile_pkey FROM wire WHERE pkey = ?)
""", (wire_pkey2, )
)
x2, y2 = c.fetchone()
return abs(x1 - x2) + abs(y1 - y2)
def find_wire_from_node(conn, g, roi, node_name, overlay=False):
"""
Finds a pair on wires in the given node such that:
1. One wire is inside the roi and the other is outside
2. The manhattan distance between these the wires is the minimum of any such pair
Returns the wire from this pair that is outside the roi and the tile the returned
wire is contained in.
"""
tile, node = node_name.split('/')
cur = conn.cursor()
cur.execute(
"""
SELECT pkey, node_pkey FROM wire WHERE
wire_in_tile_pkey IN (SELECT pkey FROM wire_in_tile WHERE name = ?)
AND
phy_tile_pkey = (SELECT pkey FROM phy_tile WHERE name = ?)
""", (node, tile)
)
results = cur.fetchall()
assert len(results) == 1
wire_pkey, node_pkey = results[0]
cur.execute(
"""
SELECT pkey FROM wire WHERE node_pkey = ?
""", (node_pkey, )
)
wire_pkeys = cur.fetchall()
in_outs = {
w: (overlay ^ wire_in_roi(conn, g, roi, w))
for w, in wire_pkeys
}
ins = {i for i, v in in_outs.items() if v}
outs = {i for i, v in in_outs.items() if not v}
min_manhattan_dist = 1000000
correct_wire = None
for i in ins:
for j in outs:
d = wire_manhattan_distance(conn, i, j)
if d < min_manhattan_dist:
min_manhattan_dist = d
correct_wire = j
assert correct_wire is not None, node_name
cur.execute(
"""
SELECT node_pkey, phy_tile_pkey, wire_in_tile_pkey FROM wire WHERE pkey = ?
""", (correct_wire, )
)
node_pkey_correct_wire, phy_tile_pkey, wire_in_tile_pkey = cur.fetchone()
cur.execute(
"""
SELECT name, tile_type_pkey FROM wire_in_tile WHERE pkey = ?
""", (wire_in_tile_pkey, )
)
wire, tile_type_pkey = cur.fetchone()
cur.execute(
"""
SELECT name FROM tile_type WHERE pkey = ?
""", (tile_type_pkey, )
)
tile_type, = cur.fetchone()
cur.execute(
"""
SELECT name FROM phy_tile WHERE pkey = ?
""", (phy_tile_pkey, )
)
tile, = cur.fetchone()
return tile, wire
def main():
parser = argparse.ArgumentParser(description="Generate synth_tiles.json")
parser.add_argument('--db_root', required=True)
parser.add_argument('--part', required=True)
parser.add_argument('--roi', required=False)
parser.add_argument('--overlay', required=False)
parser.add_argument(
'--connection_database', help='Connection database', required=True
)
parser.add_argument('--synth_tiles', required=True)
args = parser.parse_args()
db = prjxray.db.Database(args.db_root, args.part)
g = db.grid()
synth_tiles = {}
synth_tiles['tiles'] = {}
rois = dict()
if args.roi:
with open(args.roi) as f:
j = json.load(f)
synth_tiles['info'] = j['info']
roi = Roi(
db=db,
x1=j['info']['GRID_X_MIN'],
y1=j['info']['GRID_Y_MIN'],
x2=j['info']['GRID_X_MAX'],
y2=j['info']['GRID_Y_MAX'],
)
rois[roi] = j
elif args.overlay:
with open(args.overlay) as f:
j = json.load(f)
synth_tiles['info'] = list()
for r in j:
roi = Roi(
db=db,
x1=r['info']['GRID_X_MIN'],
y1=r['info']['GRID_Y_MIN'],
x2=r['info']['GRID_X_MAX'],
y2=r['info']['GRID_Y_MAX'],
)
rois[roi] = r
else:
assert False, 'Synth tiles must be for roi or overlay'
with DatabaseCache(args.connection_database, read_only=True) as conn:
tile_in_use = set()
num_synth_tiles = 0
for roi, j in rois.items():
if args.overlay:
synth_tiles['info'].append(j['info'])
tile_pin_count = dict()
for port in sorted(sorted(j['ports'], key=lambda i: i['name']),
key=lambda i: i['type'], reverse=bool(
args.overlay)):
if port['type'] == 'out':
port_type = 'input' if not args.overlay else 'output'
is_clock = False
elif port['type'] == 'in':
is_clock = False
port_type = 'output' if not args.overlay else 'input'
elif port['type'] == 'clk':
port_type = 'output' if not args.overlay else 'input'
is_clock = True
else:
assert False, port
if 'wire' not in port:
tile, wire = find_wire_from_node(
conn, g, roi, port['node'], overlay=bool(args.overlay)
)
else:
tile, wire = port['wire'].split('/')
tile_in_use.add(tile)
# Make sure connecting wire is not in ROI!
loc = g.loc_of_tilename(tile)
if bool(args.overlay) ^ roi.tile_in_roi(loc):
# Or if in the ROI, make sure it has no sites.
gridinfo = g.gridinfo_at_tilename(tile)
assert len(
db.get_tile_type(gridinfo.tile_type).get_sites()
) == 0, "{}/{}".format(tile, wire)
vpr_loc = map_tile_to_vpr_coord(conn, tile)
if tile not in synth_tiles['tiles']:
tile_name = 'SYN-IOPAD-{}'.format(num_synth_tiles)
synth_tiles['tiles'][tile] = {
'pins': [],
'loc': vpr_loc,
'tile_name': tile_name,
'wires_outside_roi': {},
}
num_synth_tiles += 1
tile_pin_count[tile] = 0
synth_tiles['tiles'][tile]['pins'].append(
{
'roi_name':
port['name'].replace('[', '_').replace(']', '_'),
'wire':
wire,
'pad':
port['pin'],
'port_type':
port_type,
'is_clock':
is_clock,
'z_loc':
tile_pin_count[tile],
}
)
if 'wires_outside_roi' in port:
outside_roi = synth_tiles['tiles'][tile
]['wires_outside_roi']
for tile_wire in port['wires_outside_roi']:
tile_name, wire_name = tile_wire.split('/')
if tile_name in outside_roi.keys():
outside_roi[tile_name].append(wire_name)
else:
outside_roi[tile_name] = [wire_name]
tile_pin_count[tile] += 1
if not args.overlay:
# Find two VBRK's in the corner of the fabric to use as the synthetic VCC/
# GND source.
vbrk_loc = None
vbrk_tile = None
vbrk2_loc = None
vbrk2_tile = None
for tile in g.tiles():
if tile in tile_in_use:
continue
loc = g.loc_of_tilename(tile)
if not roi.tile_in_roi(loc):
continue
gridinfo = g.gridinfo_at_tilename(tile)
if 'VBRK' not in gridinfo.tile_type:
continue
assert len(
db.get_tile_type(gridinfo.tile_type).get_sites()
) == 0, tile
if vbrk_loc is None:
vbrk2_loc = vbrk_loc
vbrk2_tile = vbrk_tile
vbrk_loc = loc
vbrk_tile = tile
else:
if (loc.grid_x < vbrk_loc.grid_x and
loc.grid_y < vbrk_loc.grid_y) or vbrk2_loc is None:
vbrk2_loc = vbrk_loc
vbrk2_tile = vbrk_tile
vbrk_loc = loc
vbrk_tile = tile
assert vbrk_loc is not None
assert vbrk_tile is not None
assert vbrk_tile not in synth_tiles['tiles']
vbrk_vpr_loc = map_tile_to_vpr_coord(conn, vbrk_tile)
synth_tiles['tiles'][vbrk_tile] = {
'loc':
vbrk_vpr_loc,
'pins':
[
{
'wire': 'VCC',
'pad': 'VCC',
'port_type': 'VCC',
'is_clock': False,
'z_loc': '0',
},
],
}
assert vbrk2_loc is not None
assert vbrk2_tile is not None
assert vbrk2_tile not in synth_tiles['tiles']
vbrk2_vpr_loc = map_tile_to_vpr_coord(conn, vbrk2_tile)
synth_tiles['tiles'][vbrk2_tile] = {
'loc':
vbrk2_vpr_loc,
'pins':
[
{
'wire': 'GND',
'pad': 'GND',
'port_type': 'GND',
'is_clock': False,
'z_loc': '0',
},
],
}
with open(args.synth_tiles, 'w') as f:
json.dump(synth_tiles, f, indent=2)
if __name__ == "__main__":
main()