def create_const_connectors(conn): c = conn.cursor() c.execute(""" SELECT vcc_track_pkey, gnd_track_pkey FROM constant_sources; """) vcc_track_pkey, gnd_track_pkey = c.fetchone() const_connectors = {} const_connectors[0] = Connector(conn=conn, tracks=get_track_model( conn, gnd_track_pkey)) const_connectors[1] = Connector(conn=conn, tracks=get_track_model( conn, vcc_track_pkey)) return const_connectors
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) edge_assignments = {} with DatabaseCache(args.connection_database, read_only=True) as conn: c = conn.cursor() edge_assignments, wires_in_tile_types = initialize_edge_assignments( db, 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_utils.progressbar( c.execute( """ SELECT pkey, classification FROM node WHERE classification != ?; """, (NodeClassification.CHANNEL.value, ))): reason = NodeClassification(classification) for (tile_type, wire) in yield_logical_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_type, 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_utils.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_type, wire) in yield_logical_wire_info_from_node(conn, node_pkey): key = (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. if len(wires_in_tile_types) > 0: for tile_type, wire in sorted(wires_in_tile_types): print(tile_type, wire) 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_utils.progressbar( edge_assignments.items()): (tile_type, wire) = key available_pins = [pins for pins in available_pins if len(pins) > 0] 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: if len(required_pins) == 0: continue assert len(pins & set(required_pins)) > 0, (tile_type, wire, pins, required_pins, available_pins) pin_directions = {} for key, pins in progressbar_utils.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 find_connector(wire_pkey, node_pkey): """ Finds Connector for a wire and node in the database. Args: wire_pkey (int): Primary key into wire table of target wire node_pkey (int): Primary key into node table of parent node of specified wire. Returns: None if wire is disconnected, otherwise returns Connector objet. """ # Find all graph_nodes for this node. c.execute( """ SELECT pkey, track_pkey, graph_node_type, x_low, x_high, y_low, y_high FROM graph_node WHERE node_pkey = ?;""", (node_pkey, )) graph_nodes = c.fetchall() # If there are no graph nodes, this wire is likely disconnected. if len(graph_nodes) == 0: return # If this is a track (e.g. track_pkey is not NULL), then verify # all graph_nodes for the specified node belong to the same track, # and then retrieved and return the connector for the track. track_pkey = graph_nodes[0][1] if track_pkey is not None: for node in graph_nodes: assert node[1] == track_pkey return Connector(tracks=get_track_model(conn, track_pkey)) # This is not a track, so it must be a site pin. Make sure the # graph_nodes share a type and verify that it is in fact a site pin. node_type = graph2.NodeType(graph_nodes[0][2]) for node in graph_nodes: assert node_type == graph2.NodeType(node[2]) assert node_type in [graph2.NodeType.IPIN, graph2.NodeType.OPIN] if node_type == graph2.NodeType.IPIN: site_pin_direction = SitePinDirection.IN elif node_type == graph2.NodeType.OPIN: site_pin_direction = SitePinDirection.OUT else: assert False, node_type # Build the edge_map (map of edge direction to graph node). c.execute( """ SELECT top_graph_node_pkey, bottom_graph_node_pkey, left_graph_node_pkey, right_graph_node_pkey FROM wire WHERE node_pkey = ?;""", (node_pkey, )) all_graph_node_pkeys = c.fetchall() graph_node_pkeys = None for keys in all_graph_node_pkeys: if any(keys): assert graph_node_pkeys is None graph_node_pkeys = keys # This wire may not have an connections, if so return now. if graph_node_pkeys is None: return edge_map = {} for edge, graph_node in zip( ( tracks.Direction.TOP, tracks.Direction.BOTTOM, tracks.Direction.LEFT, tracks.Direction.RIGHT, ), graph_node_pkeys, ): if graph_node is not None: edge_map[edge] = graph_node assert len(edge_map) == len(graph_nodes), (edge_map, graph_node_pkeys, graph_nodes) # Make sure that all graph nodes for this wire are in the edge_map # and at the same grid coordinate. x = graph_nodes[0][3] y = graph_nodes[0][5] for pkey, _, _, x_low, x_high, y_low, y_high in graph_nodes: assert x == x_low, (wire_pkey, node_pkey, x, x_low, x_high) assert x == x_high, (wire_pkey, node_pkey, x, x_low, x_high) assert y == y_low, (wire_pkey, node_pkey, y, y_low, y_high) assert y == y_high, (wire_pkey, node_pkey, y, y_low, y_high) assert pkey in edge_map.values(), (pkey, edge_map) return Connector(pins=Pins( edge_map=edge_map, x=x, y=y, site_pin_direction=site_pin_direction, ))
def add_synthetic_edges(conn, graph, node_mapping, grid, synth_tiles): cur = conn.cursor() delayless_switch = graph.get_switch_id('__vpr_delayless_switch__') for tile_name, synth_tile in synth_tiles['tiles'].items(): assert len(synth_tile['pins']) == 1 for pin in synth_tile['pins']: if pin['port_type'] in ['input', 'output']: wire_pkey = get_wire_pkey(conn, tile_name, pin['wire']) cur.execute( """ SELECT track_pkey FROM node WHERE pkey = ( SELECT node_pkey FROM wire WHERE pkey = ? );""", (wire_pkey, )) (track_pkey, ) = cur.fetchone() assert track_pkey is not None, (tile_name, pin['wire'], wire_pkey) elif pin['port_type'] == 'VCC': cur.execute('SELECT vcc_track_pkey FROM constant_sources') (track_pkey, ) = cur.fetchone() elif pin['port_type'] == 'GND': cur.execute('SELECT gnd_track_pkey FROM constant_sources') (track_pkey, ) = cur.fetchone() else: assert False, pin['port_type'] tracks_model, track_nodes = get_track_model(conn, track_pkey) option = list( tracks_model.get_tracks_for_wire_at_coord( tuple(synth_tile['loc'])).values()) assert len(option) > 0, (pin, len(option)) if pin['port_type'] == 'input': tile_type = 'SYN-OUTPAD' wire = 'outpad' elif pin['port_type'] == 'output': tile_type = 'SYN-INPAD' wire = 'inpad' elif pin['port_type'] == 'VCC': tile_type = 'SYN-VCC' wire = 'VCC' elif pin['port_type'] == 'GND': tile_type = 'SYN-GND' wire = 'GND' else: assert False, pin track_node = track_nodes[option[0]] assert track_node in node_mapping, (track_node, track_pkey) pin_name = graph.create_pin_name_from_tile_type_and_pin( tile_type, wire) pin_node = graph.get_nodes_for_pin(tuple(synth_tile['loc']), pin_name) if pin['port_type'] == 'input': graph.add_edge( src_node=node_mapping[track_node], sink_node=pin_node[0][0], switch_id=delayless_switch, name='synth_{}_{}'.format(tile_name, pin['wire']), ) elif pin['port_type'] in ['VCC', 'GND', 'output']: graph.add_edge( src_node=pin_node[0][0], sink_node=node_mapping[track_node], switch_id=delayless_switch, name='synth_{}_{}'.format(tile_name, pin['wire']), ) else: assert False, pin
def add_synthetic_edges(conn, graph, node_mapping, grid, synth_tiles): c = conn.cursor() routing_switch = graph.get_switch_id('routing') for loc in grid.tile_locations(): 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']: wire_pkey = get_wire_pkey(conn, tile_name, pin['wire']) c.execute( """ SELECT track_pkey FROM node WHERE pkey = ( SELECT node_pkey FROM wire WHERE pkey = ? );""", (wire_pkey, )) (track_pkey, ) = c.fetchone() assert track_pkey is not None, (tile_name, pin['wire'], wire_pkey) tracks_model, track_nodes = get_track_model(conn, track_pkey) 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]] assert track_node in node_mapping, (track_node, track_pkey) 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=node_mapping[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=node_mapping[track_node], switch_id=routing_switch, name='synth_{}_{}'.format(tile_name, pin['wire']), ) else: assert False, pin