def quick_test(db_root): db = prjxray.db.Database(db_root) g = db.grid() # Verify that we have some tile information for every tile in grid. tile_types_in_grid = set( g.gridinfo_at_loc(loc).tile_type for loc in g.tile_locations()) tile_types_in_db = set(db.get_tile_types()) site_types = set(db.get_site_types()) assert len(tile_types_in_grid - tile_types_in_db) == 0 # Verify that all tile types can be loaded. for tile_type in db.get_tile_types(): tile = db.get_tile_type(tile_type) wires = tile.get_wires() for site in tile.get_sites(): assert site.type in site_types site_type = db.get_site_type(site.type) site_pins = site_type.get_site_pins() for site_pin in site.site_pins: if site_pin.wire is not None: assert site_pin.wire in wires, (site_pin.wire, ) assert site_pin.name in site_pins for pip in tile.get_pips(): assert pip.net_to in wires assert pip.net_from in wires for loc in g.tile_locations(): gridinfo = g.gridinfo_at_loc(loc) assert gridinfo.tile_type in db.get_tile_types() for site_name, site_type in gridinfo.sites.items(): assert site_type in site_types tile = db.get_tile_type(gridinfo.tile_type) # FIXME: The way sites are named in Tile.get_instance_sites is broken # for thes tile types, skip them until the underlying data is fixed. BROKEN_TILE_TYPES = [ 'BRAM_L', 'BRAM_R', 'HCLK_IOI3', 'CMT_TOP_L_UPPER_B', 'CMT_TOP_R_UPPER_B' ] if gridinfo.tile_type in BROKEN_TILE_TYPES: continue instance_sites = list(tile.get_instance_sites(gridinfo)) assert len(instance_sites) == len(tile.get_sites())
def add_wire_to_site_relation(db, c, tile_types, site_types, tile_type_name): tile_type = db.get_tile_type(tile_type_name) for site in tile_type.get_sites(): c.execute( """ INSERT INTO site(name, x_coord, y_coord, site_type_pkey) VALUES (?, ?, ?, ?)""", (site.name, site.x, site.y, site_types[site.type])) site_pkey = c.lastrowid for site_pin in site.site_pins: c.execute( """ SELECT pkey FROM site_pin WHERE name = ? AND site_type_pkey = ?""", (site_pin.name, site_types[site.type])) result = c.fetchone() site_pin_pkey = result[0] c.execute( """ UPDATE wire_in_tile SET site_pkey = ?, site_pin_pkey = ? WHERE name = ? and tile_type_pkey = ?;""", (site_pkey, site_pin_pkey, site_pin.wire, tile_types[tile_type_name]))
def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--db_root', required=True) parser.add_argument('--part', required=True) parser.add_argument('--output_directory', required=True) parser.add_argument('--site_directory', required=True) parser.add_argument('--tile_type', required=True) parser.add_argument('--pb_types', required=True) parser.add_argument('--pin_assignments', required=True) args = parser.parse_args() with open(args.pin_assignments) as f: pin_assignments = json.load(f) db = prjxray.db.Database(args.db_root, args.part) tile_type = db.get_tile_type(args.tile_type) sites = {} pb_types = args.pb_types.split(',') equivalent_sites_dict = dict() for pb_type in pb_types: try: site, equivalent_sites = pb_type.split("/") except ValueError: site = pb_type equivalent_sites = None sites[site] = [] equivalent_sites_dict[site] = equivalent_sites.split( ':') if equivalent_sites else [] for site in tile_type.get_sites(): if site.type not in sites.keys(): continue site_type = db.get_site_type(site.type) input_wires, output_wires = get_wires(site, site_type) sites[site.type].append((site, input_wires, output_wires)) tile_xml = start_heterogeneous_tile( args.tile_type, pin_assignments, sites, equivalent_sites_dict, ) add_switchblock_locations(tile_xml) with open( '{}/{}.tile.xml'.format(args.output_directory, args.tile_type.lower()), 'w') as f: tile_str = ET.tostring(tile_xml, pretty_print=True).decode('utf-8') f.write(tile_str)
def initialize_edge_assignments(db, conn): """ Create initial edge_assignments map. """ c = conn.cursor() c2 = conn.cursor() edge_assignments = {} wires_in_tile_types = set() # First find out which tile types were split during VPR grid formation. # These tile types should not get edge assignments directly, instead # their sites will get edge assignements. sites_as_tiles = set() split_tile_types = set() for site_pkey, tile_type_pkey in c.execute(""" SELECT site_pkey, tile_type_pkey FROM site_as_tile; """): c2.execute("SELECT name FROM tile_type WHERE pkey = ?", (tile_type_pkey, )) split_tile_types.add(c2.fetchone()[0]) c2.execute( """ SELECT name FROM site_type WHERE pkey = ( SELECT site_type_pkey FROM site WHERE pkey = ? );""", (site_pkey, )) site_type_name = c2.fetchone()[0] sites_as_tiles.add(site_type_name) # Initialize edge assignments for split tiles for site_type in sites_as_tiles: site_obj = db.get_site_type(site_type) for site_pin in site_obj.get_site_pins(): key = (site_type, site_pin) assert key not in edge_assignments, key edge_assignments[key] = [] for tile_type in db.get_tile_types(): # Skip tile types that are split tiles if tile_type in split_tile_types: continue type_obj = db.get_tile_type(tile_type) for wire in type_obj.get_wires(): wires_in_tile_types.add((tile_type, wire)) for site in type_obj.get_sites(): for site_pin in site.site_pins: if site_pin.wire is None: continue key = (tile_type, site_pin.wire) assert key not in edge_assignments, key edge_assignments[key] = [] return edge_assignments, wires_in_tile_types
def add_sites_and_pips_to_node(self, db, grid): for tile, wire in self.node: tileinfo = grid.gridinfo_at_tilename(tile) tile_type = db.get_tile_type(tileinfo.tile_type) wire_info = tile_type.get_wire_info(wire) for pip in wire_info.pips: self.pips.append((tile, pip, wire)) for site in wire_info.sites: self.sites.append((tile, ) + site)
def quick_test(db_root): db = prjxray.db.Database(db_root) g = db.grid() # Verify that we have some tile information for every tile in grid. tile_types_in_grid = set( g.gridinfo_at_loc(loc).tile_type for loc in g.tile_locations()) tile_types_in_db = set(db.get_tile_types()) site_types = set(db.get_site_types()) assert len(tile_types_in_grid - tile_types_in_db) == 0 # Verify that all tile types can be loaded. for tile_type in db.get_tile_types(): tile = db.get_tile_type(tile_type) wires = tile.get_wires() for site in tile.get_sites(): assert site.type in site_types site_type = db.get_site_type(site.type) site_pins = site_type.get_site_pins() for site_pin in site.site_pins: if site_pin.wire is not None: assert site_pin.wire in wires, (site_pin.wire, ) assert site_pin.name in site_pins for pip in tile.get_pips(): assert pip.net_to in wires assert pip.net_from in wires for loc in g.tile_locations(): gridinfo = g.gridinfo_at_loc(loc) assert gridinfo.tile_type in db.get_tile_types() for site_name, site_type in gridinfo.sites.items(): assert site_type in site_types tile = db.get_tile_type(gridinfo.tile_type) instance_sites = list(tile.get_instance_sites(gridinfo)) assert len(instance_sites) == len(tile.get_sites())
def import_tile_type(db, write_cur, tile_types, site_types, tile_type_name, get_switch): assert tile_type_name not in tile_types tile_type = db.get_tile_type(tile_type_name) write_cur.execute("INSERT INTO tile_type(name) VALUES (?)", (tile_type_name, )) tile_types[tile_type_name] = write_cur.lastrowid wires = {} for wire, wire_rc_element in tile_type.get_wires().items(): capacitance = 0.0 resistance = 0.0 if wire_rc_element is not None: # microFarads -> Farads capacitance = wire_rc_element.capacitance / 1e6 # milliOhms -> Ohms resistance = wire_rc_element.resistance / 1e3 write_cur.execute( """ INSERT INTO wire_in_tile(name, tile_type_pkey, capacitance, resistance) VALUES (?, ?, ?, ?)""", (wire, tile_types[tile_type_name], capacitance, resistance)) wires[wire] = write_cur.lastrowid for pip in tile_type.get_pips(): switch_pkey = get_switch(pip, pip.timing) backward_switch_pkey = get_switch(pip, pip.backward_timing) write_cur.execute( """ INSERT INTO pip_in_tile( name, tile_type_pkey, src_wire_in_tile_pkey, dest_wire_in_tile_pkey, can_invert, is_directional, is_pseudo, is_pass_transistor, switch_pkey, backward_switch_pkey ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", (pip.name, tile_types[tile_type_name], wires[pip.net_from], wires[pip.net_to], pip.can_invert, pip.is_directional, pip.is_pseudo, pip.is_pass_transistor, switch_pkey, backward_switch_pkey)) for site in tile_type.get_sites(): if site.type not in site_types: import_site_type(db, write_cur, site_types, site.type)
def import_tile_type(db, write_cur, tile_types, site_types, tile_type_name): assert tile_type_name not in tile_types tile_type = db.get_tile_type(tile_type_name) # For Zynq7 PSS* tiles build a list of sites, wires and PIPs to ignore if tile_type_name.startswith("PSS"): masked_sites, masked_wires, masked_pips = build_pss_object_mask( db, tile_type_name) else: masked_sites = [] masked_wires = [] masked_pips = [] write_cur.execute("INSERT INTO tile_type(name) VALUES (?)", (tile_type_name, )) tile_types[tile_type_name] = write_cur.lastrowid wires = {} for wire, wire_rc_element in tile_type.get_wires().items(): if wire in masked_wires: continue write_cur.execute( """ INSERT INTO wire_in_tile(name, phy_tile_type_pkey, tile_type_pkey) VALUES (?, ?, ?)""", ( wire, tile_types[tile_type_name], tile_types[tile_type_name], )) wires[wire] = write_cur.lastrowid for site in tile_type.get_sites(): if (site.prefix, site.name) in masked_sites: continue if site.type not in site_types: import_site_type(db, write_cur, site_types, site.type)
def make_connections(db): # Some nodes are just 1 wire, so start by enumerating all wires. wires = {} grid = db.grid() for tile in progressbar.progressbar(grid.tiles()): gridinfo = grid.gridinfo_at_tilename(tile) tile_type = db.get_tile_type(gridinfo.tile_type) for wire in tile_type.get_wires(): key = (tile, wire) wires[key] = set((key, )) c = db.connections() for connection in progressbar.progressbar(c.get_connections()): make_connection(wires, connection) nodes = {} for wire_node in wires.values(): nodes[id(wire_node)] = wire_node return nodes.values()
def import_tile_type(db, c, tile_types, site_types, tile_type_name): assert tile_type_name not in tile_types tile_type = db.get_tile_type(tile_type_name) c.execute("INSERT INTO tile_type(name) VALUES (?)", (tile_type_name, )) tile_types[tile_type_name] = c.lastrowid wires = {} for wire in tile_type.get_wires(): c.execute( """ INSERT INTO wire_in_tile(name, tile_type_pkey) VALUES (?, ?)""", (wire, tile_types[tile_type_name])) wires[wire] = c.lastrowid for pip in tile_type.get_pips(): # Psuedo pips are not part of the routing fabric, so don't add them. if pip.is_pseudo: continue if not pip.is_directional: continue c.execute( """ INSERT INTO pip_in_tile( name, tile_type_pkey, src_wire_in_tile_pkey, dest_wire_in_tile_pkey ) VALUES (?, ?, ?, ?)""", (pip.name, tile_types[tile_type_name], wires[pip.net_from], wires[pip.net_to])) for site in tile_type.get_sites(): if site.type not in site_types: import_site_type(db, c, site_types, site.type)
def build_pss_object_mask(db, tile_type_name): """ Looks for objects present in PSS* tiles of Zynq7 and masks out those that are purely PS related and not configued by the PL. """ tile_type = db.get_tile_type(tile_type_name) sites = tile_type.get_sites() masked_wires = [] masked_pips = [] # Get all IOPADS for MIO and DDR signals iopad_sites = [s for s in sites if s.type == "IOPAD"] for site in iopad_sites: # Get pins/wires site_pins = [p for p in site.site_pins if p.name == "IO"] for site_pin in site_pins: # Mask the wire masked_wires.append(site_pin.wire) # Find a PIP(s) for this wire, mask them as well as wires on # their other sides. for p in tile_type.get_pips(): if p.net_from == site_pin.wire: masked_pips.append(p.name) masked_wires.append(p.net_to) if p.net_to == site_pin.wire: masked_pips.append(p.name) masked_wires.append(p.net_from) # Masked sites names masked_sites = [(s.prefix, s.name) for s in iopad_sites] return masked_sites, masked_wires, masked_pips
def main(): mydir = os.path.dirname(__file__) prjxray_db = os.path.abspath(os.path.join(mydir, "..", "..", "third_party", "prjxray-db")) db_types = prjxray.db.get_available_databases(prjxray_db) parser = argparse.ArgumentParser(description="Generate arch.xml") parser.add_argument( '--part', choices=[os.path.basename(db_type) for db_type in db_types], help="""Project X-Ray database to use.""") parser.add_argument( '--output-arch', nargs='?', type=argparse.FileType('w'), help="""File to output arch.""") parser.add_argument('--tile-types', help="Semi-colon seperated tile types.") parser.add_argument( '--pin_assignments', required=True, type=argparse.FileType('r')) parser.add_argument( '--use_roi', required=False) parser.add_argument( '--synth_tiles', required=False) parser.add_argument( '--device', required=True) args = parser.parse_args() tile_types = args.tile_types.split(',') tile_model = "../../tiles/{0}/{0}.model.xml" tile_pbtype = "../../tiles/{0}/{0}.pb_type.xml" xi_url = "http://www.w3.org/2001/XInclude" ET.register_namespace('xi', xi_url) xi_include = "{%s}include" % xi_url arch_xml = ET.Element( 'architecture', {}, nsmap = {'xi': xi_url}, ) model_xml = ET.SubElement(arch_xml, 'models') for tile_type in tile_types: ET.SubElement(model_xml, xi_include, { 'href': tile_model.format(tile_type.lower()), 'xpointer':"xpointer(models/child::node())", }) complexblocklist_xml = ET.SubElement(arch_xml, 'complexblocklist') for tile_type in tile_types: ET.SubElement(complexblocklist_xml, xi_include, { 'href': tile_pbtype.format(tile_type.lower()), }) layout_xml = ET.SubElement(arch_xml, 'layout') db = prjxray.db.Database(os.path.join(prjxray_db, args.part)) g = db.grid() x_min, x_max, y_min, y_max = g.dims() # FIXME: There is an issue in the routing phase. (https://github.com/SymbiFlow/symbiflow-arch-defs/issues/353) # if a zynq device is selected the grid must be expanded by 1 if args.device == 'xc7z010': x_max += 1 y_max += 1 name = '{}-test'.format(args.device) fixed_layout_xml = ET.SubElement(layout_xml, 'fixed_layout', { 'name': name, 'height': str(y_max+1), 'width': str(x_max+1), }) only_emit_roi = False roi_inputs = [] roi_outputs = [] synth_tiles = {} synth_tiles['tiles'] = {} if args.use_roi: only_emit_roi = True with open(args.use_roi) as f: j = json.load(f) 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'], ) synth_tiles['info'] = j['info'] for port in j['ports']: if port['name'].startswith('dout['): roi_outputs.append(port) port_type = 'input' is_clock = False elif port['name'].startswith('din['): roi_inputs.append(port) is_clock = False port_type = 'output' elif port['name'].startswith('clk'): roi_inputs.append(port) port_type = 'output' is_clock = True else: assert False, port tile, wire = port['wire'].split('/') # Make sure connecting wire is not in ROI! loc = g.loc_of_tilename(tile) if 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, tile if tile not in synth_tiles['tiles']: synth_tiles['tiles'][tile] = { 'pins': [], 'loc': g.loc_of_tilename(tile), } 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, }) with open(args.synth_tiles, 'w') as f: json.dump(synth_tiles, f) synth_tile_map = add_synthetic_tile(complexblocklist_xml) for loc in g.tile_locations(): gridinfo = g.gridinfo_at_loc(loc) tile = g.tilename_at_loc(loc) if tile in synth_tiles['tiles']: synth_tile = synth_tiles['tiles'][tile] assert len(synth_tile['pins']) == 1 vpr_tile_type = synth_tile_map[synth_tile['pins'][0]['port_type']] elif only_emit_roi and not roi.tile_in_roi(loc): # This tile is outside the ROI, skip it. continue elif gridinfo.tile_type in tile_types: # We want to import this tile type. vpr_tile_type = 'BLK_TI-{}'.format(gridinfo.tile_type) else: # We don't want this tile continue is_vbrk = gridinfo.tile_type.find('VBRK') != -1 # VBRK tiles are known to have no bitstream data. if not is_vbrk and not gridinfo.bits: print('*** WARNING *** Skipping tile {} because it lacks bitstream data.'.format(tile), file=sys.stderr) single_xml = ET.SubElement(fixed_layout_xml, 'single', { 'priority': '1', 'type': vpr_tile_type, 'x': str(loc[0]), 'y': str(loc[1]), }) meta = ET.SubElement(single_xml, 'metadata') ET.SubElement(meta, 'meta', { 'name': 'fasm_prefix', }).text = tile device_xml = ET.SubElement(arch_xml, 'device') ET.SubElement(device_xml, 'sizing', { "R_minW_nmos":"6065.520020", "R_minW_pmos":"18138.500000", }) ET.SubElement(device_xml, 'area', { "grid_logic_tile_area":"14813.392", }) ET.SubElement(device_xml, 'connection_block', { "input_switch_name":"buffer", }) ET.SubElement(device_xml, 'switch_block', { "type":"wilton", "fs":"3", }) chan_width_distr_xml = ET.SubElement(device_xml, 'chan_width_distr') ET.SubElement(chan_width_distr_xml, 'x', { 'distr':'uniform', 'peak':'1.0', }) ET.SubElement(chan_width_distr_xml, 'y', { 'distr':'uniform', 'peak':'1.0', }) switchlist_xml = ET.SubElement(arch_xml, 'switchlist') ET.SubElement(switchlist_xml, 'switch', { 'type':'mux', 'name':'routing', "R":"551", "Cin":".77e-15", "Cout":"4e-15", "Tdel":"6.8e-12", "mux_trans_size":"2.630740", "buf_size":"27.645901" }) ET.SubElement(switchlist_xml, 'switch', { 'type':'mux', 'name':'buffer', "R":"551", "Cin":".77e-15", "Cout":"4e-15", "Tdel":"6.8e-12", "mux_trans_size":"2.630740", "buf_size":"27.645901" }) segmentlist_xml = ET.SubElement(arch_xml, 'segmentlist') # VPR requires a segment, so add one. dummy_xml = ET.SubElement(segmentlist_xml, 'segment', { 'name': 'dummy', 'length': '12', 'freq': '1.0', 'type': 'bidir', 'Rmetal':'101', 'Cmetal':'22.5e15', }) ET.SubElement(dummy_xml, 'wire_switch', { 'name': 'routing', }) ET.SubElement(dummy_xml, 'opin_switch', { 'name': 'routing', }) ET.SubElement(dummy_xml, 'sb', { 'type': 'pattern', }).text = ' '.join('1' for _ in range(13)) ET.SubElement(dummy_xml, 'cb', { 'type': 'pattern', }).text = ' '.join('1' for _ in range(12)) directlist_xml = ET.SubElement(arch_xml, 'directlist') pin_assignments = json.load(args.pin_assignments) # Choose smallest distance for block to block connections with multiple # direct_connections. VPR cannot handle multiple block to block connections. directs = {} for direct in pin_assignments['direct_connections']: key = (direct['from_pin'], direct['to_pin']) if key not in directs: directs[key] = [] directs[key].append((abs(direct['x_offset']) + abs(direct['y_offset']), direct)) for direct in directs.values(): _, direct = min(direct, key=lambda v: v[0]) if direct['from_pin'].split('.')[0] not in tile_types: continue if direct['to_pin'].split('.')[0] not in tile_types: continue if direct['x_offset'] == 0 and direct['y_offset'] == 0: continue ET.SubElement(directlist_xml, 'direct', { 'name': '{}_to_{}_dx_{}_dy_{}'.format(direct['from_pin'], direct['to_pin'], direct['x_offset'], direct['y_offset']), 'from_pin': 'BLK_TI-' + direct['from_pin'], 'to_pin': 'BLK_TI-' + direct['to_pin'], 'x_offset': str(direct['x_offset']), 'y_offset': str(direct['y_offset']), 'z_offset': '0', 'switch_name': direct['switch_name'], }) arch_xml_str = ET.tostring(arch_xml, pretty_print=True).decode('utf-8') args.output_arch.write(arch_xml_str) args.output_arch.close()
def main(): parser = argparse.ArgumentParser() parser.add_argument( '--db_root', required=True, help='Project X-Ray Database') parser.add_argument( '--read_rr_graph', required=True, help='Input rr_graph file') parser.add_argument( '--write_rr_graph', required=True, help='Output rr_graph file') parser.add_argument( '--channels', required=True, help='Channel definitions from prjxray_form_channels') parser.add_argument( '--synth_tiles', help='If using an ROI, synthetic tile defintion from prjxray-arch-import') args = parser.parse_args() db = prjxray.db.Database(args.db_root) grid = db.grid() if args.synth_tiles: use_roi = True with open(args.synth_tiles) as f: synth_tiles = json.load(f) roi = Roi( db=db, x1=synth_tiles['info']['GRID_X_MIN'], y1=synth_tiles['info']['GRID_Y_MIN'], x2=synth_tiles['info']['GRID_X_MAX'], y2=synth_tiles['info']['GRID_Y_MAX'], ) print('{} generating routing graph for ROI.'.format(now())) else: use_roi = False # Convert input rr graph into graph2.Graph object. input_rr_graph = read_xml_file(args.read_rr_graph) xml_graph = xml_graph2.Graph( input_rr_graph, progressbar=progressbar.progressbar) graph = xml_graph.graph tool_version = input_rr_graph.getroot().attrib['tool_version'] tool_comment = input_rr_graph.getroot().attrib['tool_comment'] delayless_switch = graph.get_delayless_switch_id() print('{} reading channels definitions.'.format(now())) with open(args.channels) as f: channels = json.load(f) segment_id = graph.get_segment_id_from_name('dummy') track_wire_map = {} print('{} add nodes for all channels.'.format(now())) used_channels = 0 for idx, channel in progressbar.progressbar(enumerate(channels['channels'])): # Don't use dead channels if using an ROI. # Consider a channel alive if at least 1 wire in the node is part of a # live tile. if use_roi: alive = False for tile, wire in channel['wires']: loc = grid.loc_of_tilename(tile) if roi.tile_in_roi(loc) or tile in synth_tiles['tiles']: alive = True break if not alive: continue used_channels += 1 nodes = [] track_list = [] for idx2, track_dict in enumerate(channel['tracks']): if track_dict['direction'] == 'X': track_dict['x_low'] = max(track_dict['x_low'], 1) elif track_dict['direction'] == 'Y': track_dict['y_low'] = max(track_dict['y_low'], 1) track = tracks.Track(**track_dict) track_list.append(track) nodes.append(graph.add_track(track=track, segment_id=segment_id, name='track_{}_{}'.format(idx, idx2))) for a_idx, b_idx in channel['track_connections']: graph.add_edge(nodes[a_idx], nodes[b_idx], delayless_switch, 'track_{}_to_{}'.format(a_idx, b_idx)) graph.add_edge(nodes[b_idx], nodes[a_idx], delayless_switch, 'track_{}_to_{}'.format(b_idx, a_idx)) tracks_model = tracks.Tracks(track_list, channel['track_connections']) for tile, wire in channel['wires']: track_wire_map[(tile, wire)] = (tracks_model, nodes) print('original {} final {}'.format(len(channels['channels']), used_channels)) routing_switch = graph.get_switch_id('routing') pip_map = {} edges_with_mux = {} for idx, edge_with_mux in progressbar.progressbar(enumerate(channels['edges_with_mux'])): if edge_with_mux['pip'] not in edges_with_mux: edges_with_mux[edge_with_mux['pip']] = {} assert len(edge_with_mux['source_node']) == 1 edges_with_mux[edge_with_mux['pip']][tuple(edge_with_mux['source_node'][0])] = edge_with_mux['destination_node'] # Set of (src, sink, switch_id) tuples that pip edges have been sent to # VPR. VPR cannot handle duplicate paths with the same switch id. pip_set = set() print('{} Adding edges'.format(now())) for loc in progressbar.progressbar(grid.tile_locations()): gridinfo = grid.gridinfo_at_loc(loc) tile_name = grid.tilename_at_loc(loc) if use_roi: if tile_name in synth_tiles['tiles']: assert len(synth_tiles['tiles'][tile_name]['pins']) == 1 for pin in synth_tiles['tiles'][tile_name]['pins']: tracks_model, track_nodes = track_wire_map[(tile_name, pin['wire'])] option = list(tracks_model.get_tracks_for_wire_at_coord(loc)) assert len(option) > 0 if pin['port_type'] == 'input': tile_type = 'BLK_SY-OUTPAD' wire = 'outpad' elif pin['port_type'] == 'output': tile_type = 'BLK_SY-INPAD' wire = 'inpad' else: assert False, pin track_node = track_nodes[option[0][0]] pin_name = graph.create_pin_name_from_tile_type_and_pin( tile_type, wire) pin_node = graph.get_nodes_for_pin(loc, pin_name) if pin['port_type'] == 'input': graph.add_edge( src_node=track_node, sink_node=pin_node[0][0], switch_id=routing_switch, name='synth_{}_{}'.format(tile_name, pin['wire']), ) elif pin['port_type'] == 'output': graph.add_edge( src_node=pin_node[0][0], sink_node=track_node, switch_id=routing_switch, name='synth_{}_{}'.format(tile_name, pin['wire']), ) else: assert False, pin else: # Not a synth node, check if in ROI. if not roi.tile_in_roi(loc): continue tile_type = db.get_tile_type(gridinfo.tile_type) for pip in tile_type.get_pips(): if pip.is_pseudo: continue if not pip.is_directional: # TODO: Handle bidirectional pips? continue edge_node = make_connection(graph, track_wire_map, loc, tile_name, gridinfo.tile_type, pip, routing_switch, edges_with_mux, grid, pip_set) if edge_node is not None: pip_map[(tile_name, pip.name)] = edge_node print('{} Writing node mapping.'.format(now())) node_mapping = { 'pips': [], 'tracks': [] } for (tile, pip_name), edge in pip_map.items(): node_mapping['pips'].append({ 'tile': tile, 'pip': pip_name, 'edge': edge }) for (tile, wire), (_, nodes) in track_wire_map.items(): node_mapping['tracks'].append({ 'tile': tile, 'wire': wire, 'nodes': nodes, }) with open('node_mapping.pickle', 'wb') as f: pickle.dump(node_mapping, f) print('{} Create channels and serializing.'.format(now())) pool = multiprocessing.Pool(10) serialized_rr_graph = xml_graph.serialize_to_xml( tool_version=tool_version, tool_comment=tool_comment, pad_segment=segment_id, pool=pool, ) print('{} Writing to disk.'.format(now())) with open(args.write_rr_graph, "wb") as f: f.write(serialized_rr_graph) print('{} Done.'.format(now()))
def import_nodes(db, grid, conn): # Some nodes are just 1 wire, so start by enumerating all wires. cur = conn.cursor() write_cur = conn.cursor() write_cur.execute("""BEGIN EXCLUSIVE TRANSACTION;""") tile_wire_map = {} wires = {} for tile in progressbar.progressbar(grid.tiles()): gridinfo = grid.gridinfo_at_tilename(tile) tile_type = db.get_tile_type(gridinfo.tile_type) cur.execute( """SELECT pkey, tile_type_pkey FROM phy_tile WHERE name = ?;""", (tile, )) phy_tile_pkey, tile_type_pkey = cur.fetchone() for wire in tile_type.get_wires(): # pkey node_pkey tile_pkey wire_in_tile_pkey cur.execute( """ SELECT pkey FROM wire_in_tile WHERE name = ? and tile_type_pkey = ?;""", (wire, tile_type_pkey)) (wire_in_tile_pkey, ) = cur.fetchone() write_cur.execute( """ INSERT INTO wire(phy_tile_pkey, wire_in_tile_pkey) VALUES (?, ?);""", (phy_tile_pkey, wire_in_tile_pkey)) assert (tile, wire) not in tile_wire_map wire_pkey = write_cur.lastrowid tile_wire_map[(tile, wire)] = wire_pkey wires[wire_pkey] = None write_cur.execute("""COMMIT TRANSACTION;""") connections = db.connections() for connection in progressbar.progressbar(connections.get_connections()): a_pkey = tile_wire_map[(connection.wire_a.tile, connection.wire_a.wire)] b_pkey = tile_wire_map[(connection.wire_b.tile, connection.wire_b.wire)] a_node = wires[a_pkey] b_node = wires[b_pkey] if a_node is None: a_node = set((a_pkey, )) if b_node is None: b_node = set((b_pkey, )) if a_node is not b_node: a_node |= b_node for wire in a_node: wires[wire] = a_node nodes = {} for wire_pkey, node in wires.items(): if node is None: node = set((wire_pkey, )) assert wire_pkey in node nodes[id(node)] = node wires_assigned = set() for node in progressbar.progressbar(nodes.values()): write_cur.execute("""INSERT INTO node(number_pips) VALUES (0);""") node_pkey = write_cur.lastrowid for wire_pkey in node: wires_assigned.add(wire_pkey) write_cur.execute( """ UPDATE wire SET node_pkey = ? WHERE pkey = ? ;""", (node_pkey, wire_pkey)) assert len(set(wires.keys()) ^ wires_assigned) == 0 del tile_wire_map del nodes del wires write_cur.execute( "CREATE INDEX wire_in_tile_index ON wire(wire_in_tile_pkey);") write_cur.execute( "CREATE INDEX wire_index ON wire(phy_tile_pkey, wire_in_tile_pkey);") write_cur.execute("CREATE INDEX wire_node_index ON wire(node_pkey);") write_cur.connection.commit()
def add_wire_to_site_relation(db, write_cur, tile_types, site_types, tile_type_name, get_switch_timing): tile_type = db.get_tile_type(tile_type_name) for site in tile_type.get_sites(): write_cur.execute( """ INSERT INTO site(name, x_coord, y_coord, site_type_pkey) VALUES (?, ?, ?, ?)""", (site.name, site.x, site.y, site_types[site.type])) site_pkey = write_cur.lastrowid for site_pin in site.site_pins: write_cur.execute( """ SELECT pkey FROM site_pin WHERE name = ? AND site_type_pkey = ?""", (site_pin.name, site_types[site.type])) result = write_cur.fetchone() site_pin_pkey = result[0] intrinsic_delay = 0 drive_resistance = 0 capacitance = 0 if site_pin.timing is not None: # Use the largest intristic delay for now. # This conservative on slack timing, but not on hold timing. # # nanosecond -> seconds intrinsic_delay = site_pin.timing.delays[ PvtCorner.SLOW].max / 1e9 if isinstance(site_pin.timing, prjxray.tile.OutPinTiming): # milliOhms -> Ohms drive_resistance = site_pin.timing.drive_resistance / 1e3 elif isinstance(site_pin.timing, prjxray.tile.InPinTiming): # microFarads -> Farads capacitance = site_pin.timing.capacitance / 1e6 else: assert False, site_pin else: # Use min value instead of 0 to prevent # VPR from freaking out over a zero net delay. # # Note this is the single precision float minimum, because VPR # uses single precision, not double precision. intrinsic_delay = SINGLE_PRECISION_FLOAT_MIN site_pin_switch_pkey = get_switch_timing( is_pass_transistor=False, delay=intrinsic_delay, internal_capacitance=capacitance, drive_resistance=drive_resistance, ) write_cur.execute( """ UPDATE wire_in_tile SET site_pkey = ?, site_pin_pkey = ?, site_pin_switch_pkey = ? WHERE name = ? and tile_type_pkey = ?;""", (site_pkey, site_pin_pkey, site_pin_switch_pkey, site_pin.wire, tile_types[tile_type_name]))
def import_tile(db, args): """ Create a root-level pb_type with the pin names that match tile wires. This will either have 1 intermediate pb_type per site, or 1 large site for the entire tile if args.fused_sites is set to true. """ tile = db.get_tile_type(args.tile) # Wires sink to a site within the tile are input wires. input_wires = set() # Wires source from a site within the tile are output wires. output_wires = set() if args.filter_x: xs = list(map(int, args.filter_x.split(','))) def x_filter_func(site): return site.x in xs x_filter = x_filter_func else: def x_filter_func(site): return True x_filter = x_filter_func if not args.fused_sites: site_type_instances = parse_site_type_instance(args.site_types) imported_site_types = set() ignored_site_types = set() for site in tile.get_sites(): site_type = db.get_site_type(site.type) if site.type not in site_type_instances: ignored_site_types.add(site.type) continue imported_site_types.add(site.type) for site_pin in site.site_pins: site_type_pin = site_type.get_site_pin(site_pin.name) if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN: if site_pin.wire is not None: input_wires.add(site_pin.wire) elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT: if site_pin.wire is not None: output_wires.add(site_pin.wire) else: if site.type != "PS7": assert False, site_type_pin.direction # Make sure all requested site types actually get imported. assert len(set(site_type_instances.keys()) - imported_site_types) == 0, (site_type_instances.keys(), imported_site_types) for ignored_site_type in ignored_site_types: print( '*** WARNING *** Ignored site type {} in tile type {}'.format( ignored_site_type, args.tile), file=sys.stderr) else: for site in tile.get_sites(): site_type = db.get_site_type(site.type) for site_pin in site.site_pins: site_type_pin = site_type.get_site_pin(site_pin.name) if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN: if site_pin.wire is not None: input_wires.add(site_pin.wire) elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT: if site_pin.wire is not None: output_wires.add(site_pin.wire) else: assert False, site_type_pin.direction site_pbtype = args.site_directory + "/{0}/{1}.pb_type.xml" ########################################################################## # Generate the model.xml file # ########################################################################## model = ModelXml(f=args.output_model, site_directory=args.site_directory) if args.fused_sites: fused_site_name = args.tile.lower() model.add_model_include(fused_site_name, fused_site_name) ########################################################################## # Utility functions for pb_type # ########################################################################## tile_name = args.tile pb_type_xml = start_pb_type(tile_name, args.pin_assignments, input_wires, output_wires) cell_names = {} interconnect_xml = ET.Element('interconnect') if not args.fused_sites: site_type_count = {} site_prefixes = {} cells_idx = {} models_added = set() site_type_ports = {} idx = 0 for site in tile.get_sites(): if site.type in ignored_site_types: continue if not x_filter(site): continue if site.type not in site_type_count: site_type_count[site.type] = 0 site_prefixes[site.type] = [] cells_idx[idx] = site_type_count[site.type] site_type_count[site.type] += 1 site_coords = args.site_coords.upper() if site_coords == 'X': site_prefix = '{}_X{}'.format(site.type, site.x) elif site_coords == 'Y': site_prefix = '{}_Y{}'.format(site.type, site.y) elif site_coords == 'XY': site_prefix = '{}.{}_X{}Y{}'.format(site.type, site.type, site.x, site.y) else: assert False, "Invalid --site-coords value '{}'".format( site_coords) site_instance = site_type_instances[site.type][cells_idx[idx]] idx += 1 if (site.type, site_instance) not in models_added: models_added.add((site.type, site_instance)) model.add_model_include(site.type, site_instance) site_type_path = site_pbtype.format(site.type.lower(), site_instance.lower()) cell_pb_type = ET.ElementTree() root_element = cell_pb_type.parse(site_type_path) cell_names[site_instance] = 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_instance not in site_type_ports, ( site_instance, site_type_ports.keys()) site_type_ports[site_instance] = 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 not args.no_fasm_prefix: 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())", }) # Prevent emitting empty metadata if not any(child.tag == 'meta' for child in metadata_xml): include_xml.remove(metadata_xml) idx = 0 for site in tile.get_sites(): if site.type in ignored_site_types: continue site_idx = cells_idx[idx] idx += 1 if not x_filter(site): continue site_instance = site_type_instances[site.type][site_idx] site_name = cell_names[site_instance] site_type = db.get_site_type(site.type) interconnect_xml.append(ET.Comment(" Tile->Site ")) for site_pin in sorted(site.site_pins, key=lambda site_pin: site_pin.name): if site_pin.wire is None: continue port = find_port(site_pin.name, site_type_ports[site_instance]) 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_type_pin = site_type.get_site_pin(site_pin.name) if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN: add_direct(interconnect_xml, input=object_ref(add_vpr_tile_prefix(tile_name), site_pin.wire), output=object_ref(site_name, **port)) elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT: pass else: if site.type != "PS7": assert False, site_type_pin.direction interconnect_xml.append(ET.Comment(" Site->Tile ")) for site_pin in sorted(site.site_pins, key=lambda site_pin: site_pin.name): if site_pin.wire is None: continue port = find_port(site_pin.name, site_type_ports[site_instance]) if port is None: continue site_type_pin = site_type.get_site_pin(site_pin.name) if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN: pass elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT: add_direct( interconnect_xml, input=object_ref(site_name, **port), output=object_ref(add_vpr_tile_prefix(tile_name), site_pin.wire), ) else: if site.type != "PS7": assert False, site_type_pin.direction else: site_type_ports = {} site_type_path = site_pbtype.format(fused_site_name, fused_site_name) cell_pb_type = ET.ElementTree() root_element = cell_pb_type.parse(site_type_path) 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']) 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())", }) site_name = root_element.attrib['name'] def fused_port_name(site, site_pin): return '{}_{}_{}'.format(site.prefix, site.name, site_pin.name) for site in tile.get_sites(): site_type = db.get_site_type(site.type) interconnect_xml.append(ET.Comment(" Tile->Site ")) for site_pin in sorted(site.site_pins, key=lambda site_pin: site_pin.name): if site_pin.wire is None: continue port_name = fused_port_name(site, site_pin) port = find_port(port_name, ports) if port is None: print( "*** WARNING *** Didn't find port for name {} for site type {}" .format(port_name, site.type), file=sys.stderr) continue site_type_pin = site_type.get_site_pin(site_pin.name) if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN: add_direct(interconnect_xml, input=object_ref(add_vpr_tile_prefix(tile_name), site_pin.wire), output=object_ref(site_name, **port)) elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT: pass else: if site.type != "PS7": assert False, site_type_pin.direction interconnect_xml.append(ET.Comment(" Site->Tile ")) for site_pin in sorted(site.site_pins, key=lambda site_pin: site_pin.name): if site_pin.wire is None: continue port = find_port(fused_port_name(site, site_pin), ports) if port is None: # Already warned above continue site_type_pin = site_type.get_site_pin(site_pin.name) if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN: pass elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT: add_direct( interconnect_xml, input=object_ref(site_name, **port), output=object_ref(add_vpr_tile_prefix(tile_name), site_pin.wire), ) else: if site.type != "PS7": assert False, site_type_pin.direction pb_type_xml.append(interconnect_xml) model.write_model() write_xml(args.output_pb_type, pb_type_xml)
def initialize_edge_assignments(db, conn): """ Create initial edge_assignments map. """ c = conn.cursor() c2 = conn.cursor() c.execute(""" SELECT name, pkey FROM tile_type WHERE pkey IN ( SELECT DISTINCT tile_type_pkey FROM tile );""") tiles = dict(c) edge_assignments = {} wires_in_tile_types = set() # First find out which tile types were split during VPR grid formation. # These tile types should not get edge assignments directly, instead # their sites will get edge assignements. sites_as_tiles = set() split_tile_types = set() for site_pkey, tile_type_pkey in c.execute(""" SELECT site_pkey, tile_type_pkey FROM site_as_tile; """): c2.execute("SELECT name FROM tile_type WHERE pkey = ?", (tile_type_pkey, )) split_tile_types.add(c2.fetchone()[0]) c2.execute( """ SELECT name FROM site_type WHERE pkey = ( SELECT site_type_pkey FROM site WHERE pkey = ? );""", (site_pkey, )) site_type_name = c2.fetchone()[0] sites_as_tiles.add(site_type_name) # Initialize edge assignments for split tiles for site_type in sites_as_tiles: del tiles[site_type] site_obj = db.get_site_type(site_type) for site_pin in site_obj.get_site_pins(): key = (site_type, site_pin) assert key not in edge_assignments, key edge_assignments[key] = [] for tile_type in db.get_tile_types(): if tile_type not in tiles: continue del tiles[tile_type] # Skip tile types that are split tiles if tile_type in split_tile_types: continue (tile_type_pkey, ) = c.execute( """ SELECT pkey FROM tile_type WHERE name = ? """, (tile_type, )).fetchone() for (wire, ) in c.execute( """ SELECT name FROM wire_in_tile WHERE tile_type_pkey = ?""", (tile_type_pkey, )): wires_in_tile_types.add((tile_type, wire)) type_obj = db.get_tile_type(tile_type) for site in type_obj.get_sites(): for site_pin in site.site_pins: if site_pin.wire is None: continue # Skip if this wire is not in the database c.execute( """ SELECT pkey FROM wire_in_tile WHERE name = ? """, (site_pin.wire, )) if not c.fetchone(): continue key = (tile_type, site_pin.wire) assert key not in edge_assignments, key edge_assignments[key] = [] for tile_type, tile_pkey in tiles.items(): assert tile_type not in split_tile_types for (wire, ) in c.execute( """ SELECT name FROM wire_in_tile WHERE pkey in ( SELECT DISTINCT wire_in_tile_pkey FROM wire WHERE tile_pkey IN ( SELECT pkey FROM tile WHERE tile_type_pkey = ?) );""", (tile_pkey, )): wires_in_tile_types.add((tile_type, wire)) for (wire, ) in c.execute( """ SELECT DISTINCT name FROM wire_in_tile WHERE pkey in ( SELECT DISTINCT wire_in_tile_pkey FROM wire WHERE tile_pkey IN ( SELECT pkey FROM tile WHERE tile_type_pkey = ?) ) AND site_pin_pkey IS NOT NULL""", (tile_pkey, )): key = (tile_type, wire) assert key not in edge_assignments, key edge_assignments[key] = [] return edge_assignments, wires_in_tile_types
def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--db_root', required=True) parser.add_argument('--part', required=True) parser.add_argument('--output_directory', required=True) parser.add_argument('--site_directory', required=True) parser.add_argument('--tile_type', required=True) parser.add_argument('--pb_types', required=True) parser.add_argument('--pin_assignments', required=True) parser.add_argument( '--unused_wires', help="Comma seperated list of site wires to exclude in this tile.") args = parser.parse_args() with open(args.pin_assignments) as f: pin_assignments = json.load(f) db = prjxray.db.Database(args.db_root, args.part) grid = db.grid() tile_type = db.get_tile_type(args.tile_type) pb_types = args.pb_types.split(',') equivalent_sites_dict = dict() gridinfo = None for tile in grid.tiles(): if args.tile_type in tile: gridinfo = grid.gridinfo_at_tilename(tile) break assert gridinfo for pb_type in pb_types: try: site, equivalent_sites = pb_type.split("/") except ValueError: site = pb_type equivalent_sites = None equivalent_sites_dict[site] = equivalent_sites.split( ':') if equivalent_sites else [] sites = list() for site in tile_type.get_sites(): site_type = db.get_site_type(site.type) input_wires, output_wires = get_wires(site, site_type, args.unused_wires) sites.append((site_type, site, input_wires, output_wires)) sites = sorted(sites, key=lambda site: (site[1].type, int(site[1].x), int(site[1].y))) tile_xml = start_heterogeneous_tile( args.tile_type, pin_assignments, sites, equivalent_sites_dict, ) add_switchblock_locations(tile_xml) with open( '{}/{}.tile.xml'.format(args.output_directory, args.tile_type.lower()), 'w') as f: tile_str = ET.tostring(tile_xml, pretty_print=True).decode('utf-8') f.write(tile_str)
def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--db_root', required=True) parser.add_argument('--output_directory', required=True) parser.add_argument('--site_directory', required=True) parser.add_argument('--tile_type', required=True) parser.add_argument('--pb_type', required=True) parser.add_argument('--pin_assignments', required=True) parser.add_argument('--site_coords', required=True) args = parser.parse_args() with open(args.pin_assignments) as f: pin_assignments = json.load(f) db = prjxray.db.Database(args.db_root) tile_type = db.get_tile_type(args.tile_type) input_wires = set() output_wires = set() sites = [] for site in tile_type.get_sites(): if site.type != args.pb_type: continue site_type = db.get_site_type(site.type) sites.append(site) for site_pin in site.site_pins: if site_type.get_site_pin( site_pin.name).direction == SitePinDirection.IN: input_wires.add(site_pin.wire) elif site_type.get_site_pin( site_pin.name).direction == SitePinDirection.OUT: output_wires.add(site_pin.wire) else: assert False, site_pin sites.sort(key=lambda site: (site.x, site.y)) tile_xml = start_pb_type( args.tile_type, pin_assignments, input_wires, output_wires, root_pb_type=True, root_tag='tile', ) tile_xml.attrib['capacity'] = str(len(sites)) tile_xml.attrib['capacity_type'] = "explicit" equivalent_sites_xml = ET.Element('equivalent_sites') site_xml = ET.Element('site', { 'pb_type': add_vpr_tile_prefix(site.type), 'pin_mapping': 'custom' }) for site_idx, site in enumerate(sites): if site.type != args.pb_type: continue for site_pin in site.site_pins: add_tile_direct( site_xml, tile=object_ref( add_vpr_tile_prefix(args.tile_type), site_pin.wire, ), pb_type=object_ref( pb_name=add_vpr_tile_prefix(site.type), pb_idx=site_idx, pin_name=site_pin.name, ), ) equivalent_sites_xml.append(site_xml) tile_xml.append(equivalent_sites_xml) add_switchblock_locations(tile_xml) with open( '{}/{}.tile.xml'.format(args.output_directory, args.tile_type.lower()), 'w') as f: tile_str = ET.tostring(tile_xml, pretty_print=True).decode('utf-8') f.write(tile_str)
def main(): parser = argparse.ArgumentParser(description="Generate synth_tiles.json") parser.add_argument( '--db_root', required=True) parser.add_argument( '--roi', required=True) parser.add_argument( '--synth_tiles', required=False) args = parser.parse_args() db = prjxray.db.Database(args.db_root) g = db.grid() synth_tiles = {} synth_tiles['tiles'] = {} with open(args.roi) as f: j = json.load(f) 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'], ) synth_tiles['info'] = j['info'] for port in j['ports']: if port['name'].startswith('dout['): port_type = 'input' is_clock = False elif port['name'].startswith('din['): is_clock = False port_type = 'output' elif port['name'].startswith('clk'): port_type = 'output' is_clock = True else: assert False, port tile, wire = port['wire'].split('/') # Make sure connecting wire is not in ROI! loc = g.loc_of_tilename(tile) if 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, tile if tile not in synth_tiles['tiles']: synth_tiles['tiles'][tile] = { 'pins': [], 'loc': g.loc_of_tilename(tile), } 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, }) with open(args.synth_tiles, 'w') as f: json.dump(synth_tiles, f)
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() for roi, j in rois.items(): if args.overlay: synth_tiles['info'].append(j['info']) tile_pin_count = dict() num_synth_tiles = 0 for port in sorted(j['ports'], key=lambda i: (i['type'], i['name'])): 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, } 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], }) 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)
def main(): parser = argparse.ArgumentParser() parser.add_argument( '--db_root', help='Project X-Ray Database', required=True) parser.add_argument( '--connection_database', help='Database of fabric connectivity', required=True) parser.add_argument( '--pin_assignments', help='Output JSON assigning pins to tile types and direction connections', required=True) args = parser.parse_args() db = prjxray.db.Database(args.db_root) grid = db.grid() edge_assignments = {} wires_in_tile_types = set() for tile_type in db.get_tile_types(): type_obj = db.get_tile_type(tile_type) for wire in type_obj.get_wires(): wires_in_tile_types.add((tile_type, wire)) for site in type_obj.get_sites(): for site_pin in site.site_pins: if site_pin.wire is None: continue key = (tile_type, site_pin.wire) assert key not in edge_assignments, key edge_assignments[key] = [] with DatabaseCache(args.connection_database, read_only=True) as conn: direct_connections = set() print('{} Processing direct connections.'.format(now())) handle_direction_connections(conn, direct_connections, edge_assignments) wires_not_in_channels = {} c = conn.cursor() print('{} Processing non-channel nodes.'.format(now())) for node_pkey, classification in progressbar.progressbar(c.execute(""" SELECT pkey, classification FROM node WHERE classification != ?; """, (NodeClassification.CHANNEL.value,))): reason = NodeClassification(classification) for (tile, tile_type, wire) in yield_wire_info_from_node(conn, node_pkey): key = (tile_type, wire) # Sometimes nodes in particular tile instances are disconnected, # disregard classification changes if this is the case. if reason != NodeClassification.NULL: if key not in wires_not_in_channels: wires_not_in_channels[key] = reason else: other_reason = wires_not_in_channels[key] assert reason == other_reason, (tile, wire, reason, other_reason) if key in wires_in_tile_types: wires_in_tile_types.remove(key) # List of nodes that are channels. channel_nodes = [] # Map of (tile, wire) to track. This will be used to find channels for pips # that come from EDGES_TO_CHANNEL. channel_wires_to_tracks = {} # Generate track models and verify that wires are either in a channel # or not in a channel. print('{} Creating models from tracks.'.format(now())) for node_pkey, track_pkey in progressbar.progressbar(c.execute(""" SELECT pkey, track_pkey FROM node WHERE classification = ?; """, (NodeClassification.CHANNEL.value,))): assert track_pkey is not None tracks_model, _ = get_track_model(conn, track_pkey) channel_nodes.append(tracks_model) channel_wires_to_tracks[track_pkey] = tracks_model for (tile, tile_type, wire) in yield_wire_info_from_node(conn, node_pkey): tileinfo = grid.gridinfo_at_tilename(tile) key = (tileinfo.tile_type, wire) # Make sure all wires in channels always are in channels assert key not in wires_not_in_channels if key in wires_in_tile_types: wires_in_tile_types.remove(key) # Make sure all wires appear to have been assigned. assert len(wires_in_tile_types) == 0 # Verify that all tracks are sane. for node in channel_nodes: node.verify_tracks() null_tile_wires = set() # Verify that all nodes that are classified as edges to channels have at # least one site, and at least one live connection to a channel. # # If no live connections from the node are present, this node should've # been marked as NULL during channel formation. print('{} Handling edges to channels.'.format(now())) handle_edges_to_channels(conn, null_tile_wires, edge_assignments, channel_wires_to_tracks) print('{} Processing edge assignments.'.format(now())) final_edge_assignments = {} for key, available_pins in progressbar.progressbar(edge_assignments.items()): (tile_type, wire) = key if len(available_pins) == 0: if (tile_type, wire) not in null_tile_wires: # TODO: Figure out what is going on with these wires. Appear to # tile internal connections sometimes? print((tile_type, wire)) final_edge_assignments[key] = [tracks.Direction.RIGHT] continue pins = set(available_pins[0]) for p in available_pins[1:]: pins &= set(p) if len(pins) > 0: final_edge_assignments[key] = [list(pins)[0]] else: # More than 2 pins are required, final the minimal number of pins pins = set() for p in available_pins: pins |= set(p) while len(pins) > 2: pins = list(pins) prev_len = len(pins) for idx in range(len(pins)): pins_subset = list(pins) del pins_subset[idx] pins_subset = set(pins_subset) bad_subset = False for p in available_pins: if len(pins_subset & set(p)) == 0: bad_subset = True break if not bad_subset: pins = list(pins_subset) break # Failed to remove any pins, stop. if len(pins) == prev_len: break final_edge_assignments[key] = pins for key, available_pins in edge_assignments.items(): (tile_type, wire) = key pins = set(final_edge_assignments[key]) for required_pins in available_pins: assert len(pins & set(required_pins)) > 0, ( tile_type, wire, pins, required_pins) pin_directions = {} for key, pins in progressbar.progressbar(final_edge_assignments.items()): (tile_type, wire) = key if tile_type not in pin_directions: pin_directions[tile_type] = {} pin_directions[tile_type][wire] = [pin._name_ for pin in pins] with open(args.pin_assignments, 'w') as f: json.dump({ 'pin_directions': pin_directions, 'direct_connections': [d._asdict() for d in direct_connections], }, f, indent=2) print('{} Flushing database back to file "{}"'.format(now(), args.connection_database))
def main(): mydir = os.path.dirname(__file__) prjxray_db = os.path.abspath( os.path.join(mydir, "..", "..", "third_party", "prjxray-db")) db_types = prjxray.db.get_available_databases(prjxray_db) parser = argparse.ArgumentParser(description=__doc__, fromfile_prefix_chars='@', prefix_chars='-~') parser.add_argument( '--part', choices=[os.path.basename(db_type) for db_type in db_types], help="""Project X-Ray database to use.""") parser.add_argument('--tile', help="""Tile to generate for""") parser.add_argument('--site_directory', help="""Diretory where sites are defined""") parser.add_argument('--output-pb-type', nargs='?', type=argparse.FileType('w'), default=sys.stdout, help="""File to write the output too.""") parser.add_argument('--output-model', nargs='?', type=argparse.FileType('w'), default=sys.stdout, help="""File to write the output too.""") parser.add_argument('--pin_assignments', required=True, type=argparse.FileType('r')) parser.add_argument( '--site_types', required=True, help="Comma seperated list of site types to include in this tile.") parser.add_argument( '--fused_sites', action='store_true', help= "Typically a tile can treat the sites within the tile as independent. For tiles where this is not true, fused sites only imports 1 primatative for the entire tile, which should be named the same as the tile type." ) args = parser.parse_args() db = prjxray.db.Database(os.path.join(prjxray_db, args.part)) tile = db.get_tile_type(args.tile) # Wires sink to a site within the tile are input wires. input_wires = set() # Wires source from a site within the tile are output wires. output_wires = set() if not args.fused_sites: site_type_instances = {} for s in args.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) imported_site_types = set() ignored_site_types = set() for site in tile.get_sites(): site_type = db.get_site_type(site.type) if site.type not in site_type_instances: ignored_site_types.add(site.type) continue imported_site_types.add(site.type) for site_pin in site.site_pins: site_type_pin = site_type.get_site_pin(site_pin.name) if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN: if site_pin.wire is not None: input_wires.add(site_pin.wire) elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT: if site_pin.wire is not None: output_wires.add(site_pin.wire) else: assert False, site_type_pin.direction # Make sure all requested site types actually get imported. assert len(set(site_type_instances.keys()) - imported_site_types) == 0, (site_type_instances.keys(), imported_site_types) for ignored_site_type in ignored_site_types: print( '*** WARNING *** Ignored site type {} in tile type {}'.format( ignored_site_type, args.tile), file=sys.stderr) else: for site in tile.get_sites(): site_type = db.get_site_type(site.type) for site_pin in site.site_pins: site_type_pin = site_type.get_site_pin(site_pin.name) if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN: if site_pin.wire is not None: input_wires.add(site_pin.wire) elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT: if site_pin.wire is not None: output_wires.add(site_pin.wire) else: assert False, site_type_pin.direction site_model = args.site_directory + "/{0}/{1}.model.xml" site_pbtype = args.site_directory + "/{0}/{1}.pb_type.xml" xi_url = "http://www.w3.org/2001/XInclude" ET.register_namespace('xi', xi_url) xi_include = "{%s}include" % xi_url ########################################################################## # Generate the model.xml file # ########################################################################## model_xml = ET.Element( 'models', nsmap={'xi': xi_url}, ) def add_model_include(site_type, instance_name): ET.SubElement( model_xml, xi_include, { 'href': site_model.format(site_type.lower(), instance_name.lower()), 'xpointer': "xpointer(models/child::node())" }) if not args.fused_sites: site_types = set(site.type for site in tile.get_sites()) for site_type in site_types: if site_type in ignored_site_types: continue for instance in site_type_instances[site_type]: add_model_include(site_type, instance) else: fused_site_name = args.tile.lower() add_model_include(fused_site_name, fused_site_name) model_str = ET.tostring(model_xml, pretty_print=True).decode('utf-8') args.output_model.write(model_str) args.output_model.close() ########################################################################## # Generate the pb_type.xml file # ########################################################################## def add_direct(xml, input, output): ET.SubElement( xml, 'direct', { 'name': '{}_to_{}'.format(input, output), 'input': input, 'output': output }) tile_name = "BLK_TI-{}".format(args.tile) pb_type_xml = ET.Element( 'pb_type', { 'name': tile_name, }, nsmap={'xi': xi_url}, ) fc_xml = ET.SubElement(pb_type_xml, 'fc', { 'in_type': 'abs', 'in_val': '2', 'out_type': 'abs', 'out_val': '2', }) interconnect_xml = ET.Element('interconnect') pb_type_xml.append(ET.Comment(" Tile Inputs ")) # Input definitions for the TILE for name in sorted(input_wires): input_type = 'input' if 'CLK' in name: input_type = 'clock' ET.SubElement( pb_type_xml, input_type, { 'name': name, 'num_pins': '1' }, ) pb_type_xml.append(ET.Comment(" Tile Outputs ")) for name in sorted(output_wires): # Output definitions for the TILE ET.SubElement( pb_type_xml, 'output', { 'name': name, 'num_pins': '1' }, ) pb_type_xml.append(ET.Comment(" Internal Sites ")) cell_names = {} if not args.fused_sites: site_type_count = {} site_prefixes = {} cells_idx = [] site_type_ports = {} for idx, site in enumerate(tile.get_sites()): if site.type in ignored_site_types: continue if site.type not in site_type_count: site_type_count[site.type] = 0 site_prefixes[site.type] = [] cells_idx.append(site_type_count[site.type]) site_type_count[site.type] += 1 site_prefix = '{}_X{}'.format(site.type, site.x) site_instance = site_type_instances[site.type][cells_idx[idx]] print(site_prefix, site_instance) site_type_path = site_pbtype.format(site.type.lower(), site_instance.lower()) cell_pb_type = ET.ElementTree() root_element = cell_pb_type.parse(site_type_path) cell_names[site_instance] = 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_instance not in site_type_ports, ( site_instance, site_type_ports.keys()) site_type_ports[site_instance] = 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') 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 idx, site in enumerate(tile.get_sites()): if site.type in ignored_site_types: continue site_idx = cells_idx[idx] site_instance = site_type_instances[site.type][site_idx] site_name = cell_names[site_instance] site_type = db.get_site_type(site.type) interconnect_xml.append(ET.Comment(" Tile->Site ")) for site_pin in sorted(site.site_pins, key=lambda site_pin: site_pin.name): if site_pin.wire is None: continue port = find_port(site_pin.name, site_type_ports[site_instance]) 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_type_pin = site_type.get_site_pin(site_pin.name) if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN: add_direct(interconnect_xml, input=object_ref(tile_name, site_pin.wire), output=object_ref(site_name, **port)) elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT: pass else: assert False, site_type_pin.direction interconnect_xml.append(ET.Comment(" Site->Tile ")) for site_pin in sorted(site.site_pins, key=lambda site_pin: site_pin.name): if site_pin.wire is None: continue port = find_port(site_pin.name, site_type_ports[site_instance]) if port is None: continue site_type_pin = site_type.get_site_pin(site_pin.name) if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN: pass elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT: add_direct( interconnect_xml, input=object_ref(site_name, **port), output=object_ref(tile_name, site_pin.wire), ) else: assert False, site_type_pin.direction else: site_type_ports = {} site_type_path = site_pbtype.format(fused_site_name, fused_site_name) cell_pb_type = ET.ElementTree() root_element = cell_pb_type.parse(site_type_path) 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']) 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())", }) site_name = root_element.attrib['name'] def fused_port_name(site, site_pin): return '{}_{}_{}'.format(site.prefix, site.name, site_pin.name) for idx, site in enumerate(tile.get_sites()): site_type = db.get_site_type(site.type) interconnect_xml.append(ET.Comment(" Tile->Site ")) for site_pin in sorted(site.site_pins, key=lambda site_pin: site_pin.name): if site_pin.wire is None: continue port_name = fused_port_name(site, site_pin) port = find_port(port_name, ports) if port is None: print( "*** WARNING *** Didn't find port for name {} for site type {}" .format(port_name, site.type), file=sys.stderr) continue site_type_pin = site_type.get_site_pin(site_pin.name) if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN: add_direct(interconnect_xml, input=object_ref(tile_name, site_pin.wire), output=object_ref(site_name, **port)) elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT: pass else: assert False, site_type_pin.direction interconnect_xml.append(ET.Comment(" Site->Tile ")) for site_pin in sorted(site.site_pins, key=lambda site_pin: site_pin.name): if site_pin.wire is None: continue port = find_port(fused_port_name(site, site_pin), ports) if port is None: # Already warned above continue site_type_pin = site_type.get_site_pin(site_pin.name) if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN: pass elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT: add_direct( interconnect_xml, input=object_ref(site_name, **port), output=object_ref(tile_name, site_pin.wire), ) else: assert False, site_type_pin.direction pb_type_xml.append(interconnect_xml) ET.SubElement(pb_type_xml, 'switchblock_locations', { 'pattern': 'all', }) pinlocations_xml = ET.SubElement(pb_type_xml, 'pinlocations', { 'pattern': 'custom', }) if len(input_wires) > 0 or len(output_wires) > 0: pin_assignments = json.load(args.pin_assignments) sides = {} for pin in input_wires | output_wires: for side in pin_assignments['pin_directions'][args.tile][pin]: if side not in sides: sides[side] = [] sides[side].append(object_ref(tile_name, pin)) for side, pins in sides.items(): ET.SubElement(pinlocations_xml, 'loc', { 'side': side.lower(), }).text = ' '.join(pins) metadata_xml = ET.SubElement(pb_type_xml, 'metadata') ET.SubElement(metadata_xml, 'meta', { 'name': 'fasm_prefix', }).text = args.tile direct_pins = set() for direct in pin_assignments['direct_connections']: if direct['from_pin'].split('.')[0] == args.tile: direct_pins.add(direct['from_pin'].split('.')[1]) if direct['to_pin'].split('.')[0] == args.tile: direct_pins.add(direct['to_pin'].split('.')[1]) for fc_override in direct_pins: ET.SubElement(fc_xml, 'fc_override', { 'fc_type': 'frac', 'fc_val': '0.0', 'port_name': fc_override, }) pb_type_str = ET.tostring(pb_type_xml, pretty_print=True).decode('utf-8') args.output_pb_type.write(pb_type_str) args.output_pb_type.close()
def main(): parser = argparse.ArgumentParser() parser.add_argument('--db_root', required=True, help='Project X-Ray Database') parser.add_argument('--connection_database', help='Database of fabric connectivity', required=True) parser.add_argument('--pin_assignments', help='Pin assignments JSON', required=True) parser.add_argument( '--synth_tiles', help= 'If using an ROI, synthetic tile defintion from prjxray-arch-import') args = parser.parse_args() pool = multiprocessing.Pool(20) db = prjxray.db.Database(args.db_root) grid = db.grid() with DatabaseCache(args.connection_database) as conn: with open(args.pin_assignments) as f: pin_assignments = json.load(f) tile_wires = [] for tile_type, wire_map in pin_assignments['pin_directions'].items(): for wire in wire_map.keys(): tile_wires.append((tile_type, wire)) for tile_type, wire in progressbar.progressbar(tile_wires): pins = [ direction_to_enum(pin) for pin in pin_assignments['pin_directions'][tile_type][wire] ] add_graph_nodes_for_pins(conn, tile_type, wire, pins) if args.synth_tiles: use_roi = True with open(args.synth_tiles) as f: synth_tiles = json.load(f) roi = Roi( db=db, x1=synth_tiles['info']['GRID_X_MIN'], y1=synth_tiles['info']['GRID_Y_MIN'], x2=synth_tiles['info']['GRID_X_MAX'], y2=synth_tiles['info']['GRID_Y_MAX'], ) print('{} generating routing graph for ROI.'.format(now())) else: use_roi = False output_only_nodes = set() input_only_nodes = set() find_pip = create_find_pip(conn) find_wire = create_find_wire(conn) find_connector = create_find_connector(conn) print('{} Finding nodes belonging to ROI'.format(now())) if use_roi: for loc in progressbar.progressbar(grid.tile_locations()): gridinfo = grid.gridinfo_at_loc(loc) tile_name = grid.tilename_at_loc(loc) if tile_name in synth_tiles['tiles']: assert len(synth_tiles['tiles'][tile_name]['pins']) == 1 for pin in synth_tiles['tiles'][tile_name]['pins']: _, _, node_pkey = find_wire(tile_name, gridinfo.tile_type, pin['wire']) if pin['port_type'] == 'input': # This track can output be used as a sink. input_only_nodes |= set((node_pkey, )) elif pin['port_type'] == 'output': # This track can output be used as a src. output_only_nodes |= set((node_pkey, )) else: assert False, pin c = conn.cursor() c.execute('SELECT pkey FROM switch WHERE name = ?;', ('routing', )) switch_pkey = c.fetchone()[0] edges = [] edge_set = set() for loc in progressbar.progressbar(grid.tile_locations()): gridinfo = grid.gridinfo_at_loc(loc) tile_name = grid.tilename_at_loc(loc) # Not a synth node, check if in ROI. if use_roi and not roi.tile_in_roi(loc): continue tile_type = db.get_tile_type(gridinfo.tile_type) for pip in tile_type.get_pips(): if pip.is_pseudo: continue if not pip.is_directional: # TODO: Handle bidirectional pips? continue connections = make_connection( conn=conn, input_only_nodes=input_only_nodes, output_only_nodes=output_only_nodes, find_pip=find_pip, find_wire=find_wire, find_connector=find_connector, tile_name=tile_name, loc=loc, tile_type=gridinfo.tile_type, pip=pip, switch_pkey=switch_pkey) if connections: # TODO: Skip duplicate connections, until they have unique # switches for connection in connections: key = tuple(connection[0:3]) if key in edge_set: continue edge_set.add(key) edges.append(connection) print('{} Created {} edges, inserting'.format(now(), len(edges))) c.execute("""BEGIN EXCLUSIVE TRANSACTION;""") for edge in progressbar.progressbar(edges): c.execute( """ INSERT INTO graph_edge( src_graph_node_pkey, dest_graph_node_pkey, switch_pkey, tile_pkey, pip_in_tile_pkey) VALUES (?, ?, ?, ?, ?)""", edge) c.execute("""COMMIT TRANSACTION;""") print('{} Inserted edges'.format(now())) c.execute( """CREATE INDEX src_node_index ON graph_edge(src_graph_node_pkey);""" ) c.execute( """CREATE INDEX dest_node_index ON graph_edge(dest_graph_node_pkey);""" ) c.connection.commit() print('{} Indices created, marking track liveness'.format(now())) mark_track_liveness(conn, pool, input_only_nodes, output_only_nodes) print('{} Flushing database back to file "{}"'.format( now(), args.connection_database))
def classify_node(self, db, grid, wire_to_nodes): if len(self.pips) + len(self.sites) <= 1: # Some nodes don't go anywhere. return NodeClassification(type='NULL', edge_with_mux=None) if len(self.pips) == 1 and len(self.sites) == 0: # Some nodes don't go anywhere. return NodeClassification(type='NULL', edge_with_mux=None) if len(self.pips) > 1: if len(self.sites) == 0: return NodeClassification(type='CHANNEL', edge_with_mux=None) else: if len(self.sites) == 1: return NodeClassification(type='EDGES_TO_CHANNEL', edge_with_mux=None) else: assert False, (self.pips, self.sites, self.node) if len(self.sites) == 2 and len(self.pips) == 0: return NodeClassification(type='EDGE_WITH_SHORT', edge_with_mux=None) if len(self.sites) == 1 and len(self.pips) == 1: # This could be a site pin -> pip -> site pin, check. tile, pip, wire = self.pips[0] tileinfo = grid.gridinfo_at_tilename(tile) tile_type = db.get_tile_type(tileinfo.tile_type) for tile_pip in tile_type.get_pips(): if tile_pip.name == pip: if tile_pip.net_to == wire: other_wire = tile_pip.net_from other_node = wire_to_nodes[(tile, other_wire)] source_node = other_node.node destination_node = self.node elif tile_pip.net_from == wire: other_wire = tile_pip.net_to other_node = wire_to_nodes[(tile, other_wire)] source_node = self.node destination_node = other_node.node else: assert False, (tile, pip, wire, tile_pip) if len(other_node.sites) == 1 and len( other_node.pips) == 1: edge_with_mux = EdgeWithMux( source_node=tuple(sorted(source_node)), pip=pip, destination_node=tuple(sorted(destination_node)), ) return NodeClassification(type='EDGE_WITH_MUX', edge_with_mux=edge_with_mux) elif len(other_node.sites) == 0 and len( other_node.pips) == 1: # Sometimes (e.g. top of carry chain) will end up with # site pin -> pip -> nothing. return NodeClassification(type='NULL', edge_with_mux=None) else: break # This node is an edge to/from a channel, but not a # channel itself. return NodeClassification(type='EDGES_TO_CHANNEL', edge_with_mux=None) assert False, (self.pips, self.sites, self.node)
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=True) 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'] = {} with open(args.roi) as f: j = json.load(f) 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'], ) with DatabaseCache(args.connection_database, read_only=True) as conn: synth_tiles['info'] = j['info'] vbrk_in_use = set() for port in j['ports']: if port['name'].startswith('dout['): port_type = 'input' is_clock = False elif port['name'].startswith('din['): is_clock = False port_type = 'output' elif port['name'].startswith('clk'): port_type = 'output' is_clock = True else: assert False, port tile, wire = port['wire'].split('/') vbrk_in_use.add(tile) # Make sure connecting wire is not in ROI! loc = g.loc_of_tilename(tile) if 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, tile vpr_loc = map_tile_to_vpr_coord(conn, tile) if tile not in synth_tiles['tiles']: synth_tiles['tiles'][tile] = { 'pins': [], 'loc': vpr_loc, } 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, }) # 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 vbrk_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, }, ], } 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, }, ], } with open(args.synth_tiles, 'w') as f: json.dump(synth_tiles, f, indent=2)
def main(): parser = argparse.ArgumentParser() parser.add_argument('--db_root', help='Project X-Ray Database', required=True) parser.add_argument('--channels', help='Input JSON defining channel assignments', required=True) parser.add_argument( '--pin_assignments', help= 'Output JSON assigning pins to tile types and direction connections', required=True) args = parser.parse_args() db = prjxray.db.Database(args.db_root) grid = db.grid() edge_assignments = {} wires_in_tile_types = set() for tile_type in db.get_tile_types(): type_obj = db.get_tile_type(tile_type) for wire in type_obj.get_wires(): wires_in_tile_types.add((tile_type, wire)) for site in type_obj.get_sites(): for site_pin in site.site_pins: if site_pin.wire is None: continue key = (tile_type, site_pin.wire) assert key not in edge_assignments, key edge_assignments[key] = [] print('{} Reading channel data'.format(datetime.datetime.now())) with open(args.channels) as f: channels = json.load(f) print('{} Done reading channel data'.format(datetime.datetime.now())) direct_connections = set() # Edges with mux should have one source tile and one destination_tile. # The pin from the source_tile should face the destination_tile. # # It is expected that all edges_with_mux will lies in a line (e.g. X only or # Y only). for edge_with_mux in progressbar.progressbar(channels['edges_with_mux']): source_tile = None source_tile_type = None source_wire = None destination_tile = None destination_tile_type = None destination_wire = None for tile, wire in edge_with_mux['source_node']: tileinfo = grid.gridinfo_at_tilename(tile) tile_type = db.get_tile_type(tileinfo.tile_type) wire_info = tile_type.get_wire_info(wire) if len(wire_info.sites) == 1: assert source_tile is None, (tile, wire, source_tile) source_tile = tile source_tile_type = tileinfo.tile_type source_wire = wire for tile, wire in edge_with_mux['destination_node']: tileinfo = grid.gridinfo_at_tilename(tile) tile_type = db.get_tile_type(tileinfo.tile_type) wire_info = tile_type.get_wire_info(wire) if len(wire_info.sites) == 1: assert destination_tile is None, (tile, wire, destination_tile, wire_info) destination_tile = tile destination_tile_type = tileinfo.tile_type destination_wire = wire assert source_tile is not None assert destination_tile is not None source_loc = grid.loc_of_tilename(source_tile) destination_loc = grid.loc_of_tilename(destination_tile) assert source_loc.grid_x == destination_loc.grid_x or source_loc.grid_y == destination_loc.grid_y, ( source_tile, destination_tile, edge_with_mux['pip']) direct_connections.add( DirectConnection( from_pin='{}.{}'.format(source_tile_type, source_wire), to_pin='{}.{}'.format(destination_tile_type, destination_wire), switch_name='routing', x_offset=destination_loc.grid_x - source_loc.grid_x, y_offset=destination_loc.grid_y - source_loc.grid_y, )) if destination_loc.grid_x == source_loc.grid_x: if destination_loc.grid_y > source_loc.grid_y: source_dir = tracks.Direction.TOP destination_dir = tracks.Direction.BOTTOM else: source_dir = tracks.Direction.BOTTOM destination_dir = tracks.Direction.TOP else: if destination_loc.grid_x > source_loc.grid_x: source_dir = tracks.Direction.RIGHT destination_dir = tracks.Direction.LEFT else: source_dir = tracks.Direction.LEFT destination_dir = tracks.Direction.RIGHT edge_assignments[(source_tile_type, source_wire)].append( (source_dir, )) edge_assignments[(destination_tile_type, destination_wire)].append( (destination_dir, )) wires_not_in_channels = {} for node in progressbar.progressbar(channels['node_not_in_channels']): reason = node['classification'] for tile, wire in node['wires']: tileinfo = grid.gridinfo_at_tilename(tile) key = (tileinfo.tile_type, wire) # Sometimes nodes in particular tile instances are disconnected, # disregard classification changes if this is the case. if reason != 'NULL': if key not in wires_not_in_channels: wires_not_in_channels[key] = reason else: other_reason = wires_not_in_channels[key] assert reason == other_reason, (tile, wire, reason, other_reason) if key in wires_in_tile_types: wires_in_tile_types.remove(key) # List of nodes that are channels. channel_nodes = [] # Map of (tile, wire) to track. This will be used to find channels for pips # that come from EDGES_TO_CHANNEL. channel_wires_to_tracks = {} # Generate track models and verify that wires are either in a channel # or not in a channel. for channel in progressbar.progressbar(channels['channels']): track_list = [] for track in channel['tracks']: track_list.append(tracks.Track(**track)) tracks_model = tracks.Tracks(track_list, channel['track_connections']) channel_nodes.append(tracks_model) for tile, wire in channel['wires']: tileinfo = grid.gridinfo_at_tilename(tile) key = (tileinfo.tile_type, wire) # Make sure all wires in channels always are in channels assert key not in wires_not_in_channels if key in wires_in_tile_types: wires_in_tile_types.remove(key) channel_wires_to_tracks[(tile, wire)] = tracks_model # Make sure all wires appear to have been assigned. assert len(wires_in_tile_types) == 0 # Verify that all tracks are sane. for node in channel_nodes: node.verify_tracks() null_tile_wires = set() # Verify that all nodes that are classified as edges to channels have at # least one site, and at least one live connection to a channel. # # If no live connections from the node are present, this node should've # been marked as NULL during channel formation. for node in progressbar.progressbar(channels['node_not_in_channels']): reason = node['classification'] assert reason != 'EDGE_WITH_SHORT' if reason == 'NULL': for tile, wire in node['wires']: tileinfo = grid.gridinfo_at_tilename(tile) tile_type = db.get_tile_type(tileinfo.tile_type) null_tile_wires.add((tileinfo.tile_type, wire)) if reason == 'EDGES_TO_CHANNEL': num_sites = 0 for tile, wire in node['wires']: tileinfo = grid.gridinfo_at_tilename(tile) loc = grid.loc_of_tilename(tile) tile_type = db.get_tile_type(tileinfo.tile_type) wire_info = tile_type.get_wire_info(wire) num_sites += len(wire_info.sites) for pip in wire_info.pips: other_wire = prjxray.tile.get_other_wire_from_pip( tile_type.get_pip_by_name(pip), wire) key = (tile, other_wire) if key in channel_wires_to_tracks: tracks_model = channel_wires_to_tracks[key] if len(wire_info.sites) > 0: available_pins = set( pin_dir for _, pin_dir in tracks_model. get_tracks_for_wire_at_coord((loc.grid_x, loc.grid_y))) edge_assignments[(tileinfo.tile_type, wire)].append(available_pins) final_edge_assignments = {} for (tile_type, wire), available_pins in progressbar.progressbar( edge_assignments.items()): if len(available_pins) == 0: if (tile_type, wire) not in null_tile_wires: # TODO: Figure out what is going on with these wires. Appear to # tile internal connections sometimes? print((tile_type, wire)) final_edge_assignments[(tile_type, wire)] = [tracks.Direction.RIGHT] continue pins = set(available_pins[0]) for p in available_pins[1:]: pins &= set(p) if len(pins) > 0: final_edge_assignments[(tile_type, wire)] = [list(pins)[0]] else: # More than 2 pins are required, final the minimal number of pins pins = set() for p in available_pins: pins |= set(p) while len(pins) > 2: pins = list(pins) prev_len = len(pins) for idx in range(len(pins)): pins_subset = list(pins) del pins_subset[idx] pins_subset = set(pins_subset) bad_subset = False for p in available_pins: if len(pins_subset & set(p)) == 0: bad_subset = True break if not bad_subset: pins = list(pins_subset) break # Failed to remove any pins, stop. if len(pins) == prev_len: break final_edge_assignments[(tile_type, wire)] = pins for (tile_type, wire), available_pins in edge_assignments.items(): pins = set(final_edge_assignments[(tile_type, wire)]) for required_pins in available_pins: assert len(pins & set(required_pins)) > 0, (tile_type, wire, pins, required_pins) pin_directions = {} for (tile_type, wire), pins in final_edge_assignments.items(): if tile_type not in pin_directions: pin_directions[tile_type] = {} pin_directions[tile_type][wire] = [pin._name_ for pin in pins] with open(args.pin_assignments, 'w') as f: json.dump( { 'pin_directions': pin_directions, 'direct_connections': [d._asdict() for d in direct_connections], }, f, indent=2)