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)
Beispiel #2
0
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)
Beispiel #3
0
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()
Beispiel #6
0
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()))
Beispiel #7
0
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()
Beispiel #11
0
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()))
Beispiel #12
0
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)
Beispiel #13
0
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()
Beispiel #14
0
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)
Beispiel #15
0
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)
Beispiel #16
0
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))