diff --git a/libs/librrgraph/src/base/rr_graph_builder.cpp b/libs/librrgraph/src/base/rr_graph_builder.cpp index ca73a5a3811..1ef61ec55da 100644 --- a/libs/librrgraph/src/base/rr_graph_builder.cpp +++ b/libs/librrgraph/src/base/rr_graph_builder.cpp @@ -29,8 +29,12 @@ void RRGraphBuilder::add_node_to_all_locs(RRNodeId node) { t_rr_type node_type = node_storage_.node_type(node); short node_ptc_num = node_storage_.node_ptc_num(node); short node_layer = node_storage_.node_layer(node); + short node_twist = node_storage_.node_ptc_twist(node); + int node_offset = 0; for (int ix = node_storage_.node_xlow(node); ix <= node_storage_.node_xhigh(node); ix++) { for (int iy = node_storage_.node_ylow(node); iy <= node_storage_.node_yhigh(node); iy++) { + node_ptc_num += node_twist * node_offset; + node_offset++; switch (node_type) { case SOURCE: case SINK: diff --git a/libs/librrgraph/src/base/rr_graph_builder.h b/libs/librrgraph/src/base/rr_graph_builder.h index cf82d64a24a..b58748e70fe 100644 --- a/libs/librrgraph/src/base/rr_graph_builder.h +++ b/libs/librrgraph/src/base/rr_graph_builder.h @@ -193,6 +193,12 @@ class RRGraphBuilder { node_storage_.set_node_layer(id, layer); } + /** @brief set the ptc twist increment number for TILEABLE rr graphs (for more information see rr_graph_storage.h twist increment comment) */ + inline void set_node_ptc_twist_incr(RRNodeId id, int twist){ + node_storage_.set_node_ptc_twist_incr(id, twist); + } + + /** @brief set_node_pin_num() is designed for logic blocks, which are IPIN and OPIN nodes */ inline void set_node_pin_num(RRNodeId id, int new_pin_num) { node_storage_.set_node_pin_num(id, new_pin_num); @@ -295,6 +301,12 @@ class RRGraphBuilder { inline void resize_nodes(size_t size) { node_storage_.resize(size); } + + /** @brief This function resize node ptc twist increment; Since it is only used for tileable rr-graph, we don't put it in general resize function*/ + inline void resize_ptc_twist_incr(size_t size){ + node_storage_.resize(size); + } + /** @brief This function resize rr_switch to accomidate size RR Switch. */ inline void resize_switches(size_t size) { rr_switch_inf_.resize(size); diff --git a/libs/librrgraph/src/base/rr_graph_storage.cpp b/libs/librrgraph/src/base/rr_graph_storage.cpp index ef85d779a4c..110ce1eca80 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.cpp +++ b/libs/librrgraph/src/base/rr_graph_storage.cpp @@ -622,6 +622,11 @@ void t_rr_graph_storage::set_node_layer(RRNodeId id, short layer) { node_layer_[id] = layer; } +void t_rr_graph_storage::set_node_ptc_twist_incr(RRNodeId id, short twist_incr){ + VTR_ASSERT(!node_ptc_twist_incr_.empty()); + node_ptc_twist_incr_[id] = twist_incr; +} + void t_rr_graph_storage::set_node_ptc_num(RRNodeId id, int new_ptc_num) { node_ptc_[id].ptc_.pin_num = new_ptc_num; //TODO: eventually remove } @@ -785,6 +790,7 @@ t_rr_graph_view t_rr_graph_storage::view() const { vtr::make_const_array_view_id(node_first_edge_), vtr::make_const_array_view_id(node_fan_in_), vtr::make_const_array_view_id(node_layer_), + vtr::make_const_array_view_id(node_ptc_twist_incr_), vtr::make_const_array_view_id(edge_src_node_), vtr::make_const_array_view_id(edge_dest_node_), vtr::make_const_array_view_id(edge_switch_)); diff --git a/libs/librrgraph/src/base/rr_graph_storage.h b/libs/librrgraph/src/base/rr_graph_storage.h index 09d80264645..7e4f21b5968 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.h +++ b/libs/librrgraph/src/base/rr_graph_storage.h @@ -199,7 +199,7 @@ class t_rr_graph_storage { } const std::string& node_direction_string(RRNodeId id) const; - /* Find if the given node appears on a specific side */ + /** @brief Find if the given node appears on a specific side */ bool is_node_on_specific_side(RRNodeId id, e_side side) const { return is_node_on_specific_side( vtr::array_view_id( @@ -216,34 +216,47 @@ class t_rr_graph_storage { */ const char* node_side_string(RRNodeId id) const; - /* PTC get methods */ + /** @brief PTC get methods */ int node_ptc_num(RRNodeId id) const; int node_pin_num(RRNodeId id) const; //Same as ptc_num() but checks that type() is consistent int node_track_num(RRNodeId id) const; //Same as ptc_num() but checks that type() is consistent int node_class_num(RRNodeId id) const; //Same as ptc_num() but checks that type() is consistent - /* Retrieve fan_in for RRNodeId, init_fan_in must have been called first. */ + /** @brief Retrieve fan_in for RRNodeId, init_fan_in must have been called first. */ t_edge_size fan_in(RRNodeId id) const { return node_fan_in_[id]; } - /* Find the layer number that RRNodeId is located at. + /** @brief Find the layer number that RRNodeId is located at. * it is zero if the FPGA only has one die. * The layer number start from the base die (base die: 0, the die above it: 1, etc.) - * */ + */ short node_layer(RRNodeId id) const{ return node_layer_[id]; } - // This prefetechs hot RR node data required for optimization. - // - // Note: This is optional, but may lower time spent on memory stalls in - // some circumstances. - inline void prefetch_node(RRNodeId id) const { - VTR_PREFETCH(&node_storage_[id], 0, 0); + /** @brief Find the twist number that RR node uses to change ptc number across the same track. + * By default this number is zero, meaning that ptc number across the same track should be the same. + * This number is only meaningful for CHANX/CHANY nodes, not the other nodes. + */ + short node_ptc_twist(RRNodeId id) const{ + //check whether node_ptc_twist_incr has been allocated + if(node_ptc_twist_incr_.empty()){ + return 0; + } + return node_ptc_twist_incr_[id]; } - /* Edge accessors + /** @brief This prefetechs hot RR node data required for optimization. + * + * Note: This is optional, but may lower time spent on memory stalls in + * some circumstances. + */ + inline void prefetch_node(RRNodeId id) const { + VTR_PREFETCH(&node_storage_[id], 0, 0); + } + + /** @brief Edge accessors * * Preferred access methods: * - first_edge(RRNodeId) @@ -263,7 +276,8 @@ class t_rr_graph_storage { * - edge_sink_node(RRNodeId, t_edge_size) * - edge_switch(RRNodeId, t_edge_size) * - * Only call these methods after partition_edges has been invoked. */ + * Only call these methods after partition_edges has been invoked. + */ edge_idx_range edges(const RRNodeId& id) const { return vtr::make_range(edge_idx_iterator(0), edge_idx_iterator(num_edges(id))); } @@ -282,37 +296,39 @@ class t_rr_graph_storage { t_edge_size num_configurable_edges(RRNodeId node, const vtr::vector& rr_switches) const; t_edge_size num_non_configurable_edges(RRNodeId node, const vtr::vector& rr_switches) const; - // Get the first and last RREdgeId for the specified RRNodeId. - // - // The edges belonging to RRNodeId is [first_edge, last_edge), excluding - // last_edge. - // - // If first_edge == last_edge, then a RRNodeId has no edges. - RREdgeId first_edge(const RRNodeId& id) const { + /** @brief Get the first and last RREdgeId for the specified RRNodeId. + * + * The edges belonging to RRNodeId is [first_edge, last_edge), excluding + * last_edge. + * + * If first_edge == last_edge, then a RRNodeId has no edges. + */ + RREdgeId first_edge(const RRNodeId& id) const { return node_first_edge_[id]; } - // Return the first_edge of the next rr_node, which is one past the edge - // id range for the node we care about. - // - // This implies we have one dummy rr_node at the end of first_edge_, and - // we always allocate that dummy node. We also assume that the edges have - // been sorted by rr_node, which is true after partition_edges(). + /** @brief the first_edge of the next rr_node, which is one past the edge id range for the node we care about. + * This implies we have one dummy rr_node at the end of first_edge_, and + * we always allocate that dummy node. We also assume that the edges have + * been sorted by rr_node, which is true after partition_edges(). + */ RREdgeId last_edge(const RRNodeId& id) const { return (&node_first_edge_[id])[1]; } - // Returns a range of RREdgeId's belonging to RRNodeId id. - // - // If this range is empty, then RRNodeId id has no edges. + /** @brief Returns a range of RREdgeId's belonging to RRNodeId id. + * + * If this range is empty, then RRNodeId id has no edges. + */ vtr::StrongIdRange edge_range(const RRNodeId id) const { return vtr::StrongIdRange(first_edge(id), last_edge(id)); } - // Retrieve the RREdgeId for iedge'th edge in RRNodeId. - // - // This method should generally not be used, and instead first_edge and - // last_edge should be used. + /** @brief Retrieve the RREdgeId for iedge'th edge in RRNodeId. + * + * This method should generally not be used, and instead first_edge and + * last_edge should be used. + */ RREdgeId edge_id(const RRNodeId& id, t_edge_size iedge) const { RREdgeId first_edge = this->first_edge(id); RREdgeId ret(size_t(first_edge) + iedge); @@ -320,12 +336,12 @@ class t_rr_graph_storage { return ret; } - // Get the destination node for the specified edge. + /** @brief Get the destination node for the specified edge. */ RRNodeId edge_sink_node(const RREdgeId& edge) const { return edge_dest_node_[edge]; } - // Call the `apply` function with the edge id, source, and sink nodes of every edge. + /** @brief Call the `apply` function with the edge id, source, and sink nodes of every edge. */ void for_each_edge(std::function apply) const { for (size_t i = 0; i < edge_dest_node_.size(); i++) { RREdgeId edge(i); @@ -333,28 +349,30 @@ class t_rr_graph_storage { } } - // Get the destination node for the iedge'th edge from specified RRNodeId. - // - // This method should generally not be used, and instead first_edge and - // last_edge should be used. + /** @brief Get the destination node for the iedge'th edge from specified RRNodeId. + * + * This method should generally not be used, and instead first_edge and + * last_edge should be used. + */ RRNodeId edge_sink_node(const RRNodeId& id, t_edge_size iedge) const { return edge_sink_node(edge_id(id, iedge)); } - // Get the switch used for the specified edge. + /** @brief Get the switch used for the specified edge. */ short edge_switch(const RREdgeId& edge) const { return edge_switch_[edge]; } - // Get the switch used for the iedge'th edge from specified RRNodeId. - // - // This method should generally not be used, and instead first_edge and - // last_edge should be used. + /** @brief Get the switch used for the iedge'th edge from specified RRNodeId. + * + * This method should generally not be used, and instead first_edge and + * last_edge should be used. + */ short edge_switch(const RRNodeId& id, t_edge_size iedge) const { return edge_switch(edge_id(id, iedge)); } - /* + /** @brief * Node proxy methods * * The following methods implement an interface that appears to be @@ -373,7 +391,7 @@ class t_rr_graph_storage { * These methods should not be used by new VPR code, and instead access * methods that use RRNodeId and RREdgeId should be used. * - **********************/ + */ node_idx_iterator begin() const; @@ -393,19 +411,21 @@ class t_rr_graph_storage { * Node allocation methods * ***************************/ - // Makes room in storage for RRNodeId in amoritized O(1) fashion. - // - // This results in an allocation pattern similiar to what would happen - // if push_back(x) / emplace_back() were used if underlying storage - // was not preallocated. + /** @brief + * Makes room in storage for RRNodeId in amoritized O(1) fashion. + * This results in an allocation pattern similiar to what would happen + * if push_back(x) / emplace_back() were used if underlying storage + * was not pre-allocated. + */ void make_room_for_node(RRNodeId elem_position) { make_room_in_vector(&node_storage_, size_t(elem_position)); node_ptc_.reserve(node_storage_.capacity()); node_ptc_.resize(node_storage_.size()); node_layer_.resize(node_storage_.size()); + node_ptc_twist_incr_.resize(node_storage_.size()); } - // Reserve storage for RR nodes. + /** @brief Reserve storage for RR nodes. */ void reserve(size_t size) { // No edges can be assigned if mutating the rr node array. VTR_ASSERT(!edges_read_); @@ -414,7 +434,7 @@ class t_rr_graph_storage { node_layer_.reserve(size); } - // Resize node storage to accomidate size RR nodes. + /** @brief Resize node storage to accomidate size RR nodes. */ void resize(size_t size) { // No edges can be assigned if mutating the rr node array. VTR_ASSERT(!edges_read_); @@ -423,25 +443,31 @@ class t_rr_graph_storage { node_layer_.resize(size); } - // Number of RR nodes that can be accessed. + /** @brief We only allocate the ptc twist increment array while building tileable rr-graphs */ + void resize_ptc_twist_incr(size_t size){ + node_ptc_twist_incr_.resize(size); + } + + /** @brief Number of RR nodes that can be accessed. */ size_t size() const { return node_storage_.size(); } - // Is the RR graph currently empty? + /** @brief Is the RR graph currently empty? */ bool empty() const { return node_storage_.empty(); } - // Remove all nodes and edges from the RR graph. - // - // This method re-enables graph mutation if the graph was read-only. + /** @brief Remove all nodes and edges from the RR graph. + * This method re-enables graph mutation if the graph was read-only. + */ void clear() { node_storage_.clear(); node_ptc_.clear(); node_first_edge_.clear(); node_fan_in_.clear(); node_layer_.clear(); + node_ptc_twist_incr_.clear(); edge_src_node_.clear(); edge_dest_node_.clear(); edge_switch_.clear(); @@ -451,35 +477,38 @@ class t_rr_graph_storage { remapped_edges_ = false; } - // Clear the data structures that are mainly used during RR graph construction. - // After RR Graph is build, we no longer need these data structures. + /** @brief + * Clear the data structures that are mainly used during RR graph construction. + * After RR Graph is build, we no longer need these data structures. + */ void clear_temp_storage() { edge_remapped_.clear(); } - // Clear edge_remap data structure, and then initialize it with the given value + /** @brief Clear edge_remap data structure, and then initialize it with the given value */ void init_edge_remap(bool val) { edge_remapped_.clear(); edge_remapped_.resize(edge_switch_.size(), val); } - // Shrink memory usage of the RR graph storage. - // - // Note that this will temporarily increase the amount of storage required - // to allocate the small array and copy the data. + /** @brief Shrink memory usage of the RR graph storage. + * Note that this will temporarily increase the amount of storage required + * to allocate the small array and copy the data. + */ void shrink_to_fit() { node_storage_.shrink_to_fit(); node_ptc_.shrink_to_fit(); node_first_edge_.shrink_to_fit(); node_fan_in_.shrink_to_fit(); node_layer_.shrink_to_fit(); + node_ptc_twist_incr_.shrink_to_fit(); edge_src_node_.shrink_to_fit(); edge_dest_node_.shrink_to_fit(); edge_switch_.shrink_to_fit(); edge_remapped_.shrink_to_fit(); } - // Append 1 more RR node to the RR graph. + /** @brief Append 1 more RR node to the RR graph.*/ void emplace_back() { // No edges can be assigned if mutating the rr node array. VTR_ASSERT(!edges_read_); @@ -488,15 +517,16 @@ class t_rr_graph_storage { node_layer_.emplace_back(); } - // Given `order`, a vector mapping each RRNodeId to a new one (old -> new), - // and `inverse_order`, its inverse (new -> old), update the t_rr_graph_storage - // data structure to an isomorphic graph using the new RRNodeId's. - // NOTE: Re-ordering will invalidate any external references, so this - // should generally be called before creating such references. + /** @brief Given `order`, a vector mapping each RRNodeId to a new one (old -> new), + * and `inverse_order`, its inverse (new -> old), update the t_rr_graph_storage + * data structure to an isomorphic graph using the new RRNodeId's. + * NOTE: Re-ordering will invalidate any external references, so this + * should generally be called before creating such references. + */ void reorder(const vtr::vector& order, const vtr::vector& inverse_order); - /* PTC set methods */ + /** @brief PTC set methods */ void set_node_ptc_num(RRNodeId id, int); void set_node_pin_num(RRNodeId id, int); //Same as set_ptc_num() by checks type() is consistent void set_node_track_num(RRNodeId id, int); //Same as set_ptc_num() by checks type() is consistent @@ -505,12 +535,14 @@ class t_rr_graph_storage { void set_node_type(RRNodeId id, t_rr_type new_type); void set_node_coordinates(RRNodeId id, short x1, short y1, short x2, short y2); void set_node_layer(RRNodeId id, short layer); + void set_node_ptc_twist_incr(RRNodeId id, short twist); void set_node_cost_index(RRNodeId, RRIndexedDataId new_cost_index); void set_node_rc_index(RRNodeId, NodeRCIndex new_rc_index); void set_node_capacity(RRNodeId, short new_capacity); void set_node_direction(RRNodeId, Direction new_direction); - /* Add a side to the node abbributes + /** @brief + * Add a side to the node abbributes * This is the function to use when you just add a new side WITHOUT reseting side attributes */ void add_node_side(RRNodeId, e_side new_side); @@ -568,7 +600,7 @@ class t_rr_graph_storage { /* Edge mutators */ - // Reserve at least num_edges in the edge backing arrays. + /** @brief Reserve at least num_edges in the edge backing arrays. */ void reserve_edges(size_t num_edges); /*** @@ -584,36 +616,41 @@ class t_rr_graph_storage { */ void emplace_back_edge(RRNodeId src, RRNodeId dest, short edge_switch, bool remapped); - // Adds a batch of edges. + /** @brief Adds a batch of edges.*/ void alloc_and_load_edges(const t_rr_edge_info_set* rr_edges_to_create); /* Edge finalization methods */ - // Counts the number of rr switches needed based on fan in to support mux - // size dependent switch delays. - // - // init_fan_in does not need to be invoked before this method. - size_t count_rr_switches( + /** @brief Counts the number of rr switches needed based on fan in to support mux + * size dependent switch delays. + * + * init_fan_in does not need to be invoked before this method. + */ + size_t count_rr_switches( const std::vector& arch_switch_inf, t_arch_switch_fanin& arch_switch_fanins); - // Maps arch_switch_inf indicies to rr_switch_inf indicies. - // - // This must be called before partition_edges if edges were created with - // arch_switch_inf indicies. + /** @brief Maps arch_switch_inf indicies to rr_switch_inf indicies. + * + * This must be called before partition_edges if edges were created with + * arch_switch_inf indicies. + */ void remap_rr_node_switch_indices(const t_arch_switch_fanin& switch_fanin); - // Marks that edge switch values are rr switch indicies. - // - // This must be called before partition_edges if edges were created with - // rr_switch_inf indicies. + /** @brief Marks that edge switch values are rr switch indicies. + * + * This must be called before partition_edges if edges were created with + * rr_switch_inf indicies. + */ void mark_edges_as_rr_switch_ids(); - // Sorts edge data such that configurable edges appears before - // non-configurable edges. + /** @brief + * Sorts edge data such that configurable edges appears before + * non-configurable edges. + */ void partition_edges(const vtr::vector& rr_switches); - // Validate that edge data is partitioned correctly. + /** @brief Validate that edge data is partitioned correctly.*/ bool validate_node(RRNodeId node_id, const vtr::vector& rr_switches) const; bool validate(const vtr::vector& rr_switches) const; @@ -621,9 +658,8 @@ class t_rr_graph_storage { * Fan-in methods * ******************/ - /* Init per node fan-in data. Should only be called after all edges have - * been allocated - * + /** @brief Init per node fan-in data. + * Should only be called after all edges have been allocated * This is an expensive, O(N), operation so it should be called once you * have a complete rr-graph and not called often.*/ void init_fan_in(); @@ -664,11 +700,13 @@ class t_rr_graph_storage { friend class edge_compare_dest_node; friend class edge_compare_src_node_and_configurable_first; - // Take allocated edges in edge_src_node_/ edge_dest_node_ / edge_switch_ - // sort, and assign the first edge for each + /** @brief + * Take allocated edges in edge_src_node_/ edge_dest_node_ / edge_switch_ + * sort, and assign the first edge for each + */ void assign_first_edges(); - // Verify that first_edge_ array correctly partitions rr edge data. + /** @brief Verify that first_edge_ array correctly partitions rr edge data. */ bool verify_first_edges() const; /***************** @@ -687,33 +725,51 @@ class t_rr_graph_storage { * *****************/ - // storage_ stores the core RR node data used by the router and is **very** - // hot. + /** @brief + * storage_ stores the core RR node data used by the router and is **very** + * hot. + */ vtr::vector> node_storage_; - // The PTC data is cold data, and is generally not used during the inner - // loop of either the placer or router. + /**@brief + * The PTC data is cold data, and is generally not used during the inner + * loop of either the placer or router. + */ vtr::vector node_ptc_; - // This array stores the first edge of each RRNodeId. Not that the length - // of this vector is always storage_.size() + 1, where the last value is - // always equal to the number of edges in the final graph. + /** @brief + * This array stores the first edge of each RRNodeId. Not that the length + * of this vector is always storage_.size() + 1, where the last value is + * always equal to the number of edges in the final graph. + */ vtr::vector node_first_edge_; - // Fan in counts for each RR node. + /** @brief Fan in counts for each RR node. */ vtr::vector node_fan_in_; - // Layer number that each RR node is located at - // Layer number refers to the die that the node belongs to. The layer number of base die is zero and die above it one, etc. - // This data is also considered as a hot data since it is used in inner loop of router, but since it didn't fit nicely into t_rr_node_data due to alignment issues, we had to store it - // in a separate vector. + /** @brief + * Layer number that each RR node is located at + * Layer number refers to the die that the node belongs to. The layer number of base die is zero and die above it one, etc. + * This data is also considered as a hot data since it is used in inner loop of router, but since it didn't fit nicely into t_rr_node_data due to alignment issues, we had to store it + *in a separate vector. + */ vtr::vector node_layer_; - // Edge storage. + /** @brief + *Twist Increment number is defined for CHANX/CHANY nodes; it is useful for layout of tileable FPGAs used by openFPGA. + *It gives us a new track index in each tile a longer wire crosses, which enables us to make long wires with a repeated single-tile pattern that "twists" the wires as they cross the tile. + *For example, an L4 wire would change tracks 4 times with metal shorts [e.g. 0, 2, 4, 6] and track 6 would drive a switch -- together this implements an L4 wire with only one layout tile. + * Twist increment number is only meaningful for CHANX and CHANY nodes; it is 0 for other node types. + * We also don't bother allocating this storage if the FPGA is not specified to be tileable; instead in that case the twist for all nodes will always be returned as 0. + */ + vtr::vector node_ptc_twist_incr_; + + /** @brief Edge storage */ vtr::vector edge_src_node_; vtr::vector edge_dest_node_; vtr::vector edge_switch_; - /** + + /** @brief * The delay of certain switches specified in the architecture file depends on the number of inputs of the edge's sink node (pins or tracks). * For example, in the case of a MUX switch, the delay increases as the number of inputs increases. * During the construction of the RR Graph, switch IDs are assigned to the edges according to the order specified in the architecture file. @@ -736,25 +792,27 @@ class t_rr_graph_storage { ***************/ public: /* Since rr_node_storage is an internal data of RRGraphView and RRGraphBuilder, expose these flags as public */ - // Has any edges been read? - // - // Any method that mutates edge storage will be locked out after this - // variable is set. - // - // Reading any of the following members should set this flag: - // - edge_src_node_ - // - edge_dest_node_ - // - edge_switch_ + /** @brief Has any edges been read? + * + * Any method that mutates edge storage will be locked out after this + * variable is set. + * + * Reading any of the following members should set this flag: + * - edge_src_node_ + * - edge_dest_node_ + * - edge_switch_ + */ mutable bool edges_read_; - // Set after either remap_rr_node_switch_indices or mark_edges_as_rr_switch_ids - // has been called. - // - // remap_rr_node_switch_indices converts indices to arch_switch_inf into - // indices to rr_switch_inf. + /** @brief Set after either remap_rr_node_switch_indices or mark_edges_as_rr_switch_ids + * has been called. + * + * remap_rr_node_switch_indices converts indices to arch_switch_inf into + * indices to rr_switch_inf. + */ bool remapped_edges_; - // Set after partition_edges has been called. + /** @brief Set after partition_edges has been called. */ bool partitioned_; }; @@ -775,6 +833,7 @@ class t_rr_graph_view { const vtr::array_view_id node_first_edge, const vtr::array_view_id node_fan_in, const vtr::array_view_id node_layer, + const vtr::array_view_id node_ptc_twist_incr, const vtr::array_view_id edge_src_node, const vtr::array_view_id edge_dest_node, const vtr::array_view_id edge_switch) @@ -783,6 +842,7 @@ class t_rr_graph_view { , node_first_edge_(node_first_edge) , node_fan_in_(node_fan_in) , node_layer_(node_layer) + , node_ptc_twist_incr_(node_ptc_twist_incr) , edge_src_node_(edge_src_node) , edge_dest_node_(edge_dest_node) , edge_switch_(edge_switch) {} @@ -844,6 +904,15 @@ class t_rr_graph_view { return node_layer_[id]; } + /* Retrieve twist number (if available) that RRNodeId used for its ptc number */ + short node_ptc_twist_incr(RRNodeId id) const{ + //check if ptc twist increment allocated + if(node_ptc_twist_incr_.empty()){ + return 0; //if it is not allocated we just assume that is zero + } + return node_ptc_twist_incr_[id]; + } + // This prefetechs hot RR node data required for optimization. // // Note: This is optional, but may lower time spent on memory stalls in @@ -885,6 +954,7 @@ class t_rr_graph_view { vtr::array_view_id node_first_edge_; vtr::array_view_id node_fan_in_; vtr::array_view_id node_layer_; + vtr::array_view_id node_ptc_twist_incr_; vtr::array_view_id edge_src_node_; vtr::array_view_id edge_dest_node_; vtr::array_view_id edge_switch_; diff --git a/libs/librrgraph/src/base/rr_graph_view.h b/libs/librrgraph/src/base/rr_graph_view.h index 3d808b23c71..1ff9a33115e 100644 --- a/libs/librrgraph/src/base/rr_graph_view.h +++ b/libs/librrgraph/src/base/rr_graph_view.h @@ -164,6 +164,11 @@ class RRGraphView { inline short node_layer(RRNodeId node) const { return node_storage_.node_layer(node); } + + /** @brief Get the ptc number twist of a routing resource node. This function is inlined for runtime optimization. */ + inline short node_ptc_twist(RRNodeId node) const{ + return node_storage_.node_ptc_twist(node); + } /** @brief Get the first out coming edge of resource node. This function is inlined for runtime optimization. */ inline RREdgeId node_first_edge(RRNodeId node) const { diff --git a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx.h b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx.h index 20f24fcd4f6..5099e2309e8 100644 --- a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx.h +++ b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx.h @@ -4,9 +4,9 @@ * https://github.com/duck2/uxsdcxx * Modify only if your build process doesn't involve regenerating this file. * - * Cmdline: uxsdcxx/uxsdcxx.py /home/amin/Desktop/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * Input file: /home/amin/Desktop/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * md5sum of input file: 38649d034e0edccbcb511ddb8915cdff + * Cmdline: uxsdcxx/uxsdcxx.py /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * Input file: /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * md5sum of input file: bf49388f038e0d0e4a12403ebb964b42 */ #include @@ -275,8 +275,8 @@ constexpr const char *atok_lookup_t_grid_loc[] = {"block_type_id", "height_offse enum class gtok_t_grid_locs {GRID_LOC}; constexpr const char *gtok_lookup_t_grid_locs[] = {"grid_loc"}; -enum class atok_t_node_loc {LAYER, PTC, SIDE, XHIGH, XLOW, YHIGH, YLOW}; -constexpr const char *atok_lookup_t_node_loc[] = {"layer", "ptc", "side", "xhigh", "xlow", "yhigh", "ylow"}; +enum class atok_t_node_loc {LAYER, PTC, SIDE, TWIST, XHIGH, XLOW, YHIGH, YLOW}; +constexpr const char *atok_lookup_t_node_loc[] = {"layer", "ptc", "side", "twist", "xhigh", "xlow", "yhigh", "ylow"}; enum class atok_t_node_timing {C, R}; @@ -1138,6 +1138,14 @@ inline atok_t_node_loc lex_attr_t_node_loc(const char *in, const std::function * report_error){ - std::bitset<7> astate = 0; + std::bitset<8> astate = 0; for(pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()){ atok_t_node_loc in = lex_attr_t_node_loc(attr.name(), report_error); if(astate[(int)in] == 0) astate[(int)in] = 1; @@ -2354,6 +2362,9 @@ inline void load_node_loc_required_attributes(const pugi::xml_node &root, int * case atok_t_node_loc::SIDE: /* Attribute side set after element init */ break; + case atok_t_node_loc::TWIST: + /* Attribute twist set after element init */ + break; case atok_t_node_loc::XHIGH: *xhigh = load_int(attr.value(), report_error); break; @@ -2369,7 +2380,7 @@ inline void load_node_loc_required_attributes(const pugi::xml_node &root, int * default: break; /* Not possible. */ } } - std::bitset<7> test_astate = astate | std::bitset<7>(0b0000101); + std::bitset<8> test_astate = astate | std::bitset<8>(0b00001101); if(!test_astate.all()) attr_error(test_astate, atok_lookup_t_node_loc, report_error); } @@ -3281,6 +3292,9 @@ inline void load_node_loc(const pugi::xml_node &root, T &out, Context &context, case atok_t_node_loc::SIDE: out.set_node_loc_side(lex_enum_loc_side(attr.value(), true, report_error), context); break; + case atok_t_node_loc::TWIST: + out.set_node_loc_twist(load_int(attr.value(), report_error), context); + break; case atok_t_node_loc::XHIGH: /* Attribute xhigh is already set */ break; @@ -4011,6 +4025,8 @@ inline void write_node(T &in, std::ostream &os, Context &context){ os << " ptc=\"" << in.get_node_loc_ptc(child_context) << "\""; if((bool)in.get_node_loc_side(child_context)) os << " side=\"" << lookup_loc_side[(int)in.get_node_loc_side(child_context)] << "\""; + if((bool)in.get_node_loc_twist(child_context)) + os << " twist=\"" << in.get_node_loc_twist(child_context) << "\""; os << " xhigh=\"" << in.get_node_loc_xhigh(child_context) << "\""; os << " xlow=\"" << in.get_node_loc_xlow(child_context) << "\""; os << " yhigh=\"" << in.get_node_loc_yhigh(child_context) << "\""; diff --git a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_capnp.h b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_capnp.h index 8bea9c7c033..c523a6d7f42 100644 --- a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_capnp.h +++ b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_capnp.h @@ -4,9 +4,9 @@ * https://github.com/duck2/uxsdcxx * Modify only if your build process doesn't involve regenerating this file. * - * Cmdline: uxsdcxx/uxsdcap.py /home/amin/Desktop/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * Input file: /home/amin/Desktop/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * md5sum of input file: 38649d034e0edccbcb511ddb8915cdff + * Cmdline: uxsdcxx/uxsdcap.py /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * Input file: /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * md5sum of input file: bf49388f038e0d0e4a12403ebb964b42 */ #include @@ -707,6 +707,7 @@ inline void load_node_loc_capnp_type(const ucap::NodeLoc::Reader &root, T &out, out.set_node_loc_layer(root.getLayer(), context); out.set_node_loc_side(conv_enum_loc_side(root.getSide(), report_error), context); + out.set_node_loc_twist(root.getTwist(), context); } template @@ -1160,6 +1161,8 @@ inline void write_node_capnp_type(T &in, ucap::Node::Builder &root, Context &con node_loc.setPtc(in.get_node_loc_ptc(child_context)); if((bool)in.get_node_loc_side(child_context)) node_loc.setSide(conv_to_enum_loc_side(in.get_node_loc_side(child_context))); + if((bool)in.get_node_loc_twist(child_context)) + node_loc.setTwist(in.get_node_loc_twist(child_context)); node_loc.setXhigh(in.get_node_loc_xhigh(child_context)); node_loc.setXlow(in.get_node_loc_xlow(child_context)); node_loc.setYhigh(in.get_node_loc_yhigh(child_context)); diff --git a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h index d31082159a7..1fa575acf1a 100644 --- a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h +++ b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h @@ -4,9 +4,9 @@ * https://github.com/duck2/uxsdcxx * Modify only if your build process doesn't involve regenerating this file. * - * Cmdline: uxsdcxx/uxsdcxx.py /home/amin/Desktop/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * Input file: /home/amin/Desktop/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * md5sum of input file: 38649d034e0edccbcb511ddb8915cdff + * Cmdline: uxsdcxx/uxsdcxx.py /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * Input file: /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * md5sum of input file: bf49388f038e0d0e4a12403ebb964b42 */ #include @@ -368,6 +368,7 @@ class RrGraphBase { * * * + * * */ virtual inline int get_node_loc_layer(typename ContextTypes::NodeLocReadContext &ctx) = 0; @@ -375,6 +376,8 @@ class RrGraphBase { virtual inline int get_node_loc_ptc(typename ContextTypes::NodeLocReadContext &ctx) = 0; virtual inline enum_loc_side get_node_loc_side(typename ContextTypes::NodeLocReadContext &ctx) = 0; virtual inline void set_node_loc_side(enum_loc_side side, typename ContextTypes::NodeLocWriteContext &ctx) = 0; + virtual inline int get_node_loc_twist(typename ContextTypes::NodeLocReadContext &ctx) = 0; + virtual inline void set_node_loc_twist(int twist, typename ContextTypes::NodeLocWriteContext &ctx) = 0; virtual inline int get_node_loc_xhigh(typename ContextTypes::NodeLocReadContext &ctx) = 0; virtual inline int get_node_loc_xlow(typename ContextTypes::NodeLocReadContext &ctx) = 0; virtual inline int get_node_loc_yhigh(typename ContextTypes::NodeLocReadContext &ctx) = 0; diff --git a/libs/librrgraph/src/io/rr_graph.xsd b/libs/librrgraph/src/io/rr_graph.xsd index 17dfe09a7e0..6b6650e100c 100644 --- a/libs/librrgraph/src/io/rr_graph.xsd +++ b/libs/librrgraph/src/io/rr_graph.xsd @@ -266,6 +266,7 @@ + diff --git a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h index 9154e353643..736ea358a81 100644 --- a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h +++ b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h @@ -713,6 +713,9 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { inline int get_node_loc_layer(const t_rr_node& node) final { return rr_graph_->node_layer(node.id()); } + inline int get_node_loc_twist(const t_rr_node& node) final{ + return rr_graph_->node_ptc_twist(node.id()); + } inline int get_node_loc_xhigh(const t_rr_node& node) final { return rr_graph_->node_xhigh(node.id()); } @@ -756,6 +759,13 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { } } } + + inline void set_node_loc_twist(int twist, int& inode) final { + auto node = (*rr_nodes_)[inode]; + RRNodeId node_id = node.id(); + rr_graph_builder_->set_node_ptc_twist_incr(node_id,twist); + } + inline uxsd::enum_loc_side get_node_loc_side(const t_rr_node& node) final { const auto& rr_graph = (*rr_graph_); if (rr_graph.node_type(node.id()) == IPIN || rr_graph.node_type(node.id()) == OPIN) { diff --git a/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp b/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp index 9c99d068554..bba305feef1 100644 --- a/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp +++ b/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp @@ -2,11 +2,11 @@ # https://github.com/duck2/uxsdcxx # Modify only if your build process doesn't involve regenerating this file. # -# Cmdline: uxsdcxx/uxsdcap.py /home/amin/Desktop/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd -# Input file: /home/amin/Desktop/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd -# md5sum of input file: 38649d034e0edccbcb511ddb8915cdff +# Cmdline: uxsdcxx/uxsdcap.py /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd +# Input file: /home/smahmoudi/Desktop/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd +# md5sum of input file: bf49388f038e0d0e4a12403ebb964b42 -@0xd7cc43f5845f4c7f; +@0xf7009c96d0510b05; using Cxx = import "/capnp/c++.capnp"; $Cxx.namespace("ucap"); @@ -165,10 +165,11 @@ struct NodeLoc { layer @0 :Int32 = 0; ptc @1 :Int32; side @2 :LocSide; - xhigh @3 :Int32; - xlow @4 :Int32; - yhigh @5 :Int32; - ylow @6 :Int32; + twist @3 :Int32; + xhigh @4 :Int32; + xlow @5 :Int32; + yhigh @6 :Int32; + ylow @7 :Int32; } struct NodeTiming { diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index a046361c926..0b0bb8f90ab 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -1367,6 +1367,26 @@ static void build_rr_graph(const t_graph_type graph_type, } } + /*Update rr_nodes ptc_twist_incr number if we are creating tileable graph*/ + if (graph_type == GRAPH_UNIDIR_TILEABLE) { + device_ctx.rr_graph_builder.resize_ptc_twist_incr(num_rr_nodes); + for (int rr_node_id = 0; rr_node_id < num_rr_nodes; rr_node_id++) { + auto node_type = rr_graph.node_type(RRNodeId(rr_node_id)); + auto node_dir = rr_graph.node_direction(RRNodeId(rr_node_id)); + if (node_type != CHANX && node_type != CHANY) { //SRC/SINK/IPIN/OPIN + device_ctx.rr_graph_builder.set_node_ptc_twist_incr(RRNodeId(rr_node_id), 0); + } else { + //The current ptc twist increment number in UNDIR TILEABLE RRGraph is 2 and -2 + //The assumption should be synced up with openFPGA branch + if (node_dir == Direction::INC) { + device_ctx.rr_graph_builder.set_node_ptc_twist_incr(RRNodeId(rr_node_id), 2); + } else { + device_ctx.rr_graph_builder.set_node_ptc_twist_incr(RRNodeId(rr_node_id), -2); + } + } + } + } + update_chan_width(&nodes_per_chan); /* Allocate and load routing resource switches, which are derived from the switches from the architecture file, @@ -2089,6 +2109,7 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder num_edges = 0; /* Build channels */ VTR_ASSERT(Fs % 3 == 0); + for (int layer = 0; layer < grid.get_num_layers(); ++layer) { auto& device_ctx = g_vpr_ctx.device(); /* Skip the current die if architecture file specifies that it doesn't require inter-cluster programmable resource routing */ @@ -2214,6 +2235,7 @@ static void alloc_and_load_intra_cluster_rr_graph(RRGraphBuilder& rr_graph_build bool load_rr_graph) { t_rr_edge_info_set rr_edges_to_create; int num_edges = 0; + for (int layer = 0; layer < grid.get_num_layers(); layer++) { for (int i = 0; i < (int)grid.width(); ++i) { for (int j = 0; j < (int)grid.height(); ++j) {