diff --git a/openfpga/src/repack/lb_rr_graph.cpp b/openfpga/src/repack/lb_rr_graph.cpp new file mode 100644 index 000000000..99b0ecd1b --- /dev/null +++ b/openfpga/src/repack/lb_rr_graph.cpp @@ -0,0 +1,215 @@ +/************************************************************************ + * Member Functions of LbRRGraph + * include mutators, accessors and utility functions + ***********************************************************************/ +#include "vtr_assert.h" +#include "vtr_log.h" +#include "lb_rr_graph.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/************************************************** + * Public Accessors: Aggregates + *************************************************/ +LbRRGraph::node_range LbRRGraph::nodes() const { + return vtr::make_range(node_ids_.begin(), node_ids_.end()); +} + +LbRRGraph::edge_range LbRRGraph::edges() const { + return vtr::make_range(edge_ids_.begin(), edge_ids_.end()); +} + +/************************************************** + * Public Accessors node-level attributes + *************************************************/ +e_lb_rr_type LbRRGraph::node_type(const LbRRNodeId& node) const { + VTR_ASSERT(true == valid_node_id(node)); + return node_types_[node]; +} + +short LbRRGraph::node_capacity(const LbRRNodeId& node) const { + VTR_ASSERT(true == valid_node_id(node)); + return node_capacities_[node]; +} + +t_pb_graph_pin* LbRRGraph::node_pb_graph_pin(const LbRRNodeId& node) const { + VTR_ASSERT(true == valid_node_id(node)); + return node_pb_graph_pins_[node]; +} + +float LbRRGraph::node_intrinsic_cost(const LbRRNodeId& node) const { + VTR_ASSERT(true == valid_node_id(node)); + return node_intrinsic_costs_[node]; +} + +std::vector LbRRGraph::node_in_edges(const LbRRNodeId& node, t_mode* mode) const { + std::vector in_edges; + + VTR_ASSERT(true == valid_node_id(node)); + for (const LbRREdgeId& edge : node_in_edges_[node]) { + if (mode == edge_mode(edge)) { + in_edges.push_back(edge); + } + } + + return in_edges; +} + +std::vector LbRRGraph::node_out_edges(const LbRRNodeId& node, t_mode* mode) const { + std::vector out_edges; + + VTR_ASSERT(true == valid_node_id(node)); + for (const LbRREdgeId& edge : node_out_edges_[node]) { + if (mode == edge_mode(edge)) { + out_edges.push_back(edge); + } + } + + return out_edges; +} + +LbRRNodeId LbRRGraph::find_node(const e_lb_rr_type& type, t_pb_graph_pin* pb_graph_pin) const { + if (size_t(type) >= node_lookup_.size()) { + return LbRRNodeId::INVALID(); + } + + if (0 == node_lookup_[size_t(type)].count(pb_graph_pin)) { + return LbRRNodeId::INVALID(); + } + + return node_lookup_[size_t(type)].at(pb_graph_pin); +} + +LbRRNodeId LbRRGraph::edge_src_node(const LbRREdgeId& edge) const { + VTR_ASSERT(true == valid_edge_id(edge)); + return edge_src_nodes_[edge]; +} + +LbRRNodeId LbRRGraph::edge_sink_node(const LbRREdgeId& edge) const { + VTR_ASSERT(true == valid_edge_id(edge)); + return edge_sink_nodes_[edge]; +} + +float LbRRGraph::edge_intrinsic_cost(const LbRREdgeId& edge) const { + VTR_ASSERT(true == valid_edge_id(edge)); + return edge_intrinsic_costs_[edge]; +} + +t_mode* LbRRGraph::edge_mode(const LbRREdgeId& edge) const { + VTR_ASSERT(true == valid_edge_id(edge)); + return edge_modes_[edge]; +} + +/****************************************************************************** + * Public Mutators + ******************************************************************************/ +void LbRRGraph::reserve_nodes(const unsigned long& num_nodes) { + node_ids_.reserve(num_nodes); + node_types_.reserve(num_nodes); + node_capacities_.reserve(num_nodes); + node_pb_graph_pins_.reserve(num_nodes); + node_intrinsic_costs_.reserve(num_nodes); + + node_in_edges_.reserve(num_nodes); + node_out_edges_.reserve(num_nodes); +} + +void LbRRGraph::reserve_edges(const unsigned long& num_edges) { + edge_ids_.reserve(num_edges); + edge_intrinsic_costs_.reserve(num_edges); + edge_modes_.reserve(num_edges); + + edge_src_nodes_.reserve(num_edges); + edge_sink_nodes_.reserve(num_edges); +} + +LbRRNodeId LbRRGraph::create_node(const e_lb_rr_type& type) { + /* Create an new id */ + LbRRNodeId node = LbRRNodeId(node_ids_.size()); + node_ids_.push_back(node); + + /* Allocate other attributes */ + node_types_.push_back(type); + node_capacities_.push_back(-1); + node_pb_graph_pins_.push_back(nullptr); + node_intrinsic_costs_.push_back(0.); + + node_in_edges_.emplace_back(); + node_out_edges_.emplace_back(); + + return node; +} + +void LbRRGraph::set_node_type(const LbRRNodeId& node, const e_lb_rr_type& type) { + VTR_ASSERT(true == valid_node_id(node)); + node_types_[node] = type; +} + +void LbRRGraph::set_node_capacity(const LbRRNodeId& node, const short& capacity) { + VTR_ASSERT(true == valid_node_id(node)); + node_capacities_[node] = capacity; +} + +void LbRRGraph::set_node_pb_graph_pin(const LbRRNodeId& node, t_pb_graph_pin* pb_graph_pin) { + VTR_ASSERT(true == valid_node_id(node)); + node_pb_graph_pins_[node] = pb_graph_pin; + + /* Register in fast node look-up */ + if (node_type(node) >= node_lookup_.size()) { + node_lookup_.resize(node_type(node) + 1); + } + + if (0 < node_lookup_[node_type(node)].count(pb_graph_pin)) { + VTR_LOG_WARN("Detect pb_graph_pin '%s[%lu]' is mapped to LbRRGraph nodes (exist: %lu) and (to be mapped: %lu). Overwrite is done\n", + pb_graph_pin->port->name, pb_graph_pin->pin_number, + size_t(node_lookup_[node_type(node)].at(pb_graph_pin)), + size_t(node)); + } + node_lookup_[node_type(node)][pb_graph_pin] = node; +} + +void LbRRGraph::set_node_intrinsic_cost(const LbRRNodeId& node, const float& cost) { + VTR_ASSERT(true == valid_node_id(node)); + node_intrinsic_costs_[node] = cost; +} + +LbRREdgeId LbRRGraph::create_edge(const LbRRNodeId& source, + const LbRRNodeId& sink, + t_mode* mode) { + VTR_ASSERT(true == valid_node_id(source)); + VTR_ASSERT(true == valid_node_id(sink)); + + /* Create an new id */ + LbRREdgeId edge = LbRREdgeId(edge_ids_.size()); + edge_ids_.push_back(edge); + + /* Allocate other attributes */ + edge_src_nodes_.push_back(source); + edge_sink_nodes_.push_back(sink); + edge_intrinsic_costs_.push_back(0.); + edge_modes_.push_back(mode); + + node_out_edges_[source].push_back(edge); + node_in_edges_[sink].push_back(edge); + + return edge; +} + +void LbRRGraph::set_edge_intrinsic_cost(const LbRREdgeId& edge, const float& cost) { + VTR_ASSERT(true == valid_edge_id(edge)); + edge_intrinsic_costs_[edge] = cost; +} + +/****************************************************************************** + * Public validators/invalidators + ******************************************************************************/ +bool LbRRGraph::valid_node_id(const LbRRNodeId& node_id) const { + return ( size_t(node_id) < node_ids_.size() ) && ( node_id == node_ids_[node_id] ); +} + +bool LbRRGraph::valid_edge_id(const LbRREdgeId& edge_id) const { + return ( size_t(edge_id) < edge_ids_.size() ) && ( edge_id == edge_ids_[edge_id] ); +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/repack/lb_rr_graph.h b/openfpga/src/repack/lb_rr_graph.h new file mode 100644 index 000000000..c6cfbd552 --- /dev/null +++ b/openfpga/src/repack/lb_rr_graph.h @@ -0,0 +1,296 @@ +/************************************************************************ + * 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_types.h" + +#include "lb_rr_graph_fwd.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: /* 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, 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, t_mode* mode) const; + + LbRRNodeId find_node(const e_lb_rr_type& type, t_pb_graph_pin* pb_graph_pin) 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); + + /* 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: /* 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; + + 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_; +}; + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/src/repack/lb_rr_graph_fwd.h b/openfpga/src/repack/lb_rr_graph_fwd.h new file mode 100644 index 000000000..22363628b --- /dev/null +++ b/openfpga/src/repack/lb_rr_graph_fwd.h @@ -0,0 +1,19 @@ +#ifndef LB_RR_GRAPH_OBJ_FWD_H +#define LB_RR_GRAPH_OBJ_FWD_H +#include "vtr_strong_id.h" + +/*************************************************************** + * This file includes a light declaration for the class LbRRGraph + * For a detailed description and how to use the class LbRRGraph, + * please refer to lb_rr_graph_obj.h + ***************************************************************/ + +class LbRRGraph; + +struct lb_rr_node_id_tag; +struct lb_rr_edge_id_tag; + +typedef vtr::StrongId LbRRNodeId; +typedef vtr::StrongId LbRREdgeId; + +#endif diff --git a/vpr/src/pack/pack_types.h b/vpr/src/pack/pack_types.h index c8d266b57..794173217 100644 --- a/vpr/src/pack/pack_types.h +++ b/vpr/src/pack/pack_types.h @@ -13,20 +13,12 @@ #include "arch_types.h" #include "atom_netlist_fwd.h" +#include "lb_rr_graph_types.h" + /************************************************************************** * Packing Algorithm Enumerations ***************************************************************************/ -/* Describes different types of intra-logic cluster_ctx.blocks routing resource nodes */ -enum e_lb_rr_type { - LB_SOURCE = 0, - LB_SINK, - LB_INTERMEDIATE, - NUM_LB_RR_TYPES -}; -const std::vector lb_rr_type_str{ - "LB_SOURCE", "LB_SINK", "LB_INTERMEDIATE", "INVALID"}; - /************************************************************************** * Packing Algorithm Data Structures ***************************************************************************/