Merge branch 'tileable_routing' into multimode_clb
This commit is contained in:
commit
9b6a4b39bb
|
@ -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"/>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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: *
|
||||||
|
|
|
@ -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()) ) {
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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:
|
||||||
* +-------------------------------------+
|
* +-------------------------------------+
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
***********************************************************************/
|
|
|
@ -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
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
@ -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
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
|
||||||
*/
|
|
||||||
|
|
|
@ -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
|
||||||
|
***********************************************************************/
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 *
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue