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())" })
def add_model_include(self, site_type, instance_name): ET.SubElement( self.model_xml, XI_INCLUDE, { 'href': self.site_model.format(site_type.lower(), instance_name.lower()), 'xpointer': "xpointer(models/child::node())" })
def import_tile_from_database(conn, args): """ Create a root-level pb_type using the site pins and sites from the database. """ # 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() cur = conn.cursor() cur2 = conn.cursor() cur.execute("SELECT pkey FROM tile_type WHERE name = ?", (args.tile, )) tile_type_pkey = cur.fetchone()[0] # Find instances of sites, sorted by their original tile type. # Then choice the first of each site type as the wire set. # This ensures a unique and internally consistent site set for analyzing # connectivity. # # Note: This does assume that only one instance of each site is present # in each tile, which is checked. sites = {} sites_in_tiles = set() cur.execute( """ SELECT site.site_type_pkey, wire_in_tile.site_pkey, wire_in_tile.phy_tile_type_pkey FROM wire_in_tile INNER JOIN site ON site.pkey = wire_in_tile.site_pkey WHERE wire_in_tile.tile_type_pkey = ? GROUP BY site.site_type_pkey, wire_in_tile.phy_tile_type_pkey ORDER BY wire_in_tile.phy_tile_type_pkey;""", (tile_type_pkey, )) for site_type_pkey, site_pkey, phy_tile_type_pkey in cur: if site_type_pkey not in sites: sites[site_type_pkey] = site_pkey # Verify that assumption that each site type is only used once per tile # is true. key = (site_type_pkey, phy_tile_type_pkey) assert key not in sites_in_tiles, key sites_in_tiles.add(key) # Retrieve initial top-level port names top_level_pins = {} for site_pkey in sites.values(): for wire_in_tile_pkey, wire_name, direction in cur.execute( """ SELECT wire_in_tile.pkey, wire_in_tile.name, site_pin.direction FROM wire_in_tile INNER JOIN site_pin ON wire_in_tile.site_pin_pkey = site_pin.pkey WHERE site_pkey = ?""", (site_pkey, )): direction = prjxray.site_type.SitePinDirection(direction) assert wire_name not in top_level_pins top_level_pins[wire_name] = (site_pkey, wire_in_tile_pkey) if direction == prjxray.site_type.SitePinDirection.IN: assert wire_name not in input_wires input_wires.add(wire_name) elif direction == prjxray.site_type.SitePinDirection.OUT: assert wire_name not in output_wires output_wires.add(wire_name) else: assert False, wire_name ########################################################################## # Generate the model.xml file # ########################################################################## model = ModelXml(f=args.output_model, site_directory=args.site_directory) site_type_instances = parse_site_type_instance(args.site_types) for site_type_pkey in sites: cur.execute("SELECT name FROM site_type WHERE pkey = ?", (site_type_pkey, )) site_type = cur.fetchone()[0] for instance in site_type_instances[site_type]: model.add_model_include(site_type, instance) model.write_model() # Determine which input/output wires connection to other site pins, and no # others. top_level_connections, internal_connections = find_connections( conn, input_wires, output_wires, tile_type_pkey) ########################################################################## # Generate the pb_type.xml file # ########################################################################## 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') site_pbtype = args.site_directory + "/{0}/{1}.pb_type.xml" site_type_count = {} site_prefixes = {} cells_idx = [] ignored_site_types = set() cur.execute( """ WITH tiles_per_tile(num_tiles) AS ( SELECT count() FROM tile_map INNER JOIN tile ON tile_map.tile_pkey = tile.pkey WHERE tile.tile_type_pkey = ? GROUP BY tile_map.tile_pkey ) SELECT max(num_tiles) FROM tiles_per_tile; """, (tile_type_pkey, )) max_tile_count = cur.fetchone()[0] need_tile_prefixs = max_tile_count > 1 site_type_ports = {} cur.execute( """ SELECT DISTINCT site_type.name, site_instance.y_coord % 2 FROM site INNER JOIN site_type ON site.site_type_pkey = site_type.pkey INNER JOIN site_instance ON site.pkey = site_instance.site_pkey WHERE site.pkey IN ( SELECT DISTINCT site_pkey FROM wire_in_tile WHERE tile_type_pkey = ? AND site_pin_pkey IS NOT NULL ) """, (tile_type_pkey, )) for idx, (site_type, site_y) in enumerate(cur): 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 = '{}_Y{}'.format(normalize_site_type(site_type), site_y) # When tiles are merged, additional tile prefixes are required here # to disambiguate which physical tile this site belongs too if need_tile_prefixs: tile_prefix = get_tile_prefix(conn, tile_type_pkey, site_type) site_prefix = '{}.{}'.format(tile_prefix, site_prefix) site_instance = site_type_instances[site_type][cells_idx[idx]] 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) # Iterate over sites in tile cur.execute( """ SELECT site_type.name, site.pkey FROM site INNER JOIN site_type ON site.site_type_pkey = site_type.pkey WHERE site.pkey IN ( SELECT DISTINCT site_pkey FROM wire_in_tile WHERE tile_type_pkey = ? AND site_pin_pkey IS NOT NULL ) GROUP BY site.site_type_pkey, site.x_coord, site.y_coord """, (tile_type_pkey, )) for idx, (site_type, site_pkey) in enumerate(cur): 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] interconnect_xml.append(ET.Comment(" Tile->Site ")) # Iterate over pins in site cur2.execute( """ SELECT site_pin.name, site_pin.direction, wire_in_tile.name FROM wire_in_tile INNER JOIN site_pin ON wire_in_tile.site_pin_pkey = site_pin.pkey WHERE wire_in_tile.tile_type_pkey = ? AND wire_in_tile.site_pkey = ? AND wire_in_tile.site_pin_pkey IS NOT NULL; """, (tile_type_pkey, site_pkey)) site_pins = list(cur2) for site_pin_name, site_pin_direction, site_pin_wire in site_pins: site_pin_direction = prjxray.site_type.SitePinDirection( site_pin_direction) 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 # Sanity check top_level_connections if site_pin_wire not in top_level_connections: continue assert top_level_connections[site_pin_wire] == (site_type, site_pin_name) if site_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_pin_direction == prjxray.site_type.SitePinDirection.OUT: pass else: assert False, site_pin_direction interconnect_xml.append(ET.Comment(" Site->Tile ")) # Iterate over pins in site cur2.execute("") for site_pin_name, site_pin_direction, site_pin_wire in site_pins: site_pin_direction = prjxray.site_type.SitePinDirection( site_pin_direction) port = find_port(site_pin_name, site_type_ports[site_instance]) if port is None: continue # Sanity check top_level_connections if site_pin_wire not in top_level_connections: continue assert top_level_connections[site_pin_wire] == (site_type, site_pin_name) if site_pin_direction == prjxray.site_type.SitePinDirection.IN: pass elif site_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: assert False, site_pin_direction interconnect_xml.append(ET.Comment(" Site->Site ")) for (dest_site_type, dest_site_pin_name), (src_site_type, src_site_pin_name) in \ sorted(internal_connections.items(), key=lambda x: (x[1], x[0])): # Only handling single instance per site type right now assert len(site_type_instances[src_site_type]) == 1 assert len(site_type_instances[dest_site_type]) == 1 src_site_instance = site_type_instances[src_site_type][0] src_port = find_port(src_site_pin_name, site_type_ports[src_site_instance]) src_site_name = cell_names[src_site_instance] if src_port is None: print( "*** WARNING *** Didn't find port for name {} for site type {}" .format(src_site_pin_name, src_site_type), file=sys.stderr) continue dest_site_instance = site_type_instances[dest_site_type][0] dest_port = find_port(dest_site_pin_name, site_type_ports[dest_site_instance]) dest_site_name = cell_names[dest_site_instance] if dest_port is None: print( "*** WARNING *** Didn't find port for name {} for site type {}" .format(dest_site_pin_name, dest_site_type), file=sys.stderr) continue add_direct( interconnect_xml, input=object_ref(src_site_name, **src_port), output=object_ref(dest_site_name, **dest_port), ) pb_type_xml.append(interconnect_xml) write_xml(args.output_pb_type, pb_type_xml)
def create_pb_type(conn, pin_assignments, site_directory, output_directory, pb_type, site_type_pkeys, tile_type_pkeys, site_remaps, site_name_remaps, node_tile_map): cur = conn.cursor() cur2 = conn.cursor() wire_to_site_pin = {} internal_connections = {} top_level_pin_external = set() top_level_wire_external = set() all_pb_type_input_pins = None all_pb_type_output_pins = None for tile_type_pkey in tile_type_pkeys: pb_type_input_pins = set() pb_type_output_pins = set() for node_set in node_tile_map[tile_type_pkey]: ipin_count = 0 opin_count = 0 node_set_has_external = False pins_used_in_node_sets = set() input_pins = set() output_pins = set() for node_pkey in node_set: cur.execute( """ SELECT tile.tile_type_pkey, wire_in_tile.name, site_type.pkey, site_type.name, site_pin.name, site_pin.direction, count() FROM wire INNER JOIN wire_in_tile ON wire.wire_in_tile_pkey = wire_in_tile.pkey INNER JOIN site_pin ON site_pin.pkey = wire_in_tile.site_pin_pkey INNER JOIN tile ON wire.tile_pkey = tile.pkey INNER JOIN site_type ON site_type.pkey = site_pin.site_type_pkey WHERE wire.node_pkey = ? AND wire_in_tile.site_pin_pkey IS NOT NULL GROUP BY site_pin.direction; """, (node_pkey, )) for (wire_tile_type_pkey, wire_name, site_type_pkey, site_type_name, site_pin_name, direction, count) in cur: if wire_tile_type_pkey == tile_type_pkey: if site_type_pkey not in site_type_pkeys: # Remap if a mapping exists site_type_name = site_name_remaps.get( site_type_name, site_type_name) cur2.execute( "SELECT pkey FROM site_type WHERE name = ?", (site_type_name, )) new_site_type_pkey = cur2.fetchone()[0] assert new_site_type_pkey in site_type_pkeys, ( pb_type, tile_type_pkey, node_pkey, site_type_pkey, new_site_type_pkey, site_type_pkeys, site_type_name) direction = prjxray.site_type.SitePinDirection( direction) value = (site_type_name, site_pin_name, direction) if wire_name in wire_to_site_pin: assert value == wire_to_site_pin[wire_name], ( wire_name, value, wire_to_site_pin[wire_name]) else: wire_to_site_pin[wire_name] = value pins_used_in_node_sets.add( (wire_name, site_type_name, site_pin_name)) if direction == prjxray.site_type.SitePinDirection.IN: output_pins.add(wire_name) pb_type_output_pins.add( (site_type_name, site_pin_name)) opin_count += count elif direction == prjxray.site_type.SitePinDirection.OUT: input_pins.add(wire_name) pb_type_input_pins.add( (site_type_name, site_pin_name)) ipin_count += count else: assert False, (node_pkey, direction) else: node_set_has_external = True assert len(input_pins) in [0, 1], input_pins if ipin_count == 0 or opin_count == 0 or node_set_has_external or len( site_type_pkeys) == 1: # This node set is connected externally, mark as such for wire_name, site_type_name, site_pin_name in pins_used_in_node_sets: top_level_wire_external.add(wire_name) top_level_pin_external.add((site_type_name, site_pin_name)) if len(site_type_pkeys) == 1: continue if ipin_count > 0 and opin_count > 0: # TODO: Add check that pips and site pins on these internal # connections are 0 delay. assert len(input_pins) == 1 input_wire = input_pins.pop() for wire_name in output_pins: k = wire_to_site_pin[wire_name] v = wire_to_site_pin[input_wire] if k in internal_connections: assert v == internal_connections[k], ( v, internal_connections[k]) else: internal_connections[k] = v pb_type_input_pins = set(v for v in pb_type_input_pins if v in top_level_pin_external) pb_type_output_pins = set(v for v in pb_type_output_pins if v in top_level_pin_external) if all_pb_type_input_pins is None: all_pb_type_input_pins = pb_type_input_pins all_pb_type_output_pins = pb_type_output_pins else: all_pb_type_input_pins &= pb_type_input_pins all_pb_type_output_pins &= pb_type_output_pins ########################################################################## # Generate the model.xml file # ########################################################################## model = ModelXml(f=os.path.join(output_directory, pb_type.lower(), '{}.model.xml'.format(pb_type.lower())), site_directory=site_directory) for site_type_pkey in site_type_pkeys: cur.execute("SELECT name FROM site_type WHERE pkey = ?", (site_type_pkey, )) site_type = cur.fetchone()[0] model.add_model_include(site_type, site_type) model.write_model() ########################################################################## # Generate the pb_type.xml file # ########################################################################## pb_type_xml = start_pb_type( pb_type, pin_assignments, ['{}_{}'.format(site, pin) for site, pin in all_pb_type_output_pins], ['{}_{}'.format(site, pin) for site, pin in all_pb_type_input_pins], ) interconnect_xml = ET.Element('interconnect') site_pbtype = site_directory + "/{0}/{1}.pb_type.xml" site_prefixes = get_tile_prefixes(conn, tile_type_pkeys, site_type_pkeys, site_remaps) cell_names = {} site_type_ports = {} for site_type_pkey in site_type_pkeys: cur.execute("SELECT name FROM site_type WHERE pkey = ?", (site_type_pkey, )) site_type = cur.fetchone()[0] site_prefix = site_prefixes[site_type_pkey] site_type_path = site_pbtype.format(site_type.lower(), site_type.lower()) cell_pb_type = ET.ElementTree() root_element = cell_pb_type.parse(site_type_path) cell_names[site_type] = root_element.attrib['name'] ports = {} for inputs in root_element.iter('input'): ports[inputs.attrib['name']] = int(inputs.attrib['num_pins']) for clocks in root_element.iter('clock'): ports[clocks.attrib['name']] = int(clocks.attrib['num_pins']) for outputs in root_element.iter('output'): ports[outputs.attrib['name']] = int(outputs.attrib['num_pins']) assert site_type not in site_type_ports, (site_type, site_type_ports.keys()) site_type_ports[site_type] = ports attrib = dict(root_element.attrib) include_xml = ET.SubElement(pb_type_xml, 'pb_type', attrib) ET.SubElement( include_xml, XI_INCLUDE, { 'href': site_type_path, 'xpointer': "xpointer(pb_type/child::node()[local-name()!='metadata'])", }) metadata_xml = ET.SubElement(include_xml, 'metadata') if len(site_type_pkeys) > 1: ET.SubElement(metadata_xml, 'meta', { 'name': 'fasm_prefix', }).text = site_prefix # Import pb_type metadata if it exists. if any(child.tag == 'metadata' for child in root_element): ET.SubElement( metadata_xml, XI_INCLUDE, { 'href': site_type_path, 'xpointer': "xpointer(pb_type/metadata/child::node())", }) for site_type, site_pin_name in top_level_pin_external: port = find_port(site_pin_name, site_type_ports[site_type]) if port is None: print( "*** WARNING *** Didn't find port for name {} for site type {}" .format(site_pin_name, site_type), file=sys.stderr) continue site_name = cell_names[site_type] is_input = (site_type, site_pin_name) in all_pb_type_input_pins is_output = (site_type, site_pin_name) in all_pb_type_output_pins if not is_input and not is_output: continue if is_input: add_direct( interconnect_xml, input=object_ref(site_name, **port), output=object_ref( add_vpr_tile_prefix(pb_type), '{}_{}'.format(site_type, site_pin_name), ), ) for site_type, site_pin_name in top_level_pin_external: port = find_port(site_pin_name, site_type_ports[site_type]) if port is None: continue site_name = cell_names[site_type] is_input = (site_type, site_pin_name) in all_pb_type_input_pins is_output = (site_type, site_pin_name) in all_pb_type_output_pins if not is_input and not is_output: continue if is_output: add_direct( interconnect_xml, input=object_ref(add_vpr_tile_prefix(pb_type), '{}_{}'.format(site_type, site_pin_name)), output=object_ref(site_name, **port), ) for (dest_site_type, dest_site_pin_name, _), (src_site_type, src_site_pin_name, _) in \ sorted(internal_connections.items(), key=lambda x: (x[1], x[0])): src_port = find_port(src_site_pin_name, site_type_ports[src_site_type]) src_site_name = cell_names[src_site_type] if src_port is None: print( "*** WARNING *** Didn't find port for name {} for site type {}" .format(src_site_pin_name, src_site_type), file=sys.stderr) continue dest_port = find_port(dest_site_pin_name, site_type_ports[dest_site_type]) dest_site_name = cell_names[dest_site_type] if dest_port is None: print( "*** WARNING *** Didn't find port for name {} for site type {}" .format(dest_site_pin_name, dest_site_type), file=sys.stderr) continue add_direct( interconnect_xml, input=object_ref(src_site_name, **src_port), output=object_ref(dest_site_name, **dest_port), ) pb_type_xml.append(interconnect_xml) write_xml( os.path.join(output_directory, pb_type.lower(), '{}.pb_type.xml'.format(pb_type.lower())), pb_type_xml) top_level_connections = {} for wire in sorted(top_level_wire_external): site_type, site_pin_name, _ = wire_to_site_pin[wire] is_input = (site_type, site_pin_name) in all_pb_type_input_pins is_output = (site_type, site_pin_name) in all_pb_type_output_pins if not is_input and not is_output: continue top_level_connections[wire] = wire_to_site_pin[wire] return top_level_connections