| #ifndef RR_NODE_H |
| #define RR_NODE_H |
| #include "rr_node_fwd.h" |
| #include "vpr_types.h" |
| |
| #include "vtr_range.h" |
| |
| #include <memory> |
| #include <cstdint> |
| /* Main structure describing one routing resource node. Everything in * |
| * this structure should describe the graph -- information needed only * |
| * to store algorithm-specific data should be stored in one of the * |
| * parallel rr_node_* structures. * |
| * * |
| * xlow, xhigh, ylow, yhigh: Integer coordinates (see route.c for * |
| * coordinate system) of the ends of this routing resource. * |
| * xlow = xhigh and ylow = yhigh for pins or for segments of * |
| * length 1. These values are used to decide whether or not this * |
| * node should be added to the expansion heap, based on things * |
| * like whether it's outside the net bounding box or is moving * |
| * further away from the target, etc. * |
| * type: What is this routing resource? * |
| * ptc_num: Pin, track or class number, depending on rr_node type. * |
| * Needed to properly draw. * |
| * cost_index: An integer index into the table of routing resource indexed * |
| * data t_rr_index_data (this indirection allows quick dynamic * |
| * changes of rr base costs, and some memory storage savings for * |
| * fields that have only a few distinct values). * |
| * capacity: Capacity of this node (number of routes that can use it). * |
| * num_edges: Number of edges exiting this node. That is, the number * |
| * of nodes to which it connects. * |
| * edges[0..num_edges-1]: Array of indices of the neighbours of this * |
| * node. * |
| * switches[0..num_edges-1]: Array of switch indexes for each of the * |
| * edges leaving this node. * |
| * * |
| * direction: if the node represents a track, this field * |
| * indicates the direction of the track. Otherwise * |
| * the value contained in the field should be * |
| * ignored. * |
| * side: The side of a grid location where an IPIN or OPIN is located. * |
| * This field is valid only for IPINs and OPINs and should be ignored * |
| * otherwise. */ |
| |
| class t_rr_node { |
| public: //Types |
| //An iterator that dereferences to an edge index |
| // |
| //Used inconjunction with vtr::Range to return ranges of edge indices |
| class edge_idx_iterator : public std::iterator<std::bidirectional_iterator_tag, t_edge_size> { |
| public: |
| edge_idx_iterator(value_type init) |
| : value_(init) {} |
| iterator operator++() { |
| value_ += 1; |
| return *this; |
| } |
| iterator operator--() { |
| value_ -= 1; |
| return *this; |
| } |
| reference operator*() { return value_; } |
| pointer operator->() { return &value_; } |
| |
| friend bool operator==(const edge_idx_iterator lhs, const edge_idx_iterator rhs) { return lhs.value_ == rhs.value_; } |
| friend bool operator!=(const edge_idx_iterator lhs, const edge_idx_iterator rhs) { return !(lhs == rhs); } |
| |
| private: |
| value_type value_; |
| }; |
| |
| typedef vtr::Range<edge_idx_iterator> edge_idx_range; |
| |
| public: //Accessors |
| t_rr_type type() const { return type_; } |
| const char* type_string() const; /* Retrieve type as a string */ |
| |
| edge_idx_range edges() const { return vtr::make_range(edge_idx_iterator(0), edge_idx_iterator(num_edges())); } |
| edge_idx_range configurable_edges() const { return vtr::make_range(edge_idx_iterator(0), edge_idx_iterator(num_edges() - num_non_configurable_edges())); } |
| edge_idx_range non_configurable_edges() const { return vtr::make_range(edge_idx_iterator(num_edges() - num_non_configurable_edges()), edge_idx_iterator(num_edges())); } |
| |
| t_edge_size num_edges() const { return num_edges_; } |
| t_edge_size num_configurable_edges() const { return num_edges() - num_non_configurable_edges(); } |
| t_edge_size num_non_configurable_edges() const { return num_non_configurable_edges_; } |
| |
| int edge_sink_node(t_edge_size iedge) const { |
| VTR_ASSERT_SAFE(iedge < num_edges()); |
| return edges_[iedge].sink_node; |
| } |
| short edge_switch(t_edge_size iedge) const { |
| VTR_ASSERT_SAFE(iedge < num_edges()); |
| return edges_[iedge].switch_id; |
| } |
| |
| bool edge_is_configurable(t_edge_size iedge) const; |
| t_edge_size fan_in() const; |
| |
| short xlow() const; |
| short ylow() const; |
| short xhigh() const; |
| short yhigh() const; |
| signed short length() const; |
| |
| short capacity() const; |
| |
| short ptc_num() const; |
| short pin_num() const; //Same as ptc_num() but checks that type() is consistent |
| short track_num() const; //Same as ptc_num() but checks that type() is consistent |
| short class_num() const; //Same as ptc_num() but checks that type() is consistent |
| |
| short cost_index() const; |
| short rc_index() const; |
| e_direction direction() const; |
| const char* direction_string() const; |
| |
| e_side side() const; |
| const char* side_string() const; |
| |
| float R() const; |
| float C() const; |
| |
| bool validate() const; |
| |
| public: //Mutators |
| void set_type(t_rr_type new_type); |
| |
| t_edge_size add_edge(int sink_node, int iswitch); |
| |
| void shrink_to_fit(); |
| |
| //Partitions all edges so that configurable and non-configurable edges |
| //are organized for efficient access. |
| // |
| //Must be called before configurable_edges(), non_configurable_edges(), |
| //num_configurable_edges(), num_non_configurable_edges() to ensure they |
| //are correct. |
| void partition_edges(); |
| |
| void set_num_edges(size_t); //Note will remove any previous edges |
| void set_edge_sink_node(t_edge_size iedge, int sink_node); |
| void set_edge_switch(t_edge_size iedge, short switch_index); |
| |
| void set_fan_in(t_edge_size); |
| |
| void set_coordinates(short x1, short y1, short x2, short y2); |
| |
| void set_capacity(short); |
| |
| void set_ptc_num(short); |
| void set_pin_num(short); //Same as set_ptc_num() by checks type() is consistent |
| void set_track_num(short); //Same as set_ptc_num() by checks type() is consistent |
| void set_class_num(short); //Same as set_ptc_num() by checks type() is consistent |
| |
| void set_cost_index(size_t); |
| void set_rc_index(short); |
| |
| void set_direction(e_direction); |
| void set_side(e_side); |
| |
| private: //Types |
| //The edge information is stored in a structure to economize on the number of pointers held |
| //by t_rr_node (to save memory), and is not exposed externally |
| struct t_rr_edge { |
| int sink_node = -1; //The ID of the sink RR node associated with this edge |
| short switch_id = -1; //The ID of the switch type this edge represents |
| }; |
| |
| private: //Data |
| //Note: we use a plain array and use small types for sizes to save space vs std::vector |
| // (using std::vector's nearly doubles the size of the class) |
| std::unique_ptr<t_rr_edge[]> edges_ = nullptr; |
| t_edge_size num_edges_ = 0; |
| t_edge_size edges_capacity_ = 0; |
| uint8_t num_non_configurable_edges_ = 0; |
| |
| int8_t cost_index_ = -1; |
| int16_t rc_index_ = -1; |
| |
| int16_t xlow_ = -1; |
| int16_t ylow_ = -1; |
| int16_t xhigh_ = -1; |
| int16_t yhigh_ = -1; |
| |
| t_rr_type type_ = NUM_RR_TYPES; |
| union { |
| e_direction direction; //Valid only for CHANX/CHANY |
| e_side side; //Valid only for IPINs/OPINs |
| } dir_side_; |
| |
| union { |
| int16_t pin_num; |
| int16_t track_num; |
| int16_t class_num; |
| } ptc_; |
| t_edge_size fan_in_ = 0; |
| uint16_t capacity_ = 0; |
| }; |
| |
| /* Data that is pointed to by the .cost_index member of t_rr_node. It's * |
| * purpose is to store the base_cost so that it can be quickly changed * |
| * and to store fields that have only a few different values (like * |
| * seg_index) or whose values should be an average over all rr_nodes of a * |
| * certain type (like T_linear etc., which are used to predict remaining * |
| * delay in the timing_driven router). * |
| * * |
| * base_cost: The basic cost of using an rr_node. * |
| * ortho_cost_index: The index of the type of rr_node that generally * |
| * connects to this type of rr_node, but runs in the * |
| * orthogonal direction (e.g. vertical if the direction * |
| * of this member is horizontal). * |
| * seg_index: Index into segment_inf of this segment type if this type of * |
| * rr_node is an CHANX or CHANY; OPEN (-1) otherwise. * |
| * inv_length: 1/length of this type of segment. * |
| * T_linear: Delay through N segments of this type is N * T_linear + N^2 * * |
| * T_quadratic. For buffered segments all delay is T_linear. * |
| * T_quadratic: Dominant delay for unbuffered segments, 0 for buffered * |
| * segments. * |
| * C_load: Load capacitance seen by the driver for each segment added to * |
| * the chain driven by the driver. 0 for buffered segments. */ |
| |
| struct t_rr_indexed_data { |
| float base_cost; |
| float saved_base_cost; |
| int ortho_cost_index; |
| int seg_index; |
| float inv_length; |
| float T_linear; |
| float T_quadratic; |
| float C_load; |
| }; |
| |
| /* |
| * Reistance/Capacitance data for an RR Nodes |
| * |
| * In practice many RR nodes have the same values, so they are fly-weighted |
| * to keep t_rr_node small. Each RR node holds an rc_index which allows |
| * retrieval of it's RC data. |
| * |
| * R: Resistance to go through an RR node. This is only metal |
| * resistance (end to end, so conservative) -- it doesn't include the |
| * switch that leads to another rr_node. |
| * C: Total capacitance of an RR node. Includes metal capacitance, the |
| * input capacitance of all switches hanging off the node, the |
| * output capacitance of all switches to the node, and the connection |
| * box buffer capacitances hanging off it. |
| */ |
| struct t_rr_rc_data { |
| t_rr_rc_data(float Rval, float Cval) noexcept; |
| |
| float R; |
| float C; |
| }; |
| |
| /* |
| * Returns the index to a t_rr_rc_data matching the specified values. |
| * |
| * If an existing t_rr_rc_data matches the specified R/C it's index |
| * is returned, otherwise the t_rr_rc_data is created. |
| * |
| * The returned indicies index into DeviceContext.rr_rc_data. |
| */ |
| short find_create_rr_rc_data(const float R, const float C); |
| |
| #endif |