implemented an native way in finding rotable Switch blocks

This commit is contained in:
tangxifan 2019-05-25 19:37:18 -06:00
parent ae0248fbc6
commit d3eae80e64
7 changed files with 234 additions and 75 deletions

View File

@ -150,7 +150,8 @@
<!-- ODIN II specific config ends -->
<!-- Physical descriptions begin -->
<layout auto="1.0"/>
<!--layout auto="1.0"/-->
<layout height="20" width="20"/>
<spice_settings>
<parameters>
<options sim_temp="25" post="off" captab="off" fast="on"/>

View File

@ -1400,7 +1400,7 @@ void fpga_x2p_setup(t_vpr_setup vpr_setup,
/* Assign Gobal variable: build the Routing Resource Channels */
device_rr_chan = build_device_rr_chan(num_rr_nodes, rr_node, rr_node_indices, Arch->num_segments, rr_indexed_data);
device_rr_switch_block = build_device_rr_switch_blocks(num_rr_nodes, rr_node, rr_node_indices);
device_rr_switch_block = build_device_rr_switch_blocks(num_rr_nodes, rr_node, rr_node_indices, Arch->num_segments, rr_indexed_data);
/* Rotatable will be done in the next step
identify_rotatable_switch_blocks();

View File

@ -31,6 +31,8 @@
#include "fpga_x2p_globals.h"
#include "fpga_x2p_utils.h"
#include "fpga_x2p_timing_utils.h"
/* Build the list of spice_model_ports provided in the cur_spice_model delay_info */
t_spice_model_port** get_spice_model_delay_info_ports(t_spice_model* cur_spice_model,
char* port_list,

View File

@ -82,9 +82,9 @@ void print_device_rr_chan_stats(DeviceRRChan& device_rr_chan);
static
RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y,
int LL_num_rr_nodes,
t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices);
int LL_num_rr_nodes, t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices, int num_segments,
t_rr_indexed_data* LL_rr_indexed_data);
/***** subroutines *****/
void assign_switch_block_mirror(t_sb* src, t_sb* des) {
@ -272,16 +272,18 @@ boolean is_two_switch_blocks_mirror(t_sb* src, t_sb* des) {
/* check the numbers of opin_rr_nodes */
for (int side = 0; side < src->num_sides; ++side) {
if (src->num_ipin_rr_nodes[side] != des->num_ipin_rr_nodes[side]) {
if (src->num_opin_rr_nodes[side] != des->num_opin_rr_nodes[side]) {
return FALSE;
}
}
/* Make sure the number of conf bits are the same */
/* Make sure the number of conf bits are the same
* TODO: the check should be done when conf_bits are initialized when creating SBs
if ( (src->conf_bits_msb - src->conf_bits_lsb)
!= (des->conf_bits_msb - des->conf_bits_lsb)) {
return FALSE;
}
*/
return TRUE;
}
@ -845,9 +847,9 @@ DeviceRRChan build_device_rr_chan(int LL_num_rr_nodes, t_rr_node* LL_rr_node,
*/
static
RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y,
int LL_num_rr_nodes,
t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices) {
int LL_num_rr_nodes, t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices, int num_segments,
t_rr_indexed_data* LL_rr_indexed_data) {
/* Create an object to return */
RRSwitchBlock rr_switch_block;
@ -868,8 +870,7 @@ RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y,
Side side_manager(side);
int ix = 0;
int iy = 0;
int chan_width = 0;
t_rr_node** chan_rr_node = NULL;
RRChan rr_chan;
int temp_num_opin_rr_nodes[2] = {0,0};
t_rr_node** temp_opin_rr_node[2] = {NULL, NULL};
enum e_side opin_grid_side[2] = {NUM_SIDES, NUM_SIDES};
@ -884,11 +885,11 @@ RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y,
/* Routing channels*/
ix = sb_x;
iy = sb_y + 1;
/* Channel width */
chan_width = chan_width_y[ix];
/* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */
chan_rr_node = get_chan_rr_nodes(&chan_width, CHANY, ix, iy,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
/* Create a rr_chan object and check if it is unique in the graph */
rr_chan = build_one_rr_chan(CHANY, ix, iy,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices,
num_segments, LL_rr_indexed_data);
chan_dir_to_port_dir_mapping[0] = OUT_PORT;
chan_dir_to_port_dir_mapping[1] = IN_PORT;
@ -916,12 +917,12 @@ RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y,
/* Routing channels*/
ix = sb_x + 1;
iy = sb_y;
/* Channel width */
chan_width = chan_width_x[iy];
/* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */
/* Collect rr_nodes for Tracks for top: chany[x][y+1] */
chan_rr_node = get_chan_rr_nodes(&chan_width, CHANX, ix, iy,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
/* Create a rr_chan object and check if it is unique in the graph */
rr_chan = build_one_rr_chan(CHANX, ix, iy,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices,
num_segments, LL_rr_indexed_data);
chan_dir_to_port_dir_mapping[0] = OUT_PORT;
chan_dir_to_port_dir_mapping[1] = IN_PORT;
@ -948,12 +949,12 @@ RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y,
/* Routing channels*/
ix = sb_x;
iy = sb_y;
/* Channel width */
chan_width = chan_width_y[ix];
/* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */
/* Collect rr_nodes for Tracks for bottom: chany[x][y] */
chan_rr_node = get_chan_rr_nodes(&chan_width, CHANY, ix, iy,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
/* Create a rr_chan object and check if it is unique in the graph */
rr_chan = build_one_rr_chan(CHANY, ix, iy,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices,
num_segments, LL_rr_indexed_data);
chan_dir_to_port_dir_mapping[0] = IN_PORT;
chan_dir_to_port_dir_mapping[1] = OUT_PORT;
@ -980,12 +981,12 @@ RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y,
/* Routing channels*/
ix = sb_x;
iy = sb_y;
/* Channel width */
chan_width = chan_width_x[iy];
/* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */
/* Collect rr_nodes for Tracks for left: chanx[x][y] */
chan_rr_node = get_chan_rr_nodes(&chan_width, CHANX, ix, iy,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
/* Create a rr_chan object and check if it is unique in the graph */
rr_chan = build_one_rr_chan(CHANX, ix, iy,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices,
num_segments, LL_rr_indexed_data);
chan_dir_to_port_dir_mapping[0] = IN_PORT;
chan_dir_to_port_dir_mapping[1] = OUT_PORT;
@ -1010,15 +1011,21 @@ RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y,
exit(1);
}
/* Fill chan_rr_nodes */
for (int itrack = 0; itrack < chan_width; ++itrack) {
/* Identify the directionality, record it in rr_node_direction */
if (INC_DIRECTION == chan_rr_node[itrack]->direction) {
rr_switch_block.add_chan_node(chan_rr_node[itrack], side_manager.get_side(), chan_dir_to_port_dir_mapping[0]);
} else {
assert (DEC_DIRECTION == chan_rr_node[itrack]->direction);
rr_switch_block.add_chan_node(chan_rr_node[itrack], side_manager.get_side(), chan_dir_to_port_dir_mapping[1]);
/* Organize a vector of port direction */
if (0 < rr_chan.get_chan_width()) {
std::vector<enum PORTS> rr_chan_dir;
rr_chan_dir.resize(rr_chan.get_chan_width());
for (size_t itrack = 0; itrack < rr_chan.get_chan_width(); ++itrack) {
/* Identify the directionality, record it in rr_node_direction */
if (INC_DIRECTION == rr_chan.get_node(itrack)->direction) {
rr_chan_dir[itrack] = chan_dir_to_port_dir_mapping[0];
} else {
assert (DEC_DIRECTION == rr_chan.get_node(itrack)->direction);
rr_chan_dir[itrack] = chan_dir_to_port_dir_mapping[1];
}
}
/* Fill chan_rr_nodes */
rr_switch_block.add_chan_node(side_manager.get_side(), rr_chan, rr_chan_dir);
}
/* Fill opin_rr_nodes */
@ -1037,7 +1044,6 @@ RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y,
rr_switch_block.clear_ipin_nodes(side_manager.get_side());
/* Free */
my_free(chan_rr_node);
temp_num_opin_rr_nodes[0] = 0;
my_free(temp_opin_rr_node[0]);
temp_num_opin_rr_nodes[1] = 0;
@ -1058,9 +1064,9 @@ RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y,
* Each switch block in the FPGA fabric will be an instance of these modules.
* We maintain a map from each instance to each module
*/
DeviceRRSwitchBlock build_device_rr_switch_blocks(int LL_num_rr_nodes,
t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices) {
DeviceRRSwitchBlock build_device_rr_switch_blocks(int LL_num_rr_nodes, t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices, int num_segments,
t_rr_indexed_data* LL_rr_indexed_data) {
/* Create an object */
DeviceRRSwitchBlock LL_device_rr_switch_block;
@ -1072,7 +1078,9 @@ DeviceRRSwitchBlock build_device_rr_switch_blocks(int LL_num_rr_nodes,
for (int ix = 0; ix < nx + 1; ++ix) {
for (int iy = 0; iy < ny + 1; ++iy) {
RRSwitchBlock rr_switch_block = build_rr_switch_block(ix, iy,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
LL_num_rr_nodes, LL_rr_node,
LL_rr_node_indices,
num_segments, LL_rr_indexed_data);
DeviceCoordinator sb_coordinator((size_t)ix, (size_t)iy);
LL_device_rr_switch_block.add_rr_switch_block(sb_coordinator, rr_switch_block);
}

View File

@ -14,9 +14,9 @@ DeviceRRChan build_device_rr_chan(int LL_num_rr_nodes, t_rr_node* LL_rr_node,
* Each switch block in the FPGA fabric will be an instance of these modules.
* We maintain a map from each instance to each module
*/
DeviceRRSwitchBlock build_device_rr_switch_blocks(int LL_num_rr_nodes,
t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices);
DeviceRRSwitchBlock build_device_rr_switch_blocks(int LL_num_rr_nodes, t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices, int num_segments,
t_rr_indexed_data* LL_rr_indexed_data);
/* Rotatable will be done in the next step
identify_rotatable_switch_blocks();

View File

@ -6,6 +6,13 @@
/* Member Functions of Class RRChan */
/* Constructors */
RRChan::RRChan() {
type_ = NUM_RR_TYPES;
nodes_.resize(0);
node_segments_.resize(0);
}
/* Accessors */
t_rr_type RRChan::get_type() const {
return type_;
@ -112,9 +119,18 @@ void RRChan::add_node(t_rr_node* node, size_t node_segment) {
nodes_[node->ptc_num] = node;
node_segments_[node->ptc_num] = node_segment;
assert(valid_node_type(node));
return;
}
/* rotate the nodes and node_segments with a given offset */
void RRChan::rotate(size_t rotate_begin, size_t rotate_end, size_t offset) {
std::rotate(nodes_.begin() + rotate_begin, nodes_.begin() + rotate_begin + offset, nodes_.begin() + rotate_end);
std::rotate(node_segments_.begin() + rotate_begin, node_segments_.begin() + rotate_begin + offset, node_segments_.begin() + rotate_end);
return;
}
/* Clear content */
void RRChan::clear() {
nodes_.clear();
@ -133,6 +149,19 @@ bool RRChan::valid_type(t_rr_type type) const {
return false;
}
/* Check each node, see if the node type is consistent with the type */
bool RRChan::valid_node_type(t_rr_node* node) const {
valid_type(node->type);
if (NUM_RR_TYPES == type_) {
return true;
}
valid_type(type_);
if (type_ != node->type) {
return false;
}
return true;
}
/* check if the node id is valid */
bool RRChan::valid_node_id(size_t node_id) const {
if (node_id < nodes_.size()) {
@ -333,7 +362,7 @@ size_t RRSwitchBlock::get_num_sides() const {
size_t RRSwitchBlock::get_chan_width(enum e_side side) const {
Side side_manager(side);
assert(side_manager.validate());
return chan_node_[side_manager.to_size_t()].size();
return chan_node_[side_manager.to_size_t()].get_chan_width();
}
/* Get the maximum number of routing tracks on all sides */
@ -371,9 +400,24 @@ t_rr_node* RRSwitchBlock::get_chan_node(enum e_side side, size_t track_id) const
/* Ensure the track is valid in the context of this switch block at a specific side */
assert( validate_track_id(side, track_id) );
return chan_node_[side_manager.to_size_t()][track_id];
return chan_node_[side_manager.to_size_t()].get_node(track_id);
}
/* get the segment id of a channel rr_node */
size_t RRSwitchBlock::get_chan_node_segment(enum e_side side, size_t track_id) const {
Side side_manager(side);
assert(side_manager.validate());
/* Ensure the side is valid in the context of this switch block */
assert( validate_side(side) );
/* Ensure the track is valid in the context of this switch block at a specific side */
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 RRSwitchBlock::get_num_ipin_nodes(enum e_side side) const {
Side side_manager(side);
@ -443,8 +487,8 @@ int RRSwitchBlock::get_node_index(t_rr_node* node,
switch (node->type) {
case CHANX:
case CHANY:
for (size_t inode = 0; inode < get_chan_width(node_side); ++inode) {
if ((node == chan_node_[side_manager.to_size_t()][inode])
for (size_t inode = 0; inode < get_chan_width(node_side); ++inode){
if ((node == chan_node_[side_manager.to_size_t()].get_node(inode))
/* Check if direction meets specification */
&&(node_direction == chan_node_direction_[side_manager.to_size_t()][inode])) {
cnt++;
@ -580,6 +624,83 @@ bool RRSwitchBlock::is_node_imply_short_connection(t_rr_node* src_node) const {
return false;
}
/* 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 RRSwitchBlock::is_mirrorable(RRSwitchBlock& 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) {
Side 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(side_manager.get_side()))
&& (size_t(-1) != cand.get_track_id_first_short_connection(side_manager.get_side())))
|| ((size_t(-1) != get_track_id_first_short_connection(side_manager.get_side()) )
&& ( size_t(-1) == cand.get_track_id_first_short_connection(side_manager.get_side()))) ) {
return false;
}
}
/* check the numbers of opin_rr_nodes */
for (size_t side = 0; side < get_num_sides(); ++side) {
Side side_manager(side);
if (get_num_opin_nodes(side_manager.get_side()) != cand.get_num_opin_nodes(side_manager.get_side())) {
return false;
}
}
/* Make sure the number of conf bits are the same */
/* TODO: recover this check when the SB conf bits are allocated during setup stage!!!
if ( ( get_num_conf_bits() != cand.get_num_conf_bits() )
|| ( get_num_reserved_conf_bits() != cand.get_num_reserved_conf_bits() ) ) {
return false;
}
*/
return true;
}
/* Determine an initial offset in rotating the candidate Switch Block to find a mirror matching
* We try to find the offset in track_id where the two Switch Blocks have their first short connections
*/
size_t RRSwitchBlock::get_hint_rotate_offset(RRSwitchBlock& cand) const {
size_t offset_hint = size_t(-1);
assert (get_num_sides() == cand.get_num_sides());
/* check the numbers/directionality of channel rr_nodes */
for (size_t side = 0; side < get_num_sides(); ++side) {
Side side_manager(side);
/* Ensure we have the same channel width on this side */
assert (get_chan_width(side_manager.get_side()) == cand.get_chan_width(side_manager.get_side()));
/* Find the track id of the first short connection */
size_t src_offset = get_track_id_first_short_connection(side_manager.get_side());
size_t des_offset = cand.get_track_id_first_short_connection(side_manager.get_side());
if ( size_t(-1) == src_offset || size_t(-1) == des_offset ) {
return 0; /* default we give zero */
}
size_t temp_hint = abs( (int)(src_offset - des_offset));
offset_hint = std::min(temp_hint, offset_hint);
}
return offset_hint;
}
/* check if the candidate SB is a mirror of the current one */
/* Idenify mirror Switch blocks
* Check each two switch blocks:
@ -630,16 +751,18 @@ bool RRSwitchBlock::is_mirror(RRSwitchBlock& cand) const {
for (size_t side = 0; side < get_num_sides(); ++side) {
Side side_manager(side);
if (get_num_ipin_nodes(side_manager.get_side()) != cand.get_num_ipin_nodes(side_manager.get_side())) {
if (get_num_opin_nodes(side_manager.get_side()) != cand.get_num_opin_nodes(side_manager.get_side())) {
return false;
}
}
/* Make sure the number of conf bits are the same */
/* TODO: the num conf bits will be fixed when allocate the SBs
if ( ( get_num_conf_bits() != cand.get_num_conf_bits() )
|| ( get_num_reserved_conf_bits() != cand.get_num_reserved_conf_bits() ) ) {
return false;
}
*/
return true;
}
@ -732,17 +855,14 @@ void RRSwitchBlock::init_num_sides(size_t num_sides) {
}
/* Add a node to the chan_node_ list and also assign its direction in chan_node_direction_ */
void RRSwitchBlock::add_chan_node(t_rr_node* node, enum e_side node_side, enum PORTS node_direction) {
void RRSwitchBlock::add_chan_node(enum e_side node_side, RRChan rr_chan, std::vector<enum PORTS> rr_chan_dir) {
Side side_manager(node_side);
/* Validate: 1. side is valid, the type of node is valid */
assert(validate_side(node_side));
/* resize the array if needed, node is placed in the sequence of node->ptc_num */
if (size_t(node->ptc_num + 1) > chan_node_[side_manager.to_size_t()].size()) {
chan_node_[side_manager.to_size_t()].resize(node->ptc_num + 1); /* resize to the maximum */
chan_node_direction_[side_manager.to_size_t()].resize(node->ptc_num + 1); /* resize to the maximum */
}
/* fill the dedicated element in the vector */
chan_node_[side_manager.to_size_t()][node->ptc_num] = node;
chan_node_direction_[side_manager.to_size_t()][node->ptc_num] = node_direction;
chan_node_[side_manager.to_size_t()] = rr_chan;
chan_node_direction_[side_manager.to_size_t()] = rr_chan_dir;
return;
}
@ -798,7 +918,7 @@ void RRSwitchBlock::rotate_chan_node(size_t offset) {
continue;
}
for (size_t inode = 0; inode < get_chan_width(side_manager.get_side()) - 1; ++inode) {
if ( ( abs(chan_node_[side][inode]->yhigh - chan_node_[side][inode]->ylow + chan_node_[side][inode]->xhigh - chan_node_[side][inode]->xlow) != abs(chan_node_[side][inode + 1]->yhigh - chan_node_[side][inode + 1]->ylow + chan_node_[side][inode + 1]->xhigh - chan_node_[side][inode + 1]->xlow))
if ( (get_chan_node_segment(side_manager.get_side(), inode) != get_chan_node_segment(side_manager.get_side(), inode + 1))
|| ( inode == get_chan_width(side_manager.get_side()) - 2) ) {
/* Record the upper bound */
if ( inode == get_chan_width(side_manager.get_side()) - 2) {
@ -815,12 +935,10 @@ void RRSwitchBlock::rotate_chan_node(size_t offset) {
}
assert(offset < rotate_end - rotate_begin + 1);
/* Find a group split, rotate */
std::rotate(chan_node_.begin() + rotate_begin,
chan_node_.begin() + rotate_begin + offset,
chan_node_.begin() + rotate_end);
std::rotate(chan_node_direction_.begin() + rotate_begin,
chan_node_direction_.begin() + rotate_begin + offset,
chan_node_direction_.begin() + rotate_end);
chan_node_[side].rotate(rotate_begin, rotate_end, offset);
std::rotate(chan_node_direction_[side].begin() + rotate_begin,
chan_node_direction_[side].begin() + rotate_begin + offset,
chan_node_direction_[side].begin() + rotate_end);
/* Update the lower bound */
rotate_begin = inode + 1;
}
@ -865,12 +983,12 @@ void RRSwitchBlock::rotate_opin_node(size_t offset) {
/* Make sure offset is in range */
assert (offset < rotate_end - rotate_begin + 1);
/* Find a group split, rotate */
std::rotate(opin_node_.begin() + rotate_begin,
opin_node_.begin() + rotate_begin + offset,
opin_node_.begin() + rotate_end);
std::rotate(opin_node_grid_side_.begin() + rotate_begin,
opin_node_grid_side_.begin() + rotate_begin + offset,
opin_node_grid_side_.begin() + rotate_end);
std::rotate(opin_node_[side].begin() + rotate_begin,
opin_node_[side].begin() + rotate_begin + offset,
opin_node_[side].begin() + rotate_end);
std::rotate(opin_node_grid_side_[side].begin() + rotate_begin,
opin_node_grid_side_[side].begin() + rotate_begin + offset,
opin_node_grid_side_[side].begin() + rotate_end);
/* Update the lower bound */
rotate_begin = inode + 1;
}
@ -971,6 +1089,7 @@ bool RRSwitchBlock::is_node_mirror(RRSwitchBlock& cand,
t_rr_node* node = this->get_chan_node(node_side, track_id);
t_rr_node* cand_node = cand.get_chan_node(node_side, track_id);
bool is_short_conkt = this->is_node_imply_short_connection(node);
if (is_short_conkt != cand.is_node_imply_short_connection(cand_node)) {
return false;
}
@ -1012,6 +1131,19 @@ bool RRSwitchBlock::is_node_mirror(RRSwitchBlock& cand,
return true;
}
size_t RRSwitchBlock::get_track_id_first_short_connection(enum e_side node_side) const {
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_node_imply_short_connection(get_chan_node(node_side, inode))) {
return inode;
}
}
return size_t(-1);
}
/* Validate if the number of sides are consistent among internal data arrays ! */
bool RRSwitchBlock::validate_num_sides() const {
size_t num_sides = chan_node_direction_.size();
@ -1055,7 +1187,7 @@ bool RRSwitchBlock::validate_track_id(enum e_side side, size_t track_id) const {
if (false == validate_side(side)) {
return false;
}
if ( ( track_id < chan_node_[side_manager.to_size_t()].size())
if ( ( track_id < chan_node_[side_manager.to_size_t()].get_chan_width())
&& ( track_id < chan_node_direction_[side_manager.to_size_t()].size()) ) {
return true;
}
@ -1238,18 +1370,26 @@ void DeviceRRSwitchBlock::add_rr_switch_block(DeviceCoordinator& coordinator,
/* add rotatable mirror support */
for (size_t mirror_id = 0; mirror_id < get_num_rotatable_mirror(); ++mirror_id) {
RRSwitchBlock rotate_mirror = rr_switch_block;
is_rotatable_mirror = true;
/* Try to rotate as many times as the maximum channel width in this switch block
* This may not fully cover all the rotation possibility but may be enough now
*/
/* Skip if these may never match as a mirror (violation in basic requirements */
if (false == get_switch_block(rotatable_mirror_[mirror_id]).is_mirrorable(rotate_mirror)) {
continue;
}
/* Give an initial rotation to accelerate the prediction */
size_t hint_offset = get_switch_block(rotatable_mirror_[mirror_id]).get_hint_rotate_offset(rotate_mirror);
rotate_mirror.rotate_chan_node(hint_offset);
for (size_t offset = 0; offset < rr_switch_block.get_max_chan_width(); ++offset) {
rotate_mirror.rotate(1);
if (true == get_switch_block(unique_mirror_[mirror_id]).is_mirror(rotate_mirror)) {
if (true == get_switch_block(rotatable_mirror_[mirror_id]).is_mirror(rotate_mirror)) {
/* This is a mirror, raise the flag and we finish */
is_rotatable_mirror = false;
/* Record the id of unique mirror */
rr_switch_block_rotatable_mirror_id_[coordinator.get_x()][coordinator.get_y()] = mirror_id;
break;
}
rotate_mirror.rotate_chan_node(1);
}
if (false == is_rotatable_mirror) {
break;

View File

@ -36,6 +36,8 @@
* -------------
*/
class RRChan {
public: /* Constructors */
RRChan();
public: /* Accessors */
t_rr_type get_type() const;
size_t get_chan_width() const; /* get the number of tracks in this channel */
@ -48,9 +50,11 @@ class RRChan {
void set_type(t_rr_type type); /* modify type */
void reserve_node(size_t node_size); /* reseve a number of nodes to the array */
void add_node(t_rr_node* node, size_t node_segment); /* add a node to the array */
void rotate(size_t rotate_begin, size_t rotate_end, size_t offset); /* rotate the nodes and node_segments with a given offset */
void clear(); /* clear the content */
private: /* internal functions */
bool valid_type(t_rr_type type) const;
bool valid_node_type(t_rr_node* node) const;
bool valid_node_id(size_t node_id) const;
private: /* Internal Data */
t_rr_type type_; /* channel type: CHANX or CHANY */
@ -129,6 +133,7 @@ class RRSwitchBlock {
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 */
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 */
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 */
@ -145,6 +150,8 @@ class RRSwitchBlock {
size_t get_conf_bits_msb() const;
bool is_node_imply_short_connection(t_rr_node* src_node) const; /* Check if the node imply a short connection inside the SB, which happens to long wires across a FPGA fabric */
bool is_mirror(RRSwitchBlock& cand) const; /* check if the candidate SB is a mirror of the current one */
bool is_mirrorable(RRSwitchBlock& cand) const; /* check if the candidate SB satisfy the basic requirements on being a mirror of the current one */
size_t get_hint_rotate_offset(RRSwitchBlock& cand) const; /* Determine an initial offset in rotating the candidate Switch Block to find a mirror matching*/
public: /* Cooridinator conversion */
DeviceCoordinator get_side_block_coordinator(enum e_side side) const;
public: /* Verilog writer */
@ -153,7 +160,7 @@ class RRSwitchBlock {
public: /* Mutators */
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(t_rr_node* node, enum e_side node_side, enum PORTS node_direction); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */
void add_chan_node(enum e_side node_side, RRChan rr_chan, std::vector<enum PORTS> rr_chan_dir); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */
void add_ipin_node(t_rr_node* node, enum e_side node_side, enum e_side grid_side); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */
void add_opin_node(t_rr_node* node, enum e_side node_side, enum e_side grid_side); /* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */
void set_num_reserved_conf_bits(size_t num_reserved_conf_bits);
@ -170,6 +177,7 @@ class RRSwitchBlock {
private: /* Internal Mutators */
private: /* internal functions */
bool is_node_mirror (RRSwitchBlock& cand, enum e_side node_side, size_t track_id) const;
size_t get_track_id_first_short_connection(enum e_side node_side) const;
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;
@ -178,8 +186,8 @@ class RRSwitchBlock {
bool validate_num_conf_bits() const;
private: /* Internal Data */
DeviceCoordinator coordinator_;
std::vector<RRChan> chan_node_;
std::vector< std::vector<enum PORTS> > chan_node_direction_;
std::vector< std::vector<t_rr_node*> > chan_node_;
std::vector< std::vector<t_rr_node*> > ipin_node_;
std::vector< std::vector<enum e_side> > ipin_node_grid_side_;
std::vector< std::vector<t_rr_node*> > opin_node_;