Esempio n. 1
0
    def __init__(
        self,
        input_file_name,
        output_file_name=None,
        progressbar=None,
        build_pin_edges=True,
        rebase_nodes=True,
        filter_nodes=True,
    ):
        if progressbar is None:
            progressbar = lambda x: x  # noqa: E731

        self.input_file_name = input_file_name
        self.progressbar = progressbar
        self.output_file_name = output_file_name

        graph_input = graph_from_xml(input_file_name,
                                     progressbar,
                                     filter_nodes=filter_nodes)
        graph_input['build_pin_edges'] = build_pin_edges

        self.root_attrib = graph_input["root_attrib"]
        del graph_input["root_attrib"]

        if rebase_nodes:
            rebase_nodes = []
            for node in graph_input['nodes']:
                node_d = node._asdict()
                node_d['id'] = len(rebase_nodes)
                rebase_nodes.append(graph2.Node(**node_d))

            graph_input['nodes'] = rebase_nodes

        self.graph = graph2.Graph(**graph_input)

        self.xf = None
        self.xf_tag = []

        if DEBUG > 0:
            self._write_xml = self._write_xml_debug
        else:
            self._write_xml = self._write_xml_no_debug
Esempio n. 2
0
def read_node(node, new_node_id=None):
    node_loc = node.loc
    node_timing = node.timing

    return graph2.Node(
        id=new_node_id if new_node_id is not None else node.id,
        type=enum_from_string(graph2.NodeType, node.type),
        direction=enum_from_string(graph2.NodeDirection, node.direction),
        capacity=node.capacity,
        loc=graph2.NodeLoc(
            x_low=node_loc.xlow,
            y_low=node_loc.ylow,
            x_high=node_loc.xhigh,
            y_high=node_loc.yhigh,
            ptc=node_loc.ptc,
            side=enum_from_string(tracks.Direction, node_loc.side),
        ),
        timing=graph2.NodeTiming(r=node_timing.r, c=node_timing.c),
        metadata=None,
        segment=graph2.NodeSegment(segment_id=node.segment.segmentId),
    )
Esempio n. 3
0
def main():

    # Parse arguments
    parser = argparse.ArgumentParser()

    parser.add_argument("--rr-graph-in",
                        required=True,
                        type=str,
                        help="Input RR graph XML")
    parser.add_argument("--rr-graph-out",
                        required=True,
                        type=str,
                        help="Output RR graph XML")
    parser.add_argument("--gsb",
                        default=None,
                        type=str,
                        help="Path to GSB data files")
    parser.add_argument("--openfpga-arch-in",
                        type=str,
                        required=True,
                        help="OpenFPGA arch.xml input")
    parser.add_argument(
        "--capnp-schema",
        default=None,
        type=str,
        help="Path to rr graph cap'n'proto schema (for binary rr graph writing)"
    )

    args = parser.parse_args()

    # Verify the output rr graph extension
    rr_graph_out_ext = os.path.splitext(args.rr_graph_out)[1].lower()

    if rr_graph_out_ext == ".xml":
        pass

    if rr_graph_out_ext == ".bin":

        # Check if we have Cap'n'proto schema provided
        if args.capnp_schema is None:
            print(
                "ERROR: Binary rr graph writeout requires Cap'n'proto schema")
            exit(-1)

    else:
        print("ERROR: Unsupported rr graph extension '{}'".format(
            rr_graph_out_ext))
        exit(-1)

    # Read and parse the OpenFPGA arch XML file
    xml_tree = ET.parse(args.openfpga_arch_in,
                        ET.XMLParser(remove_blank_text=True))
    xml_openfpga_arch = xml_tree.getroot()
    assert xml_openfpga_arch is not None and \
        xml_openfpga_arch.tag == "openfpga_architecture"

    # Get circuit models
    circuit_models = load_circuit_models(xml_openfpga_arch)

    # Load the routing graph
    print("Loading rr graph...")
    xml_graph = rr_xml.Graph(input_file_name=args.rr_graph_in,
                             output_file_name=args.rr_graph_out,
                             rebase_nodes=False,
                             filter_nodes=False,
                             load_edges=True,
                             build_pin_edges=False,
                             progressbar=progressbar_utils.progressbar)

    compute_rr_graph_stats(xml_graph.graph)

    # Load GSB data
    if args.gsb is not None:
        print("Loading GSB data...")
        gsb_data = load_gsb_data(args.gsb, progressbar_utils.progressbar)
        assert len(gsb_data), "No GSB data found!"

        # DEBUG
        total_mux_count = 0
        conf_mux_count = 0
        for loc, gsbs in gsb_data.items():
            total_mux_count += len(gsbs)
            for gsb in gsbs:
                if len(gsb.drivers) > 1:
                    conf_mux_count += 1

        print(" {:>6} locs".format(len(gsb_data)))
        print(" {:>6} all muxes".format(total_mux_count))
        print(" {:>6} configurable muxes".format(conf_mux_count))

        # Identify routing muxes
        print("Identifying routing muxes...")
        routing_muxes = identify_routing_muxes(xml_graph.graph, gsb_data)

        # Build routing mux models
        print("Building routing muxes models...")
        routing_muxes_models = build_routing_muxes_models(
            circuit_models, routing_muxes)

        # Annotate edges
        print("Annotating rr graph edges...")
        annotate_edges(xml_graph.graph, routing_muxes)

    # Re-add all channel nodes as tracks and clear their PTCs. This allows
    # the Graph2 class code to re-assign PTCs which makes the graph usable
    # for SymbiFlow VPR.
    for i, node in enumerate(xml_graph.graph.nodes):

        # Check endpoint locations
        assert node.loc.x_low <= node.loc.x_high, node
        assert node.loc.y_low <= node.loc.y_high, node

        # Handle CHAN node
        if node.type in [rr.NodeType.CHANX, rr.NodeType.CHANY]:

            # Verify direction
            assert node.direction in [
                rr.NodeDirection.INC_DIR, rr.NodeDirection.DEC_DIR,
                rr.NodeDirection.BI_DIR
            ], node

            # Named tuples to dicts
            node = node._asdict()
            loc = node["loc"]._asdict()

            # Clear PTC
            loc["ptc"] = None

            # Not sure why the segment id has its own NamedTuple object but
            # the Graph2 code requires it.
            node["segment"] = rr.NodeSegment(segment_id=node["segment"])

            # Dicts to named tuples
            loc = rr.NodeLoc(**loc)
            node["loc"] = loc
            node = rr.Node(**node)

            # Replace the node
            xml_graph.graph.nodes[i] = node

            # Add it as a track
            xml_graph.graph.tracks.append(node.id)

        # Handle non-CHAN node
        else:

            # Verify direction
            assert node.direction == rr.NodeDirection.NO_DIR, node

            # Set direction to None
            node = node._asdict()
            node["direction"] = None
            node = rr.Node(**node)

            # Replace the node
            xml_graph.graph.nodes[i] = node

    # Create channels from tracks
    channels_obj = xml_graph.graph.create_channels(pad_segment=0)

    # Remove padding channels
    print("Removing padding nodes...")
    xml_graph.graph.nodes = [
        n for n in xml_graph.graph.nodes if n.capacity > 0
    ]

    # Write the routing graph
    nodes_obj = xml_graph.graph.nodes
    edges_obj = xml_graph.graph.edges
    node_remap = lambda x: x

    print("Serializing the rr graph...")

    if rr_graph_out_ext == ".xml":
        xml_graph.serialize_to_xml(
            channels_obj=channels_obj,
            nodes_obj=nodes_obj,
            edges_obj=yield_edges(edges_obj),
            node_remap=node_remap,
        )

    elif rr_graph_out_ext == ".bin":

        # Build the writer
        writer = BinaryGraphWriter(
            graph=xml_graph.graph,
            root_attrib=xml_graph.root_attrib,
            capnp_schema_file_name=args.capnp_schema,
            output_file_name=args.rr_graph_out,
            progressbar=progressbar_utils.progressbar,
        )

        # Write
        writer.serialize_to_capnp(
            channels_obj=channels_obj,
            num_nodes=len(nodes_obj),
            nodes_obj=nodes_obj,
            num_edges=len(edges_obj),
            edges_obj=yield_edges(edges_obj),
        )

    else:
        assert False, rr_graph_out_ext
Esempio n. 4
0
def graph_from_xml(input_file_name,
                   progressbar=None,
                   filter_nodes=True,
                   load_edges=False):
    """
    Loads relevant information about the routing resource graph from an XML
    file.
    """

    if progressbar is None:
        progressbar = lambda x: x  # noqa: E731

    root_attrib = {}
    switches = []
    segments = []
    block_types = []
    grid = []
    nodes = []
    edges = []

    # Itertate over XML elements
    switch_timing = None
    switch_sizing = None
    segment_timing = None
    pins = []
    pin_classes = []
    node_loc = None
    node_timing = None
    node_segment = None

    for path, element in progressbar(
            iterate_xml(input_file_name, load_edges=load_edges)):

        # Root tag
        if path == "" and element.tag == "rr_graph":
            root_attrib = dict(element.attrib)

        # Switch timing
        if path == "rr_graph/switches/switch" and element.tag == "timing":
            switch_timing = graph2.SwitchTiming(
                r=float(element.attrib.get('R', 0)),
                c_in=float(element.attrib.get('Cin', 0)),
                c_out=float(element.attrib.get('Cout', 0)),
                c_internal=float(element.attrib.get('Cinternal', 0)),
                t_del=float(element.attrib.get('Tdel', 0)),
            )

        # Switch sizing
        if path == "rr_graph/switches/switch" and element.tag == "sizing":
            switch_sizing = graph2.SwitchSizing(
                mux_trans_size=float(element.attrib['mux_trans_size']),
                buf_size=float(element.attrib['buf_size']),
            )

        # Switch
        if path == "rr_graph/switches" and element.tag == "switch":
            switches.append(
                graph2.Switch(
                    id=int(element.attrib['id']),
                    type=enum_from_string(graph2.SwitchType,
                                          element.attrib['type']),
                    name=element.attrib['name'],
                    timing=switch_timing,
                    sizing=switch_sizing,
                ))

            switch_timing = None
            switch_sizing = None

        # Segment timing
        if path == "rr_graph/segments/segment" and element.tag == "timing":
            segment_timing = graph2.SegmentTiming(
                r_per_meter=float(element.attrib.get('R_per_meter', 0)),
                c_per_meter=float(element.attrib.get('C_per_meter', 0)),
            )

        # Segment
        if path == "rr_graph/segments" and element.tag == "segment":
            segments.append(
                graph2.Segment(
                    id=int(element.attrib['id']),
                    name=element.attrib['name'],
                    timing=segment_timing,
                ))

            segment_timing = None

        # Block type - pin
        if path == "rr_graph/block_types/block_type/pin_class" and element.tag == "pin":
            pins.append(
                graph2.Pin(
                    ptc=int(element.attrib['ptc']),
                    name=element.text,
                ))

        # Block type - pin_class
        if path == "rr_graph/block_types/block_type" and element.tag == "pin_class":
            pin_classes.append(
                graph2.PinClass(
                    type=enum_from_string(graph2.PinType,
                                          element.attrib['type']),
                    pin=pins,
                ))

            pins = []

        # Block type
        if path == "rr_graph/block_types" and element.tag == "block_type":
            block_types.append(
                graph2.BlockType(
                    id=int(element.attrib['id']),
                    name=element.attrib['name'],
                    width=int(element.attrib['width']),
                    height=int(element.attrib['height']),
                    pin_class=pin_classes,
                ))

            pin_classes = []

        # Grid
        if path == "rr_graph/grid" and element.tag == "grid_loc":
            grid.append(
                graph2.GridLoc(
                    x=int(element.attrib['x']),
                    y=int(element.attrib['y']),
                    block_type_id=int(element.attrib['block_type_id']),
                    width_offset=int(element.attrib['width_offset']),
                    height_offset=int(element.attrib['height_offset']),
                ))

        # Node - loc
        if path == "rr_graph/rr_nodes/node" and element.tag == "loc":
            if 'side' in element.attrib:
                side = enum_from_string(tracks.Direction,
                                        element.attrib['side'])
            else:
                side = None

            node_loc = graph2.NodeLoc(x_low=int(element.attrib['xlow']),
                                      y_low=int(element.attrib['ylow']),
                                      x_high=int(element.attrib['xhigh']),
                                      y_high=int(element.attrib['yhigh']),
                                      ptc=int(element.attrib['ptc']),
                                      side=side)

        # Node - timing
        if path == "rr_graph/rr_nodes/node" and element.tag == "timing":
            node_timing = graph2.NodeTiming(
                r=float(element.attrib['R']),
                c=float(element.attrib['C']),
            )

        # Node - segment
        if path == "rr_graph/rr_nodes/node" and element.tag == "segment":
            node_segment = int(element.attrib['segment_id'])

        # Node
        if path == "rr_graph/rr_nodes" and element.tag == "node":
            node_type = enum_from_string(graph2.NodeType,
                                         element.attrib['type'])

            if filter_nodes and node_type not in [
                    graph2.NodeType.SOURCE, graph2.NodeType.SINK,
                    graph2.NodeType.OPIN, graph2.NodeType.IPIN
            ]:
                continue

            # Dropping metadata for now
            metadata = None

            nodes.append(
                graph2.Node(
                    id=int(element.attrib['id']),
                    type=node_type,
                    direction=graph2.NodeDirection.NO_DIR,
                    capacity=int(element.attrib['capacity']),
                    loc=node_loc,
                    timing=node_timing,
                    metadata=metadata,
                    segment=node_segment,
                    canonical_loc=None,
                    connection_box=None,
                ))

            node_loc = None
            node_timing = None
            node_segment = None

        # Edge
        if path == "rr_graph/rr_edges" and element.tag == "edge":
            if load_edges:
                edges.append(
                    graph2.Edge(
                        src_node=int(element.attrib['src_node']),
                        sink_node=int(element.attrib['sink_node']),
                        switch_id=int(element.attrib['switch_id']),
                        metadata=None  # FIXME: Add reading edge metadata
                    ))

    return dict(root_attrib=root_attrib,
                switches=switches,
                segments=segments,
                block_types=block_types,
                grid=grid,
                nodes=nodes,
                edges=edges)