Merge branch 'refactoring' into dev
This commit is contained in:
commit
f136dd8820
|
@ -163,9 +163,10 @@ enum e_interconnect {
|
|||
COMPLETE_INTERC = 1,
|
||||
DIRECT_INTERC = 2,
|
||||
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. */
|
||||
enum e_side : unsigned char {
|
||||
|
|
|
@ -79,6 +79,12 @@ Rect<T>::Rect(Point<T> bottom_left_val, Point<T> top_right_val)
|
|||
//pass
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Rect<T>::Rect() {
|
||||
//pass
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
T Rect<T>::xmin() const {
|
||||
return bottom_left_.x();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# 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_arch -f ./test_openfpga_arch/k6_frac_N10_40nm_openfpga.xml
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "place_macro.h"
|
||||
#include "compressed_grid.h"
|
||||
|
||||
#include "rr_graph_obj.h"
|
||||
|
||||
//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.
|
||||
|
@ -143,6 +145,9 @@ struct DeviceContext : public Context {
|
|||
/* chan_width is for x|y-directed channels; i.e. between rows */
|
||||
t_chan_width chan_width;
|
||||
|
||||
/* RRGraph object */
|
||||
RRGraph rr_graph;
|
||||
|
||||
/* Structures to define the routing architecture of the FPGA. */
|
||||
std::vector<t_rr_node> rr_nodes; /* autogenerated in build_rr_graph */
|
||||
|
||||
|
|
|
@ -40,6 +40,9 @@
|
|||
#include "vtr_flat_map.h"
|
||||
#include "vtr_cache.h"
|
||||
|
||||
/* Header for rr_graph related definition */
|
||||
#include "rr_graph_types.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Global data types and constants
|
||||
******************************************************************************/
|
||||
|
@ -1011,15 +1014,6 @@ struct t_det_routing_arch {
|
|||
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]. *
|
||||
* 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]
|
||||
|
||||
/* 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. *
|
||||
* index: Array index (ID) of this routing resource node. *
|
||||
* iswitch: Index of the switch type used to go from this rr_node to *
|
||||
|
|
|
@ -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.
|
||||
**********************************************************************/
|
||||
bool check_rr_graph(const RRGraph& rr_graph) {
|
||||
bool check_flag = true;
|
||||
size_t num_err = 0;
|
||||
|
||||
if (false == check_rr_graph_duplicated_edges(rr_graph)) {
|
||||
VTR_LOG_WARN("Fail in checking duplicated edges !\n");
|
||||
check_flag = false;
|
||||
num_err++;
|
||||
}
|
||||
|
||||
if (false == check_rr_graph_dangling_nodes(rr_graph)) {
|
||||
VTR_LOG_WARN("Fail in checking dangling nodes !\n");
|
||||
check_flag = false;
|
||||
num_err++;
|
||||
}
|
||||
|
||||
if (false == check_rr_graph_source_nodes(rr_graph)) {
|
||||
VTR_LOG_WARN("Fail in checking source nodes!\n");
|
||||
check_flag = false;
|
||||
num_err++;
|
||||
}
|
||||
|
||||
if (false == check_rr_graph_sink_nodes(rr_graph)) {
|
||||
VTR_LOG_WARN("Fail in checking sink nodes!\n");
|
||||
check_flag = false;
|
||||
num_err++;
|
||||
}
|
||||
|
||||
if (false == check_rr_graph_source_nodes(rr_graph)) {
|
||||
VTR_LOG_WARN("Fail in checking source nodes!\n");
|
||||
check_flag = false;
|
||||
num_err++;
|
||||
}
|
||||
|
||||
if (false == check_rr_graph_sink_nodes(rr_graph)) {
|
||||
VTR_LOG_WARN("Fail in checking sink nodes!\n");
|
||||
check_flag = false;
|
||||
num_err++;
|
||||
}
|
||||
|
||||
/* Error out if there is any fatal errors found */
|
||||
if (0 < num_err) {
|
||||
VTR_LOG_WARN("Checked Routing Resource graph with %d errors !\n",
|
||||
num_err);
|
||||
|
||||
return check_flag;
|
||||
}
|
||||
|
||||
return (0 == num_err);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -7,6 +7,7 @@
|
|||
#include <map>
|
||||
#include <limits>
|
||||
|
||||
#include "vtr_geometry.h"
|
||||
#include "vtr_vector_map.h"
|
||||
#include "vtr_log.h"
|
||||
#include "vtr_util.h"
|
||||
|
@ -14,13 +15,26 @@
|
|||
#include "rr_graph_obj.h"
|
||||
#include "rr_graph_obj_utils.h"
|
||||
|
||||
//Accessors
|
||||
RRGraph::node_range RRGraph::nodes() const {
|
||||
return vtr::make_range(node_ids_.begin(), node_ids_.end());
|
||||
/********************************************************************
|
||||
* Constructors
|
||||
*******************************************************************/
|
||||
RRGraph::RRGraph()
|
||||
: num_nodes_(0)
|
||||
, num_edges_(0) {
|
||||
//Pass
|
||||
}
|
||||
|
||||
RRGraph::edge_range RRGraph::edges() const {
|
||||
return vtr::make_range(edge_ids_.begin(), edge_ids_.end());
|
||||
/********************************************************************
|
||||
* Accessors
|
||||
*******************************************************************/
|
||||
RRGraph::lazy_node_range RRGraph::nodes() const {
|
||||
return vtr::make_range(lazy_node_iterator(RRNodeId(0), invalid_node_ids_),
|
||||
lazy_node_iterator(RRNodeId(num_nodes_), invalid_node_ids_));
|
||||
}
|
||||
|
||||
RRGraph::lazy_edge_range RRGraph::edges() const {
|
||||
return vtr::make_range(lazy_edge_iterator(RREdgeId(0), invalid_edge_ids_),
|
||||
lazy_edge_iterator(RREdgeId(num_edges_), invalid_edge_ids_));
|
||||
}
|
||||
|
||||
RRGraph::switch_range RRGraph::switches() const {
|
||||
|
@ -117,11 +131,11 @@ vtr::Point<short> RRGraph::node_end_coordinate(const RRNodeId& node) const {
|
|||
}
|
||||
|
||||
short RRGraph::node_fan_in(const RRNodeId& node) const {
|
||||
return node_in_edges(node).size();
|
||||
return node_num_in_edges_[node];
|
||||
}
|
||||
|
||||
short RRGraph::node_fan_out(const RRNodeId& node) const {
|
||||
return node_out_edges(node).size();
|
||||
return node_num_out_edges_[node];
|
||||
}
|
||||
|
||||
short RRGraph::node_capacity(const RRNodeId& node) const {
|
||||
|
@ -189,118 +203,65 @@ RRSegmentId RRGraph::node_segment(const RRNodeId& node) const {
|
|||
return node_segments_[node];
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the number of configurable input edges of a node
|
||||
* TODO: we would use the node_num_configurable_in_edges()
|
||||
* when the rr_graph edges have been partitioned
|
||||
* This can avoid unneccessary walkthrough
|
||||
*/
|
||||
short RRGraph::node_num_configurable_in_edges(const RRNodeId& node) const {
|
||||
return node_configurable_in_edges(node).size();
|
||||
RRGraph::edge_range RRGraph::node_edges(const RRNodeId& node) const {
|
||||
VTR_ASSERT_SAFE(valid_node_id(node));
|
||||
|
||||
return vtr::make_range(node_edges_[node].get(),
|
||||
node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the number of configurable output edges of a node
|
||||
* TODO: we would use the node_num_configurable_out_edges()
|
||||
* when the rr_graph edges have been partitioned
|
||||
* This can avoid unneccessary walkthrough
|
||||
*/
|
||||
short RRGraph::node_num_configurable_out_edges(const RRNodeId& node) const {
|
||||
return node_configurable_out_edges(node).size();
|
||||
RRGraph::edge_range RRGraph::node_in_edges(const RRNodeId& node) const {
|
||||
VTR_ASSERT_SAFE(valid_node_id(node));
|
||||
|
||||
return vtr::make_range(node_edges_[node].get(),
|
||||
node_edges_[node].get() + node_num_in_edges_[node]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the number of non-configurable input edges of a node
|
||||
* TODO: we would use the node_num_configurable_in_edges()
|
||||
* when the rr_graph edges have been partitioned
|
||||
* This can avoid unneccessary walkthrough
|
||||
*/
|
||||
short RRGraph::node_num_non_configurable_in_edges(const RRNodeId& node) const {
|
||||
return node_non_configurable_in_edges(node).size();
|
||||
}
|
||||
RRGraph::edge_range RRGraph::node_out_edges(const RRNodeId& node) const {
|
||||
VTR_ASSERT_SAFE(valid_node_id(node));
|
||||
|
||||
/*
|
||||
* Get the number of non-configurable output edges of a node
|
||||
* TODO: we would use the node_num_configurable_out_edges()
|
||||
* when the rr_graph edges have been partitioned
|
||||
* This can avoid unneccessary walkthrough
|
||||
*/
|
||||
short RRGraph::node_num_non_configurable_out_edges(const RRNodeId& node) const {
|
||||
return node_non_configurable_out_edges(node).size();
|
||||
return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]),
|
||||
(node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node]);
|
||||
}
|
||||
|
||||
/* Get the list of configurable edges from the input edges of a given node
|
||||
* And return the range(iterators) of the list
|
||||
*/
|
||||
RRGraph::edge_range RRGraph::node_configurable_in_edges(const RRNodeId& node) const {
|
||||
/* Make sure we will access a valid node */
|
||||
VTR_ASSERT_SAFE(valid_node_id(node));
|
||||
|
||||
/* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */
|
||||
auto begin = node_in_edges(node).begin();
|
||||
|
||||
/* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */
|
||||
auto end = node_in_edges(node).end() - node_num_non_configurable_in_edges_[node];
|
||||
|
||||
return vtr::make_range(begin, end);
|
||||
return vtr::make_range(node_edges_[node].get(),
|
||||
node_edges_[node].get() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]);
|
||||
}
|
||||
|
||||
/* Get the list of configurable edges from the input edges of a given node
|
||||
/* Get the list of non configurable edges from the input edges of a given node
|
||||
* And return the range(iterators) of the list
|
||||
*/
|
||||
RRGraph::edge_range RRGraph::node_non_configurable_in_edges(const RRNodeId& node) const {
|
||||
/* Make sure we will access a valid node */
|
||||
VTR_ASSERT_SAFE(valid_node_id(node));
|
||||
|
||||
/* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */
|
||||
auto begin = node_in_edges(node).end() - node_num_non_configurable_in_edges_[node];
|
||||
|
||||
/* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */
|
||||
auto end = node_in_edges(node).end();
|
||||
|
||||
return vtr::make_range(begin, end);
|
||||
return vtr::make_range(node_edges_[node].get() + node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node],
|
||||
node_edges_[node].get() + node_num_in_edges_[node]);
|
||||
}
|
||||
|
||||
/* Get the list of configurable edges from the input edges of a given node
|
||||
/* Get the list of configurable edges from the output edges of a given node
|
||||
* And return the range(iterators) of the list
|
||||
*/
|
||||
RRGraph::edge_range RRGraph::node_configurable_out_edges(const RRNodeId& node) const {
|
||||
/* Make sure we will access a valid node */
|
||||
VTR_ASSERT_SAFE(valid_node_id(node));
|
||||
|
||||
/* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */
|
||||
auto begin = node_out_edges(node).begin();
|
||||
|
||||
/* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */
|
||||
auto end = node_out_edges(node).end() - node_num_non_configurable_out_edges_[node];
|
||||
|
||||
return vtr::make_range(begin, end);
|
||||
return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]),
|
||||
(node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node]);
|
||||
}
|
||||
|
||||
/* Get the list of configurable edges from the input edges of a given node
|
||||
/* Get the list of non configurable edges from the output edges of a given node
|
||||
* And return the range(iterators) of the list
|
||||
*/
|
||||
RRGraph::edge_range RRGraph::node_non_configurable_out_edges(const RRNodeId& node) const {
|
||||
/* Make sure we will access a valid node */
|
||||
VTR_ASSERT_SAFE(valid_node_id(node));
|
||||
|
||||
/* By default the configurable edges will be stored at the first part of the edge list (0 to XX) */
|
||||
auto begin = node_out_edges(node).end() - node_num_non_configurable_out_edges_[node];
|
||||
|
||||
/* By default the non-configurable edges will be stored at second part of the edge list (XX to end) */
|
||||
auto end = node_out_edges(node).end();
|
||||
|
||||
return vtr::make_range(begin, end);
|
||||
}
|
||||
|
||||
RRGraph::edge_range RRGraph::node_out_edges(const RRNodeId& node) const {
|
||||
VTR_ASSERT_SAFE(valid_node_id(node));
|
||||
return vtr::make_range(node_out_edges_[node].begin(), node_out_edges_[node].end());
|
||||
}
|
||||
|
||||
RRGraph::edge_range RRGraph::node_in_edges(const RRNodeId& node) const {
|
||||
VTR_ASSERT_SAFE(valid_node_id(node));
|
||||
return vtr::make_range(node_in_edges_[node].begin(), node_in_edges_[node].end());
|
||||
return vtr::make_range((node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node],
|
||||
(node_edges_[node].get() + node_num_in_edges_[node]) + node_num_out_edges_[node]);
|
||||
}
|
||||
|
||||
//Edge attributes
|
||||
|
@ -392,21 +353,21 @@ RRNodeId RRGraph::find_node(const short& x, const short& y, const t_rr_type& typ
|
|||
|
||||
/* Check if x, y, type and ptc, side is valid */
|
||||
if ((x < 0) /* See if x is smaller than the index of first element */
|
||||
|| (size_t(x) > node_lookup_.size() - 1)) { /* See if x is large than the index of last element */
|
||||
|| (size_t(x) > node_lookup_.dim_size(0) - 1)) { /* See if x is large than the index of last element */
|
||||
/* Return a zero range! */
|
||||
return RRNodeId::INVALID();
|
||||
}
|
||||
|
||||
/* Check if x, y, type and ptc, side is valid */
|
||||
if ((y < 0) /* See if y is smaller than the index of first element */
|
||||
|| (size_t(y) > node_lookup_[x].size() - 1)) { /* See if y is large than the index of last element */
|
||||
|| (size_t(y) > node_lookup_.dim_size(1) - 1)) { /* See if y is large than the index of last element */
|
||||
/* Return a zero range! */
|
||||
return RRNodeId::INVALID();
|
||||
}
|
||||
|
||||
/* Check if x, y, type and ptc, side is valid */
|
||||
/* itype is always larger than -1, we can skip checking */
|
||||
if (itype > node_lookup_[x][y].size() - 1) { /* See if type is large than the index of last element */
|
||||
if (itype > node_lookup_.dim_size(2) - 1) { /* See if type is large than the index of last element */
|
||||
/* Return a zero range! */
|
||||
return RRNodeId::INVALID();
|
||||
}
|
||||
|
@ -437,20 +398,20 @@ short RRGraph::chan_num_tracks(const short& x, const short& y, const t_rr_type&
|
|||
|
||||
/* Check if x, y, type and ptc is valid */
|
||||
if ((x < 0) /* See if x is smaller than the index of first element */
|
||||
|| (size_t(x) > node_lookup_.size() - 1)) { /* See if x is large than the index of last element */
|
||||
|| (size_t(x) > node_lookup_.dim_size(0) - 1)) { /* See if x is large than the index of last element */
|
||||
/* Return a zero range! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if x, y, type and ptc is valid */
|
||||
if ((y < 0) /* See if y is smaller than the index of first element */
|
||||
|| (size_t(y) > node_lookup_[x].size() - 1)) { /* See if y is large than the index of last element */
|
||||
|| (size_t(y) > node_lookup_.dim_size(1) - 1)) { /* See if y is large than the index of last element */
|
||||
/* Return a zero range! */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if x, y, type and ptc is valid */
|
||||
if ((size_t(type) > node_lookup_[x][y].size() - 1)) { /* See if type is large than the index of last element */
|
||||
if ((size_t(type) > node_lookup_.dim_size(2) - 1)) { /* See if type is large than the index of last element */
|
||||
/* Return a zero range! */
|
||||
return 0;
|
||||
}
|
||||
|
@ -488,15 +449,20 @@ bool RRGraph::validate_node_segment(const RRNodeId& node) const {
|
|||
/* Check if the segment id of every node is in range */
|
||||
bool RRGraph::validate_node_segments() const {
|
||||
bool all_valid = true;
|
||||
for (auto node : nodes()) {
|
||||
if (true == validate_node_segment(node)) {
|
||||
for (size_t id = 0; id < num_nodes_; ++id) {
|
||||
/* Try to find if this is an invalid id or not */
|
||||
if (!valid_node_id(RRNodeId(id))) {
|
||||
/* Skip this id */
|
||||
continue;
|
||||
}
|
||||
if (true == validate_node_segment(RRNodeId(id))) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here it means we find an invalid segment id */
|
||||
all_valid = false;
|
||||
/* Print a warning! */
|
||||
VTR_LOG_WARN("Node %d has an invalid segment id (%d)!\n",
|
||||
size_t(node), size_t(node_segment(node)));
|
||||
id, size_t(node_segment(RRNodeId(id))));
|
||||
}
|
||||
return all_valid;
|
||||
}
|
||||
|
@ -510,15 +476,20 @@ bool RRGraph::validate_edge_switch(const RREdgeId& edge) const {
|
|||
/* Check if the switch id of every edge is in range */
|
||||
bool RRGraph::validate_edge_switches() const {
|
||||
bool all_valid = true;
|
||||
for (auto edge : edges()) {
|
||||
if (true == validate_edge_switch(edge)) {
|
||||
for (size_t id = 0; id < num_edges_; ++id) {
|
||||
/* Try to find if this is an invalid id or not */
|
||||
if (!valid_edge_id(RREdgeId(id))) {
|
||||
/* Skip this id */
|
||||
continue;
|
||||
}
|
||||
if (true == validate_edge_switch(RREdgeId(id))) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here it means we find an invalid segment id */
|
||||
all_valid = false;
|
||||
/* Print a warning! */
|
||||
VTR_LOG_WARN("Edge %d has an invalid switch id (%d)!\n",
|
||||
size_t(edge), size_t(edge_switch(edge)));
|
||||
id, size_t(edge_switch(RREdgeId(id))));
|
||||
}
|
||||
return all_valid;
|
||||
}
|
||||
|
@ -622,8 +593,13 @@ bool RRGraph::validate_node_edges(const RRNodeId& node) const {
|
|||
/* check if all the nodes' input edges are valid */
|
||||
bool RRGraph::validate_nodes_in_edges() const {
|
||||
bool all_valid = true;
|
||||
for (auto node : nodes()) {
|
||||
if (true == validate_node_in_edges(node)) {
|
||||
for (size_t id = 0; id < num_nodes_; ++id) {
|
||||
/* Try to find if this is an invalid id or not */
|
||||
if (!valid_node_id(RRNodeId(id))) {
|
||||
/* Skip this id */
|
||||
continue;
|
||||
}
|
||||
if (true == validate_node_in_edges(RRNodeId(id))) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here, it means there is something wrong!
|
||||
|
@ -637,8 +613,13 @@ bool RRGraph::validate_nodes_in_edges() const {
|
|||
/* check if all the nodes' output edges are valid */
|
||||
bool RRGraph::validate_nodes_out_edges() const {
|
||||
bool all_valid = true;
|
||||
for (auto node : nodes()) {
|
||||
if (true == validate_node_out_edges(node)) {
|
||||
for (size_t id = 0; id < num_nodes_; ++id) {
|
||||
/* Try to find if this is an invalid id or not */
|
||||
if (!valid_node_id(RRNodeId(id))) {
|
||||
/* Skip this id */
|
||||
continue;
|
||||
}
|
||||
if (true == validate_node_out_edges(RRNodeId(id))) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here, it means there is something wrong!
|
||||
|
@ -676,15 +657,20 @@ bool RRGraph::validate_edge_sink_node(const RREdgeId& edge) const {
|
|||
/* Check if source nodes of a edge are all valid */
|
||||
bool RRGraph::validate_edge_src_nodes() const {
|
||||
bool all_valid = true;
|
||||
for (auto edge : edges()) {
|
||||
if (true == validate_edge_src_node(edge)) {
|
||||
for (size_t id = 0; id < num_edges_; ++id) {
|
||||
/* Try to find if this is an invalid id or not */
|
||||
if (!valid_edge_id(RREdgeId(id))) {
|
||||
/* Skip this id */
|
||||
continue;
|
||||
}
|
||||
if (true == validate_edge_src_node(RREdgeId(id))) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here, it means there is something wrong!
|
||||
* Print a warning
|
||||
*/
|
||||
VTR_LOG_WARN("Edge %d has a invalid source node %d!\n",
|
||||
size_t(edge), size_t(edge_src_node(edge)));
|
||||
id, size_t(edge_src_node(RREdgeId(id))));
|
||||
all_valid = false;
|
||||
}
|
||||
return all_valid;
|
||||
|
@ -693,15 +679,20 @@ bool RRGraph::validate_edge_src_nodes() const {
|
|||
/* Check if source nodes of a edge are all valid */
|
||||
bool RRGraph::validate_edge_sink_nodes() const {
|
||||
bool all_valid = true;
|
||||
for (auto edge : edges()) {
|
||||
if (true == validate_edge_sink_node(edge)) {
|
||||
for (size_t id = 0; id < num_edges_; ++id) {
|
||||
/* Try to find if this is an invalid id or not */
|
||||
if (!valid_edge_id(RREdgeId(id))) {
|
||||
/* Skip this id */
|
||||
continue;
|
||||
}
|
||||
if (true == validate_edge_sink_node(RREdgeId(id))) {
|
||||
continue;
|
||||
}
|
||||
/* Reach here, it means there is something wrong!
|
||||
* Print a warning
|
||||
*/
|
||||
VTR_LOG_WARN("Edge %d has a invalid sink node %d!\n",
|
||||
size_t(edge), size_t(edge_sink_node(edge)));
|
||||
id, size_t(edge_sink_node(RREdgeId(id))));
|
||||
all_valid = false;
|
||||
}
|
||||
return all_valid;
|
||||
|
@ -714,7 +705,6 @@ bool RRGraph::validate_edge_sink_nodes() const {
|
|||
* Warnings are thrown if optional checking fails
|
||||
*/
|
||||
bool RRGraph::validate() const {
|
||||
bool check_flag = true;
|
||||
size_t num_err = 0;
|
||||
|
||||
initialize_fast_node_lookup();
|
||||
|
@ -724,34 +714,32 @@ bool RRGraph::validate() const {
|
|||
*/
|
||||
if (false == validate_sizes()) {
|
||||
VTR_LOG_WARN("Fail in validating node- and edge-related vector sizes!\n");
|
||||
check_flag = false;
|
||||
num_err++;
|
||||
}
|
||||
|
||||
/* Fundamental check */
|
||||
if (false == validate_nodes_edges()) {
|
||||
VTR_LOG_WARN("Fail in validating edges connected to each node!\n");
|
||||
check_flag = false;
|
||||
num_err++;
|
||||
}
|
||||
|
||||
if (false == validate_node_segments()) {
|
||||
VTR_LOG_WARN("Fail in validating segment IDs of nodes !\n");
|
||||
check_flag = false;
|
||||
num_err++;
|
||||
}
|
||||
|
||||
if (false == validate_edge_switches()) {
|
||||
VTR_LOG_WARN("Fail in validating switch IDs of edges !\n");
|
||||
check_flag = false;
|
||||
num_err++;
|
||||
}
|
||||
|
||||
/* Error out if there is any fatal errors found */
|
||||
if (0 < num_err) {
|
||||
VTR_LOG_ERROR("Routing Resource graph is not valid due to %d fatal errors !\n",
|
||||
num_err);
|
||||
}
|
||||
|
||||
return check_flag;
|
||||
return (0 == num_err);
|
||||
}
|
||||
|
||||
bool RRGraph::is_dirty() const {
|
||||
|
@ -767,55 +755,58 @@ void RRGraph::clear_dirty() {
|
|||
}
|
||||
|
||||
/* Reserve a list of nodes */
|
||||
void RRGraph::reserve_nodes(const int& num_nodes) {
|
||||
void RRGraph::reserve_nodes(const unsigned long& num_nodes) {
|
||||
/* Reserve the full set of vectors related to nodes */
|
||||
/* Basic information */
|
||||
this->node_ids_.reserve(num_nodes);
|
||||
this->node_types_.reserve(num_nodes);
|
||||
|
||||
this->node_bounding_boxes_.reserve(num_nodes);
|
||||
|
||||
this->node_capacities_.reserve(num_nodes);
|
||||
this->node_ptc_nums_.reserve(num_nodes);
|
||||
this->node_cost_indices_.reserve(num_nodes);
|
||||
this->node_directions_.reserve(num_nodes);
|
||||
this->node_sides_.reserve(num_nodes);
|
||||
this->node_Rs_.reserve(num_nodes);
|
||||
this->node_Cs_.reserve(num_nodes);
|
||||
this->node_segments_.reserve(num_nodes);
|
||||
|
||||
/* Edge-related vectors */
|
||||
this->node_num_in_edges_.reserve(num_nodes);
|
||||
this->node_num_out_edges_.reserve(num_nodes);
|
||||
this->node_num_non_configurable_in_edges_.reserve(num_nodes);
|
||||
this->node_num_non_configurable_out_edges_.reserve(num_nodes);
|
||||
|
||||
/* Edge-relate vectors */
|
||||
this->node_in_edges_.reserve(num_nodes);
|
||||
this->node_out_edges_.reserve(num_nodes);
|
||||
this->node_edges_.reserve(num_nodes);
|
||||
}
|
||||
|
||||
/* Reserve a list of edges */
|
||||
void RRGraph::reserve_edges(const int& num_edges) {
|
||||
void RRGraph::reserve_edges(const unsigned long& num_edges) {
|
||||
/* Reserve the full set of vectors related to edges */
|
||||
this->edge_ids_.reserve(num_edges);
|
||||
this->edge_src_nodes_.reserve(num_edges);
|
||||
this->edge_sink_nodes_.reserve(num_edges);
|
||||
this->edge_switches_.reserve(num_edges);
|
||||
}
|
||||
|
||||
/* Reserve a list of switches */
|
||||
void RRGraph::reserve_switches(const int& num_switches) {
|
||||
void RRGraph::reserve_switches(const size_t& num_switches) {
|
||||
this->switch_ids_.reserve(num_switches);
|
||||
this->switches_.reserve(num_switches);
|
||||
}
|
||||
|
||||
/* Reserve a list of segments */
|
||||
void RRGraph::reserve_segments(const int& num_segments) {
|
||||
void RRGraph::reserve_segments(const size_t& num_segments) {
|
||||
this->segment_ids_.reserve(num_segments);
|
||||
this->segments_.reserve(num_segments);
|
||||
}
|
||||
|
||||
/* Mutators */
|
||||
RRNodeId RRGraph::create_node(const t_rr_type& type) {
|
||||
//Allocate an ID
|
||||
RRNodeId node_id = RRNodeId(node_ids_.size());
|
||||
/* Allocate an ID */
|
||||
RRNodeId node_id = RRNodeId(num_nodes_);
|
||||
/* Expand range of node ids */
|
||||
num_nodes_++;
|
||||
|
||||
//Initialize the attributes
|
||||
node_ids_.push_back(node_id);
|
||||
/* Initialize the attributes */
|
||||
node_types_.push_back(type);
|
||||
|
||||
node_bounding_boxes_.emplace_back(-1, -1, -1, -1);
|
||||
|
@ -827,12 +818,14 @@ RRNodeId RRGraph::create_node(const t_rr_type& type) {
|
|||
node_sides_.push_back(NUM_SIDES);
|
||||
node_Rs_.push_back(0.);
|
||||
node_Cs_.push_back(0.);
|
||||
node_segments_.push_back(RRSegmentId::INVALID());
|
||||
|
||||
node_in_edges_.emplace_back(); //Initially empty
|
||||
node_out_edges_.emplace_back(); //Initially empty
|
||||
node_edges_.emplace_back(); //Initially empty
|
||||
|
||||
node_num_non_configurable_in_edges_.emplace_back(); //Initially empty
|
||||
node_num_non_configurable_out_edges_.emplace_back(); //Initially empty
|
||||
node_num_in_edges_.emplace_back(0);
|
||||
node_num_out_edges_.emplace_back(0);
|
||||
node_num_non_configurable_in_edges_.emplace_back(0);
|
||||
node_num_non_configurable_out_edges_.emplace_back(0);
|
||||
|
||||
invalidate_fast_node_lookup();
|
||||
|
||||
|
@ -846,19 +839,20 @@ RREdgeId RRGraph::create_edge(const RRNodeId& source, const RRNodeId& sink, cons
|
|||
VTR_ASSERT(valid_node_id(sink));
|
||||
VTR_ASSERT(valid_switch_id(switch_id));
|
||||
|
||||
//Allocate an ID
|
||||
RREdgeId edge_id = RREdgeId(edge_ids_.size());
|
||||
|
||||
//Initialize the attributes
|
||||
edge_ids_.push_back(edge_id);
|
||||
/* Allocate an ID */
|
||||
RREdgeId edge_id = RREdgeId(num_edges_);
|
||||
/* Expand range of edge ids */
|
||||
num_edges_++;
|
||||
|
||||
/* Initialize the attributes */
|
||||
edge_src_nodes_.push_back(source);
|
||||
edge_sink_nodes_.push_back(sink);
|
||||
edge_switches_.push_back(switch_id);
|
||||
|
||||
//Add the edge to the nodes
|
||||
node_out_edges_[source].push_back(edge_id);
|
||||
node_in_edges_[sink].push_back(edge_id);
|
||||
//We do not create the entry in node_edges_ here!
|
||||
//For memory efficiency this is done when
|
||||
//rebuild_node_edges() is called (i.e. after all
|
||||
//edges have been created).
|
||||
|
||||
VTR_ASSERT(validate_sizes());
|
||||
|
||||
|
@ -902,7 +896,7 @@ void RRGraph::remove_node(const RRNodeId& node) {
|
|||
}
|
||||
|
||||
//Mark node invalid
|
||||
node_ids_[node] = RRNodeId::INVALID();
|
||||
invalid_node_ids_.insert(node);
|
||||
|
||||
//Invalidate the node look-up
|
||||
invalidate_fast_node_lookup();
|
||||
|
@ -918,23 +912,24 @@ void RRGraph::remove_edge(const RREdgeId& edge) {
|
|||
RRNodeId src_node = edge_src_node(edge);
|
||||
RRNodeId sink_node = edge_sink_node(edge);
|
||||
|
||||
//Invalidate node to edge references
|
||||
// TODO: consider making this optional (e.g. if called from remove_node)
|
||||
for (size_t i = 0; i < node_out_edges_[src_node].size(); ++i) {
|
||||
if (node_out_edges_[src_node][i] == edge) {
|
||||
node_out_edges_[src_node][i] = RREdgeId::INVALID();
|
||||
/* Invalidate node to edge references
|
||||
* TODO: consider making this optional (e.g. if called from remove_node)
|
||||
*/
|
||||
for (size_t i = 0; i < node_num_in_edges_[src_node]; ++i) {
|
||||
if (node_edges_[src_node][i] == edge) {
|
||||
node_edges_[src_node][i] = RREdgeId::INVALID();
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < node_in_edges_[sink_node].size(); ++i) {
|
||||
if (node_in_edges_[sink_node][i] == edge) {
|
||||
node_in_edges_[sink_node][i] = RREdgeId::INVALID();
|
||||
for (size_t i = node_num_in_edges_[sink_node]; i < node_num_in_edges_[sink_node] + node_num_out_edges_[sink_node]; ++i) {
|
||||
if (node_edges_[sink_node][i] == edge) {
|
||||
node_edges_[sink_node][i] = RREdgeId::INVALID();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Mark edge invalid
|
||||
edge_ids_[edge] = RREdgeId::INVALID();
|
||||
/* Mark edge invalid */
|
||||
invalid_edge_ids_.insert(edge);
|
||||
|
||||
set_dirty();
|
||||
}
|
||||
|
@ -1047,94 +1042,154 @@ void RRGraph::set_node_segment(const RRNodeId& node, const RRSegmentId& segment_
|
|||
|
||||
node_segments_[node] = segment_id;
|
||||
}
|
||||
void RRGraph::rebuild_node_edges() {
|
||||
node_edges_.resize(nodes().size());
|
||||
node_num_in_edges_.resize(nodes().size(), 0);
|
||||
node_num_out_edges_.resize(nodes().size(), 0);
|
||||
node_num_non_configurable_in_edges_.resize(nodes().size(), 0);
|
||||
node_num_non_configurable_out_edges_.resize(nodes().size(), 0);
|
||||
|
||||
/* For a given node in a rr_graph
|
||||
* classify the edges of each node to be configurable (1st part) and non-configurable (2nd part)
|
||||
*/
|
||||
void RRGraph::partition_node_in_edges(const RRNodeId& node) {
|
||||
//Partition the edges so the first set of edges are all configurable, and the later are not
|
||||
auto first_non_config_edge = std::partition(node_in_edges_[node].begin(), node_in_edges_[node].end(),
|
||||
[&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */
|
||||
//Count the number of edges of each type
|
||||
for (RREdgeId edge : edges()) {
|
||||
if (!edge) continue;
|
||||
|
||||
size_t num_conf_edges = std::distance(node_in_edges_[node].begin(), first_non_config_edge);
|
||||
size_t num_non_conf_edges = node_in_edges_[node].size() - num_conf_edges; //Note we calculate using the size_t to get full range
|
||||
RRNodeId src_node = edge_src_node(edge);
|
||||
RRNodeId sink_node = edge_sink_node(edge);
|
||||
bool config = edge_is_configurable(edge);
|
||||
|
||||
/* Check that within allowable range (no overflow when stored as num_non_configurable_edges_
|
||||
*/
|
||||
VTR_ASSERT_MSG(num_non_conf_edges <= node_in_edges_[node].size(),
|
||||
"Exceeded RR node maximum number of non-configurable input edges");
|
||||
|
||||
node_num_non_configurable_in_edges_[node] = num_non_conf_edges; //Narrowing
|
||||
}
|
||||
|
||||
/* For a given node in a rr_graph
|
||||
* classify the edges of each node to be configurable (1st part) and non-configurable (2nd part)
|
||||
*/
|
||||
void RRGraph::partition_node_out_edges(const RRNodeId& node) {
|
||||
//Partition the edges so the first set of edges are all configurable, and the later are not
|
||||
auto first_non_config_edge = std::partition(node_out_edges_[node].begin(), node_out_edges_[node].end(),
|
||||
[&](const RREdgeId edge) { return edge_is_configurable(edge); }); /* Condition to partition edges */
|
||||
|
||||
size_t num_conf_edges = std::distance(node_out_edges_[node].begin(), first_non_config_edge);
|
||||
size_t num_non_conf_edges = node_out_edges_[node].size() - num_conf_edges; //Note we calculate using the size_t to get full range
|
||||
|
||||
/* Check that within allowable range (no overflow when stored as num_non_configurable_edges_
|
||||
*/
|
||||
VTR_ASSERT_MSG(num_non_conf_edges <= node_out_edges_[node].size(),
|
||||
"Exceeded RR node maximum number of non-configurable output edges");
|
||||
|
||||
node_num_non_configurable_out_edges_[node] = num_non_conf_edges; //Narrowing
|
||||
}
|
||||
|
||||
/* For all nodes in a rr_graph
|
||||
* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part)
|
||||
*/
|
||||
void RRGraph::partition_in_edges() {
|
||||
/* For each node */
|
||||
for (auto node : nodes()) {
|
||||
this->partition_node_in_edges(node);
|
||||
++node_num_out_edges_[src_node];
|
||||
++node_num_in_edges_[sink_node];
|
||||
if (!config) {
|
||||
++node_num_non_configurable_out_edges_[src_node];
|
||||
++node_num_non_configurable_in_edges_[sink_node];
|
||||
}
|
||||
}
|
||||
|
||||
/* For all nodes in a rr_graph
|
||||
* classify the output edges of each node to be configurable (1st part) and non-configurable (2nd part)
|
||||
*/
|
||||
void RRGraph::partition_out_edges() {
|
||||
/* For each node */
|
||||
for (auto node : nodes()) {
|
||||
this->partition_node_out_edges(node);
|
||||
//Allocate precisely the correct space for each nodes edge list
|
||||
for (RRNodeId node : nodes()) {
|
||||
if (!node) continue;
|
||||
|
||||
node_edges_[node] = std::make_unique<RREdgeId[]>(node_num_in_edges_[node] + node_num_out_edges_[node]);
|
||||
}
|
||||
|
||||
//Insert the edges into the node lists
|
||||
{
|
||||
vtr::vector<RRNodeId, int> inserted_edge_cnt(nodes().size(), 0);
|
||||
for (RREdgeId edge : edges()) {
|
||||
RRNodeId src_node = edge_src_node(edge);
|
||||
RRNodeId sink_node = edge_sink_node(edge);
|
||||
|
||||
node_edges_[src_node][inserted_edge_cnt[src_node]++] = edge;
|
||||
node_edges_[sink_node][inserted_edge_cnt[sink_node]++] = edge;
|
||||
}
|
||||
}
|
||||
|
||||
/* For all nodes in a rr_graph
|
||||
* classify both input and output edges of each node
|
||||
* to be configurable (1st part) and non-configurable (2nd part)
|
||||
#if 0
|
||||
//TODO: Sanity Check remove!
|
||||
for (RRNodeId node : nodes()) {
|
||||
for (size_t iedge = 0; iedge < node_num_in_edges_[node] + node_num_out_edges_[node]; ++iedge) {
|
||||
RREdgeId edge = node_edges_[node][iedge];
|
||||
VTR_ASSERT(edge_src_node(edge) == node || edge_sink_node(edge) == node);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//Partition each node's edge lists according to their type to line up with the counts
|
||||
|
||||
auto is_configurable_edge = [&](const RREdgeId edge) {
|
||||
return edge_is_configurable(edge);
|
||||
};
|
||||
|
||||
for (RRNodeId node : nodes()) {
|
||||
if (!node) continue;
|
||||
|
||||
//We partition the nodes first by incoming/outgoing:
|
||||
//
|
||||
// +---------------------------+-----------------------------+
|
||||
// | in | out |
|
||||
// +---------------------------+-----------------------------+
|
||||
//
|
||||
//and then the two subsets by configurability. So the final ordering is:
|
||||
//
|
||||
// +-----------+---------------+------------+----------------+
|
||||
// | in_config | in_non_config | out_config | out_non_config |
|
||||
// +-----------+---------------+------------+----------------+
|
||||
//
|
||||
|
||||
//Partition first into incoming/outgoing
|
||||
auto is_incoming_edge = [&](const RREdgeId edge) {
|
||||
return edge_sink_node(edge) == node;
|
||||
};
|
||||
/* Use stable_partition to keep the relative order,
|
||||
* This is mainly for comparing the RRGraph write with rr_node writer
|
||||
* so that it is easy to check consistency
|
||||
*/
|
||||
void RRGraph::partition_edges() {
|
||||
/* Partition input edges */
|
||||
this->partition_in_edges();
|
||||
/* Partition output edges */
|
||||
this->partition_out_edges();
|
||||
std::stable_partition(node_edges_[node].get(),
|
||||
node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node],
|
||||
is_incoming_edge);
|
||||
|
||||
//Partition incoming by configurable/non-configurable
|
||||
std::stable_partition(node_edges_[node].get(),
|
||||
node_edges_[node].get() + node_num_in_edges_[node],
|
||||
is_configurable_edge);
|
||||
|
||||
//Partition outgoing by configurable/non-configurable
|
||||
std::stable_partition(node_edges_[node].get() + node_num_in_edges_[node],
|
||||
node_edges_[node].get() + node_num_in_edges_[node] + node_num_out_edges_[node],
|
||||
is_configurable_edge);
|
||||
|
||||
#if 0
|
||||
//TODO: Sanity check remove!
|
||||
size_t nedges = node_num_in_edges_[node] + node_num_out_edges_[node];
|
||||
for (size_t iedge = 0; iedge < nedges; ++iedge) {
|
||||
RREdgeId edge = node_edges_[node][iedge];
|
||||
if (iedge < node_num_in_edges_[node]) { //Incoming
|
||||
VTR_ASSERT(edge_sink_node(edge) == node);
|
||||
if (iedge < node_num_in_edges_[node] - node_num_non_configurable_in_edges_[node]) {
|
||||
VTR_ASSERT(edge_is_configurable(edge));
|
||||
} else {
|
||||
VTR_ASSERT(!edge_is_configurable(edge));
|
||||
}
|
||||
} else { //Outgoing
|
||||
VTR_ASSERT(edge_src_node(edge) == node);
|
||||
if (iedge < node_num_in_edges_[node] + node_num_out_edges_[node] - node_num_non_configurable_out_edges_[node]) {
|
||||
VTR_ASSERT(edge_is_configurable(edge));
|
||||
} else {
|
||||
VTR_ASSERT(!edge_is_configurable(edge));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void RRGraph::build_fast_node_lookup() const {
|
||||
/* Free the current fast node look-up, we will rebuild a new one here */
|
||||
invalidate_fast_node_lookup();
|
||||
|
||||
for (auto node : nodes()) {
|
||||
/* Get the max (x,y) and then we can resize the ndmatrix */
|
||||
vtr::Point<short> max_coord(0, 0);
|
||||
for (size_t id = 0; id < num_nodes_; ++id) {
|
||||
/* Try to find if this is an invalid id or not */
|
||||
if (!valid_node_id(RRNodeId(id))) {
|
||||
/* Skip this id */
|
||||
continue;
|
||||
}
|
||||
max_coord.set_x(std::max(max_coord.x(), node_xlow(RRNodeId(id))));
|
||||
max_coord.set_y(std::max(max_coord.y(), node_ylow(RRNodeId(id))));
|
||||
}
|
||||
node_lookup_.resize({(size_t)max_coord.x() + 1, (size_t)max_coord.y() + 1, NUM_RR_TYPES + 1});
|
||||
|
||||
for (size_t id = 0; id < num_nodes_; ++id) {
|
||||
/* Try to find if this is an invalid id or not */
|
||||
if (!valid_node_id(RRNodeId(id))) {
|
||||
/* Skip this id */
|
||||
continue;
|
||||
}
|
||||
RRNodeId node = RRNodeId(id);
|
||||
size_t x = node_xlow(node);
|
||||
if (x >= node_lookup_.size()) {
|
||||
node_lookup_.resize(x + 1);
|
||||
}
|
||||
|
||||
size_t y = node_ylow(node);
|
||||
if (y >= node_lookup_[x].size()) {
|
||||
node_lookup_[x].resize(y + 1);
|
||||
}
|
||||
|
||||
size_t itype = node_type(node);
|
||||
if (itype >= node_lookup_[x][y].size()) {
|
||||
node_lookup_[x][y].resize(itype + 1);
|
||||
}
|
||||
|
||||
size_t ptc = node_ptc_num(node);
|
||||
if (ptc >= node_lookup_[x][y][itype].size()) {
|
||||
|
@ -1172,11 +1227,13 @@ void RRGraph::initialize_fast_node_lookup() const {
|
|||
}
|
||||
|
||||
bool RRGraph::valid_node_id(const RRNodeId& node) const {
|
||||
return size_t(node) < node_ids_.size() && node_ids_[node] == node;
|
||||
return (size_t(node) < num_nodes_)
|
||||
&& (!invalid_node_ids_.count(node));
|
||||
}
|
||||
|
||||
bool RRGraph::valid_edge_id(const RREdgeId& edge) const {
|
||||
return size_t(edge) < edge_ids_.size() && edge_ids_[edge] == edge;
|
||||
return (size_t(edge) < num_edges_)
|
||||
&& (!invalid_edge_ids_.count(edge));
|
||||
}
|
||||
|
||||
/* check if a given switch id is valid or not */
|
||||
|
@ -1205,26 +1262,25 @@ bool RRGraph::validate_sizes() const {
|
|||
}
|
||||
|
||||
bool RRGraph::validate_node_sizes() const {
|
||||
return node_types_.size() == node_ids_.size()
|
||||
&& node_bounding_boxes_.size() == node_ids_.size()
|
||||
&& node_capacities_.size() == node_ids_.size()
|
||||
&& node_ptc_nums_.size() == node_ids_.size()
|
||||
&& node_cost_indices_.size() == node_ids_.size()
|
||||
&& node_directions_.size() == node_ids_.size()
|
||||
&& node_sides_.size() == node_ids_.size()
|
||||
&& node_Rs_.size() == node_ids_.size()
|
||||
&& node_Cs_.size() == node_ids_.size()
|
||||
&& node_segments_.size() == node_ids_.size()
|
||||
&& node_num_non_configurable_in_edges_.size() == node_ids_.size()
|
||||
&& node_num_non_configurable_out_edges_.size() == node_ids_.size()
|
||||
&& node_in_edges_.size() == node_ids_.size()
|
||||
&& node_out_edges_.size() == node_ids_.size();
|
||||
return node_types_.size() == num_nodes_
|
||||
&& node_bounding_boxes_.size() == num_nodes_
|
||||
&& node_capacities_.size() == num_nodes_
|
||||
&& node_ptc_nums_.size() == num_nodes_
|
||||
&& node_cost_indices_.size() == num_nodes_
|
||||
&& node_directions_.size() == num_nodes_
|
||||
&& node_sides_.size() == num_nodes_
|
||||
&& node_Rs_.size() == num_nodes_
|
||||
&& node_Cs_.size() == num_nodes_
|
||||
&& node_segments_.size() == num_nodes_
|
||||
&& node_num_non_configurable_in_edges_.size() == num_nodes_
|
||||
&& node_num_non_configurable_out_edges_.size() == num_nodes_
|
||||
&& node_edges_.size() == num_nodes_;
|
||||
}
|
||||
|
||||
bool RRGraph::validate_edge_sizes() const {
|
||||
return edge_src_nodes_.size() == edge_ids_.size()
|
||||
&& edge_sink_nodes_.size() == edge_ids_.size()
|
||||
&& edge_switches_.size() == edge_ids_.size();
|
||||
return edge_src_nodes_.size() == num_edges_
|
||||
&& edge_sink_nodes_.size() == num_edges_
|
||||
&& edge_switches_.size() == num_edges_;
|
||||
}
|
||||
|
||||
bool RRGraph::validate_switch_sizes() const {
|
||||
|
@ -1236,8 +1292,8 @@ bool RRGraph::validate_segment_sizes() const {
|
|||
}
|
||||
|
||||
void RRGraph::compress() {
|
||||
vtr::vector<RRNodeId, RRNodeId> node_id_map(node_ids_.size());
|
||||
vtr::vector<RREdgeId, RREdgeId> edge_id_map(edge_ids_.size());
|
||||
vtr::vector<RRNodeId, RRNodeId> node_id_map(num_nodes_);
|
||||
vtr::vector<RREdgeId, RREdgeId> edge_id_map(num_edges_);
|
||||
|
||||
build_id_maps(node_id_map, edge_id_map);
|
||||
|
||||
|
@ -1248,17 +1304,48 @@ void RRGraph::compress() {
|
|||
|
||||
invalidate_fast_node_lookup();
|
||||
|
||||
/* Clear invalid node list */
|
||||
invalid_node_ids_.clear();
|
||||
|
||||
/* Clear invalid edge list */
|
||||
invalid_edge_ids_.clear();
|
||||
|
||||
clear_dirty();
|
||||
}
|
||||
|
||||
void RRGraph::build_id_maps(vtr::vector<RRNodeId, RRNodeId>& node_id_map,
|
||||
vtr::vector<RREdgeId, RREdgeId>& edge_id_map) {
|
||||
node_id_map = compress_ids(node_ids_);
|
||||
edge_id_map = compress_ids(edge_ids_);
|
||||
/* Build node ids including invalid ids and compress */
|
||||
vtr::vector<RRNodeId, RRNodeId> node_ids;
|
||||
for (size_t id = 0; id < num_nodes_; ++id) {
|
||||
/* Try to find if this is an invalid id or not */
|
||||
if (!valid_node_id(RRNodeId(id))) {
|
||||
/* Give and invalid id */
|
||||
node_ids.push_back(RRNodeId::INVALID());
|
||||
continue;
|
||||
}
|
||||
/* Reach here, this is a valid id, push to the edge list */
|
||||
node_ids.push_back(RRNodeId(id));
|
||||
}
|
||||
node_id_map = compress_ids(node_ids);
|
||||
|
||||
/* Build edge ids including invalid ids and compress */
|
||||
vtr::vector<RREdgeId, RREdgeId> edge_ids;
|
||||
for (size_t id = 0; id < num_edges_; ++id) {
|
||||
/* Try to find if this is an invalid id or not */
|
||||
if (!valid_edge_id(RREdgeId(id))) {
|
||||
/* Give and invalid id */
|
||||
edge_ids.push_back(RREdgeId::INVALID());
|
||||
continue;
|
||||
}
|
||||
/* Reach here, this is a valid id, push to the edge list */
|
||||
edge_ids.push_back(RREdgeId(id));
|
||||
}
|
||||
edge_id_map = compress_ids(edge_ids);
|
||||
}
|
||||
|
||||
void RRGraph::clean_nodes(const vtr::vector<RRNodeId, RRNodeId>& node_id_map) {
|
||||
node_ids_ = clean_and_reorder_ids(node_id_map);
|
||||
num_nodes_ = node_id_map.size();
|
||||
|
||||
node_types_ = clean_and_reorder_values(node_types_, node_id_map);
|
||||
|
||||
|
@ -1272,39 +1359,46 @@ void RRGraph::clean_nodes(const vtr::vector<RRNodeId, RRNodeId>& node_id_map) {
|
|||
node_Rs_ = clean_and_reorder_values(node_Rs_, node_id_map);
|
||||
node_Cs_ = clean_and_reorder_values(node_Cs_, node_id_map);
|
||||
|
||||
VTR_ASSERT(validate_node_sizes());
|
||||
node_segments_ = clean_and_reorder_values(node_segments_, node_id_map);
|
||||
node_num_non_configurable_in_edges_ = clean_and_reorder_values(node_num_non_configurable_in_edges_, node_id_map);
|
||||
node_num_non_configurable_out_edges_ = clean_and_reorder_values(node_num_non_configurable_out_edges_, node_id_map);
|
||||
node_num_in_edges_ = clean_and_reorder_values(node_num_in_edges_, node_id_map);
|
||||
node_num_out_edges_ = clean_and_reorder_values(node_num_out_edges_, node_id_map);
|
||||
//node_edges_ = clean_and_reorder_values(node_edges_, node_id_map);
|
||||
|
||||
VTR_ASSERT_MSG(are_contiguous(node_ids_), "Ids should be contiguous");
|
||||
VTR_ASSERT_MSG(all_valid(node_ids_), "All Ids should be valid");
|
||||
VTR_ASSERT(validate_node_sizes());
|
||||
}
|
||||
|
||||
void RRGraph::clean_edges(const vtr::vector<RREdgeId, RREdgeId>& edge_id_map) {
|
||||
edge_ids_ = clean_and_reorder_ids(edge_id_map);
|
||||
num_edges_ = edge_id_map.size();
|
||||
|
||||
edge_src_nodes_ = clean_and_reorder_values(edge_src_nodes_, edge_id_map);
|
||||
edge_sink_nodes_ = clean_and_reorder_values(edge_sink_nodes_, edge_id_map);
|
||||
edge_switches_ = clean_and_reorder_values(edge_switches_, edge_id_map);
|
||||
|
||||
VTR_ASSERT(validate_edge_sizes());
|
||||
|
||||
VTR_ASSERT_MSG(are_contiguous(edge_ids_), "Ids should be contiguous");
|
||||
VTR_ASSERT_MSG(all_valid(edge_ids_), "All Ids should be valid");
|
||||
}
|
||||
|
||||
void RRGraph::rebuild_node_refs(const vtr::vector<RREdgeId, RREdgeId>& edge_id_map) {
|
||||
for (const auto& node : nodes()) {
|
||||
node_in_edges_[node] = update_valid_refs(node_in_edges_[node], edge_id_map);
|
||||
node_out_edges_[node] = update_valid_refs(node_out_edges_[node], edge_id_map);
|
||||
for (size_t id = 0; id < num_nodes_; ++id) {
|
||||
/* Try to find if this is an invalid id or not */
|
||||
if (!valid_node_id(RRNodeId(id))) {
|
||||
/* Skip this id */
|
||||
continue;
|
||||
}
|
||||
RRNodeId node = RRNodeId(id);
|
||||
|
||||
VTR_ASSERT_MSG(all_valid(node_in_edges_[node]), "All Ids should be valid");
|
||||
VTR_ASSERT_MSG(all_valid(node_out_edges_[node]), "All Ids should be valid");
|
||||
auto begin = node_edges_[node].get();
|
||||
auto end = begin + node_num_in_edges_[node] + node_num_out_edges_[node];
|
||||
update_valid_refs(begin, end, edge_id_map);
|
||||
|
||||
VTR_ASSERT_MSG(all_valid(begin, end), "All Ids should be valid");
|
||||
}
|
||||
}
|
||||
|
||||
/* Empty all the vectors related to nodes */
|
||||
void RRGraph::clear_nodes() {
|
||||
node_ids_.clear();
|
||||
|
||||
num_nodes_ = 0;
|
||||
node_types_.clear();
|
||||
node_bounding_boxes_.clear();
|
||||
|
||||
|
@ -1317,11 +1411,12 @@ void RRGraph::clear_nodes() {
|
|||
node_Cs_.clear();
|
||||
node_segments_.clear();
|
||||
|
||||
node_num_in_edges_.clear();
|
||||
node_num_out_edges_.clear();
|
||||
node_num_non_configurable_in_edges_.clear();
|
||||
node_num_non_configurable_out_edges_.clear();
|
||||
|
||||
node_in_edges_.clear();
|
||||
node_out_edges_.clear();
|
||||
node_edges_.clear();
|
||||
|
||||
/* clean node_look_up */
|
||||
node_lookup_.clear();
|
||||
|
@ -1329,7 +1424,7 @@ void RRGraph::clear_nodes() {
|
|||
|
||||
/* Empty all the vectors related to edges */
|
||||
void RRGraph::clear_edges() {
|
||||
edge_ids_.clear();
|
||||
num_edges_ = 0;
|
||||
edge_src_nodes_.clear();
|
||||
edge_sink_nodes_.clear();
|
||||
edge_switches_.clear();
|
||||
|
|
|
@ -198,30 +198,44 @@
|
|||
/* Standard header files required go first */
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
|
||||
/* EXTERNAL library header files go second*/
|
||||
#include "vtr_ndmatrix.h"
|
||||
#include "vtr_vector.h"
|
||||
#include "vtr_range.h"
|
||||
#include "vtr_geometry.h"
|
||||
#include "arch_types.h"
|
||||
|
||||
/* VPR header files go third */
|
||||
#include "vpr_types.h"
|
||||
#include "rr_graph_types.h"
|
||||
#include "rr_graph_fwd.h"
|
||||
|
||||
class RRGraph {
|
||||
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 */
|
||||
typedef vtr::vector<RRNodeId, RRNodeId>::const_iterator node_iterator;
|
||||
typedef vtr::vector<RREdgeId, RREdgeId>::const_iterator edge_iterator;
|
||||
typedef vtr::vector<RRSwitchId, RRSwitchId>::const_iterator switch_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 */
|
||||
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<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 */
|
||||
/* Aggregates: create range-based loops for nodes/edges/switches/segments
|
||||
|
@ -247,8 +261,8 @@ class RRGraph {
|
|||
* // Do something with each segment
|
||||
* }
|
||||
*/
|
||||
node_range nodes() const;
|
||||
edge_range edges() const;
|
||||
lazy_node_range nodes() const;
|
||||
lazy_edge_range edges() const;
|
||||
switch_range switches() const;
|
||||
segment_range segments() const;
|
||||
|
||||
|
@ -445,23 +459,9 @@ class RRGraph {
|
|||
*/
|
||||
RRSegmentId node_segment(const RRNodeId& node) const;
|
||||
|
||||
/* Get the number of non-configurable incoming edges to a node */
|
||||
short node_num_configurable_in_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;
|
||||
//Returns an iterable range of all edges (incoming & outgoing) for
|
||||
//the specified node
|
||||
edge_range node_edges(const RRNodeId& node) const;
|
||||
|
||||
/* Get a list of edge ids, which are incoming edges to a node */
|
||||
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 */
|
||||
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
|
||||
* An example to explain the terminology used in RRGraph
|
||||
* edgeA
|
||||
|
@ -583,10 +589,10 @@ class RRGraph {
|
|||
* rr_graph.create_node(CHANX);
|
||||
* }
|
||||
*/
|
||||
void reserve_nodes(const int& num_nodes);
|
||||
void reserve_edges(const int& num_edges);
|
||||
void reserve_switches(const int& num_switches);
|
||||
void reserve_segments(const int& num_segments);
|
||||
void reserve_nodes(const unsigned long& num_nodes);
|
||||
void reserve_edges(const unsigned long& num_edges);
|
||||
void reserve_switches(const size_t& num_switches);
|
||||
void reserve_segments(const size_t& num_segments);
|
||||
|
||||
/* Add new elements (node, edge, switch, etc.) to RRGraph */
|
||||
/* Add a node to the RRGraph with a deposited type
|
||||
|
@ -596,6 +602,7 @@ class RRGraph {
|
|||
* set_node_xlow(node, 0);
|
||||
*/
|
||||
RRNodeId create_node(const t_rr_type& type);
|
||||
|
||||
/* Add a edge to the RRGraph, by providing the source and sink node
|
||||
* This function will automatically create a node and
|
||||
* configure the nodes and edges in connection
|
||||
|
@ -690,15 +697,14 @@ class RRGraph {
|
|||
/* 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);
|
||||
|
||||
/* Edge partitioning is performed for efficiency,
|
||||
* so we can store configurable and non-configurable edge lists for a node in one vector,
|
||||
* and efficiently iterate over all edges, or only the configurable or non-configurable subsets.
|
||||
* This function will re-organize the incoming and outgoing edges of each node,
|
||||
* i.e., node_in_edges() and node_out_edges():
|
||||
* 1. configurable edges (1st part of the vectors)
|
||||
* 2. non-configurable edges (2nd part of the vectors)
|
||||
/*
|
||||
* Build the node to edge references to allow iteration through
|
||||
* a node's in/out edges.
|
||||
*
|
||||
* Must be called before any node_*_in_edges() or node_*_out_edges() member
|
||||
* functions can be called.
|
||||
*/
|
||||
void partition_edges();
|
||||
void rebuild_node_edges();
|
||||
|
||||
/* 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
|
||||
|
@ -708,18 +714,52 @@ class RRGraph {
|
|||
/* top-level function to free, should be called when to delete a RRGraph */
|
||||
void clear();
|
||||
|
||||
private: /* Internal Mutators to perform edge partitioning */
|
||||
/* 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);
|
||||
public: /* Type implementations */
|
||||
/*
|
||||
* 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) */
|
||||
void partition_node_out_edges(const RRNodeId& node);
|
||||
lazy_id_iterator(value_type init, const std::unordered_set<ID>& invalid_ids)
|
||||
: value_(init)
|
||||
, invalid_ids_(invalid_ids) {}
|
||||
|
||||
/* classify the input edges of each node to be configurable (1st part) and non-configurable (2nd part) */
|
||||
void partition_in_edges();
|
||||
//Advance to the next ID value
|
||||
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) */
|
||||
void partition_out_edges();
|
||||
//Advance to the previous ID value
|
||||
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 */
|
||||
void clear_nodes();
|
||||
|
@ -787,7 +827,9 @@ class RRGraph {
|
|||
|
||||
private: /* Internal 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, vtr::Rect<short>> node_bounding_boxes_;
|
||||
|
@ -800,15 +842,44 @@ class RRGraph {
|
|||
vtr::vector<RRNodeId, float> node_Rs_;
|
||||
vtr::vector<RRNodeId, float> node_Cs_;
|
||||
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 */
|
||||
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_sink_nodes_;
|
||||
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
|
||||
* 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_;
|
||||
};
|
||||
|
||||
|
|
|
@ -38,6 +38,16 @@ bool all_valid(const Container& values) {
|
|||
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
|
||||
template<typename Container>
|
||||
Container compress_ids(const Container& ids) {
|
||||
|
@ -162,4 +172,20 @@ ValueContainer update_valid_refs(const ValueContainer& values, const IdContainer
|
|||
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
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -36,6 +36,9 @@
|
|||
|
||||
#include "rr_types.h"
|
||||
|
||||
#include "create_rr_graph.h"
|
||||
#include "write_xml_rr_graph_obj.h"
|
||||
|
||||
//#define VERBOSE
|
||||
|
||||
struct t_mux {
|
||||
|
@ -331,6 +334,9 @@ void create_rr_graph(const t_graph_type graph_type,
|
|||
base_cost_type,
|
||||
&det_routing_arch->wire_to_rr_ipin_switch,
|
||||
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 {
|
||||
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,
|
||||
base_cost_type);
|
||||
}
|
||||
|
||||
/* Xifan Tang - Create rr_graph object: load rr_nodes to the object */
|
||||
convert_rr_graph(segment_inf);
|
||||
}
|
||||
|
||||
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
|
||||
if (!det_routing_arch->write_rr_graph_filename.empty()) {
|
||||
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();
|
||||
|
||||
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,
|
||||
|
|
Loading…
Reference in New Issue