Merge branch 'refactoring' into dev

This commit is contained in:
tangxifan 2020-01-31 17:29:17 -07:00
commit f136dd8820
16 changed files with 1003 additions and 364 deletions

View File

@ -163,9 +163,10 @@ enum e_interconnect {
COMPLETE_INTERC = 1, COMPLETE_INTERC = 1,
DIRECT_INTERC = 2, DIRECT_INTERC = 2,
MUX_INTERC = 3, MUX_INTERC = 3,
NUM_INTERC_TYPES NUM_INTERC_TYPES /* Xifan Tang - Invalid types for interconnect */
}; };
constexpr std::array<const char*, NUM_INTERC_TYPES> INTERCONNECT_TYPE_STRING = {{"complete", "direct", "mux"}}; //String versions of interconnection type /* Xifan Tang - String versions of interconnection type */
constexpr std::array<const char*, NUM_INTERC_TYPES> INTERCONNECT_TYPE_STRING = {{"complete", "direct", "mux"}};
/* Orientations. */ /* Orientations. */
enum e_side : unsigned char { enum e_side : unsigned char {

View File

@ -79,6 +79,12 @@ Rect<T>::Rect(Point<T> bottom_left_val, Point<T> top_right_val)
//pass //pass
} }
template<class T>
Rect<T>::Rect() {
//pass
}
template<class T> template<class T>
T Rect<T>::xmin() const { T Rect<T>::xmin() const {
return bottom_left_.x(); return bottom_left_.x();

View File

@ -1,5 +1,5 @@
# Run VPR for the s298 design # Run VPR for the s298 design
vpr ./test_vpr_arch/k6_frac_N10_40nm.xml ./test_blif/s298.blif vpr ./test_vpr_arch/k6_frac_N10_40nm.xml ./test_blif/s298.blif --write_rr_graph example_rr_graph.xml
# Read OpenFPGA architecture definition # Read OpenFPGA architecture definition
read_openfpga_arch -f ./test_openfpga_arch/k6_frac_N10_40nm_openfpga.xml read_openfpga_arch -f ./test_openfpga_arch/k6_frac_N10_40nm_openfpga.xml

View File

@ -22,6 +22,8 @@
#include "place_macro.h" #include "place_macro.h"
#include "compressed_grid.h" #include "compressed_grid.h"
#include "rr_graph_obj.h"
//A Context is collection of state relating to a particular part of VPR //A Context is collection of state relating to a particular part of VPR
// //
//This is a base class who's only purpose is to disable copying of contexts. //This is a base class who's only purpose is to disable copying of contexts.
@ -143,6 +145,9 @@ struct DeviceContext : public Context {
/* chan_width is for x|y-directed channels; i.e. between rows */ /* chan_width is for x|y-directed channels; i.e. between rows */
t_chan_width chan_width; t_chan_width chan_width;
/* RRGraph object */
RRGraph rr_graph;
/* Structures to define the routing architecture of the FPGA. */ /* Structures to define the routing architecture of the FPGA. */
std::vector<t_rr_node> rr_nodes; /* autogenerated in build_rr_graph */ std::vector<t_rr_node> rr_nodes; /* autogenerated in build_rr_graph */

View File

@ -40,6 +40,9 @@
#include "vtr_flat_map.h" #include "vtr_flat_map.h"
#include "vtr_cache.h" #include "vtr_cache.h"
/* Header for rr_graph related definition */
#include "rr_graph_types.h"
/******************************************************************************* /*******************************************************************************
* Global data types and constants * Global data types and constants
******************************************************************************/ ******************************************************************************/
@ -1011,15 +1014,6 @@ struct t_det_routing_arch {
std::string write_rr_graph_filename; std::string write_rr_graph_filename;
}; };
enum e_direction : unsigned char {
INC_DIRECTION = 0,
DEC_DIRECTION = 1,
BI_DIRECTION = 2,
NO_DIRECTION = 3,
NUM_DIRECTIONS
};
constexpr std::array<const char*, NUM_DIRECTIONS> DIRECTION_STRING = {{"INC_DIRECTION", "DEC_DIRECTION", "BI_DIRECTION", "NO_DIRECTION"}};
/* Lists detailed information about segmentation. [0 .. W-1]. * /* Lists detailed information about segmentation. [0 .. W-1]. *
* length: length of segment. * * length: length of segment. *
@ -1132,26 +1126,6 @@ struct t_linked_f_pointer {
typedef std::vector<std::vector<std::vector<std::vector<std::vector<int>>>>> t_rr_node_indices; //[0..num_rr_types-1][0..grid_width-1][0..grid_height-1][0..NUM_SIDES-1][0..max_ptc-1] typedef std::vector<std::vector<std::vector<std::vector<std::vector<int>>>>> t_rr_node_indices; //[0..num_rr_types-1][0..grid_width-1][0..grid_height-1][0..NUM_SIDES-1][0..max_ptc-1]
/* Type of a routing resource node. x-directed channel segment, *
* y-directed channel segment, input pin to a clb to pad, output *
* from a clb or pad (i.e. output pin of a net) and: *
* SOURCE: A dummy node that is a logical output within a block *
* -- i.e., the gate that generates a signal. *
* SINK: A dummy node that is a logical input within a block *
* -- i.e. the gate that needs a signal. */
typedef enum e_rr_type : unsigned char {
SOURCE = 0,
SINK,
IPIN,
OPIN,
CHANX,
CHANY,
NUM_RR_TYPES
} t_rr_type;
constexpr std::array<t_rr_type, NUM_RR_TYPES> RR_TYPES = {{SOURCE, SINK, IPIN, OPIN, CHANX, CHANY}};
constexpr std::array<const char*, NUM_RR_TYPES> rr_node_typename{{"SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY"}};
/* Basic element used to store the traceback (routing) of each net. * /* Basic element used to store the traceback (routing) of each net. *
* index: Array index (ID) of this routing resource node. * * index: Array index (ID) of this routing resource node. *
* iswitch: Index of the switch type used to go from this rr_node to * * iswitch: Index of the switch type used to go from this rr_node to *

View File

@ -107,7 +107,7 @@ static bool check_rr_graph_source_nodes(const RRGraph& rr_graph) {
} }
} }
return invalid_sources; return !invalid_sources;
} }
/*********************************************************************** /***********************************************************************
@ -136,7 +136,7 @@ static bool check_rr_graph_sink_nodes(const RRGraph& rr_graph) {
} }
} }
return invalid_sinks; return !invalid_sinks;
} }
/*********************************************************************** /***********************************************************************
@ -153,48 +153,43 @@ static bool check_rr_graph_sink_nodes(const RRGraph& rr_graph) {
* will work properly. * will work properly.
**********************************************************************/ **********************************************************************/
bool check_rr_graph(const RRGraph& rr_graph) { bool check_rr_graph(const RRGraph& rr_graph) {
bool check_flag = true;
size_t num_err = 0; size_t num_err = 0;
if (false == check_rr_graph_duplicated_edges(rr_graph)) { if (false == check_rr_graph_duplicated_edges(rr_graph)) {
VTR_LOG_WARN("Fail in checking duplicated edges !\n"); VTR_LOG_WARN("Fail in checking duplicated edges !\n");
check_flag = false;
num_err++; num_err++;
} }
if (false == check_rr_graph_dangling_nodes(rr_graph)) { if (false == check_rr_graph_dangling_nodes(rr_graph)) {
VTR_LOG_WARN("Fail in checking dangling nodes !\n"); VTR_LOG_WARN("Fail in checking dangling nodes !\n");
check_flag = false;
num_err++; num_err++;
} }
if (false == check_rr_graph_source_nodes(rr_graph)) { if (false == check_rr_graph_source_nodes(rr_graph)) {
VTR_LOG_WARN("Fail in checking source nodes!\n"); VTR_LOG_WARN("Fail in checking source nodes!\n");
check_flag = false;
num_err++; num_err++;
} }
if (false == check_rr_graph_sink_nodes(rr_graph)) { if (false == check_rr_graph_sink_nodes(rr_graph)) {
VTR_LOG_WARN("Fail in checking sink nodes!\n"); VTR_LOG_WARN("Fail in checking sink nodes!\n");
check_flag = false;
num_err++; num_err++;
} }
if (false == check_rr_graph_source_nodes(rr_graph)) { if (false == check_rr_graph_source_nodes(rr_graph)) {
VTR_LOG_WARN("Fail in checking source nodes!\n"); VTR_LOG_WARN("Fail in checking source nodes!\n");
check_flag = false;
num_err++; num_err++;
} }
if (false == check_rr_graph_sink_nodes(rr_graph)) { if (false == check_rr_graph_sink_nodes(rr_graph)) {
VTR_LOG_WARN("Fail in checking sink nodes!\n"); VTR_LOG_WARN("Fail in checking sink nodes!\n");
check_flag = false;
num_err++; num_err++;
} }
/* Error out if there is any fatal errors found */ /* Error out if there is any fatal errors found */
VTR_LOG_WARN("Checked Routing Resource graph with %d errors !\n", if (0 < num_err) {
num_err); VTR_LOG_WARN("Checked Routing Resource graph with %d errors !\n",
num_err);
}
return check_flag; return (0 == num_err);
} }

View File

@ -0,0 +1,138 @@
/* Standard header files required go first */
#include <map>
/* EXTERNAL library header files go second*/
#include "vtr_assert.h"
#include "vtr_time.h"
#include "vtr_memory.h"
/* VPR header files go then */
#include "vpr_types.h"
#include "rr_graph_obj.h"
#include "check_rr_graph_obj.h"
#include "create_rr_graph.h"
/* Finally we include global variables */
#include "globals.h"
/********************************************************************
* TODO: remove when this conversion (from traditional to new data structure)
* is no longer needed
* This function will convert an existing rr_graph in device_ctx to the RRGraph
*object
* This function is used to test our RRGraph if it is acceptable in downstream
*routers
********************************************************************/
void convert_rr_graph(std::vector<t_segment_inf>& vpr_segments) {
/* Release freed memory before start building rr_graph */
vtr::malloc_trim(0);
vtr::ScopedStartFinishTimer timer("Conversion to routing resource graph object");
/* IMPORTANT: to build clock tree,
* vpr added segments to the original arch segments
* This is why to use vpr_segments as an inputs!!!
*/
auto& device_ctx = g_vpr_ctx.mutable_device();
/* The number of switches are in general small,
* reserve switches may not bring significant memory efficiency
* So, we just use create_switch to push_back each time
*/
device_ctx.rr_graph.reserve_switches(device_ctx.rr_switch_inf.size());
// Create the switches
for (size_t iswitch = 0; iswitch < device_ctx.rr_switch_inf.size(); ++iswitch) {
device_ctx.rr_graph.create_switch(device_ctx.rr_switch_inf[iswitch]);
}
/* The number of segments are in general small, reserve segments may not bring
* significant memory efficiency */
device_ctx.rr_graph.reserve_segments(vpr_segments.size());
// Create the segments
for (size_t iseg = 0; iseg < vpr_segments.size(); ++iseg) {
device_ctx.rr_graph.create_segment(vpr_segments[iseg]);
}
/* Reserve list of nodes to be memory efficient */
device_ctx.rr_graph.reserve_nodes((unsigned long)device_ctx.rr_nodes.size());
// Create the nodes
for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) {
auto& node = device_ctx.rr_nodes[inode];
RRNodeId rr_node = device_ctx.rr_graph.create_node(node.type());
device_ctx.rr_graph.set_node_xlow(rr_node, node.xlow());
device_ctx.rr_graph.set_node_ylow(rr_node, node.ylow());
device_ctx.rr_graph.set_node_xhigh(rr_node, node.xhigh());
device_ctx.rr_graph.set_node_yhigh(rr_node, node.yhigh());
device_ctx.rr_graph.set_node_capacity(rr_node, node.capacity());
device_ctx.rr_graph.set_node_ptc_num(rr_node, node.ptc_num());
device_ctx.rr_graph.set_node_cost_index(rr_node, node.cost_index());
if (CHANX == node.type() || CHANY == node.type()) {
device_ctx.rr_graph.set_node_direction(rr_node, node.direction());
}
if (IPIN == node.type() || OPIN == node.type()) {
device_ctx.rr_graph.set_node_side(rr_node, node.side());
}
device_ctx.rr_graph.set_node_R(rr_node, node.R());
device_ctx.rr_graph.set_node_C(rr_node, node.C());
/* Set up segment id */
short irc_data = node.cost_index();
short iseg = device_ctx.rr_indexed_data[irc_data].seg_index;
device_ctx.rr_graph.set_node_segment(rr_node, RRSegmentId(iseg));
}
/* Reserve list of edges to be memory efficient */
unsigned long num_edges_to_reserve = 0;
for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) {
const auto& node = device_ctx.rr_nodes[inode];
num_edges_to_reserve += node.num_edges();
}
device_ctx.rr_graph.reserve_edges(num_edges_to_reserve);
/* Add edges for each node */
for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) {
const auto& node = device_ctx.rr_nodes[inode];
for (int iedge = 0; iedge < node.num_edges(); ++iedge) {
size_t isink_node = node.edge_sink_node(iedge);
int iswitch = node.edge_switch(iedge);
device_ctx.rr_graph.create_edge(RRNodeId(inode),
RRNodeId(isink_node),
RRSwitchId(iswitch));
}
}
/* Ensure that we reserved what we want */
VTR_ASSERT(num_edges_to_reserve == (unsigned long)device_ctx.rr_graph.edges().size());
/* Partition edges to be two class: configurable (1st part) and
* non-configurable (2nd part)
* See how the router will use the edges and determine the strategy
* if we want to partition the edges first or depends on the routing needs
*/
device_ctx.rr_graph.rebuild_node_edges();
/* Essential check for rr_graph, build look-up and */
if (false == device_ctx.rr_graph.validate()) {
/* Error out if built-in validator of rr_graph fails */
vpr_throw(VPR_ERROR_ROUTE,
__FILE__,
__LINE__,
"Fundamental errors occurred when validating rr_graph object!\n");
}
/* Error out if advanced checker of rr_graph fails */
if (false == check_rr_graph(device_ctx.rr_graph)) {
vpr_throw(VPR_ERROR_ROUTE,
__FILE__,
__LINE__,
"Advanced checking rr_graph object fails! Routing may still work "
"but not smooth\n");
}
}

View File

@ -0,0 +1,17 @@
#ifndef CREATE_RR_GRAPH_H
#define CREATE_RR_GRAPH_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!
*/
#include "rr_graph_obj.h"
/* IMPORTANT: to build clock tree,
* vpr added segments to the original arch segments
* This is why to use vpr_segments as an inputs!!!
*/
void convert_rr_graph(std::vector<t_segment_inf>& vpr_segments);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -198,30 +198,44 @@
/* Standard header files required go first */ /* Standard header files required go first */
#include <limits> #include <limits>
#include <vector> #include <vector>
#include <unordered_set>
#include <unordered_map>
/* EXTERNAL library header files go second*/ /* EXTERNAL library header files go second*/
#include "vtr_ndmatrix.h"
#include "vtr_vector.h" #include "vtr_vector.h"
#include "vtr_range.h" #include "vtr_range.h"
#include "vtr_geometry.h" #include "vtr_geometry.h"
#include "arch_types.h" #include "arch_types.h"
/* VPR header files go third */ /* VPR header files go third */
#include "vpr_types.h" #include "rr_graph_types.h"
#include "rr_graph_fwd.h" #include "rr_graph_fwd.h"
class RRGraph { class RRGraph {
public: /* Types */ public: /* Types */
//Lazy iterator utility forward declaration
template<class ID>
class lazy_id_iterator;
/* Iterators used to create iterator-based loop for nodes/edges/switches/segments */ /* Iterators used to create iterator-based loop for nodes/edges/switches/segments */
typedef vtr::vector<RRNodeId, RRNodeId>::const_iterator node_iterator; typedef vtr::vector<RRNodeId, RRNodeId>::const_iterator node_iterator;
typedef vtr::vector<RREdgeId, RREdgeId>::const_iterator edge_iterator; typedef vtr::vector<RREdgeId, RREdgeId>::const_iterator edge_iterator;
typedef vtr::vector<RRSwitchId, RRSwitchId>::const_iterator switch_iterator; typedef vtr::vector<RRSwitchId, RRSwitchId>::const_iterator switch_iterator;
typedef vtr::vector<RRSegmentId, RRSegmentId>::const_iterator segment_iterator; typedef vtr::vector<RRSegmentId, RRSegmentId>::const_iterator segment_iterator;
typedef lazy_id_iterator<RRNodeId> lazy_node_iterator;
typedef lazy_id_iterator<RREdgeId> lazy_edge_iterator;
/* Ranges used to create range-based loop for nodes/edges/switches/segments */ /* Ranges used to create range-based loop for nodes/edges/switches/segments */
typedef vtr::Range<node_iterator> node_range; typedef vtr::Range<node_iterator> node_range;
typedef vtr::Range<edge_iterator> edge_range; typedef vtr::Range<RREdgeId*> edge_range;
typedef vtr::Range<switch_iterator> switch_range; typedef vtr::Range<switch_iterator> switch_range;
typedef vtr::Range<segment_iterator> segment_range; typedef vtr::Range<segment_iterator> segment_range;
typedef vtr::Range<lazy_node_iterator> lazy_node_range;
typedef vtr::Range<lazy_edge_iterator> lazy_edge_range;
public: /* Constructors */
RRGraph();
public: /* Accessors */ public: /* Accessors */
/* Aggregates: create range-based loops for nodes/edges/switches/segments /* Aggregates: create range-based loops for nodes/edges/switches/segments
@ -247,8 +261,8 @@ class RRGraph {
* // Do something with each segment * // Do something with each segment
* } * }
*/ */
node_range nodes() const; lazy_node_range nodes() const;
edge_range edges() const; lazy_edge_range edges() const;
switch_range switches() const; switch_range switches() const;
segment_range segments() const; segment_range segments() const;
@ -445,23 +459,9 @@ class RRGraph {
*/ */
RRSegmentId node_segment(const RRNodeId& node) const; RRSegmentId node_segment(const RRNodeId& node) const;
/* Get the number of non-configurable incoming edges to a node */ //Returns an iterable range of all edges (incoming & outgoing) for
short node_num_configurable_in_edges(const RRNodeId& node) const; //the specified node
edge_range node_edges(const RRNodeId& node) const;
/* Get the number of non-configurable outgoing edges from a node */
short node_num_non_configurable_in_edges(const RRNodeId& node) const;
/* Get the number of configurable output edges of a node */
short node_num_configurable_out_edges(const RRNodeId& node) const;
/* Get the number of non-configurable output edges of a node */
short node_num_non_configurable_out_edges(const RRNodeId& node) const;
/* Get the range (list) of edges related to a given node */
edge_range node_configurable_in_edges(const RRNodeId& node) const;
edge_range node_non_configurable_in_edges(const RRNodeId& node) const;
edge_range node_configurable_out_edges(const RRNodeId& node) const;
edge_range node_non_configurable_out_edges(const RRNodeId& node) const;
/* Get a list of edge ids, which are incoming edges to a node */ /* Get a list of edge ids, which are incoming edges to a node */
edge_range node_in_edges(const RRNodeId& node) const; edge_range node_in_edges(const RRNodeId& node) const;
@ -469,6 +469,12 @@ class RRGraph {
/* Get a list of edge ids, which are outgoing edges from a node */ /* Get a list of edge ids, which are outgoing edges from a node */
edge_range node_out_edges(const RRNodeId& node) const; edge_range node_out_edges(const RRNodeId& node) const;
/* Get the range (list) of edges related to a given node */
edge_range node_configurable_in_edges(const RRNodeId& node) const;
edge_range node_non_configurable_in_edges(const RRNodeId& node) const;
edge_range node_configurable_out_edges(const RRNodeId& node) const;
edge_range node_non_configurable_out_edges(const RRNodeId& node) const;
/* Edge-related attributes /* Edge-related attributes
* An example to explain the terminology used in RRGraph * An example to explain the terminology used in RRGraph
* edgeA * edgeA
@ -583,10 +589,10 @@ class RRGraph {
* rr_graph.create_node(CHANX); * rr_graph.create_node(CHANX);
* } * }
*/ */
void reserve_nodes(const int& num_nodes); void reserve_nodes(const unsigned long& num_nodes);
void reserve_edges(const int& num_edges); void reserve_edges(const unsigned long& num_edges);
void reserve_switches(const int& num_switches); void reserve_switches(const size_t& num_switches);
void reserve_segments(const int& num_segments); void reserve_segments(const size_t& num_segments);
/* Add new elements (node, edge, switch, etc.) to RRGraph */ /* Add new elements (node, edge, switch, etc.) to RRGraph */
/* Add a node to the RRGraph with a deposited type /* Add a node to the RRGraph with a deposited type
@ -596,6 +602,7 @@ class RRGraph {
* set_node_xlow(node, 0); * set_node_xlow(node, 0);
*/ */
RRNodeId create_node(const t_rr_type& type); RRNodeId create_node(const t_rr_type& type);
/* Add a edge to the RRGraph, by providing the source and sink node /* Add a edge to the RRGraph, by providing the source and sink node
* This function will automatically create a node and * This function will automatically create a node and
* configure the nodes and edges in connection * configure the nodes and edges in connection
@ -690,15 +697,14 @@ class RRGraph {
/* Set the routing segment linked to a node, only applicable to CHANX and CHANY */ /* Set the routing segment linked to a node, only applicable to CHANX and CHANY */
void set_node_segment(const RRNodeId& node, const RRSegmentId& segment_index); void set_node_segment(const RRNodeId& node, const RRSegmentId& segment_index);
/* Edge partitioning is performed for efficiency, /*
* so we can store configurable and non-configurable edge lists for a node in one vector, * Build the node to edge references to allow iteration through
* and efficiently iterate over all edges, or only the configurable or non-configurable subsets. * a node's in/out edges.
* This function will re-organize the incoming and outgoing edges of each node, *
* i.e., node_in_edges() and node_out_edges(): * Must be called before any node_*_in_edges() or node_*_out_edges() member
* 1. configurable edges (1st part of the vectors) * functions can be called.
* 2. non-configurable edges (2nd part of the vectors)
*/ */
void partition_edges(); void rebuild_node_edges();
/* Graph-level Clean-up, remove invalid nodes/edges etc. /* Graph-level Clean-up, remove invalid nodes/edges etc.
* This will clear the dirty flag (query by is_dirty()) of RRGraph object, if it was set * This will clear the dirty flag (query by is_dirty()) of RRGraph object, if it was set
@ -708,18 +714,52 @@ class RRGraph {
/* top-level function to free, should be called when to delete a RRGraph */ /* top-level function to free, should be called when to delete a RRGraph */
void clear(); void clear();
private: /* Internal Mutators to perform edge partitioning */ public: /* Type implementations */
/* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ /*
void partition_node_in_edges(const RRNodeId& node); * This class (forward delcared above) is a template used to represent a lazily calculated
* iterator of the specified ID type. The key assumption made is that the ID space is
* contiguous and can be walked by incrementing the underlying ID value. To account for
* invalid IDs, it keeps a reference to the invalid ID set and returns ID::INVALID() for
* ID values in the set.
*
* It is used to lazily create an iteration range (e.g. as returned by RRGraph::edges() RRGraph::nodes())
* just based on the count of allocated elements (i.e. RRGraph::num_nodes_ or RRGraph::num_edges_),
* and the set of any invalid IDs (i.e. RRGraph::invalid_node_ids_, RRGraph::invalid_edge_ids_).
*/
template<class ID>
class lazy_id_iterator : public std::iterator<std::bidirectional_iterator_tag, ID> {
public:
//Since we pass ID as a template to std::iterator we need to use an explicit 'typename'
//to bring the value_type and iterator names into scope
typedef typename std::iterator<std::bidirectional_iterator_tag, ID>::value_type value_type;
typedef typename std::iterator<std::bidirectional_iterator_tag, ID>::iterator iterator;
/* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ lazy_id_iterator(value_type init, const std::unordered_set<ID>& invalid_ids)
void partition_node_out_edges(const RRNodeId& node); : value_(init)
, invalid_ids_(invalid_ids) {}
/* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */ //Advance to the next ID value
void partition_in_edges(); iterator operator++() {
value_ = ID(size_t(value_) + 1);
return *this;
}
/* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part) */ //Advance to the previous ID value
void partition_out_edges(); iterator operator--() {
value_ = ID(size_t(value_) - 1);
return *this;
}
//Dereference the iterator
value_type operator*() const { return (invalid_ids_.count(value_)) ? ID::INVALID() : value_; }
friend bool operator==(const lazy_id_iterator<ID> lhs, const lazy_id_iterator<ID> rhs) { return lhs.value_ == rhs.value_; }
friend bool operator!=(const lazy_id_iterator<ID> lhs, const lazy_id_iterator<ID> rhs) { return !(lhs == rhs); }
private:
value_type value_;
const std::unordered_set<ID>& invalid_ids_;
};
private: /* Internal free functions */ private: /* Internal free functions */
void clear_nodes(); void clear_nodes();
@ -787,7 +827,9 @@ class RRGraph {
private: /* Internal Data */ private: /* Internal Data */
/* Node related data */ /* Node related data */
vtr::vector<RRNodeId, RRNodeId> node_ids_; /* Unique identifiers for the nodes */ size_t num_nodes_; /* Range of node ids */
std::unordered_set<RRNodeId> invalid_node_ids_; /* Invalid edge ids */
vtr::vector<RRNodeId, t_rr_type> node_types_; vtr::vector<RRNodeId, t_rr_type> node_types_;
vtr::vector<RRNodeId, vtr::Rect<short>> node_bounding_boxes_; vtr::vector<RRNodeId, vtr::Rect<short>> node_bounding_boxes_;
@ -800,15 +842,44 @@ class RRGraph {
vtr::vector<RRNodeId, float> node_Rs_; vtr::vector<RRNodeId, float> node_Rs_;
vtr::vector<RRNodeId, float> node_Cs_; vtr::vector<RRNodeId, float> node_Cs_;
vtr::vector<RRNodeId, RRSegmentId> node_segments_; /* Segment ids for each node */ vtr::vector<RRNodeId, RRSegmentId> node_segments_; /* Segment ids for each node */
/* Record the dividing point between configurable and non-configurable edges for each node */
vtr::vector<RRNodeId, size_t> node_num_non_configurable_in_edges_;
vtr::vector<RRNodeId, size_t> node_num_non_configurable_out_edges_;
vtr::vector<RRNodeId, std::vector<RREdgeId>> node_in_edges_; /*
vtr::vector<RRNodeId, std::vector<RREdgeId>> node_out_edges_; * We store the edges assoicated with each node in a single array per node (for memory efficiency).
*
* The array of edges is sorted into sub-ranges to allow for easy iteration (with node_in_edges(),
* node_non_configurable_out_edges() etc.).
*
* For a particular 'node' we store the sizes of the various sub-ranges in the node_num_* members,
* from which the delimiters for each sub-range can be calculated.
*
*
* node_edges_[node]:
*
*
* node_num_non_configurable_in_edges_[node] node_num_non_configurable_out_edges_[node]
* <-------------------> <-------------------->
*
* +------------------+---------------------+------------------+----------------------+
* | in_edges_config | in_edges_non_config | out_edges_config | out_edges_non_config |
* +------------------+---------------------+------------------+----------------------+
*
* <--------------------------------------> <--------------------------------------->
* node_num_in_edges_[node] node_num_out_edges_[node]
*
* All elements of node_edges_ should be initialized after all edges have been created (with create_edge()),
* by calling rebuild_node_edges(), which will allocate node_edges_, add the relevant edges and partition
* each node's arrays into the appropriate. rebuild_node_edges() also initializes all the node_num_* members
* based on the edges (created with create_edge()) in the edge_* members.
*/
vtr::vector<RRNodeId, uint16_t> node_num_in_edges_;
vtr::vector<RRNodeId, uint16_t> node_num_out_edges_;
vtr::vector<RRNodeId, uint16_t> node_num_non_configurable_in_edges_;
vtr::vector<RRNodeId, uint16_t> node_num_non_configurable_out_edges_;
vtr::vector<RRNodeId, std::unique_ptr<RREdgeId[]>> node_edges_;
/* Edge related data */ /* Edge related data */
vtr::vector<RREdgeId, RREdgeId> edge_ids_; /* unique identifiers for edges */ size_t num_edges_; /* Range of edge ids */
std::unordered_set<RREdgeId> invalid_edge_ids_; /* Invalid edge ids */
vtr::vector<RREdgeId, RRNodeId> edge_src_nodes_; vtr::vector<RREdgeId, RRNodeId> edge_src_nodes_;
vtr::vector<RREdgeId, RRNodeId> edge_sink_nodes_; vtr::vector<RREdgeId, RRNodeId> edge_sink_nodes_;
vtr::vector<RREdgeId, RRSwitchId> edge_switches_; vtr::vector<RREdgeId, RRSwitchId> edge_switches_;
@ -836,7 +907,7 @@ class RRGraph {
/* Fast look-up to search a node by its type, coordinator and ptc_num /* Fast look-up to search a node by its type, coordinator and ptc_num
* Indexing of fast look-up: [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1] * Indexing of fast look-up: [0..xmax][0..ymax][0..NUM_TYPES-1][0..ptc_max][0..NUM_SIDES-1]
*/ */
typedef std::vector<std::vector<std::vector<std::vector<std::vector<RRNodeId>>>>> NodeLookup; typedef vtr::NdMatrix<std::vector<std::vector<RRNodeId>>, 3> NodeLookup;
mutable NodeLookup node_lookup_; mutable NodeLookup node_lookup_;
}; };

View File

@ -38,6 +38,16 @@ bool all_valid(const Container& values) {
return true; return true;
} }
template<typename Iterator>
bool all_valid(Iterator begin, Iterator end) {
for (auto itr = begin; itr != end; ++itr) {
if (!*itr) {
return false;
}
}
return true;
}
//Builds a mapping from old to new ids by skipping values marked invalid //Builds a mapping from old to new ids by skipping values marked invalid
template<typename Container> template<typename Container>
Container compress_ids(const Container& ids) { Container compress_ids(const Container& ids) {
@ -162,4 +172,20 @@ ValueContainer update_valid_refs(const ValueContainer& values, const IdContainer
return updated; return updated;
} }
template<typename Iterator, typename IdContainer>
void update_valid_refs(Iterator begin, Iterator end, const IdContainer& id_map) {
for (auto itr = begin; itr != end; ++itr) {
auto orig_val = *itr;
if (orig_val) {
//Original item valid
auto new_val = id_map[orig_val];
if (new_val) {
//The original item exists in the new mapping
*itr = new_val;
}
}
}
}
#endif #endif

View File

@ -0,0 +1,43 @@
#ifndef RR_GRAPH_TYPES
#define RR_GRAPH_TYPES
/********************************************************************
* Data types required by routing resource graph (RRGraph) definition
*******************************************************************/
/********************************************************************
* Directionality of a routing track (node type CHANX and CHANY) in
* a routing resource graph
*******************************************************************/
enum e_direction : unsigned char {
INC_DIRECTION = 0,
DEC_DIRECTION = 1,
BI_DIRECTION = 2,
NO_DIRECTION = 3,
NUM_DIRECTIONS
};
constexpr std::array<const char*, NUM_DIRECTIONS> DIRECTION_STRING = {{"INC_DIRECTION", "DEC_DIRECTION", "BI_DIRECTION", "NO_DIRECTION"}};
/* Type of a routing resource node. x-directed channel segment, *
* y-directed channel segment, input pin to a clb to pad, output *
* from a clb or pad (i.e. output pin of a net) and: *
* SOURCE: A dummy node that is a logical output within a block *
* -- i.e., the gate that generates a signal. *
* SINK: A dummy node that is a logical input within a block *
* -- i.e. the gate that needs a signal. */
typedef enum e_rr_type : unsigned char {
SOURCE = 0,
SINK,
IPIN,
OPIN,
CHANX,
CHANY,
NUM_RR_TYPES
} t_rr_type;
constexpr std::array<t_rr_type, NUM_RR_TYPES> RR_TYPES = {{SOURCE, SINK, IPIN, OPIN, CHANX, CHANY}};
constexpr std::array<const char*, NUM_RR_TYPES> rr_node_typename{{"SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY"}};
#endif

View File

@ -0,0 +1,239 @@
/*********************************************************************
* This file defines the writing rr graph function in XML format.
* The rr graph is separated into channels, nodes, switches,
* grids, edges, block types, and segments. Each tag has several
* children tags such as timing, location, or some general
* details. Each tag has attributes to describe them
********************************************************************/
#include <fstream>
#include <iostream>
#include <string.h>
#include <iomanip>
#include <limits>
#include "vpr_error.h"
#include "globals.h"
#include "read_xml_arch_file.h"
#include "vtr_version.h"
#include "rr_graph_obj.h"
#include "write_xml_rr_graph_obj.h"
using namespace std;
/* All values are printed with this precision value. The higher the
* value, the more accurate the read in rr graph is. Using numeric_limits
* max_digits10 guarentees that no values change during a sequence of
* float -> string -> float conversions */
constexpr int FLOAT_PRECISION = std::numeric_limits<float>::max_digits10;
/*********************** External Subroutines to this module *******************/
void write_rr_channel(fstream &fp);
void write_rr_grid(fstream &fp);
void write_rr_block_types(fstream &fp);
/************************ Subroutine definitions ****************************/
static
void add_metadata_to_xml(std::fstream& fp, const char* tab_prefix, const t_metadata_dict& meta) {
fp << tab_prefix << "<metadata>" << std::endl;
for (const auto& meta_elem : meta) {
const std::string& key = meta_elem.first;
const std::vector<t_metadata_value>& values = meta_elem.second;
for (const auto& value : values) {
fp << tab_prefix << "\t<meta name=\"" << key << "\"";
fp << ">" << value.as_string() << "</meta>" << std::endl;
}
}
fp << tab_prefix << "</metadata>" << std::endl;
}
/* All relevant rr node info is written out to the graph.
* This includes location, timing, and segment info
*/
static
void write_rr_graph_node(fstream &fp, const RRGraph& rr_graph) {
/* TODO: we should make it function full independent from device_ctx !!! */
auto& device_ctx = g_vpr_ctx.device();
std::array<const char*, NUM_DIRECTIONS> DIRECTION_STRING_WRITE_XML = {{"INC_DIR", "DEC_DIR", "BI_DIR", "NO_DIR"}};
fp << "\t<rr_nodes>" << endl;
for (auto node : rr_graph.nodes()) {
fp << "\t\t<node";
fp << " id=\"" << rr_graph.node_index(node);
fp << "\" type=\"" << rr_node_typename[rr_graph.node_type(node)];
if (CHANX == rr_graph.node_type(node) || CHANY == rr_graph.node_type(node)) {
fp << "\" direction=\"" << DIRECTION_STRING_WRITE_XML[rr_graph.node_direction(node)];
}
fp << "\" capacity=\"" << rr_graph.node_capacity(node);
fp << "\">" << endl;
fp << "\t\t\t<loc";
fp << " xlow=\"" << rr_graph.node_xlow(node);
fp << "\" ylow=\"" << rr_graph.node_ylow(node);
fp << "\" xhigh=\"" << rr_graph.node_xhigh(node);
fp << "\" yhigh=\"" << rr_graph.node_yhigh(node);
if (IPIN == rr_graph.node_type(node) || OPIN == rr_graph.node_type(node)) {
fp << "\" side=\"" << SIDE_STRING[rr_graph.node_side(node)];
}
fp << "\" ptc=\"" << rr_graph.node_ptc_num(node) ;
fp << "\"/>" << endl;
fp << "\t\t\t<timing R=\"" << setprecision(FLOAT_PRECISION) << rr_graph.node_R(node)
<< "\" C=\"" << setprecision(FLOAT_PRECISION) << rr_graph.node_C(node) << "\"/>" << endl;
if (RRSegmentId::INVALID() != rr_graph.node_segment(node)) {
fp << "\t\t\t<segment segment_id=\"" << size_t(rr_graph.node_segment(node)) << "\"/>" << endl;
}
const auto iter = device_ctx.rr_node_metadata.find(rr_graph.node_index(node));
if(iter != device_ctx.rr_node_metadata.end()) {
const t_metadata_dict & meta = iter->second;
add_metadata_to_xml(fp, "\t\t\t", meta);
}
fp << "\t\t</node>" << endl;
}
fp << "\t</rr_nodes>" << endl << endl;
return;
}
/* Segment information in the t_segment_inf data structure is written out.
* Information includes segment id, name, and optional timing parameters
*/
static
void write_rr_graph_segments(fstream &fp, const RRGraph& rr_graph) {
fp << "\t<segments>" << endl;
for (auto seg : rr_graph.segments()) {
fp << "\t\t<segment id=\"" << rr_graph.segment_index(seg) <<
"\" name=\"" << rr_graph.get_segment(seg).name << "\">" << endl;
fp << "\t\t\t<timing R_per_meter=\"" << setprecision(FLOAT_PRECISION) << rr_graph.get_segment(seg).Rmetal <<
"\" C_per_meter=\"" <<setprecision(FLOAT_PRECISION) << rr_graph.get_segment(seg).Cmetal << "\"/>" << endl;
fp << "\t\t</segment>" << endl;
}
fp << "\t</segments>" << endl << endl;
return;
}
/* Switch info is written out into xml format. This includes
* general, sizing, and optional timing information
*/
static
void write_rr_graph_switches(fstream &fp, const RRGraph& rr_graph) {
fp << "\t<switches>" << endl;
for (auto rr_switch : rr_graph.switches()) {
fp << "\t\t<switch id=\"" << rr_graph.switch_index(rr_switch);
t_rr_switch_inf cur_switch = rr_graph.get_switch(rr_switch);
if (cur_switch.type() == SwitchType::TRISTATE) {
fp << "\" type=\"tristate";
} else if (cur_switch.type() == SwitchType::MUX) {
fp << "\" type=\"mux";
} else if (cur_switch.type() == SwitchType::PASS_GATE) {
fp << "\" type=\"pass_gate";
} else if (cur_switch.type() == SwitchType::SHORT) {
fp << "\" type=\"short";
} else if (cur_switch.type() == SwitchType::BUFFER) {
fp << "\" type=\"buffer";
} else {
VPR_THROW(VPR_ERROR_ROUTE, "Invalid switch type %d\n", cur_switch.type());
}
fp << "\"";
if (cur_switch.name) {
fp << " name=\"" << cur_switch.name << "\"";
}
fp << ">" << endl;
fp << "\t\t\t<timing R=\"" << setprecision(FLOAT_PRECISION) << cur_switch.R <<
"\" Cin=\"" << setprecision(FLOAT_PRECISION) << cur_switch.Cin <<
"\" Cout=\"" << setprecision(FLOAT_PRECISION) << cur_switch.Cout <<
"\" Cinternal=\"" << setprecision(FLOAT_PRECISION) << cur_switch.Cinternal <<
"\" Tdel=\"" << setprecision(FLOAT_PRECISION) << cur_switch.Tdel << "\"/>" << endl;
fp << "\t\t\t<sizing mux_trans_size=\"" << setprecision(FLOAT_PRECISION) << cur_switch.mux_trans_size <<
"\" buf_size=\"" << setprecision(FLOAT_PRECISION) << cur_switch.buf_size << "\"/>" << endl;
fp << "\t\t</switch>" << endl;
}
fp << "\t</switches>" << endl << endl;
return;
}
/* Edges connecting to each rr node is printed out. The two nodes
* it connects to are also printed
*/
static
void write_rr_graph_edges(fstream &fp, const RRGraph& rr_graph) {
auto& device_ctx = g_vpr_ctx.device();
fp << "\t<rr_edges>" << endl;
for (auto node : rr_graph.nodes()) {
/* Sort the edges by the ids of sink nodes */
std::vector<RREdgeId> sorted_out_edge_ids;
for (auto edge: rr_graph.node_out_edges(node)) {
fp << "\t\t<edge src_node=\"" << rr_graph.node_index(node) <<
"\" sink_node=\"" << rr_graph.node_index(rr_graph.edge_sink_node(edge)) <<
"\" switch_id=\"" << rr_graph.switch_index(rr_graph.edge_switch(edge)) << "\"";
bool wrote_edge_metadata = false;
const auto iter = device_ctx.rr_edge_metadata.find( std::make_tuple(rr_graph.node_index(node),
rr_graph.node_index(rr_graph.edge_sink_node(edge)),
rr_graph.switch_index(rr_graph.edge_switch(edge))) );
if(iter != device_ctx.rr_edge_metadata.end()) {
fp << ">" << endl;
const t_metadata_dict & meta = iter->second;
add_metadata_to_xml(fp, "\t\t\t", meta);
wrote_edge_metadata = true;
}
if(wrote_edge_metadata == false) {
fp << "/>" << endl;
} else {
fp << "\t\t</edge>" << endl;
}
}
}
fp << "\t</rr_edges>" << endl << endl;
}
/* This function is used to write the rr_graph into xml format into a a file with name: file_name */
void write_xml_rr_graph_obj(const char *file_name, const RRGraph& rr_graph) {
fstream fp;
fp.open(file_name, fstream::out | fstream::trunc);
/* Prints out general info for easy error checking*/
if (!fp.is_open() || !fp.good()) {
vpr_throw(VPR_ERROR_OTHER, __FILE__, __LINE__,
"couldn't open file \"%s\" for generating RR graph file\n", file_name);
}
cout << "Writing RR graph" << endl;
fp << "<rr_graph tool_name=\"vpr\" tool_version=\"" << vtr::VERSION <<
"\" tool_comment=\"Generated from arch file "
<< get_arch_file_name() << "\">" << endl;
/* Write out each individual component
* Use existing write_rr_* functions as much as possible
* 1. For those using external data structures outside RRGraph,
* leave as it is.
* 2. For those using RRGraph internal data,
* write new functions
*/
write_rr_channel(fp);
write_rr_graph_switches(fp, rr_graph);
write_rr_graph_segments(fp, rr_graph);
write_rr_block_types(fp);
write_rr_grid(fp);
write_rr_graph_node(fp, rr_graph);
write_rr_graph_edges(fp, rr_graph);
fp << "</rr_graph>";
fp.close();
cout << "Finished generating RR graph file named " << file_name << endl << endl;
}

View File

@ -0,0 +1,12 @@
/*********************************************************************
* This function writes the RR_graph generated by VPR into a file in XML format
* Information included in the file includes rr nodes, rr switches,
* the grid, block info, node indices
********************************************************************/
#ifndef WRITE_XML_RR_GRAPH_OBJ_H
#define WRITE_XML_RR_GRAPH_OBJ_H
void write_xml_rr_graph_obj(const char *file_name, const RRGraph& rr_graph);
#endif

View File

@ -36,6 +36,9 @@
#include "rr_types.h" #include "rr_types.h"
#include "create_rr_graph.h"
#include "write_xml_rr_graph_obj.h"
//#define VERBOSE //#define VERBOSE
struct t_mux { struct t_mux {
@ -331,6 +334,9 @@ void create_rr_graph(const t_graph_type graph_type,
base_cost_type, base_cost_type,
&det_routing_arch->wire_to_rr_ipin_switch, &det_routing_arch->wire_to_rr_ipin_switch,
det_routing_arch->read_rr_graph_filename.c_str()); det_routing_arch->read_rr_graph_filename.c_str());
/* Xifan Tang - Create rr_graph object: load rr_nodes to the object */
convert_rr_graph(segment_inf);
} }
} else { } else {
if (channel_widths_unchanged(device_ctx.chan_width, nodes_per_chan) && !device_ctx.rr_nodes.empty()) { if (channel_widths_unchanged(device_ctx.chan_width, nodes_per_chan) && !device_ctx.rr_nodes.empty()) {
@ -369,6 +375,9 @@ void create_rr_graph(const t_graph_type graph_type,
det_routing_arch->wire_to_rr_ipin_switch, det_routing_arch->wire_to_rr_ipin_switch,
base_cost_type); base_cost_type);
} }
/* Xifan Tang - Create rr_graph object: load rr_nodes to the object */
convert_rr_graph(segment_inf);
} }
process_non_config_sets(); process_non_config_sets();
@ -378,6 +387,11 @@ void create_rr_graph(const t_graph_type graph_type,
//Write out rr graph file if needed //Write out rr graph file if needed
if (!det_routing_arch->write_rr_graph_filename.empty()) { if (!det_routing_arch->write_rr_graph_filename.empty()) {
write_rr_graph(det_routing_arch->write_rr_graph_filename.c_str(), segment_inf); write_rr_graph(det_routing_arch->write_rr_graph_filename.c_str(), segment_inf);
/* Just to test the writer of rr_graph_obj, give a filename in a fixed style*/
std::string rr_graph_obj_filename(det_routing_arch->write_rr_graph_filename);
rr_graph_obj_filename += std::string(".obj");
write_xml_rr_graph_obj(rr_graph_obj_filename.c_str(), device_ctx.rr_graph);
} }
} }
@ -1391,6 +1405,9 @@ void free_rr_graph() {
device_ctx.rr_edge_metadata.clear(); device_ctx.rr_edge_metadata.clear();
invalidate_router_lookahead_cache(); invalidate_router_lookahead_cache();
/* Xifan Tang - Clear the rr_graph object */
device_ctx.rr_graph.clear();
} }
static void build_rr_sinks_sources(const int i, static void build_rr_sinks_sources(const int i,