def main(): parser = argparse.ArgumentParser( description= "Creates design.json from output of ROI generation tcl script.") parser.add_argument('--design_txt', required=True) parser.add_argument('--design_info_txt', required=True) parser.add_argument('--pad_wires', required=True) args = parser.parse_args() j = {} j['ports'] = [] j['info'] = {} with open(args.design_txt) as f: for d in csv.DictReader(f, delimiter=' '): j['ports'].append(d) with open(args.design_info_txt) as f: for l in f: name, value = l.strip().split(' = ') j['info'][name] = int(value) db = Database(get_db_root()) grid = db.grid() 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 open(args.pad_wires) as f: for l in f: parts = l.strip().split(' ') name = parts[0] pin = parts[1] wires = parts[2:] wires_outside_roi = [] for wire in wires: tile = wire.split('/')[0] loc = grid.loc_of_tilename(tile) if not roi.tile_in_roi(loc): wires_outside_roi.append(wire) set_port_wires(j['ports'], name, pin, wires_outside_roi) json.dump(j, sys.stdout, indent=2, sort_keys=True)
def run(db_root, filename_in, f_out, sparse=False, roi=None, debug=False): db = Database(db_root) assembler = fasm_assembler.FasmAssembler(db) extra_features = [] if roi: with open(roi) as f: roi_j = json.load(f) x1 = roi_j['info']['GRID_X_MIN'] x2 = roi_j['info']['GRID_X_MAX'] y1 = roi_j['info']['GRID_Y_MIN'] y2 = roi_j['info']['GRID_Y_MAX'] assembler.mark_roi_frames(Roi(db=db, x1=x1, x2=x2, y1=y1, y2=y2)) if 'required_features' in roi_j: extra_features = fasm.parse_fasm_string('\n'.join( roi_j['required_features'])) assembler.parse_fasm_filename(filename_in, extra_features=extra_features) frames = assembler.get_frames(sparse=sparse) if debug: dump_frames_sparse(frames) dump_frm(f_out, frames)
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 main(): parser = argparse.ArgumentParser( description= "Creates design.json from output of ROI generation tcl script.") parser.add_argument('--design_txt', required=True) parser.add_argument('--design_info_txt', required=True) parser.add_argument('--pad_wires', required=True) parser.add_argument('--design_fasm', required=True) args = parser.parse_args() design_json = {} design_json['ports'] = [] design_json['info'] = {} with open(args.design_txt) as f: for d in csv.DictReader(f, delimiter=' '): if d['name'].startswith('dout['): d['type'] = 'out' elif d['name'].startswith('din['): d['type'] = 'in' elif d['name'].startswith('clk'): d['type'] = 'clk' else: assert False, d design_json['ports'].append(d) with open(args.design_info_txt) as f: for l in f: name, value = l.strip().split(' = ') design_json['info'][name] = int(value) db = Database(get_db_root(), get_part()) grid = db.grid() roi = Roi( db=db, x1=design_json['info']['GRID_X_MIN'], y1=design_json['info']['GRID_Y_MIN'], x2=design_json['info']['GRID_X_MAX'], y2=design_json['info']['GRID_Y_MAX'], ) with open(args.pad_wires) as f: for l in f: parts = l.strip().split(' ') name = parts[0] pin = parts[1] wires = parts[2:] wires_outside_roi = [] for wire in wires: tile = wire.split('/')[0] loc = grid.loc_of_tilename(tile) if not roi.tile_in_roi(loc): wires_outside_roi.append(wire) set_port_wires(design_json['ports'], name, pin, wires_outside_roi) frames_in_use = set() for tile in roi.gen_tiles(): gridinfo = grid.gridinfo_at_tilename(tile) for bit in gridinfo.bits.values(): frames_in_use.add(bit.base_address) required_features = [] for fasm_line in fasm.parse_fasm_filename(args.design_fasm): if fasm_line.annotations: for annotation in fasm_line.annotations: if annotation.name != 'unknown_segment': continue unknown_base_address = int(annotation.value, 0) assert False, "Found unknown bit in base address 0x{:08x}".format( unknown_base_address) if not fasm_line.set_feature: continue tile = fasm_line.set_feature.feature.split('.')[0] loc = grid.loc_of_tilename(tile) gridinfo = grid.gridinfo_at_tilename(tile) not_in_roi = not roi.tile_in_roi(loc) if not_in_roi: required_features.append(fasm_line) design_json['required_features'] = sorted( fasm.fasm_tuple_to_string(required_features, canonical=True).split('\n'), key=extract_numbers) design_json['ports'].sort(key=lambda x: extract_numbers(x['name'])) xjson.pprint(sys.stdout, design_json)
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 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('--write_rr_node_map', required=True, help='Output map of graph_node_pkey to rr inode file') parser.add_argument('--connection_database', help='Database of fabric connectivity', required=True) parser.add_argument( '--synth_tiles', help= 'If using an ROI, synthetic tile defintion from prjxray-arch-import') parser.add_argument( '--graph_limit', help='Limit grid to specified dimensions in x_min,y_min,x_max,y_max', ) args = parser.parse_args() db = prjxray.db.Database(args.db_root) synth_tiles = None 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())) elif args.graph_limit: use_roi = True 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, ) else: use_roi = False roi = None synth_tiles = None # Convert input rr graph into graph2.Graph object. input_rr_graph = read_xml_file(args.read_rr_graph) if synth_tiles is None: synth_tiles = find_constant_network(input_rr_graph) xml_graph = xml_graph2.Graph( input_rr_graph, progressbar=progressbar_utils.progressbar, output_file_name=args.write_rr_graph, ) graph = xml_graph.graph tool_version = input_rr_graph.getroot().attrib['tool_version'] tool_comment = input_rr_graph.getroot().attrib['tool_comment'] with DatabaseCache(args.connection_database, True) as conn: cur = conn.cursor() for name, internal_capacitance, drive_resistance, intrinsic_delay, \ switch_type in cur.execute(""" SELECT name, internal_capacitance, drive_resistance, intrinsic_delay, switch_type FROM switch;"""): # Add back missing switchs, which were unused in arch xml, and so # were not emitted in rrgraph XML. # # TODO: This can be removed once # https://github.com/verilog-to-routing/vtr-verilog-to-routing/issues/354 # is fixed. try: graph.get_switch_id(name) continue except KeyError: xml_graph.add_switch( graph2.Switch( id=None, name=name, type=graph2.SwitchType[switch_type.upper()], timing=graph2.SwitchTiming( r=drive_resistance, c_in=0.0, c_out=0.0, c_internal=internal_capacitance, t_del=intrinsic_delay, ), sizing=graph2.SwitchSizing( mux_trans_size=0, buf_size=0, ), )) # Mapping of graph_node.pkey to rr node id. node_mapping = {} print('{} Creating connection box list'.format(now())) connection_box_map = create_connection_boxes(conn, graph) # Match site pins rr nodes with graph_node's in the connection_database. print('{} Importing graph nodes'.format(now())) import_graph_nodes(conn, graph, node_mapping, connection_box_map) # Walk all track graph nodes and add them. print('{} Creating tracks'.format(now())) segment_id = graph.get_segment_id_from_name('dummy') create_track_rr_graph(conn, graph, node_mapping, use_roi, roi, synth_tiles, segment_id) # 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. if use_roi: print('{} Adding synthetic edges'.format(now())) add_synthetic_edges(conn, graph, node_mapping, grid, synth_tiles) print('{} Creating channels.'.format(now())) channels_obj = create_channels(conn) x_dim, y_dim = phy_grid_dims(conn) connection_box_obj = graph.create_connection_box_object(x_dim=x_dim, y_dim=y_dim) print('{} Serializing to disk.'.format(now())) with xml_graph: xml_graph.start_serialize_to_xml( tool_version=tool_version, tool_comment=tool_comment, channels_obj=channels_obj, connection_box_obj=connection_box_obj, ) xml_graph.serialize_nodes(yield_nodes(xml_graph.graph.nodes)) xml_graph.serialize_edges( import_graph_edges(conn, graph, node_mapping)) print('{} Writing node map.'.format(now())) with open(args.write_rr_node_map, 'wb') as f: pickle.dump(node_mapping, f) print('{} Done writing node map.'.format(now()))
def fasm2frames(db_root, part, filename_in, f_out=None, sparse=False, roi=None, debug=False, emit_pudc_b_pullup=False): db = Database(db_root, part) assembler = fasm_assembler.FasmAssembler(db) set_features = set() def feature_callback(feature): set_features.add(feature) assembler.set_feature_callback(feature_callback) # Build mapping of tile to IO bank tile_to_bank = {} bank_to_tile = defaultdict(lambda: set()) if part is not None: with open(os.path.join(db_root, part, "package_pins.csv"), "r") as fp: reader = csv.DictReader(fp) package_pins = [l for l in reader] with open(os.path.join(db_root, part, "part.json"), "r") as fp: part_data = json.load(fp) for bank, loc in part_data["iobanks"].items(): tile = "HCLK_IOI3_" + loc bank_to_tile[bank].add(tile) tile_to_bank[tile] = bank for pin in package_pins: bank_to_tile[pin["bank"]].add(pin["tile"]) tile_to_bank[pin["tile"]] = pin["bank"] if emit_pudc_b_pullup: pudc_b_in_use = False pudc_b_tile_site = find_pudc_b(db) def check_for_pudc_b(set_feature): feature_callback(set_feature) parts = set_feature.feature.split('.') if parts[0] == pudc_b_tile_site[0] and parts[ 1] == pudc_b_tile_site[1]: nonlocal pudc_b_in_use pudc_b_in_use = True if pudc_b_tile_site is not None: assembler.set_feature_callback(check_for_pudc_b) extra_features = [] if roi: with open(roi) as f: roi_j = json.load(f) x1 = roi_j['info']['GRID_X_MIN'] x2 = roi_j['info']['GRID_X_MAX'] y1 = roi_j['info']['GRID_Y_MIN'] y2 = roi_j['info']['GRID_Y_MAX'] assembler.mark_roi_frames(Roi(db=db, x1=x1, x2=x2, y1=y1, y2=y2)) if 'required_features' in roi_j: extra_features = list( fasm.parse_fasm_string('\n'.join(roi_j['required_features']))) # Get required extra features for the part required_features = db.get_required_fasm_features(part) extra_features += list(fasm.parse_fasm_string( '\n'.join(required_features))) assembler.parse_fasm_filename(filename_in, extra_features=extra_features) if emit_pudc_b_pullup and not pudc_b_in_use and pudc_b_tile_site is not None: # Enable IN-only and PULLUP on PUDC_B IOB. # # TODO: The following FASM string only works on Artix 50T and Zynq 10 # fabrics. It is known to be wrong for the K70T fabric, but it is # unclear how to know which IOSTANDARD to use. missing_features = [] for line in fasm.parse_fasm_string(""" {tile}.{site}.LVCMOS12_LVCMOS15_LVCMOS18_LVCMOS25_LVCMOS33_LVTTL_SSTL135_SSTL15.IN_ONLY {tile}.{site}.LVCMOS25_LVCMOS33_LVTTL.IN {tile}.{site}.PULLTYPE.PULLUP """.format( tile=pudc_b_tile_site[0], site=pudc_b_tile_site[1], )): assembler.add_fasm_line(line, missing_features) if missing_features: raise fasm_assembler.FasmLookupError('\n'.join(missing_features)) if part is not None: # Make a set of all used IOB tiles and sites. Look for the "STEPDOWN" # feature. If one is set for an IOB then set it for all other IOBs of # the same bank. stepdown_tags = defaultdict(lambda: set()) stepdown_banks = set() used_iob_sites = set() for set_feature in set_features: if set_feature.value == 0: continue feature = set_feature.feature parts = feature.split(".") if len(parts) >= 3: tile, site, tag = feature.split(".", maxsplit=2) if "IOB33" in tile: used_iob_sites.add(( tile, site, )) # Store STEPDOWN related tags. if "STEPDOWN" in tag: bank = tile_to_bank[tile] stepdown_banks.add(bank) stepdown_tags[bank].add(tag) # Set the feature for unused IOBs, loop over all banks which were # observed to have the STEPDOWN feature set. missing_features = [] for bank in stepdown_banks: for tile in bank_to_tile[bank]: # This is an IOB33 tile. Set the STEPDOWN feature in it but # only if it is unused. if "IOB33" in tile: for site in get_iob_sites(db, tile): if (tile, site) in used_iob_sites: continue for tag in stepdown_tags[bank]: feature = "{}.{}.{}".format(tile, site, tag) for line in fasm.parse_fasm_string(feature): assembler.add_fasm_line(line, missing_features) # This is a HCLK_IOI3 tile, set the stepdown feature for it # too. if "HCLK_IOI3" in tile: feature = "{}.STEPDOWN".format(tile) for line in fasm.parse_fasm_string(feature): assembler.add_fasm_line(line, missing_features) if missing_features: raise fasm_assembler.FasmLookupError('\n'.join(missing_features)) frames = assembler.get_frames(sparse=sparse) if debug: dump_frames_sparse(frames) if f_out is not None: dump_frm(f_out, frames) return frames
def main(): parser = argparse.ArgumentParser() parser.add_argument('--db_root', required=True, help='Project X-Ray Database') parser.add_argument('--part', required=True, help='FPGA part') 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('--write_rr_node_map', required=True, help='Output map of graph_node_pkey to rr inode file') parser.add_argument('--connection_database', help='Database of fabric connectivity', required=True) parser.add_argument( '--synth_tiles', help= 'If using an ROI, synthetic tile defintion from prjxray-arch-import') parser.add_argument('--overlay', action='store_true', required=False, help='Use synth tiles for Overlay instead of ROI') parser.add_argument( '--graph_limit', help='Limit grid to specified dimensions in x_min,y_min,x_max,y_max', ) parser.add_argument( '--vpr_capnp_schema_dir', help='Directory container VPR schema files', ) print('{} Starting routing import'.format(now())) args = parser.parse_args() db = prjxray.db.Database(args.db_root, args.part) populate_hclk_cmt_tiles(db) synth_tiles = None if args.overlay: assert args.synth_tiles use_roi = True with open(args.synth_tiles) as f: synth_tiles = json.load(f) region_dict = dict() for r in synth_tiles['info']: bounds = (r['GRID_X_MIN'], r['GRID_X_MAX'], r['GRID_Y_MIN'], r['GRID_Y_MAX']) region_dict[r['name']] = bounds roi = Overlay(region_dict=region_dict) print('{} generating routing graph for Overlay.'.format(now())) elif 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())) elif args.graph_limit: use_roi = True 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, ) else: use_roi = False roi = None synth_tiles = None capnp_graph = capnp_graph2.Graph( rr_graph_schema_fname=os.path.join(args.vpr_capnp_schema_dir, 'rr_graph_uxsdcxx.capnp'), input_file_name=args.read_rr_graph, progressbar=progressbar_utils.progressbar, output_file_name=args.write_rr_graph, ) graph = capnp_graph.graph if synth_tiles is None: synth_tiles = find_constant_network(graph) if args.overlay: synth_tiles_const = find_constant_network(graph) synth_tiles['tiles'].update(synth_tiles_const['tiles']) with sqlite3.connect("file:{}?mode=ro".format(args.connection_database), uri=True) as conn: populate_bufg_rebuf_map(conn) cur = conn.cursor() for name, internal_capacitance, drive_resistance, intrinsic_delay, penalty_cost, \ switch_type in cur.execute(""" SELECT name, internal_capacitance, drive_resistance, intrinsic_delay, penalty_cost, switch_type FROM switch;"""): # Add back missing switchs, which were unused in arch xml, and so # were not emitted in rrgraph XML. # # TODO: This can be removed once # https://github.com/verilog-to-routing/vtr-verilog-to-routing/issues/354 # is fixed. try: graph.get_switch_id(name) continue except KeyError: capnp_graph.add_switch( graph2.Switch( id=None, name=name, type=graph2.SwitchType[switch_type.upper()], timing=graph2.SwitchTiming( r=drive_resistance, c_in=0.0, c_out=0.0, c_internal=internal_capacitance, t_del=intrinsic_delay, p_cost=penalty_cost, ), sizing=graph2.SwitchSizing( mux_trans_size=0, buf_size=0, ), )) # Mapping of graph_node.pkey to rr node id. node_mapping = {} print('{} Creating connection box list'.format(now())) connection_box_map = create_connection_boxes(conn, graph) # Match site pins rr nodes with graph_node's in the connection_database. print('{} Importing graph nodes'.format(now())) import_graph_nodes(conn, graph, node_mapping, connection_box_map) # Walk all track graph nodes and add them. print('{} Creating tracks'.format(now())) segment_id = graph.get_segment_id_from_name('dummy') create_track_rr_graph(conn, graph, node_mapping, use_roi, roi, synth_tiles, segment_id) # 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. print('{} Adding synthetic edges'.format(now())) add_synthetic_edges(conn, graph, node_mapping, grid, synth_tiles, args.overlay) print('{} Creating channels.'.format(now())) channels_obj = create_channels(conn) node_remap = create_node_remap(capnp_graph.graph.nodes, channels_obj) x_dim, y_dim = phy_grid_dims(conn) connection_box_obj = graph.create_connection_box_object(x_dim=x_dim, y_dim=y_dim) num_edges = get_number_graph_edges(conn, graph, node_mapping) print('{} Serializing to disk.'.format(now())) capnp_graph.serialize_to_capnp( channels_obj=channels_obj, connection_box_obj=connection_box_obj, num_nodes=len(capnp_graph.graph.nodes), nodes_obj=yield_nodes(capnp_graph.graph.nodes), num_edges=num_edges, edges_obj=import_graph_edges(conn, graph, node_mapping), node_remap=node_remap, ) for k in node_mapping: node_mapping[k] = node_remap(node_mapping[k]) print('{} Writing node map.'.format(now())) with open(args.write_rr_node_map, 'wb') as f: pickle.dump(node_mapping, f) print('{} Done writing node map.'.format(now()))
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(): 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 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(description="Generate arch.xml") parser.add_argument( '--db_root', required=True, help="Project X-Ray database to use." ) parser.add_argument('--part', required=True, help="FPGA part") parser.add_argument( '--output-arch', nargs='?', type=argparse.FileType('w'), help="""File to output arch.""" ) parser.add_argument( '--tile-types', required=True, help="Semi-colon seperated tile types." ) parser.add_argument( '--pb_types', required=True, help="Semi-colon seperated pb_types types." ) parser.add_argument( '--pin_assignments', required=True, type=argparse.FileType('r') ) parser.add_argument('--use_roi', required=False) parser.add_argument('--use_overlay', 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(',') pb_types = args.pb_types.split(',') model_xml_spec = "../../tiles/{0}/{0}.model.xml" pbtype_xml_spec = "../../tiles/{0}/{0}.pb_type.xml" tile_xml_spec = "../../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 pb_type in pb_types: ET.SubElement( model_xml, xi_include, { 'href': model_xml_spec.format(pb_type.lower()), 'xpointer': "xpointer(models/child::node())", } ) tiles_xml = ET.SubElement(arch_xml, 'tiles') tile_capacity = {} for tile_type in tile_types: uri = tile_xml_spec.format(tile_type.lower()) ET.SubElement(tiles_xml, xi_include, { 'href': uri, }) with open(uri) as f: tile_xml = ET.parse(f, ET.XMLParser()) tile_root = tile_xml.getroot() assert tile_root.tag == 'tile' tile_capacity[tile_type] = 0 for sub_tile in tile_root.iter('sub_tile'): if 'capacity' in sub_tile.attrib: tile_capacity[tile_type] += int( sub_tile.attrib['capacity'] ) else: tile_capacity[tile_type] += 1 complexblocklist_xml = ET.SubElement(arch_xml, 'complexblocklist') for pb_type in pb_types: ET.SubElement( complexblocklist_xml, xi_include, { 'href': pbtype_xml_spec.format(pb_type.lower()), } ) layout_xml = ET.SubElement(arch_xml, 'layout') db = prjxray.db.Database(args.db_root, 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'], ) for _, tile_info in synth_tiles['tiles'].items(): if tile_info['pins'][0]['port_type'] in ['GND', 'VCC']: continue assert tuple(tile_info['loc']) not in synth_loc_map tile_name = tile_info['tile_name'] num_input = len( list( filter( lambda t: t['port_type'] == 'output', tile_info['pins'] ) ) ) num_output = len( list( filter( lambda t: t['port_type'] == 'input', tile_info['pins'] ) ) ) create_synth_io_tile( complexblocklist_xml, tiles_xml, tile_name, num_input, num_output ) synth_loc_map[tuple(tile_info['loc'])] = tile_name create_synth_pb_types(model_xml, complexblocklist_xml) synth_tile_map = add_constant_synthetic_tiles( model_xml, complexblocklist_xml, tiles_xml ) for _, tile_info in synth_tiles['tiles'].items(): if tile_info['pins'][0]['port_type'] not in ['GND', 'VCC']: continue assert tuple(tile_info['loc']) not in synth_loc_map 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, ) elif args.use_overlay: with open(args.use_overlay) as f: j = json.load(f) with open(args.synth_tiles) as f: synth_tiles = json.load(f) region_dict = dict() for r in synth_tiles['info']: bounds = ( r['GRID_X_MIN'], r['GRID_X_MAX'], r['GRID_Y_MIN'], r['GRID_Y_MAX'] ) region_dict[r['name']] = bounds roi = Overlay(region_dict=region_dict) for _, tile_info in synth_tiles['tiles'].items(): if tile_info['pins'][0]['port_type'] in ['GND', 'VCC']: continue assert tuple(tile_info['loc']) not in synth_loc_map tile_name = tile_info['tile_name'] num_input = len( list( filter( lambda t: t['port_type'] == 'output', tile_info['pins'] ) ) ) num_output = len( list( filter( lambda t: t['port_type'] == 'input', tile_info['pins'] ) ) ) create_synth_io_tile( complexblocklist_xml, tiles_xml, tile_name, num_input, num_output ) synth_loc_map[tuple(tile_info['loc'])] = tile_name create_synth_pb_types(model_xml, complexblocklist_xml, True) 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_const = insert_constant_tiles( conn, model_xml, complexblocklist_xml, tiles_xml ) synth_loc_map.update(synth_loc_map_const) # 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, tile_capacity=tile_capacity, ): 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 WHERE name != "__vpr_delayless_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) ) ALLOWED_ZERO_OFFSET_DIRECT = [ "GTP_CHANNEL_0", "GTP_CHANNEL_1", "GTP_CHANNEL_2", "GTP_CHANNEL_3", "GTP_CHANNEL_0_MID_LEFT", "GTP_CHANNEL_1_MID_LEFT", "GTP_CHANNEL_2_MID_LEFT", "GTP_CHANNEL_3_MID_LEFT", "GTP_CHANNEL_0_MID_RIGHT", "GTP_CHANNEL_1_MID_RIGHT", "GTP_CHANNEL_2_MID_RIGHT", "GTP_CHANNEL_3_MID_RIGHT", "GTP_COMMON_MID_LEFT", "GTP_COMMON_MID_RIGHT", ] zero_offset_directs = dict() for direct in directs.values(): _, direct = min(direct, key=lambda v: v[0]) from_tile = direct['from_pin'].split('.')[0] to_tile = direct['to_pin'].split('.')[0] if from_tile not in tile_types: continue if to_tile not in tile_types: continue # In general, the Z offset is 0, except for special cases # such as for the GTP tiles, where there are direct connections # within the same (x, y) cooredinates, but between different sub_tiles direct['z_offset'] = 0 if direct['x_offset'] == 0 and direct['y_offset'] == 0: if from_tile == to_tile and from_tile in ALLOWED_ZERO_OFFSET_DIRECT: if from_tile not in zero_offset_directs: zero_offset_directs[from_tile] = list() zero_offset_directs[from_tile].append(direct) continue add_direct(directlist_xml, direct) for tile, directs in zero_offset_directs.items(): uri = tile_xml_spec.format(tile.lower()) ports = list() with open(uri) as f: tile_xml = ET.parse(f, ET.XMLParser()) tile_root = tile_xml.getroot() for capacity, sub_tile in enumerate(tile_root.iter('sub_tile')): for in_port in sub_tile.iter('input'): ports.append((in_port.attrib["name"], capacity)) for out_port in sub_tile.iter('output'): ports.append((out_port.attrib["name"], capacity)) for clk_port in sub_tile.iter('clock'): ports.append((clk_port.attrib["name"], capacity)) for direct in directs: tile_type, from_port = direct['from_pin'].split('.') _, to_port = direct['to_pin'].split('.') if tile != tile_type: continue from_port_capacity = None to_port_capacity = None for port, capacity in ports: if port == from_port: from_port_capacity = capacity if port == to_port: to_port_capacity = capacity assert from_port_capacity is not None and to_port_capacity is not None, ( tile, from_port, to_port ) direct["z_offset"] = to_port_capacity - from_port_capacity add_direct(directlist_xml, direct) 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 run( db_root, filename_in, f_out, sparse=False, roi=None, debug=False, emit_pudc_b_pullup=False): db = Database(db_root) assembler = fasm_assembler.FasmAssembler(db) if emit_pudc_b_pullup: pudc_b_in_use = False pudc_b_tile_site = find_pudc_b(db) def check_for_pudc_b(set_feature): parts = set_feature.feature.split('.') if parts[0] == pudc_b_tile_site[0] and parts[ 1] == pudc_b_tile_site[1]: nonlocal pudc_b_in_use pudc_b_in_use = True if pudc_b_tile_site is not None: assembler.set_feature_callback(check_for_pudc_b) extra_features = [] if roi: with open(roi) as f: roi_j = json.load(f) x1 = roi_j['info']['GRID_X_MIN'] x2 = roi_j['info']['GRID_X_MAX'] y1 = roi_j['info']['GRID_Y_MIN'] y2 = roi_j['info']['GRID_Y_MAX'] assembler.mark_roi_frames(Roi(db=db, x1=x1, x2=x2, y1=y1, y2=y2)) if 'required_features' in roi_j: extra_features = fasm.parse_fasm_string( '\n'.join(roi_j['required_features'])) assembler.parse_fasm_filename(filename_in, extra_features=extra_features) if emit_pudc_b_pullup and not pudc_b_in_use and pudc_b_tile_site is not None: # Enable IN-only and PULLUP on PUDC_B IOB. # # TODO: The following FASM string only works on Artix 50T and Zynq 10 # fabrics. It is known to be wrong for the K70T fabric, but it is # unclear how to know which IOSTANDARD to use. missing_features = [] for line in fasm.parse_fasm_string(""" {tile}.{site}.LVCMOS12_LVCMOS15_LVCMOS18_LVCMOS25_LVCMOS33_LVTTL_SSTL135.IN_ONLY {tile}.{site}.LVCMOS25_LVCMOS33_LVTTL.IN {tile}.{site}.PULLTYPE.PULLUP """.format( tile=pudc_b_tile_site[0], site=pudc_b_tile_site[1], )): assembler.add_fasm_line(line, missing_features) if missing_features: raise fasm_assembler.FasmLookupError('\n'.join(missing_features)) frames = assembler.get_frames(sparse=sparse) if debug: dump_frames_sparse(frames) dump_frm(f_out, frames)
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() 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('--connection_database', help='Database of fabric connectivity', required=True) 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, output_file_name=args.write_rr_graph, ) graph = xml_graph.graph # Add back short switch, which is unused in arch xml, so is not emitted in # rrgraph XML. # # TODO: This can be removed once # https://github.com/verilog-to-routing/vtr-verilog-to-routing/issues/354 # is fixed. try: short = graph.get_switch_id('short') except KeyError: short = xml_graph.add_switch( graph2.Switch( id=None, name='short', type=graph2.SwitchType.SHORT, timing=None, sizing=graph2.SwitchSizing( mux_trans_size=0, buf_size=0, ), )) tool_version = input_rr_graph.getroot().attrib['tool_version'] tool_comment = input_rr_graph.getroot().attrib['tool_comment'] with DatabaseCache(args.connection_database, True) as conn: # Mapping of graph_node.pkey to rr node id. node_mapping = {} # Match site pins rr nodes with graph_node's in the connection_database. print('{} Importing graph nodes'.format(now())) import_graph_nodes(conn, graph, node_mapping) # Walk all track graph nodes and add them. print('{} Creating tracks'.format(now())) segment_id = graph.get_segment_id_from_name('dummy') create_track_rr_graph(conn, graph, node_mapping, use_roi, roi, synth_tiles, segment_id) # 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. if use_roi: print('{} Adding synthetic edges'.format(now())) add_synthetic_edges(conn, graph, node_mapping, grid, synth_tiles) print('{} Creating channels.'.format(now())) channels_obj = create_channels(conn) print('{} Serializing to disk.'.format(now())) with xml_graph: xml_graph.start_serialize_to_xml( tool_version=tool_version, tool_comment=tool_comment, channels_obj=channels_obj, ) xml_graph.serialize_nodes(yield_nodes(xml_graph.graph.nodes)) xml_graph.serialize_edges( import_graph_edges(conn, graph, node_mapping))