/************************************************************************ * This file introduces a class to model a Routing Resource Graph (RRGraph or *RRG) which is used by packer. * * Overview * ======== * RRGraph aims to describe in a general way how routing resources are connected * inside a pb_graph * * 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. an intermediate node(INTERMEDIATE_NODE), which are input/output pins of *non-primitive and non-root pb_graph_nodes. It represents a pb_graph_pin that *exists in a pb_graph * 2. a virtual source (SOURCE), which are inputs of root pb_graph_nodes or *outputs of primitive pb_graph_node * 3. a sink node (SINK), which are outputs of root pb_graph_nodes or inputs or *primitive pb_graph_node * * Edge * ---- * Each edge represents a connection between two pb_graph_pins * It represents a pb_graph_edge in a pb_graph * * Guidlines on using the LbRRGraph data structure * ============================================= * * For those want to access data from RRGraph * ------------------------------------------ * Some examples for most frequent data query: * * // Strongly suggest to use a read-only lb_rr_graph object * const LbRRGraph& lb_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 * LbRRNodeId node_id; * e_lb_rr_type node_type = lb_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); * * Please refer to the detailed comments on each public accessors * * For those want to build/modify a LbRRGraph * ----------------------------------------- * 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 lb_rr_graph; * ... // Building RRGraph * lb_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 +--------+ * * * 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. * * +---------+ pb_graph_pin +----------------+ * | RRGraph |---------------->| Pb_graph_node | * +---------+ pb_graph_edge +----------------+ * ***********************************************************************/ #ifndef LB_RR_GRAPH_OBJ_H #define LB_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 #include /* Header from vtrutil library */ #include "vtr_range.h" #include "vtr_vector.h" /* Header from readarch library */ #include "physical_types.h" /* Header from vpr library */ #include "lb_rr_graph_fwd.h" #include "pack_types.h" /* begin namespace openfpga */ namespace openfpga { class LbRRGraph { public: /* Types */ /* Iterators used to create iterator-based loop for * nodes/edges/switches/segments */ typedef vtr::vector::const_iterator node_iterator; typedef vtr::vector::const_iterator edge_iterator; /* Ranges used to create range-based loop for nodes/edges/switches/segments */ typedef vtr::Range node_range; typedef vtr::Range edge_range; public: /* Constructors */ LbRRGraph(); 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 LbRRGraph& lb_rr_graph; * for (const LbRRNodeId& node : lb_rr_graph.nodes()) { * // Do something with each node * } * * for (const LbRREdgeId& edge : lb_rr_graph.edges()) { * // Do something with each edge * } * */ node_range nodes() const; edge_range edges() const; /* Node-level attributes */ e_lb_rr_type node_type(const LbRRNodeId& node) const; short node_capacity(const LbRRNodeId& node) const; t_pb_graph_pin* node_pb_graph_pin(const LbRRNodeId& node) const; float node_intrinsic_cost(const LbRRNodeId& node) const; /* Get a list of edge ids, which are incoming edges to a node */ std::vector node_in_edges(const LbRRNodeId& node) const; std::vector node_in_edges(const LbRRNodeId& node, t_mode* mode) const; /* Get a list of edge ids, which are outgoing edges from a node */ std::vector node_out_edges(const LbRRNodeId& node) const; std::vector node_out_edges(const LbRRNodeId& node, t_mode* mode) const; /* General method to look up a node with type and only pb_graph_pin * information */ LbRRNodeId find_node(const e_lb_rr_type& type, const t_pb_graph_pin* pb_graph_pin) const; /* Method to find special node */ LbRRNodeId ext_source_node() const; LbRRNodeId ext_sink_node() const; /* General method to look up a edge with source and sink nodes */ std::vector find_edge(const LbRRNodeId& src_node, const LbRRNodeId& sink_node) const; /* Get the source node which drives a edge */ LbRRNodeId edge_src_node(const LbRREdgeId& edge) const; /* Get the sink node which a edge ends to */ LbRRNodeId edge_sink_node(const LbRREdgeId& edge) const; float edge_intrinsic_cost(const LbRREdgeId& edge) const; t_mode* edge_mode(const LbRREdgeId& 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: * LbRRGraph lb_rr_graph; * // Add 1000 CHANX nodes to the LbRRGraph object * rr_graph.reserve_nodes(1000); * for (size_t i = 0; i < 1000; ++i) { * rr_graph.create_node(CHANX); * } */ void reserve_nodes(const unsigned long& num_nodes); void reserve_edges(const unsigned long& num_edges); /* 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); */ LbRRNodeId create_node(const e_lb_rr_type& type); /* Create special nodes */ LbRRNodeId create_ext_source_node(const e_lb_rr_type& type); LbRRNodeId create_ext_sink_node(const e_lb_rr_type& type); /* Set node-level information */ void set_node_type(const LbRRNodeId& node, const e_lb_rr_type& type); void set_node_capacity(const LbRRNodeId& node, const short& capacity); void set_node_pb_graph_pin(const LbRRNodeId& node, t_pb_graph_pin* pb_graph_pin); void set_node_intrinsic_cost(const LbRRNodeId& node, const float& cost); /* 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 */ LbRREdgeId create_edge(const LbRRNodeId& source, const LbRRNodeId& sink, t_mode* mode); void set_edge_intrinsic_cost(const LbRREdgeId& edge, const float& cost); public: /* Public validators */ /* Validate is the node id does exist in the RRGraph */ bool valid_node_id(const LbRRNodeId& node) const; /* Validate is the edge id does exist in the RRGraph */ bool valid_edge_id(const LbRREdgeId& edge) const; bool validate() const; bool empty() const; private: /* Private Validators */ bool validate_node_sizes() const; bool validate_edge_sizes() const; bool validate_sizes() const; bool validate_node_is_edge_src(const LbRRNodeId& node, const LbRREdgeId& edge) const; bool validate_node_is_edge_sink(const LbRRNodeId& node, const LbRREdgeId& edge) const; bool validate_node_in_edges(const LbRRNodeId& node) const; bool validate_node_out_edges(const LbRRNodeId& node) const; bool validate_nodes_in_edges() const; bool validate_nodes_out_edges() const; bool validate_nodes_edges() const; private: /* Internal Data */ /* Node related data */ vtr::vector node_ids_; vtr::vector node_types_; vtr::vector node_capacities_; vtr::vector node_pb_graph_pins_; vtr::vector node_intrinsic_costs_; /* Edges per node is sorted by modes: [][] */ vtr::vector> node_in_edges_; vtr::vector> node_out_edges_; /* Edge related data */ /* Range of edge ids, use the unsigned long as * the number of edges could be >10 times larger than the number of nodes! */ vtr::vector edge_ids_; vtr::vector edge_src_nodes_; vtr::vector edge_sink_nodes_; vtr::vector edge_intrinsic_costs_; vtr::vector edge_modes_; /* Fast look-up to search a node by its type, coordinator and ptc_num * Indexing of fast look-up: [0..NUM_TYPES-1][t_pb_graph_pin*] */ typedef std::vector> NodeLookup; mutable NodeLookup node_lookup_; /* Special node look-up */ LbRRNodeId ext_source_node_; LbRRNodeId ext_sink_node_; }; } /* end namespace openfpga */ #endif