Merge branch 'refactoring' into dev

This commit is contained in:
tangxifan 2020-03-05 15:36:16 -07:00
commit 5dcffb1a6e
19 changed files with 2988 additions and 29 deletions

View File

@ -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")

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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

View File

@ -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);
}
}

View File

@ -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&);

View File

@ -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 */

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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