diff --git a/openfpga/src/annotation/rr_gsb.cpp b/openfpga/src/annotation/rr_gsb.cpp new file mode 100644 index 000000000..54b9fa8f2 --- /dev/null +++ b/openfpga/src/annotation/rr_gsb.cpp @@ -0,0 +1,1001 @@ +/************************************************************************ + * 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_direction_.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 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 RRGSB::get_cb_ipin_sides(const t_rr_type& cb_type) const { + VTR_ASSERT (validate_cb_type(cb_type)); + + std::vector 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 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 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); +} + +/* 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 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 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 side_coordinate = get_side_block_coordinate(node_side); + + /* Get the coordinate of where the track starts */ + vtr::Point 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 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! + */ + 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 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 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 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 RRGSB::get_side_block_coordinate(const e_side& side) const { + SideManager side_manager(side); + VTR_ASSERT(side_manager.validate()); + vtr::Point 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 RRGSB::get_grid_coordinate() const { + vtr::Point 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, RRChan& rr_chan, const std::vector& 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); +} + +/* 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 functions for validation */ + +/* 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 */ + RRNodeId node = this->get_chan_node(node_side, track_id); + RRNodeId cand_node = cand.get_chan_node(node_side, track_id); + 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; + } + + /* For non-passing wires, check driving rr_nodes */ + if (rr_graph.node_in_edges(node).size() != rr_graph.node_in_edges(cand_node).size()) { + return false; + } + + std::vector node_in_edges; + for (const RREdgeId& edge : rr_graph.node_in_edges(node)) { + node_in_edges.push_back(edge); + } + + std::vector 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(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 node_in_edges; + for (const RREdgeId& edge : rr_graph.node_in_edges(node)) { + node_in_edges.push_back(edge); + } + + std::vector 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); +} + +/* 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*/ diff --git a/openfpga/src/annotation/rr_gsb.h b/openfpga/src/annotation/rr_gsb.h index 7febeffc7..4f3af9552 100644 --- a/openfpga/src/annotation/rr_gsb.h +++ b/openfpga/src/annotation/rr_gsb.h @@ -4,6 +4,9 @@ /******************************************************************** * Include header files required by the data structure definition *******************************************************************/ +/* Headers from vtrutil library */ +#include "vtr_geometry.h" + #include "rr_chan.h" /* Begin namespace openfpga */ @@ -15,7 +18,6 @@ namespace openfpga { * 1. A switch block * 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 - * This is a collection of rr_nodes, which may be replaced with RRNodeId in new RRGraph * * +---------------------------------+ * | Y-direction CB | @@ -53,141 +55,176 @@ class RRGSB { RRGSB(const RRGSB&);/* Copy constructor */ RRGSB();/* Default constructor */ public: /* Accessors */ - size_t get_num_sides() const; /* Get the number of sides of this SB */ - size_t get_chan_width(enum e_side side) const; /* Get the number of routing tracks on a side */ - size_t get_cb_chan_width(t_rr_type cb_type) const; /* Get the number of routing tracks of a X/Y-direction CB */ - std::vector get_cb_ipin_sides(t_rr_type cb_type) const; /* Get the sides of CB ipins in the array */ - size_t get_max_chan_width() const; /* Get the maximum number of routing tracks on all sides */ - enum PORTS get_chan_node_direction(enum e_side side, size_t track_id) const; /* Get the direction of a rr_node at a given side and track_id */ - RRChan get_chan(enum e_side side) const; /* get a rr_node at a given side and track_id */ - std::vector get_chan_segment_ids(enum e_side side) const; /* Get a list of segments used in this routing channel */ - std::vector get_chan_node_ids_by_segment_ids(enum e_side side, size_t seg_id) const; /* Get a list of segments used in this routing channel */ - t_rr_node* get_chan_node(enum e_side side, size_t track_id) const; /* get a rr_node at a given side and track_id */ - size_t get_chan_node_segment(enum e_side side, size_t track_id) const; /* get the segment id of a channel rr_node */ - size_t get_num_ipin_nodes(enum e_side side) const; /* Get the number of IPIN rr_nodes on a side */ - t_rr_node* get_ipin_node(enum e_side side, size_t node_id) const; /* get a rr_node at a given side and track_id */ - enum e_side get_ipin_node_grid_side(enum e_side side, size_t node_id) const; /* get a rr_node at a given side and track_id */ - enum e_side get_ipin_node_grid_side(t_rr_node* ipin_node) const; /* get a rr_node at a given side and track_id */ - size_t get_num_opin_nodes(enum e_side side) const; /* Get the number of OPIN rr_nodes on a side */ - t_rr_node* get_opin_node(enum e_side side, size_t node_id) const; /* get a rr_node at a given side and track_id */ - enum e_side get_opin_node_grid_side(enum e_side side, size_t node_id) const; /* get a rr_node at a given side and track_id */ - enum e_side get_opin_node_grid_side(t_rr_node* opin_node) const; /* get a rr_node at a given side and track_id */ - int get_cb_chan_node_index(t_rr_type cb_type, t_rr_node* node) const; - int get_chan_node_index(enum e_side node_side, t_rr_node* node) const; - int get_node_index(t_rr_node* node, enum e_side node_side, enum PORTS node_direction) const; /* Get the node index in the array, return -1 if not found */ - void get_node_side_and_index(t_rr_node* node, enum PORTS node_direction, enum e_side* node_side, int* node_index) const; /* Given a rr_node, try to find its side and index in the Switch block */ - bool is_sb_node_exist_opposite_side(t_rr_node* node, enum e_side node_side) const; /* Check if the node exist in the opposite side of this Switch Block */ - public: /* Accessors: get information about configuration ports */ - size_t get_sb_num_reserved_conf_bits() const; - size_t get_sb_reserved_conf_bits_lsb() const; - size_t get_sb_reserved_conf_bits_msb() const; - size_t get_sb_num_conf_bits() const; - size_t get_sb_conf_bits_lsb() const; - size_t get_sb_conf_bits_msb() const; - size_t get_cb_num_reserved_conf_bits(t_rr_type cb_type) const; - size_t get_cb_reserved_conf_bits_lsb(t_rr_type cb_type) const; - size_t get_cb_reserved_conf_bits_msb(t_rr_type cb_type) const; - size_t get_cb_num_conf_bits(t_rr_type cb_type) const; - size_t get_cb_conf_bits_lsb(t_rr_type cb_type) const; - size_t get_cb_conf_bits_msb(t_rr_type cb_type) const; - bool is_sb_node_passing_wire(const enum e_side node_side, const size_t track_id) const; /* Check if the node imply a short connection inside the SB, which happens to long wires across a FPGA fabric */ - bool is_sb_side_mirror(const RRGSB& cand, enum e_side side) const; /* check if a side of candidate SB is a mirror of the current one */ - bool is_sb_side_segment_mirror(const RRGSB& cand, enum e_side side, size_t seg_id) const; /* check if all the routing segments of a side of candidate SB is a mirror of the current one */ - bool is_sb_mirror(const RRGSB& cand) const; /* check if the candidate SB is a mirror of the current one */ - bool is_sb_mirrorable(const RRGSB& cand) const; /* check if the candidate SB satisfy the basic requirements on being a mirror of the current one */ - bool is_cb_mirror(const RRGSB& cand, t_rr_type cb_type) const; /* check if the candidate SB is a mirror of the current one */ - bool is_cb_exist(t_rr_type cb_type) const; /* check if the candidate SB is a mirror of the current one */ - size_t get_hint_rotate_offset(const RRGSB& cand) const; /* Determine an initial offset in rotating the candidate Switch Block to find a mirror matching*/ + /* Get the number of sides of this SB */ + size_t get_num_sides() const; + + /* Get the number of routing tracks on a side */ + size_t get_chan_width(const e_side& side) const; + + /* Get the maximum number of routing tracks on all sides */ + size_t get_max_chan_width() const; + + /* Get the number of routing tracks of a X/Y-direction CB */ + size_t get_cb_chan_width(const t_rr_type& cb_type) const; + + /* Get the sides of CB ipins in the array */ + std::vector get_cb_ipin_sides(const t_rr_type& cb_type) const; + + /* Get the direction of a rr_node at a given side and track_id */ + enum PORTS get_chan_node_direction(const e_side& side, const size_t& track_id) const; + + /* Get a list of segments used in this routing channel */ + std::vector get_chan_segment_ids(const e_side& side) const; + + /* Get a list of segments used in this routing channel */ + std::vector 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; + + /* get the segment id of a channel rr_node */ + RRSegmentId get_chan_node_segment(const e_side& side, const size_t& track_id) const; + + /* Get the number of IPIN rr_nodes on a side */ + size_t get_num_ipin_nodes(const e_side& side) const; + + /* get a rr_node at a given side and track_id */ + RRNodeId get_ipin_node(const e_side& side, const size_t& node_id) const; + + /* Get the number of OPIN rr_nodes on a side */ + size_t get_num_opin_nodes(const e_side& side) const; + + /* get a rr_node at a given side and track_id */ + RRNodeId get_opin_node(const e_side& side, const size_t& node_id) const; + + int get_cb_chan_node_index(const t_rr_type& cb_type, const RRNodeId& node) const; + + int get_chan_node_index(const e_side& node_side, const RRNodeId& node) const; + + /* Get the node index in the array, return -1 if not found */ + int get_node_index(const RRGraph& rr_graph, const RRNodeId& node, const e_side& node_side, const PORTS& node_direction) const; + + /* Given a rr_node, try to find its side and index in the Switch block */ + void get_node_side_and_index(const RRGraph& rr_graph, const RRNodeId& node, const PORTS& node_direction, e_side& node_side, int& node_index) const; + + /* Check if the node exist in the opposite side of this Switch Block */ + bool is_sb_node_exist_opposite_side(const RRGraph& rr_graph, const RRNodeId& node, const e_side& node_side) const; + public: /* Accessors: to identify mirrors */ + /* check if the candidate SB is a mirror of the current one */ + bool is_cb_mirror(const RRGraph& rr_graph, const RRGSB& cand, const t_rr_type& cb_type) const; + + /* check if the candidate SB is a mirror of the current one */ + bool is_cb_exist(const t_rr_type& cb_type) const; + + /* Check if the node imply a short connection inside the SB, which happens to long wires across a FPGA fabric */ + bool is_sb_node_passing_wire(const RRGraph& rr_graph, const e_side& node_side, const size_t& track_id) const; + + /* check if the candidate SB satisfy the basic requirements + * on being a mirror of the current one + */ + bool is_sb_mirrorable(const RRGraph& rr_graph, const RRGSB& cand) const; + + /* check if all the routing segments of a side of candidate SB is a mirror of the current one */ + bool is_sb_side_segment_mirror(const RRGraph& rr_graph, const RRGSB& cand, + const e_side& side, const RRSegmentId& seg_id) const; + + /* check if a side of candidate SB is a mirror of the current one + * Check the specified side of two switch blocks: + * 1. Number of channel/opin/ipin rr_nodes are same + * For channel rr_nodes + * 2. check if their track_ids (ptc_num) are same + * 3. Check if the switches (ids) are same + * For opin/ipin rr_nodes, + * 4. check if their parent type_descriptors same, + * 5. check if pin class id and pin id are same + * If all above are satisfied, the side of the two switch blocks are mirrors! + */ + bool is_sb_side_mirror(const RRGraph& rr_graph, const RRGSB& cand, const e_side& side) const; + + /* check if the candidate SB is a mirror of the current one + * Idenify mirror Switch blocks + * Check each two switch blocks: + * 1. Number of channel/opin/ipin rr_nodes are same + * For channel rr_nodes + * 2. check if their track_ids (ptc_num) are same + * 3. Check if the switches (ids) are same + * For opin/ipin rr_nodes, + * 4. check if their parent type_descriptors same, + * 5. check if pin class id and pin id are same + * If all above are satisfied, the two switch blocks are mirrors! + */ + bool is_sb_mirror(const RRGraph& rr_graph, const RRGSB& cand) const; + public: /* Cooridinator conversion and output */ - size_t get_x() const; /* get the x coordinator of this switch block */ - size_t get_y() const; /* get the y coordinator of this switch block */ - size_t get_sb_x() const; /* get the x coordinator of this switch block */ - size_t get_sb_y() const; /* get the y coordinator of this switch block */ - DeviceCoordinator get_sb_coordinator() const; /* Get the coordinator of the SB */ - size_t get_cb_x(t_rr_type cb_type) const; /* get the x coordinator of this X/Y-direction block */ - size_t get_cb_y(t_rr_type cb_type) const; /* get the y coordinator of this X/Y-direction block */ - DeviceCoordinator get_cb_coordinator(t_rr_type cb_type) const; /* Get the coordinator of the X/Y-direction CB */ - enum e_side get_cb_chan_side(t_rr_type cb_type) const; /* get the side of a Connection block */ - enum e_side get_cb_chan_side(enum e_side ipin_side) const; /* get the side of a Connection block */ - DeviceCoordinator get_side_block_coordinator(enum e_side side) const; - DeviceCoordinator get_grid_coordinator() const; - public: /* Verilog writer */ - const char* gen_gsb_verilog_module_name() const; - const char* gen_gsb_verilog_instance_name() const; - const char* gen_sb_verilog_module_name() const; - const char* gen_sb_verilog_instance_name() const; - const char* gen_sb_verilog_side_module_name(enum e_side side, size_t seg_id) const; - const char* gen_sb_verilog_side_instance_name(enum e_side side, size_t seg_id) const; - const char* gen_cb_verilog_module_name(t_rr_type cb_type) const; - const char* gen_cb_verilog_instance_name(t_rr_type cb_type) const; - const char* gen_cb_verilog_routing_track_name(t_rr_type cb_type, size_t track_id) const; + size_t get_x() const; /* get the x coordinate of this switch block */ + size_t get_y() const; /* get the y coordinate of this switch block */ + size_t get_sb_x() const; /* get the x coordinate of this switch block */ + size_t get_sb_y() const; /* get the y coordinate of this switch block */ + vtr::Point get_sb_coordinate() const; /* Get the coordinate of the SB */ + size_t get_cb_x(const t_rr_type& cb_type) const; /* get the x coordinate of this X/Y-direction block */ + size_t get_cb_y(const t_rr_type& cb_type) const; /* get the y coordinate of this X/Y-direction block */ + vtr::Point get_cb_coordinate(const t_rr_type& cb_type) const; /* Get the coordinate of the X/Y-direction CB */ + e_side get_cb_chan_side(const t_rr_type& cb_type) const; /* get the side of a Connection block */ + e_side get_cb_chan_side(const e_side& ipin_side) const; /* get the side of a Connection block */ + vtr::Point get_side_block_coordinate(const e_side& side) const; + vtr::Point get_grid_coordinate() const; public: /* Mutators */ void set(const RRGSB& src); /* get a copy from a source */ - void set_coordinator(size_t x, size_t y); - void init_num_sides(size_t num_sides); /* Allocate the vectors with the given number of sides */ - void add_chan_node(enum e_side node_side, RRChan& rr_chan, std::vector rr_chan_dir); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ - void add_ipin_node(t_rr_node* node, const enum e_side node_side, const enum e_side grid_side); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ - void add_opin_node(t_rr_node* node, const enum e_side node_side, const enum e_side grid_side); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ - void set_sb_num_reserved_conf_bits(size_t num_reserved_conf_bits); - void set_sb_conf_bits_lsb(size_t conf_bits_lsb); - void set_sb_conf_bits_msb(size_t conf_bits_msb); - void set_cb_num_reserved_conf_bits(t_rr_type cb_type, size_t num_reserved_conf_bits); - void set_cb_conf_bits_lsb(t_rr_type cb_type, size_t conf_bits_lsb); - void set_cb_conf_bits_msb(t_rr_type cb_type, size_t conf_bits_msb); - void rotate_side_chan_node_by_direction(enum e_side side, enum e_direction chan_dir, size_t offset); /* rotate all the channel nodes by a given offset */ - void counter_rotate_side_chan_node_by_direction(enum e_side side, enum e_direction chan_dir, size_t offset); /* rotate all the channel nodes by a given offset */ - void rotate_side_chan_node(enum e_side side, size_t offset); /* rotate all the channel nodes by a given offset */ - void rotate_chan_node(size_t offset); /* rotate all the channel nodes by a given offset */ - void rotate_chan_node_in_group(size_t offset); /* rotate all the channel nodes by a given offset */ - void rotate_side_opin_node_in_group(enum e_side side, size_t offset); /* rotate all the opin nodes by a given offset */ - void rotate_opin_node_in_group(size_t offset); /* rotate all the opin nodes by a given offset */ - void rotate_side(enum e_side side, size_t offset); /* rotate all the channel and opin nodes by a given offset */ - void rotate(size_t offset); /* rotate all the channel and opin nodes by a given offset */ - void swap_chan_node(enum e_side src_side, enum e_side des_side); /* swap the chan rr_nodes on two sides */ - void swap_opin_node(enum e_side src_side, enum e_side des_side); /* swap the OPIN rr_nodes on two sides */ - void swap_ipin_node(enum e_side src_side, enum e_side des_side); /* swap the IPIN rr_nodes on two sides */ - void reverse_opin_node(enum e_side side); /* reverse the OPIN rr_nodes on two sides */ - void reverse_ipin_node(enum e_side side); /* reverse the IPIN rr_nodes on two sides */ + void set_coordinate(const size_t& x, const size_t& y); + void init_num_sides(const size_t& num_sides); /* Allocate the vectors with the given number of sides */ + void add_chan_node(const e_side& node_side, RRChan& rr_chan, const std::vector& rr_chan_dir); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ + void add_ipin_node(const RRNodeId& node, const e_side& node_side); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ + void add_opin_node(const RRNodeId& node, const e_side& node_side); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */ public: /* Mutators: cleaners */ void clear(); - void clear_chan_nodes(enum e_side node_side); /* Clean the chan_width of a side */ - void clear_ipin_nodes(enum e_side node_side); /* Clean the number of IPINs of a side */ - void clear_opin_nodes(enum e_side node_side); /* Clean the number of OPINs of a side */ - void clear_one_side(enum e_side node_side); /* Clean chan/opin/ipin nodes at one side */ - private: /* Internal Mutators */ - void mirror_side_chan_node_direction(enum e_side side); /* Mirror the node direction and port direction of routing track nodes on a side */ + + /* Clean the chan_width of a side */ + void clear_chan_nodes(const e_side& node_side); + + /* Clean the number of IPINs of a side */ + void clear_ipin_nodes(const e_side& node_side); + + /* Clean the number of OPINs of a side */ + void clear_opin_nodes(const e_side& node_side); + + /* Clean chan/opin/ipin nodes at one side */ + void clear_one_side(const e_side& node_side); private: /* internal functions */ - bool is_sb_node_mirror (const RRGSB& cand, enum e_side node_side, size_t track_id) const; - bool is_cb_node_mirror (const RRGSB& cand, t_rr_type cb_type, enum e_side node_side, size_t node_id) const; - size_t get_track_id_first_short_connection(enum e_side node_side) const; + bool is_sb_node_mirror(const RRGraph& rr_graph, + const RRGSB& cand, + const e_side& node_side, + const size_t& track_id) const; + + bool 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; + + size_t get_track_id_first_short_connection(const RRGraph& rr_graph, const e_side& node_side) const; + + private: /* internal validators */ bool validate_num_sides() const; - bool validate_side(enum e_side side) const; - bool validate_track_id(enum e_side side, size_t track_id) const; - bool validate_opin_node_id(enum e_side side, size_t node_id) const; - bool validate_ipin_node_id(enum e_side side, size_t node_id) const; - bool validate_cb_type(t_rr_type cb_type) const; + bool validate_side(const e_side& side) const; + bool validate_track_id(const e_side& side, const size_t& track_id) const; + bool validate_opin_node_id(const e_side& side, const size_t& node_id) const; + bool validate_ipin_node_id(const e_side& side, const size_t& node_id) const; + bool validate_cb_type(const t_rr_type& cb_type) const; private: /* Internal Data */ /* Coordinator */ - DeviceCoordinator coordinator_; + vtr::Point coordinate_; /* Routing channel data */ std::vector chan_node_; - std::vector< std::vector > chan_node_direction_; + std::vector> chan_node_direction_; /* Logic Block Inputs data */ - std::vector< std::vector > ipin_node_; - std::vector< std::vector > ipin_node_grid_side_; + std::vector> ipin_node_; /* Logic Block Outputs data */ - std::vector< std::vector > opin_node_; - std::vector< std::vector > opin_node_grid_side_; - - /* Configuration bits */ - ConfPorts sb_conf_port_; - ConfPorts cbx_conf_port_; - ConfPorts cby_conf_port_; + std::vector> opin_node_; }; - } /* End namespace openfpga*/ #endif diff --git a/openfpga/src/utils/openfpga_rr_graph_utils.cpp b/openfpga/src/utils/openfpga_rr_graph_utils.cpp new file mode 100644 index 000000000..cac7284d5 --- /dev/null +++ b/openfpga/src/utils/openfpga_rr_graph_utils.cpp @@ -0,0 +1,66 @@ +/******************************************************************** + * This file includes most utilized functions for the rr_graph + * data structure in the OpenFPGA context + *******************************************************************/ +/* Headers from vtrutil library */ +#include "vtr_assert.h" +#include "vtr_log.h" + +#include "openfpga_rr_graph_utils.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/************************************************************************ + * Get the coordinator of a starting point of a routing track + * For routing tracks in INC_DIRECTION + * (xlow, ylow) should be the starting point + * + * For routing tracks in DEC_DIRECTION + * (xhigh, yhigh) should be the starting point + ***********************************************************************/ +vtr::Point get_track_rr_node_start_coordinate(const RRGraph& rr_graph, + const RRNodeId& track_rr_node) { + /* 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)) ); + + vtr::Point start_coordinator; + + if (INC_DIRECTION == rr_graph.node_direction(track_rr_node)) { + start_coordinator.set(rr_graph.node_xlow(track_rr_node), rr_graph.node_ylow(track_rr_node)); + } else { + VTR_ASSERT(DEC_DIRECTION == rr_graph.node_direction(track_rr_node)); + start_coordinator.set(rr_graph.node_xhigh(track_rr_node), rr_graph.node_yhigh(track_rr_node)); + } + + return start_coordinator; +} + +/************************************************************************ + * Get the coordinator of a end point of a routing track + * For routing tracks in INC_DIRECTION + * (xhigh, yhigh) should be the starting point + * + * For routing tracks in DEC_DIRECTION + * (xlow, ylow) should be the starting point + ***********************************************************************/ +vtr::Point get_track_rr_node_end_coordinate(const RRGraph& rr_graph, + const RRNodeId& track_rr_node) { + /* 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)) ); + + vtr::Point end_coordinator; + + if (INC_DIRECTION == rr_graph.node_direction(track_rr_node)) { + end_coordinator.set(rr_graph.node_xhigh(track_rr_node), rr_graph.node_yhigh(track_rr_node)); + } else { + VTR_ASSERT(DEC_DIRECTION == rr_graph.node_direction(track_rr_node)); + end_coordinator.set(rr_graph.node_xlow(track_rr_node), rr_graph.node_ylow(track_rr_node)); + } + + return end_coordinator; +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/utils/openfpga_rr_graph_utils.h b/openfpga/src/utils/openfpga_rr_graph_utils.h new file mode 100644 index 000000000..44306664b --- /dev/null +++ b/openfpga/src/utils/openfpga_rr_graph_utils.h @@ -0,0 +1,28 @@ +#ifndef OPENFPGA_RR_GRAPH_UTILS_H +#define OPENFPGA_RR_GRAPH_UTILS_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +/* Headers from vtrutil library */ +#include "vtr_geometry.h" + +/* Headers from vpr library */ +#include "rr_graph_obj.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +vtr::Point get_track_rr_node_start_coordinate(const RRGraph& rr_graph, + const RRNodeId& track_rr_node); + +vtr::Point get_track_rr_node_end_coordinate(const RRGraph& rr_graph, + const RRNodeId& track_rr_node); + +} /* end namespace openfpga */ + +#endif