Merge branch 'refactoring' into dev
This commit is contained in:
commit
f136dd8820
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
|
@ -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 *
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 "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,
|
||||||
|
|
Loading…
Reference in New Issue