OpenFPGA/vpr/src/tileable_rr_graph/rr_gsb.cpp

1159 lines
39 KiB
C++

/************************************************************************
* Member functions for class RRGSB
***********************************************************************/
/* Headers from vtrutil library */
#include "vtr_log.h"
#include "vtr_assert.h"
/* Headers from openfpgautil library */
#include "openfpga_side_manager.h"
#include "openfpga_rr_graph_utils.h"
#include "rr_gsb.h"
/* namespace openfpga begins */
namespace openfpga {
/************************************************************************
* Constructors
***********************************************************************/
/* Constructor for an empty object */
RRGSB::RRGSB() {
/* Set a clean start! */
coordinate_.set(0, 0);
chan_node_.clear();
chan_node_direction_.clear();
chan_node_in_edges_.clear();
ipin_node_.clear();
opin_node_.clear();
}
/* Copy constructor */
RRGSB::RRGSB(const RRGSB& src) {
/* Copy coordinate */
this->set(src);
return;
}
/************************************************************************
* Accessors
***********************************************************************/
/* Get the number of sides of this SB */
size_t RRGSB::get_num_sides() const {
VTR_ASSERT (validate_num_sides());
return chan_node_direction_.size();
}
/* Get the number of routing tracks on a side */
size_t RRGSB::get_chan_width(const e_side& side) const {
SideManager side_manager(side);
VTR_ASSERT(side_manager.validate());
return chan_node_[side_manager.to_size_t()].get_chan_width();
}
/* Get the number of routing tracks on a side */
t_rr_type RRGSB::get_chan_type(const e_side& side) const {
SideManager side_manager(side);
VTR_ASSERT(side_manager.validate());
return chan_node_[side_manager.to_size_t()].get_type();
}
/* Get the maximum number of routing tracks on all sides */
size_t RRGSB::get_max_chan_width() const {
size_t max_chan_width = 0;
for (size_t side = 0; side < get_num_sides(); ++side) {
SideManager side_manager(side);
max_chan_width = std::max(max_chan_width, get_chan_width(side_manager.get_side()));
}
return max_chan_width;
}
/* Get the number of routing tracks of a X/Y-direction CB */
size_t RRGSB::get_cb_chan_width(const t_rr_type& cb_type) const {
return get_chan_width(get_cb_chan_side(cb_type));
}
/* Get the sides of ipin_nodes belong to the cb */
std::vector<enum e_side> RRGSB::get_cb_ipin_sides(const t_rr_type& cb_type) const {
VTR_ASSERT (validate_cb_type(cb_type));
std::vector<enum e_side> ipin_sides;
/* Make sure a clean start */
ipin_sides.clear();
switch(cb_type) {
case CHANX:
ipin_sides.push_back(TOP);
ipin_sides.push_back(BOTTOM);
break;
case CHANY:
ipin_sides.push_back(RIGHT);
ipin_sides.push_back(LEFT);
break;
default:
VTR_LOG("Invalid type of connection block!\n");
exit(1);
}
return ipin_sides;
}
/* Get the direction of a rr_node at a given side and track_id */
enum PORTS RRGSB::get_chan_node_direction(const e_side& side, const size_t& track_id) const {
SideManager side_manager(side);
VTR_ASSERT(side_manager.validate());
/* Ensure the side is valid in the context of this switch block */
VTR_ASSERT( validate_side(side) );
/* Ensure the track is valid in the context of this switch block at a specific side */
VTR_ASSERT( validate_track_id(side, track_id) );
return chan_node_direction_[side_manager.to_size_t()][track_id];
}
/* Get a list of segments used in this routing channel */
std::vector<RRSegmentId> RRGSB::get_chan_segment_ids(const e_side& side) const {
SideManager side_manager(side);
VTR_ASSERT(side_manager.validate());
/* Ensure the side is valid in the context of this switch block */
VTR_ASSERT( validate_side(side) );
return chan_node_[side_manager.to_size_t()].get_segment_ids();
}
/* Get a list of rr_nodes whose sed_id is specified */
std::vector<size_t> RRGSB::get_chan_node_ids_by_segment_ids(const e_side& side,
const RRSegmentId& seg_id) const {
return chan_node_[size_t(side)].get_node_ids_by_segment_ids(seg_id);
}
/* get a rr_node at a given side and track_id */
RRNodeId RRGSB::get_chan_node(const e_side& side, const size_t& track_id) const {
SideManager side_manager(side);
VTR_ASSERT(side_manager.validate());
/* Ensure the side is valid in the context of this switch block */
VTR_ASSERT( validate_side(side) );
/* Ensure the track is valid in the context of this switch block at a specific side */
VTR_ASSERT( validate_track_id(side, track_id) );
return chan_node_[side_manager.to_size_t()].get_node(track_id);
}
std::vector<RREdgeId> RRGSB::get_chan_node_in_edges(const RRGraph& rr_graph,
const e_side& side,
const size_t& track_id) const {
SideManager side_manager(side);
VTR_ASSERT(side_manager.validate());
/* Ensure the side is valid in the context of this switch block */
VTR_ASSERT( validate_side(side) );
/* Ensure the track is valid in the context of this switch block at a specific side */
VTR_ASSERT( validate_track_id(side, track_id) );
/* The chan node must be an output port for the GSB, we allow users to access input edges*/
VTR_ASSERT(OUT_PORT == get_chan_node_direction(side, track_id));
/* if sorted, we give sorted edges
* if not sorted, we give the empty vector
*/
if (0 == chan_node_in_edges_.size()) {
std::vector<RREdgeId> unsorted_edges;
for (const RREdgeId& edge : rr_graph.node_in_edges(get_chan_node(side, track_id))) {
unsorted_edges.push_back(edge);
}
return unsorted_edges;
}
return chan_node_in_edges_[side_manager.to_size_t()][track_id];
}
/* get the segment id of a channel rr_node */
RRSegmentId RRGSB::get_chan_node_segment(const e_side& side, const size_t& track_id) const {
SideManager side_manager(side);
VTR_ASSERT(side_manager.validate());
/* Ensure the side is valid in the context of this switch block */
VTR_ASSERT( validate_side(side) );
/* Ensure the track is valid in the context of this switch block at a specific side */
VTR_ASSERT( validate_track_id(side, track_id) );
return chan_node_[side_manager.to_size_t()].get_node_segment(track_id);
}
/* Get the number of IPIN rr_nodes on a side */
size_t RRGSB::get_num_ipin_nodes(const e_side& side) const {
SideManager side_manager(side);
VTR_ASSERT(side_manager.validate());
return ipin_node_[side_manager.to_size_t()].size();
}
/* get a opin_node at a given side and track_id */
RRNodeId RRGSB::get_ipin_node(const e_side& side, const size_t& node_id) const {
SideManager side_manager(side);
VTR_ASSERT(side_manager.validate());
/* Ensure the side is valid in the context of this switch block */
VTR_ASSERT( validate_side(side) );
/* Ensure the track is valid in the context of this switch block at a specific side */
VTR_ASSERT( validate_ipin_node_id(side, node_id) );
return ipin_node_[side_manager.to_size_t()][node_id];
}
/* Get the number of OPIN rr_nodes on a side */
size_t RRGSB::get_num_opin_nodes(const e_side& side) const {
SideManager side_manager(side);
VTR_ASSERT(side_manager.validate());
return opin_node_[side_manager.to_size_t()].size();
}
/* get a opin_node at a given side and track_id */
RRNodeId RRGSB::get_opin_node(const e_side& side, const size_t& node_id) const {
SideManager side_manager(side);
VTR_ASSERT(side_manager.validate());
/* Ensure the side is valid in the context of this switch block */
VTR_ASSERT(validate_side(side) );
/* Ensure the track is valid in the context of this switch block at a specific side */
VTR_ASSERT(validate_opin_node_id(side, node_id) );
return opin_node_[side_manager.to_size_t()][node_id];
}
/* Get the node index of a routing track of a connection block, return -1 if not found */
int RRGSB::get_cb_chan_node_index(const t_rr_type& cb_type, const RRNodeId& node) const {
enum e_side chan_side = get_cb_chan_side(cb_type);
return get_chan_node_index(chan_side, node);
}
/* Get the node index in the array, return -1 if not found */
int RRGSB::get_chan_node_index(const e_side& node_side, const RRNodeId& node) const {
VTR_ASSERT (validate_side(node_side));
return chan_node_[size_t(node_side)].get_node_track_id(node);
}
/* Get the node index in the array, return -1 if not found */
int RRGSB::get_node_index(const RRGraph& rr_graph,
const RRNodeId& node,
const e_side& node_side,
const PORTS& node_direction) const {
size_t cnt;
int ret;
cnt = 0;
ret = -1;
/* Depending on the type of rr_node, we search different arrays */
switch (rr_graph.node_type(node)) {
case CHANX:
case CHANY:
for (size_t inode = 0; inode < get_chan_width(node_side); ++inode){
if ((node == chan_node_[size_t(node_side)].get_node(inode))
/* Check if direction meets specification */
&&(node_direction == chan_node_direction_[size_t(node_side)][inode])) {
cnt++;
ret = inode;
break;
}
}
break;
case IPIN:
for (size_t inode = 0; inode < get_num_ipin_nodes(node_side); ++inode) {
if (node == ipin_node_[size_t(node_side)][inode]) {
cnt++;
ret = inode;
break;
}
}
break;
case OPIN:
for (size_t inode = 0; inode < get_num_opin_nodes(node_side); ++inode) {
if (node == opin_node_[size_t(node_side)][inode]) {
cnt++;
ret = inode;
break;
}
}
break;
default:
VTR_LOG("Invalid cur_rr_node type! Should be [CHANX|CHANY|IPIN|OPIN]\n");
exit(1);
}
VTR_ASSERT((0 == cnt)||(1 == cnt));
return ret; /* Return an invalid value: nonthing is found*/
}
/* Get the side of a node in this SB */
void RRGSB::get_node_side_and_index(const RRGraph& rr_graph,
const RRNodeId& node,
const PORTS& node_direction,
e_side& node_side,
int& node_index) const {
size_t side;
SideManager side_manager;
/* Count the number of existence of cur_rr_node in cur_sb_info
* It could happen that same cur_rr_node appears on different sides of a SB
* For example, a routing track go vertically across the SB.
* Then its corresponding rr_node appears on both TOP and BOTTOM sides of this SB.
* We need to ensure that the found rr_node has the same direction as user want.
* By specifying the direction of rr_node, There should be only one rr_node can satisfy!
*/
for (side = 0; side < get_num_sides(); ++side) {
side_manager.set_side(side);
node_index = get_node_index(rr_graph, node, side_manager.get_side(), node_direction);
if (-1 != node_index) {
break;
}
}
if (side == get_num_sides()) {
/* we find nothing, return NUM_SIDES, and a OPEN node (-1) */
node_side = NUM_SIDES;
VTR_ASSERT(-1 == node_index);
return;
}
node_side = side_manager.get_side();
VTR_ASSERT(-1 != node_index);
return;
}
/* Check if the node exist in the opposite side of this Switch Block */
bool RRGSB::is_sb_node_exist_opposite_side(const RRGraph& rr_graph,
const RRNodeId& node,
const e_side& node_side) const {
SideManager side_manager(node_side);
int index;
VTR_ASSERT((CHANX == rr_graph.node_type(node)) || (CHANY == rr_graph.node_type(node)));
/* See if we can find the same src_rr_node in the opposite chan_side
* if there is one, it means a shorted wire across the SB
*/
index = get_node_index(rr_graph, node, side_manager.get_opposite(), IN_PORT);
return (-1 != index);
}
/* check if the candidate CB is a mirror of the current one */
bool RRGSB::is_cb_mirror(const RRGraph& rr_graph, const RRGSB& cand, const t_rr_type& cb_type) const {
/* Check if channel width is the same */
if ( get_cb_chan_width(cb_type) != cand.get_cb_chan_width(cb_type) ) {
return false;
}
enum e_side chan_side = get_cb_chan_side(cb_type);
/* check the numbers/directionality of channel rr_nodes */
if ( false == chan_node_[size_t(chan_side)].is_mirror(rr_graph, cand.chan_node_[size_t(chan_side)]) ) {
return false;
}
/* check the equivalence of ipins */
std::vector<enum e_side> ipin_side = get_cb_ipin_sides(cb_type);
for (size_t side = 0; side < ipin_side.size(); ++side) {
/* Ensure we have the same number of IPINs on this side */
if ( get_num_ipin_nodes(ipin_side[side]) != cand.get_num_ipin_nodes(ipin_side[side]) ) {
return false;
}
for (size_t inode = 0; inode < get_num_ipin_nodes(ipin_side[side]); ++inode) {
if (false == is_cb_node_mirror(rr_graph, cand, cb_type, ipin_side[side], inode)) {
return false;
}
}
}
return true;
}
/* check if the CB exist in this GSB */
bool RRGSB::is_cb_exist(const t_rr_type& cb_type) const {
/* if channel width is zero, there is no CB */
return (0 != get_cb_chan_width(cb_type));
}
/* check if the SB exist in this GSB */
bool RRGSB::is_sb_exist() const {
/* if all the channel width is zero and number of OPINs are zero, there is no SB */
for (size_t side = 0; side < get_num_sides(); ++side) {
SideManager side_manager(side);
if (0 != get_chan_width(side_manager.get_side())) {
return true;
}
if (0 != get_num_opin_nodes(side_manager.get_side())) {
return true;
}
}
return false;
}
/************************************************************************
* Check if the node indicates a passing wire across the Switch Block part of the GSB
* Therefore, we actually do the following check
* Check if a track starts from this GSB or not
* For INC_DIRECTION
* (xlow, ylow) should be same as the GSB side coordinate
* For DEC_DIRECTION
* (xhigh, yhigh) should be same as the GSB side coordinate
***********************************************************************/
bool RRGSB::is_sb_node_passing_wire(const RRGraph& rr_graph,
const e_side& node_side,
const size_t& track_id) const {
/* Get the rr_node */
RRNodeId track_node = get_chan_node(node_side, track_id);
/* Get the coordinates */
vtr::Point<size_t> side_coordinate = get_side_block_coordinate(node_side);
/* Get the coordinate of where the track starts */
vtr::Point<size_t> track_start = get_track_rr_node_start_coordinate(rr_graph, track_node);
/* INC_DIRECTION start_track: (xlow, ylow) should be same as the GSB side coordinate */
/* DEC_DIRECTION start_track: (xhigh, yhigh) should be same as the GSB side coordinate */
if ( (track_start.x() == side_coordinate.x())
&& (track_start.y() == side_coordinate.y())
&& (OUT_PORT == get_chan_node_direction(node_side, track_id)) ) {
/* Double check: start track should be an OUTPUT PORT of the GSB */
return false; /* This is a starting point */
}
/* Get the coordinate of where the track ends */
vtr::Point<size_t> track_end = get_track_rr_node_end_coordinate(rr_graph, track_node);
/* INC_DIRECTION end_track: (xhigh, yhigh) should be same as the GSB side coordinate */
/* DEC_DIRECTION end_track: (xlow, ylow) should be same as the GSB side coordinate */
if ( (track_end.x() == side_coordinate.x())
&& (track_end.y() == side_coordinate.y())
&& (IN_PORT == get_chan_node_direction(node_side, track_id)) ) {
/* Double check: end track should be an INPUT PORT of the GSB */
return false; /* This is an ending point */
}
/* Reach here it means that this will be a passing wire,
* we should be able to find the node on the opposite side of the GSB!
*/
if (true != is_sb_node_exist_opposite_side(rr_graph, track_node, node_side)) {
VTR_LOG("GSB[%lu][%lu] track node[%lu] at %s:\n",
get_x(), get_y(), track_id, SIDE_STRING[node_side]);
rr_graph.print_node(track_node);
}
VTR_ASSERT (true == is_sb_node_exist_opposite_side(rr_graph, track_node, node_side));
return true;
}
/* check if the candidate SB satisfy the basic requirements on being a mirror of the current one */
/* Idenify mirror Switch blocks
* Check each two switch blocks:
* Number of channel/opin/ipin rr_nodes are same
* If all above are satisfied, the two switch blocks may be mirrors !
*/
bool RRGSB::is_sb_mirrorable(const RRGraph& rr_graph, const RRGSB& cand) const {
/* check the numbers of sides */
if (get_num_sides() != cand.get_num_sides()) {
return false;
}
/* check the numbers/directionality of channel rr_nodes */
for (size_t side = 0; side < get_num_sides(); ++side) {
SideManager side_manager(side);
/* Ensure we have the same channel width on this side */
if (get_chan_width(side_manager.get_side()) != cand.get_chan_width(side_manager.get_side())) {
return false;
}
if ( ((size_t(-1) == get_track_id_first_short_connection(rr_graph, side_manager.get_side()))
&& (size_t(-1) != cand.get_track_id_first_short_connection(rr_graph, side_manager.get_side())))
|| ((size_t(-1) != get_track_id_first_short_connection(rr_graph, side_manager.get_side()) )
&& ( size_t(-1) == cand.get_track_id_first_short_connection(rr_graph, side_manager.get_side()))) ) {
return false;
}
}
/* check the numbers of opin_rr_nodes */
for (size_t side = 0; side < get_num_sides(); ++side) {
SideManager side_manager(side);
if (get_num_opin_nodes(side_manager.get_side()) != cand.get_num_opin_nodes(side_manager.get_side())) {
return false;
}
}
return true;
}
/* check if all the routing segments of a side of candidate SB is a mirror of the current one */
bool RRGSB::is_sb_side_segment_mirror(const RRGraph& rr_graph, const RRGSB& cand,
const e_side& side, const RRSegmentId& seg_id) const {
/* Create a side manager */
SideManager side_manager(side);
/* Make sure both Switch blocks has this side!!! */
VTR_ASSERT ( side_manager.to_size_t() < get_num_sides() );
VTR_ASSERT ( side_manager.to_size_t() < cand.get_num_sides() );
/* check the numbers/directionality of channel rr_nodes */
/* Ensure we have the same channel width on this side */
if (get_chan_width(side) != cand.get_chan_width(side)) {
return false;
}
for (size_t itrack = 0; itrack < get_chan_width(side); ++itrack) {
/* Bypass unrelated segments */
if (seg_id != get_chan_node_segment(side, itrack)) {
continue;
}
/* Check the directionality of each node */
if (get_chan_node_direction(side, itrack) != cand.get_chan_node_direction(side, itrack)) {
return false;
}
/* Check the track_id of each node
* ptc is not necessary, we care the connectivity!
*/
/* For OUT_PORT rr_node, we need to check fan-in */
if (OUT_PORT != get_chan_node_direction(side, itrack)) {
continue; /* skip IN_PORT */
}
if (false == is_sb_node_mirror(rr_graph, cand, side, itrack)) {
return false;
}
}
/* check the numbers of opin_rr_nodes */
if (get_num_opin_nodes(side) != cand.get_num_opin_nodes(side)) {
return false;
}
/* check the numbers of ipin_rr_nodes */
if (get_num_ipin_nodes(side) != cand.get_num_ipin_nodes(side)) {
return false;
}
return true;
}
/* check if a side of candidate SB is a mirror of the current one */
bool RRGSB::is_sb_side_mirror(const RRGraph& rr_graph, const RRGSB& cand, const e_side& side) const {
/* get a list of segments */
std::vector<RRSegmentId> seg_ids = chan_node_[size_t(side)].get_segment_ids();
for (size_t iseg = 0; iseg < seg_ids.size(); ++iseg) {
if (false == is_sb_side_segment_mirror(rr_graph, cand, side, seg_ids[iseg])) {
return false;
}
}
return true;
}
/* check if the candidate SB is a mirror of the current one */
bool RRGSB::is_sb_mirror(const RRGraph& rr_graph, const RRGSB& cand) const {
/* check the numbers of sides */
if (get_num_sides() != cand.get_num_sides()) {
return false;
}
/* check the numbers/directionality of channel rr_nodes */
for (size_t side = 0; side < get_num_sides(); ++side) {
SideManager side_manager(side);
if (false == is_sb_side_mirror(rr_graph, cand, side_manager.get_side())) {
return false;
}
}
return true;
}
/* Public Accessors: Cooridinator conversion */
/* get the x coordinate of this GSB */
size_t RRGSB::get_x() const {
return coordinate_.x();
}
/* get the y coordinate of this GSB */
size_t RRGSB::get_y() const {
return coordinate_.y();
}
/* get the x coordinate of this switch block */
size_t RRGSB::get_sb_x() const {
return coordinate_.x();
}
/* get the y coordinate of this switch block */
size_t RRGSB::get_sb_y() const {
return coordinate_.y();
}
/* Get the number of sides of this SB */
vtr::Point<size_t> RRGSB::get_sb_coordinate() const {
return coordinate_;
}
/* get the x coordinate of this X/Y-direction block */
size_t RRGSB::get_cb_x(const t_rr_type& cb_type) const {
VTR_ASSERT (validate_cb_type(cb_type));
switch(cb_type) {
case CHANX:
return get_side_block_coordinate(LEFT).x();
case CHANY:
return get_side_block_coordinate(TOP).x();
default:
VTR_LOG("Invalid type of connection block!\n");
exit(1);
}
}
/* get the y coordinate of this X/Y-direction block */
size_t RRGSB::get_cb_y(const t_rr_type& cb_type) const {
VTR_ASSERT (validate_cb_type(cb_type));
switch(cb_type) {
case CHANX:
return get_side_block_coordinate(LEFT).y();
case CHANY:
return get_side_block_coordinate(TOP).y();
default:
VTR_LOG("Invalid type of connection block!\n");
exit(1);
}
}
/* Get the coordinate of the X/Y-direction CB */
vtr::Point<size_t> RRGSB::get_cb_coordinate(const t_rr_type& cb_type) const {
VTR_ASSERT (validate_cb_type(cb_type));
switch(cb_type) {
case CHANX:
return get_side_block_coordinate(LEFT);
case CHANY:
return get_side_block_coordinate(TOP);
default:
VTR_LOG("Invalid type of connection block!\n");
exit(1);
}
}
e_side RRGSB::get_cb_chan_side(const t_rr_type& cb_type) const {
VTR_ASSERT (validate_cb_type(cb_type));
switch(cb_type) {
case CHANX:
return LEFT;
case CHANY:
return TOP;
default:
VTR_LOG("Invalid type of connection block!\n");
exit(1);
}
}
/* Get the side of routing channel in the GSB according to the side of IPIN */
e_side RRGSB::get_cb_chan_side(const e_side& ipin_side) const {
switch(ipin_side) {
case TOP:
return LEFT;
case RIGHT:
return TOP;
case BOTTOM:
return LEFT;
case LEFT:
return TOP;
default:
VTR_LOG("Invalid type of ipin_side!\n");
exit(1);
}
}
vtr::Point<size_t> RRGSB::get_side_block_coordinate(const e_side& side) const {
SideManager side_manager(side);
VTR_ASSERT(side_manager.validate());
vtr::Point<size_t> ret(get_sb_x(), get_sb_y());
switch (side_manager.get_side()) {
case TOP:
/* (0 == side) */
/* 1. Channel Y [x][y+1] inputs */
ret.set_y(ret.y() + 1);
break;
case RIGHT:
/* 1 == side */
/* 2. Channel X [x+1][y] inputs */
ret.set_x(ret.x() + 1);
break;
case BOTTOM:
/* 2 == side */
/* 3. Channel Y [x][y] inputs */
break;
case LEFT:
/* 3 == side */
/* 4. Channel X [x][y] inputs */
break;
default:
VTR_LOG(" Invalid side!\n");
exit(1);
}
return ret;
}
vtr::Point<size_t> RRGSB::get_grid_coordinate() const {
vtr::Point<size_t> ret(get_sb_x(), get_sb_y());
ret.set_y(ret.y() + 1);
return ret;
}
/************************************************************************
* Public Mutators
***********************************************************************/
/* get a copy from a source */
void RRGSB::set(const RRGSB& src) {
/* Copy coordinate */
this->set_coordinate(src.get_sb_coordinate().x(), src.get_sb_coordinate().y());
/* Initialize sides */
this->init_num_sides(src.get_num_sides());
/* Copy vectors */
for (size_t side = 0; side < src.get_num_sides(); ++side) {
SideManager side_manager(side);
/* Copy chan_nodes */
/* skip if there is no channel width */
if ( 0 < src.get_chan_width(side_manager.get_side()) ) {
this->chan_node_[side_manager.get_side()].set(src.chan_node_[side_manager.get_side()]);
/* Copy chan_node_direction_*/
this->chan_node_direction_[side_manager.get_side()].clear();
for (size_t inode = 0; inode < src.get_chan_width(side_manager.get_side()); ++inode) {
this->chan_node_direction_[side_manager.get_side()].push_back(src.get_chan_node_direction(side_manager.get_side(), inode));
}
}
/* Copy opin_node and opin_node_grid_side_ */
this->opin_node_[side_manager.get_side()].clear();
for (size_t inode = 0; inode < src.get_num_opin_nodes(side_manager.get_side()); ++inode) {
this->opin_node_[side_manager.get_side()].push_back(src.get_opin_node(side_manager.get_side(), inode));
}
/* Copy ipin_node and ipin_node_grid_side_ */
this->ipin_node_[side_manager.get_side()].clear();
for (size_t inode = 0; inode < src.get_num_ipin_nodes(side_manager.get_side()); ++inode) {
this->ipin_node_[side_manager.get_side()].push_back(src.get_ipin_node(side_manager.get_side(), inode));
}
}
}
/* Set the coordinate (x,y) for the switch block */
void RRGSB::set_coordinate(const size_t& x, const size_t& y) {
coordinate_.set(x, y);
}
/* Allocate the vectors with the given number of sides */
void RRGSB::init_num_sides(const size_t& num_sides) {
/* Initialize the vectors */
chan_node_.resize(num_sides);
chan_node_direction_.resize(num_sides);
ipin_node_.resize(num_sides);
opin_node_.resize(num_sides);
}
/* Add a node to the chan_node_ list and also assign its direction in chan_node_direction_ */
void RRGSB::add_chan_node(const e_side& node_side,
const RRChan& rr_chan,
const std::vector<enum PORTS>& rr_chan_dir) {
/* Validate: 1. side is valid, the type of node is valid */
VTR_ASSERT(validate_side(node_side));
/* fill the dedicated element in the vector */
chan_node_[size_t(node_side)].set(rr_chan);
chan_node_direction_[size_t(node_side)].resize(rr_chan_dir.size());
for (size_t inode = 0; inode < rr_chan_dir.size(); ++inode) {
chan_node_direction_[size_t(node_side)][inode] = rr_chan_dir[inode];
}
}
/* Add a node to the chan_node_ list and also assign its direction in chan_node_direction_ */
void RRGSB::add_ipin_node(const RRNodeId& node, const e_side& node_side) {
VTR_ASSERT(validate_side(node_side));
/* push pack the dedicated element in the vector */
ipin_node_[size_t(node_side)].push_back(node);
}
/* Add a node to the chan_node_ list and also assign its direction in chan_node_direction_ */
void RRGSB::add_opin_node(const RRNodeId& node, const e_side& node_side) {
VTR_ASSERT(validate_side(node_side));
/* push pack the dedicated element in the vector */
opin_node_[size_t(node_side)].push_back(node);
}
void RRGSB::sort_chan_node_in_edges(const RRGraph& rr_graph,
const e_side& chan_side,
const size_t& track_id) {
std::map<size_t, std::map<size_t, RREdgeId>> from_grid_edge_map;
std::map<size_t, std::map<size_t, RREdgeId>> from_track_edge_map;
const RRNodeId& chan_node = chan_node_[size_t(chan_side)].get_node(track_id);
/* Count the edges and ensure every of them has been sorted */
size_t edge_counter = 0;
/* For each incoming edge, find the node side and index in this GSB.
* and cache these. Then we will use the data to sort the edge in the
* following sequence:
* 0----------------------------------------------------------------> num_in_edges()
* |<--TOP side-->|<--RIGHT side-->|<--BOTTOM side-->|<--LEFT side-->|
* For each side, the edge will be sorted by the node index starting from 0
* For each side, the edge from grid pins will be the 1st part
* while the edge from routing tracks will be the 2nd part
*/
for (const RREdgeId& edge : rr_graph.node_in_edges(chan_node)) {
/* We care the source node of this edge, and it should be an input of the GSB!!! */
const RRNodeId& src_node = rr_graph.edge_src_node(edge);
e_side side = NUM_SIDES;
int index = 0;
get_node_side_and_index(rr_graph, src_node, IN_PORT, side, index);
/* Must have valid side and index */
if (NUM_SIDES == side) {
VTR_LOG("GSB[%lu][%lu]:\n", get_x(), get_y());
VTR_LOG("SRC node:\n");
rr_graph.print_node(src_node);
VTR_LOG("Channel node:\n");
rr_graph.print_node(chan_node);
}
VTR_ASSERT(NUM_SIDES != side);
VTR_ASSERT(OPEN != index);
if (OPIN == rr_graph.node_type(src_node)) {
from_grid_edge_map[side][index] = edge;
} else {
VTR_ASSERT( (CHANX == rr_graph.node_type(src_node))
|| (CHANY == rr_graph.node_type(src_node)) );
from_track_edge_map[side][index] = edge;
}
edge_counter++;
}
/* Store the sorted edge */
for (size_t side = 0; side < get_num_sides(); ++side) {
/* Edges from grid outputs are the 1st part */
for (size_t opin_id = 0; opin_id < opin_node_[side].size(); ++opin_id) {
if ( (0 < from_grid_edge_map.count(side))
&& (0 < from_grid_edge_map.at(side).count(opin_id)) ) {
chan_node_in_edges_[size_t(chan_side)][track_id].push_back(from_grid_edge_map[side][opin_id]);
}
}
/* Edges from routing tracks are the 2nd part */
for (size_t itrack = 0; itrack < chan_node_[side].get_chan_width(); ++itrack) {
if ( (0 < from_track_edge_map.count(side))
&& (0 < from_track_edge_map.at(side).count(itrack)) ) {
chan_node_in_edges_[size_t(chan_side)][track_id].push_back(from_track_edge_map[side][itrack]);
}
}
}
VTR_ASSERT(edge_counter == chan_node_in_edges_[size_t(chan_side)][track_id].size());
}
void RRGSB::sort_chan_node_in_edges(const RRGraph& rr_graph) {
/* Allocate here, as sort edge is optional, we do not allocate when adding nodes */
chan_node_in_edges_.resize(get_num_sides());
for (size_t side = 0; side < get_num_sides(); ++side) {
SideManager side_manager(side);
chan_node_in_edges_[side].resize(chan_node_[side].get_chan_width());
for (size_t track_id = 0; track_id < chan_node_[side].get_chan_width(); ++track_id) {
/* Only sort the output nodes and bypass passing wires */
if ( (OUT_PORT == chan_node_direction_[side][track_id])
&& (false == is_sb_node_passing_wire(rr_graph, side_manager.get_side(), track_id)) ) {
sort_chan_node_in_edges(rr_graph, side_manager.get_side(), track_id);
}
}
}
}
/************************************************************************
* Public Mutators: clean-up functions
***********************************************************************/
/* Reset the RRGSB to pristine state */
void RRGSB::clear() {
/* Clean all the vectors */
VTR_ASSERT(validate_num_sides());
/* Clear the inner vector of each matrix */
for (size_t side = 0; side < get_num_sides(); ++side) {
chan_node_direction_[side].clear();
chan_node_[side].clear();
ipin_node_[side].clear();
opin_node_[side].clear();
}
chan_node_direction_.clear();
chan_node_.clear();
ipin_node_.clear();
opin_node_.clear();
}
/* Clean the chan_width of a side */
void RRGSB::clear_chan_nodes(const e_side& node_side) {
VTR_ASSERT(validate_side(node_side));
chan_node_[size_t(node_side)].clear();
chan_node_direction_[size_t(node_side)].clear();
}
/* Clean the number of IPINs of a side */
void RRGSB::clear_ipin_nodes(const e_side& node_side) {
VTR_ASSERT(validate_side(node_side));
ipin_node_[size_t(node_side)].clear();
}
/* Clean the number of OPINs of a side */
void RRGSB::clear_opin_nodes(const e_side& node_side) {
VTR_ASSERT(validate_side(node_side));
opin_node_[size_t(node_side)].clear();
}
/* Clean chan/opin/ipin nodes at one side */
void RRGSB::clear_one_side(const e_side& node_side) {
clear_chan_nodes(node_side);
clear_ipin_nodes(node_side);
clear_opin_nodes(node_side);
}
/************************************************************************
* Internal Accessors: identify mirrors
***********************************************************************/
/* check if two rr_nodes have a similar set of drive_rr_nodes
* for each drive_rr_node:
* 1. CHANX or CHANY: should have the same side and index
* 2. OPIN or IPIN: should have the same side and index
* 3. each drive_rr_switch should be the same
*/
bool RRGSB::is_sb_node_mirror(const RRGraph& rr_graph,
const RRGSB& cand,
const e_side& node_side,
const size_t& track_id) const {
/* Ensure rr_nodes are either the output of short-connection or multiplexer */
bool is_short_conkt = this->is_sb_node_passing_wire(rr_graph, node_side, track_id);
if (is_short_conkt != cand.is_sb_node_passing_wire(rr_graph, node_side, track_id)) {
return false;
}
if (true == is_short_conkt) {
/* Since, both are pass wires,
* The two node should be equivalent
* we can return here
*/
return true;
}
/* Use unsorted/sorted edges */
std::vector<RREdgeId> node_in_edges = get_chan_node_in_edges(rr_graph, node_side, track_id);
std::vector<RREdgeId> cand_node_in_edges = cand.get_chan_node_in_edges(rr_graph, node_side, track_id);
/* For non-passing wires, check driving rr_nodes */
if (node_in_edges.size() != cand_node_in_edges.size()) {
return false;
}
VTR_ASSERT(node_in_edges.size() == cand_node_in_edges.size());
for (size_t iedge = 0; iedge < node_in_edges.size(); ++iedge) {
RREdgeId src_edge = node_in_edges[iedge];
RREdgeId src_cand_edge = cand_node_in_edges[iedge];
RRNodeId src_node = rr_graph.edge_src_node(src_edge);
RRNodeId src_cand_node = rr_graph.edge_src_node(src_cand_edge);
/* node type should be the same */
if (rr_graph.node_type(src_node) != rr_graph.node_type(src_cand_node)) {
return false;
}
/* switch type should be the same */
if (rr_graph.edge_switch(src_edge) != rr_graph.edge_switch(src_cand_edge)) {
return false;
}
int src_node_id, des_node_id;
enum e_side src_node_side, des_node_side;
this->get_node_side_and_index(rr_graph, src_node, OUT_PORT, src_node_side, src_node_id);
cand.get_node_side_and_index(rr_graph, src_cand_node, OUT_PORT, des_node_side, des_node_id);
if (src_node_id != des_node_id) {
return false;
}
if (src_node_side != des_node_side) {
return false;
}
}
return true;
}
/* check if two ipin_nodes have a similar set of drive_rr_nodes
* for each drive_rr_node:
* 1. CHANX or CHANY: should have the same side and index
* 2. each drive_rr_switch should be the same
*/
bool RRGSB::is_cb_node_mirror(const RRGraph& rr_graph,
const RRGSB& cand,
const t_rr_type& cb_type,
const e_side& node_side,
const size_t& node_id) const {
/* Ensure rr_nodes are either the output of short-connection or multiplexer */
RRNodeId node = this->get_ipin_node(node_side, node_id);
RRNodeId cand_node = cand.get_ipin_node(node_side, node_id);
if ( rr_graph.node_in_edges(node).size() != rr_graph.node_in_edges(cand_node).size() ) {
return false;
}
std::vector<RREdgeId> node_in_edges;
for (const RREdgeId& edge : rr_graph.node_in_edges(node)) {
node_in_edges.push_back(edge);
}
std::vector<RREdgeId> cand_node_in_edges;
for (const RREdgeId& edge : rr_graph.node_in_edges(cand_node)) {
cand_node_in_edges.push_back(edge);
}
VTR_ASSERT(node_in_edges.size() == cand_node_in_edges.size());
for (size_t iedge = 0; iedge < node_in_edges.size(); ++iedge) {
RREdgeId src_edge = node_in_edges[iedge];
RREdgeId src_cand_edge = cand_node_in_edges[iedge];
RRNodeId src_node = rr_graph.edge_src_node(src_edge);
RRNodeId src_cand_node = rr_graph.edge_src_node(src_cand_edge);
/* node type should be the same */
if (rr_graph.node_type(src_node) != rr_graph.node_type(src_cand_node)) {
return false;
}
/* switch type should be the same */
if (rr_graph.edge_switch(src_edge)!= rr_graph.edge_switch(src_cand_edge)) {
return false;
}
int src_node_id, des_node_id;
enum e_side src_node_side, des_node_side;
enum e_side chan_side = get_cb_chan_side(cb_type);
switch (rr_graph.node_type(src_node)) {
case CHANX:
case CHANY:
/* if the drive rr_nodes are routing tracks, find index */
src_node_id = this->get_chan_node_index(chan_side, src_node);
des_node_id = cand.get_chan_node_index(chan_side, src_cand_node);
break;
case OPIN:
this->get_node_side_and_index(rr_graph, src_node, OUT_PORT, src_node_side, src_node_id);
cand.get_node_side_and_index(rr_graph, src_cand_node, OUT_PORT, des_node_side, des_node_id);
if (src_node_side != des_node_side) {
return false;
}
break;
default:
VTR_LOG("Invalid type of drive_rr_nodes for ipin_node!\n");
exit(1);
}
if (src_node_id != des_node_id) {
return false;
}
}
return true;
}
size_t RRGSB::get_track_id_first_short_connection(const RRGraph& rr_graph, const e_side& node_side) const {
VTR_ASSERT(validate_side(node_side));
/* Walk through chan_nodes and find the first short connection */
for (size_t inode = 0; inode < get_chan_width(node_side); ++inode) {
if (true == is_sb_node_passing_wire(rr_graph, node_side, inode)) {
return inode;
}
}
return size_t(-1);
}
/************************************************************************
* Internal validators
***********************************************************************/
/* Validate if the number of sides are consistent among internal data arrays ! */
bool RRGSB::validate_num_sides() const {
size_t num_sides = chan_node_direction_.size();
if ( num_sides != chan_node_.size() ) {
return false;
}
if ( num_sides != ipin_node_.size() ) {
return false;
}
if ( num_sides != opin_node_.size() ) {
return false;
}
return true;
}
/* Check if the side valid in the context: does the switch block have the side? */
bool RRGSB::validate_side(const e_side& side) const {
return (size_t(side) < get_num_sides());
}
/* Check the track_id is valid for chan_node_ and chan_node_direction_ */
bool RRGSB::validate_track_id(const e_side& side, const size_t& track_id) const {
if (false == validate_side(side)) {
return false;
}
return ( ( track_id < chan_node_[size_t(side)].get_chan_width())
&& ( track_id < chan_node_direction_[size_t(side)].size()) );
}
/* Check the opin_node_id is valid for opin_node_ and opin_node_grid_side_ */
bool RRGSB::validate_opin_node_id(const e_side& side, const size_t& node_id) const {
if (false == validate_side(side)) {
return false;
}
return (node_id < opin_node_[size_t(side)].size());
}
/* Check the ipin_node_id is valid for opin_node_ and opin_node_grid_side_ */
bool RRGSB::validate_ipin_node_id(const e_side& side, const size_t& node_id) const {
if (false == validate_side(side)) {
return false;
}
return (node_id < ipin_node_[size_t(side)].size());
}
bool RRGSB::validate_cb_type(const t_rr_type& cb_type) const {
return ( (CHANX == cb_type) || (CHANY == cb_type) );
}
} /* End namespace openfpga*/