OpenFPGA/vpr/src/route/rr_node.h

265 lines
11 KiB
C
Raw Normal View History

#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