Merge branch 'refactoring' into dev
This commit is contained in:
commit
5dcffb1a6e
|
@ -56,13 +56,14 @@ set_target_properties(libvpr8 PROPERTIES PREFIX "") #Avoid extra 'lib' prefix
|
|||
|
||||
#Specify link-time dependancies
|
||||
target_link_libraries(libvpr8
|
||||
libvtrutil
|
||||
libarchfpga
|
||||
libsdcparse
|
||||
libblifparse
|
||||
libtatum
|
||||
libargparse
|
||||
libpugixml)
|
||||
libvtrutil
|
||||
libopenfpgautil
|
||||
libarchfpga
|
||||
libsdcparse
|
||||
libblifparse
|
||||
libtatum
|
||||
libargparse
|
||||
libpugixml)
|
||||
|
||||
#link graphics library only when graphics set to on
|
||||
if (VPR_USE_EZGL STREQUAL "on")
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef CLB2CLB_DIRECTS_H
|
||||
#define CLB2CLB_DIRECTS_H
|
||||
|
||||
#include "physical_types.h"
|
||||
|
||||
struct t_clb_to_clb_directs {
|
||||
t_physical_tile_type_ptr from_clb_type;
|
||||
int from_clb_pin_start_index;
|
||||
int from_clb_pin_end_index;
|
||||
t_physical_tile_type_ptr to_clb_type;
|
||||
int to_clb_pin_start_index;
|
||||
int to_clb_pin_end_index;
|
||||
int switch_index; //The switch type used by this direct connection
|
||||
};
|
||||
|
||||
#endif
|
|
@ -41,6 +41,8 @@
|
|||
#include "rr_graph_obj_util.h"
|
||||
#include "check_rr_graph_obj.h"
|
||||
|
||||
#include "clb2clb_directs.h"
|
||||
|
||||
//#define VERBOSE
|
||||
|
||||
struct t_mux {
|
||||
|
@ -55,16 +57,6 @@ struct t_mux_size_distribution {
|
|||
t_mux_size_distribution* next;
|
||||
};
|
||||
|
||||
struct t_clb_to_clb_directs {
|
||||
t_physical_tile_type_ptr from_clb_type;
|
||||
int from_clb_pin_start_index;
|
||||
int from_clb_pin_end_index;
|
||||
t_physical_tile_type_ptr to_clb_type;
|
||||
int to_clb_pin_start_index;
|
||||
int to_clb_pin_end_index;
|
||||
int switch_index; //The switch type used by this direct connection
|
||||
};
|
||||
|
||||
struct t_pin_loc {
|
||||
int pin_index;
|
||||
int width_offset;
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
/************************************************************************
|
||||
* This file contains member functions for class ChanNodeDetails
|
||||
***********************************************************************/
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include "chan_node_details.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/************************************************************************
|
||||
* Constructors
|
||||
***********************************************************************/
|
||||
ChanNodeDetails::ChanNodeDetails(const ChanNodeDetails& src) {
|
||||
/* duplicate */
|
||||
size_t chan_width = src.get_chan_width();
|
||||
this->reserve(chan_width);
|
||||
for (size_t itrack = 0; itrack < chan_width; ++itrack) {
|
||||
track_node_ids_.push_back(src.get_track_node_id(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));
|
||||
track_start_.push_back(src.is_track_start(itrack));
|
||||
track_end_.push_back(src.is_track_end(itrack));
|
||||
}
|
||||
}
|
||||
|
||||
ChanNodeDetails::ChanNodeDetails() {
|
||||
this->clear();
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Accessors
|
||||
***********************************************************************/
|
||||
size_t ChanNodeDetails::get_chan_width() const {
|
||||
assert(validate_chan_width());
|
||||
return track_node_ids_.size();
|
||||
}
|
||||
|
||||
size_t ChanNodeDetails::get_track_node_id(const size_t& track_id) const {
|
||||
assert(validate_track_id(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(const size_t& track_id) const {
|
||||
assert(validate_track_id(track_id));
|
||||
return track_direction_[track_id];
|
||||
}
|
||||
|
||||
size_t ChanNodeDetails::get_track_segment_length(const size_t& track_id) const {
|
||||
assert(validate_track_id(track_id));
|
||||
return seg_length_[track_id];
|
||||
}
|
||||
|
||||
size_t ChanNodeDetails::get_track_segment_id(const size_t& track_id) const {
|
||||
assert(validate_track_id(track_id));
|
||||
return seg_ids_[track_id];
|
||||
}
|
||||
|
||||
bool ChanNodeDetails::is_track_start(const size_t& track_id) const {
|
||||
assert(validate_track_id(track_id));
|
||||
return track_start_[track_id];
|
||||
}
|
||||
|
||||
bool ChanNodeDetails::is_track_end(const size_t& track_id) const {
|
||||
assert(validate_track_id(track_id));
|
||||
return track_end_[track_id];
|
||||
}
|
||||
|
||||
/* Track_id is the starting point of group (whose is_start should be true)
|
||||
* This function will try to find the track_ids with the same directionality as track_id and seg_length
|
||||
* A group size is the number of such nodes between the starting points (include the 1st starting point)
|
||||
*/
|
||||
std::vector<size_t> ChanNodeDetails::get_seg_group(const size_t& track_id) const {
|
||||
assert(validate_chan_width());
|
||||
assert(validate_track_id(track_id));
|
||||
assert(is_track_start(track_id));
|
||||
|
||||
std::vector<size_t> group;
|
||||
/* Make sure a clean start */
|
||||
group.clear();
|
||||
|
||||
for (size_t itrack = track_id; itrack < get_chan_width(); ++itrack) {
|
||||
if ( (get_track_direction(itrack) != get_track_direction(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))
|
||||
|| ( (true == is_track_start(itrack)) && (itrack == track_id)) ) {
|
||||
group.push_back(itrack);
|
||||
continue;
|
||||
}
|
||||
/* Stop if this another starting point */
|
||||
if (true == is_track_start(itrack)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
/* Get a list of track_ids with the given list of track indices */
|
||||
std::vector<size_t> ChanNodeDetails::get_seg_group_node_id(const std::vector<size_t>& seg_group) const {
|
||||
std::vector<size_t> group;
|
||||
/* Make sure a clean start */
|
||||
group.clear();
|
||||
|
||||
for (size_t id = 0; id < seg_group.size(); ++id) {
|
||||
assert(validate_track_id(seg_group[id]));
|
||||
group.push_back(get_track_node_id(seg_group[id]));
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
/* Get the number of tracks that starts in this routing channel */
|
||||
size_t ChanNodeDetails::get_num_starting_tracks(const e_direction& track_direction) const {
|
||||
size_t counter = 0;
|
||||
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)) {
|
||||
continue;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
/* Get the number of tracks that ends in this routing channel */
|
||||
size_t ChanNodeDetails::get_num_ending_tracks(const e_direction& track_direction) const {
|
||||
size_t counter = 0;
|
||||
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)) {
|
||||
continue;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Mutators
|
||||
***********************************************************************/
|
||||
/* Reserve the capacitcy of vectors */
|
||||
void ChanNodeDetails::reserve(const size_t& chan_width) {
|
||||
track_node_ids_.reserve(chan_width);
|
||||
track_direction_.reserve(chan_width);
|
||||
seg_length_.reserve(chan_width);
|
||||
seg_ids_.reserve(chan_width);
|
||||
track_start_.reserve(chan_width);
|
||||
track_end_.reserve(chan_width);
|
||||
}
|
||||
|
||||
/* Add a track to the channel */
|
||||
void ChanNodeDetails::add_track(const size_t& track_node_id, const e_direction& track_direction,
|
||||
const size_t& seg_id, const size_t& seg_length,
|
||||
const size_t& is_start, const size_t& is_end) {
|
||||
track_node_ids_.push_back(track_node_id);
|
||||
track_direction_.push_back(track_direction);
|
||||
seg_ids_.push_back(seg_id);
|
||||
seg_length_.push_back(seg_length);
|
||||
track_start_.push_back(is_start);
|
||||
track_end_.push_back(is_end);
|
||||
}
|
||||
|
||||
/* Update the node_id of a given track */
|
||||
void ChanNodeDetails::set_track_node_id(const size_t& track_index, const 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(const 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 */
|
||||
void ChanNodeDetails::set_tracks_start(const e_direction& track_direction) {
|
||||
for (size_t inode = 0; inode < get_chan_width(); ++inode) {
|
||||
/* Bypass non-match tracks */
|
||||
if (track_direction != get_track_direction(inode)) {
|
||||
continue; /* Pass condition*/
|
||||
}
|
||||
track_start_[inode] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set tracks with a given direction to end */
|
||||
void ChanNodeDetails::set_tracks_end(const e_direction& track_direction) {
|
||||
for (size_t inode = 0; inode < get_chan_width(); ++inode) {
|
||||
/* Bypass non-match tracks */
|
||||
if (track_direction != get_track_direction(inode)) {
|
||||
continue; /* Pass condition*/
|
||||
}
|
||||
track_end_[inode] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* rotate the track_node_id by an offset */
|
||||
void ChanNodeDetails::rotate_track_node_id(const size_t& offset, const e_direction& track_direction, const bool& counter_rotate) {
|
||||
/* Direct return if offset = 0*/
|
||||
if (0 == offset) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Rotate the node_ids by groups
|
||||
* A group begins from a track_start and ends before another track_start
|
||||
*/
|
||||
assert(validate_chan_width());
|
||||
for (size_t itrack = 0; itrack < get_chan_width(); ++itrack) {
|
||||
/* Bypass non-start segment */
|
||||
if (false == is_track_start(itrack) ) {
|
||||
continue;
|
||||
}
|
||||
/* Bypass segments do not match track_direction */
|
||||
if (track_direction != get_track_direction(itrack) ) {
|
||||
continue;
|
||||
}
|
||||
/* Find the group nodes */
|
||||
std::vector<size_t> track_group = get_seg_group(itrack);
|
||||
/* 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);
|
||||
/* adapt offset to the range of track_group_node_id */
|
||||
size_t actual_offset = offset % track_group_node_id.size();
|
||||
/* Rotate or Counter rotate */
|
||||
if (true == counter_rotate) {
|
||||
std::rotate(track_group_node_id.rbegin(), track_group_node_id.rbegin() + actual_offset, track_group_node_id.rend());
|
||||
} else {
|
||||
std::rotate(track_group_node_id.begin(), track_group_node_id.begin() + actual_offset, track_group_node_id.end());
|
||||
}
|
||||
/* Update the node_ids */
|
||||
for (size_t inode = 0; inode < track_group.size(); ++inode) {
|
||||
track_node_ids_[track_group[inode]] = track_group_node_id[inode];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void ChanNodeDetails::clear() {
|
||||
track_node_ids_.clear();
|
||||
track_direction_.clear();
|
||||
seg_ids_.clear();
|
||||
seg_length_.clear();
|
||||
track_start_.clear();
|
||||
track_end_.clear();
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Validators
|
||||
***********************************************************************/
|
||||
bool ChanNodeDetails::validate_chan_width() const {
|
||||
size_t chan_width = track_node_ids_.size();
|
||||
if ( (chan_width == track_direction_.size())
|
||||
&&(chan_width == seg_ids_.size())
|
||||
&&(chan_width == seg_length_.size())
|
||||
&&(chan_width == track_start_.size())
|
||||
&&(chan_width == track_end_.size()) ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChanNodeDetails::validate_track_id(const size_t& track_id) const {
|
||||
if ( (track_id < track_node_ids_.size())
|
||||
&& (track_id < track_direction_.size())
|
||||
&& (track_id < seg_ids_.size())
|
||||
&& (track_id < seg_length_.size())
|
||||
&& (track_id < track_start_.size())
|
||||
&& (track_id < track_end_.size()) ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,75 @@
|
|||
#ifndef CHAN_NODE_DETAILS_H
|
||||
#define CHAN_NODE_DETAILS_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <vector>
|
||||
#include "vpr_types.h"
|
||||
|
||||
/************************************************************************
|
||||
* This file contains a class to model the details of routing node
|
||||
* in a channel:
|
||||
* 1. segment information: length, frequency etc.
|
||||
* 2. starting point of segment
|
||||
* 3. ending point of segment
|
||||
* 4. potentail track_id(ptc_num) of each segment
|
||||
***********************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/************************************************************************
|
||||
* ChanNodeDetails records segment length, directionality and starting of routing tracks
|
||||
* +---------------------------------+
|
||||
* | Index | Direction | Start Point |
|
||||
* +---------------------------------+
|
||||
* | 0 | --------> | Yes |
|
||||
* +---------------------------------+
|
||||
***********************************************************************/
|
||||
|
||||
class ChanNodeDetails {
|
||||
public : /* Constructor */
|
||||
ChanNodeDetails(const ChanNodeDetails&); /* Duplication */
|
||||
ChanNodeDetails(); /* Initilization */
|
||||
public: /* Accessors */
|
||||
size_t get_chan_width() const;
|
||||
size_t get_track_node_id(const size_t& track_id) const;
|
||||
std::vector<size_t> get_track_node_ids() const;
|
||||
e_direction get_track_direction(const size_t& track_id) const;
|
||||
size_t get_track_segment_length(const size_t& track_id) const;
|
||||
size_t get_track_segment_id(const size_t& track_id) const;
|
||||
bool is_track_start(const size_t& track_id) const;
|
||||
bool is_track_end(const size_t& track_id) const;
|
||||
std::vector<size_t> get_seg_group(const size_t& track_id) const;
|
||||
std::vector<size_t> get_seg_group_node_id(const std::vector<size_t>& seg_group) const;
|
||||
size_t get_num_starting_tracks(const e_direction& track_direction) const;
|
||||
size_t get_num_ending_tracks(const e_direction& track_direction) const;
|
||||
public: /* Mutators */
|
||||
void reserve(const size_t& chan_width); /* Reserve the capacitcy of vectors */
|
||||
void add_track(const size_t& track_node_id, const e_direction& track_direction,
|
||||
const size_t& seg_id, const size_t& seg_length,
|
||||
const size_t& is_start, const size_t& is_end);
|
||||
void set_track_node_id(const size_t& track_index, const size_t& track_node_id);
|
||||
void set_track_node_ids(const std::vector<size_t>& track_node_ids);
|
||||
void set_tracks_start(const e_direction& track_direction);
|
||||
void set_tracks_end(const e_direction& track_direction);
|
||||
void rotate_track_node_id(const size_t& offset,
|
||||
const e_direction& track_direction,
|
||||
const bool& counter_rotate); /* rotate the track_node_id by an offset */
|
||||
void clear();
|
||||
private: /* validators */
|
||||
bool validate_chan_width() const;
|
||||
bool validate_track_id(const size_t& track_id) const;
|
||||
private: /* Internal data */
|
||||
std::vector<size_t> track_node_ids_; /* indices 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<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 */
|
||||
};
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -127,8 +127,8 @@ std::vector<RRSegmentId> RRChan::get_segment_ids() const {
|
|||
}
|
||||
|
||||
/* Get a list of nodes whose segment_id is specified */
|
||||
std::vector<RRNodeId> RRChan::get_node_ids_by_segment_ids(const RRSegmentId& seg_id) const {
|
||||
std::vector<RRNodeId> node_list;
|
||||
std::vector<size_t> RRChan::get_node_ids_by_segment_ids(const RRSegmentId& seg_id) const {
|
||||
std::vector<size_t> node_list;
|
||||
|
||||
/* make sure a clean start */
|
||||
node_list.clear();
|
||||
|
@ -137,7 +137,7 @@ std::vector<RRNodeId> RRChan::get_node_ids_by_segment_ids(const RRSegmentId& seg
|
|||
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(nodes_[inode]);
|
||||
node_list.push_back(inode);
|
||||
}
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ class RRChan {
|
|||
RRSegmentId get_node_segment(const size_t& track_num) const;
|
||||
bool is_mirror(const RRGraph& rr_graph, const RRChan& cand) const; /* evaluate if two RR_chan is mirror to each other */
|
||||
std::vector<RRSegmentId> get_segment_ids() const; /* Get a list of segments used in this routing channel */
|
||||
std::vector<RRNodeId> get_node_ids_by_segment_ids(const RRSegmentId& seg_id) const; /* Get a list of segments used in this routing channel */
|
||||
std::vector<size_t> get_node_ids_by_segment_ids(const RRSegmentId& seg_id) const; /* Get a list of segments used in this routing channel */
|
||||
public: /* Mutators */
|
||||
/* copy */
|
||||
void set(const RRChan&);
|
|
@ -0,0 +1,479 @@
|
|||
/************************************************************************
|
||||
* This file contains most utilized functions for rr_graph builders
|
||||
***********************************************************************/
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
#include "vpr_utils.h"
|
||||
|
||||
#include "rr_graph_builder_utils.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/************************************************************************
|
||||
* 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 */
|
||||
VTR_ASSERT(pin_index < cur_grid.type->num_pins);
|
||||
return cur_grid.type->pin_class[pin_index];
|
||||
}
|
||||
|
||||
/* Deteremine the side of a io grid */
|
||||
e_side determine_io_grid_pin_side(const vtr::Point<size_t>& device_size,
|
||||
const vtr::Point<size_t>& grid_coordinate) {
|
||||
/* TOP side IO of FPGA */
|
||||
if (device_size.y() == grid_coordinate.y()) {
|
||||
return BOTTOM; /* Such I/O has only Bottom side pins */
|
||||
} else if (device_size.x() == grid_coordinate.x()) { /* RIGHT side IO of FPGA */
|
||||
return LEFT; /* Such I/O has only Left side pins */
|
||||
} else if (0 == grid_coordinate.y()) { /* BOTTOM side IO of FPGA */
|
||||
return TOP; /* Such I/O has only Top side pins */
|
||||
} else if (0 == grid_coordinate.x()) { /* LEFT side IO of FPGA */
|
||||
return RIGHT; /* Such I/O has only Right side pins */
|
||||
} else {
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"I/O Grid is in the center part of FPGA! Currently unsupported!\n");
|
||||
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 e_pin_type& pin_type,
|
||||
const e_side& pin_side,
|
||||
const int& pin_width,
|
||||
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_width][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 e_pin_type& pin_type,
|
||||
const e_side& io_side) {
|
||||
size_t num_pins = 0;
|
||||
|
||||
/* For IO_TYPE sides */
|
||||
for (const e_side& side : {TOP, RIGHT, BOTTOM, LEFT}) {
|
||||
/* skip unwanted sides */
|
||||
if ( (true == is_io_type(cur_grid.type))
|
||||
&& (side != io_side) ) {
|
||||
continue;
|
||||
}
|
||||
/* Get pin list */
|
||||
for (int width = 0; width < cur_grid.type->width; ++width) {
|
||||
for (int height = 0; height < cur_grid.type->height; ++height) {
|
||||
std::vector<int> pin_list = get_grid_side_pins(cur_grid, pin_type, side, width, 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 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;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Idenfity if a X-direction routing channel exist in the fabric
|
||||
* This could be entirely possible that a routig channel
|
||||
* is in the middle of a multi-width and multi-height grid
|
||||
*
|
||||
* As the chanx always locates on top of a grid with the same coord
|
||||
*
|
||||
* +----------+
|
||||
* | CHANX |
|
||||
* | [x][y] |
|
||||
* +----------+
|
||||
*
|
||||
* +----------+
|
||||
* | Grid | height_offset = height - 1
|
||||
* | [x][y] |
|
||||
* +----------+
|
||||
*
|
||||
* +----------+
|
||||
* | Grid | height_offset = height - 2
|
||||
* | [x][y-1] |
|
||||
* +----------+
|
||||
* If the CHANX is in the middle of a multi-width and multi-height grid
|
||||
* it should locate at a grid whose height_offset is lower than the its height defined in physical_tile
|
||||
* When height_offset == height - 1, it means that the grid is at the top side of this multi-width and multi-height block
|
||||
***********************************************************************/
|
||||
bool is_chanx_exist(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chanx_coord) {
|
||||
return (grids[chanx_coord.x()][chanx_coord.y()].height_offset == grids[chanx_coord.x()][chanx_coord.y()].type->height - 1);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Idenfity if a Y-direction routing channel exist in the fabric
|
||||
* This could be entirely possible that a routig channel
|
||||
* is in the middle of a multi-width and multi-height grid
|
||||
*
|
||||
* As the chany always locates on right of a grid with the same coord
|
||||
*
|
||||
* +-----------+ +---------+ +--------+
|
||||
* | Grid | | Grid | | CHANY |
|
||||
* | [x-1][y] | | [x][y] | | [x][y] |
|
||||
* +-----------+ +---------+ +--------+
|
||||
* width_offset width_offset
|
||||
* = width - 2 = width -1
|
||||
* If the CHANY is in the middle of a multi-width and multi-height grid
|
||||
* it should locate at a grid whose width_offset is lower than the its width defined in physical_tile
|
||||
* When height_offset == height - 1, it means that the grid is at the top side of this multi-width and multi-height block
|
||||
***********************************************************************/
|
||||
bool is_chany_exist(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chany_coord) {
|
||||
return (grids[chany_coord.x()][chany_coord.y()].width_offset == grids[chany_coord.y()][chany_coord.y()].type->width - 1);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Identify if a X-direction routing channel is at the right side of a
|
||||
* multi-height grid
|
||||
*
|
||||
* +-----------------+
|
||||
* | |
|
||||
* | | +-------------+
|
||||
* | Grid | | CHANX |
|
||||
* | [x-1][y] | | [x][y] |
|
||||
* | | +-------------+
|
||||
* | |
|
||||
* +-----------------+
|
||||
***********************************************************************/
|
||||
bool is_chanx_right_to_multi_height_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chanx_coord) {
|
||||
VTR_ASSERT(0 < chanx_coord.x());
|
||||
if (1 == chanx_coord.x()) {
|
||||
/* This is already the LEFT side of FPGA fabric,
|
||||
* it is the same results as chanx is right to a multi-height grid
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We check the left neighbor of chanx, if it does not exist, the chanx is left to a multi-height grid */
|
||||
vtr::Point<size_t> left_chanx_coord(chanx_coord.x() - 1, chanx_coord.y());
|
||||
if (false == is_chanx_exist(grids, left_chanx_coord)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Identify if a X-direction routing channel is at the left side of a
|
||||
* multi-height grid
|
||||
*
|
||||
* +-----------------+
|
||||
* | |
|
||||
* +---------------+ | |
|
||||
* | CHANX | | Grid |
|
||||
* | [x][y] | | [x+1][y] |
|
||||
* +---------------+ | |
|
||||
* | |
|
||||
* +-----------------+
|
||||
***********************************************************************/
|
||||
bool is_chanx_left_to_multi_height_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chanx_coord) {
|
||||
VTR_ASSERT(chanx_coord.x() < grids.width() - 1);
|
||||
if (grids.width() - 2 == chanx_coord.x()) {
|
||||
/* This is already the RIGHT side of FPGA fabric,
|
||||
* it is the same results as chanx is right to a multi-height grid
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We check the right neighbor of chanx, if it does not exist, the chanx is left to a multi-height grid */
|
||||
vtr::Point<size_t> right_chanx_coord(chanx_coord.x() + 1, chanx_coord.y());
|
||||
if (false == is_chanx_exist(grids, right_chanx_coord)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Identify if a Y-direction routing channel is at the top side of a
|
||||
* multi-width grid
|
||||
*
|
||||
* +--------+
|
||||
* | CHANY |
|
||||
* | [x][y] |
|
||||
* +--------+
|
||||
*
|
||||
* +-----------------+
|
||||
* | |
|
||||
* | |
|
||||
* | Grid |
|
||||
* | [x-1][y] |
|
||||
* | |
|
||||
* | |
|
||||
* +-----------------+
|
||||
***********************************************************************/
|
||||
bool is_chany_top_to_multi_width_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chany_coord) {
|
||||
VTR_ASSERT(0 < chany_coord.y());
|
||||
if (1 == chany_coord.y()) {
|
||||
/* This is already the BOTTOM side of FPGA fabric,
|
||||
* it is the same results as chany is at the top of a multi-width grid
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We check the bottom neighbor of chany, if it does not exist, the chany is left to a multi-height grid */
|
||||
vtr::Point<size_t> bottom_chany_coord(chany_coord.x(), chany_coord.y() - 1);
|
||||
if (false == is_chany_exist(grids, bottom_chany_coord)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Identify if a Y-direction routing channel is at the bottom side of a
|
||||
* multi-width grid
|
||||
*
|
||||
* +-----------------+
|
||||
* | |
|
||||
* | |
|
||||
* | Grid |
|
||||
* | [x+1][y] |
|
||||
* | |
|
||||
* | |
|
||||
* +-----------------+
|
||||
* +--------+
|
||||
* | CHANY |
|
||||
* | [x][y] |
|
||||
* +--------+
|
||||
*
|
||||
***********************************************************************/
|
||||
bool is_chany_bottom_to_multi_width_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chany_coord) {
|
||||
VTR_ASSERT(chany_coord.y() < grids.height() - 1);
|
||||
if (grids.height() - 2 == chany_coord.y()) {
|
||||
/* This is already the TOP side of FPGA fabric,
|
||||
* it is the same results as chany is at the bottom of a multi-width grid
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We check the top neighbor of chany, if it does not exist, the chany is left to a multi-height grid */
|
||||
vtr::Point<size_t> top_chany_coord(chany_coord.x(), chany_coord.y() + 1);
|
||||
if (false == is_chany_exist(grids, top_chany_coord)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Get the track_id of a routing track w.r.t its coordinator
|
||||
* In tileable routing architecture, the track_id changes SB by SB.
|
||||
* Therefore the track_ids are stored in a vector, indexed by the relative coordinator
|
||||
* based on the starting point of the track
|
||||
* For routing tracks in INC_DIRECTION
|
||||
* (xlow, ylow) should be the starting point
|
||||
*
|
||||
* (xlow, ylow) (xhigh, yhigh)
|
||||
* track_id[0] -------------------------------> track_id[xhigh - xlow + yhigh - ylow]
|
||||
*
|
||||
* For routing tracks in DEC_DIRECTION
|
||||
* (xhigh, yhigh) should be the starting point
|
||||
*
|
||||
* (xlow, ylow) (xhigh, yhigh)
|
||||
* track_id[0] <------------------------------- track_id[xhigh - xlow + yhigh - ylow]
|
||||
*
|
||||
*
|
||||
***********************************************************************/
|
||||
short get_rr_node_actual_track_id(const RRGraph& rr_graph,
|
||||
const RRNodeId& track_rr_node,
|
||||
const vtr::Point<size_t>& coord,
|
||||
const vtr::vector<RRNodeId, std::vector<size_t>>& tileable_rr_graph_node_track_ids) {
|
||||
vtr::Point<size_t> low_coord(rr_graph.node_xlow(track_rr_node), rr_graph.node_ylow(track_rr_node));
|
||||
size_t offset = (int)abs((int)coord.x() - (int)low_coord.x() + (int)coord.y() - (int)low_coord.y());
|
||||
return tileable_rr_graph_node_track_ids[track_rr_node][offset];
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* 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 RRGraph& rr_graph,
|
||||
const RRNodeId& track_rr_node,
|
||||
const vtr::vector<RRNodeId, std::vector<size_t>>& tileable_rr_graph_node_track_ids) {
|
||||
/* Make sure we have CHANX or CHANY */
|
||||
VTR_ASSERT( (CHANX == rr_graph.node_type(track_rr_node))
|
||||
|| (CHANY == rr_graph.node_type(track_rr_node)) );
|
||||
|
||||
if (INC_DIRECTION == rr_graph.node_direction(track_rr_node)) {
|
||||
return tileable_rr_graph_node_track_ids[track_rr_node].back();
|
||||
}
|
||||
|
||||
VTR_ASSERT(DEC_DIRECTION == rr_graph.node_direction(track_rr_node));
|
||||
return tileable_rr_graph_node_track_ids[track_rr_node].front();
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Find the number of nodes in the same class
|
||||
* in a routing resource graph
|
||||
************************************************************************/
|
||||
short find_rr_graph_num_nodes(const RRGraph& rr_graph,
|
||||
const std::vector<t_rr_type>& node_types) {
|
||||
short counter = 0;
|
||||
|
||||
for (const RRNodeId& node : rr_graph.nodes()) {
|
||||
/* Bypass the nodes not in the class */
|
||||
if (node_types.end() == std::find(node_types.begin(), node_types.end(), rr_graph.node_type(node))) {
|
||||
continue;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Find the maximum fan-in for a given class of nodes
|
||||
* in a routing resource graph
|
||||
************************************************************************/
|
||||
short find_rr_graph_max_fan_in(const RRGraph& rr_graph,
|
||||
const std::vector<t_rr_type>& node_types) {
|
||||
short max_fan_in = 0;
|
||||
|
||||
for (const RRNodeId& node : rr_graph.nodes()) {
|
||||
/* Bypass the nodes not in the class */
|
||||
if (node_types.end() == std::find(node_types.begin(), node_types.end(), rr_graph.node_type(node))) {
|
||||
continue;
|
||||
}
|
||||
max_fan_in = std::max(rr_graph.node_fan_in(node), max_fan_in);
|
||||
}
|
||||
|
||||
return max_fan_in;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Find the minimum fan-in for a given class of nodes
|
||||
* in a routing resource graph
|
||||
************************************************************************/
|
||||
short find_rr_graph_min_fan_in(const RRGraph& rr_graph,
|
||||
const std::vector<t_rr_type>& node_types) {
|
||||
short min_fan_in = 0;
|
||||
|
||||
for (const RRNodeId& node : rr_graph.nodes()) {
|
||||
/* Bypass the nodes not in the class */
|
||||
if (node_types.end() == std::find(node_types.begin(), node_types.end(), rr_graph.node_type(node))) {
|
||||
continue;
|
||||
}
|
||||
min_fan_in = std::min(rr_graph.node_fan_in(node), min_fan_in);
|
||||
}
|
||||
|
||||
|
||||
return min_fan_in;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Find the average fan-in for a given class of nodes
|
||||
* in a routing resource graph
|
||||
************************************************************************/
|
||||
short find_rr_graph_average_fan_in(const RRGraph& rr_graph,
|
||||
const std::vector<t_rr_type>& node_types) {
|
||||
/* Get the maximum SB mux size */
|
||||
size_t sum = 0;
|
||||
size_t counter = 0;
|
||||
|
||||
for (const RRNodeId& node : rr_graph.nodes()) {
|
||||
/* Bypass the nodes not in the class */
|
||||
if (node_types.end() == std::find(node_types.begin(), node_types.end(), rr_graph.node_type(node))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sum += rr_graph.node_fan_in(node);
|
||||
counter++;
|
||||
}
|
||||
|
||||
return sum / counter;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Print statistics of multiplexers in a routing resource graph
|
||||
************************************************************************/
|
||||
void print_rr_graph_mux_stats(const RRGraph& rr_graph) {
|
||||
|
||||
/* Print MUX size distribution */
|
||||
std::vector<t_rr_type> sb_node_types;
|
||||
sb_node_types.push_back(CHANX);
|
||||
sb_node_types.push_back(CHANY);
|
||||
|
||||
/* Print statistics */
|
||||
VTR_LOG("------------------------------------------------\n");
|
||||
VTR_LOG("Total No. of Switch Block multiplexer size: %d\n",
|
||||
find_rr_graph_num_nodes(rr_graph, sb_node_types));
|
||||
VTR_LOG("Maximum Switch Block multiplexer size: %d\n",
|
||||
find_rr_graph_max_fan_in(rr_graph, sb_node_types));
|
||||
VTR_LOG("Minimum Switch Block multiplexer size: %d\n",
|
||||
find_rr_graph_min_fan_in(rr_graph, sb_node_types));
|
||||
VTR_LOG("Average Switch Block multiplexer size: %lu\n",
|
||||
find_rr_graph_average_fan_in(rr_graph, sb_node_types));
|
||||
VTR_LOG("------------------------------------------------\n");
|
||||
|
||||
/* Get the maximum CB mux size */
|
||||
std::vector<t_rr_type> cb_node_types(1, IPIN);
|
||||
|
||||
VTR_LOG("------------------------------------------------\n");
|
||||
VTR_LOG("Total No. of Connection Block Multiplexer size: %d\n",
|
||||
find_rr_graph_num_nodes(rr_graph, cb_node_types));
|
||||
VTR_LOG("Maximum Connection Block Multiplexer size: %d\n",
|
||||
find_rr_graph_max_fan_in(rr_graph, cb_node_types));
|
||||
VTR_LOG("Minimum Connection Block Multiplexer size: %d\n",
|
||||
find_rr_graph_min_fan_in(rr_graph, cb_node_types));
|
||||
VTR_LOG("Average Connection Block Multiplexer size: %lu\n",
|
||||
find_rr_graph_average_fan_in(rr_graph, cb_node_types));
|
||||
VTR_LOG("------------------------------------------------\n");
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,87 @@
|
|||
#ifndef RR_GRAPH_BUILDER_UTILS_H
|
||||
#define RR_GRAPH_BUILDER_UTILS_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include "device_grid.h"
|
||||
#include "rr_graph_obj.h"
|
||||
#include "vtr_geometry.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
int get_grid_pin_class_index(const t_grid_tile& cur_grid,
|
||||
const int pin_index);
|
||||
|
||||
e_side determine_io_grid_pin_side(const vtr::Point<size_t>& device_size,
|
||||
const vtr::Point<size_t>& grid_coordinate);
|
||||
|
||||
std::vector<int> get_grid_side_pins(const t_grid_tile& cur_grid,
|
||||
const e_pin_type& pin_type,
|
||||
const e_side& pin_side,
|
||||
const int& pin_width,
|
||||
const int& pin_height);
|
||||
|
||||
size_t get_grid_num_pins(const t_grid_tile& cur_grid,
|
||||
const e_pin_type& pin_type,
|
||||
const e_side& io_side);
|
||||
|
||||
size_t get_grid_num_classes(const t_grid_tile& cur_grid,
|
||||
const e_pin_type& pin_type);
|
||||
|
||||
bool is_chanx_exist(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chanx_coord);
|
||||
|
||||
bool is_chany_exist(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chany_coord);
|
||||
|
||||
bool is_chanx_right_to_multi_height_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chanx_coord);
|
||||
|
||||
bool is_chanx_left_to_multi_height_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chanx_coord);
|
||||
|
||||
bool is_chany_top_to_multi_width_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chany_coord);
|
||||
|
||||
bool is_chany_bottom_to_multi_width_grid(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chany_coord);
|
||||
|
||||
short get_rr_node_actual_track_id(const RRGraph& rr_graph,
|
||||
const RRNodeId& track_rr_node,
|
||||
const vtr::Point<size_t>& coord,
|
||||
const vtr::vector<RRNodeId, std::vector<size_t>>& tileable_rr_graph_node_track_ids);
|
||||
|
||||
vtr::Point<size_t> get_track_rr_node_start_coordinator(const RRGraph& rr_graph,
|
||||
const RRNodeId& track_rr_node);
|
||||
|
||||
vtr::Point<size_t> get_track_rr_node_end_coordinator(const RRGraph& rr_graph,
|
||||
const RRNodeId& track_rr_node);
|
||||
|
||||
short get_track_rr_node_end_track_id(const RRGraph& rr_graph,
|
||||
const RRNodeId& track_rr_node,
|
||||
const vtr::vector<RRNodeId, std::vector<size_t>>& tileable_rr_graph_node_track_ids);
|
||||
|
||||
short find_rr_graph_num_nodes(const RRGraph& rr_graph,
|
||||
const std::vector<t_rr_type>& node_types);
|
||||
|
||||
short find_rr_graph_max_fan_in(const RRGraph& rr_graph,
|
||||
const std::vector<t_rr_type>& node_types);
|
||||
|
||||
short find_rr_graph_min_fan_in(const RRGraph& rr_graph,
|
||||
const std::vector<t_rr_type>& node_types);
|
||||
|
||||
short find_rr_graph_average_fan_in(const RRGraph& rr_graph,
|
||||
const std::vector<t_rr_type>& node_types);
|
||||
|
||||
void print_rr_graph_mux_stats(const RRGraph& rr_graph);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
||||
|
|
@ -117,7 +117,7 @@ std::vector<RRSegmentId> RRGSB::get_chan_segment_ids(const e_side& side) const {
|
|||
}
|
||||
|
||||
/* Get a list of rr_nodes whose sed_id is specified */
|
||||
std::vector<RRNodeId> RRGSB::get_chan_node_ids_by_segment_ids(const e_side& side,
|
||||
std::vector<size_t> RRGSB::get_chan_node_ids_by_segment_ids(const e_side& side,
|
||||
const RRSegmentId& seg_id) const {
|
||||
return chan_node_[size_t(side)].get_node_ids_by_segment_ids(seg_id);
|
||||
}
|
|
@ -19,11 +19,11 @@ namespace openfpga {
|
|||
* 2. A X-direction Connection block locates at the left side of the switch block
|
||||
* 2. A Y-direction Connection block locates at the top side of the switch block
|
||||
*
|
||||
* +---------------------------------+
|
||||
* | Y-direction CB |
|
||||
* | [x][y + 1] |
|
||||
* +---------------------------------+
|
||||
*
|
||||
* +-------------+ +---------------------------------+
|
||||
* | | | Y-direction CB |
|
||||
* | Grid | | [x][y + 1] |
|
||||
* | [x][y+1] | +---------------------------------+
|
||||
* +-------------+
|
||||
* TOP SIDE
|
||||
* +-------------+ +---------------------------------+
|
||||
* | | | OPIN_NODE CHAN_NODES OPIN_NODES |
|
||||
|
@ -77,8 +77,8 @@ class RRGSB {
|
|||
std::vector<RRSegmentId> get_chan_segment_ids(const e_side& side) const;
|
||||
|
||||
/* Get a list of segments used in this routing channel */
|
||||
std::vector<RRNodeId> get_chan_node_ids_by_segment_ids(const e_side& side,
|
||||
const RRSegmentId& seg_id) const;
|
||||
std::vector<size_t> get_chan_node_ids_by_segment_ids(const e_side& side,
|
||||
const RRSegmentId& seg_id) const;
|
||||
|
||||
/* get a rr_node at a given side and track_id */
|
||||
RRNodeId get_chan_node(const e_side& side, const size_t& track_id) const;
|
|
@ -0,0 +1,238 @@
|
|||
/************************************************************************
|
||||
* 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 <vector>
|
||||
#include <algorithm>
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
#include "tileable_chan_details_builder.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/************************************************************************
|
||||
* 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;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Adapt the number of channel width to a tileable routing architecture
|
||||
***********************************************************************/
|
||||
int adapt_to_tileable_route_chan_width(const int& chan_width,
|
||||
const std::vector<t_segment_inf>& segment_infs) {
|
||||
int tileable_chan_width = 0;
|
||||
|
||||
/* Estimate the number of segments per type by the given ChanW*/
|
||||
std::vector<size_t> num_tracks_per_seg_type = get_num_tracks_per_seg_type(chan_width,
|
||||
segment_infs,
|
||||
true); /* Force to use the full segment group */
|
||||
/* Sum-up the number of tracks */
|
||||
for (size_t iseg = 0; iseg < num_tracks_per_seg_type.size(); ++iseg) {
|
||||
tileable_chan_width += num_tracks_per_seg_type[iseg];
|
||||
}
|
||||
|
||||
return tileable_chan_width;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* 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 bool& force_start,
|
||||
const bool& force_end,
|
||||
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 */
|
||||
}
|
||||
VTR_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 */
|
||||
VTR_ASSERT(cur_track == actual_chan_width);
|
||||
|
||||
/* If this is on the border of a device/heterogeneous blocks, segments should start/end */
|
||||
if (true == force_start) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* If this is on the border of a device/heterogeneous blocks, segments should start/end */
|
||||
if (true == force_end) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
return chan_node_details;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef TILEABLE_CHAN_DETAILS_BUILDER_H
|
||||
#define TILEABLE_CHAN_DETAILS_BUILDER_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <vector>
|
||||
#include "physical_types.h"
|
||||
#include "chan_node_details.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
int adapt_to_tileable_route_chan_width(const int& chan_width, const std::vector<t_segment_inf>& segment_inf);
|
||||
|
||||
ChanNodeDetails build_unidir_chan_node_details(const size_t& chan_width,
|
||||
const size_t& max_seg_length,
|
||||
const bool& force_start,
|
||||
const bool& force_end,
|
||||
const std::vector<t_segment_inf>& segment_inf);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,80 @@
|
|||
#ifndef TILEABLE_RR_GRAPH_GSB_H
|
||||
#define TILEABLE_RR_GRAPH_GSB_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <vector>
|
||||
|
||||
#include "vtr_vector.h"
|
||||
#include "vtr_geometry.h"
|
||||
|
||||
#include "physical_types.h"
|
||||
#include "device_grid.h"
|
||||
|
||||
#include "rr_gsb.h"
|
||||
#include "rr_graph_obj.h"
|
||||
#include "clb2clb_directs.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/************************************************************************
|
||||
* Data stuctures related to the functions
|
||||
***********************************************************************/
|
||||
typedef std::vector<std::vector<std::vector<RRNodeId>>> t_track2track_map;
|
||||
typedef std::vector<std::vector<std::vector<RRNodeId>>> t_track2pin_map;
|
||||
typedef std::vector<std::vector<std::vector<RRNodeId>>> t_pin2track_map;
|
||||
|
||||
/************************************************************************
|
||||
* Functions
|
||||
***********************************************************************/
|
||||
t_track2track_map build_gsb_track_to_track_map(const RRGraph& rr_graph,
|
||||
const RRGSB& rr_gsb,
|
||||
const e_switch_block_type& sb_type,
|
||||
const int& Fs,
|
||||
const e_switch_block_type& sb_subtype,
|
||||
const int& subFs,
|
||||
const bool& wire_opposite_side,
|
||||
const std::vector<t_segment_inf>& segment_inf);
|
||||
|
||||
RRGSB build_one_tileable_rr_gsb(const DeviceGrid& grids,
|
||||
const RRGraph& rr_graph,
|
||||
const std::vector<size_t>& device_chan_width,
|
||||
const std::vector<t_segment_inf>& segment_inf,
|
||||
const vtr::Point<size_t>& gsb_coordinate);
|
||||
|
||||
void build_edges_for_one_tileable_rr_gsb(RRGraph& rr_graph,
|
||||
const RRGSB& rr_gsb,
|
||||
const t_track2pin_map& track2ipin_map,
|
||||
const t_pin2track_map& opin2track_map,
|
||||
const t_track2track_map& track2track_map,
|
||||
const vtr::vector<RRNodeId, RRSwitchId> rr_node_driver_switches);
|
||||
|
||||
t_track2pin_map build_gsb_track_to_ipin_map(const RRGraph& rr_graph,
|
||||
const RRGSB& rr_gsb,
|
||||
const DeviceGrid& grids,
|
||||
const std::vector<t_segment_inf>& segment_inf,
|
||||
int** Fc_in);
|
||||
|
||||
t_pin2track_map build_gsb_opin_to_track_map(const RRGraph& rr_graph,
|
||||
const RRGSB& rr_gsb,
|
||||
const DeviceGrid& grids,
|
||||
const std::vector<t_segment_inf>& segment_inf,
|
||||
int** Fc_out);
|
||||
|
||||
void build_direct_connections_for_one_gsb(RRGraph& rr_graph,
|
||||
const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& from_grid_coordinate,
|
||||
const RRSwitchId& delayless_switch,
|
||||
const std::vector<t_direct_inf>& directs,
|
||||
const std::vector<t_clb_to_clb_directs>& clb_to_clb_directs);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
/************************************************************************
|
||||
* This file contains functions that are used to allocate nodes
|
||||
* for the tileable routing resource graph builder
|
||||
***********************************************************************/
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
#include "vtr_geometry.h"
|
||||
|
||||
#include "vpr_utils.h"
|
||||
|
||||
#include "rr_graph_builder_utils.h"
|
||||
#include "tileable_chan_details_builder.h"
|
||||
#include "tileable_rr_graph_node_builder.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/************************************************************************
|
||||
* Find the number output pins by considering all the grid
|
||||
***********************************************************************/
|
||||
static
|
||||
size_t estimate_num_grid_rr_nodes_by_type(const DeviceGrid& grids,
|
||||
const t_rr_type& node_type) {
|
||||
size_t num_grid_rr_nodes = 0;
|
||||
|
||||
for (size_t ix = 0; ix < grids.width(); ++ix) {
|
||||
for (size_t iy = 0; iy < grids.height(); ++iy) {
|
||||
|
||||
/* Skip EMPTY tiles */
|
||||
if (true == is_empty_type(grids[ix][iy].type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Skip height > 1 or width > 1 tiles (mostly heterogeneous blocks) */
|
||||
if ( (0 < grids[ix][iy].width_offset)
|
||||
|| (0 < grids[ix][iy].height_offset) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
enum e_side io_side = NUM_SIDES;
|
||||
|
||||
/* If this is the block on borders, we consider IO side */
|
||||
if (true == is_io_type(grids[ix][iy].type)) {
|
||||
vtr::Point<size_t> io_device_size(grids.width() - 1, grids.height() - 1);
|
||||
vtr::Point<size_t> grid_coordinate(ix, iy);
|
||||
io_side = determine_io_grid_pin_side(io_device_size, grid_coordinate);
|
||||
}
|
||||
|
||||
switch (node_type) {
|
||||
case OPIN:
|
||||
/* get the number of OPINs */
|
||||
num_grid_rr_nodes += get_grid_num_pins(grids[ix][iy], DRIVER, io_side);
|
||||
break;
|
||||
case IPIN:
|
||||
/* get the number of IPINs */
|
||||
num_grid_rr_nodes += get_grid_num_pins(grids[ix][iy], RECEIVER, io_side);
|
||||
break;
|
||||
case SOURCE:
|
||||
/* SOURCE: number of classes whose type is DRIVER */
|
||||
num_grid_rr_nodes += get_grid_num_classes(grids[ix][iy], DRIVER);
|
||||
break;
|
||||
case SINK:
|
||||
/* SINK: number of classes whose type is RECEIVER */
|
||||
num_grid_rr_nodes += get_grid_num_classes(grids[ix][iy], RECEIVER);
|
||||
break;
|
||||
default:
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Invalid routing resource node!\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return num_grid_rr_nodes;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* For X-direction Channel: CHANX
|
||||
* We pair each x-direction routing channel to the grid below it
|
||||
* as they share the same coordinate
|
||||
*
|
||||
* As such, the range of CHANX coordinate starts from x = 1, y = 0
|
||||
* which is the grid (I/O) at the left bottom of the fabric
|
||||
*
|
||||
* As such, the range of CHANX coordinate ends to x = width - 2, y = height - 2
|
||||
* which is the grid at the top right of the core fabric
|
||||
* Note that the I/O ring is
|
||||
*
|
||||
* TOP SIDE OF FPGA
|
||||
*
|
||||
* +-------------+ +-------------+ +---------------------+
|
||||
* | Grid | | Grid | ... | Grid |
|
||||
* | [1][0] | | [2][0] | | [width-2][height-1] |
|
||||
* +-------------+ +-------------+ +---------------------+
|
||||
*
|
||||
* +-------------+ +-------------+ +---------------------+
|
||||
* | X-Channel | | X-Channel | ... | X-Channel |
|
||||
* | [1][0] | | [2][0] | | [width-2][height-2] |
|
||||
* +-------------+ +-------------+ +---------------------+
|
||||
*
|
||||
* +-------------+ +-------------+ +---------------------+
|
||||
* | Grid | | Grid | ... | Grid |
|
||||
* | [1][0] | | [2][0] | | [width-2][height-2] |
|
||||
* +-------------+ +-------------+ +---------------------+
|
||||
*
|
||||
* ... ... ...
|
||||
*
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
* | X-Channel | | X-Channel | ... | X-Channel |
|
||||
* | [1][1] | | [2][1] | | [width-2][1] |
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
*
|
||||
* LEFT +-------------+ +-------------+ +--------------+ RIGHT
|
||||
* SIDE | Grid | | Grid | ... | Grid | SIDE
|
||||
* GRID | [1][1] | | [2][1] | | [width-2][1] | GRID
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
*
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
* | X-Channel | | X-Channel | ... | X-Channel |
|
||||
* | [1][0] | | [2][0] | | [width-2][0] |
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
*
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
* | Grid | | Grid | ... | Grid |
|
||||
* | [1][0] | | [2][0] | | [width-2][0] |
|
||||
* +-------------+ +-------------+ +--------------+
|
||||
*
|
||||
* BOTTOM SIDE OF FPGA
|
||||
*
|
||||
* The figure above describe how the X-direction routing channels are
|
||||
* organized in a homogeneous FPGA fabric
|
||||
* Note that we talk about general-purpose uni-directional routing architecture here
|
||||
* It means that a routing track may span across multiple grids
|
||||
* However, the hard limits are as follows
|
||||
* All the routing tracks will start at the most LEFT routing channel
|
||||
* All the routing tracks will end at the most RIGHT routing channel
|
||||
*
|
||||
* Things will become more complicated in terms of track starting and end
|
||||
* in the context of heterogeneous FPGAs
|
||||
* We may have a grid which span multiple column and rows, as exemplified in the figure below
|
||||
* In such case,
|
||||
* all the routing tracks [x-1][y] at the left side of the grid [x][y] are forced to end
|
||||
* all the routing tracks [x+2][y] at the right side of the grid [x][y] are forced to start
|
||||
* And there are no routing tracks inside the grid[x][y]
|
||||
* It means that X-channel [x][y] & [x+1][y] will no exist
|
||||
*
|
||||
* +------------+ +-------------+ +-------------+ +--------------+
|
||||
* | X-Channel | | X-Channel | | X-Channel | | X-Channel |
|
||||
* | [x-1][y+2] | | [x][y+2] | | [x+1][y+2] | | [x+2][y+2] |
|
||||
* +------------+ +-------------+ +-------------+ +--------------+
|
||||
*
|
||||
* +------------+ +-----------------------------------+ +--------------+
|
||||
* | Grid | | | | Grid |
|
||||
* | [x-1][y+1] | | | | [x+2][y+1] |
|
||||
* +------------+ | | +--------------+
|
||||
* | |
|
||||
* +------------+ | | +--------------+
|
||||
* | X-channel | | Grid | | X-Channel |
|
||||
* | [x-1][y] | | [x][y] - [x+1][y+1] | | [x+2][y] |
|
||||
* +------------+ | | +--------------+
|
||||
* | |
|
||||
* +------------+ | | +--------------+
|
||||
* | Grid | | | | Grid |
|
||||
* | [x-1][y] | | | | [x+2][y] |
|
||||
* +------------+ +-----------------------------------+ +--------------+
|
||||
*
|
||||
*
|
||||
*
|
||||
***********************************************************************/
|
||||
static
|
||||
size_t estimate_num_chanx_rr_nodes(const DeviceGrid& grids,
|
||||
const size_t& chan_width,
|
||||
const std::vector<t_segment_inf>& segment_infs) {
|
||||
size_t num_chanx_rr_nodes = 0;
|
||||
|
||||
for (size_t iy = 0; iy < grids.height() - 1; ++iy) {
|
||||
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
|
||||
vtr::Point<size_t> chanx_coord(ix, iy);
|
||||
|
||||
/* Bypass if the routing channel does not exist */
|
||||
if (false == is_chanx_exist(grids, chanx_coord)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool force_start = false;
|
||||
bool force_end = false;
|
||||
|
||||
/* All the tracks have to start when
|
||||
* - the routing channel touch the RIGHT side a heterogeneous block
|
||||
* - the routing channel touch the LEFT side of FPGA
|
||||
*/
|
||||
if (true == is_chanx_right_to_multi_height_grid(grids, chanx_coord)) {
|
||||
force_start = true;
|
||||
}
|
||||
|
||||
/* All the tracks have to end when
|
||||
* - the routing channel touch the LEFT side a heterogeneous block
|
||||
* - the routing channel touch the RIGHT side of FPGA
|
||||
*/
|
||||
if (true == is_chanx_left_to_multi_height_grid(grids, chanx_coord)) {
|
||||
force_end = true;
|
||||
}
|
||||
|
||||
/* Evaluate if the routing channel locates in the middle of a grid */
|
||||
ChanNodeDetails chanx_details = build_unidir_chan_node_details(chan_width, grids.width() - 2, force_start, force_end, segment_infs);
|
||||
/* When an INC_DIRECTION CHANX starts, we need a new rr_node */
|
||||
num_chanx_rr_nodes += chanx_details.get_num_starting_tracks(INC_DIRECTION);
|
||||
/* When an DEC_DIRECTION CHANX ends, we need a new rr_node */
|
||||
num_chanx_rr_nodes += chanx_details.get_num_ending_tracks(DEC_DIRECTION);
|
||||
}
|
||||
}
|
||||
|
||||
return num_chanx_rr_nodes;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Estimate the number of CHANY rr_nodes for Y-direction routing channels
|
||||
* The technical rationale is very similar to the X-direction routing channel
|
||||
* Refer to the detailed explanation there
|
||||
***********************************************************************/
|
||||
static
|
||||
size_t estimate_num_chany_rr_nodes(const DeviceGrid& grids,
|
||||
const size_t& chan_width,
|
||||
const std::vector<t_segment_inf>& segment_infs) {
|
||||
size_t num_chany_rr_nodes = 0;
|
||||
|
||||
for (size_t ix = 0; ix < grids.width() - 1; ++ix) {
|
||||
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
|
||||
vtr::Point<size_t> chany_coord(ix, iy);
|
||||
|
||||
/* Bypass if the routing channel does not exist */
|
||||
if (false == is_chany_exist(grids, chany_coord)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool force_start = false;
|
||||
bool force_end = false;
|
||||
|
||||
/* All the tracks have to start when
|
||||
* - the routing channel touch the TOP side a heterogeneous block
|
||||
* - the routing channel touch the BOTTOM side of FPGA
|
||||
*/
|
||||
if (true == is_chany_top_to_multi_width_grid(grids, chany_coord)) {
|
||||
force_start = true;
|
||||
}
|
||||
|
||||
/* All the tracks have to end when
|
||||
* - the routing channel touch the BOTTOM side a heterogeneous block
|
||||
* - the routing channel touch the TOP side of FPGA
|
||||
*/
|
||||
if (true == is_chany_bottom_to_multi_width_grid(grids, chany_coord)) {
|
||||
force_end = true;
|
||||
}
|
||||
|
||||
ChanNodeDetails chany_details = build_unidir_chan_node_details(chan_width, grids.height() - 2, force_start, force_end, segment_infs);
|
||||
/* When an INC_DIRECTION CHANX starts, we need a new rr_node */
|
||||
num_chany_rr_nodes += chany_details.get_num_starting_tracks(INC_DIRECTION);
|
||||
/* When an DEC_DIRECTION CHANX ends, we need a new rr_node */
|
||||
num_chany_rr_nodes += chany_details.get_num_ending_tracks(DEC_DIRECTION);
|
||||
}
|
||||
}
|
||||
|
||||
return num_chany_rr_nodes;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Estimate the number of nodes by each type in a routing resource graph
|
||||
***********************************************************************/
|
||||
static
|
||||
std::vector<size_t> estimate_num_rr_nodes(const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chan_width,
|
||||
const std::vector<t_segment_inf>& segment_infs) {
|
||||
|
||||
/* Reset the OPIN, IPIN, SOURCE, SINK counter to be zero */
|
||||
std::vector<size_t> num_rr_nodes_per_type(NUM_RR_TYPES, 0);
|
||||
|
||||
/**
|
||||
* 1 Find number of rr nodes related to grids
|
||||
*/
|
||||
num_rr_nodes_per_type[OPIN] = estimate_num_grid_rr_nodes_by_type(grids, OPIN);
|
||||
num_rr_nodes_per_type[IPIN] = estimate_num_grid_rr_nodes_by_type(grids, IPIN);
|
||||
num_rr_nodes_per_type[SOURCE] = estimate_num_grid_rr_nodes_by_type(grids, SOURCE);
|
||||
num_rr_nodes_per_type[SINK] = estimate_num_grid_rr_nodes_by_type(grids, SINK);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
num_rr_nodes_per_type[CHANX] = estimate_num_chanx_rr_nodes(grids, chan_width.x(), segment_infs);
|
||||
num_rr_nodes_per_type[CHANY] = estimate_num_chany_rr_nodes(grids, chan_width.y(), segment_infs);
|
||||
|
||||
return num_rr_nodes_per_type;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Allocate rr_nodes to a rr_graph object
|
||||
* This function just allocate the memory and ensure its efficiency
|
||||
* It will NOT fill detailed information for each node!!!
|
||||
*
|
||||
* Note: ensure that there are NO nodes in the rr_graph
|
||||
***********************************************************************/
|
||||
void alloc_rr_graph_nodes(RRGraph& rr_graph,
|
||||
const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chan_width,
|
||||
const std::vector<t_segment_inf>& segment_infs) {
|
||||
VTR_ASSERT(0 == rr_graph.nodes().size());
|
||||
|
||||
std::vector<size_t> num_rr_nodes_per_type = estimate_num_rr_nodes(grids, chan_width, segment_infs);
|
||||
|
||||
/* Reserve the number of node to be memory efficient */
|
||||
size_t num_nodes = 0;
|
||||
for (const size_t& num_node_per_type : num_rr_nodes_per_type) {
|
||||
num_nodes += num_node_per_type;
|
||||
}
|
||||
|
||||
rr_graph.reserve_nodes(num_nodes);
|
||||
|
||||
/* Add nodes by types */
|
||||
for (const t_rr_type& node_type : {SOURCE, SINK, IPIN, OPIN, CHANX, CHANY}) {
|
||||
for (size_t inode = 0; inode < num_rr_nodes_per_type[size_t(node_type)]; ++inode) {
|
||||
rr_graph.create_node(node_type);
|
||||
}
|
||||
}
|
||||
|
||||
VTR_ASSERT(num_nodes == rr_graph.nodes().size());
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef TILEABLE_RR_GRAPH_NODE_BUILDER_H
|
||||
#define TILEABLE_RR_GRAPH_NODE_BUILDER_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_geometry.h"
|
||||
|
||||
/* Headers from readarch library */
|
||||
#include "physical_types.h"
|
||||
|
||||
/* Headers from vpr library */
|
||||
#include "rr_graph_obj.h"
|
||||
#include "device_grid.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
void alloc_rr_graph_nodes(RRGraph& rr_graph,
|
||||
const DeviceGrid& grids,
|
||||
const vtr::Point<size_t>& chan_width,
|
||||
const std::vector<t_segment_inf>& segment_infs);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue