def add_direct(directlist_xml, direct): direct_dict = { 'name': '{}_to_{}_dx_{}_dy_{}_dz_{}'.format( direct['from_pin'], direct['to_pin'], direct['x_offset'], direct['y_offset'], direct['z_offset'] ), 'from_pin': add_vpr_tile_prefix(direct['from_pin']), 'to_pin': add_vpr_tile_prefix(direct['to_pin']), 'x_offset': str(direct['x_offset']), 'y_offset': str(direct['y_offset']), 'z_offset': str(direct['z_offset']), } # If the switch is a delayless_switch, the switch name # needs to be avoided as VPR automatically assigns # the delayless switch to this direct connection if direct['switch_name'] != '__vpr_delayless_switch__': direct_dict['switch_name'] = direct['switch_name'] ET.SubElement(directlist_xml, 'direct', direct_dict)
def add_equivalent_sites(tile_xml, equivalent_sites, inc_priority=False): """ Used to add to the <tile> tag the equivalent tiles associated with it.""" pb_types = equivalent_sites.split(',') equivalent_sites_xml = ET.SubElement(tile_xml, 'equivalent_sites') priority = 0 for eq_site in pb_types: eq_pb_type_xml = ET.parse( "{}/{tile}/{tile}.pb_type.xml".format( args.tiles_directory, tile=eq_site.lower() ) ) pb_type_root = eq_pb_type_xml.getroot() site_xml = ET.SubElement( equivalent_sites_xml, 'site', { 'pb_type': tile_import.add_vpr_tile_prefix(eq_site), 'priority': str(priority) } ) if inc_priority: priority += 1 add_direct_mappings(tile_xml, site_xml, pb_type_root)
def get_tiles(conn, g, roi, synth_loc_map, synth_tile_map, tile_types): """ Yields tiles in grid. Yields ------ vpr_tile_type : str VPR tile type at this grid location. grid_x, grid_y : int Grid coordinate of tile fasm_tile_prefix : str FASM prefix for this tile. """ c = conn.cursor() c2 = conn.cursor() only_emit_roi = roi is not None for tile_pkey, grid_x, grid_y, phy_tile_pkey, tile_type_pkey, site_as_tile_pkey in c.execute( """ SELECT pkey, grid_x, grid_y, phy_tile_pkey, tile_type_pkey, site_as_tile_pkey FROM tile """): # Just output synth tiles, no additional processing is required here. if (grid_x, grid_y) in synth_loc_map: synth_tile = synth_loc_map[(grid_x, grid_y)] assert len(synth_tile['pins']) == 1 vpr_tile_type = synth_tile_map[synth_tile['pins'][0]['port_type']] # Synth tiles have no bits, but there needs to be a prefix, so # use the original tile name. c2.execute( "SELECT name FROM phy_tile WHERE pkey = ?", (phy_tile_pkey, ) ) fasm_tile_prefix = c2.fetchone()[0] yield vpr_tile_type, grid_x, grid_y, fasm_tile_prefix continue c2.execute( "SELECT name FROM tile_type WHERE pkey = ?", (tile_type_pkey, ) ) tile_type = c2.fetchone()[0] if tile_type not in tile_types: # We don't want this tile continue if only_emit_roi and not is_in_roi(conn, roi, tile_pkey): # Tile is outside ROI, skip it continue vpr_tile_type = add_vpr_tile_prefix(tile_type) fasm_tile_prefix = get_fasm_tile_prefix( conn, g, tile_pkey, site_as_tile_pkey ) yield vpr_tile_type, grid_x, grid_y, fasm_tile_prefix
def get_tiles(conn, g, roi, synth_loc_map, synth_tile_map, tile_types, tile_capacity): """ Yields tiles in grid. Yields ------ vpr_tile_type : str VPR tile type at this grid location. grid_x, grid_y : int Grid coordinate of tile metadata_function : function that takes lxml.Element Function for attaching metadata tags to <single> elements. Function must be supplied, but doesn't need to add metadata if not required. """ c = conn.cursor() c2 = conn.cursor() only_emit_roi = roi is not None for tile_pkey, grid_x, grid_y, phy_tile_pkey, tile_type_pkey, site_as_tile_pkey in c.execute( """ SELECT pkey, grid_x, grid_y, phy_tile_pkey, tile_type_pkey, site_as_tile_pkey FROM tile """): # Just output synth tiles, no additional processing is required here. if (grid_x, grid_y) in synth_loc_map: vpr_tile_type = synth_loc_map[(grid_x, grid_y)] yield vpr_tile_type, grid_x, grid_y, lambda x: None continue c2.execute("SELECT name FROM tile_type WHERE pkey = ?", (tile_type_pkey, )) tile_type = c2.fetchone()[0] if tile_type not in tile_types: # We don't want this tile continue if only_emit_roi and not is_in_roi(conn, roi, tile_pkey): # Tile is outside ROI, skip it continue vpr_tile_type = add_vpr_tile_prefix(tile_type) meta_fun = get_fasm_tile_prefix(conn, g, tile_pkey, site_as_tile_pkey, tile_capacity[tile_type]) yield vpr_tile_type, grid_x, grid_y, meta_fun
def add_equivalent_sites(tile_xml, equivalent_sites): """ Used to add to the <tile> tag the equivalent tiles associated with it.""" pb_types = equivalent_sites.split(',') equivalent_sites_xml = ET.SubElement(tile_xml, 'equivalent_sites') for eq_site in pb_types: eq_pb_type_xml = ET.parse("{}/{tile}/{tile}.pb_type.xml".format( args.tiles_directory, tile=eq_site.lower())) pb_type_root = eq_pb_type_xml.getroot() site_xml = ET.SubElement( equivalent_sites_xml, 'site', { 'pb_type': tile_import.add_vpr_tile_prefix(eq_site), 'pin_mapping': 'custom' }) add_direct_mappings(tile_xml, site_xml, pb_type_root)
def import_physical_tile(args): """ Imports the physical tile. This created the actual tile.xml definition of the tile which will be merged in the arch.xml. """ ########################################################################## # Utility functions to create tile tag. # ########################################################################## def get_ports_from_xml(xml): """ Used to retrieve ports from a given XML root of a pb_type.""" ports = set() for child in xml: if child.tag in PORT_TAGS: ports.add(child.attrib['name']) return ports def add_ports(tile_xml, pb_type_xml): """ Used to copy the ports from a given XML root of a pb_type.""" for child in pb_type_xml: if child.tag in PORT_TAGS: child_copy = copy.deepcopy(child) tile_xml.append(child_copy) def add_direct_mappings(tile_xml, site_xml, eq_pb_type_xml): """ Used to add the direct pin mappings between a pb_type and the corresponding tile """ tile_ports = sorted(get_ports_from_xml(tile_xml)) site_ports = sorted(get_ports_from_xml(eq_pb_type_xml)) tile_name = tile_xml.attrib['name'] site_name = site_xml.attrib['pb_type'] for site_port in site_ports: for tile_port in tile_ports: if site_port == tile_port: direct_map = ET.SubElement( site_xml, 'direct', { 'from': "{}.{}".format(tile_name, tile_port), 'to': "{}.{}".format(site_name, site_port) } ) def add_equivalent_sites(tile_xml, equivalent_sites, inc_priority=False): """ Used to add to the <tile> tag the equivalent tiles associated with it.""" pb_types = equivalent_sites.split(',') equivalent_sites_xml = ET.SubElement(tile_xml, 'equivalent_sites') priority = 0 for eq_site in pb_types: eq_pb_type_xml = ET.parse( "{}/{tile}/{tile}.pb_type.xml".format( args.tiles_directory, tile=eq_site.lower() ) ) pb_type_root = eq_pb_type_xml.getroot() site_xml = ET.SubElement( equivalent_sites_xml, 'site', { 'pb_type': tile_import.add_vpr_tile_prefix(eq_site), 'priority': str(priority) } ) if inc_priority: priority += 1 add_direct_mappings(tile_xml, site_xml, pb_type_root) ########################################################################## # Generate the tile.xml file # ########################################################################## tile_name = args.tile pb_type_xml = ET.parse( "{}/{tile}/{tile}.pb_type.xml".format( args.tiles_directory, tile=tile_name.lower() ) ) pb_type_root = pb_type_xml.getroot() ports = sorted(get_ports_from_xml(pb_type_root)) tile_xml = ET.Element( 'tile', { 'name': tile_import.add_vpr_tile_prefix(tile_name), }, nsmap={'xi': XI_URL}, ) add_ports(tile_xml, pb_type_root) equivalent_sites = args.equivalent_sites add_equivalent_sites(tile_xml, equivalent_sites, args.priority) fc_xml = tile_import.add_fc(tile_xml) pin_assignments = json.load(args.pin_assignments) tile_import.add_pinlocations( tile_name, tile_xml, fc_xml, pin_assignments, ports ) tile_import.add_switchblock_locations(tile_xml) tile_str = ET.tostring(tile_xml, pretty_print=True).decode('utf-8') args.output_tile.write(tile_str) args.output_tile.close()
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('--device', required=True) parser.add_argument('--synth_tiles', required=False) parser.add_argument('--connection_database', required=True) parser.add_argument( '--graph_limit', help='Limit grid to specified dimensions in x_min,y_min,x_max,y_max', ) 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" tile_tile = "../../tiles/{0}/{0}.tile.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())", } ) tiles_xml = ET.SubElement(arch_xml, 'tiles') for tile_type in tile_types: ET.SubElement( tiles_xml, xi_include, { 'href': tile_tile.format(tile_type.lower()), } ) 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() synth_tiles = {} synth_tiles['tiles'] = {} synth_loc_map = {} synth_tile_map = {} roi = None if args.use_roi: with open(args.use_roi) as f: j = json.load(f) with open(args.synth_tiles) as f: synth_tiles = 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_tile_map = add_synthetic_tiles( model_xml, complexblocklist_xml, tiles_xml, need_io=True ) for _, tile_info in synth_tiles['tiles'].items(): assert tuple(tile_info['loc']) not in synth_loc_map assert len(tile_info['pins']) == 1 vpr_tile_type = synth_tile_map[tile_info['pins'][0]['port_type']] synth_loc_map[tuple(tile_info['loc'])] = vpr_tile_type elif args.graph_limit: x_min, y_min, x_max, y_max = map(int, args.graph_limit.split(',')) roi = Roi( db=db, x1=x_min, y1=y_min, x2=x_max, y2=y_max, ) with DatabaseCache(args.connection_database, read_only=True) as conn: c = conn.cursor() if 'GND' not in synth_tile_map: synth_tile_map, synth_loc_map = insert_constant_tiles( conn, model_xml, complexblocklist_xml, tiles_xml ) # Find the grid extent. y_max = 0 x_max = 0 for grid_x, grid_y in c.execute("SELECT grid_x, grid_y FROM tile"): x_max = max(grid_x + 2, x_max) y_max = max(grid_y + 2, y_max) name = '{}-test'.format(args.device) fixed_layout_xml = ET.SubElement( layout_xml, 'fixed_layout', { 'name': name, 'height': str(y_max), 'width': str(x_max), } ) for vpr_tile_type, grid_x, grid_y, metadata_function in get_tiles( conn=conn, g=g, roi=roi, synth_loc_map=synth_loc_map, synth_tile_map=synth_tile_map, tile_types=tile_types, ): single_xml = ET.SubElement( fixed_layout_xml, 'single', { 'priority': '1', 'type': vpr_tile_type, 'x': str(grid_x), 'y': str(grid_y), } ) metadata_function(single_xml) switchlist_xml = ET.SubElement(arch_xml, 'switchlist') for name, internal_capacitance, drive_resistance, intrinsic_delay, \ switch_type in c.execute(""" SELECT name, internal_capacitance, drive_resistance, intrinsic_delay, switch_type FROM switch;"""): attrib = { 'type': switch_type, 'name': name, "R": str(drive_resistance), "Cin": str(0), "Cout": str(0), "Tdel": str(intrinsic_delay), } if internal_capacitance != 0: attrib["Cinternal"] = str(internal_capacitance) if False: attrib["mux_trans_size"] = str(0) attrib["buf_size"] = str(0) ET.SubElement(switchlist_xml, 'switch', attrib) segmentlist_xml = ET.SubElement(arch_xml, 'segmentlist') # VPR requires a segment, so add one. dummy_xml = ET.SubElement( segmentlist_xml, 'segment', { 'name': 'dummy', 'length': '2', 'freq': '1.0', 'type': 'bidir', 'Rmetal': '0', 'Cmetal': '0', } ) ET.SubElement(dummy_xml, 'wire_switch', { 'name': 'buffer', }) ET.SubElement(dummy_xml, 'opin_switch', { 'name': 'buffer', }) ET.SubElement(dummy_xml, 'sb', { 'type': 'pattern', }).text = ' '.join('1' for _ in range(3)) ET.SubElement(dummy_xml, 'cb', { 'type': 'pattern', }).text = ' '.join('1' for _ in range(2)) for (name, length) in c.execute("SELECT name, length FROM segment"): if length is None: length = 1 segment_xml = ET.SubElement( segmentlist_xml, 'segment', { 'name': name, 'length': str(length), 'freq': '1.0', 'type': 'bidir', 'Rmetal': '0', 'Cmetal': '0', } ) ET.SubElement(segment_xml, 'wire_switch', { 'name': 'buffer', }) ET.SubElement(segment_xml, 'opin_switch', { 'name': 'buffer', }) ET.SubElement(segment_xml, 'sb', { 'type': 'pattern', }).text = ' '.join('1' for _ in range(length + 1)) ET.SubElement(segment_xml, 'cb', { 'type': 'pattern', }).text = ' '.join('1' for _ in range(length)) ET.SubElement( switchlist_xml, 'switch', { 'type': 'mux', 'name': 'buffer', "R": "551", "Cin": ".77e-15", "Cout": "4e-15", # TODO: This value should be the "typical" pip switch delay from # This value is the dominate term in the inter-cluster delay # estimate. "Tdel": "0.178e-9", "mux_trans_size": "2.630740", "buf_size": "27.645901" } ) 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', } ) 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': add_vpr_tile_prefix(direct['from_pin']), 'to_pin': add_vpr_tile_prefix(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 get_tiles( conn, g, roi, synth_loc_map, synth_tile_map, tile_types, tile_capacity ): """ Yields tiles in grid. Yields ------ vpr_tile_type : str VPR tile type at this grid location. grid_x, grid_y : int Grid coordinate of tile metadata_function : function that takes lxml.Element Function for attaching metadata tags to <single> elements. Function must be supplied, but doesn't need to add metadata if not required. """ c = conn.cursor() c2 = conn.cursor() only_emit_roi = roi is not None for tile_pkey, grid_x, grid_y, phy_tile_pkey, tile_type_pkey, site_as_tile_pkey in c.execute( """ SELECT pkey, grid_x, grid_y, phy_tile_pkey, tile_type_pkey, site_as_tile_pkey FROM tile """): if phy_tile_pkey is not None: c2.execute( "SELECT prohibited FROM site_instance WHERE phy_tile_pkey = ?", (phy_tile_pkey, ) ) any_prohibited_sites = any( prohibited for (prohibited, ) in c2.fetchall() ) # Skip generation of tiles containing prohibited sites if any_prohibited_sites: continue # Just output synth tiles, no additional processing is required here. if (grid_x, grid_y) in synth_loc_map: vpr_tile_type = synth_loc_map[(grid_x, grid_y)] yield vpr_tile_type, grid_x, grid_y, lambda x: None continue c2.execute( "SELECT name FROM tile_type WHERE pkey = ?", (tile_type_pkey, ) ) tile_type = c2.fetchone()[0] if tile_type not in tile_types: # We don't want this tile continue if only_emit_roi and not is_in_roi(conn, roi, tile_pkey): # Tile is outside ROI, skip it continue vpr_tile_type = add_vpr_tile_prefix(tile_type) # For Zynq PSS* tiles do not emit fasm prefixes if tile_type.startswith('PSS'): def get_none_tile_prefix(single_xml): return None meta_fun = get_none_tile_prefix else: meta_fun = get_fasm_tile_prefix( conn, g, tile_pkey, site_as_tile_pkey, tile_capacity[tile_type] ) yield vpr_tile_type, grid_x, grid_y, meta_fun