Merge branch 'tileable_routing' into multimode_clb

This commit is contained in:
tangxifan 2019-06-26 11:36:08 -06:00
commit 9b6a4b39bb
48 changed files with 4399 additions and 1261 deletions

View File

@ -150,7 +150,7 @@
<!-- ODIN II specific config ends --> <!-- ODIN II specific config ends -->
<!-- Physical descriptions begin --> <!-- Physical descriptions begin -->
<layout auto="1.0"/> <layout auto="1.0" tileable_routing="off"/>
<spice_settings> <spice_settings>
<parameters> <parameters>
<options sim_temp="25" post="off" captab="off" fast="on"/> <options sim_temp="25" post="off" captab="off" fast="on"/>

View File

@ -928,6 +928,7 @@ typedef struct s_direct_inf {
/* Detailed routing architecture */ /* Detailed routing architecture */
typedef struct s_arch t_arch; typedef struct s_arch t_arch;
struct s_arch { struct s_arch {
bool tileable; /* Xifan TANG: tileable rr_graph support */
t_chan_width_dist Chans; t_chan_width_dist Chans;
enum e_switch_block_type SBType; enum e_switch_block_type SBType;
float R_minW_nmos; float R_minW_nmos;

View File

@ -2062,6 +2062,25 @@ static void ProcessLayout(INOUTP ezxml_t Node, OUTP struct s_arch *arch) {
arch->clb_grid.Aspect); arch->clb_grid.Aspect);
} }
} }
/* Xifan TANG: Tileable Routing Support
* Load tileable_routing if applicable
*/
arch->tileable = false;
Prop = FindProperty(Node, "tileable_routing", FALSE);
if (Prop != NULL) {
if ( 0 == strcmp("on", Prop)) {
arch->tileable = true;
}
ezxml_set_attr(Node, "tileable_routing", NULL);
}
if (true == arch->tileable) {
vpr_printf(TIO_MESSAGE_INFO,
"Tileable routing architecture generation is enabled.\n");
} else {
vpr_printf(TIO_MESSAGE_INFO,
"Tileable routing architecture generation is disable. FPGA may not be tileable! \n");
}
} }
/* Takes in node pointing to <device> and loads all the /* Takes in node pointing to <device> and loads all the

View File

@ -542,6 +542,7 @@ static void SetupRoutingArch(INP t_arch Arch,
RoutingArch->directionality = BI_DIRECTIONAL; RoutingArch->directionality = BI_DIRECTIONAL;
if (Arch.Segments) if (Arch.Segments)
RoutingArch->directionality = Arch.Segments[0].directionality; RoutingArch->directionality = Arch.Segments[0].directionality;
RoutingArch->tileable = Arch.tileable;
} }
static void SetupRouterOpts(INP t_options Options, INP boolean TimingEnabled, static void SetupRouterOpts(INP t_options Options, INP boolean TimingEnabled,

View File

@ -296,10 +296,15 @@ static int binary_search_place_and_route(struct s_placer_opts placer_opts,
if (router_opts.route_type == GLOBAL) { if (router_opts.route_type == GLOBAL) {
graph_type = GRAPH_GLOBAL; graph_type = GRAPH_GLOBAL;
/* Xifan Tang: tileable undirectional rr_graph support */
} else if (BI_DIRECTIONAL == det_routing_arch.directionality) {
graph_type = GRAPH_BIDIR;
} else if (UNI_DIRECTIONAL == det_routing_arch.directionality) {
if (true == det_routing_arch.tileable) {
graph_type = GRAPH_UNIDIR_TILEABLE;
} else { } else {
graph_type = ( graph_type = GRAPH_UNIDIR;
det_routing_arch.directionality == BI_DIRECTIONAL ? }
GRAPH_BIDIR : GRAPH_UNIDIR);
} }
max_pins_per_clb = 0; max_pins_per_clb = 0;

View File

@ -36,6 +36,7 @@
#include "arch_types.h" #include "arch_types.h"
#include <map> #include <map>
#include <vector> #include <vector>
#include <array>
/******************************************************************************* /*******************************************************************************
* Global data types and constants * Global data types and constants
@ -815,6 +816,7 @@ struct s_det_routing_arch {
float R_minW_pmos; float R_minW_pmos;
int num_swseg_pattern; /*Xifan TANG: Switch Segment Pattern Support*/ int num_swseg_pattern; /*Xifan TANG: Switch Segment Pattern Support*/
short opin_to_wire_switch; /* mrFPGA: Xifan TANG*/ short opin_to_wire_switch; /* mrFPGA: Xifan TANG*/
bool tileable; /* Xifan Tang: tileable rr_graph support */
}; };
/* Defines the detailed routing architecture of the FPGA. Only important * /* Defines the detailed routing architecture of the FPGA. Only important *
@ -907,6 +909,10 @@ typedef enum e_rr_type {
SOURCE = 0, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE, NUM_RR_TYPES SOURCE = 0, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE, NUM_RR_TYPES
} t_rr_type; } t_rr_type;
constexpr std::array<const char*, NUM_RR_TYPES + 1> rr_node_typename { {
"SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY", "INTRA_CLUSTER_EDGE", "NUM_RR_TYPES"
} };
/* Type of a routing resource node. x-directed channel segment, * /* Type of a routing resource node. x-directed channel segment, *
* y-directed channel segment, input pin to a clb to pad, output * * 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: * * from a clb or pad (i.e. output pin of a net) and: *

View File

@ -49,6 +49,7 @@ ChanNodeDetails::ChanNodeDetails(const ChanNodeDetails& src) {
for (size_t itrack = 0; itrack < chan_width; ++itrack) { for (size_t itrack = 0; itrack < chan_width; ++itrack) {
track_node_ids_.push_back(src.get_track_node_id(itrack)); track_node_ids_.push_back(src.get_track_node_id(itrack));
track_direction_.push_back(src.get_track_direction(itrack)); track_direction_.push_back(src.get_track_direction(itrack));
seg_ids_.push_back(src.get_track_segment_id(itrack));
seg_length_.push_back(src.get_track_segment_length(itrack)); seg_length_.push_back(src.get_track_segment_length(itrack));
track_start_.push_back(src.is_track_start(itrack)); track_start_.push_back(src.is_track_start(itrack));
track_end_.push_back(src.is_track_end(itrack)); track_end_.push_back(src.is_track_end(itrack));
@ -72,6 +73,15 @@ size_t ChanNodeDetails::get_track_node_id(size_t track_id) const {
return track_node_ids_[track_id]; return track_node_ids_[track_id];
} }
/* Return a copy of vector */
std::vector<size_t> ChanNodeDetails::get_track_node_ids() const {
std::vector<size_t> copy;
for (size_t inode = 0; inode < get_chan_width(); ++inode) {
copy.push_back(track_node_ids_[inode]);
}
return copy;
}
e_direction ChanNodeDetails::get_track_direction(size_t track_id) const { e_direction ChanNodeDetails::get_track_direction(size_t track_id) const {
assert(validate_track_id(track_id)); assert(validate_track_id(track_id));
return track_direction_[track_id]; return track_direction_[track_id];
@ -82,6 +92,11 @@ size_t ChanNodeDetails::get_track_segment_length(size_t track_id) const {
return seg_length_[track_id]; return seg_length_[track_id];
} }
size_t ChanNodeDetails::get_track_segment_id(size_t track_id) const {
assert(validate_track_id(track_id));
return seg_ids_[track_id];
}
bool ChanNodeDetails::is_track_start(size_t track_id) const { bool ChanNodeDetails::is_track_start(size_t track_id) const {
assert(validate_track_id(track_id)); assert(validate_track_id(track_id));
return track_start_[track_id]; return track_start_[track_id];
@ -105,12 +120,12 @@ std::vector<size_t> ChanNodeDetails::get_seg_group(size_t track_id) const {
/* Make sure a clean start */ /* Make sure a clean start */
group.clear(); group.clear();
/* track_id is the first element */
group.push_back(track_id);
for (size_t itrack = track_id; itrack < get_chan_width(); ++itrack) { for (size_t itrack = track_id; itrack < get_chan_width(); ++itrack) {
if ( (get_track_direction(itrack) == get_track_direction(track_id) ) if ( (get_track_direction(itrack) != get_track_direction(track_id) )
&& (get_track_segment_length(itrack) == get_track_segment_length(track_id)) ) { || (get_track_segment_id(itrack) != get_track_segment_id(track_id)) ) {
/* Bypass any nodes in different direction and segment information*/
continue;
}
if ( (false == is_track_start(itrack)) if ( (false == is_track_start(itrack))
|| ( (true == is_track_start(itrack)) && (itrack == track_id)) ) { || ( (true == is_track_start(itrack)) && (itrack == track_id)) ) {
group.push_back(itrack); group.push_back(itrack);
@ -121,7 +136,6 @@ std::vector<size_t> ChanNodeDetails::get_seg_group(size_t track_id) const {
break; break;
} }
} }
}
return group; return group;
} }
@ -140,9 +154,13 @@ std::vector<size_t> ChanNodeDetails::get_seg_group_node_id(std::vector<size_t> s
} }
/* Get the number of tracks that starts in this routing channel */ /* Get the number of tracks that starts in this routing channel */
size_t ChanNodeDetails::get_num_starting_tracks() const { size_t ChanNodeDetails::get_num_starting_tracks(enum e_direction track_direction) const {
size_t counter = 0; size_t counter = 0;
for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) { for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) {
/* Bypass unmatched track_direction */
if (track_direction != get_track_direction(itrack)) {
continue;
}
if (false == is_track_start(itrack)) { if (false == is_track_start(itrack)) {
continue; continue;
} }
@ -152,9 +170,13 @@ size_t ChanNodeDetails::get_num_starting_tracks() const {
} }
/* Get the number of tracks that ends in this routing channel */ /* Get the number of tracks that ends in this routing channel */
size_t ChanNodeDetails::get_num_ending_tracks() const { size_t ChanNodeDetails::get_num_ending_tracks(enum e_direction track_direction) const {
size_t counter = 0; size_t counter = 0;
for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) { for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) {
/* Bypass unmatched track_direction */
if (track_direction != get_track_direction(itrack)) {
continue;
}
if (false == is_track_end(itrack)) { if (false == is_track_end(itrack)) {
continue; continue;
} }
@ -163,6 +185,7 @@ size_t ChanNodeDetails::get_num_ending_tracks() const {
return counter; return counter;
} }
/************************************************************************ /************************************************************************
* Mutators * Mutators
***********************************************************************/ ***********************************************************************/
@ -171,24 +194,42 @@ void ChanNodeDetails::reserve(size_t chan_width) {
track_node_ids_.reserve(chan_width); track_node_ids_.reserve(chan_width);
track_direction_.reserve(chan_width); track_direction_.reserve(chan_width);
seg_length_.reserve(chan_width); seg_length_.reserve(chan_width);
seg_ids_.reserve(chan_width);
track_start_.reserve(chan_width); track_start_.reserve(chan_width);
track_end_.reserve(chan_width); track_end_.reserve(chan_width);
} }
/* Add a track to the channel */ /* Add a track to the channel */
void ChanNodeDetails::add_track(size_t track_node_id, e_direction track_direction, size_t seg_length, size_t is_start, size_t is_end) { void ChanNodeDetails::add_track(size_t track_node_id, e_direction track_direction, size_t seg_id, size_t seg_length, size_t is_start, size_t is_end) {
track_node_ids_.push_back(track_node_id); track_node_ids_.push_back(track_node_id);
track_direction_.push_back(track_direction); track_direction_.push_back(track_direction);
seg_ids_.push_back(seg_id);
seg_length_.push_back(seg_length); seg_length_.push_back(seg_length);
track_start_.push_back(is_start); track_start_.push_back(is_start);
track_end_.push_back(is_end); track_end_.push_back(is_end);
} }
/* Update the node_id of a given track */
void ChanNodeDetails::set_track_node_id(size_t track_index, size_t track_node_id) {
assert(validate_track_id(track_index));
track_node_ids_[track_index] = track_node_id;
}
/* Update the node_ids from a vector */
void ChanNodeDetails::set_track_node_ids(std::vector<size_t> track_node_ids) {
/* the size of vector should match chan_width */
assert ( get_chan_width() == track_node_ids.size() );
for (size_t inode = 0; inode < track_node_ids.size(); ++inode) {
track_node_ids_[inode] = track_node_ids[inode];
}
}
/* Set tracks with a given direction to start */ /* Set tracks with a given direction to start */
void ChanNodeDetails::set_tracks_start(e_direction track_direction) { void ChanNodeDetails::set_tracks_start(e_direction track_direction) {
for (size_t inode = 0; inode < get_chan_width(); ++inode) { for (size_t inode = 0; inode < get_chan_width(); ++inode) {
/* Bypass non-match tracks */ /* Bypass non-match tracks */
if (track_direction != get_track_direction(inode)) { if (track_direction != get_track_direction(inode)) {
continue; /* Pass condition*/
} }
track_start_[inode] = true; track_start_[inode] = true;
} }
@ -199,13 +240,19 @@ void ChanNodeDetails::set_tracks_end(e_direction track_direction) {
for (size_t inode = 0; inode < get_chan_width(); ++inode) { for (size_t inode = 0; inode < get_chan_width(); ++inode) {
/* Bypass non-match tracks */ /* Bypass non-match tracks */
if (track_direction != get_track_direction(inode)) { if (track_direction != get_track_direction(inode)) {
continue; /* Pass condition*/
} }
track_end_[inode] = true; track_end_[inode] = true;
} }
} }
/* rotate the track_node_id by an offset */ /* rotate the track_node_id by an offset */
void ChanNodeDetails::rotate_track_node_id(size_t offset, bool counter_rotate) { void ChanNodeDetails::rotate_track_node_id(size_t offset, e_direction track_direction, bool counter_rotate) {
/* Direct return if offset = 0*/
if (0 == offset) {
return;
}
/* Rotate the node_ids by groups /* Rotate the node_ids by groups
* A group begins from a track_start and ends before another track_start * A group begins from a track_start and ends before another track_start
*/ */
@ -215,15 +262,21 @@ void ChanNodeDetails::rotate_track_node_id(size_t offset, bool counter_rotate) {
if (false == is_track_start(itrack) ) { if (false == is_track_start(itrack) ) {
continue; continue;
} }
/* Bypass segments do not match track_direction */
if (track_direction != get_track_direction(itrack) ) {
continue;
}
/* Find the group nodes */ /* Find the group nodes */
std::vector<size_t> track_group = get_seg_group(itrack); std::vector<size_t> track_group = get_seg_group(itrack);
/* Build a vector of the node ids of the tracks */ /* Build a vector of the node ids of the tracks */
std::vector<size_t> track_group_node_id = get_seg_group_node_id(track_group); std::vector<size_t> track_group_node_id = get_seg_group_node_id(track_group);
/* adapt offset to the range of track_group_node_id */
size_t actual_offset = offset % track_group_node_id.size();
/* Rotate or Counter rotate */ /* Rotate or Counter rotate */
if (true == counter_rotate) { if (true == counter_rotate) {
std::rotate(track_group_node_id.begin(), track_group_node_id.end() - offset, track_group_node_id.end()); std::rotate(track_group_node_id.rbegin(), track_group_node_id.rbegin() + actual_offset, track_group_node_id.rend());
} else { } else {
std::rotate(track_group_node_id.begin(), track_group_node_id.begin() + offset, track_group_node_id.end()); std::rotate(track_group_node_id.begin(), track_group_node_id.begin() + actual_offset, track_group_node_id.end());
} }
/* Update the node_ids */ /* Update the node_ids */
for (size_t inode = 0; inode < track_group.size(); ++inode) { for (size_t inode = 0; inode < track_group.size(); ++inode) {
@ -236,6 +289,7 @@ void ChanNodeDetails::rotate_track_node_id(size_t offset, bool counter_rotate) {
void ChanNodeDetails::clear() { void ChanNodeDetails::clear() {
track_node_ids_.clear(); track_node_ids_.clear();
track_direction_.clear(); track_direction_.clear();
seg_ids_.clear();
seg_length_.clear(); seg_length_.clear();
track_start_.clear(); track_start_.clear();
track_end_.clear(); track_end_.clear();
@ -247,6 +301,7 @@ void ChanNodeDetails::clear() {
bool ChanNodeDetails::validate_chan_width() const { bool ChanNodeDetails::validate_chan_width() const {
size_t chan_width = track_node_ids_.size(); size_t chan_width = track_node_ids_.size();
if ( (chan_width == track_direction_.size()) if ( (chan_width == track_direction_.size())
&&(chan_width == seg_ids_.size())
&&(chan_width == seg_length_.size()) &&(chan_width == seg_length_.size())
&&(chan_width == track_start_.size()) &&(chan_width == track_start_.size())
&&(chan_width == track_end_.size()) ) { &&(chan_width == track_end_.size()) ) {
@ -258,6 +313,7 @@ bool ChanNodeDetails::validate_chan_width() const {
bool ChanNodeDetails::validate_track_id(size_t track_id) const { bool ChanNodeDetails::validate_track_id(size_t track_id) const {
if ( (track_id < track_node_ids_.size()) if ( (track_id < track_node_ids_.size())
&& (track_id < track_direction_.size()) && (track_id < track_direction_.size())
&& (track_id < seg_ids_.size())
&& (track_id < seg_length_.size()) && (track_id < seg_length_.size())
&& (track_id < track_start_.size()) && (track_id < track_start_.size())
&& (track_id < track_end_.size()) ) { && (track_id < track_end_.size()) ) {

View File

@ -75,20 +75,24 @@ class ChanNodeDetails {
public: /* Accessors */ public: /* Accessors */
size_t get_chan_width() const; size_t get_chan_width() const;
size_t get_track_node_id(size_t track_id) const; size_t get_track_node_id(size_t track_id) const;
std::vector<size_t> get_track_node_ids() const;
e_direction get_track_direction(size_t track_id) const; e_direction get_track_direction(size_t track_id) const;
size_t get_track_segment_length(size_t track_id) const; size_t get_track_segment_length(size_t track_id) const;
size_t get_track_segment_id(size_t track_id) const;
bool is_track_start(size_t track_id) const; bool is_track_start(size_t track_id) const;
bool is_track_end(size_t track_id) const; bool is_track_end(size_t track_id) const;
std::vector<size_t> get_seg_group(size_t track_id) const; std::vector<size_t> get_seg_group(size_t track_id) const;
std::vector<size_t> get_seg_group_node_id(std::vector<size_t> seg_group) const; std::vector<size_t> get_seg_group_node_id(std::vector<size_t> seg_group) const;
size_t get_num_starting_tracks() const; size_t get_num_starting_tracks(enum e_direction track_direction) const;
size_t get_num_ending_tracks() const; size_t get_num_ending_tracks(enum e_direction track_direction) const;
public: /* Mutators */ public: /* Mutators */
void reserve(size_t chan_width); /* Reserve the capacitcy of vectors */ void reserve(size_t chan_width); /* Reserve the capacitcy of vectors */
void add_track(size_t track_node_id, e_direction track_direction, size_t seg_length, size_t is_start, size_t is_end); void add_track(size_t track_node_id, e_direction track_direction, size_t seg_id, size_t seg_length, size_t is_start, size_t is_end);
void set_track_node_id(size_t track_index, size_t track_node_id);
void set_track_node_ids(std::vector<size_t> track_node_ids);
void set_tracks_start(e_direction track_direction); void set_tracks_start(e_direction track_direction);
void set_tracks_end(e_direction track_direction); void set_tracks_end(e_direction track_direction);
void rotate_track_node_id(size_t offset, bool counter_rotate); /* rotate the track_node_id by an offset */ void rotate_track_node_id(size_t offset, e_direction track_direction, bool counter_rotate); /* rotate the track_node_id by an offset */
void clear(); void clear();
private: /* validators */ private: /* validators */
bool validate_chan_width() const; bool validate_chan_width() const;
@ -96,6 +100,7 @@ class ChanNodeDetails {
private: /* Internal data */ private: /* Internal data */
std::vector<size_t> track_node_ids_; /* indices of each track */ std::vector<size_t> track_node_ids_; /* indices of each track */
std::vector<e_direction> track_direction_; /* direction of each track */ std::vector<e_direction> track_direction_; /* direction of each track */
std::vector<size_t> seg_ids_; /* id of segment of each track */
std::vector<size_t> seg_length_; /* Length of each segment */ std::vector<size_t> seg_length_; /* Length of each segment */
std::vector<bool> track_start_; /* flag to identify if this is the starting point of the track */ std::vector<bool> track_start_; /* flag to identify if this is the starting point of the track */
std::vector<bool> track_end_; /* flag to identify if this is the ending point of the track */ std::vector<bool> track_end_; /* flag to identify if this is the ending point of the track */

View File

@ -23,7 +23,7 @@
***********************************************************************/ ***********************************************************************/
/************************************************************************ /************************************************************************
* Filename: rr_graph_gsb.c * Filename: rr_graph_gsb.cpp
* Created by: Xifan Tang * Created by: Xifan Tang
* Change history: * Change history:
* +-------------------------------------+ * +-------------------------------------+

View File

@ -42,11 +42,11 @@
* 2. A Y-direction Connection block locates at the top side of the switch block * 2. A Y-direction Connection block locates at the top side of the switch block
* *
* +---------------------------------+ * +---------------------------------+
* | Y-direction CB | * IPIN_NODES | Y-direction CB | IPIN_NODES
* | [x][y + 1] | * | [x][y + 1] |
* +---------------------------------+ * +---------------------------------+
* *
* TOP SIDE * IPIN_NODES TOP SIDE
* +-------------+ +---------------------------------+ * +-------------+ +---------------------------------+
* | | | OPIN_NODE CHAN_NODES OPIN_NODES | * | | | OPIN_NODE CHAN_NODES OPIN_NODES |
* | | | | * | | | |
@ -61,7 +61,7 @@
* | | | | * | | | |
* | | | OPIN_NODE CHAN_NODES OPIN_NODES | * | | | OPIN_NODE CHAN_NODES OPIN_NODES |
* +-------------+ +---------------------------------+ * +-------------+ +---------------------------------+
* BOTTOM SIDE * IPIN_NODES BOTTOM SIDE
* *
***********************************************************************/ ***********************************************************************/
@ -92,6 +92,7 @@
/* Define open nodes */ /* Define open nodes */
#define OPEN_NODE_ID RRNodeId(-1) #define OPEN_NODE_ID RRNodeId(-1)
#define OPEN_EDGE_ID RREdgeId(-1) #define OPEN_EDGE_ID RREdgeId(-1)
#define OPEN_SEGMENT_ID RRSegmentId(-1)
/*********************************************************************** /***********************************************************************
* This data structure focuses on modeling the internal pin-to-pin connections. * This data structure focuses on modeling the internal pin-to-pin connections.
@ -142,6 +143,9 @@ class GSBGraph {
/* Aggregates */ /* Aggregates */
node_range nodes() const; node_range nodes() const;
edge_range edges() const; edge_range edges() const;
public: /* Coordinator generation */
public: /* Accessors */
public: /* Mutators */
private: /* Internal Data */ private: /* Internal Data */
/* Coordinator of this GSB */ /* Coordinator of this GSB */
DeviceCoordinator coordinator_; DeviceCoordinator coordinator_;
@ -152,6 +156,7 @@ class GSBGraph {
vtr::vector<RRNodeId, enum e_side> node_sides_; vtr::vector<RRNodeId, enum e_side> node_sides_;
vtr::vector<RRNodeId, enum e_direction> node_directions_; vtr::vector<RRNodeId, enum e_direction> node_directions_;
vtr::vector<RRNodeId, enum e_side> node_grid_sides_; vtr::vector<RRNodeId, enum e_side> node_grid_sides_;
vtr::vector<RRNodeId, RRSegmentId> node_segment_ids_;
vtr::vector<RRNodeId, std::vector<RREdgeId>> node_in_edges; vtr::vector<RRNodeId, std::vector<RREdgeId>> node_in_edges;
vtr::vector<RRNodeId, std::vector<RREdgeId>> node_out_edges; vtr::vector<RRNodeId, std::vector<RREdgeId>> node_out_edges;
@ -160,6 +165,10 @@ class GSBGraph {
vtr::vector<RREdgeId, RREdgeId> edge_ids_; vtr::vector<RREdgeId, RREdgeId> edge_ids_;
vtr::vector<RREdgeId, RREdgeId> edge_src_nodes_; /* each element is a node_id */ vtr::vector<RREdgeId, RREdgeId> edge_src_nodes_; /* each element is a node_id */
vtr::vector<RREdgeId, RREdgeId> edge_sink_nodes_; /* each element is a node_id */ vtr::vector<RREdgeId, RREdgeId> edge_sink_nodes_; /* each element is a node_id */
/* fast look-up [node_side][node_type][node_id] */
typedef std::vector< std::vector< std::vector<RRNodeId> > > NodeLookup;
mutable NodeLookup node_lookup_;
}; };
#endif #endif

View File

@ -0,0 +1,409 @@
/**********************************************************
* MIT License
*
* Copyright (c) 2018 LNIS - The University of Utah
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***********************************************************************/
/************************************************************************
* Filename: rr_graph_builder_utils.cpp
* Created by: Xifan Tang
* Change history:
* +-------------------------------------+
* | Date | Author | Notes
* +-------------------------------------+
* | 2019/06/23 | Xifan Tang | Created
* +-------------------------------------+
***********************************************************************/
/************************************************************************
* This file contains most utilized functions for rr_graph builders
***********************************************************************/
#include <cstdlib>
#include <cassert>
#include <vector>
#include <algorithm>
#include "rr_graph_builder_utils.h"
#include "globals.h"
/************************************************************************
* Initialize a rr_node
************************************************************************/
void tileable_rr_graph_init_rr_node(t_rr_node* cur_rr_node) {
cur_rr_node->xlow = 0;
cur_rr_node->xhigh = 0;
cur_rr_node->ylow = 0;
cur_rr_node->xhigh = 0;
cur_rr_node->ptc_num = 0;
cur_rr_node->track_ids.clear();
cur_rr_node->cost_index = 0;
cur_rr_node->occ = 0;
cur_rr_node->fan_in = 0;
cur_rr_node->num_edges = 0;
cur_rr_node->type = NUM_RR_TYPES;
cur_rr_node->edges = NULL;
cur_rr_node->switches = NULL;
cur_rr_node->driver_switch = 0;
cur_rr_node->unbuf_switched = 0;
cur_rr_node->buffered = 0;
cur_rr_node->R = 0.;
cur_rr_node->C = 0.;
cur_rr_node->direction = BI_DIRECTION; /* Give an invalid value, easy to check errors */
cur_rr_node->drivers = SINGLE;
cur_rr_node->num_wire_drivers = 0;
cur_rr_node->num_opin_drivers = 0;
cur_rr_node->num_drive_rr_nodes = 0;
cur_rr_node->drive_rr_nodes = NULL;
cur_rr_node->drive_switches = NULL;
cur_rr_node->vpack_net_num_changed = FALSE;
cur_rr_node->is_parasitic_net = FALSE;
cur_rr_node->is_in_heap = FALSE;
cur_rr_node->sb_num_drive_rr_nodes = 0;
cur_rr_node->sb_drive_rr_nodes = NULL;
cur_rr_node->sb_drive_switches = NULL;
cur_rr_node->pb = NULL;
cur_rr_node->name_mux = NULL;
cur_rr_node->id_path = -1;
cur_rr_node->prev_node = -1;
cur_rr_node->prev_edge = -1;
cur_rr_node->net_num = -1;
cur_rr_node->vpack_net_num = -1;
cur_rr_node->prev_node_in_pack = -1;
cur_rr_node->prev_edge_in_pack = -1;
cur_rr_node->net_num_in_pack = -1;
cur_rr_node->pb_graph_pin = NULL;
cur_rr_node->tnode = NULL;
cur_rr_node->pack_intrinsic_cost = 0.;
cur_rr_node->z = 0;
return;
}
/************************************************************************
* Get the class index of a grid pin
***********************************************************************/
int get_grid_pin_class_index(const t_grid_tile& cur_grid,
const int pin_index) {
/* check */
assert ( pin_index < cur_grid.type->num_pins);
return cur_grid.type->pin_class[pin_index];
}
/* Deteremine the side of a io grid */
enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size,
const DeviceCoordinator& grid_coordinator) {
/* TOP side IO of FPGA */
if (device_size.get_y() == grid_coordinator.get_y()) {
return BOTTOM; /* Such I/O has only Bottom side pins */
} else if (device_size.get_x() == grid_coordinator.get_x()) { /* RIGHT side IO of FPGA */
return LEFT; /* Such I/O has only Left side pins */
} else if (0 == grid_coordinator.get_y()) { /* BOTTOM side IO of FPGA */
return TOP; /* Such I/O has only Top side pins */
} else if (0 == grid_coordinator.get_x()) { /* LEFT side IO of FPGA */
return RIGHT; /* Such I/O has only Right side pins */
} else {
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d]) I/O Grid is in the center part of FPGA! Currently unsupported!\n",
__FILE__, __LINE__);
exit(1);
}
}
/************************************************************************
* Get a list of pin_index for a grid (either OPIN or IPIN)
* For IO_TYPE, only one side will be used, we consider one side of pins
* For others, we consider all the sides
***********************************************************************/
std::vector<int> get_grid_side_pins(const t_grid_tile& cur_grid,
const enum e_pin_type pin_type,
const enum e_side pin_side,
const int pin_height) {
std::vector<int> pin_list;
/* Make sure a clear start */
pin_list.clear();
for (int ipin = 0; ipin < cur_grid.type->num_pins; ++ipin) {
int class_id = cur_grid.type->pin_class[ipin];
if ( (1 == cur_grid.type->pinloc[pin_height][pin_side][ipin])
&& (pin_type == cur_grid.type->class_inf[class_id].type) ) {
pin_list.push_back(ipin);
}
}
return pin_list;
}
/************************************************************************
* Get the number of pins for a grid (either OPIN or IPIN)
* For IO_TYPE, only one side will be used, we consider one side of pins
* For others, we consider all the sides
***********************************************************************/
size_t get_grid_num_pins(const t_grid_tile& cur_grid,
const enum e_pin_type pin_type,
const enum e_side io_side) {
size_t num_pins = 0;
Side io_side_manager(io_side);
/* For IO_TYPE sides */
for (size_t side = 0; side < NUM_SIDES; ++side) {
Side side_manager(side);
/* skip unwanted sides */
if ( (IO_TYPE == cur_grid.type)
&& (side != io_side_manager.to_size_t()) ) {
continue;
}
/* Get pin list */
for (int height = 0; height < cur_grid.type->height; ++height) {
std::vector<int> pin_list = get_grid_side_pins(cur_grid, pin_type, side_manager.get_side(), height);
num_pins += pin_list.size();
}
}
return num_pins;
}
/************************************************************************
* Get the number of pins for a grid (either OPIN or IPIN)
* For IO_TYPE, only one side will be used, we consider one side of pins
* For others, we consider all the sides
***********************************************************************/
size_t get_grid_num_classes(const t_grid_tile& cur_grid,
const enum e_pin_type pin_type) {
size_t num_classes = 0;
for (int iclass = 0; iclass < cur_grid.type->num_class; ++iclass) {
/* Bypass unmatched pin_type */
if (pin_type != cur_grid.type->class_inf[iclass].type) {
continue;
}
num_classes++;
}
return num_classes;
}
/************************************************************************
* Add a edge connecting two rr_nodes
* For src rr_node, update the edge list and update switch_id,
* For des rr_node, update the fan_in
***********************************************************************/
void add_one_edge_for_two_rr_nodes(const t_rr_graph* rr_graph,
const int src_rr_node_id,
const int des_rr_node_id,
const short switch_id) {
/* Check */
assert ( (-1 < src_rr_node_id) && (src_rr_node_id < rr_graph->num_rr_nodes) );
assert ( (-1 < des_rr_node_id) && (des_rr_node_id < rr_graph->num_rr_nodes) );
t_rr_node* src_rr_node = &(rr_graph->rr_node[src_rr_node_id]);
t_rr_node* des_rr_node = &(rr_graph->rr_node[des_rr_node_id]);
/* Allocate edge and switch to src_rr_node */
src_rr_node->num_edges++;
if (NULL == src_rr_node->edges) {
/* calloc */
src_rr_node->edges = (int*) my_calloc( src_rr_node->num_edges, sizeof(int) );
src_rr_node->switches = (short*) my_calloc( src_rr_node->num_edges, sizeof(short) );
} else {
/* realloc */
src_rr_node->edges = (int*) my_realloc(src_rr_node->edges,
src_rr_node->num_edges * sizeof(int));
src_rr_node->switches = (short*) my_realloc(src_rr_node->switches,
src_rr_node->num_edges * sizeof(short));
}
/* Fill edge and switch info */
src_rr_node->edges[src_rr_node->num_edges - 1] = des_rr_node_id;
src_rr_node->switches[src_rr_node->num_edges - 1] = switch_id;
/* Update the des_rr_node */
des_rr_node->fan_in++;
return;
}
/************************************************************************
* Add a set of edges for a source rr_node
* For src rr_node, update the edge list and update switch_id,
* For des rr_node, update the fan_in
***********************************************************************/
void add_edges_for_two_rr_nodes(const t_rr_graph* rr_graph,
const int src_rr_node_id,
const std::vector<int> des_rr_node_ids,
const std::vector<short> driver_switches) {
/* Check src_rr_node id is in range */
assert ( (-1 < src_rr_node_id) && (src_rr_node_id < rr_graph->num_rr_nodes) );
t_rr_node* src_rr_node = &(rr_graph->rr_node[src_rr_node_id]);
/* Check des_rr_node and driver_switches should match in size */
assert ( des_rr_node_ids.size() == driver_switches.size() );
/* Get a stamp of the current num_edges of src_rr_node */
int start_edge_id = src_rr_node->num_edges;
/* To avoid adding redundant edges,
* we will search the edge list and
* check if each des_rr_node_id already exists
* We rebuild a vector des_rr_node_ids_to_add where redundancy is removed
*/
std::vector<int> des_rr_node_ids_to_add;
std::vector<short> driver_switches_to_add;
for (size_t inode = 0; inode < des_rr_node_ids.size(); ++inode) {
/* search */
bool is_redundant = false;
for (int iedge = 0; iedge < src_rr_node->num_edges; ++iedge) {
if (des_rr_node_ids[inode] == src_rr_node->edges[iedge]) {
is_redundant = true;
break;
}
}
/* add or skip */
if (true == is_redundant) {
continue; /* go to the next */
}
assert (false == is_redundant);
/* add to the list */
des_rr_node_ids_to_add.push_back(des_rr_node_ids[inode]);
driver_switches_to_add.push_back(driver_switches[inode]);
}
/* Allocate edge and switch to src_rr_node */
src_rr_node->num_edges += des_rr_node_ids_to_add.size();
if (NULL == src_rr_node->edges) {
/* calloc */
src_rr_node->edges = (int*) my_calloc( src_rr_node->num_edges, sizeof(int) );
src_rr_node->switches = (short*) my_calloc( src_rr_node->num_edges, sizeof(short) );
} else {
/* realloc */
src_rr_node->edges = (int*) my_realloc(src_rr_node->edges,
src_rr_node->num_edges * sizeof(int));
src_rr_node->switches = (short*) my_realloc(src_rr_node->switches,
src_rr_node->num_edges * sizeof(short));
}
for (size_t inode = 0; inode < des_rr_node_ids_to_add.size(); ++inode) {
/* Check des_rr_node id is in range */
int des_rr_node_id = des_rr_node_ids_to_add[inode];
assert ( (-1 < des_rr_node_id) && (des_rr_node_id < rr_graph->num_rr_nodes) );
t_rr_node* des_rr_node = &(rr_graph->rr_node[des_rr_node_id]);
/* Fill edge and switch info */
src_rr_node->edges[start_edge_id] = des_rr_node_id;
src_rr_node->switches[start_edge_id] = driver_switches_to_add[inode];
/* Update the des_rr_node */
des_rr_node->fan_in++;
/* Increment the start_edge_id */
start_edge_id++;
}
/* Check */
assert( start_edge_id == src_rr_node->num_edges );
return;
}
/************************************************************************
* Get the coordinator of a starting point of a routing track
* For routing tracks in INC_DIRECTION
* (xlow, ylow) should be the starting point
*
* For routing tracks in DEC_DIRECTION
* (xhigh, yhigh) should be the starting point
***********************************************************************/
DeviceCoordinator get_track_rr_node_start_coordinator(const t_rr_node* track_rr_node) {
/* Make sure we have CHANX or CHANY */
assert ( (CHANX == track_rr_node->type) ||(CHANY == track_rr_node->type) );
DeviceCoordinator start_coordinator;
if (INC_DIRECTION == track_rr_node->direction) {
start_coordinator.set(track_rr_node->xlow, track_rr_node->ylow);
} else {
assert (DEC_DIRECTION == track_rr_node->direction);
start_coordinator.set(track_rr_node->xhigh, track_rr_node->yhigh);
}
return start_coordinator;
}
/************************************************************************
* Get the coordinator of a end point of a routing track
* For routing tracks in INC_DIRECTION
* (xhigh, yhigh) should be the starting point
*
* For routing tracks in DEC_DIRECTION
* (xlow, ylow) should be the starting point
***********************************************************************/
DeviceCoordinator get_track_rr_node_end_coordinator(const t_rr_node* track_rr_node) {
/* Make sure we have CHANX or CHANY */
assert ( (CHANX == track_rr_node->type) ||(CHANY == track_rr_node->type) );
DeviceCoordinator end_coordinator;
if (INC_DIRECTION == track_rr_node->direction) {
end_coordinator.set(track_rr_node->xhigh, track_rr_node->yhigh);
} else {
assert (DEC_DIRECTION == track_rr_node->direction);
end_coordinator.set(track_rr_node->xlow, track_rr_node->ylow);
}
return end_coordinator;
}
/************************************************************************
* Get the ptc of a routing track in the channel where it ends
* For routing tracks in INC_DIRECTION
* the ptc is the last of track_ids
*
* For routing tracks in DEC_DIRECTION
* the ptc is the first of track_ids
***********************************************************************/
short get_track_rr_node_end_track_id(const t_rr_node* track_rr_node) {
/* Make sure we have CHANX or CHANY */
assert ( (CHANX == track_rr_node->type) ||(CHANY == track_rr_node->type) );
if (INC_DIRECTION == track_rr_node->direction) {
return track_rr_node->track_ids.back();
}
assert (DEC_DIRECTION == track_rr_node->direction);
return track_rr_node->track_ids.front();
}

View File

@ -0,0 +1,45 @@
#ifndef RR_GRAPH_BUILDER_UTILS_H
#define RR_GRAPH_BUILDER_UTILS_H
#include "vpr_types.h"
#include "fpga_x2p_types.h"
#include "device_coordinator.h"
void tileable_rr_graph_init_rr_node(t_rr_node* cur_rr_node);
int get_grid_pin_class_index(const t_grid_tile& cur_grid,
const int pin_index);
enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size,
const DeviceCoordinator& grid_coordinator);
std::vector<int> get_grid_side_pins(const t_grid_tile& cur_grid,
const enum e_pin_type pin_type,
const enum e_side pin_side,
const int pin_height);
size_t get_grid_num_pins(const t_grid_tile& cur_grid,
const enum e_pin_type pin_type,
const enum e_side io_side);
size_t get_grid_num_classes(const t_grid_tile& cur_grid,
const enum e_pin_type pin_type);
void add_one_edge_for_two_rr_nodes(const t_rr_graph* rr_graph,
const int src_rr_node_id,
const int des_rr_node_id,
const short switch_id);
void add_edges_for_two_rr_nodes(const t_rr_graph* rr_graph,
const int src_rr_node_id,
const std::vector<int> des_rr_node,
const std::vector<short> driver_switches);
DeviceCoordinator get_track_rr_node_start_coordinator(const t_rr_node* track_rr_node);
DeviceCoordinator get_track_rr_node_end_coordinator(const t_rr_node* track_rr_node);
short get_track_rr_node_end_track_id(const t_rr_node* track_rr_node);
#endif

View File

@ -1,616 +0,0 @@
/**********************************************************
* MIT License
*
* Copyright (c) 2018 LNIS - The University of Utah
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***********************************************************************/
/************************************************************************
* Filename: rr_graph_tileable_builder.c
* Created by: Xifan Tang
* Change history:
* +-------------------------------------+
* | Date | Author | Notes
* +-------------------------------------+
* | 2019/06/11 | Xifan Tang | Created
* +-------------------------------------+
***********************************************************************/
/************************************************************************
* This file contains a builder for the complex rr_graph data structure
* Different from VPR rr_graph builders, this builder aims to create a
* highly regular rr_graph, where each Connection Block (CB), Switch
* Block (SB) is the same (except for those on the borders). Thus, the
* rr_graph is called tileable, which brings significant advantage in
* producing large FPGA fabrics.
***********************************************************************/
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <vector>
#include "vpr_types.h"
#include "globals.h"
#include "vpr_utils.h"
#include "rr_graph_util.h"
#include "rr_graph.h"
#include "rr_graph2.h"
#include "route_common.h"
#include "fpga_x2p_types.h"
#include "rr_graph_tileable_builder.h"
#include "chan_node_details.h"
#include "device_coordinator.h"
/************************************************************************
* Local function in the file
***********************************************************************/
/************************************************************************
* Generate the number of tracks for each types of routing segments
* w.r.t. the frequency of each of segments and channel width
* Note that if we dertermine the number of tracks per type using
* chan_width * segment_frequency / total_freq may cause
* The total track num may not match the chan_width,
* therefore, we assign tracks one by one until we meet the frequency requirement
* In this way, we can assign the number of tracks with repect to frequency
***********************************************************************/
static
std::vector<size_t> get_num_tracks_per_seg_type(size_t chan_width,
std::vector<t_segment_inf> segment_inf,
bool use_full_seg_groups) {
std::vector<size_t> result;
std::vector<double> demand;
/* Make sure a clean start */
result.resize(segment_inf.size());
demand.resize(segment_inf.size());
/* Scale factor so we can divide by any length
* and still use integers */
/* Get the sum of frequency */
size_t scale = 1;
size_t freq_sum = 0;
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
scale *= segment_inf[iseg].length;
freq_sum += segment_inf[iseg].frequency;
}
size_t reduce = scale * freq_sum;
/* Init assignments to 0 and set the demand values */
/* Get the fraction of each segment type considering the frequency:
* num_track_per_seg = chan_width * (freq_of_seg / sum_freq)
*/
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
result[iseg] = 0;
demand[iseg] = scale * chan_width * segment_inf[iseg].frequency;
if (true == use_full_seg_groups) {
demand[iseg] /= segment_inf[iseg].length;
}
}
/* check if the sum of num_tracks, matches the chan_width */
/* Keep assigning tracks until we use them up */
size_t assigned = 0;
size_t size = 0;
size_t imax = 0;
while (assigned < chan_width) {
/* Find current maximum demand */
double max = 0;
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
if (demand[iseg] > max) {
imax = iseg;
}
max = std::max(demand[iseg], max);
}
/* Assign tracks to the type and reduce the types demand */
size = (use_full_seg_groups ? segment_inf[imax].length : 1);
demand[imax] -= reduce;
result[imax] += size;
assigned += size;
}
/* Undo last assignment if we were closer to goal without it */
if ((assigned - chan_width) > (size / 2)) {
result[imax] -= size;
}
return result;
}
/************************************************************************
* Build details of routing tracks in a channel
* The function will
* 1. Assign the segments for each routing channel,
* To be specific, for each routing track, we assign a routing segment.
* The assignment is subject to users' specifications, such as
* a. length of each type of segment
* b. frequency of each type of segment.
* c. routing channel width
*
* 2. The starting point of each segment in the channel will be assigned
* For each segment group with same directionality (tracks have the same length),
* every L track will be a starting point (where L denotes the length of segments)
* In this case, if the number of tracks is not a multiple of L,
* indeed we may have some <L segments. This can be considered as a side effect.
* But still the rr_graph is tileable, which is the first concern!
*
* Here is a quick example of Length-4 wires in a W=12 routing channel
* +---------------------------------+
* | Index | Direction | Start Point |
* +---------------------------------+
* | 0 | --------> | Yes |
* +---------------------------------+
* | 1 | <-------- | Yes |
* +---------------------------------+
* | 2 | --------> | No |
* +---------------------------------+
* | 3 | <-------- | No |
* +---------------------------------+
* | 4 | --------> | No |
* +---------------------------------+
* | 5 | <-------- | No |
* +---------------------------------+
* | 7 | --------> | No |
* +---------------------------------+
* | 8 | <-------- | No |
* +---------------------------------+
* | 9 | --------> | Yes |
* +---------------------------------+
* | 10 | <-------- | Yes |
* +---------------------------------+
* | 11 | --------> | No |
* +---------------------------------+
* | 12 | <-------- | No |
* +---------------------------------+
*
* 3. SPECIAL for fringes: TOP|RIGHT|BOTTOM|RIGHT
* if device_side is NUM_SIDES, we assume this channel does not locate on borders
* All segments will start and ends with no exception
*
* 4. IMPORTANT: we should be aware that channel width maybe different
* in X-direction and Y-direction channels!!!
* So we will load segment details for different channels
***********************************************************************/
static
ChanNodeDetails build_unidir_chan_node_details(size_t chan_width, size_t max_seg_length,
enum e_side device_side,
std::vector<t_segment_inf> segment_inf) {
ChanNodeDetails chan_node_details;
/* Correct the chan_width: it should be an even number */
if (0 != chan_width % 2) {
chan_width++; /* increment it to be even */
}
assert (0 == chan_width % 2);
/* Reserve channel width */
chan_node_details.reserve(chan_width);
/* Return if zero width is forced */
if (0 == chan_width) {
return chan_node_details;
}
/* Find the number of segments required by each group */
std::vector<size_t> num_tracks = get_num_tracks_per_seg_type(chan_width/2, segment_inf, TRUE);
/* Add node to ChanNodeDetails */
size_t cur_track = 0;
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
/* segment length will be set to maxium segment length if this is a longwire */
size_t seg_len = segment_inf[iseg].length;
if (TRUE == segment_inf[iseg].longline) {
seg_len = max_seg_length;
}
for (size_t itrack = 0; itrack < num_tracks[iseg]; ++itrack) {
bool seg_start = false;
/* Every length of wire, we set a starting point */
if (0 == itrack % seg_len) {
seg_start = true;
}
/* Since this is a unidirectional routing architecture,
* Add a pair of tracks, 1 INC_DIRECTION track and 1 DEC_DIRECTION track
*/
chan_node_details.add_track(cur_track, INC_DIRECTION, seg_len, seg_start, false);
cur_track++;
chan_node_details.add_track(cur_track, DEC_DIRECTION, seg_len, seg_start, false);
cur_track++;
}
}
/* Check if all the tracks have been satisified */
assert (cur_track == chan_width);
/* If this is on the border of a device, segments should start */
switch (device_side) {
case TOP:
case RIGHT:
/* INC_DIRECTION should all end */
chan_node_details.set_tracks_end(INC_DIRECTION);
/* DEC_DIRECTION should all start */
chan_node_details.set_tracks_start(DEC_DIRECTION);
break;
case BOTTOM:
case LEFT:
/* INC_DIRECTION should all start */
chan_node_details.set_tracks_start(INC_DIRECTION);
/* DEC_DIRECTION should all end */
chan_node_details.set_tracks_end(DEC_DIRECTION);
break;
case NUM_SIDES:
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d]) Invalid device_side!\n",
__FILE__, __LINE__);
exit(1);
}
return chan_node_details;
}
/* Deteremine the side of a io grid */
static
enum e_side determine_io_grid_pin_side(const DeviceCoordinator& device_size,
const DeviceCoordinator& grid_coordinator) {
/* TOP side IO of FPGA */
if (device_size.get_y() == grid_coordinator.get_y()) {
return BOTTOM; /* Such I/O has only Bottom side pins */
} else if (device_size.get_x() == grid_coordinator.get_x()) { /* RIGHT side IO of FPGA */
return LEFT; /* Such I/O has only Left side pins */
} else if (0 == grid_coordinator.get_y()) { /* BOTTOM side IO of FPGA */
return TOP; /* Such I/O has only Top side pins */
} else if (0 == grid_coordinator.get_x()) { /* LEFT side IO of FPGA */
return RIGHT; /* Such I/O has only Right side pins */
} else {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])I/O Grid is in the center part of FPGA! Currently unsupported!\n",
__FILE__, __LINE__);
exit(1);
}
}
/************************************************************************
* Get a list of pin_index for a grid (either OPIN or IPIN)
* For IO_TYPE, only one side will be used, we consider one side of pins
* For others, we consider all the sides
***********************************************************************/
static
std::vector<int> get_grid_side_pins(const t_grid_tile& cur_grid, enum e_pin_type pin_type, enum e_side pin_side, int pin_height) {
std::vector<int> pin_list;
/* Make sure a clear start */
pin_list.clear();
for (int ipin = 0; ipin < cur_grid.type->num_pins; ++ipin) {
if ( (1 == cur_grid.type->pinloc[pin_height][pin_side][ipin])
&& (pin_type == cur_grid.type->pin_class[ipin]) ) {
pin_list.push_back(ipin);
}
}
return pin_list;
}
/************************************************************************
* Get the number of pins for a grid (either OPIN or IPIN)
* For IO_TYPE, only one side will be used, we consider one side of pins
* For others, we consider all the sides
***********************************************************************/
static
size_t get_grid_num_pins(const t_grid_tile& cur_grid, enum e_pin_type pin_type, enum e_side io_side) {
size_t num_pins = 0;
Side io_side_manager(io_side);
/* For IO_TYPE sides */
for (size_t side = 0; side < NUM_SIDES; ++side) {
Side side_manager(side);
/* skip unwanted sides */
if ( (IO_TYPE == cur_grid.type)
&& (side != io_side_manager.to_size_t()) ) {
continue;
}
/* Get pin list */
for (int height = 0; height < cur_grid.type->height; ++height) {
std::vector<int> pin_list = get_grid_side_pins(cur_grid, pin_type, side_manager.get_side(), height);
num_pins += pin_list.size();
}
}
return num_pins;
}
/************************************************************************
* Estimate the number of rr_nodes per category:
* CHANX, CHANY, IPIN, OPIN, SOURCE, SINK
***********************************************************************/
static
std::vector<size_t> estimate_num_rr_nodes_per_type(const DeviceCoordinator& device_size,
std::vector<std::vector<t_grid_tile>> grids,
std::vector<size_t> chan_width,
std::vector<t_segment_inf> segment_infs) {
std::vector<size_t> num_rr_nodes_per_type;
/* reserve the vector:
* we have the follow type:
* SOURCE = 0, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE, NUM_RR_TYPES
* NUM_RR_TYPES and INTRA_CLUSTER_EDGE will be 0
*/
num_rr_nodes_per_type.resize(NUM_RR_TYPES);
/* Make sure a clean start */
for (size_t i = 0; i < NUM_RR_TYPES; ++i) {
num_rr_nodes_per_type[i] = 0;
}
/************************************************************************
* 1. Search the grid and find the number OPINs and IPINs per grid
* Note that the number of SOURCE nodes are the same as OPINs
* and the number of SINK nodes are the same as IPINs
***********************************************************************/
for (size_t ix = 0; ix < grids.size(); ++ix) {
for (size_t iy = 0; iy < grids[ix].size(); ++iy) {
/* Skip EMPTY tiles */
if (EMPTY_TYPE == grids[ix][iy].type) {
continue;
}
/* Skip height>1 tiles (mostly heterogeneous blocks) */
if (0 < grids[ix][iy].offset) {
continue;
}
enum e_side io_side = NUM_SIDES;
/* If this is the block on borders, we consider IO side */
if (IO_TYPE == grid[ix][iy].type) {
DeviceCoordinator io_device_size(device_size.get_x() - 1, device_size.get_y() - 1);
DeviceCoordinator grid_coordinator(ix, iy);
io_side = determine_io_grid_pin_side(device_size, grid_coordinator);
}
/* get the number of OPINs */
num_rr_nodes_per_type[OPIN] += get_grid_num_pins(grids[ix][iy], DRIVER, io_side);
/* get the number of IPINs */
num_rr_nodes_per_type[IPIN] += get_grid_num_pins(grids[ix][iy], RECEIVER, io_side);
}
}
/* SOURCE and SINK */
num_rr_nodes_per_type[SOURCE] = num_rr_nodes_per_type[OPIN];
num_rr_nodes_per_type[SINK] = num_rr_nodes_per_type[IPIN];
/************************************************************************
* 2. Assign the segments for each routing channel,
* To be specific, for each routing track, we assign a routing segment.
* The assignment is subject to users' specifications, such as
* a. length of each type of segment
* b. frequency of each type of segment.
* c. routing channel width
*
* SPECIAL for fringes:
* All segments will start and ends with no exception
*
* IMPORTANT: we should be aware that channel width maybe different
* in X-direction and Y-direction channels!!!
* So we will load segment details for different channels
***********************************************************************/
/* For X-direction Channel */
/* For LEFT side of FPGA */
ChanNodeDetails left_chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, LEFT, segment_infs);
for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) {
num_rr_nodes_per_type[CHANX] += left_chanx_details.get_num_starting_tracks();
}
/* For RIGHT side of FPGA */
ChanNodeDetails right_chanx_details = build_unidir_chan_node_details(chan_width[0], device_size.get_x() - 2, RIGHT, segment_infs);
for (size_t iy = 0; iy < device_size.get_y() - 1; ++iy) {
num_rr_nodes_per_type[CHANX] += right_chanx_details.get_num_starting_tracks();
}
/* For core of FPGA */
ChanNodeDetails core_chanx_details = build_unidir_chan_node_details(chan_width[1], device_size.get_x() - 2, NUM_SIDES, segment_infs);
for (size_t ix = 1; ix < grids.size() - 2; ++ix) {
for (size_t iy = 1; iy < grids[ix].size() - 2; ++iy) {
num_rr_nodes_per_type[CHANX] += core_chanx_details.get_num_starting_tracks();
}
}
/* For Y-direction Channel */
/* For TOP side of FPGA */
ChanNodeDetails top_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, TOP, segment_infs);
for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) {
num_rr_nodes_per_type[CHANY] += top_chany_details.get_num_starting_tracks();
}
/* For BOTTOM side of FPGA */
ChanNodeDetails bottom_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, BOTTOM, segment_infs);
for (size_t ix = 0; ix < device_size.get_x() - 1; ++ix) {
num_rr_nodes_per_type[CHANY] += bottom_chany_details.get_num_starting_tracks();
}
/* For core of FPGA */
ChanNodeDetails core_chany_details = build_unidir_chan_node_details(chan_width[1], device_size.get_y() - 2, NUM_SIDES, segment_infs);
for (size_t ix = 1; ix < grids.size() - 2; ++ix) {
for (size_t iy = 1; iy < grids[ix].size() - 2; ++iy) {
num_rr_nodes_per_type[CHANY] += core_chany_details.get_num_starting_tracks();
}
}
return num_rr_nodes_per_type;
}
/************************************************************************
* Main function of this file
* Builder for a detailed uni-directional tileable rr_graph
* Global graph is not supported here, the VPR rr_graph generator can be used
* It follows the procedures to complete the rr_graph generation
* 1. Assign the segments for each routing channel,
* To be specific, for each routing track, we assign a routing segment.
* The assignment is subject to users' specifications, such as
* a. length of each type of segment
* b. frequency of each type of segment.
* c. routing channel width
* 2. Estimate the number of nodes in the rr_graph
* This will estimate the number of
* a. IPINs, input pins of each grid
* b. OPINs, output pins of each grid
* c. SOURCE, virtual node which drives OPINs
* d. SINK, virtual node which is connected to IPINs
* e. CHANX and CHANY, routing segments of each channel
* 3. Create the connectivity of OPINs
* a. Evenly assign connections to OPINs to routing tracks
* b. the connection pattern should be same across the fabric
* 4. Create the connectivity of IPINs
* a. Evenly assign connections from routing tracks to IPINs
* b. the connection pattern should be same across the fabric
* 5. Create the switch block patterns,
* It is based on the type of switch block, the supported patterns are
* a. Disjoint, which connects routing track (i)th from (i)th and (i)th routing segments
* b. Universal, which connects routing track (i)th from (i)th and (M-i)th routing segments
* c. Wilton, which rotates the connection of Disjoint by 1 track
* 6. Allocate rr_graph, fill the node information
* For each node, fill
* a. basic information: coordinator(xlow, xhigh, ylow, yhigh), ptc_num
* b. edges (both incoming and outcoming)
* c. handle direct-connections
* 7. Build fast look-up for the rr_graph
* 8. Allocate external data structures
* a. cost_index
* b. RC tree
***********************************************************************/
t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
INP t_type_ptr types, INP int L_nx, INP int L_ny,
INP struct s_grid_tile **L_grid, INP int chan_width,
INP struct s_chan_width_dist *chan_capacity_inf,
INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types,
INP int num_switches, INP t_segment_inf * segment_inf,
INP int global_route_switch, INP int delayless_switch,
INP t_timing_inf timing_inf, INP int wire_to_ipin_switch,
INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs,
INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings,
/*Xifan TANG: Switch Segment Pattern Support*/
INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns,
INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) {
/* Create an empty graph */
t_rr_graph rr_graph;
rr_graph.rr_node_indices = NULL;
rr_graph.rr_node = NULL;
rr_graph.num_rr_nodes = 0;
/* Reset warning flag */
*Warnings = RR_GRAPH_NO_WARN;
/* Create a matrix of grid */
DeviceCoordinator device_size(L_nx + 2, L_ny + 2);
std::vector< std::vector<t_grid_tile> > grids;
/* reserve vector capacity to be memory efficient */
grids.resize(L_nx + 2);
for (int ix = 0; ix < (L_nx + 2); ++ix) {
grids[ix].resize(L_ny + 2);
for (int iy = 0; ix < (L_ny + 2); ++iy) {
grid[ix][iy] = L_grid[ix][iy];
}
}
/* Create a vector of channel width, we support X-direction and Y-direction has different W */
std::vector<size_t> device_chan_width;
device_chan_width.push_back(chan_width);
device_chan_width.push_back(chan_width);
/* Create a vector of segment_inf */
std::vector<t_segment_inf> segment_infs;
for (int iseg = 0; iseg < num_seg_types; ++iseg) {
segment_infs.push_back(segment_inf[iseg]);
}
/************************************************************************
* 2. Estimate the number of nodes in the rr_graph
* This will estimate the number of
* a. IPINs, input pins of each grid
* b. OPINs, output pins of each grid
* c. SOURCE, virtual node which drives OPINs
* d. SINK, virtual node which is connected to IPINs
* e. CHANX and CHANY, routing segments of each channel
***********************************************************************/
std::vector<size_t> num_rr_nodes_per_type = estimate_num_rr_nodes_per_type(device_size, grids, device_chan_width, segment_infs);
/************************************************************************
* 3. Allocate the rr_nodes
***********************************************************************/
rr_graph.num_rr_nodes = 0;
for (size_t i = 0; i < num_rr_nodes_per_type.size(); ++i) {
rr_graph.num_rr_nodes += num_rr_nodes_per_type[i];
}
/* use calloc to initialize everything to be zero */
rr_graph.rr_node = (t_rr_node*)my_calloc(rr_graph.num_rr_nodes, sizeof(t_rr_node));
/************************************************************************
* 4. Initialize the basic information of rr_nodes:
* coordinators: xlow, ylow, xhigh, yhigh,
* features: capacity, track_ids, ptc_num, direction
* grid_info : pb_graph_pin
***********************************************************************/
/************************************************************************
* 3. Create the connectivity of OPINs
* a. Evenly assign connections to OPINs to routing tracks
* b. the connection pattern should be same across the fabric
***********************************************************************/
int **Fc_in = NULL; /* [0..num_types-1][0..num_pins-1] */
boolean Fc_clipped;
Fc_clipped = FALSE;
Fc_in = alloc_and_load_actual_fc(L_num_types, types, chan_width,
FALSE, UNI_DIRECTIONAL, &Fc_clipped, ignore_Fc_0);
if (Fc_clipped) {
*Warnings |= RR_GRAPH_WARN_FC_CLIPPED;
}
/************************************************************************
* 4. Create the connectivity of IPINs
* a. Evenly assign connections from routing tracks to IPINs
* b. the connection pattern should be same across the fabric
***********************************************************************/
int **Fc_out = NULL; /* [0..num_types-1][0..num_pins-1] */
Fc_clipped = FALSE;
Fc_out = alloc_and_load_actual_fc(L_num_types, types, chan_width,
TRUE, UNI_DIRECTIONAL, &Fc_clipped, ignore_Fc_0);
/************************************************************************
* 6. Allocate rr_graph, fill the node information
* For each node, fill
* a. basic information: coordinator(xlow, xhigh, ylow, yhigh), ptc_num
* b. edges (both incoming and outcoming)
* c. handle direct-connections
***********************************************************************/
/* Alloc node lookups, count nodes, alloc rr nodes */
/*
rr_graph.num_rr_nodes = 0;
rr_graph.rr_node_indices = alloc_and_load_rr_node_indices(nodes_per_chan, L_nx, L_ny,
&(rr_graph.num_rr_nodes), seg_details);
rr_graph.rr_node = (t_rr_node *) my_malloc(sizeof(t_rr_node) * rr_graph.num_rr_nodes);
memset(rr_node, 0, sizeof(t_rr_node) * rr_graph.num_rr_nodes);
boolean* L_rr_edge_done = (boolean *) my_malloc(sizeof(boolean) * rr_graph.num_rr_nodes);
memset(L_rr_edge_done, 0, sizeof(boolean) * rr_graph.num_rr_nodes);
*/
/* handle direct-connections */
t_clb_to_clb_directs* clb_to_clb_directs = NULL;
if (num_directs > 0) {
clb_to_clb_directs = alloc_and_load_clb_to_clb_directs(directs, num_directs);
}
/************************************************************************
* 8. Allocate external data structures
* a. cost_index
* b. RC tree
***********************************************************************/
rr_graph_externals(timing_inf, segment_inf, num_seg_types, chan_width,
wire_to_ipin_switch, base_cost_type);
return rr_graph;
}
/************************************************************************
* End of file : rr_graph_tileable_builder.c
***********************************************************************/

View File

@ -1,18 +0,0 @@
#ifndef RR_GRAPH_TILEABLE_BUILDER_H
#define RR_GRAPH_TILEABLE_BUILDER_H
t_rr_graph build_tileable_unidir_rr_graph(INP int L_num_types,
INP t_type_ptr types, INP int L_nx, INP int L_ny,
INP struct s_grid_tile **L_grid, INP int chan_width,
INP struct s_chan_width_dist *chan_capacity_inf,
INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types,
INP int num_switches, INP t_segment_inf * segment_inf,
INP int global_route_switch, INP int delayless_switch,
INP t_timing_inf timing_inf, INP int wire_to_ipin_switch,
INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs,
INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings,
/*Xifan TANG: Switch Segment Pattern Support*/
INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns,
INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges);
#endif

View File

@ -0,0 +1,255 @@
/**********************************************************
* MIT License
*
* Copyright (c) 2018 LNIS - The University of Utah
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***********************************************************************/
/************************************************************************
* Filename: tileable_chan_details_builder.cpp
* Created by: Xifan Tang
* Change history:
* +-------------------------------------+
* | Date | Author | Notes
* +-------------------------------------+
* | 2019/06/23 | Xifan Tang | Created
* +-------------------------------------+
***********************************************************************/
/************************************************************************
* This file contains a builder for the ChanNodeDetails data structure
* Different from VPR rr_graph builders, this builder aims to create a
* highly regular routing channel. Thus, it is called tileable,
* which brings significant advantage in producing large FPGA fabrics.
***********************************************************************/
#include <stdio.h>
#include <assert.h>
#include <vector>
#include <algorithm>
#include "tileable_chan_details_builder.h"
/************************************************************************
* Generate the number of tracks for each types of routing segments
* w.r.t. the frequency of each of segments and channel width
* Note that if we dertermine the number of tracks per type using
* chan_width * segment_frequency / total_freq may cause
* The total track num may not match the chan_width,
* therefore, we assign tracks one by one until we meet the frequency requirement
* In this way, we can assign the number of tracks with repect to frequency
***********************************************************************/
static
std::vector<size_t> get_num_tracks_per_seg_type(const size_t chan_width,
const std::vector<t_segment_inf> segment_inf,
const bool use_full_seg_groups) {
std::vector<size_t> result;
std::vector<double> demand;
/* Make sure a clean start */
result.resize(segment_inf.size());
demand.resize(segment_inf.size());
/* Scale factor so we can divide by any length
* and still use integers */
/* Get the sum of frequency */
size_t scale = 1;
size_t freq_sum = 0;
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
scale *= segment_inf[iseg].length;
freq_sum += segment_inf[iseg].frequency;
}
size_t reduce = scale * freq_sum;
/* Init assignments to 0 and set the demand values */
/* Get the fraction of each segment type considering the frequency:
* num_track_per_seg = chan_width * (freq_of_seg / sum_freq)
*/
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
result[iseg] = 0;
demand[iseg] = scale * chan_width * segment_inf[iseg].frequency;
if (true == use_full_seg_groups) {
demand[iseg] /= segment_inf[iseg].length;
}
}
/* check if the sum of num_tracks, matches the chan_width */
/* Keep assigning tracks until we use them up */
size_t assigned = 0;
size_t size = 0;
size_t imax = 0;
while (assigned < chan_width) {
/* Find current maximum demand */
double max = 0;
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
if (demand[iseg] > max) {
imax = iseg;
}
max = std::max(demand[iseg], max);
}
/* Assign tracks to the type and reduce the types demand */
size = (use_full_seg_groups ? segment_inf[imax].length : 1);
demand[imax] -= reduce;
result[imax] += size;
assigned += size;
}
/* Undo last assignment if we were closer to goal without it */
if ((assigned - chan_width) > (size / 2)) {
result[imax] -= size;
}
return result;
}
/************************************************************************
* Build details of routing tracks in a channel
* The function will
* 1. Assign the segments for each routing channel,
* To be specific, for each routing track, we assign a routing segment.
* The assignment is subject to users' specifications, such as
* a. length of each type of segment
* b. frequency of each type of segment.
* c. routing channel width
*
* 2. The starting point of each segment in the channel will be assigned
* For each segment group with same directionality (tracks have the same length),
* every L track will be a starting point (where L denotes the length of segments)
* In this case, if the number of tracks is not a multiple of L,
* indeed we may have some <L segments. This can be considered as a side effect.
* But still the rr_graph is tileable, which is the first concern!
*
* Here is a quick example of Length-4 wires in a W=12 routing channel
* +---------------------------------------+--------------+
* | Index | Direction | Starting Point | Ending Point |
* +---------------------------------------+--------------+
* | 0 | MUX--------> | Yes | No |
* +---------------------------------------+--------------+
* | 1 | <--------MUX | Yes | No |
* +---------------------------------------+--------------+
* | 2 | --------> | No | No |
* +---------------------------------------+--------------+
* | 3 | <-------- | No | No |
* +---------------------------------------+--------------+
* | 4 | --------> | No | No |
* +---------------------------------------+--------------+
* | 5 | <-------- | No | No |
* +---------------------------------------+--------------+
* | 7 | -------->MUX | No | Yes |
* +---------------------------------------+--------------+
* | 8 | MUX<-------- | No | Yes |
* +---------------------------------------+--------------+
* | 9 | MUX--------> | Yes | No |
* +---------------------------------------+--------------+
* | 10 | <--------MUX | Yes | No |
* +---------------------------------------+--------------+
* | 11 | -------->MUX | No | Yes |
* +------------------------------------------------------+
* | 12 | <-------- | No | No |
* +------------------------------------------------------+
*
* 3. SPECIAL for fringes: TOP|RIGHT|BOTTOM|RIGHT
* if device_side is NUM_SIDES, we assume this channel does not locate on borders
* All segments will start and ends with no exception
*
* 4. IMPORTANT: we should be aware that channel width maybe different
* in X-direction and Y-direction channels!!!
* So we will load segment details for different channels
***********************************************************************/
ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const size_t max_seg_length,
const enum e_side device_side,
const std::vector<t_segment_inf> segment_inf) {
ChanNodeDetails chan_node_details;
size_t actual_chan_width = chan_width;
/* Correct the chan_width: it should be an even number */
if (0 != actual_chan_width % 2) {
actual_chan_width++; /* increment it to be even */
}
assert (0 == actual_chan_width % 2);
/* Reserve channel width */
chan_node_details.reserve(chan_width);
/* Return if zero width is forced */
if (0 == actual_chan_width) {
return chan_node_details;
}
/* Find the number of segments required by each group */
std::vector<size_t> num_tracks = get_num_tracks_per_seg_type(actual_chan_width/2, segment_inf, FALSE);
/* Add node to ChanNodeDetails */
size_t cur_track = 0;
for (size_t iseg = 0; iseg < segment_inf.size(); ++iseg) {
/* segment length will be set to maxium segment length if this is a longwire */
size_t seg_len = segment_inf[iseg].length;
if (TRUE == segment_inf[iseg].longline) {
seg_len = max_seg_length;
}
for (size_t itrack = 0; itrack < num_tracks[iseg]; ++itrack) {
bool seg_start = false;
bool seg_end = false;
/* Every first track of a group of Length-N wires, we set a starting point */
if (0 == itrack % seg_len) {
seg_start = true;
}
/* Every last track of a group of Length-N wires or this is the last track in this group, we set an ending point */
if ( (seg_len - 1 == itrack % seg_len)
|| (itrack == num_tracks[iseg] - 1) ) {
seg_end = true;
}
/* Since this is a unidirectional routing architecture,
* Add a pair of tracks, 1 INC_DIRECTION track and 1 DEC_DIRECTION track
*/
chan_node_details.add_track(cur_track, INC_DIRECTION, iseg, seg_len, seg_start, seg_end);
cur_track++;
chan_node_details.add_track(cur_track, DEC_DIRECTION, iseg, seg_len, seg_start, seg_end);
cur_track++;
}
}
/* Check if all the tracks have been satisified */
assert (cur_track == actual_chan_width);
/* If this is on the border of a device, segments should start */
switch (device_side) {
case TOP:
case RIGHT:
/* INC_DIRECTION should all end */
chan_node_details.set_tracks_end(INC_DIRECTION);
/* DEC_DIRECTION should all start */
chan_node_details.set_tracks_start(DEC_DIRECTION);
break;
case BOTTOM:
case LEFT:
/* INC_DIRECTION should all start */
chan_node_details.set_tracks_start(INC_DIRECTION);
/* DEC_DIRECTION should all end */
chan_node_details.set_tracks_end(DEC_DIRECTION);
break;
case NUM_SIDES:
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d]) Invalid device_side!\n",
__FILE__, __LINE__);
exit(1);
}
return chan_node_details;
}

View File

@ -0,0 +1,11 @@
#ifndef TILEABLE_CHAN_DETAILS_BUILDER_H
#define TILEABLE_CHAN_DETAILS_BUILDER_H
#include "vpr_types.h"
#include "chan_node_details.h"
ChanNodeDetails build_unidir_chan_node_details(const size_t chan_width, const size_t max_seg_length,
const enum e_side device_side,
const std::vector<t_segment_inf> segment_inf);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
#ifndef TILEABLE_RR_GRAPH_BUILDER_H
#define TILEABLE_RR_GRAPH_BUILDER_H
#include <vector>
#include "vpr_types.h"
void build_tileable_unidir_rr_graph(INP const int L_num_types,
INP t_type_ptr types, INP const int L_nx, INP const int L_ny,
INP struct s_grid_tile **L_grid, INP const int chan_width,
INP const enum e_switch_block_type sb_type, INP const int Fs,
INP const int num_seg_types,
INP const t_segment_inf * segment_inf,
INP const int num_switches, INP const int delayless_switch,
INP const t_timing_inf timing_inf, INP const int wire_to_ipin_switch,
INP const enum e_base_cost_type base_cost_type,
INP const t_direct_inf *directs,
INP const int num_directs, INP const boolean ignore_Fc_0,
OUTP int *Warnings);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,65 @@
#ifndef TILEABLE_RR_GRAPH_GSB_H
#define TILEABLE_RR_GRAPH_GSB_H
#include <vector>
#include "vtr_ndmatrix.h"
#include "rr_blocks.h"
#include "fpga_x2p_types.h"
/************************************************************************
* Data stuctures related to the functions
***********************************************************************/
typedef std::vector<std::vector<std::vector<int>>> t_track2track_map;
typedef std::vector<std::vector<std::vector<int>>> t_track2pin_map;
typedef std::vector<std::vector<std::vector<int>>> t_pin2track_map;
/************************************************************************
* Functions
***********************************************************************/
t_track2track_map build_gsb_track_to_track_map(const t_rr_graph* rr_graph,
const RRGSB& rr_gsb,
const enum e_switch_block_type sb_type,
const int Fs,
const std::vector<t_segment_inf> segment_inf);
RRGSB build_one_tileable_rr_gsb(const DeviceCoordinator& device_range,
const std::vector<size_t> device_chan_width,
const std::vector<t_segment_inf> segment_inf,
const DeviceCoordinator& gsb_coordinator,
t_rr_graph* rr_graph);
void build_edges_for_one_tileable_rr_gsb(const t_rr_graph* rr_graph,
const RRGSB* rr_gsb,
const t_track2pin_map track2ipin_map,
const t_pin2track_map opin2track_map,
const t_track2track_map track2track_map);
t_track2pin_map build_gsb_track_to_ipin_map(t_rr_graph* rr_graph,
const RRGSB& rr_gsb,
const std::vector<std::vector<t_grid_tile>> grids,
const std::vector<t_segment_inf> segment_inf,
int** Fc_in);
t_pin2track_map build_gsb_opin_to_track_map(t_rr_graph* rr_graph,
const RRGSB& rr_gsb,
const std::vector<std::vector<t_grid_tile>> grids,
const std::vector<t_segment_inf> segment_inf,
int** Fc_out);
void build_direct_connections_for_one_gsb(t_rr_graph* rr_graph,
const DeviceCoordinator& device_size,
const std::vector<std::vector<t_grid_tile>> grids,
const DeviceCoordinator& from_grid_coordinator,
const t_grid_tile& from_grid,
const int delayless_switch,
const int num_directs,
const t_direct_inf *directs,
const t_clb_to_clb_directs *clb_to_clb_directs);
#endif

View File

@ -1800,6 +1800,7 @@ void identify_rr_node_driver_switch(t_det_routing_arch RoutingArch,
} }
LL_rr_node[inode].driver_switch = LL_rr_node[inode].drive_switches[0]; LL_rr_node[inode].driver_switch = LL_rr_node[inode].drive_switches[0];
for (iedge = 0; iedge < LL_rr_node[inode].num_drive_rr_nodes; iedge++) { for (iedge = 0; iedge < LL_rr_node[inode].num_drive_rr_nodes; iedge++) {
if (LL_rr_node[inode].driver_switch != LL_rr_node[inode].drive_switches[iedge])
assert (LL_rr_node[inode].driver_switch == LL_rr_node[inode].drive_switches[iedge]); assert (LL_rr_node[inode].driver_switch == LL_rr_node[inode].drive_switches[iedge]);
} }
} }
@ -1830,6 +1831,7 @@ t_rr_node** get_chan_rr_nodes(int* num_chan_rr_nodes,
chan_rr_nodes = (t_rr_node**)my_malloc((*num_chan_rr_nodes)*sizeof(t_rr_node*)); chan_rr_nodes = (t_rr_node**)my_malloc((*num_chan_rr_nodes)*sizeof(t_rr_node*));
/* Fill the array */ /* Fill the array */
for (itrack = 0; itrack < (*num_chan_rr_nodes); itrack++) { for (itrack = 0; itrack < (*num_chan_rr_nodes); itrack++) {
/* CHANX follows a weird way in searching rr_nodes */
inode = get_rr_node_index(x, y, CHANX, itrack, LL_rr_node_indices); inode = get_rr_node_index(x, y, CHANX, itrack, LL_rr_node_indices);
chan_rr_nodes[itrack] = &(LL_rr_node[inode]); chan_rr_nodes[itrack] = &(LL_rr_node[inode]);
} }
@ -3136,6 +3138,7 @@ void spice_backannotate_vpr_post_route_info(t_det_routing_arch RoutingArch,
/* Build previous node lists for each rr_node */ /* Build previous node lists for each rr_node */
vpr_printf(TIO_MESSAGE_INFO, "Building previous node list for all Routing Resource Nodes...\n"); vpr_printf(TIO_MESSAGE_INFO, "Building previous node list for all Routing Resource Nodes...\n");
build_prev_node_list_rr_nodes(num_rr_nodes, rr_node); build_prev_node_list_rr_nodes(num_rr_nodes, rr_node);
//sort_rr_graph_drive_rr_nodes(num_rr_nodes, rr_node);
/* Build driver switches for each rr_node*/ /* Build driver switches for each rr_node*/
vpr_printf(TIO_MESSAGE_INFO, "Identifying driver switches for all Routing Resource Nodes...\n"); vpr_printf(TIO_MESSAGE_INFO, "Identifying driver switches for all Routing Resource Nodes...\n");

View File

@ -2528,6 +2528,7 @@ void link_one_pb_graph_node_pin_to_phy_pb_graph_pin(t_pb_graph_pin* cur_pb_graph
} }
/* Create the link */ /* Create the link */
cur_pb_graph_pin->physical_pb_graph_pin = phy_pb_graph_pin; cur_pb_graph_pin->physical_pb_graph_pin = phy_pb_graph_pin;
/*
vpr_printf (TIO_MESSAGE_INFO, " match pin (%s[%d]->%s[%d]) to (%s[%d]->%s[%d]) rotate_offset_acc=%d\n", vpr_printf (TIO_MESSAGE_INFO, " match pin (%s[%d]->%s[%d]) to (%s[%d]->%s[%d]) rotate_offset_acc=%d\n",
cur_pb_graph_pin->parent_node->pb_type->name, cur_pb_graph_pin->parent_node->pb_type->name,
cur_pb_graph_pin->parent_node->placement_index, cur_pb_graph_pin->parent_node->placement_index,
@ -2537,6 +2538,7 @@ void link_one_pb_graph_node_pin_to_phy_pb_graph_pin(t_pb_graph_pin* cur_pb_graph
phy_pb_graph_pin->port->name, phy_pb_graph_pin->pin_number, phy_pb_graph_pin->port->name, phy_pb_graph_pin->pin_number,
cur_pb_graph_pin->port->phy_mode_pin_rotate_offset_acc cur_pb_graph_pin->port->phy_mode_pin_rotate_offset_acc
); );
*/
/* Accumulate the phy_mode_pin offset when we have a matched */ /* Accumulate the phy_mode_pin offset when we have a matched */
if (0 != cur_pb_graph_pin->port->physical_mode_pin_rotate_offset) { if (0 != cur_pb_graph_pin->port->physical_mode_pin_rotate_offset) {
cur_pb_graph_pin->port->phy_mode_pin_rotate_offset_acc += cur_pb_graph_pin->port->physical_mode_pin_rotate_offset; cur_pb_graph_pin->port->phy_mode_pin_rotate_offset_acc += cur_pb_graph_pin->port->physical_mode_pin_rotate_offset;

View File

@ -10,6 +10,7 @@
#include <assert.h> #include <assert.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <vector>
/* Include vpr structs*/ /* Include vpr structs*/
#include "util.h" #include "util.h"
@ -25,6 +26,8 @@
#include "fpga_x2p_pbtypes_utils.h" #include "fpga_x2p_pbtypes_utils.h"
#include "fpga_x2p_rr_graph_utils.h" #include "fpga_x2p_rr_graph_utils.h"
#include "rr_graph_builder_utils.h"
/* Initial rr_graph */ /* Initial rr_graph */
void init_rr_graph(INOUTP t_rr_graph* local_rr_graph) { void init_rr_graph(INOUTP t_rr_graph* local_rr_graph) {
/* Give zero and NULL to all the contents */ /* Give zero and NULL to all the contents */
@ -954,8 +957,8 @@ void build_prev_node_list_rr_nodes(int LL_num_rr_nodes,
if (0 == LL_rr_node[inode].fan_in) { if (0 == LL_rr_node[inode].fan_in) {
continue; continue;
} }
LL_rr_node[inode].drive_rr_nodes = (t_rr_node**)my_malloc(sizeof(t_rr_node*)*LL_rr_node[inode].num_drive_rr_nodes); LL_rr_node[inode].drive_rr_nodes = (t_rr_node**)my_malloc(sizeof(t_rr_node*) * LL_rr_node[inode].num_drive_rr_nodes);
LL_rr_node[inode].drive_switches = (int*)my_malloc(sizeof(int)*LL_rr_node[inode].num_drive_rr_nodes); LL_rr_node[inode].drive_switches = (int*)my_malloc(sizeof(int) * LL_rr_node[inode].num_drive_rr_nodes);
} }
/* Initialize */ /* Initialize */
for (inode = 0; inode < LL_num_rr_nodes; inode++) { for (inode = 0; inode < LL_num_rr_nodes; inode++) {
@ -985,6 +988,73 @@ void build_prev_node_list_rr_nodes(int LL_num_rr_nodes,
return; return;
} }
/************************************************************************
* Sort the drive_rr_nodes by node type and ptc_num
* 1. node type priority: (follow the index of t_rr_type
* SOURCE, SINK, IPIN, OPIN, CHANX, CHANY, INTRA_CLUSTER_EDGE, NUM_RR_TYPES
* 2. node ptc_num (feature number): from low to high
* The ptc_num only matters when two nodes have the same type
***********************************************************************/
void sort_rr_graph_drive_rr_nodes(int LL_num_rr_nodes,
t_rr_node* LL_rr_node) {
for (int inode = 0; inode < LL_num_rr_nodes; ++inode) {
/* Create a copy of the edges and switches of this node */
std::vector<t_rr_node*> sorted_drive_nodes;
std::vector<int> sorted_drive_switches;
/* Ensure a clean start */
sorted_drive_nodes.clear();
sorted_drive_switches.clear();
/* Build the vectors w.r.t. to the order of node_type and ptc_num */
for (int i_from_node = 0; i_from_node < LL_rr_node[inode].num_drive_rr_nodes; ++i_from_node) {
/* For blank edges: directly push_back */
if (0 == sorted_drive_nodes.size()) {
sorted_drive_nodes.push_back(LL_rr_node[inode].drive_rr_nodes[i_from_node]);
sorted_drive_switches.push_back(LL_rr_node[inode].drive_switches[i_from_node]);
continue;
}
/* Start sorting since the edges are not empty */
size_t insert_pos = sorted_drive_nodes.size(); /* the pos to insert. By default, it is the last element */
for (size_t j_from_node = 0; j_from_node < sorted_drive_nodes.size(); ++j_from_node) {
/* Sort by node_type and ptc_num */
if (LL_rr_node[inode].drive_rr_nodes[i_from_node]->type < sorted_drive_nodes[j_from_node]->type) {
/* iedge should be ahead of jedge */
insert_pos = j_from_node;
break; /* least type should stay in the front of the vector */
} else if (LL_rr_node[inode].drive_rr_nodes[i_from_node]->type == sorted_drive_nodes[j_from_node]->type) {
/* Special as track_ids vary, we consider the last track_ids for those node has the same type as inode */
if (LL_rr_node[i_from_node].type == LL_rr_node[inode].type) {
if (get_track_rr_node_end_track_id(&(LL_rr_node[i_from_node]))
< get_track_rr_node_end_track_id(&(LL_rr_node[j_from_node])) ) {
insert_pos = j_from_node;
break; /* least type should stay in the front of the vector */
}
/* Now a lower ptc_num will win */
} else if (LL_rr_node[inode].drive_rr_nodes[i_from_node]->ptc_num < sorted_drive_nodes[j_from_node]->ptc_num) {
insert_pos = j_from_node;
break; /* least type should stay in the front of the vector */
}
}
}
/* We find the position, inserted to the vector */
sorted_drive_nodes.insert(sorted_drive_nodes.begin() + insert_pos, LL_rr_node[inode].drive_rr_nodes[i_from_node]);
sorted_drive_switches.insert(sorted_drive_switches.begin() + insert_pos, LL_rr_node[inode].drive_switches[i_from_node]);
}
/* Overwrite the edges and switches with sorted numbers */
for (size_t iedge = 0; iedge < sorted_drive_nodes.size(); ++iedge) {
LL_rr_node[inode].drive_rr_nodes[iedge] = sorted_drive_nodes[iedge];
}
for (size_t iedge = 0; iedge < sorted_drive_switches.size(); ++iedge) {
LL_rr_node[inode].drive_switches[iedge] = sorted_drive_switches[iedge];
}
}
return;
}
void alloc_and_load_prev_node_list_rr_graph_rr_nodes(t_rr_graph* local_rr_graph) { void alloc_and_load_prev_node_list_rr_graph_rr_nodes(t_rr_graph* local_rr_graph) {
build_prev_node_list_rr_nodes(local_rr_graph->num_rr_nodes, local_rr_graph->rr_node); build_prev_node_list_rr_nodes(local_rr_graph->num_rr_nodes, local_rr_graph->rr_node);

View File

@ -1,3 +1,5 @@
#ifndef FPGA_X2P_RR_GRAPH_UTILS_H
#define FPGA_X2P_RR_GRAPH_UTILS_H
void init_rr_graph(INOUTP t_rr_graph* local_rr_graph); void init_rr_graph(INOUTP t_rr_graph* local_rr_graph);
@ -89,6 +91,9 @@ void free_rr_graph_traceback(t_rr_graph* local_rr_graph,
void build_prev_node_list_rr_nodes(int LL_num_rr_nodes, void build_prev_node_list_rr_nodes(int LL_num_rr_nodes,
t_rr_node* LL_rr_node); t_rr_node* LL_rr_node);
void sort_rr_graph_drive_rr_nodes(int LL_num_rr_nodes,
t_rr_node* LL_rr_node);
void alloc_and_load_prev_node_list_rr_graph_rr_nodes(t_rr_graph* local_rr_graph); void alloc_and_load_prev_node_list_rr_graph_rr_nodes(t_rr_graph* local_rr_graph);
void backannotate_rr_graph_routing_results_to_net_name(t_rr_graph* local_rr_graph); void backannotate_rr_graph_routing_results_to_net_name(t_rr_graph* local_rr_graph);
@ -106,3 +111,5 @@ void get_chan_rr_node_end_coordinate(t_rr_node* chan_rr_node,
int* x_end, int* y_end); int* x_end, int* y_end);
int get_rr_node_wire_length(t_rr_node* src_rr_node); int get_rr_node_wire_length(t_rr_node* src_rr_node);
#endif

View File

@ -1,3 +1,8 @@
#ifndef FPGA_X2P_TYPES_H
#define FPGA_X2P_TYPES_H
#include "route_common.h"
/* Define the basic data structures used for FPGA-SPICE */ /* Define the basic data structures used for FPGA-SPICE */
/* Default ID of switch used in rr_node */ /* Default ID of switch used in rr_node */
@ -135,3 +140,4 @@ struct fpga_spice_phy_pb {
int num_iopads; int num_iopads;
}; };
#endif

View File

@ -1,7 +1,46 @@
/***********************************/ /**********************************************************
/* SPICE Modeling for VPR */ * MIT License
/* Xifan TANG, EPFL/LSI */ *
/***********************************/ * Copyright (c) 2018 LNIS - The University of Utah
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***********************************************************************/
/************************************************************************
* Filename: fpga_x2p_unique_routing.c
* Created by: Xifan Tang
* Change history:
* +-------------------------------------+
* | Date | Author | Notes
* +-------------------------------------+
* | 2019/06/25 | Xifan Tang | Created
* +-------------------------------------+
***********************************************************************/
/************************************************************************
* This file contains builders for the data structures
* 1. RRGSB: General Switch Block (GSB).
* 2. RRChan: Generic routing channels
* We also include functions to identify unique modules of
* Switch Blocks and Connection Blocks based on the data structures
* t_sb and t_cb
***********************************************************************/
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -1096,157 +1135,180 @@ RRGSB build_rr_gsb(DeviceCoordinator& device_range,
return rr_gsb; return rr_gsb;
} }
/* Rotate the Switch block and try to add to rotatable mirrors */ /* sort drive_rr_nodes of a rr_node inside rr_gsb subject to the index of rr_gsb array */
static static
RRGSB rotate_rr_switch_block_for_mirror(DeviceCoordinator& device_range, void sort_rr_gsb_one_ipin_node_drive_rr_nodes(const RRGSB& rr_gsb,
const RRGSB& rr_switch_block) { t_rr_node* ipin_node,
RRGSB rotated_rr_switch_block; enum e_side ipin_chan_side) {
rotated_rr_switch_block.set(rr_switch_block); /* Create a copy of the edges and switches of this node */
size_t Fco_offset = 1; std::vector<t_rr_node*> sorted_drive_nodes;
std::vector<int> sorted_drive_switches;
/* For the 4 Switch Blocks at the four corners */ /* Ensure a clean start */
/* 1. BOTTOM-LEFT corner: sorted_drive_nodes.clear();
* nothing to do. This is the base we like sorted_drive_switches.clear();
*/
if ( ( 0 == rotated_rr_switch_block.get_sb_x()) /* Build the vectors w.r.t. to the order of node_type and ptc_num */
&& ( 0 == rotated_rr_switch_block.get_sb_y()) ) { for (int i_from_node = 0; i_from_node < ipin_node->num_drive_rr_nodes; ++i_from_node) {
return rotated_rr_switch_block; /* For blank edges: directly push_back */
if (0 == sorted_drive_nodes.size()) {
sorted_drive_nodes.push_back(ipin_node->drive_rr_nodes[i_from_node]);
sorted_drive_switches.push_back(ipin_node->drive_switches[i_from_node]);
continue;
} }
/* 2. TOP-LEFT corner: /* Start sorting since the edges are not empty */
* swap the opin_node between TOP and BOTTOM, size_t insert_pos = sorted_drive_nodes.size(); /* the pos to insert. By default, it is the last element */
* swap the chan_node between TOP and BOTTOM, for (size_t j_from_node = 0; j_from_node < sorted_drive_nodes.size(); ++j_from_node) {
*/ /* Sort by node_type and ptc_num */
if ( ( 0 == rotated_rr_switch_block.get_sb_x()) if (ipin_node->drive_rr_nodes[i_from_node]->type < sorted_drive_nodes[j_from_node]->type) {
&& (device_range.get_y() == rotated_rr_switch_block.get_sb_y()) ) { /* iedge should be ahead of jedge */
rotated_rr_switch_block.swap_opin_node(TOP, BOTTOM); insert_pos = j_from_node;
rotated_rr_switch_block.swap_chan_node(TOP, BOTTOM); break; /* least type should stay in the front of the vector */
return rotated_rr_switch_block; } else if (ipin_node->drive_rr_nodes[i_from_node]->type
== sorted_drive_nodes[j_from_node]->type) {
int i_from_node_track_index = rr_gsb.get_chan_node_index(ipin_chan_side, ipin_node->drive_rr_nodes[i_from_node]);
int j_from_node_track_index = rr_gsb.get_chan_node_index(ipin_chan_side, sorted_drive_nodes[j_from_node]);
/* We must have a valide node index */
assert ( (-1 != i_from_node_track_index) && (-1 != j_from_node_track_index) );
/* Now a lower ptc_num will win */
if ( i_from_node_track_index < j_from_node_track_index ) {
insert_pos = j_from_node;
break; /* least type should stay in the front of the vector */
}
}
}
/* We find the position, inserted to the vector */
sorted_drive_nodes.insert(sorted_drive_nodes.begin() + insert_pos, ipin_node->drive_rr_nodes[i_from_node]);
sorted_drive_switches.insert(sorted_drive_switches.begin() + insert_pos, ipin_node->drive_switches[i_from_node]);
} }
/* 3. TOP-RIGHT corner: /* Overwrite the edges and switches with sorted numbers */
* swap the opin_node between TOP and BOTTOM, for (size_t iedge = 0; iedge < sorted_drive_nodes.size(); ++iedge) {
* swap the chan_node between TOP and BOTTOM, ipin_node->drive_rr_nodes[iedge] = sorted_drive_nodes[iedge];
* swap the opin_node between LEFT and RIGHT,
* swap the chan_node between LEFT and RIGHT,
*/
if ( (device_range.get_x() == rotated_rr_switch_block.get_sb_x())
&& (device_range.get_y() == rotated_rr_switch_block.get_sb_y()) ) {
rotated_rr_switch_block.swap_opin_node(TOP, BOTTOM);
rotated_rr_switch_block.swap_chan_node(TOP, BOTTOM);
rotated_rr_switch_block.swap_opin_node(LEFT, RIGHT);
rotated_rr_switch_block.swap_chan_node(LEFT, RIGHT);
return rotated_rr_switch_block;
} }
/* 4. BOTTOM-RIGHT corner: for (size_t iedge = 0; iedge < sorted_drive_switches.size(); ++iedge) {
* swap the opin_node between LEFT and RIGHT, ipin_node->drive_switches[iedge] = sorted_drive_switches[iedge];
* swap the chan_node between LEFT and RIGHT,
*/
if ( (device_range.get_x() == rotated_rr_switch_block.get_sb_x())
&& (0 == rotated_rr_switch_block.get_sb_y()) ) {
rotated_rr_switch_block.swap_opin_node(LEFT, RIGHT);
rotated_rr_switch_block.swap_chan_node(LEFT, RIGHT);
return rotated_rr_switch_block;
} }
/* For Switch blocks on the borders */ return;
/* 1. BOTTOM side:
* nothing to do. This is the base we like
*/
if ( 0 == rotated_rr_switch_block.get_sb_y()) {
return rotated_rr_switch_block;
}
/* 2. TOP side:
* swap the opin_node between TOP and BOTTOM,
* swap the chan_node between TOP and BOTTOM,
*/
if (device_range.get_y() == rotated_rr_switch_block.get_sb_y() ) {
/* For RIGHT SIDE: X-channel in INC_DIRECTION, rotate by an offset of its x-coordinator */
rotated_rr_switch_block.rotate_side_chan_node_by_direction(RIGHT, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1));
/* Rotate the same nodes on the opposite side */
rotated_rr_switch_block.rotate_side_chan_node_by_direction(LEFT, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1));
/* For LEFT SIDE: X-channel in DEC_DIRECTION, rotate by an offset of its x-coordinator */
rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(LEFT, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1));
/* Rotate the same nodes on the opposite side */
rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(RIGHT, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1));
//rotated_rr_switch_block.swap_opin_node(TOP, BOTTOM);
//rotated_rr_switch_block.swap_chan_node(TOP, BOTTOM);
//rotated_rr_switch_block.reverse_opin_node(TOP);
//rotated_rr_switch_block.reverse_opin_node(BOTTOM);
return rotated_rr_switch_block;
}
/* 3. RIGHT side:
* swap the opin_node between LEFT and RIGHT,
* swap the chan_node between LEFT and RIGHT,
*/
if (device_range.get_x() == rotated_rr_switch_block.get_sb_x() ) {
/* For TOP SIDE: Y-channel in INC_DIRECTION, rotate by an offset of its y-coordinator */
rotated_rr_switch_block.rotate_side_chan_node_by_direction(TOP, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1));
/* Rotate the same nodes on the opposite side */
rotated_rr_switch_block.rotate_side_chan_node_by_direction(BOTTOM, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1));
/* For BOTTOM SIDE: Y-channel in DEC_DIRECTION, rotate by an offset of its y-coordinator */
rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(BOTTOM, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1));
/* Rotate the same nodes on the opposite side */
rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(TOP, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1));
//rotated_rr_switch_block.swap_opin_node(LEFT, RIGHT);
//rotated_rr_switch_block.swap_chan_node(LEFT, RIGHT);
//rotated_rr_switch_block.reverse_opin_node(LEFT);
//rotated_rr_switch_block.reverse_opin_node(RIGHT);
return rotated_rr_switch_block;
}
/* 4. LEFT side:
* nothing to do. This is the base we like
*/
if (0 == rotated_rr_switch_block.get_sb_x() ) {
return rotated_rr_switch_block;
}
/* SB[1][1] is the baseline, we do not modify */
if ( (1 == rotated_rr_switch_block.get_sb_x())
&& (1 == rotated_rr_switch_block.get_sb_y()) ) {
return rotated_rr_switch_block;
}
/* Reach here, it means we have a SB at the center region */
/* For TOP SIDE: Y-channel in INC_DIRECTION, rotate by an offset of its y-coordinator */
if (1 < rotated_rr_switch_block.get_sb_y()) {
rotated_rr_switch_block.rotate_side_chan_node_by_direction(TOP, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1));
/* Rotate the same nodes on the opposite side */
rotated_rr_switch_block.rotate_side_chan_node_by_direction(BOTTOM, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1));
}
/* For RIGHT SIDE: X-channel in INC_DIRECTION, rotate by an offset of its x-coordinator */
if (1 < rotated_rr_switch_block.get_sb_x()) {
rotated_rr_switch_block.rotate_side_chan_node_by_direction(RIGHT, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1));
/* Rotate the same nodes on the opposite side */
rotated_rr_switch_block.rotate_side_chan_node_by_direction(LEFT, INC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1));
}
/* For BOTTOM SIDE: Y-channel in DEC_DIRECTION, rotate by an offset of its y-coordinator */
if ( 1 < rotated_rr_switch_block.get_sb_y()) {
rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(BOTTOM, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1));
/* Rotate the same nodes on the opposite side */
rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(TOP, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_y() - 1));
}
/* For LEFT SIDE: X-channel in DEC_DIRECTION, rotate by an offset of its x-coordinator */
if ( 1 < rotated_rr_switch_block.get_sb_x()) {
rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(LEFT, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1));
/* Rotate the same nodes on the opposite side */
rotated_rr_switch_block.counter_rotate_side_chan_node_by_direction(RIGHT, DEC_DIRECTION, Fco_offset * (rotated_rr_switch_block.get_sb_x() - 1));
}
return rotated_rr_switch_block;
} }
/* sort drive_rr_nodes of a rr_node inside rr_gsb subject to the index of rr_gsb array */
static
void sort_rr_gsb_one_chan_node_drive_rr_nodes(const RRGSB& rr_gsb,
enum e_side chan_side,
size_t track_id) {
/* If this is a passing wire, we return directly.
* The passing wire will be handled in other GSBs
*/
if (true == rr_gsb.is_sb_node_passing_wire(chan_side, track_id)) {
return;
}
/* Get the chan_node */
t_rr_node* chan_node = rr_gsb.get_chan_node(chan_side, track_id);
/* Create a copy of the edges and switches of this node */
std::vector<t_rr_node*> sorted_drive_nodes;
std::vector<int> sorted_drive_switches;
/* Ensure a clean start */
sorted_drive_nodes.clear();
sorted_drive_switches.clear();
/* Build the vectors w.r.t. to the order of node_type and ptc_num */
for (int i_from_node = 0; i_from_node < chan_node->num_drive_rr_nodes; ++i_from_node) {
/* For blank edges: directly push_back */
if (0 == sorted_drive_nodes.size()) {
sorted_drive_nodes.push_back(chan_node->drive_rr_nodes[i_from_node]);
sorted_drive_switches.push_back(chan_node->drive_switches[i_from_node]);
continue;
}
/* Start sorting since the edges are not empty */
size_t insert_pos = sorted_drive_nodes.size(); /* the pos to insert. By default, it is the last element */
for (size_t j_from_node = 0; j_from_node < sorted_drive_nodes.size(); ++j_from_node) {
/* Sort by node_type and ptc_num */
if (chan_node->drive_rr_nodes[i_from_node]->type < sorted_drive_nodes[j_from_node]->type) {
/* iedge should be ahead of jedge */
insert_pos = j_from_node;
break; /* least type should stay in the front of the vector */
} else if (chan_node->drive_rr_nodes[i_from_node]->type
== sorted_drive_nodes[j_from_node]->type) {
/* For channel node, we do not know the node direction
* But we are pretty sure it is either IN_PORT or OUT_PORT
* So we just try and find what is valid
*/
enum e_side i_from_node_side = NUM_SIDES;
int i_from_node_index = -1;
rr_gsb.get_node_side_and_index(chan_node->drive_rr_nodes[i_from_node],
IN_PORT, &i_from_node_side, &i_from_node_index);
/* check */
if (! ( (NUM_SIDES != i_from_node_side) && (-1 != i_from_node_index) ) )
assert ( (NUM_SIDES != i_from_node_side) && (-1 != i_from_node_index) );
enum e_side j_from_node_side = NUM_SIDES;
int j_from_node_index = -1;
rr_gsb.get_node_side_and_index(sorted_drive_nodes[j_from_node],
IN_PORT, &j_from_node_side, &j_from_node_index);
/* check */
assert ( (NUM_SIDES != j_from_node_side) && (-1 != j_from_node_index) );
/* Now a lower ptc_num will win */
if ( i_from_node_index < j_from_node_index) {
insert_pos = j_from_node;
break; /* least type should stay in the front of the vector */
}
}
}
/* We find the position, inserted to the vector */
sorted_drive_nodes.insert(sorted_drive_nodes.begin() + insert_pos, chan_node->drive_rr_nodes[i_from_node]);
sorted_drive_switches.insert(sorted_drive_switches.begin() + insert_pos, chan_node->drive_switches[i_from_node]);
}
/* Overwrite the edges and switches with sorted numbers */
for (size_t iedge = 0; iedge < sorted_drive_nodes.size(); ++iedge) {
chan_node->drive_rr_nodes[iedge] = sorted_drive_nodes[iedge];
}
for (size_t iedge = 0; iedge < sorted_drive_switches.size(); ++iedge) {
chan_node->drive_switches[iedge] = sorted_drive_switches[iedge];
}
return;
}
/* sort drive_rr_nodes of each rr_node subject to the index of rr_gsb array */
static
void sort_rr_gsb_drive_rr_nodes(const RRGSB& rr_gsb) {
/* Sort the drive_rr_nodes for each rr_node */
for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
Side gsb_side_manager(side);
enum e_side gsb_side = gsb_side_manager.get_side();
/* For IPIN node: sort drive_rr_nodes according to the index in the routing channels */
for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(gsb_side); ++inode) {
/* Get the chan side, so we have the routing tracks */
enum e_side ipin_chan_side = rr_gsb.get_cb_chan_side(gsb_side);
sort_rr_gsb_one_ipin_node_drive_rr_nodes(rr_gsb,
rr_gsb.get_ipin_node(gsb_side, inode),
ipin_chan_side);
}
/* For CHANX | CHANY node: sort drive_rr_nodes according to the index in the routing channels */
for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) {
/* Bypass IN_PORT */
if (IN_PORT == rr_gsb.get_chan_node_direction(gsb_side, inode)) {
continue;
}
/* Get the chan side, so we have the routing tracks */
sort_rr_gsb_one_chan_node_drive_rr_nodes(rr_gsb,
gsb_side,
inode);
}
}
return;
}
/* Build a list of Switch blocks, each of which contains a collection of rr_nodes /* Build a list of Switch blocks, each of which contains a collection of rr_nodes
* We will maintain a list of unique switch blocks, which will be outputted as a Verilog module * We will maintain a list of unique switch blocks, which will be outputted as a Verilog module
@ -1258,22 +1320,25 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir,
t_ivec*** LL_rr_node_indices, int num_segments, t_ivec*** LL_rr_node_indices, int num_segments,
t_rr_indexed_data* LL_rr_indexed_data) { t_rr_indexed_data* LL_rr_indexed_data) {
/* Create an object */ /* Create an object */
DeviceRRGSB LL_drive_rr_gsb; DeviceRRGSB LL_device_rr_gsb;
/* Initialize */ /* Initialize */
DeviceCoordinator sb_range((size_t)nx, (size_t)ny); DeviceCoordinator sb_range((size_t)nx, (size_t)ny);
DeviceCoordinator reserve_range((size_t)nx + 1, (size_t)ny + 1); DeviceCoordinator reserve_range((size_t)nx + 1, (size_t)ny + 1);
LL_drive_rr_gsb.reserve(reserve_range); LL_device_rr_gsb.reserve(reserve_range);
/* For each switch block, determine the size of array */ /* For each switch block, determine the size of array */
for (size_t ix = 0; ix <= sb_range.get_x(); ++ix) { for (size_t ix = 0; ix <= sb_range.get_x(); ++ix) {
for (size_t iy = 0; iy <= sb_range.get_y(); ++iy) { for (size_t iy = 0; iy <= sb_range.get_y(); ++iy) {
RRGSB rr_sb = build_rr_gsb(sb_range, ix, iy, RRGSB rr_gsb = build_rr_gsb(sb_range, ix, iy,
LL_num_rr_nodes, LL_rr_node, LL_num_rr_nodes, LL_rr_node,
LL_rr_node_indices, LL_rr_node_indices,
num_segments, LL_rr_indexed_data); num_segments, LL_rr_indexed_data);
DeviceCoordinator sb_coordinator = rr_sb.get_sb_coordinator(); /* sort drive_rr_nodes */
LL_drive_rr_gsb.add_rr_gsb(sb_coordinator, rr_sb); sort_rr_gsb_drive_rr_nodes(rr_gsb);
/* Add to device_rr_gsb */
DeviceCoordinator sb_coordinator = rr_gsb.get_sb_coordinator();
LL_device_rr_gsb.add_rr_gsb(sb_coordinator, rr_gsb);
} }
} }
/* Report number of unique mirrors */ /* Report number of unique mirrors */
@ -1283,7 +1348,8 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir,
if (TRUE == output_sb_xml) { if (TRUE == output_sb_xml) {
write_device_rr_gsb_to_xml(sb_xml_dir, LL_drive_rr_gsb); create_dir_path(sb_xml_dir);
write_device_rr_gsb_to_xml(sb_xml_dir, LL_device_rr_gsb);
/* Skip rotating mirror searching */ /* Skip rotating mirror searching */
vpr_printf(TIO_MESSAGE_INFO, vpr_printf(TIO_MESSAGE_INFO,
@ -1294,66 +1360,43 @@ DeviceRRGSB build_device_rr_gsb(boolean output_sb_xml, char* sb_xml_dir,
/* Build a list of unique modules for each Switch Block */ /* Build a list of unique modules for each Switch Block */
/* Build a list of unique modules for each side of each Switch Block */ /* Build a list of unique modules for each side of each Switch Block */
LL_drive_rr_gsb.build_unique_module(); LL_device_rr_gsb.build_unique_module();
vpr_printf(TIO_MESSAGE_INFO, vpr_printf(TIO_MESSAGE_INFO,
"Detect %lu routing segments used by switch blocks.\n", "Detect %lu routing segments used by switch blocks.\n",
LL_drive_rr_gsb.get_num_segments()); LL_device_rr_gsb.get_num_segments());
/* Report number of unique CB Modules */ /* Report number of unique CB Modules */
vpr_printf(TIO_MESSAGE_INFO, vpr_printf(TIO_MESSAGE_INFO,
"Detect %d independent connection blocks from %d X-channel connection blocks.\n", "Detect %d independent connection blocks from %d X-channel connection blocks.\n",
LL_drive_rr_gsb.get_num_cb_unique_module(CHANX), (nx + 0) * (ny + 1) ); LL_device_rr_gsb.get_num_cb_unique_module(CHANX), (nx + 0) * (ny + 1) );
vpr_printf(TIO_MESSAGE_INFO, vpr_printf(TIO_MESSAGE_INFO,
"Detect %d independent connection blocks from %d Y-channel connection blocks.\n", "Detect %d independent connection blocks from %d Y-channel connection blocks.\n",
LL_drive_rr_gsb.get_num_cb_unique_module(CHANY), (nx + 1) * (ny + 0) ); LL_device_rr_gsb.get_num_cb_unique_module(CHANY), (nx + 1) * (ny + 0) );
/* Report number of unique SB modules */ /* Report number of unique SB modules */
vpr_printf(TIO_MESSAGE_INFO, vpr_printf(TIO_MESSAGE_INFO,
"Detect %d independent switch blocks from %d switch blocks.\n", "Detect %d independent switch blocks from %d switch blocks.\n",
LL_drive_rr_gsb.get_num_sb_unique_module(), (nx + 1) * (ny + 1) ); LL_device_rr_gsb.get_num_sb_unique_module(), (nx + 1) * (ny + 1) );
/* Report number of unique mirrors */ /* Report number of unique mirrors */
for (size_t side = 0; side < LL_drive_rr_gsb.get_max_num_sides(); ++side) { for (size_t side = 0; side < LL_device_rr_gsb.get_max_num_sides(); ++side) {
Side side_manager(side); Side side_manager(side);
/* get segment ids */ /* get segment ids */
for (size_t iseg = 0; iseg < LL_drive_rr_gsb.get_num_segments(); ++iseg) { for (size_t iseg = 0; iseg < LL_device_rr_gsb.get_num_segments(); ++iseg) {
vpr_printf(TIO_MESSAGE_INFO, vpr_printf(TIO_MESSAGE_INFO,
"For side %s, segment id %lu: Detect %d independent switch blocks from %d switch blocks.\n", "For side %s, segment id %lu: Detect %d independent switch blocks from %d switch blocks.\n",
side_manager.c_str(), LL_drive_rr_gsb.get_segment_id(iseg), side_manager.c_str(), LL_device_rr_gsb.get_segment_id(iseg),
LL_drive_rr_gsb.get_num_sb_unique_submodule(side_manager.get_side(), iseg), LL_device_rr_gsb.get_num_sb_unique_submodule(side_manager.get_side(), iseg),
(nx + 1) * (ny + 1) ); (nx + 1) * (ny + 1) );
} }
} }
/* Create directory if needed */ return LL_device_rr_gsb;
if (TRUE == output_sb_xml) {
create_dir_path(sb_xml_dir);
}
for (size_t ix = 0; ix <= sb_range.get_x(); ++ix) {
for (size_t iy = 0; iy <= sb_range.get_y(); ++iy) {
RRGSB rr_sb = LL_drive_rr_gsb.get_gsb(ix, iy);
RRGSB rotated_rr_sb = rotate_rr_switch_block_for_mirror(sb_range, rr_sb);
if (TRUE == output_sb_xml) {
std::string fname_prefix(sb_xml_dir);
/* Add slash if needed */
if ('/' != fname_prefix.back()) {
fname_prefix += "/";
}
fname_prefix += "rotated_";
write_rr_switch_block_to_xml(fname_prefix, rotated_rr_sb);
}
}
}
return LL_drive_rr_gsb;
} }
/************************************************************************
/* Rotatable will be done in the next step * End of file : fpga_x2p_unique_routing.c
void identify_rotatable_switch_blocks(); ***********************************************************************/
void identify_rotatable_connection_blocks();
*/

View File

@ -1,3 +1,42 @@
/**********************************************************
* MIT License
*
* Copyright (c) 2018 LNIS - The University of Utah
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
***********************************************************************/
/************************************************************************
* Filename: rr_blocks.cpp
* Created by: Xifan Tang
* Change history:
* +-------------------------------------+
* | Date | Author | Notes
* +-------------------------------------+
* | 2019/06/26 | Xifan Tang | Created
* +-------------------------------------+
***********************************************************************/
/************************************************************************
* This file contains member function for the data structures defined
* in rr_block.h
***********************************************************************/
#include <cassert> #include <cassert>
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>
@ -7,6 +46,8 @@
#include "rr_blocks.h" #include "rr_blocks.h"
#include "rr_graph_builder_utils.h"
/* Member Functions of Class RRChan */ /* Member Functions of Class RRChan */
/* Constructors */ /* Constructors */
@ -125,6 +166,24 @@ std::vector<size_t> RRChan::get_segment_ids() const {
return seg_list; return seg_list;
} }
/* Get a list of nodes whose segment_id is specified */
std::vector<size_t> RRChan::get_node_ids_by_segment_ids(size_t seg_id) const {
std::vector<size_t> node_list;
/* make sure a clean start */
node_list.clear();
/* Traverse node_segments */
for (size_t inode = 0; inode < get_chan_width(); ++inode) {
/* Try to find the node_segment id in the list */
if ( seg_id == node_segments_[inode] ) {
node_list.push_back(inode);
}
}
return node_list;
}
/* Mutators */ /* Mutators */
void RRChan::set(const RRChan& rr_chan) { void RRChan::set(const RRChan& rr_chan) {
/* Ensure a clean start */ /* Ensure a clean start */
@ -611,6 +670,22 @@ RRChan RRGSB::get_chan(enum e_side side) const {
return chan_node_[side_manager.to_size_t()]; return chan_node_[side_manager.to_size_t()];
} }
/* Get a list of segments used in this routing channel */
std::vector<size_t> RRGSB::get_chan_segment_ids(enum e_side side) const {
Side side_manager(side);
assert(side_manager.validate());
/* Ensure the side is valid in the context of this switch block */
assert( validate_side(side) );
return get_chan(side).get_segment_ids();
}
/* Get a list of rr_nodes whose sed_id is specified */
std::vector<size_t> RRGSB::get_chan_node_ids_by_segment_ids(enum e_side side, size_t seg_id) const {
return get_chan(side).get_node_ids_by_segment_ids(seg_id);
}
/* get a rr_node at a given side and track_id */ /* get a rr_node at a given side and track_id */
t_rr_node* RRGSB::get_chan_node(enum e_side side, size_t track_id) const { t_rr_node* RRGSB::get_chan_node(enum e_side side, size_t track_id) const {
Side side_manager(side); Side side_manager(side);
@ -969,23 +1044,53 @@ size_t RRGSB::get_cb_conf_bits_msb(t_rr_type cb_type) const {
} }
} }
/* Check if the node imply a short connection inside the SB, which happens to long wires across a FPGA fabric */ /************************************************************************
bool RRGSB::is_sb_node_imply_short_connection(t_rr_node* src_node) const { * Check if the node indicates a passing wire across the Switch Block part of the GSB
* Therefore, we actually do the following check
* Check if a track starts from this GSB or not
* For INC_DIRECTION
* (xlow, ylow) should be same as the GSB side coordinator
* For DEC_DIRECTION
* (xhigh, yhigh) should be same as the GSB side coordinator
***********************************************************************/
bool RRGSB::is_sb_node_passing_wire(const enum e_side node_side,
const size_t track_id) const {
assert((CHANX == src_node->type) || (CHANY == src_node->type)); /* Get the rr_node */
t_rr_node* track_node = get_chan_node(node_side, track_id);
/* Get the coordinators */
DeviceCoordinator side_coordinator = get_side_block_coordinator(node_side);
/* Get the coordinator of where the track starts */
DeviceCoordinator track_start = get_track_rr_node_start_coordinator(track_node);
/* INC_DIRECTION start_track: (xlow, ylow) should be same as the GSB side coordinator */
/* DEC_DIRECTION start_track: (xhigh, yhigh) should be same as the GSB side coordinator */
if ( (track_start.get_x() == side_coordinator.get_x())
&& (track_start.get_y() == side_coordinator.get_y())
&& (OUT_PORT == get_chan_node_direction(node_side, track_id)) ) {
/* Double check: start track should be an OUTPUT PORT of the GSB */
return false; /* This is a starting point */
}
/* Get the coordinator of where the track ends */
DeviceCoordinator track_end = get_track_rr_node_end_coordinator(track_node);
/* INC_DIRECTION end_track: (xhigh, yhigh) should be same as the GSB side coordinator */
/* DEC_DIRECTION end_track: (xlow, ylow) should be same as the GSB side coordinator */
if ( (track_end.get_x() == side_coordinator.get_x())
&& (track_end.get_y() == side_coordinator.get_y())
&& (IN_PORT == get_chan_node_direction(node_side, track_id)) ) {
/* Double check: end track should be an INPUT PORT of the GSB */
return false; /* This is an ending point */
}
/* Reach here it means that this will be a passing wire,
* we should be able to find the node on the opposite side of the GSB!
*/
assert (true == is_sb_node_exist_opposite_side(track_node, node_side));
for (size_t inode = 0; inode < size_t(src_node->num_drive_rr_nodes); ++inode) {
enum e_side side;
int index;
get_node_side_and_index(src_node->drive_rr_nodes[inode], IN_PORT, &side, &index);
/* We need to be sure that drive_rr_node is part of the SB */
if (((-1 == index) || (NUM_SIDES == side))
&& ((CHANX == src_node->drive_rr_nodes[inode]->type) || (CHANY == src_node->drive_rr_nodes[inode]->type))) {
return true; return true;
}
}
return false;
} }
/* check if the candidate SB satisfy the basic requirements on being a mirror of the current one */ /* check if the candidate SB satisfy the basic requirements on being a mirror of the current one */
@ -1224,6 +1329,17 @@ bool RRGSB::is_sb_mirror(const RRGSB& cand) const {
/* Public Accessors: Cooridinator conversion */ /* Public Accessors: Cooridinator conversion */
/* get the x coordinator of this GSB */
size_t RRGSB::get_x() const {
return coordinator_.get_x();
}
/* get the y coordinator of this GSB */
size_t RRGSB::get_y() const {
return coordinator_.get_y();
}
/* get the x coordinator of this switch block */ /* get the x coordinator of this switch block */
size_t RRGSB::get_sb_x() const { size_t RRGSB::get_sb_x() const {
return coordinator_.get_x(); return coordinator_.get_x();
@ -1302,6 +1418,24 @@ enum e_side RRGSB::get_cb_chan_side(t_rr_type cb_type) const {
} }
} }
/* Get the side of routing channel in the GSB according to the side of IPIN */
enum e_side RRGSB::get_cb_chan_side(enum e_side ipin_side) const {
switch(ipin_side) {
case TOP:
return LEFT;
case RIGHT:
return TOP;
case BOTTOM:
return LEFT;
case LEFT:
return TOP;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Invalid type of ipin_side!\n",
__FILE__, __LINE__);
exit(1);
}
}
DeviceCoordinator RRGSB::get_side_block_coordinator(enum e_side side) const { DeviceCoordinator RRGSB::get_side_block_coordinator(enum e_side side) const {
Side side_manager(side); Side side_manager(side);
@ -1337,6 +1471,13 @@ DeviceCoordinator RRGSB::get_side_block_coordinator(enum e_side side) const {
return ret; return ret;
} }
DeviceCoordinator RRGSB::get_grid_coordinator() const {
DeviceCoordinator ret(get_sb_x(), get_sb_y());
ret.set_y(ret.get_y() + 1);
return ret;
}
/* Public Accessors Verilog writer */ /* Public Accessors Verilog writer */
const char* RRGSB::gen_cb_verilog_routing_track_name(t_rr_type cb_type, const char* RRGSB::gen_cb_verilog_routing_track_name(t_rr_type cb_type,
size_t track_id) const { size_t track_id) const {
@ -1372,6 +1513,21 @@ const char* RRGSB::gen_sb_verilog_module_name() const {
return ret; return ret;
} }
const char* RRGSB::gen_gsb_verilog_module_name() const {
std::string x_str = std::to_string(get_sb_x());
std::string y_str = std::to_string(get_sb_y());
char* ret = (char*)my_malloc(sizeof(char)*
( 3 + 1
+ x_str.length() + 2
+ y_str.length() + 1
+ 1));
sprintf (ret, "gsb_%s__%s_",
x_str.c_str(), y_str.c_str());
return ret;
}
const char* RRGSB::gen_sb_verilog_instance_name() const { const char* RRGSB::gen_sb_verilog_instance_name() const {
char* ret = (char*)my_malloc(sizeof(char)* char* ret = (char*)my_malloc(sizeof(char)*
( strlen(gen_sb_verilog_module_name()) + 3 ( strlen(gen_sb_verilog_module_name()) + 3
@ -1382,6 +1538,16 @@ const char* RRGSB::gen_sb_verilog_instance_name() const {
return ret; return ret;
} }
const char* RRGSB::gen_gsb_verilog_instance_name() const {
char* ret = (char*)my_malloc(sizeof(char)*
( strlen(gen_gsb_verilog_module_name()) + 3
+ 1));
sprintf (ret, "%s_0_",
gen_gsb_verilog_module_name());
return ret;
}
/* Public Accessors Verilog writer */ /* Public Accessors Verilog writer */
const char* RRGSB::gen_sb_verilog_side_module_name(enum e_side side, size_t seg_id) const { const char* RRGSB::gen_sb_verilog_side_module_name(enum e_side side, size_t seg_id) const {
Side side_manager(side); Side side_manager(side);
@ -1539,7 +1705,7 @@ void RRGSB::add_chan_node(enum e_side node_side, RRChan& rr_chan, std::vector<en
} }
/* Add a node to the chan_node_ list and also assign its direction in chan_node_direction_ */ /* Add a node to the chan_node_ list and also assign its direction in chan_node_direction_ */
void RRGSB::add_ipin_node(t_rr_node* node, enum e_side node_side, enum e_side grid_side) { void RRGSB::add_ipin_node(t_rr_node* node, const enum e_side node_side, const enum e_side grid_side) {
Side side_manager(node_side); Side side_manager(node_side);
assert(validate_side(node_side)); assert(validate_side(node_side));
/* push pack the dedicated element in the vector */ /* push pack the dedicated element in the vector */
@ -1550,7 +1716,7 @@ void RRGSB::add_ipin_node(t_rr_node* node, enum e_side node_side, enum e_side gr
} }
/* Add a node to the chan_node_ list and also assign its direction in chan_node_direction_ */ /* Add a node to the chan_node_ list and also assign its direction in chan_node_direction_ */
void RRGSB::add_opin_node(t_rr_node* node, enum e_side node_side, enum e_side grid_side) { void RRGSB::add_opin_node(t_rr_node* node, const enum e_side node_side, const enum e_side grid_side) {
Side side_manager(node_side); Side side_manager(node_side);
assert(validate_side(node_side)); assert(validate_side(node_side));
/* push pack the dedicated element in the vector */ /* push pack the dedicated element in the vector */
@ -1823,8 +1989,10 @@ void RRGSB::mirror_side_chan_node_direction(enum e_side side) {
void RRGSB::swap_chan_node(enum e_side src_side, enum e_side des_side) { void RRGSB::swap_chan_node(enum e_side src_side, enum e_side des_side) {
Side src_side_manager(src_side); Side src_side_manager(src_side);
Side des_side_manager(des_side); Side des_side_manager(des_side);
std::swap(chan_node_[src_side_manager.to_size_t()], chan_node_[des_side_manager.to_size_t()]); std::swap(chan_node_[src_side_manager.to_size_t()],
std::swap(chan_node_direction_[src_side_manager.to_size_t()], chan_node_direction_[des_side_manager.to_size_t()]); chan_node_[des_side_manager.to_size_t()]);
std::swap(chan_node_direction_[src_side_manager.to_size_t()],
chan_node_direction_[des_side_manager.to_size_t()]);
return; return;
} }
@ -1832,8 +2000,10 @@ void RRGSB::swap_chan_node(enum e_side src_side, enum e_side des_side) {
void RRGSB::swap_opin_node(enum e_side src_side, enum e_side des_side) { void RRGSB::swap_opin_node(enum e_side src_side, enum e_side des_side) {
Side src_side_manager(src_side); Side src_side_manager(src_side);
Side des_side_manager(des_side); Side des_side_manager(des_side);
std::swap(opin_node_[src_side_manager.to_size_t()], opin_node_[des_side_manager.to_size_t()]); std::swap(opin_node_[src_side_manager.to_size_t()],
std::swap(opin_node_grid_side_[src_side_manager.to_size_t()], opin_node_grid_side_[des_side_manager.to_size_t()]); opin_node_[des_side_manager.to_size_t()]);
std::swap(opin_node_grid_side_[src_side_manager.to_size_t()],
opin_node_grid_side_[des_side_manager.to_size_t()]);
return; return;
} }
@ -1841,27 +2011,34 @@ void RRGSB::swap_opin_node(enum e_side src_side, enum e_side des_side) {
void RRGSB::swap_ipin_node(enum e_side src_side, enum e_side des_side) { void RRGSB::swap_ipin_node(enum e_side src_side, enum e_side des_side) {
Side src_side_manager(src_side); Side src_side_manager(src_side);
Side des_side_manager(des_side); Side des_side_manager(des_side);
std::swap(ipin_node_[src_side_manager.to_size_t()], ipin_node_[des_side_manager.to_size_t()]); std::swap(ipin_node_[src_side_manager.to_size_t()],
std::swap(ipin_node_grid_side_[src_side_manager.to_size_t()], ipin_node_grid_side_[des_side_manager.to_size_t()]); ipin_node_[des_side_manager.to_size_t()]);
std::swap(ipin_node_grid_side_[src_side_manager.to_size_t()],
ipin_node_grid_side_[des_side_manager.to_size_t()]);
return; return;
} }
/* Reverse the vector of the OPIN rr_nodes on a side */ /* Reverse the vector of the OPIN rr_nodes on a side */
void RRGSB::reverse_opin_node(enum e_side side) { void RRGSB::reverse_opin_node(enum e_side side) {
Side side_manager(side); Side side_manager(side);
std::reverse(opin_node_[side_manager.to_size_t()].begin(), opin_node_[side_manager.to_size_t()].end()); std::reverse(opin_node_[side_manager.to_size_t()].begin(),
std::reverse(opin_node_grid_side_[side_manager.to_size_t()].begin(), opin_node_grid_side_[side_manager.to_size_t()].end()); opin_node_[side_manager.to_size_t()].end());
std::reverse(opin_node_grid_side_[side_manager.to_size_t()].begin(),
opin_node_grid_side_[side_manager.to_size_t()].end());
return; return;
} }
/* Reverse the vector of the OPIN rr_nodes on a side */ /* Reverse the vector of the OPIN rr_nodes on a side */
void RRGSB::reverse_ipin_node(enum e_side side) { void RRGSB::reverse_ipin_node(enum e_side side) {
Side side_manager(side); Side side_manager(side);
std::reverse(ipin_node_[side_manager.to_size_t()].begin(), ipin_node_[side_manager.to_size_t()].end()); std::reverse(ipin_node_[side_manager.to_size_t()].begin(),
std::reverse(ipin_node_grid_side_[side_manager.to_size_t()].begin(), ipin_node_grid_side_[side_manager.to_size_t()].end()); ipin_node_[side_manager.to_size_t()].end());
std::reverse(ipin_node_grid_side_[side_manager.to_size_t()].begin(),
ipin_node_grid_side_[side_manager.to_size_t()].end());
return; return;
} }
/* Reset the RRGSB to pristine state */
void RRGSB::clear() { void RRGSB::clear() {
/* Clean all the vectors */ /* Clean all the vectors */
assert(validate_num_sides()); assert(validate_num_sides());
@ -1943,18 +2120,10 @@ bool RRGSB::is_sb_node_mirror(const RRGSB& cand,
/* Ensure rr_nodes are either the output of short-connection or multiplexer */ /* Ensure rr_nodes are either the output of short-connection or multiplexer */
t_rr_node* node = this->get_chan_node(node_side, track_id); t_rr_node* node = this->get_chan_node(node_side, track_id);
t_rr_node* cand_node = cand.get_chan_node(node_side, track_id); t_rr_node* cand_node = cand.get_chan_node(node_side, track_id);
bool is_short_conkt = this->is_sb_node_imply_short_connection(node); bool is_short_conkt = this->is_sb_node_passing_wire(node_side, track_id);
if (is_short_conkt != cand.is_sb_node_imply_short_connection(cand_node)) { if (is_short_conkt != cand.is_sb_node_passing_wire(node_side, track_id)) {
return false; return false;
}
/* Find the driving rr_node in this sb */
if (true == is_short_conkt) {
/* Ensure we have the same track id for the driving nodes */
if ( this->is_sb_node_exist_opposite_side(node, node_side)
!= cand.is_sb_node_exist_opposite_side(cand_node, node_side)) {
return false;
}
} else { /* check driving rr_nodes */ } else { /* check driving rr_nodes */
if ( node->num_drive_rr_nodes != cand_node->num_drive_rr_nodes ) { if ( node->num_drive_rr_nodes != cand_node->num_drive_rr_nodes ) {
return false; return false;
@ -2049,7 +2218,7 @@ size_t RRGSB::get_track_id_first_short_connection(enum e_side node_side) const {
/* Walk through chan_nodes and find the first short connection */ /* Walk through chan_nodes and find the first short connection */
for (size_t inode = 0; inode < get_chan_width(node_side); ++inode) { for (size_t inode = 0; inode < get_chan_width(node_side); ++inode) {
if (true == is_sb_node_imply_short_connection(get_chan_node(node_side, inode))) { if (true == is_sb_node_passing_wire(node_side, inode)) {
return inode; return inode;
} }
} }
@ -2882,3 +3051,6 @@ bool DeviceRRGSB::validate_cb_type(t_rr_type cb_type) const {
return false; return false;
} }
/************************************************************************
* End of file : rr_blocks.cpp
***********************************************************************/

View File

@ -84,6 +84,7 @@ class RRChan {
int get_node_segment(size_t track_num) const; int get_node_segment(size_t track_num) const;
bool is_mirror(const RRChan& cand) const; /* evaluate if two RR_chan is mirror to each other */ bool is_mirror(const RRChan& cand) const; /* evaluate if two RR_chan is mirror to each other */
std::vector<size_t> get_segment_ids() const; /* Get a list of segments used in this routing channel */ std::vector<size_t> get_segment_ids() const; /* Get a list of segments used in this routing channel */
std::vector<size_t> get_node_ids_by_segment_ids(size_t seg_id) const; /* Get a list of segments used in this routing channel */
public: /* Mutators */ public: /* Mutators */
void set(const RRChan&); /* copy */ void set(const RRChan&); /* copy */
void set_type(t_rr_type type); /* modify type */ void set_type(t_rr_type type); /* modify type */
@ -188,6 +189,8 @@ class RRGSB {
size_t get_max_chan_width() const; /* Get the maximum number of routing tracks on all sides */ size_t get_max_chan_width() const; /* Get the maximum number of routing tracks on all sides */
enum PORTS get_chan_node_direction(enum e_side side, size_t track_id) const; /* Get the direction of a rr_node at a given side and track_id */ enum PORTS get_chan_node_direction(enum e_side side, size_t track_id) const; /* Get the direction of a rr_node at a given side and track_id */
RRChan get_chan(enum e_side side) const; /* get a rr_node at a given side and track_id */ RRChan get_chan(enum e_side side) const; /* get a rr_node at a given side and track_id */
std::vector<size_t> get_chan_segment_ids(enum e_side side) const; /* Get a list of segments used in this routing channel */
std::vector<size_t> get_chan_node_ids_by_segment_ids(enum e_side side, size_t seg_id) const; /* Get a list of segments used in this routing channel */
t_rr_node* get_chan_node(enum e_side side, size_t track_id) const; /* get a rr_node at a given side and track_id */ t_rr_node* get_chan_node(enum e_side side, size_t track_id) const; /* get a rr_node at a given side and track_id */
size_t get_chan_node_segment(enum e_side side, size_t track_id) const; /* get the segment id of a channel rr_node */ size_t get_chan_node_segment(enum e_side side, size_t track_id) const; /* get the segment id of a channel rr_node */
size_t get_num_ipin_nodes(enum e_side side) const; /* Get the number of IPIN rr_nodes on a side */ size_t get_num_ipin_nodes(enum e_side side) const; /* Get the number of IPIN rr_nodes on a side */
@ -216,7 +219,7 @@ class RRGSB {
size_t get_cb_num_conf_bits(t_rr_type cb_type) const; size_t get_cb_num_conf_bits(t_rr_type cb_type) const;
size_t get_cb_conf_bits_lsb(t_rr_type cb_type) const; size_t get_cb_conf_bits_lsb(t_rr_type cb_type) const;
size_t get_cb_conf_bits_msb(t_rr_type cb_type) const; size_t get_cb_conf_bits_msb(t_rr_type cb_type) const;
bool is_sb_node_imply_short_connection(t_rr_node* src_node) const; /* Check if the node imply a short connection inside the SB, which happens to long wires across a FPGA fabric */ bool is_sb_node_passing_wire(const enum e_side node_side, const size_t track_id) const; /* Check if the node imply a short connection inside the SB, which happens to long wires across a FPGA fabric */
bool is_sb_side_mirror(const RRGSB& cand, enum e_side side) const; /* check if a side of candidate SB is a mirror of the current one */ bool is_sb_side_mirror(const RRGSB& cand, enum e_side side) const; /* check if a side of candidate SB is a mirror of the current one */
bool is_sb_side_segment_mirror(const RRGSB& cand, enum e_side side, size_t seg_id) const; /* check if all the routing segments of a side of candidate SB is a mirror of the current one */ bool is_sb_side_segment_mirror(const RRGSB& cand, enum e_side side, size_t seg_id) const; /* check if all the routing segments of a side of candidate SB is a mirror of the current one */
bool is_sb_mirror(const RRGSB& cand) const; /* check if the candidate SB is a mirror of the current one */ bool is_sb_mirror(const RRGSB& cand) const; /* check if the candidate SB is a mirror of the current one */
@ -225,6 +228,8 @@ class RRGSB {
bool is_cb_exist(t_rr_type cb_type) const; /* check if the candidate SB is a mirror of the current one */ bool is_cb_exist(t_rr_type cb_type) const; /* check if the candidate SB is a mirror of the current one */
size_t get_hint_rotate_offset(const RRGSB& cand) const; /* Determine an initial offset in rotating the candidate Switch Block to find a mirror matching*/ size_t get_hint_rotate_offset(const RRGSB& cand) const; /* Determine an initial offset in rotating the candidate Switch Block to find a mirror matching*/
public: /* Cooridinator conversion and output */ public: /* Cooridinator conversion and output */
size_t get_x() const; /* get the x coordinator of this switch block */
size_t get_y() const; /* get the y coordinator of this switch block */
size_t get_sb_x() const; /* get the x coordinator of this switch block */ size_t get_sb_x() const; /* get the x coordinator of this switch block */
size_t get_sb_y() const; /* get the y coordinator of this switch block */ size_t get_sb_y() const; /* get the y coordinator of this switch block */
DeviceCoordinator get_sb_coordinator() const; /* Get the coordinator of the SB */ DeviceCoordinator get_sb_coordinator() const; /* Get the coordinator of the SB */
@ -232,8 +237,12 @@ class RRGSB {
size_t get_cb_y(t_rr_type cb_type) const; /* get the y coordinator of this X/Y-direction block */ size_t get_cb_y(t_rr_type cb_type) const; /* get the y coordinator of this X/Y-direction block */
DeviceCoordinator get_cb_coordinator(t_rr_type cb_type) const; /* Get the coordinator of the X/Y-direction CB */ DeviceCoordinator get_cb_coordinator(t_rr_type cb_type) const; /* Get the coordinator of the X/Y-direction CB */
enum e_side get_cb_chan_side(t_rr_type cb_type) const; /* get the side of a Connection block */ enum e_side get_cb_chan_side(t_rr_type cb_type) const; /* get the side of a Connection block */
enum e_side get_cb_chan_side(enum e_side ipin_side) const; /* get the side of a Connection block */
DeviceCoordinator get_side_block_coordinator(enum e_side side) const; DeviceCoordinator get_side_block_coordinator(enum e_side side) const;
DeviceCoordinator get_grid_coordinator() const;
public: /* Verilog writer */ public: /* Verilog writer */
const char* gen_gsb_verilog_module_name() const;
const char* gen_gsb_verilog_instance_name() const;
const char* gen_sb_verilog_module_name() const; const char* gen_sb_verilog_module_name() const;
const char* gen_sb_verilog_instance_name() const; const char* gen_sb_verilog_instance_name() const;
const char* gen_sb_verilog_side_module_name(enum e_side side, size_t seg_id) const; const char* gen_sb_verilog_side_module_name(enum e_side side, size_t seg_id) const;
@ -246,8 +255,8 @@ class RRGSB {
void set_coordinator(size_t x, size_t y); void set_coordinator(size_t x, size_t y);
void init_num_sides(size_t num_sides); /* Allocate the vectors with the given number of sides */ void init_num_sides(size_t num_sides); /* Allocate the vectors with the given number of sides */
void add_chan_node(enum e_side node_side, RRChan& rr_chan, std::vector<enum PORTS> rr_chan_dir); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ void add_chan_node(enum e_side node_side, RRChan& rr_chan, std::vector<enum PORTS> rr_chan_dir); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */
void add_ipin_node(t_rr_node* node, enum e_side node_side, enum e_side grid_side); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ void add_ipin_node(t_rr_node* node, const enum e_side node_side, const enum e_side grid_side); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */
void add_opin_node(t_rr_node* node, enum e_side node_side, enum e_side grid_side); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ void add_opin_node(t_rr_node* node, const enum e_side node_side, const enum e_side grid_side); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */
void set_sb_num_reserved_conf_bits(size_t num_reserved_conf_bits); void set_sb_num_reserved_conf_bits(size_t num_reserved_conf_bits);
void set_sb_conf_bits_lsb(size_t conf_bits_lsb); void set_sb_conf_bits_lsb(size_t conf_bits_lsb);
void set_sb_conf_bits_msb(size_t conf_bits_msb); void set_sb_conf_bits_msb(size_t conf_bits_msb);

View File

@ -11,10 +11,10 @@
#include "write_rr_blocks.h" #include "write_rr_blocks.h"
void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb) { void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_gsb) {
/* Prepare file name */ /* Prepare file name */
std::string fname(fname_prefix); std::string fname(fname_prefix);
fname += rr_sb.gen_sb_verilog_module_name(); fname += rr_gsb.gen_gsb_verilog_module_name();
fname += ".xml"; fname += ".xml";
vpr_printf(TIO_MESSAGE_INFO, "Output SB XML: %s\r", fname.c_str()); vpr_printf(TIO_MESSAGE_INFO, "Output SB XML: %s\r", fname.c_str());
@ -25,30 +25,67 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb) {
fp.open(fname, std::fstream::out | std::fstream::trunc); fp.open(fname, std::fstream::out | std::fstream::trunc);
/* Output location of the Switch Block */ /* Output location of the Switch Block */
fp << "<rr_sb x=\"" << rr_sb.get_sb_x() << "\" y=\"" << rr_sb.get_sb_y() << "\"" fp << "<rr_gsb x=\"" << rr_gsb.get_x() << "\" y=\"" << rr_gsb.get_y() << "\""
<< " num_sides=\"" << rr_sb.get_num_sides() << "\">" << std::endl; << " num_sides=\"" << rr_gsb.get_num_sides() << "\">" << std::endl;
/* Output each side */ /* Output each side */
for (size_t side = 0; side < rr_sb.get_num_sides(); ++side) { for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) {
Side side_manager(side); Side gsb_side_manager(side);
enum e_side gsb_side = gsb_side_manager.get_side();
/* Output IPIN nodes */
for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(gsb_side); ++inode) {
t_rr_node* cur_rr_node = rr_gsb.get_ipin_node(gsb_side, inode);
/* General information of this IPIN */
fp << "\t<" << rr_node_typename[cur_rr_node->type]
<< " side=\"" << gsb_side_manager.to_string()
<< "\" index=\"" << inode
<< "\" mux_size=\"" << cur_rr_node->num_drive_rr_nodes
<< "\">"
<< std::endl;
/* General information of each driving nodes */
for (int jnode = 0; jnode < cur_rr_node->num_drive_rr_nodes; ++jnode) {
enum e_side chan_side = rr_gsb.get_cb_chan_side(gsb_side);
Side chan_side_manager(chan_side);
/* For channel node, we do not know the node direction
* But we are pretty sure it is either IN_PORT or OUT_PORT
* So we just try and find what is valid
*/
int drive_node_index = rr_gsb.get_chan_node_index(chan_side, cur_rr_node->drive_rr_nodes[jnode]);
/* We must have a valide node index */
assert (-1 != drive_node_index);
size_t des_segment_id = rr_gsb.get_chan_node_segment(chan_side, drive_node_index);
fp << "\t\t<driver_node type=\"" << rr_node_typename[cur_rr_node->drive_rr_nodes[jnode]->type]
<< "\" side=\"" << chan_side_manager.to_string()
<< "\" index=\"" << drive_node_index
<< "\" segment_id=\"" << des_segment_id
<< "\"/>"
<< std::endl;
}
fp << "\t</" << rr_node_typename[cur_rr_node->type]
<< ">"
<< std::endl;
}
/* Output chan nodes */ /* Output chan nodes */
for (size_t inode = 0; inode < rr_sb.get_chan_width(side_manager.get_side()); ++inode) { for (size_t inode = 0; inode < rr_gsb.get_chan_width(gsb_side); ++inode) {
/* We only care OUT_PORT */ /* We only care OUT_PORT */
if (OUT_PORT != rr_sb.get_chan_node_direction(side_manager.get_side(), inode)) { if (OUT_PORT != rr_gsb.get_chan_node_direction(gsb_side, inode)) {
continue; continue;
} }
/* Output drivers */ /* Output drivers */
size_t num_drive_rr_nodes = 0; size_t num_drive_rr_nodes = 0;
t_rr_node** drive_rr_nodes = 0; t_rr_node** drive_rr_nodes = 0;
t_rr_node* cur_rr_node = rr_sb.get_chan_node(side_manager.get_side(), inode); t_rr_node* cur_rr_node = rr_gsb.get_chan_node(gsb_side, inode);
/* Output node information: location, index, side */ /* Output node information: location, index, side */
size_t src_segment_id = rr_sb.get_chan_node_segment(side_manager.get_side(), inode); size_t src_segment_id = rr_gsb.get_chan_node_segment(gsb_side, inode);
/* Check if this node is directly connected to the node on the opposite side */ /* Check if this node is directly connected to the node on the opposite side */
if (true == rr_sb.is_sb_node_imply_short_connection(cur_rr_node)) { if (true == rr_gsb.is_sb_node_passing_wire(gsb_side, inode)) {
/* Double check if the interc lies inside a channel wire, that is interc between segments */
assert(true == rr_sb.is_sb_node_exist_opposite_side(cur_rr_node, side_manager.get_side()));
num_drive_rr_nodes = 0; num_drive_rr_nodes = 0;
drive_rr_nodes = NULL; drive_rr_nodes = NULL;
} else { } else {
@ -56,8 +93,8 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb) {
drive_rr_nodes = cur_rr_node->drive_rr_nodes; drive_rr_nodes = cur_rr_node->drive_rr_nodes;
} }
fp << "\t<" << convert_chan_type_to_string(cur_rr_node->type) fp << "\t<" << rr_node_typename[cur_rr_node->type]
<< " side=\"" << side_manager.to_string() << " side=\"" << gsb_side_manager.to_string()
<< "\" index=\"" << inode << "\" index=\"" << inode
<< "\" segment_id=\"" << src_segment_id << "\" segment_id=\"" << src_segment_id
<< "\" mux_size=\"" << num_drive_rr_nodes << "\" mux_size=\"" << num_drive_rr_nodes
@ -66,10 +103,10 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb) {
/* Direct connection: output the node on the opposite side */ /* Direct connection: output the node on the opposite side */
if (0 == num_drive_rr_nodes) { if (0 == num_drive_rr_nodes) {
Side oppo_side = side_manager.get_opposite(); Side oppo_side = gsb_side_manager.get_opposite();
fp << "\t\t<driver_node type=\"" << convert_chan_type_to_string(cur_rr_node->type) fp << "\t\t<driver_node type=\"" << rr_node_typename[cur_rr_node->type]
<< "\" side=\"" << oppo_side.to_string() << "\" side=\"" << oppo_side.to_string()
<< "\" index=\"" << rr_sb.get_node_index(cur_rr_node, oppo_side.get_side(), IN_PORT) << "\" index=\"" << rr_gsb.get_node_index(cur_rr_node, oppo_side.get_side(), IN_PORT)
<< "\" segment_id=\"" << src_segment_id << "\" segment_id=\"" << src_segment_id
<< "\"/>" << "\"/>"
<< std::endl; << std::endl;
@ -77,22 +114,22 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb) {
for (size_t jnode = 0; jnode < num_drive_rr_nodes; ++jnode) { for (size_t jnode = 0; jnode < num_drive_rr_nodes; ++jnode) {
enum e_side drive_node_side = NUM_SIDES; enum e_side drive_node_side = NUM_SIDES;
int drive_node_index = -1; int drive_node_index = -1;
rr_sb.get_node_side_and_index(drive_rr_nodes[jnode], IN_PORT, &drive_node_side, &drive_node_index); rr_gsb.get_node_side_and_index(drive_rr_nodes[jnode], IN_PORT, &drive_node_side, &drive_node_index);
if (-1 == drive_node_index)
assert(-1 != drive_node_index);
Side drive_side(drive_node_side); Side drive_side(drive_node_side);
std::string node_type_str;
if (OPIN == drive_rr_nodes[jnode]->type) { if (OPIN == drive_rr_nodes[jnode]->type) {
node_type_str = "opin"; Side grid_side(rr_gsb.get_opin_node_grid_side(drive_node_side, drive_node_index));
Side grid_side(rr_sb.get_opin_node_grid_side(drive_node_side, drive_node_index)); fp << "\t\t<driver_node type=\"" << rr_node_typename[OPIN]
fp << "\t\t<driver_node type=\"" << node_type_str
<< "\" side=\"" << drive_side.to_string() << "\" side=\"" << drive_side.to_string()
<< "\" index=\"" << drive_node_index << "\" index=\"" << drive_node_index
<< "\" grid_side=\"" << grid_side.to_string() << "\" grid_side=\"" << grid_side.to_string()
<<"\"/>" <<"\"/>"
<< std::endl; << std::endl;
} else { } else {
node_type_str = convert_chan_type_to_string(drive_rr_nodes[jnode]->type); size_t des_segment_id = rr_gsb.get_chan_node_segment(drive_node_side, drive_node_index);
size_t des_segment_id = rr_sb.get_chan_node_segment(drive_node_side, drive_node_index); fp << "\t\t<driver_node type=\"" << rr_node_typename[drive_rr_nodes[jnode]->type]
fp << "\t\t<driver_node type=\"" << node_type_str
<< "\" side=\"" << drive_side.to_string() << "\" side=\"" << drive_side.to_string()
<< "\" index=\"" << drive_node_index << "\" index=\"" << drive_node_index
<< "\" segment_id=\"" << des_segment_id << "\" segment_id=\"" << des_segment_id
@ -107,7 +144,7 @@ void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb) {
} }
} }
fp << "</rr_sb>" fp << "</rr_gsb>"
<< std::endl; << std::endl;
/* close a file */ /* close a file */
@ -130,8 +167,8 @@ void write_device_rr_gsb_to_xml(char* sb_xml_dir,
/* For each switch block, an XML file will be outputted */ /* For each switch block, an XML file will be outputted */
for (size_t ix = 0; ix < sb_range.get_x(); ++ix) { for (size_t ix = 0; ix < sb_range.get_x(); ++ix) {
for (size_t iy = 0; iy < sb_range.get_y(); ++iy) { for (size_t iy = 0; iy < sb_range.get_y(); ++iy) {
RRGSB rr_sb = LL_device_rr_gsb.get_gsb(ix, iy); RRGSB rr_gsb = LL_device_rr_gsb.get_gsb(ix, iy);
write_rr_switch_block_to_xml(fname_prefix, rr_sb); write_rr_switch_block_to_xml(fname_prefix, rr_gsb);
} }
} }

View File

@ -1,7 +1,7 @@
#ifndef WRITE_RR_BLOCKS_H #ifndef WRITE_RR_BLOCKS_H
#define WRITE_RR_BLOCKS_H #define WRITE_RR_BLOCKS_H
void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_sb); void write_rr_switch_block_to_xml(std::string fname_prefix, RRGSB& rr_gsb);
void write_device_rr_gsb_to_xml(char* sb_xml_dir, DeviceRRGSB& LL_device_rr_gsb); void write_device_rr_gsb_to_xml(char* sb_xml_dir, DeviceRRGSB& LL_device_rr_gsb);

View File

@ -216,7 +216,7 @@ void fpga_spice_generate_bitstream_switch_box_interc(FILE* fp,
const RRGSB& rr_sb, const RRGSB& rr_sb,
t_sram_orgz_info* cur_sram_orgz_info, t_sram_orgz_info* cur_sram_orgz_info,
enum e_side chan_side, enum e_side chan_side,
t_rr_node* cur_rr_node) { size_t chan_node_id) {
int num_drive_rr_nodes = 0; int num_drive_rr_nodes = 0;
t_rr_node** drive_rr_nodes = NULL; t_rr_node** drive_rr_nodes = NULL;
@ -227,12 +227,12 @@ void fpga_spice_generate_bitstream_switch_box_interc(FILE* fp,
__FILE__, __LINE__); __FILE__, __LINE__);
exit(1); exit(1);
} }
/* Get the rr_node */
t_rr_node* cur_rr_node = rr_sb.get_chan_node(chan_side, chan_node_id);
/* Determine if the interc lies inside a channel wire, that is interc between segments */ /* Determine if the interc lies inside a channel wire, that is interc between segments */
/* Check each num_drive_rr_nodes, see if they appear in the cur_sb_info */ /* Check each num_drive_rr_nodes, see if they appear in the cur_sb_info */
if (true == rr_sb.is_sb_node_imply_short_connection(cur_rr_node)) { if (true == rr_sb.is_sb_node_passing_wire(chan_side, chan_node_id)) {
/* Double check if the interc lies inside a channel wire, that is interc between segments */
assert(true == rr_sb.is_sb_node_exist_opposite_side(cur_rr_node, chan_side));
num_drive_rr_nodes = 0; num_drive_rr_nodes = 0;
drive_rr_nodes = NULL; drive_rr_nodes = NULL;
} else { } else {
@ -364,7 +364,7 @@ void fpga_spice_generate_bitstream_routing_switch_box_subckt(FILE* fp,
if (OUT_PORT == rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)) { if (OUT_PORT == rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)) {
fpga_spice_generate_bitstream_switch_box_interc(fp, rr_sb, cur_sram_orgz_info, fpga_spice_generate_bitstream_switch_box_interc(fp, rr_sb, cur_sram_orgz_info,
side_manager.get_side(), side_manager.get_side(),
rr_sb.get_chan_node(side_manager.get_side(), itrack)); itrack);
} }
} }
} }

View File

@ -255,15 +255,14 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup,
/* Dump routing resources: switch blocks, connection blocks and channel tracks */ /* Dump routing resources: switch blocks, connection blocks and channel tracks */
dump_verilog_routing_resources(sram_verilog_orgz_info, src_dir_path, rr_dir_path, Arch, &vpr_setup.RoutingArch, dump_verilog_routing_resources(sram_verilog_orgz_info, src_dir_path, rr_dir_path, Arch, &vpr_setup.RoutingArch,
num_rr_nodes, rr_node, rr_node_indices, rr_indexed_data, num_rr_nodes, rr_node, rr_node_indices, rr_indexed_data,
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts, vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy); vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy);
/* Dump logic blocks /* Dump logic blocks
* Branches to go: * Branches to go:
* 1. a compact output * 1. a compact output
* 2. a full-size output * 2. a full-size output
*/ */
dump_compact_verilog_logic_blocks(sram_verilog_orgz_info, src_dir_path, lb_dir_path, &Arch, dump_compact_verilog_logic_blocks(sram_verilog_orgz_info, src_dir_path, lb_dir_path, &Arch);
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts);
/* Dump internal structures of submodules */ /* Dump internal structures of submodules */
dump_verilog_submodules(sram_verilog_orgz_info, src_dir_path, submodule_dir_path, dump_verilog_submodules(sram_verilog_orgz_info, src_dir_path, submodule_dir_path,
@ -275,7 +274,6 @@ void vpr_fpga_verilog(t_vpr_setup vpr_setup,
top_netlist_path, src_dir_path, submodule_dir_path, lb_dir_path, rr_dir_path, top_netlist_path, src_dir_path, submodule_dir_path, lb_dir_path, rr_dir_path,
num_rr_nodes, rr_node, rr_node_indices, num_rr_nodes, rr_node, rr_node_indices,
num_clocks, num_clocks,
vpr_setup.FPGA_SPICE_Opts.SynVerilogOpts,
vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy, vpr_setup.FPGA_SPICE_Opts.compact_routing_hierarchy,
*(Arch.spice)); *(Arch.spice));

View File

@ -281,9 +281,7 @@ void dump_compact_verilog_one_physical_block(t_sram_orgz_info* cur_sram_orgz_inf
char* verilog_dir_path, char* verilog_dir_path,
char* subckt_dir_path, char* subckt_dir_path,
t_type_ptr phy_block_type, t_type_ptr phy_block_type,
int border_side, int border_side) {
t_arch* arch,
t_syn_verilog_opts fpga_verilog_opts) {
int iz; int iz;
int temp_reserved_conf_bits_msb; int temp_reserved_conf_bits_msb;
int temp_iopad_lsb, temp_iopad_msb; int temp_iopad_lsb, temp_iopad_msb;
@ -514,8 +512,7 @@ void dump_compact_verilog_one_physical_block(t_sram_orgz_info* cur_sram_orgz_inf
void dump_compact_verilog_logic_blocks(t_sram_orgz_info* cur_sram_orgz_info, void dump_compact_verilog_logic_blocks(t_sram_orgz_info* cur_sram_orgz_info,
char* verilog_dir, char* verilog_dir,
char* subckt_dir, char* subckt_dir,
t_arch* arch, t_arch* arch) {
t_syn_verilog_opts fpga_verilog_opts) {
int itype, iside, num_sides; int itype, iside, num_sides;
int* stamped_spice_model_cnt = NULL; int* stamped_spice_model_cnt = NULL;
t_sram_orgz_info* stamped_sram_orgz_info = NULL; t_sram_orgz_info* stamped_sram_orgz_info = NULL;
@ -537,23 +534,20 @@ void dump_compact_verilog_logic_blocks(t_sram_orgz_info* cur_sram_orgz_info,
for (iside = 0; iside < num_sides; iside++) { for (iside = 0; iside < num_sides; iside++) {
dump_compact_verilog_one_physical_block(cur_sram_orgz_info, dump_compact_verilog_one_physical_block(cur_sram_orgz_info,
verilog_dir, subckt_dir, verilog_dir, subckt_dir,
&type_descriptors[itype], iside, &type_descriptors[itype], iside);
arch, fpga_verilog_opts);
} }
continue; continue;
} else if (FILL_TYPE == &type_descriptors[itype]) { } else if (FILL_TYPE == &type_descriptors[itype]) {
/* For CLB */ /* For CLB */
dump_compact_verilog_one_physical_block(cur_sram_orgz_info, dump_compact_verilog_one_physical_block(cur_sram_orgz_info,
verilog_dir, subckt_dir, verilog_dir, subckt_dir,
&type_descriptors[itype], -1, &type_descriptors[itype], -1);
arch, fpga_verilog_opts);
continue; continue;
} else { } else {
/* For heterogenenous blocks */ /* For heterogenenous blocks */
dump_compact_verilog_one_physical_block(cur_sram_orgz_info, dump_compact_verilog_one_physical_block(cur_sram_orgz_info,
verilog_dir, subckt_dir, verilog_dir, subckt_dir,
&type_descriptors[itype], -1, &type_descriptors[itype], -1);
arch, fpga_verilog_opts);
} }
} }
@ -975,7 +969,7 @@ void dump_compact_verilog_defined_one_connection_box(t_sram_orgz_info* cur_sram_
static static
void dump_compact_verilog_defined_connection_boxes(t_sram_orgz_info* cur_sram_orgz_info, void dump_compact_verilog_defined_connection_boxes(t_sram_orgz_info* cur_sram_orgz_info,
FILE* fp) { FILE* fp) {
int ix, iy; DeviceCoordinator sb_range = device_rr_gsb.get_gsb_range();
/* Check the file handler*/ /* Check the file handler*/
if (NULL == fp) { if (NULL == fp) {
@ -984,21 +978,23 @@ void dump_compact_verilog_defined_connection_boxes(t_sram_orgz_info* cur_sram_or
exit(1); exit(1);
} }
/* X - channels [1...nx][0..ny]*/ /* Walk through GSBs */
for (iy = 0; iy < (ny + 1); iy++) { for (size_t ix = 0; ix < sb_range.get_x(); ++ix) {
for (ix = 1; ix < (nx + 1); ix++) { for (size_t iy = 0; iy < sb_range.get_y(); ++iy) {
const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy); const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy);
if ((TRUE == is_cb_exist(CHANX, ix, iy))
/* Get X-channel CB coordinator */
const DeviceCoordinator cbx_coordinator = rr_gsb.get_cb_coordinator(CHANX);
/* X - channels [1...nx][0..ny]*/
if ((TRUE == is_cb_exist(CHANX, cbx_coordinator.get_x(), cbx_coordinator.get_x()))
&&(true == rr_gsb.is_cb_exist(CHANX))) { &&(true == rr_gsb.is_cb_exist(CHANX))) {
dump_compact_verilog_defined_one_connection_box(cur_sram_orgz_info, fp, rr_gsb, CHANX); dump_compact_verilog_defined_one_connection_box(cur_sram_orgz_info, fp, rr_gsb, CHANX);
} }
}
} /* Get X-channel CB coordinator */
const DeviceCoordinator cby_coordinator = rr_gsb.get_cb_coordinator(CHANY);
/* Y - channels [1...ny][0..nx]*/ /* Y - channels [1...ny][0..nx]*/
for (ix = 0; ix < (nx + 1); ix++) { if ((TRUE == is_cb_exist(CHANY, cby_coordinator.get_x(), cby_coordinator.get_x()))
for (iy = 1; iy < (ny + 1); iy++) {
const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy);
if ((TRUE == is_cb_exist(CHANY, ix, iy))
&&(true == rr_gsb.is_cb_exist(CHANY))) { &&(true == rr_gsb.is_cb_exist(CHANY))) {
dump_compact_verilog_defined_one_connection_box(cur_sram_orgz_info, fp, rr_gsb, CHANY); dump_compact_verilog_defined_one_connection_box(cur_sram_orgz_info, fp, rr_gsb, CHANY);
} }
@ -1180,7 +1176,6 @@ void dump_compact_verilog_top_netlist(t_sram_orgz_info* cur_sram_orgz_info,
t_rr_node* LL_rr_node, t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices, t_ivec*** LL_rr_node_indices,
int num_clock, int num_clock,
t_syn_verilog_opts fpga_verilog_opts,
boolean compact_routing_hierarchy, boolean compact_routing_hierarchy,
t_spice verilog) { t_spice verilog) {
FILE* fp = NULL; FILE* fp = NULL;

View File

@ -5,15 +5,12 @@ void dump_compact_verilog_one_physical_block(t_sram_orgz_info* cur_sram_orgz_inf
char* verilog_dir_path, char* verilog_dir_path,
char* subckt_dir_path, char* subckt_dir_path,
t_type_ptr phy_block_type, t_type_ptr phy_block_type,
int border_side, int border_side);
t_arch* arch,
t_syn_verilog_opts fpga_verilog_opts);
void dump_compact_verilog_logic_blocks(t_sram_orgz_info* cur_sram_orgz_info, void dump_compact_verilog_logic_blocks(t_sram_orgz_info* cur_sram_orgz_info,
char* verilog_dir, char* verilog_dir,
char* subckt_dir, char* subckt_dir,
t_arch* arch, t_arch* arch);
t_syn_verilog_opts fpga_verilog_opts);
void dump_compact_verilog_top_netlist(t_sram_orgz_info* cur_sram_orgz_info, void dump_compact_verilog_top_netlist(t_sram_orgz_info* cur_sram_orgz_info,
char* circuit_name, char* circuit_name,
@ -26,7 +23,6 @@ void dump_compact_verilog_top_netlist(t_sram_orgz_info* cur_sram_orgz_info,
t_rr_node* LL_rr_node, t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices, t_ivec*** LL_rr_node_indices,
int num_clock, int num_clock,
t_syn_verilog_opts fpga_verilog_opts,
boolean compact_routing_hierarchy, boolean compact_routing_hierarchy,
t_spice verilog); t_spice verilog);
#endif #endif

View File

@ -2765,7 +2765,7 @@ void verilog_generate_routing_wires_report_timing(FILE* fp,
||(CHANY == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type)); ||(CHANY == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type));
/* We only care the output port and it should indicate a SB mux */ /* We only care the output port and it should indicate a SB mux */
if ( (OUT_PORT != rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)) if ( (OUT_PORT != rr_sb.get_chan_node_direction(side_manager.get_side(), itrack))
|| (true == rr_sb.is_sb_node_imply_short_connection(rr_sb.get_chan_node(side_manager.get_side(), itrack)))) { || (true == rr_sb.is_sb_node_passing_wire(side_manager.get_side(), itrack))) {
continue; continue;
} }
/* Bypass if we have only 1 driving node */ /* Bypass if we have only 1 driving node */
@ -3170,7 +3170,7 @@ void verilog_generate_routing_wire_report_timing(t_trpt_opts trpt_opts,
||(CHANY == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type)); ||(CHANY == rr_sb.get_chan_node(side_manager.get_side(), itrack)->type));
/* We only care the output port and it should indicate a SB mux */ /* We only care the output port and it should indicate a SB mux */
if ( (OUT_PORT != rr_sb.get_chan_node_direction(side_manager.get_side(), itrack)) if ( (OUT_PORT != rr_sb.get_chan_node_direction(side_manager.get_side(), itrack))
|| (false != rr_sb.is_sb_node_imply_short_connection(rr_sb.get_chan_node(side_manager.get_side(), itrack)))) { || (false != rr_sb.is_sb_node_passing_wire(side_manager.get_side(), itrack))) {
continue; continue;
} }
/* Bypass if we have only 1 driving node */ /* Bypass if we have only 1 driving node */

View File

@ -308,68 +308,6 @@ void dump_verilog_routing_chan_subckt(char* verilog_dir,
return; return;
} }
static
t_rr_node** verilog_get_grid_side_pin_rr_nodes(int* num_pin_rr_nodes,
t_rr_type pin_type,
int x,
int y,
int side,
t_ivec*** LL_rr_node_indices) {
int height, ipin, class_id, inode;
t_type_ptr type = NULL;
t_rr_node** ret = NULL;
enum e_pin_type pin_class_type;
int cur;
/* Check */
assert((!(0 > x))&&(!(x > (nx + 1))));
assert((!(0 > y))&&(!(y > (ny + 1))));
type = grid[x][y].type;
assert(NULL != type);
/* Assign the type of PIN*/
switch (pin_type) {
case IPIN:
/* case SINK: */
pin_class_type = RECEIVER; /* This is the end of a route path*/
break;
/*case SOURCE:*/
case OPIN:
pin_class_type = DRIVER; /* This is the start of a route path */
break;
/* SINK and SOURCE are hypothesis nodes */
default:
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid pin_type!\n", __FILE__, __LINE__);
exit(1);
}
/* Output the pins on the side*/
(*num_pin_rr_nodes) = 0;
height = grid[x][y].offset;
for (ipin = 0; ipin < type->num_pins; ipin++) {
class_id = type->pin_class[ipin];
if ((1 == type->pinloc[height][side][ipin])&&(pin_class_type == type->class_inf[class_id].type)) {
(*num_pin_rr_nodes)++;
}
}
/* Malloc */
ret = (t_rr_node**)my_malloc(sizeof(t_rr_node*)*(*num_pin_rr_nodes));
/* Fill the return array*/
cur = 0;
height = grid[x][y].offset;
for (ipin = 0; ipin < type->num_pins; ipin++) {
class_id = type->pin_class[ipin];
if ((1 == type->pinloc[height][side][ipin])&&(pin_class_type == type->class_inf[class_id].type)) {
inode = get_rr_node_index(x, y, pin_type, ipin, LL_rr_node_indices);
ret[cur] = &(rr_node[inode]);
cur++;
}
}
assert(cur == (*num_pin_rr_nodes));
return ret;
}
void dump_verilog_grid_side_pin_with_given_index(FILE* fp, t_rr_type pin_type, void dump_verilog_grid_side_pin_with_given_index(FILE* fp, t_rr_type pin_type,
int pin_index, int side, int pin_index, int side,
int x, int y, int x, int y,
@ -489,142 +427,6 @@ void dump_verilog_grid_side_pins(FILE* fp,
return; return;
} }
/* Determine the channel coordinates in switch box subckt */
static
void verilog_determine_src_chan_coordinate_switch_box(t_rr_node* src_rr_node,
t_rr_node* des_rr_node,
int side,
int switch_box_x,
int switch_box_y,
int* src_chan_x,
int* src_chan_y,
char** src_chan_port_name) {
/* Check */
assert((!(0 > side))&&(side < 4));
assert((CHANX == src_rr_node->type)||(CHANY == src_rr_node->type));
assert((CHANX == des_rr_node->type)||(CHANY == des_rr_node->type));
assert((!(0 > switch_box_x))&&(!(switch_box_x > (nx + 1))));
assert((!(0 > switch_box_y))&&(!(switch_box_y > (ny + 1))));
/* Initialize*/
(*src_chan_x) = 0;
(*src_chan_y) = 0;
(*src_chan_port_name) = NULL;
switch (side) {
case 0: /*TOP*/
/* The destination rr_node only have one condition!!! */
assert((INC_DIRECTION == des_rr_node->direction)&&(CHANY == des_rr_node->type));
/* Following cases:
* |
* / | \
*/
if ((INC_DIRECTION == src_rr_node->direction)&&(CHANY == src_rr_node->type)) {
(*src_chan_x) = switch_box_x;
(*src_chan_y) = switch_box_y;
(*src_chan_port_name) = "in";
} else if ((INC_DIRECTION == src_rr_node->direction)&&(CHANX == src_rr_node->type)) {
(*src_chan_x) = switch_box_x;
(*src_chan_y) = switch_box_y;
(*src_chan_port_name) = "in";
} else if ((DEC_DIRECTION == src_rr_node->direction)&&(CHANX == src_rr_node->type)) {
(*src_chan_x) = switch_box_x + 1;
(*src_chan_y) = switch_box_y;
(*src_chan_port_name) = "in";
} else {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid source channel!\n", __FILE__, __LINE__);
exit(1);
}
break;
case 1: /*RIGHT*/
/* The destination rr_node only have one condition!!! */
assert((INC_DIRECTION == des_rr_node->direction)&&(CHANX == des_rr_node->type));
/* Following cases:
* \
* --- ----
* /
*/
if ((DEC_DIRECTION == src_rr_node->direction)&&(CHANY == src_rr_node->type)) {
(*src_chan_x) = switch_box_x;
(*src_chan_y) = switch_box_y + 1;
(*src_chan_port_name) = "in";
} else if ((INC_DIRECTION == src_rr_node->direction)&&(CHANX == src_rr_node->type)) {
(*src_chan_x) = switch_box_x;
(*src_chan_y) = switch_box_y;
(*src_chan_port_name) = "in";
} else if ((INC_DIRECTION == src_rr_node->direction)&&(CHANY == src_rr_node->type)) {
(*src_chan_x) = switch_box_x;
(*src_chan_y) = switch_box_y;
(*src_chan_port_name) = "in";
} else {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid source channel!\n", __FILE__, __LINE__);
exit(1);
}
break;
case 2: /*BOTTOM*/
/* The destination rr_node only have one condition!!! */
assert((DEC_DIRECTION == des_rr_node->direction)&&(CHANY == des_rr_node->type));
/* Following cases:
* |
* \ /
* |
*/
if ((DEC_DIRECTION == src_rr_node->direction)&&(CHANY == src_rr_node->type)) {
(*src_chan_x) = switch_box_x;
(*src_chan_y) = switch_box_y + 1;
(*src_chan_port_name) = "in";
} else if ((INC_DIRECTION == src_rr_node->direction)&&(CHANX == src_rr_node->type)) {
(*src_chan_x) = switch_box_x;
(*src_chan_y) = switch_box_y;
(*src_chan_port_name) = "in";
} else if ((DEC_DIRECTION == src_rr_node->direction)&&(CHANX == src_rr_node->type)) {
(*src_chan_x) = switch_box_x + 1;
(*src_chan_y) = switch_box_y;
(*src_chan_port_name) = "in";
} else {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid source channel!\n", __FILE__, __LINE__);
exit(1);
}
break;
case 3: /*LEFT*/
/* The destination rr_node only have one condition!!! */
assert((DEC_DIRECTION == des_rr_node->direction)&&(CHANX == des_rr_node->type));
/* Following cases:
* /
* --- ----
* \
*/
if ((DEC_DIRECTION == src_rr_node->direction)&&(CHANX == src_rr_node->type)) {
(*src_chan_x) = switch_box_x + 1;
(*src_chan_y) = switch_box_y;
(*src_chan_port_name) = "in";
} else if ((INC_DIRECTION == src_rr_node->direction)&&(CHANY == src_rr_node->type)) {
(*src_chan_x) = switch_box_x;
(*src_chan_y) = switch_box_y;
(*src_chan_port_name) = "in";
} else if ((DEC_DIRECTION == src_rr_node->direction)&&(CHANY == src_rr_node->type)) {
(*src_chan_x) = switch_box_x;
(*src_chan_y) = switch_box_y + 1;
(*src_chan_port_name) = "in";
} else {
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid source channel!\n", __FILE__, __LINE__);
exit(1);
}
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s, [LINE%d])Invalid side!\n", __FILE__, __LINE__);
exit(1);
}
/* Make sure the source rr_node (channel) is in the range*/
assert((!((*src_chan_x) < src_rr_node->xlow))&&(!((*src_chan_x) > src_rr_node->xhigh)));
if (!((!((*src_chan_y) < src_rr_node->ylow))&&(!((*src_chan_y) > src_rr_node->yhigh)))) {
assert((!((*src_chan_y) < src_rr_node->ylow))&&(!((*src_chan_y) > src_rr_node->yhigh)));
}
return;
}
void dump_verilog_switch_box_chan_port(FILE* fp, void dump_verilog_switch_box_chan_port(FILE* fp,
t_sb* cur_sb_info, t_sb* cur_sb_info,
int chan_side, int chan_side,
@ -680,6 +482,7 @@ void dump_verilog_unique_switch_box_chan_port(FILE* fp,
/* Get the index in sb_info of cur_rr_node */ /* Get the index in sb_info of cur_rr_node */
index = rr_sb.get_node_index(cur_rr_node, chan_side, cur_rr_node_direction); index = rr_sb.get_node_index(cur_rr_node, chan_side, cur_rr_node_direction);
/* Make sure this node is included in this sb_info */ /* Make sure this node is included in this sb_info */
if (!((-1 != index)&&(NUM_SIDES != chan_side)))
assert((-1 != index)&&(NUM_SIDES != chan_side)); assert((-1 != index)&&(NUM_SIDES != chan_side));
chan_rr_node_type = cur_rr_node->type; chan_rr_node_type = cur_rr_node->type;
@ -737,9 +540,7 @@ void dump_verilog_unique_switch_box_short_interc(FILE* fp,
if (0 == actual_fan_in) { if (0 == actual_fan_in) {
assert(drive_rr_node == cur_rr_node); assert(drive_rr_node == cur_rr_node);
} else { } else {
Side side_manager(chan_side); assert (1 == actual_fan_in);
/* drive_rr_node = &(rr_node[cur_rr_node->prev_node]); */
assert(1 == rr_node_drive_switch_box(drive_rr_node, cur_rr_node, rr_sb.get_sb_coordinator().get_x(), rr_sb.get_sb_coordinator().get_y(), side_manager.get_side()));
} }
int grid_x = drive_rr_node->xlow; int grid_x = drive_rr_node->xlow;
@ -1581,7 +1382,7 @@ void dump_verilog_unique_switch_box_interc(t_sram_orgz_info* cur_sram_orgz_info,
FILE* fp, FILE* fp,
const RRGSB& rr_sb, const RRGSB& rr_sb,
enum e_side chan_side, enum e_side chan_side,
t_rr_node* cur_rr_node) { size_t chan_node_id) {
int num_drive_rr_nodes = 0; int num_drive_rr_nodes = 0;
t_rr_node** drive_rr_nodes = NULL; t_rr_node** drive_rr_nodes = NULL;
@ -1592,11 +1393,12 @@ void dump_verilog_unique_switch_box_interc(t_sram_orgz_info* cur_sram_orgz_info,
exit(1); exit(1);
} }
/* Get the node */
t_rr_node* cur_rr_node = rr_sb.get_chan_node(chan_side, chan_node_id);
/* Determine if the interc lies inside a channel wire, that is interc between segments */ /* Determine if the interc lies inside a channel wire, that is interc between segments */
/* Check each num_drive_rr_nodes, see if they appear in the cur_sb_info */ /* Check each num_drive_rr_nodes, see if they appear in the cur_sb_info */
if (true == rr_sb.is_sb_node_imply_short_connection(cur_rr_node)) { if (true == rr_sb.is_sb_node_passing_wire(chan_side, chan_node_id)) {
/* Double check if the interc lies inside a channel wire, that is interc between segments */
assert(true == rr_sb.is_sb_node_exist_opposite_side(cur_rr_node, chan_side));
num_drive_rr_nodes = 0; num_drive_rr_nodes = 0;
drive_rr_nodes = NULL; drive_rr_nodes = NULL;
} else { } else {
@ -2072,7 +1874,7 @@ void dump_verilog_routing_switch_box_unique_side_module(t_sram_orgz_info* cur_sr
} }
dump_verilog_unique_switch_box_interc(cur_sram_orgz_info, fp, rr_sb, dump_verilog_unique_switch_box_interc(cur_sram_orgz_info, fp, rr_sb,
side_manager.get_side(), side_manager.get_side(),
rr_sb.get_chan_node(side_manager.get_side(), itrack)); itrack);
} }
} }
@ -2482,7 +2284,7 @@ void dump_verilog_routing_switch_box_unique_subckt(t_sram_orgz_info* cur_sram_or
if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) { if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) {
dump_verilog_unique_switch_box_interc(cur_sram_orgz_info, fp, rr_sb, dump_verilog_unique_switch_box_interc(cur_sram_orgz_info, fp, rr_sb,
side_manager.get_side(), side_manager.get_side(),
rr_gsb.get_chan_node(side_manager.get_side(), itrack)); itrack);
} }
} }
} }
@ -3962,7 +3764,6 @@ void dump_verilog_routing_resources(t_sram_orgz_info* cur_sram_orgz_info,
int LL_num_rr_nodes, t_rr_node* LL_rr_node, int LL_num_rr_nodes, t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices, t_ivec*** LL_rr_node_indices,
t_rr_indexed_data* LL_rr_indexed_data, t_rr_indexed_data* LL_rr_indexed_data,
t_syn_verilog_opts fpga_verilog_opts,
boolean compact_routing_hierarchy) { boolean compact_routing_hierarchy) {
assert(UNI_DIRECTIONAL == routing_arch->directionality); assert(UNI_DIRECTIONAL == routing_arch->directionality);

View File

@ -132,7 +132,6 @@ void dump_verilog_routing_resources(t_sram_orgz_info* cur_sram_orgz_info,
int LL_num_rr_nodes, t_rr_node* LL_rr_node, int LL_num_rr_nodes, t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices, t_ivec*** LL_rr_node_indices,
t_rr_indexed_data* LL_rr_indexed_data, t_rr_indexed_data* LL_rr_indexed_data,
t_syn_verilog_opts fpga_verilog_opts,
boolean compact_routing_hierarchy); boolean compact_routing_hierarchy);
#endif #endif

View File

@ -370,7 +370,7 @@ void verilog_generate_sdc_break_loop_sb(FILE* fp,
||(CHANY == chan_rr_node->type)); ||(CHANY == chan_rr_node->type));
/* We only care the output port and it should indicate a SB mux */ /* We only care the output port and it should indicate a SB mux */
if ( (OUT_PORT != rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) if ( (OUT_PORT != rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack))
|| (false != rr_gsb.is_sb_node_imply_short_connection(chan_rr_node))) { || (false != rr_gsb.is_sb_node_passing_wire(side_manager.get_side(), itrack))) {
continue; continue;
} }
/* Bypass if we have only 1 driving node */ /* Bypass if we have only 1 driving node */
@ -741,7 +741,7 @@ void verilog_generate_sdc_constrain_sbs(t_sdc_opts sdc_opts,
continue; continue;
} }
/* Constrain thru wires */ /* Constrain thru wires */
if (false != rr_gsb.is_sb_node_imply_short_connection(chan_rr_node)) { if (false != rr_gsb.is_sb_node_passing_wire(side_manager.get_side(), itrack)) {
/* Set the max, min delay to 0? */ /* Set the max, min delay to 0? */
verilog_generate_sdc_constrain_one_sb_path(fp, rr_gsb, verilog_generate_sdc_constrain_one_sb_path(fp, rr_gsb,
chan_rr_node, chan_rr_node,
@ -2510,7 +2510,7 @@ void verilog_generate_wire_report_timing_blockage_direction(FILE* fp,
int LL_nx, int LL_ny) { int LL_nx, int LL_ny) {
int ix, iy; int ix, iy;
int side, itrack, inode; int side, itrack;
t_sb* cur_sb_info = NULL; t_sb* cur_sb_info = NULL;

View File

@ -22,16 +22,26 @@ static boolean rr_node_is_global_clb_ipin(int inode);
static void check_pass_transistors(int from_node); static void check_pass_transistors(int from_node);
/************************ Subroutine definitions ****************************/ /************************ Subroutine definitions ****************************/
/****************************************************************************
* Print detailed information of a node to ease debugging
****************************************************************************/
static
void print_rr_node_details(t_rr_node* cur_rr_node) {
vpr_printf(TIO_MESSAGE_INFO,
"\tNode %d details: type=%s, (xlow,ylow)=(%d,%d)->(xhigh,yhigh)=(%d,%d), ptc_num=%d\n",
cur_rr_node - rr_node,
rr_node_typename[cur_rr_node->type],
cur_rr_node->xlow, cur_rr_node->ylow,
cur_rr_node->xhigh, cur_rr_node->yhigh,
cur_rr_node->ptc_num);
return;
}
void check_rr_graph(INP t_graph_type graph_type, INP t_type_ptr types,
INP int L_nx, INP int L_ny, INP int nodes_per_chan, INP int Fs, void check_rr_graph(INP const t_graph_type graph_type,
INP int num_seg_types, INP int num_switches, INP const int L_nx, INP const int L_ny,
INP t_segment_inf * segment_inf, INP int global_route_switch, INP const int num_switches,
INP int delayless_switch, INP int wire_to_ipin_switch, int **Fc_in) {
t_seg_details * seg_details, int **Fc_in, int **Fc_out,
int *****opin_to_track_map, int *****ipin_to_track_map,
t_ivec **** track_to_ipin_lookup, t_ivec *** switch_block_conn,
boolean * perturb_ipins) {
int *num_edges_from_current_to_node; /* [0..num_rr_nodes-1] */ int *num_edges_from_current_to_node; /* [0..num_rr_nodes-1] */
int *total_edges_to_node; /* [0..num_rr_nodes-1] */ int *total_edges_to_node; /* [0..num_rr_nodes-1] */
@ -67,6 +77,8 @@ void check_rr_graph(INP t_graph_type graph_type, INP t_type_ptr types,
if (to_node < 0 || to_node >= num_rr_nodes) { if (to_node < 0 || to_node >= num_rr_nodes) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has an edge %d.\n", inode, to_node); vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has an edge %d.\n", inode, to_node);
print_rr_node_details(&rr_node[inode]);
vpr_printf(TIO_MESSAGE_ERROR, "\tEdge is out of range.\n"); vpr_printf(TIO_MESSAGE_ERROR, "\tEdge is out of range.\n");
exit(1); exit(1);
} }
@ -78,6 +90,7 @@ void check_rr_graph(INP t_graph_type graph_type, INP t_type_ptr types,
if (switch_type < 0 || switch_type >= num_switches) { if (switch_type < 0 || switch_type >= num_switches) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has a switch type %d.\n", inode, switch_type); vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has a switch type %d.\n", inode, switch_type);
print_rr_node_details(&rr_node[inode]);
vpr_printf(TIO_MESSAGE_ERROR, "\tSwitch type is out of range.\n"); vpr_printf(TIO_MESSAGE_ERROR, "\tSwitch type is out of range.\n");
exit(1); exit(1);
} }
@ -99,6 +112,8 @@ void check_rr_graph(INP t_graph_type graph_type, INP t_type_ptr types,
|| (rr_type != CHANX && rr_type != CHANY)) { || (rr_type != CHANX && rr_type != CHANY)) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d connects to node %d %d times.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d connects to node %d %d times.\n",
inode, to_node, num_edges_from_current_to_node[to_node]); inode, to_node, num_edges_from_current_to_node[to_node]);
print_rr_node_details(&rr_node[inode]);
print_rr_node_details(&rr_node[to_node]);
exit(1); exit(1);
} }
@ -109,6 +124,8 @@ void check_rr_graph(INP t_graph_type graph_type, INP t_type_ptr types,
|| switch_types_from_current_to_node[to_node] != BUF_AND_PTRANS_FLAG) { || switch_types_from_current_to_node[to_node] != BUF_AND_PTRANS_FLAG) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d connects to node %d %d times.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d connects to node %d %d times.\n",
inode, to_node, num_edges_from_current_to_node[to_node]); inode, to_node, num_edges_from_current_to_node[to_node]);
print_rr_node_details(&rr_node[inode]);
print_rr_node_details(&rr_node[to_node]);
exit(1); exit(1);
} }
} }
@ -160,10 +177,12 @@ void check_rr_graph(INP t_graph_type graph_type, INP t_type_ptr types,
if (!is_chain && !is_fringe && !is_wire) { if (!is_chain && !is_fringe && !is_wire) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has no fanin.\n", inode); vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: node %d has no fanin.\n", inode);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} else if (!is_chain && !is_fringe_warning_sent) { } else if (!is_chain && !is_fringe_warning_sent) {
vpr_printf(TIO_MESSAGE_WARNING, "in check_rr_graph: fringe node %d has no fanin.\n", inode); vpr_printf(TIO_MESSAGE_WARNING, "in check_rr_graph: fringe node %d has no fanin.\n", inode);
vpr_printf(TIO_MESSAGE_WARNING, "\tThis is possible on the fringe for low Fc_out, N, and certain Lengths\n"); vpr_printf(TIO_MESSAGE_WARNING, "\tThis is possible on the fringe for low Fc_out, N, and certain Lengths\n");
print_rr_node_details(&rr_node[inode]);
is_fringe_warning_sent = TRUE; is_fringe_warning_sent = TRUE;
} }
} }
@ -173,6 +192,7 @@ void check_rr_graph(INP t_graph_type graph_type, INP t_type_ptr types,
if (total_edges_to_node[inode] != 0) { if (total_edges_to_node[inode] != 0) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: SOURCE node %d has a fanin of %d, expected 0.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_rr_graph: SOURCE node %d has a fanin of %d, expected 0.\n",
inode, total_edges_to_node[inode]); inode, total_edges_to_node[inode]);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
} }
@ -227,18 +247,21 @@ void check_node(int inode, enum e_route_type route_type) {
if (xlow > xhigh || ylow > yhigh) { if (xlow > xhigh || ylow > yhigh) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: rr endpoints are (%d,%d) and (%d,%d).\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: rr endpoints are (%d,%d) and (%d,%d).\n",
xlow, ylow, xhigh, yhigh); xlow, ylow, xhigh, yhigh);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
if (xlow < 0 || xhigh > nx + 1 || ylow < 0 || yhigh > ny + 1) { if (xlow < 0 || xhigh > nx + 1 || ylow < 0 || yhigh > ny + 1) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: rr endpoints (%d,%d) and (%d,%d) are out of range.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: rr endpoints (%d,%d) and (%d,%d) are out of range.\n",
xlow, ylow, xhigh, yhigh); xlow, ylow, xhigh, yhigh);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
if (ptc_num < 0) { if (ptc_num < 0) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
inode, rr_type, ptc_num); inode, rr_type, ptc_num);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
@ -256,11 +279,13 @@ void check_node(int inode, enum e_route_type route_type) {
if (type == NULL) { if (type == NULL) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d (type %d) is at an illegal clb location (%d, %d).\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d (type %d) is at an illegal clb location (%d, %d).\n",
inode, rr_type, xlow, ylow); inode, rr_type, xlow, ylow);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
if (xlow != xhigh || ylow != (yhigh - type->height + 1)) { if (xlow != xhigh || ylow != (yhigh - type->height + 1)) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d (type %d) has endpoints (%d,%d) and (%d,%d)\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d (type %d) has endpoints (%d,%d) and (%d,%d)\n",
inode, rr_type, xlow, ylow, xhigh, yhigh); inode, rr_type, xlow, ylow, xhigh, yhigh);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
break; break;
@ -279,11 +304,13 @@ void check_node(int inode, enum e_route_type route_type) {
/* end */ /* end */
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: CHANX out of range for endpoints (%d,%d) and (%d,%d)\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: CHANX out of range for endpoints (%d,%d) and (%d,%d)\n",
xlow, ylow, xhigh, yhigh); xlow, ylow, xhigh, yhigh);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
if (route_type == GLOBAL && xlow != xhigh) { if (route_type == GLOBAL && xlow != xhigh) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d spans multiple channel segments (not allowed for global routing).\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d spans multiple channel segments (not allowed for global routing).\n",
inode); inode);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
break; break;
@ -302,11 +329,13 @@ void check_node(int inode, enum e_route_type route_type) {
/* end */ /* end */
vpr_printf(TIO_MESSAGE_ERROR, "Error in check_node: CHANY out of range for endpoints (%d,%d) and (%d,%d)\n", vpr_printf(TIO_MESSAGE_ERROR, "Error in check_node: CHANY out of range for endpoints (%d,%d) and (%d,%d)\n",
xlow, ylow, xhigh, yhigh); xlow, ylow, xhigh, yhigh);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
if (route_type == GLOBAL && ylow != yhigh) { if (route_type == GLOBAL && ylow != yhigh) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d spans multiple channel segments (not allowed for global routing).\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d spans multiple channel segments (not allowed for global routing).\n",
inode); inode);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
break; break;
@ -326,11 +355,13 @@ void check_node(int inode, enum e_route_type route_type) {
|| type->class_inf[ptc_num].type != DRIVER) { || type->class_inf[ptc_num].type != DRIVER) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
inode, rr_type, ptc_num); inode, rr_type, ptc_num);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
if (type->class_inf[ptc_num].num_pins != capacity) { if (type->class_inf[ptc_num].num_pins != capacity) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a capacity of %d.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a capacity of %d.\n",
inode, rr_type, capacity); inode, rr_type, capacity);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
break; break;
@ -341,11 +372,13 @@ void check_node(int inode, enum e_route_type route_type) {
|| type->class_inf[ptc_num].type != RECEIVER) { || type->class_inf[ptc_num].type != RECEIVER) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
inode, rr_type, ptc_num); inode, rr_type, ptc_num);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
if (type->class_inf[ptc_num].num_pins != capacity) { if (type->class_inf[ptc_num].num_pins != capacity) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
inode, rr_type, capacity); inode, rr_type, capacity);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
break; break;
@ -356,12 +389,14 @@ void check_node(int inode, enum e_route_type route_type) {
|| type->class_inf[type->pin_class[ptc_num]].type != DRIVER) { || type->class_inf[type->pin_class[ptc_num]].type != DRIVER) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
inode, rr_type, ptc_num); inode, rr_type, ptc_num);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
if (capacity != 1) { if (capacity != 1) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
inode, rr_type, capacity); inode, rr_type, capacity);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
break; break;
@ -371,11 +406,13 @@ void check_node(int inode, enum e_route_type route_type) {
|| type->class_inf[type->pin_class[ptc_num]].type != RECEIVER) { || type->class_inf[type->pin_class[ptc_num]].type != RECEIVER) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) had a ptc_num of %d.\n",
inode, rr_type, ptc_num); inode, rr_type, ptc_num);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
if (capacity != 1) { if (capacity != 1) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
inode, rr_type, capacity); inode, rr_type, capacity);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
break; break;
@ -392,12 +429,14 @@ void check_node(int inode, enum e_route_type route_type) {
if (ptc_num >= nodes_per_chan) { if (ptc_num >= nodes_per_chan) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a ptc_num of %d.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a ptc_num of %d.\n",
inode, rr_type, ptc_num); inode, rr_type, ptc_num);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
if (capacity != tracks_per_node) { if (capacity != tracks_per_node) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
inode, rr_type, capacity); inode, rr_type, capacity);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
break; break;
@ -414,12 +453,14 @@ void check_node(int inode, enum e_route_type route_type) {
if (ptc_num >= nodes_per_chan) { if (ptc_num >= nodes_per_chan) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a ptc_num of %d.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a ptc_num of %d.\n",
inode, rr_type, ptc_num); inode, rr_type, ptc_num);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
if (capacity != tracks_per_node) { if (capacity != tracks_per_node) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: inode %d (type %d) has a capacity of %d.\n",
inode, rr_type, capacity); inode, rr_type, capacity);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
break; break;
@ -439,6 +480,7 @@ void check_node(int inode, enum e_route_type route_type) {
* If such a node was ever used in a final routing (not just in an rr_graph), other * * If such a node was ever used in a final routing (not just in an rr_graph), other *
* error checks in check_routing will catch it. */ * error checks in check_routing will catch it. */
vpr_printf(TIO_MESSAGE_WARNING, "in check_node: node %d has no edges.\n", inode); vpr_printf(TIO_MESSAGE_WARNING, "in check_node: node %d has no edges.\n", inode);
print_rr_node_details(&rr_node[inode]);
} }
} }
@ -446,6 +488,7 @@ void check_node(int inode, enum e_route_type route_type) {
if (num_edges != 0) { if (num_edges != 0) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d is a sink, but has %d edges.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d is a sink, but has %d edges.\n",
inode, num_edges); inode, num_edges);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
} }
@ -459,6 +502,7 @@ void check_node(int inode, enum e_route_type route_type) {
if (C < 0. || R < 0.) { if (C < 0. || R < 0.) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d of type %d has R = %g and C = %g.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d of type %d has R = %g and C = %g.\n",
inode, rr_type, R, C); inode, rr_type, R, C);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
} }
@ -467,6 +511,7 @@ void check_node(int inode, enum e_route_type route_type) {
if (C != 0. || R != 0.) { if (C != 0. || R != 0.) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d of type %d has R = %g and C = %g.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d of type %d has R = %g and C = %g.\n",
inode, rr_type, R, C); inode, rr_type, R, C);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
} }
@ -475,6 +520,7 @@ void check_node(int inode, enum e_route_type route_type) {
if (cost_index < 0 || cost_index >= num_rr_indexed_data) { if (cost_index < 0 || cost_index >= num_rr_indexed_data) {
vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d cost index (%d) is out of range.\n", vpr_printf(TIO_MESSAGE_ERROR, "in check_node: node %d cost index (%d) is out of range.\n",
inode, cost_index); inode, cost_index);
print_rr_node_details(&rr_node[inode]);
exit(1); exit(1);
} }
} }
@ -534,6 +580,8 @@ static void check_pass_transistors(int from_node) {
vpr_printf(TIO_MESSAGE_ERROR, "connection from node %d to node %d uses a pass transistor (switch type %d)\n", vpr_printf(TIO_MESSAGE_ERROR, "connection from node %d to node %d uses a pass transistor (switch type %d)\n",
from_node, to_node, from_switch_type); from_node, to_node, from_switch_type);
vpr_printf(TIO_MESSAGE_ERROR, "but there is no corresponding pass transistor edge in the other direction.\n"); vpr_printf(TIO_MESSAGE_ERROR, "but there is no corresponding pass transistor edge in the other direction.\n");
print_rr_node_details(&rr_node[from_node]);
print_rr_node_details(&rr_node[to_node]);
exit(1); exit(1);
} }

View File

@ -1,26 +1,10 @@
#ifndef CHECK_RR_GRAPH_H #ifndef CHECK_RR_GRAPH_H
#define CHECK_RR_GRAPH_H #define CHECK_RR_GRAPH_H
void check_rr_graph(INP t_graph_type graph_type, void check_rr_graph(INP const t_graph_type graph_type,
INP t_type_ptr types, INP const int L_nx, INP const int L_ny,
INP int L_nx, INP const int num_switches,
INP int L_ny, int **Fc_in);
INP int nodes_per_chan,
INP int Fs,
INP int num_seg_types,
INP int num_switches,
INP t_segment_inf * segment_inf,
INP int global_route_switch,
INP int delayless_switch,
INP int wire_to_ipin_switch,
t_seg_details * seg_details,
int ** Fc_in,
int ** Fc_out,
int *****opin_to_track_map,
int *****ipin_to_track_map,
t_ivec **** track_to_ipin_lookup,
t_ivec *** switch_block_conn,
boolean * perturb_ipins);
void check_node(int inode, enum e_route_type route_type); void check_node(int inode, enum e_route_type route_type);

View File

@ -273,10 +273,15 @@ boolean try_route(int width_fac, struct s_router_opts router_opts,
if (router_opts.route_type == GLOBAL) { if (router_opts.route_type == GLOBAL) {
graph_type = GRAPH_GLOBAL; graph_type = GRAPH_GLOBAL;
/* Xifan Tang: tileable undirectional rr_graph support */
} else if (BI_DIRECTIONAL == det_routing_arch.directionality) {
graph_type = GRAPH_BIDIR;
} else if (UNI_DIRECTIONAL == det_routing_arch.directionality) {
if (true == det_routing_arch.tileable) {
graph_type = GRAPH_UNIDIR_TILEABLE;
} else { } else {
graph_type = ( graph_type = GRAPH_UNIDIR;
det_routing_arch.directionality == BI_DIRECTIONAL ? }
GRAPH_BIDIR : GRAPH_UNIDIR);
} }
/* Set the channel widths */ /* Set the channel widths */

View File

@ -1,3 +1,6 @@
#ifndef ROUTE_COMMON_H
#define ROUTE_COMMON_H
/************ Defines and types shared by all route files ********************/ /************ Defines and types shared by all route files ********************/
typedef struct s_heap t_heap; typedef struct s_heap t_heap;
@ -118,4 +121,4 @@ void auto_detect_and_reserve_locally_used_opins(float pres_fac, boolean rip_up_l
void free_chunk_memory_trace(void); void free_chunk_memory_trace(void);
#endif

View File

@ -16,6 +16,8 @@
#include "read_xml_arch_file.h" #include "read_xml_arch_file.h"
#include "ReadOptions.h" #include "ReadOptions.h"
#include "tileable_rr_graph_builder.h"
/* Xifan TANG: SWSEG SUPPORT */ /* Xifan TANG: SWSEG SUPPORT */
#include "rr_graph_swseg.h" #include "rr_graph_swseg.h"
/* end */ /* end */
@ -69,14 +71,6 @@ static t_chunk rr_mem_ch = {NULL, 0, NULL};
/* Status of current chunk being dished out by calls to my_chunk_malloc. */ /* Status of current chunk being dished out by calls to my_chunk_malloc. */
/********************* Subroutines local to this module. *******************/ /********************* Subroutines local to this module. *******************/
static int ****alloc_and_load_pin_to_track_map(INP enum e_pin_type pin_type,
INP int nodes_per_chan, INP int *Fc, INP t_type_ptr Type,
INP boolean perturb_switch_pattern,
INP enum e_directionality directionality);
static struct s_ivec ***alloc_and_load_track_to_pin_lookup(
INP int ****pin_to_track_map, INP int *Fc, INP int height,
INP int num_pins, INP int nodes_per_chan);
static void build_bidir_rr_opins(INP int i, INP int j, static void build_bidir_rr_opins(INP int i, INP int j,
INOUTP t_rr_node * L_rr_node, INP t_ivec *** L_rr_node_indices, INOUTP t_rr_node * L_rr_node, INP t_ivec *** L_rr_node_indices,
@ -124,10 +118,6 @@ static void check_all_tracks_reach_pins(t_type_ptr type,
int ****tracks_connected_to_pin, int nodes_per_chan, int Fc, int ****tracks_connected_to_pin, int nodes_per_chan, int Fc,
enum e_pin_type ipin_or_opin); enum e_pin_type ipin_or_opin);
static boolean *alloc_and_load_perturb_ipins(INP int nodes_per_chan,
INP int L_num_types, INP int **Fc_in, INP int **Fc_out,
INP enum e_directionality directionality);
static void build_rr_sinks_sources(INP int i, INP int j, static void build_rr_sinks_sources(INP int i, INP int j,
INP t_rr_node * L_rr_node, INP t_ivec *** L_rr_node_indices, INP t_rr_node * L_rr_node, INP t_ivec *** L_rr_node_indices,
INP int delayless_switch, INP struct s_grid_tile **L_grid); INP int delayless_switch, INP struct s_grid_tile **L_grid);
@ -188,19 +178,35 @@ static void print_distribution(FILE * fptr,
t_mux_size_distribution * distr_struct); t_mux_size_distribution * distr_struct);
#endif #endif
static void free_type_pin_to_track_map(int***** ipin_to_track_map,
t_type_ptr types);
static void free_type_track_to_ipin_map(struct s_ivec**** track_to_pin_map,
t_type_ptr types, int nodes_per_chan);
static t_seg_details *alloc_and_load_global_route_seg_details( static t_seg_details *alloc_and_load_global_route_seg_details(
INP int nodes_per_chan, INP int global_route_switch); INP int nodes_per_chan, INP int global_route_switch);
static
void build_classic_rr_graph(INP t_graph_type graph_type, INP int L_num_types,
INP t_type_ptr types, INP int L_nx, INP int L_ny,
INP struct s_grid_tile **L_grid, INP int chan_width,
INP struct s_chan_width_dist *chan_capacity_inf,
INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types,
INP int num_switches, INP t_segment_inf * segment_inf,
INP int global_route_switch, INP int delayless_switch,
INP t_timing_inf timing_inf, INP int wire_to_ipin_switch,
INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs,
INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings,
/*Xifan TANG: Switch Segment Pattern Support*/
INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns,
INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges);
/* UDSD Modifications by WMF End */ /* UDSD Modifications by WMF End */
/******************* Subroutine definitions *******************************/ /******************* Subroutine definitions *******************************/
/*************************************************************************
* Top-level function of rr_graph builder
* Xifan TANG: this top function can branch between tileable rr_graph generator
* and the classical rr_graph generator
************************************************************************/
void build_rr_graph(INP t_graph_type graph_type, INP int L_num_types, void build_rr_graph(INP t_graph_type graph_type, INP int L_num_types,
INP t_type_ptr types, INP int L_nx, INP int L_ny, INP t_type_ptr types, INP int L_nx, INP int L_ny,
INP struct s_grid_tile **L_grid, INP int chan_width, INP struct s_grid_tile **L_grid, INP int chan_width,
@ -214,6 +220,50 @@ void build_rr_graph(INP t_graph_type graph_type, INP int L_num_types,
/*Xifan TANG: Switch Segment Pattern Support*/ /*Xifan TANG: Switch Segment Pattern Support*/
INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns, INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns,
INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) { INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) {
/* Branch here */
if (GRAPH_UNIDIR_TILEABLE == graph_type) {
build_tileable_unidir_rr_graph(L_num_types, types,
L_nx, L_ny, L_grid,
chan_width,
sb_type, Fs, num_seg_types, segment_inf,
num_switches, delayless_switch,
timing_inf, wire_to_ipin_switch,
base_cost_type, directs, num_directs, ignore_Fc_0, Warnings);
} else {
build_classic_rr_graph(graph_type, L_num_types, types,
L_nx, L_ny, L_grid,
chan_width, chan_capacity_inf,
sb_type, Fs, num_seg_types, num_switches, segment_inf,
global_route_switch, delayless_switch,
timing_inf, wire_to_ipin_switch,
base_cost_type, directs, num_directs, ignore_Fc_0, Warnings,
num_swseg_pattern, swseg_patterns,
opin_to_cb_fast_edges, opin_logic_eq_edges);
}
return;
}
/* Xifan TANG: I rename the classical rr_graph builder here.
* We can have a clean build_rr_graph top function,
* where we branch for tileable routing and classical */
static
void build_classic_rr_graph(INP t_graph_type graph_type, INP int L_num_types,
INP t_type_ptr types, INP int L_nx, INP int L_ny,
INP struct s_grid_tile **L_grid, INP int chan_width,
INP struct s_chan_width_dist *chan_capacity_inf,
INP enum e_switch_block_type sb_type, INP int Fs, INP int num_seg_types,
INP int num_switches, INP t_segment_inf * segment_inf,
INP int global_route_switch, INP int delayless_switch,
INP t_timing_inf timing_inf, INP int wire_to_ipin_switch,
INP enum e_base_cost_type base_cost_type, INP t_direct_inf *directs,
INP int num_directs, INP boolean ignore_Fc_0, OUTP int *Warnings,
/*Xifan TANG: Switch Segment Pattern Support*/
INP int num_swseg_pattern, INP t_swseg_pattern_inf* swseg_patterns,
INP boolean opin_to_cb_fast_edges, INP boolean opin_logic_eq_edges) {
/* Temp structures used to build graph */ /* Temp structures used to build graph */
int nodes_per_chan, i, j; int nodes_per_chan, i, j;
t_seg_details *seg_details = NULL; t_seg_details *seg_details = NULL;
@ -473,11 +523,8 @@ void build_rr_graph(INP t_graph_type graph_type, INP int L_num_types,
} else } else
; ;
check_rr_graph(graph_type, types, L_nx, L_ny, nodes_per_chan, Fs, check_rr_graph(graph_type, L_nx, L_ny,
num_seg_types, num_switches, segment_inf, global_route_switch, num_switches, Fc_in);
delayless_switch, wire_to_ipin_switch, seg_details, Fc_in, Fc_out,
opin_to_track_map, ipin_to_track_map, track_to_ipin_lookup,
switch_block_conn, perturb_ipins);
/* Free all temp structs */ /* Free all temp structs */
if (seg_details) { if (seg_details) {
@ -531,9 +578,9 @@ void build_rr_graph(INP t_graph_type graph_type, INP int L_num_types,
} }
} }
void rr_graph_externals(t_timing_inf timing_inf, void rr_graph_externals(const t_timing_inf timing_inf,
t_segment_inf * segment_inf, int num_seg_types, int nodes_per_chan, const t_segment_inf * segment_inf, const int num_seg_types, const int nodes_per_chan,
int wire_to_ipin_switch, enum e_base_cost_type base_cost_type) { const int wire_to_ipin_switch, const enum e_base_cost_type base_cost_type) {
add_rr_graph_C_from_switches(timing_inf.C_ipin_cblock); add_rr_graph_C_from_switches(timing_inf.C_ipin_cblock);
alloc_and_load_rr_indexed_data(segment_inf, num_seg_types, rr_node_indices, alloc_and_load_rr_indexed_data(segment_inf, num_seg_types, rr_node_indices,
nodes_per_chan, wire_to_ipin_switch, base_cost_type); nodes_per_chan, wire_to_ipin_switch, base_cost_type);
@ -543,7 +590,7 @@ void rr_graph_externals(t_timing_inf timing_inf,
alloc_and_load_rr_clb_source(rr_node_indices); alloc_and_load_rr_clb_source(rr_node_indices);
} }
static boolean * boolean *
alloc_and_load_perturb_ipins(INP int nodes_per_chan, INP int L_num_types, alloc_and_load_perturb_ipins(INP int nodes_per_chan, INP int L_num_types,
INP int **Fc_in, INP int **Fc_out, INP enum e_directionality directionality) { INP int **Fc_in, INP int **Fc_out, INP enum e_directionality directionality) {
int i; int i;
@ -645,6 +692,9 @@ alloc_and_load_actual_fc(INP int L_num_types, INP t_type_ptr types,
for (j = 0; j < types[i].num_pins; ++j) { for (j = 0; j < types[i].num_pins; ++j) {
Fc[j] = types[i].Fc[j]; Fc[j] = types[i].Fc[j];
/* Xifan Tang: give an initial value! */
Result[i][j] = -1;
if(Fc[j] == 0 && ignore_Fc_0 == FALSE) { if(Fc[j] == 0 && ignore_Fc_0 == FALSE) {
/* Special case indicating that this pin does not connect to general-purpose routing */ /* Special case indicating that this pin does not connect to general-purpose routing */
Result[i][j] = 0; Result[i][j] = 0;
@ -675,7 +725,7 @@ alloc_and_load_actual_fc(INP int L_num_types, INP t_type_ptr types,
} }
/* frees the track to ipin mapping for each physical grid type */ /* frees the track to ipin mapping for each physical grid type */
static void free_type_track_to_ipin_map(struct s_ivec**** track_to_pin_map, void free_type_track_to_ipin_map(struct s_ivec**** track_to_pin_map,
t_type_ptr types, int nodes_per_chan) { t_type_ptr types, int nodes_per_chan) {
int i, itrack, ioff, iside; int i, itrack, ioff, iside;
for (i = 0; i < num_types; i++) { for (i = 0; i < num_types; i++) {
@ -698,7 +748,7 @@ static void free_type_track_to_ipin_map(struct s_ivec**** track_to_pin_map,
} }
/* frees the ipin to track mapping for each physical grid type */ /* frees the ipin to track mapping for each physical grid type */
static void free_type_pin_to_track_map(int***** ipin_to_track_map, void free_type_pin_to_track_map(int***** ipin_to_track_map,
t_type_ptr types) { t_type_ptr types) {
int i; int i;
for (i = 0; i < num_types; i++) { for (i = 0; i < num_types; i++) {
@ -1532,7 +1582,7 @@ void alloc_and_load_edges_and_switches(INP t_rr_node * L_rr_node, INP int inode,
assert(i == num_edges); assert(i == num_edges);
} }
static int **** int ****
alloc_and_load_pin_to_track_map(INP enum e_pin_type pin_type, alloc_and_load_pin_to_track_map(INP enum e_pin_type pin_type,
INP int nodes_per_chan, INP int *Fc, INP t_type_ptr Type, INP int nodes_per_chan, INP int *Fc, INP t_type_ptr Type,
INP boolean perturb_switch_pattern, INP boolean perturb_switch_pattern,
@ -1873,7 +1923,7 @@ static void check_all_tracks_reach_pins(t_type_ptr type,
/* Allocates and loads the track to ipin lookup for each physical grid type. This /* Allocates and loads the track to ipin lookup for each physical grid type. This
* is the same information as the ipin_to_track map but accessed in a different way. */ * is the same information as the ipin_to_track map but accessed in a different way. */
static struct s_ivec *** struct s_ivec ***
alloc_and_load_track_to_pin_lookup(INP int ****pin_to_track_map, INP int *Fc, alloc_and_load_track_to_pin_lookup(INP int ****pin_to_track_map, INP int *Fc,
INP int height, INP int num_pins, INP int nodes_per_chan) { INP int height, INP int num_pins, INP int nodes_per_chan) {
int ipin, iside, itrack, iconn, ioff, pin_counter; int ipin, iside, itrack, iconn, ioff, pin_counter;

View File

@ -59,9 +59,31 @@ alloc_and_load_actual_fc(INP int L_num_types, INP t_type_ptr types,
INP int nodes_per_chan, INP boolean is_Fc_out, INP int nodes_per_chan, INP boolean is_Fc_out,
INP enum e_directionality directionality, OUTP boolean * Fc_clipped, INP boolean ignore_Fc_0); INP enum e_directionality directionality, OUTP boolean * Fc_clipped, INP boolean ignore_Fc_0);
void rr_graph_externals(t_timing_inf timing_inf, void rr_graph_externals(const t_timing_inf timing_inf,
t_segment_inf * segment_inf, int num_seg_types, int nodes_per_chan, const t_segment_inf * segment_inf, const int num_seg_types, const int nodes_per_chan,
int wire_to_ipin_switch, enum e_base_cost_type base_cost_type); const int wire_to_ipin_switch, const enum e_base_cost_type base_cost_type);
/* Xifan Tang: Functions shared by tileable rr_graph generator */
int ****alloc_and_load_pin_to_track_map(INP enum e_pin_type pin_type,
INP int nodes_per_chan, INP int *Fc, INP t_type_ptr Type,
INP boolean perturb_switch_pattern,
INP enum e_directionality directionality);
struct s_ivec ***alloc_and_load_track_to_pin_lookup(
INP int ****pin_to_track_map, INP int *Fc, INP int height,
INP int num_pins, INP int nodes_per_chan);
boolean *
alloc_and_load_perturb_ipins(INP int nodes_per_chan, INP int L_num_types,
INP int **Fc_in, INP int **Fc_out, INP enum e_directionality directionality);
void free_type_pin_to_track_map(int***** ipin_to_track_map,
t_type_ptr types);
void free_type_track_to_ipin_map(struct s_ivec**** track_to_pin_map,
t_type_ptr types, int nodes_per_chan);
#endif #endif

View File

@ -25,7 +25,7 @@ static float get_average_opin_delay(t_ivec *** L_rr_node_indices,
static void load_rr_indexed_data_T_values(int index_start, static void load_rr_indexed_data_T_values(int index_start,
int num_indices_to_load, t_rr_type rr_type, int nodes_per_chan, int num_indices_to_load, t_rr_type rr_type, int nodes_per_chan,
t_ivec *** L_rr_node_indices, t_segment_inf * segment_inf); t_ivec *** L_rr_node_indices, const t_segment_inf * segment_inf);
/******************** Subroutine definitions *********************************/ /******************** Subroutine definitions *********************************/
@ -42,7 +42,7 @@ static void load_rr_indexed_data_T_values(int index_start,
* etc. more expensive than others. I give each segment type in an * * etc. more expensive than others. I give each segment type in an *
* x-channel its own cost_index, and each segment type in a y-channel its * * x-channel its own cost_index, and each segment type in a y-channel its *
* own cost_index. */ * own cost_index. */
void alloc_and_load_rr_indexed_data(INP t_segment_inf * segment_inf, void alloc_and_load_rr_indexed_data(INP const t_segment_inf * segment_inf,
INP int num_segment, INP t_ivec *** L_rr_node_indices, INP int num_segment, INP t_ivec *** L_rr_node_indices,
INP int nodes_per_chan, int wire_to_ipin_switch, INP int nodes_per_chan, int wire_to_ipin_switch,
enum e_base_cost_type base_cost_type) { enum e_base_cost_type base_cost_type) {
@ -258,7 +258,7 @@ static float get_average_opin_delay(t_ivec *** L_rr_node_indices,
static void load_rr_indexed_data_T_values(int index_start, static void load_rr_indexed_data_T_values(int index_start,
int num_indices_to_load, t_rr_type rr_type, int nodes_per_chan, int num_indices_to_load, t_rr_type rr_type, int nodes_per_chan,
t_ivec *** L_rr_node_indices, t_segment_inf * segment_inf) { t_ivec *** L_rr_node_indices, const t_segment_inf * segment_inf) {
/* Loads the average propagation times through segments of each index type * /* Loads the average propagation times through segments of each index type *
* for either all CHANX segment types or all CHANY segment types. It does * * for either all CHANX segment types or all CHANY segment types. It does *

View File

@ -1,3 +1,3 @@
void alloc_and_load_rr_indexed_data(t_segment_inf * segment_inf, void alloc_and_load_rr_indexed_data(const t_segment_inf * segment_inf,
int num_segment, t_ivec *** L_rr_node_indices, int nodes_per_chan, int num_segment, t_ivec *** L_rr_node_indices, int nodes_per_chan,
int wire_to_ipin_switch, enum e_base_cost_type base_cost_type); int wire_to_ipin_switch, enum e_base_cost_type base_cost_type);

View File

@ -1165,8 +1165,8 @@ void alloc_and_load_idirect_from_blk_pin(t_direct_inf* directs, int num_directs,
* This data structure supplements the the info in the "directs" data structure * This data structure supplements the the info in the "directs" data structure
* TODO: The function that does this parsing in placement is poorly done because it lacks generality on heterogeniety, should replace with this one * TODO: The function that does this parsing in placement is poorly done because it lacks generality on heterogeniety, should replace with this one
*/ */
t_clb_to_clb_directs * alloc_and_load_clb_to_clb_directs(INP t_direct_inf *directs, t_clb_to_clb_directs * alloc_and_load_clb_to_clb_directs(INP const t_direct_inf *directs,
INP int num_directs) { INP const int num_directs) {
int i, j; int i, j;
t_clb_to_clb_directs *clb_to_clb_directs; t_clb_to_clb_directs *clb_to_clb_directs;
char *pb_type_name, *port_name; char *pb_type_name, *port_name;

View File

@ -41,7 +41,7 @@ void alloc_and_load_idirect_from_blk_pin(t_direct_inf* directs, int num_directs,
void parse_direct_pin_name(char * src_string, int line, int * start_pin_index, void parse_direct_pin_name(char * src_string, int line, int * start_pin_index,
int * end_pin_index, char * pb_type_name, char * port_name); int * end_pin_index, char * pb_type_name, char * port_name);
t_clb_to_clb_directs *alloc_and_load_clb_to_clb_directs(INP t_direct_inf *directs, INP int num_directs); t_clb_to_clb_directs *alloc_and_load_clb_to_clb_directs(INP const t_direct_inf *directs, INP const int num_directs);
void free_cb(t_pb *pb); void free_cb(t_pb *pb);