| #! /usr/bin/env python3 | |
| """ Tool generate a pin map CSV from channels.db and a *_package_pins.csv for pin placement. """ | |
| from __future__ import print_function | |
| import argparse | |
| import sys | |
| import csv | |
| import sqlite3 | |
| import json | |
| def get_vpr_coords_from_site_name(conn, site_name): | |
| cur = conn.cursor() | |
| cur.execute( | |
| """ | |
| SELECT DISTINCT tile.grid_x, tile.grid_y | |
| FROM site_instance | |
| INNER JOIN wire_in_tile | |
| ON | |
| site_instance.site_pkey = wire_in_tile.site_pkey | |
| INNER JOIN wire | |
| ON | |
| wire.phy_tile_pkey = site_instance.phy_tile_pkey | |
| AND | |
| wire_in_tile.pkey = wire.wire_in_tile_pkey | |
| INNER JOIN tile | |
| ON tile.pkey = wire.tile_pkey | |
| WHERE | |
| site_instance.name = ?;""", (site_name, ) | |
| ) | |
| results = cur.fetchall() | |
| if len(results) == 1: | |
| return results[0] | |
| def get_sites_at_tilename(conn, tile_name): | |
| """ | |
| Returns a list of sites and a dictionary of site_name to site_type that are present | |
| in a given tile. | |
| """ | |
| cur = conn.cursor() | |
| cur.execute( | |
| """ | |
| SELECT site_type.name, site_instance.name, site_instance.x_coord, site_instance.y_coord | |
| FROM site_instance | |
| INNER JOIN site ON site_instance.site_pkey = site.pkey | |
| INNER JOIN site_type ON site.site_type_pkey = site_type.pkey | |
| WHERE site_instance.phy_tile_pkey IN ( | |
| SELECT | |
| pkey | |
| FROM | |
| phy_tile | |
| WHERE | |
| name = ? | |
| ) | |
| ORDER BY site_type.name, site_instance.x_coord, site_instance.y_coord;""", | |
| (tile_name, ) | |
| ) | |
| site_instances = dict() | |
| sites = list() | |
| for site_type, site_instance, _, _ in cur: | |
| site_instances[site_instance] = site_type | |
| sites.append(site_instance) | |
| return sites, site_instances | |
| def main(): | |
| parser = argparse.ArgumentParser(description='Creates a pin map CSV.') | |
| parser.add_argument( | |
| "--output", | |
| type=argparse.FileType('w'), | |
| default=sys.stdout, | |
| help='The output pin map CSV file' | |
| ) | |
| parser.add_argument( | |
| '--connection_database', | |
| help='Database of fabric connectivity', | |
| required=True | |
| ) | |
| parser.add_argument( | |
| "--synth_tiles", | |
| type=argparse.FileType('r'), | |
| required=False, | |
| help='Pin map synth_tiles JSON file' | |
| ) | |
| parser.add_argument( | |
| "--overlay", | |
| action='store_true', | |
| required=False, | |
| help='Whether the pin map should contain a mix of real and synth IOs' | |
| ) | |
| parser.add_argument( | |
| "--package_pins", | |
| type=argparse.FileType('r'), | |
| required=True, | |
| help='Map listing relationship between pads and sites.' | |
| ) | |
| args = parser.parse_args() | |
| CAPACITY_IOS = ["IPAD", "OPAD"] | |
| pin_to_iob = {} | |
| with sqlite3.connect(args.connection_database) as conn: | |
| for line in csv.DictReader(args.package_pins): | |
| pin = line['pin'] | |
| assert line['pin'] not in pin_to_iob | |
| site = line['site'] | |
| tile = line['tile'] | |
| loc = get_vpr_coords_from_site_name(conn, site) | |
| if loc is None: | |
| continue | |
| sites, site_instances = get_sites_at_tilename(conn, tile) | |
| if site_instances[site] in CAPACITY_IOS: | |
| z_loc = sites.index(site) | |
| else: | |
| z_loc = 0 | |
| loc = loc + (z_loc, ) | |
| pin_to_iob[pin] = (site, loc) | |
| args.package_pins.seek(0) | |
| if args.synth_tiles: | |
| synth_tiles = json.load(args.synth_tiles) | |
| fieldnames = [ | |
| 'name', 'x', 'y', 'z', 'is_clock', 'is_input', 'is_output', 'iob', | |
| 'real_io_assoc' | |
| ] | |
| writer = csv.DictWriter(args.output, fieldnames=fieldnames) | |
| writer.writeheader() | |
| synth_tile_pads = set() | |
| if args.synth_tiles: | |
| for synth_tile in synth_tiles['tiles'].values(): | |
| for pin in synth_tile['pins']: | |
| assert pin['pad'] not in synth_tile_pads, pin['pad'] | |
| synth_tile_pads.add(pin['pad']) | |
| real_io_assoc = pin['pad'] in pin_to_iob | |
| x = synth_tile['loc'][0] | |
| y = synth_tile['loc'][1] | |
| z = pin['z_loc'] | |
| writer.writerow( | |
| dict( | |
| name=pin['pad'], | |
| x=x, | |
| y=y, | |
| z=z, | |
| is_clock=1 if pin['is_clock'] else 0, | |
| is_input=0 if pin['port_type'] == 'input' else 1, | |
| is_output=0 if pin['port_type'] == 'output' else 1, | |
| iob=pin_to_iob[pin['pad']][0] if real_io_assoc else '', | |
| real_io_assoc=real_io_assoc, | |
| ) | |
| ) | |
| if not args.synth_tiles or args.overlay: | |
| for line in csv.DictReader(args.package_pins): | |
| # Skip PS7 MIO and DDR pads as they are not routable | |
| if line['tile'].startswith('PSS'): | |
| continue | |
| if line['pin'] in synth_tile_pads: | |
| continue | |
| loc = pin_to_iob[line['pin']][1] | |
| if loc is not None: | |
| z = 0 if len(loc) == 2 else loc[2] | |
| writer.writerow( | |
| dict( | |
| name=line['pin'], | |
| x=loc[0], | |
| y=loc[1], | |
| z=loc[2], | |
| is_clock=1, | |
| is_input=1, | |
| is_output=1, | |
| iob=line['site'], | |
| real_io_assoc='True', | |
| ) | |
| ) | |
| if __name__ == '__main__': | |
| main() |