| /************************************************************************ |
| * This file introduces a class to model a Routing Resource Graph (RRGraph or RRG) |
| * which is widely used by placers, routers, analyzers etc. |
| * |
| * Overview |
| * ======== |
| * RRGraph aims to describe in a general way how routing resources are connected |
| * in a FPGA fabric. |
| * It includes device-level information for routing resources, |
| * such as the physical location of nodes, |
| * routing segment information of each routing resource |
| * switch information of each routing resource. |
| * |
| * A Routing Resource Graph (RRGraph or RRG) is a directed graph (has many cycles), |
| * which consists of a number of nodes and edges. |
| * |
| * Node |
| * ---- |
| * Each node represents a routing resource, which could be |
| * 1. a routing track in X-direction or Y-direction (CHANX or CHANY) |
| * 2. an input or an output of a logic block (IPIN or OPIN) |
| * 3. a virtual source or sink node (SOURCE or SINK), which are starting/ending points of routing trees. |
| * |
| * Edge |
| * ---- |
| * Each edge represents a switch between routing resources, which could be |
| * 1. a multiplexer |
| * 2. a tri-state buffer |
| * 3. a pass gate |
| * 4. a non-configurable (can not be turned off) buffer |
| * 5. a short (metal connection that can not be turned off |
| * |
| * Note: Multiplexers are the most common type |
| * |
| * The switch information are categorized in the rr_switch_inf of RRGraph class. |
| * rr_switch_inf is created to minimize memory footprint of RRGraph classs |
| * While the RRG could contain millions (even much larger) of edges, there are only |
| * a limited number of types of switches. |
| * Hence, we use a flyweight pattern to store switch-related information that differs |
| * only for types of switches (switch type, drive strength, R, C, etc.). |
| * Each edge stores the ids of the switch that implements it so this additional information |
| * can be easily looked up. |
| * |
| * Note: All the switch-related information, such as R, C, should be placed in rr_switch_inf |
| * but NOT directly in the edge-related data of RRGraph. |
| * If you wish to create a new data structure to represent switches between routing resources, |
| * please follow the flyweight pattern by linking your switch ids to edges only! |
| * |
| * Guidlines on using the RRGraph data structure |
| * ============================================= |
| * |
| * For those want to access data from RRGraph |
| * ------------------------------------------ |
| * Some examples for most frequent data query: |
| * |
| * // Strongly suggest to use a read-only rr_graph object |
| * const RRGraph& rr_graph; |
| * |
| * // Access type of a node with a given node id |
| * // Get the unique node id that you may get |
| * // from other data structures or functions |
| * RRNodeId node_id; |
| * t_rr_type node_type = rr_graph.node_type(node_id); |
| * |
| * // Access all the fan-out edges from a given node |
| * for (const RREdgeId& out_edge_id : rr_graph.node_out_edges(node_id)) { |
| * // Do something with out_edge |
| * } |
| * // If you only want to learn the number of fan-out edges |
| * size_t num_out_edges = rr_graph.node_fan_out(node_id); |
| * |
| * // Access all the switches connected to a given node |
| * for (const RREdgeId& in_edge_id : rr_graph.node_in_edges(node_id)) { |
| * RRSwitchId edge_switch_id = rr_graph.edge_switch(in_edge_id); |
| * // Do something with the switch |
| * } |
| * |
| * Please refer to the detailed comments on each public accessors |
| * |
| * For those want to build/modify a RRGraph |
| * ----------------------------------------- |
| * Do NOT add a builder to this data structure! |
| * Builders should be kept as free functions that use the public mutators |
| * We suggest developers to create builders in separated C/C++ source files |
| * outside the rr_graph header and source files |
| * |
| * After build/modify a RRGraph, please do run a fundamental check, a public accessor. |
| * to ensure that your RRGraph does not include invalid nodes/edges/switches/segements |
| * as well as connections. |
| * The validate() function gurantees the consistency between internal data structures, |
| * such as the id cross-reference between nodes and edges etc., |
| * so failing it indicates a fatal bug! |
| * This is a must-do check! |
| * |
| * Example: |
| * RRGraph rr_graph; |
| * ... // Building RRGraph |
| * rr_graph.validate(); |
| * |
| * Optionally, we strongly recommend developers to run an advance check in check_rr_graph() |
| * This guarantees legal and routable RRGraph for VPR routers. |
| * |
| * This checks for connectivity or other information in the RRGraph that is unexpected |
| * or unusual in an FPGA, and likely indicates a problem in your graph generation. |
| * However, if you are intentionally creating an RRGraph with this unusual, |
| * buts still technically legal, behaviour, you can write your own check_rr_graph() with weaker assumptions. |
| * |
| * Note: Do NOT modify the coordinate system for nodes, they are designed for downstream drawers and routers |
| * |
| * For those want to extend RRGraph data structure |
| * -------------------------------------------------------------------------- |
| * Please avoid modifying any existing public/private accessors/mutators |
| * in order to keep a stable RRGraph object in the framework |
| * Developers may add more internal data to RRGraph as well as associate accessors/mutators |
| * Please update and comment on the added features properly to keep this data structure friendly to be extended. |
| * |
| * Try to keep your extension within only graph-related internal data to RRGraph. |
| * In other words, extension is necessary when the new node/edge attributes are needed. |
| * RRGraph should NOT include other data which are shared by other data structures outside. |
| * The rr-graph is the single largest data structure in VPR, |
| * so avoid adding unnecessary information per node or per edge to it, as it will impact memory footprint. |
| * Instead, using indices to point to the outside data source instead of embedding to RRGraph |
| * For example: |
| * For any placement/routing cost related information, try to extend t_rr_indexed_data, but not RRGraph |
| * For any placement/routing results, try to extend PlaceContext and RoutingContext, but not RRGraph |
| * |
| * For those want to develop placers or routers |
| * -------------------------------------------------------------------------- |
| * The RRGraph is designed to be a read-only database/graph, once created. |
| * Placement and routing should NOT change any attributes of RRGraph. |
| * Any placement and routing results should be stored in other data structures, such as PlaceContext and RoutingContext. |
| * |
| * Tracing Cross-Reference |
| * ======================= |
| * RRGraph is designed to a self-contained data structure as much as possible. |
| * It includes the switch information (rr_switch) and segment_information (rr_segment) |
| * which are necessary to build-up any external data structures. |
| * |
| * Internal cross-reference |
| * ------------------------ |
| * |
| * +--------+ +--------+ |
| * | | node_in_edges | | |
| * | | node_out_edges | | |
| * | Node |----------------->| Edge |--+ |
| * | |<-----------------| | | |
| * | | edge_src_node | | | |
| * +--------+ edge_sink_node +--------+ |edge_switch |
| * | | |
| * | node_segment | |
| * v v |
| * +------------+ +----------+ |
| * | | | | |
| * | | | | |
| * | Segments | | Switch | |
| * | | | | |
| * | | | | |
| * +------------+ +----------+ |
| * |
| * |
| * External cross-reference |
| * ------------------------ |
| * The only cross-reference to outside data structures is the cost_index |
| * corresponding to the data structure t_rr_index_data |
| * Details can be found in the definition of t_rr_index_data |
| * This allows rapid look up by the router of additional information it needs for this node, using a flyweight pattern. |
| * |
| * +---------+ cost_index +------------------------------+ |
| * | RRGraph |-------------->| cost_index_data[cost_index] | |
| * +---------+ +------------------------------+ |
| * |
| * Note: if you wish to use a customized routing-cost data structure, |
| * please use the flyweigth pattern as we do for t_rr_index_data! |
| * |
| * Access to a node/edge/switch/segment, please use the StrongId created |
| * --------------------------------------------------------------------- |
| * For node, use RRNodeId |
| * For edge, use RREdgeId |
| * For switch, use RRSwitchId |
| * For segment, use RRSegmentId |
| * |
| * These are the unique identifier for each data type. |
| * To check if your id is valid or not, use the INVALID() function of StrongId class. |
| * Example: |
| * if (node_id == RRNodeId::INVALID()) { |
| * } |
| * |
| ***********************************************************************/ |
| #ifndef RR_GRAPH_OBJ_H |
| #define RR_GRAPH_OBJ_H |
| |
| /* |
| * Notes in include header files in a head file |
| * Only include the neccessary header files |
| * that is required by the data types in the function/class declarations! |
| */ |
| /* Header files should be included in a sequence */ |
| /* Standard header files required go first */ |
| #include <limits> |
| #include <vector> |
| |
| /* EXTERNAL library header files go second*/ |
| #include "vtr_vector.h" |
| #include "vtr_range.h" |
| #include "vtr_geometry.h" |
| #include "arch_types.h" |
| |
| /* VPR header files go third */ |
| #include "vpr_types.h" |
| #include "rr_graph_fwd.h" |
| |
| class RRGraph { |
| public: /* Types */ |
| /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ |
| typedef vtr::vector<RRNodeId, RRNodeId>::const_iterator node_iterator; |
| typedef vtr::vector<RREdgeId, RREdgeId>::const_iterator edge_iterator; |
| typedef vtr::vector<RRSwitchId, RRSwitchId>::const_iterator switch_iterator; |
| typedef vtr::vector<RRSegmentId, RRSegmentId>::const_iterator segment_iterator; |
| |
| /* Ranges used to create range-based loop for nodes/edges/switches/segments */ |
| typedef vtr::Range<node_iterator> node_range; |
| typedef vtr::Range<edge_iterator> edge_range; |
| typedef vtr::Range<switch_iterator> switch_range; |
| typedef vtr::Range<segment_iterator> segment_range; |
| |
| public: /* Accessors */ |
| /* Aggregates: create range-based loops for nodes/edges/switches/segments |
| * To iterate over the nodes/edges/switches/segments in a RRGraph, |
| * using a range-based loop is suggested. |
| * ----------------------------------------------------------------- |
| * Example: iterate over all the nodes |
| * // Strongly suggest to use a read-only rr_graph object |
| * const RRGraph& rr_graph; |
| * for (const RRNodeId& node : rr_graph.nodes()) { |
| * // Do something with each node |
| * } |
| * |
| * for (const RREdgeId& edge : rr_graph.edges()) { |
| * // Do something with each edge |
| * } |
| * |
| * for (const RRSwitchId& switch : rr_graph.switches()) { |
| * // Do something with each switch |
| * } |
| * |
| * for (const RRSegmentId& segment : rr_graph.segments()) { |
| * // Do something with each segment |
| * } |
| */ |
| node_range nodes() const; |
| edge_range edges() const; |
| switch_range switches() const; |
| segment_range segments() const; |
| |
| /* Node-level attributes */ |
| size_t node_index(const RRNodeId& node) const; /* TODO: deprecate this accessor as outside functions should use RRNodeId */ |
| |
| /* get the type of a RRGraph node : types of each node, can be channel wires (CHANX or CHANY) or |
| * logic block pins(OPIN or IPIN) or virtual nodes (SOURCE or SINK) |
| * see t_rr_type definition for more details |
| */ |
| t_rr_type node_type(const RRNodeId& node) const; |
| |
| /* Get coordinate of a node. (xlow, xhigh, ylow, yhigh): |
| * For OPIN/IPIN/SOURCE/SINK, xlow = xhigh and ylow = yhigh |
| * This is still the case when a logic block has a height > 1 |
| * For CHANX/CHANY, (xlow, ylow) and (xhigh, yhigh) represent |
| * where the routing segment starts and ends. |
| * Note that our convention alway keeps |
| * xlow <= xhigh and ylow <= yhigh |
| * Therefore, (xlow, ylow) is a starting point for a CHANX/CHANY in INC_DIRECTION |
| * (xhigh, yhigh) is a starting point for a CHANX/CHANY in DEC_DIRECTION |
| * |
| * Note: there is only a single drive point for each routing segment (track) |
| * in the context of uni-directional wires |
| * |
| * Example : |
| * CHANX in INC_DIRECTION |
| * (xlow, ylow) (xhigh, yhigh) |
| * | | |
| * \|/ \|/ |
| * ----------------------------> |
| * |
| * CHANX in DEC_DIRECTION |
| * (xlow, ylow) (xhigh, yhigh) |
| * | | |
| * \|/ \|/ |
| * <---------------------------- |
| * |
| * CHANY in INC_DIRECTION |
| * |
| * /|\ <-------(xhigh, yhigh) |
| * | |
| * | <-------(xlow, ylow) |
| * |
| * CHANY in DEC_DIRECTION |
| * |
| * | <-------(xhigh, yhigh) |
| * | |
| * \|/ <-------(xlow, ylow) |
| */ |
| short node_xlow(const RRNodeId& node) const; |
| short node_ylow(const RRNodeId& node) const; |
| short node_xhigh(const RRNodeId& node) const; |
| short node_yhigh(const RRNodeId& node) const; |
| |
| /* Get the length of a routing track. |
| * Note that it is ONLY meaningful for CHANX and CHANY, which represents the number of logic blocks that a routing track spans |
| * For nodes that are OPIN/IPIN/SOURCE/SINK, the length is supposed to be always 0 |
| */ |
| short node_length(const RRNodeId& node) const; |
| |
| /* A short-cut function to get coordinates of a node, |
| * where xmin of vtr::Rect = xlow, |
| * ymin of vtr::Rect = ylow, |
| * xmax of vtr::Rect = xhigh, |
| * ymax of vtr::Rect = yhigh. |
| */ |
| vtr::Rect<short> node_bounding_box(const RRNodeId& node) const; |
| |
| /* Get node starting and ending points in routing channels. |
| * See details in the figures for node_xlow(), node_ylow(), node_xhigh() and node_yhigh() |
| * For routing tracks in INC_DIRECTION: |
| * node_start_coordinate() returns (xlow, ylow) as the starting point |
| * node_end_coordinate() returns (xhigh, yhigh) as the ending point |
| * |
| * For routing tracks in DEC_DIRECTION: |
| * node_start_coordinate() returns (xhigh, yhigh) as the starting point |
| * node_end_coordinate() returns (xlow, ylow) as the ending point |
| * |
| * For routing tracks in BI_DIRECTION: |
| * node_start_coordinate() returns (xlow, ylow) as the starting point |
| * node_end_coordinate() returns (xhigh, yhigh) as the ending point |
| * |
| * Applicable to routing track nodes only!!! |
| * This function will requires the types of node to be either CHANX or CHANY |
| */ |
| vtr::Point<short> node_start_coordinate(const RRNodeId& node) const; |
| vtr::Point<short> node_end_coordinate(const RRNodeId& node) const; |
| |
| /* Get the capacity of a node. |
| * Literally, how many nets can be mapped to the node. |
| * Typically, each node has a capacity of 1 but special nodes (SOURCE and SINK) will have a |
| * large number due to logic equivalent pins |
| * See Vaughn Betz's book for more details |
| */ |
| short node_capacity(const RRNodeId& node) const; |
| |
| /* Get the number of edges that drives a given node |
| * Note that each edge is typically driven by a node |
| * (true in VPR RRG that is currently supported, may not be true in customized RRG) |
| * This can also represent the number of drive nodes |
| * An example where fan-in of a node C is 2 |
| * |
| * edge A |
| * node A -------->+ |
| * | |
| * |-->node C |
| * edgeB | |
| * node B -------->+ |
| * |
| */ |
| short node_fan_in(const RRNodeId& node) const; |
| |
| /* Get the number of edges that are driven a given node |
| * Note that each edge typically drives by a node |
| * (true in VPR RRG that is currently supported, may not be true in customized RRG) |
| * This can also represent the number of fan-out nodes |
| * An example where fan-out of a node A is 2 |
| * |
| * edge A |
| * node A -+--------> node B |
| * | |
| * | |
| * | edgeB |
| * +--------> node C |
| * |
| */ |
| short node_fan_out(const RRNodeId& node) const; |
| |
| /* Get the ptc_num of a node |
| * The ptc (pin, track, or class) number is an integer |
| * that allows you to differentiate between wires, pins or sources/sinks with overlapping x,y coordinates or extent. |
| * This is useful for drawing rr-graphs nicely. |
| * For example, all the CHANX rr_nodes that have the same y coordinate and x-coordinates |
| * that overlap will have different ptc numbers, by convention starting at 0. |
| * This allows them to be drawn without overlapping, as the ptc num can be used as a track identifier. |
| * The main routing code does not care about ptc num. |
| * |
| * The ptc_num carries different meanings for different node types |
| * (true in VPR RRG that is currently supported, may not be true in customized RRG) |
| * CHANX or CHANY: the track id in routing channels |
| * OPIN or IPIN: the index of pins in the logic block data structure |
| * SOURCE and SINK: the class id of a pin (indicating logic equivalence of pins) in the logic block data structure |
| * |
| * To ease the access to ptc_num for different types of nodes: |
| * node_pin_num() is designed for logic blocks, which are IPIN and OPIN nodes |
| * node_track_num() is designed for routing tracks, which are CHANX and CHANY nodes |
| * node_class_num() is designed for routing source and sinks, which are SOURCE and SINK nodes |
| * |
| * Due to a useful identifier, ptc_num is used in building fast look-up |
| */ |
| short node_ptc_num(const RRNodeId& node) const; |
| short node_pin_num(const RRNodeId& node) const; |
| short node_track_num(const RRNodeId& node) const; |
| short node_class_num(const RRNodeId& node) const; |
| |
| /* Get the index of cost data in the list of cost_indexed_data data structure |
| * It contains the routing cost for different nodes in the RRGraph |
| * when used in evaluate different routing paths |
| * See cross-reference section in this header file for more details |
| */ |
| short node_cost_index(const RRNodeId& node) const; |
| |
| /* Get the directionality of a node |
| * see node coordinate for details |
| * only matters the routing track nodes (CHANX and CHANY) |
| */ |
| e_direction node_direction(const RRNodeId& node) const; |
| |
| /* Get the side where the node physically locates on a logic block. |
| * Mainly applicable to IPIN and OPIN nodes, which locates on the perimeter of logic block |
| * The side should be consistent to <pinlocation> definition in architecture XML |
| * |
| * TOP |
| * +-----------+ |
| * | | |
| * LEFT | Logic | RIGHT |
| * | Block | |
| * | | |
| * +-----------+ |
| * BOTTOM |
| * |
| */ |
| e_side node_side(const RRNodeId& node) const; |
| |
| /* Get resistance of a node, used to built RC tree for timing analysis */ |
| float node_R(const RRNodeId& node) const; |
| |
| /* Get capacitance of a node, used to built RC tree for timing analysis */ |
| float node_C(const RRNodeId& node) const; |
| |
| /* Get segment id of a node, containing the information of the routing |
| * segment that the node represents. See more details in the data structure t_segment_inf |
| */ |
| RRSegmentId node_segment(const RRNodeId& node) const; |
| |
| /* Get the number of non-configurable incoming edges to a node */ |
| short node_num_configurable_in_edges(const RRNodeId& node) const; |
| |
| /* Get the number of non-configurable outgoing edges from a node */ |
| short node_num_non_configurable_in_edges(const RRNodeId& node) const; |
| |
| /* Get the number of configurable output edges of a node */ |
| short node_num_configurable_out_edges(const RRNodeId& node) const; |
| |
| /* Get the number of non-configurable output edges of a node */ |
| short node_num_non_configurable_out_edges(const RRNodeId& node) const; |
| |
| /* Get the range (list) of edges related to a given node */ |
| edge_range node_configurable_in_edges(const RRNodeId& node) const; |
| edge_range node_non_configurable_in_edges(const RRNodeId& node) const; |
| edge_range node_configurable_out_edges(const RRNodeId& node) const; |
| edge_range node_non_configurable_out_edges(const RRNodeId& node) const; |
| |
| /* Get a list of edge ids, which are incoming edges to a node */ |
| edge_range node_in_edges(const RRNodeId& node) const; |
| |
| /* Get a list of edge ids, which are outgoing edges from a node */ |
| edge_range node_out_edges(const RRNodeId& node) const; |
| |
| /* Edge-related attributes |
| * An example to explain the terminology used in RRGraph |
| * edgeA |
| * nodeA --------> nodeB |
| * | edgeB |
| * +-------> nodeC |
| * |
| * +----------+----------------+----------------+ |
| * | Edge Id | edge_src_node | edge_sink_node | |
| * +----------+----------------+----------------+ |
| * | edgeA | nodeA | nodeB | |
| * +----------+----------------+----------------+ |
| * | edgeB | nodeA | nodeC | |
| * +----------+----------------+----------------+ |
| * |
| */ |
| size_t edge_index(const RREdgeId& edge) const; /* TODO: deprecate this accessor as outside functions should use RREdgeId */ |
| /* Get the source node which drives a edge */ |
| RRNodeId edge_src_node(const RREdgeId& edge) const; |
| /* Get the sink node which a edge ends to */ |
| RRNodeId edge_sink_node(const RREdgeId& edge) const; |
| /* Get the switch id which a edge represents |
| * using switch id, timing and other information can be found |
| * for any node-to-node connection |
| */ |
| RRSwitchId edge_switch(const RREdgeId& edge) const; |
| /* Judge if a edge is configurable or not. |
| * A configurable edge is controlled by a programmable memory bit |
| * while a non-configurable edge is typically a hard-wired connection |
| */ |
| bool edge_is_configurable(const RREdgeId& edge) const; |
| bool edge_is_non_configurable(const RREdgeId& edge) const; |
| |
| /* Switch Info */ |
| size_t switch_index(const RRSwitchId& switch_id) const; /* TODO: deprecate this accessor as outside functions should use RRSwitchId */ |
| /* Get the switch info of a switch used in this RRGraph */ |
| const t_rr_switch_inf& get_switch(const RRSwitchId& switch_id) const; |
| |
| /* Segment Info */ |
| size_t segment_index(const RRSegmentId& segment_id) const; /* TODO: deprecate this accessor as outside functions should use RRSegmentId */ |
| /* Get the segment info of a routing segment used in this RRGraph */ |
| const t_segment_inf& get_segment(const RRSegmentId& segment_id) const; |
| |
| /* Utilities */ |
| /* Find the edges connecting two nodes */ |
| std::vector<RREdgeId> find_edges(const RRNodeId& src_node, const RRNodeId& sink_node) const; |
| /* Find a node with given features from internal fast look-up */ |
| RRNodeId find_node(const short& x, const short& y, const t_rr_type& type, const int& ptc, const e_side& side = NUM_SIDES) const; |
| /* Find the number of routing tracks in a routing channel with a given coordinate */ |
| short chan_num_tracks(const short& x, const short& y, const t_rr_type& type) const; |
| |
| /* This flag is raised when the RRgraph contains invalid nodes/edges etc. |
| * Invalid nodes/edges exist when users remove nodes/edges from RRGraph |
| * RRGraph object will not immediately remove the nodes and edges but |
| * will mark them with invalid ids. |
| * Afterwards the is_dirty flag is raised as an indicator, to tell users |
| * that a clean-up process (invoked by compress() function)is required. |
| * After executing compress(), the is_dirty will be reset to false |
| * |
| * Example: |
| * RRGraph rr_graph; |
| * RRNodeId node_id; // Node id to be removed |
| * rr_graph.remove_node(node_id); |
| * // RRGraph is now dirty (rr_graph.is_dirty() == true) |
| * ... |
| * // During this period, when you perform data query, |
| * // You may encounter invalid nodes and edges |
| * // It may happen that |
| * // 1. their ids are invalid |
| * // 2. the cross-reference between nodes and edge, i.e., |
| * // node_in_edges(), node_out_edges() |
| * // 3. invalid node returned from find_node(), which use fast look-up |
| * ... |
| * rr_graph.compress(); |
| * // RRGraph is now clean (rr_graph.is_dirty() == false) |
| */ |
| bool is_dirty() const; |
| |
| public: /* Echos */ |
| void print_node(const RRNodeId& node) const; /* Print the detailed information of a node */ |
| |
| public: /* Public Validators */ |
| /* Check data structure for internal consistency |
| * This function will |
| * 1. re-build fast look-up for nodes |
| * 2. check all the edges and nodes are connected |
| * Literally, no invalid ids in fan-in/fan-out of edges/nodes |
| * 3. check that all the nodes representing routing tracks have valid id linked to its segment-related data structure |
| * 4. check that all the edges have valid id linked to its switch-related data structure |
| * |
| * Any valid and non-dirty RRGraph should pass this check |
| * It is highly recommended to run this function after building any RRGraph object |
| */ |
| bool validate() const; |
| |
| /* Validate is the node id does exist in the RRGraph */ |
| bool valid_node_id(const RRNodeId& node) const; |
| |
| /* Validate is the edge id does exist in the RRGraph */ |
| bool valid_edge_id(const RREdgeId& edge) const; |
| |
| public: /* Mutators */ |
| /* Reserve the lists of nodes, edges, switches etc. to be memory efficient. |
| * This function is mainly used to reserve memory space inside RRGraph, |
| * when adding a large number of nodes/edge/switches/segments, |
| * in order to avoid memory fragements |
| * For example: |
| * RRGraph rr_graph; |
| * // Add 1000 CHANX nodes to the RRGraph object |
| * rr_graph.reserve_nodes(1000); |
| * for (size_t i = 0; i < 1000; ++i) { |
| * rr_graph.create_node(CHANX); |
| * } |
| */ |
| void reserve_nodes(const int& num_nodes); |
| void reserve_edges(const int& num_edges); |
| void reserve_switches(const int& num_switches); |
| void reserve_segments(const int& num_segments); |
| |
| /* Add new elements (node, edge, switch, etc.) to RRGraph */ |
| /* Add a node to the RRGraph with a deposited type |
| * Detailed node-level information should be added using the set_node_* functions |
| * For example: |
| * RRNodeId node = create_node(); |
| * set_node_xlow(node, 0); |
| */ |
| RRNodeId create_node(const t_rr_type& type); |
| /* Add a edge to the RRGraph, by providing the source and sink node |
| * This function will automatically create a node and |
| * configure the nodes and edges in connection |
| */ |
| RREdgeId create_edge(const RRNodeId& source, const RRNodeId& sink, const RRSwitchId& switch_id); |
| RRSwitchId create_switch(const t_rr_switch_inf& switch_info); |
| RRSegmentId create_segment(const t_segment_inf& segment_info); |
| |
| /* Remove elements from RRGraph |
| * This function just turn the nodes and edges to an invalid id without deletion |
| * This will cause the RRGraph to be marked as dirty (is_dirty(): false => true) |
| * To thoroughly remove the edges and nodes as well as clear the dirty flag, |
| * use compress() after the remove functions |
| * Example: |
| * RRGraph rr_graph; |
| * rr_graph.remove_node() |
| * .. // remove more nodes |
| * rr_graph.remove_edge() |
| * .. // remove more nodes |
| * // rr_graph.is_dirty() == true |
| * // If you want to access any node or edge |
| * // Check codes for ids should be intensively used |
| * // Such as, |
| * // for (const RREdgeId& in_edge : rr_graph.node_in_edges()) { |
| * // if (RREdgeId::INVALID() != in_edge) { |
| * // ... |
| * // } |
| * // } |
| * rr_graph.compress() |
| * // rr_graph.is_dirty() == false |
| */ |
| void remove_node(const RRNodeId& node); |
| void remove_edge(const RREdgeId& edge); |
| |
| /* Set node-level information */ |
| void set_node_xlow(const RRNodeId& node, const short& xlow); |
| void set_node_ylow(const RRNodeId& node, const short& ylow); |
| void set_node_xhigh(const RRNodeId& node, const short& xhigh); |
| void set_node_yhigh(const RRNodeId& node, const short& yhigh); |
| |
| /* This is a short-cut function, set xlow/xhigh/ylow/yhigh for a node |
| * Please respect the following to configure the bb object: |
| * bb.xmin = xlow, bb.ymin = ylow; bb.xmax = xhigh, bb.ymax = yhigh; |
| */ |
| void set_node_bounding_box(const RRNodeId& node, const vtr::Rect<short>& bb); |
| |
| void set_node_capacity(const RRNodeId& node, const short& capacity); |
| |
| /* A generic function to set the ptc_num for a node */ |
| void set_node_ptc_num(const RRNodeId& node, const short& ptc); |
| |
| /* Only applicable to IPIN and OPIN, set the ptc_num for a node, which is the pin id in a logic block, |
| * See definition in t_type_descriptor data structure |
| */ |
| void set_node_pin_num(const RRNodeId& node, const short& pin_id); |
| |
| /* Only applicable to CHANX and CHANY, set the ptc_num for a node, which is the track id in a routing channel, |
| * Routing channel is a group of routing tracks, each of which has a unique index |
| * An example |
| * Routing Channel |
| * +------------------+ |
| * | | |
| * ---|----------------->|----> track_id: 0 |
| * | | |
| * ... More tracks ... |
| * | | |
| * ---|----------------->|----> track_id: 1 |
| * | | |
| * +------------------+ |
| */ |
| void set_node_track_num(const RRNodeId& node, const short& track_id); |
| |
| /* Only applicable to SOURCE and SINK, set the ptc_num for a node, which is the class number in a logic block, |
| * See definition in t_type_descriptor data structure |
| */ |
| void set_node_class_num(const RRNodeId& node, const short& class_id); |
| |
| /* Set the routing cost index for node, see node_cost_index() for details */ |
| /* TODO: the cost index should be changed to a StrongId!!! */ |
| void set_node_cost_index(const RRNodeId& node, const short& cost_index); |
| |
| /* Set the directionality for a node, only applicable to CHANX and CHANY */ |
| void set_node_direction(const RRNodeId& node, const e_direction& direction); |
| |
| /* Set the side for a node, only applicable to OPIN and IPIN */ |
| void set_node_side(const RRNodeId& node, const e_side& side); |
| |
| /* Set the RC information for a node */ |
| void set_node_R(const RRNodeId& node, const float& R); |
| void set_node_C(const RRNodeId& node, const float& C); |
| |
| /* Set the routing segment linked to a node, only applicable to CHANX and CHANY */ |
| void set_node_segment(const RRNodeId& node, const RRSegmentId& segment_index); |
| |
| /* Edge partitioning is performed for efficiency, |
| * so we can store configurable and non-configurable edge lists for a node in one vector, |
| * and efficiently iterate over all edges, or only the configurable or non-configurable subsets. |
| * This function will re-organize the incoming and outgoing edges of each node, |
| * i.e., node_in_edges() and node_out_edges(): |
| * 1. configurable edges (1st part of the vectors) |
| * 2. non-configurable edges (2nd part of the vectors) |
| */ |
| void partition_edges(); |
| |
| /* Graph-level Clean-up, remove invalid nodes/edges etc. |
| * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if it was set |
| */ |
| void compress(); |
| |
| /* top-level function to free, should be called when to delete a RRGraph */ |
| void clear(); |
| |
| private: /* Internal Mutators to perform edge partitioning */ |
| /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ |
| void partition_node_in_edges(const RRNodeId& node); |
| |
| /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ |
| void partition_node_out_edges(const RRNodeId& node); |
| |
| /* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ |
| void partition_in_edges(); |
| |
| /* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ |
| void partition_out_edges(); |
| |
| private: /* Internal free functions */ |
| void clear_nodes(); |
| void clear_edges(); |
| void clear_switches(); |
| void clear_segments(); |
| |
| private: /* Graph Compression related */ |
| void build_id_maps(vtr::vector<RRNodeId, RRNodeId>& node_id_map, |
| vtr::vector<RREdgeId, RREdgeId>& edge_id_map); |
| void clean_nodes(const vtr::vector<RRNodeId, RRNodeId>& node_id_map); |
| void clean_edges(const vtr::vector<RREdgeId, RREdgeId>& edge_id_map); |
| void rebuild_node_refs(const vtr::vector<RREdgeId, RREdgeId>& edge_id_map); |
| |
| void set_dirty(); |
| void clear_dirty(); |
| |
| private: /* Internal validators and builders */ |
| /* Fast look-up builders and validators */ |
| void build_fast_node_lookup() const; |
| void invalidate_fast_node_lookup() const; |
| bool valid_fast_node_lookup() const; |
| void initialize_fast_node_lookup() const; |
| |
| /* Graph property Validation */ |
| bool validate_sizes() const; |
| bool validate_node_sizes() const; |
| bool validate_edge_sizes() const; |
| bool validate_switch_sizes() const; |
| bool validate_segment_sizes() const; |
| |
| bool validate_invariants() const; |
| bool validate_unique_edges_invariant() const; |
| |
| bool validate_crossrefs() const; |
| bool validate_node_edge_crossrefs() const; |
| |
| /* Node-level validators */ |
| bool validate_node_segment(const RRNodeId& node) const; |
| bool validate_node_in_edges(const RRNodeId& node) const; |
| bool validate_node_out_edges(const RRNodeId& node) const; |
| bool validate_node_edges(const RRNodeId& node) const; |
| |
| /* Edge-level checking */ |
| bool validate_node_is_edge_src(const RRNodeId& node, const RREdgeId& edge) const; |
| bool validate_node_is_edge_sink(const RRNodeId& node, const RREdgeId& edge) const; |
| bool validate_edge_switch(const RREdgeId& edge) const; |
| bool validate_edge_src_node(const RREdgeId& edge) const; |
| bool validate_edge_sink_node(const RREdgeId& edge) const; |
| |
| /* List-level checking */ |
| bool validate_nodes_in_edges() const; |
| bool validate_nodes_out_edges() const; |
| bool validate_nodes_edges() const; |
| bool validate_node_segments() const; |
| bool validate_edge_switches() const; |
| bool validate_edge_src_nodes() const; |
| bool validate_edge_sink_nodes() const; |
| |
| /* Validate switch list */ |
| bool valid_switch_id(const RRSwitchId& switch_id) const; |
| |
| /* Validate segment list */ |
| bool valid_segment_id(const RRSegmentId& segment_id) const; |
| |
| private: /* Internal Data */ |
| /* Node related data */ |
| vtr::vector<RRNodeId, RRNodeId> node_ids_; /* Unique identifiers for the nodes */ |
| vtr::vector<RRNodeId, t_rr_type> node_types_; |
| |
| vtr::vector<RRNodeId, vtr::Rect<short>> node_bounding_boxes_; |
| |
| vtr::vector<RRNodeId, short> node_capacities_; |
| vtr::vector<RRNodeId, short> node_ptc_nums_; |
| vtr::vector<RRNodeId, short> node_cost_indices_; |
| vtr::vector<RRNodeId, e_direction> node_directions_; |
| vtr::vector<RRNodeId, e_side> node_sides_; |
| vtr::vector<RRNodeId, float> node_Rs_; |
| vtr::vector<RRNodeId, float> node_Cs_; |
| vtr::vector<RRNodeId, RRSegmentId> node_segments_; /* Segment ids for each node */ |
| /* Record the dividing point between configurable and non-configurable edges for each node */ |
| vtr::vector<RRNodeId, size_t> node_num_non_configurable_in_edges_; |
| vtr::vector<RRNodeId, size_t> node_num_non_configurable_out_edges_; |
| |
| vtr::vector<RRNodeId, std::vector<RREdgeId>> node_in_edges_; |
| vtr::vector<RRNodeId, std::vector<RREdgeId>> node_out_edges_; |
| |
| /* Edge related data */ |
| vtr::vector<RREdgeId, RREdgeId> edge_ids_; /* unique identifiers for edges */ |
| vtr::vector<RREdgeId, RRNodeId> edge_src_nodes_; |
| vtr::vector<RREdgeId, RRNodeId> edge_sink_nodes_; |
| vtr::vector<RREdgeId, RRSwitchId> edge_switches_; |
| |
| /* Switch related data |
| * Note that so far there has been no need to remove |
| * switches, so no such facility exists |
| */ |
| /* Unique identifiers for switches which are used in the RRGraph */ |
| vtr::vector<RRSwitchId, RRSwitchId> switch_ids_; |
| /* Detailed information about the switches, which are used in the RRGraph */ |
| vtr::vector<RRSwitchId, t_rr_switch_inf> switches_; |
| |
| /* Segment relatex data |
| * Segment info should be corrected annotated for each rr_node |
| * whose type is CHANX and CHANY |
| */ |
| vtr::vector<RRSegmentId, RRSegmentId> segment_ids_; /* unique identifiers for routing segments which are used in the RRGraph */ |
| vtr::vector<RRSegmentId, t_segment_inf> segments_; /* detailed information about the segments, which are used in the RRGraph */ |
| |
| /* Misc. */ |
| /* A flag to indicate if the graph contains invalid elements (nodes/edges etc.) */ |
| bool dirty_ = false; |
| |
| /* Fast look-up to search a node by its type, coordinator and ptc_num |
| * Indexing of fast look-up: [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] |
| */ |
| typedef std::vector<std::vector<std::vector<std::vector<std::vector<RRNodeId>>>>> NodeLookup; |
| mutable NodeLookup node_lookup_; |
| }; |
| |
| #endif |