update class rr_switch_block and be ready for updating the downstream verilog generator

This commit is contained in:
tangxifan 2019-05-22 22:04:31 -06:00
parent 502344b13a
commit 4aab93b729
9 changed files with 717 additions and 2 deletions

View File

@ -0,0 +1,57 @@
#include <algorithm>
#include "device_coordinator.h"
/* Member functions for DeviceCoordinator */
/* Public constructors */
/*
DeviceCoordinator::DeviceCoordinator(DeviceCoordinator& coordinator) {
set(coordinator.get_x(), coordinator.get_y());
return;
}
*/
DeviceCoordinator::DeviceCoordinator(size_t x, size_t y) {
set(x, y);
return;
}
DeviceCoordinator::DeviceCoordinator() {
set(0, 0);
return;
}
/* Public accessors */
size_t DeviceCoordinator::get_x() const {
return x_;
}
size_t DeviceCoordinator::get_y() const {
return y_;
}
/* Public mutators */
void DeviceCoordinator::set(size_t x, size_t y) {
set_x(x);
set_y(y);
return;
}
void DeviceCoordinator::set_x(size_t x) {
x_ = x;
return;
}
void DeviceCoordinator::set_y(size_t y) {
y_ = y;
return;
}
void DeviceCoordinator::rotate() {
std::swap(x_, y_);
return;
}
void DeviceCoordinator::clear() {
set(0, 0);
return;
}

View File

@ -0,0 +1,33 @@
#ifndef DEVICE_COORDINATOR_H
#define DEVICE_COORDINATOR_H
/* Coordinator System for FPGA Device
* It is based on a 3-D (x,y,z) coordinator system
* (x,y) is used for all the routing resources,
* z is used for only grid, which have multiple logic blocks
*/
class DeviceCoordinator {
public: /* Contructors */
/*
DeviceCoordinator(DeviceCoordinator& coordinator);
*/
DeviceCoordinator(size_t x, size_t y);
DeviceCoordinator();
public: /* Accessors */
size_t get_x() const;
size_t get_y() const;
public: /* Mutators */
void set(size_t x, size_t y);
void set_x(size_t x);
void set_y(size_t y);
void rotate();
void clear();
private: /* Internal Mutators */
private: /* internal functions */
private: /* Internal Data */
size_t x_;
size_t y_;
size_t z_;
};
#endif

View File

@ -27,6 +27,7 @@
/* Include spice support headers*/
#include "read_xml_spice_util.h"
#include "linkedlist.h"
#include "rr_blocks.h"
#include "fpga_x2p_types.h"
#include "fpga_x2p_globals.h"
#include "fpga_x2p_utils.h"
@ -35,6 +36,7 @@
#include "fpga_x2p_pbtypes_utils.h"
#include "fpga_x2p_pb_rr_graph.h"
#include "fpga_x2p_router.h"
#include "fpga_x2p_unique_routing.h"
/* Get initial value of a Latch/FF output*/
int get_ff_output_init_val(t_logical_block* ff_logical_block) {
@ -3127,6 +3129,7 @@ void spice_backannotate_vpr_post_route_info(t_det_routing_arch RoutingArch,
/* Build Array for each Switch block and Connection block */
vpr_printf(TIO_MESSAGE_INFO, "Collecting detailed information for each Switch block...\n");
alloc_and_build_switch_blocks_info(RoutingArch, num_rr_nodes, rr_node, rr_node_indices);
device_rr_switch_block = build_device_rr_switch_blocks(RoutingArch, num_rr_nodes, rr_node, rr_node_indices);
vpr_printf(TIO_MESSAGE_INFO, "Collecting detailed information for each to Connection block...\n");
alloc_and_build_connection_blocks_info(RoutingArch, num_rr_nodes, rr_node, rr_node_indices);

View File

@ -46,3 +46,4 @@ char* fpga_spice_bitstream_routing_log_file_postfix = "_routing_bitstream.log";
char* default_sdc_folder = "SDC/";
DeviceRRChan device_rr_chan;
DeviceRRSwitchBlock device_rr_switch_block;

View File

@ -41,5 +41,6 @@ extern char* fpga_spice_bitstream_logic_block_log_file_postfix;
extern char* fpga_spice_bitstream_routing_log_file_postfix;
extern DeviceRRChan device_rr_chan;
extern DeviceRRSwitchBlock device_rr_switch_block;
#endif

View File

@ -80,6 +80,13 @@ RRChan build_one_rr_chan(t_rr_type chan_type, size_t chan_x, size_t chan_y,
void print_device_rr_chan_stats(DeviceRRChan& device_rr_chan);
static
RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y,
t_det_routing_arch RoutingArch,
int LL_num_rr_nodes,
t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices);
/***** subroutines *****/
void assign_switch_block_mirror(t_sb* src, t_sb* des) {
assert ( (NULL != src) && (NULL != des) );
@ -796,6 +803,288 @@ DeviceRRChan build_device_rr_chan(int LL_num_rr_nodes, t_rr_node* LL_rr_node,
return LL_device_rr_chan;
}
/* Build arrays for rr_nodes of each Switch Blocks
* A Switch Box subckt consists of following ports:
* 1. Channel Y [x][y] inputs
* 2. Channel X [x+1][y] inputs
* 3. Channel Y [x][y-1] outputs
* 4. Channel X [x][y] outputs
* 5. Grid[x][y+1] Right side outputs pins
* 6. Grid[x+1][y+1] Left side output pins
* 7. Grid[x+1][y+1] Bottom side output pins
* 8. Grid[x+1][y] Top side output pins
* 9. Grid[x+1][y] Left side output pins
* 10. Grid[x][y] Right side output pins
* 11. Grid[x][y] Top side output pins
* 12. Grid[x][y+1] Bottom side output pins
*
* -------------- --------------
* | | | |
* | Grid | ChanY | Grid |
* | [x][y+1] | [x][y+1] | [x+1][y+1] |
* | | | |
* -------------- --------------
* ----------
* ChanX | Switch | ChanX
* [x][y] | Box | [x+1][y]
* | [x][y] |
* ----------
* -------------- --------------
* | | | |
* | Grid | ChanY | Grid |
* | [x][y] | [x][y] | [x+1][y] |
* | | | |
* -------------- --------------
* For channels chanY with INC_DIRECTION on the top side, they should be marked as outputs
* For channels chanY with DEC_DIRECTION on the top side, they should be marked as inputs
* For channels chanY with INC_DIRECTION on the bottom side, they should be marked as inputs
* For channels chanY with DEC_DIRECTION on the bottom side, they should be marked as outputs
* For channels chanX with INC_DIRECTION on the left side, they should be marked as inputs
* For channels chanX with DEC_DIRECTION on the left side, they should be marked as outputs
* For channels chanX with INC_DIRECTION on the right side, they should be marked as outputs
* For channels chanX with DEC_DIRECTION on the right side, they should be marked as inputs
*/
static
RRSwitchBlock build_rr_switch_block(int sb_x, int sb_y,
t_det_routing_arch RoutingArch,
int LL_num_rr_nodes,
t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices) {
/* Create an object to return */
RRSwitchBlock rr_switch_block;
/* Check */
assert((!(0 > sb_x))&&(!(sb_x > (nx + 1))));
assert((!(0 > sb_y))&&(!(sb_y > (ny + 1))));
/* Basic information*/
rr_switch_block.init_num_sides(4); /* Fixed number of sides */
/* Find all rr_nodes of channels */
/* Side: TOP => 0, RIGHT => 1, BOTTOM => 2, LEFT => 3 */
for (size_t side = 0; side < rr_switch_block.get_num_sides(); ++side) {
/* Local variables inside this for loop */
Side side_manager(side);
int ix = 0;
int iy = 0;
int chan_width = 0;
t_rr_node** chan_rr_node = NULL;
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};
enum PORTS chan_dir_to_port_dir_mapping[2] = {OUT_PORT, IN_PORT}; /* 0: INC_DIRECTION => ?; 1: DEC_DIRECTION => ? */
switch (side) {
case 0: /* TOP */
/* For the bording, we should take special care */
if (sb_y == ny) {
rr_switch_block.clear_one_side(side_manager.get_side());
break;
}
/* 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);
chan_dir_to_port_dir_mapping[0] = OUT_PORT;
chan_dir_to_port_dir_mapping[1] = IN_PORT;
/* Include Grid[x][y+1] RIGHT side outputs pins */
temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0],
OPIN, sb_x, sb_y + 1, 1,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
/* Include Grid[x+1][y+1] Left side output pins */
temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1],
OPIN, sb_x + 1, sb_y + 1, 3,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
/* Assign grid side of OPIN */
/* Grid[x][y+1] RIGHT side outputs pins */
opin_grid_side[0] = RIGHT;
/* Grid[x+1][y+1] left side outputs pins */
opin_grid_side[1] = LEFT;
break;
case 1: /* RIGHT */
/* For the bording, we should take special care */
if (sb_x == nx) {
rr_switch_block.clear_one_side(side_manager.get_side());
break;
}
/* 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);
chan_dir_to_port_dir_mapping[0] = OUT_PORT;
chan_dir_to_port_dir_mapping[1] = IN_PORT;
/* include Grid[x+1][y+1] Bottom side output pins */
temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0],
OPIN, sb_x + 1, sb_y + 1, 2,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
/* include Grid[x+1][y] Top side output pins */
temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1],
OPIN, sb_x + 1, sb_y, 0,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
/* Assign grid side of OPIN */
/* Grid[x+1][y+1] BOTTOM side outputs pins */
opin_grid_side[0] = BOTTOM;
/* Grid[x+1][y] TOP side outputs pins */
opin_grid_side[1] = TOP;
break;
case 2:
/* For the bording, we should take special care */
if (sb_y == 0) {
rr_switch_block.clear_one_side(side_manager.get_side());
break;
}
/* 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);
chan_dir_to_port_dir_mapping[0] = IN_PORT;
chan_dir_to_port_dir_mapping[1] = OUT_PORT;
/* TODO: include Grid[x+1][y] Left side output pins */
temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0],
OPIN, sb_x + 1, sb_y, 3,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
/* TODO: include Grid[x][y] Right side output pins */
temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1],
OPIN, sb_x, sb_y, 1,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
/* Assign grid side of OPIN */
/* Grid[x+1][y] LEFT side outputs pins */
opin_grid_side[0] = LEFT;
/* Grid[x][y] RIGHT side outputs pins */
opin_grid_side[1] = RIGHT;
break;
case 3:
/* For the bording, we should take special care */
if (sb_x == 0) {
rr_switch_block.clear_one_side(side_manager.get_side());
break;
}
/* 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);
chan_dir_to_port_dir_mapping[0] = IN_PORT;
chan_dir_to_port_dir_mapping[1] = OUT_PORT;
/* include Grid[x][y+1] Bottom side outputs pins */
temp_opin_rr_node[0] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[0],
OPIN, sb_x, sb_y + 1, 2,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
/* include Grid[x][y] Top side output pins */
temp_opin_rr_node[1] = get_grid_side_pin_rr_nodes(&temp_num_opin_rr_nodes[1],
OPIN, sb_x, sb_y, 0,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
/* Grid[x][y+1] BOTTOM side outputs pins */
opin_grid_side[0] = BOTTOM;
/* Grid[x][y] TOP side outputs pins */
opin_grid_side[0] = TOP;
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d])Invalid side index!\n",
__FILE__, __LINE__);
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]);
}
}
/* Fill opin_rr_nodes */
/* Copy from temp_opin_rr_node to opin_rr_node */
for (int inode = 0; inode < temp_num_opin_rr_nodes[0]; ++inode) {
/* Grid[x+1][y+1] Bottom side outputs pins */
rr_switch_block.add_opin_node(temp_opin_rr_node[0][inode], side_manager.get_side(), opin_grid_side[0]);
}
for (int inode = 0; inode < temp_num_opin_rr_nodes[1]; ++inode) {
/* Grid[x+1][y] TOP side outputs pins */
rr_switch_block.add_opin_node(temp_opin_rr_node[1][inode], side_manager.get_side(), opin_grid_side[1]);
}
/* Clean ipin_rr_nodes */
/* We do not have any IPIN for a Switch Block */
rr_switch_block.clear_ipin_nodes(side_manager.get_side());
/* Free */
temp_num_opin_rr_nodes[0] = 0;
my_free(temp_opin_rr_node[0]);
temp_num_opin_rr_nodes[1] = 0;
my_free(temp_opin_rr_node[1]);
/* Set them to NULL, avoid double free errors */
temp_opin_rr_node[0] = NULL;
temp_opin_rr_node[1] = NULL;
opin_grid_side[0] = NUM_SIDES;
opin_grid_side[1] = NUM_SIDES;
}
return rr_switch_block;
}
/* Build a list of Switch blocks, each of which contains a collection of rr_nodes
* We will maintain a list of unique switch blocks, which will be outputted as a Verilog module
* 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(t_det_routing_arch RoutingArch,
int LL_num_rr_nodes,
t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices) {
/* Create an object */
DeviceRRSwitchBlock LL_device_rr_switch_block;
/* Initialize */
DeviceCoordinator device_coordinator(size_t(nx + 1), size_t(ny + 1));
LL_device_rr_switch_block.reserve(device_coordinator);
/* For each switch block, determine the size of array */
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, RoutingArch,
LL_num_rr_nodes, LL_rr_node, LL_rr_node_indices);
DeviceCoordinator sb_coordinator(ix, iy);
LL_device_rr_switch_block.add_rr_switch_block(sb_coordinator, rr_switch_block);
}
}
/* Report number of unique mirrors */
vpr_printf(TIO_MESSAGE_INFO,
"Detect %d independent switch blocks from %d switch blocks.\n",
LL_device_rr_switch_block.get_num_unique_mirror(), (nx + 1) * (ny + 1) );
return LL_device_rr_switch_block;
}
/* Rotatable will be done in the next step
void identify_rotatable_switch_blocks();

View File

@ -9,6 +9,16 @@ DeviceRRChan build_device_rr_chan(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);
/* Build a list of Switch blocks, each of which contains a collection of rr_nodes
* We will maintain a list of unique switch blocks, which will be outputted as a Verilog module
* 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(t_det_routing_arch RoutingArch,
int LL_num_rr_nodes,
t_rr_node* LL_rr_node,
t_ivec*** LL_rr_node_indices);
/* Rotatable will be done in the next step
identify_rotatable_switch_blocks();
identify_rotatable_connection_blocks();

View File

@ -1,10 +1,11 @@
#include <cassert>
#include <algorithm>
#include "rr_blocks.h"
/* Member Functions of Class RRChan */
/* accessors */
/* Accessors */
t_rr_type RRChan::get_type() const {
return type_;
}
@ -560,7 +561,133 @@ bool RRSwitchBlock::is_mirror(RRSwitchBlock& cand) const {
return true;
}
/* Internal functions */
/* Public mutators */
/* Allocate the vectors with the given number of sides */
void RRSwitchBlock::init_num_sides(size_t num_sides) {
/* Initialize the vectors */
chan_rr_node_direction_.resize(num_sides);
chan_rr_node_.resize(num_sides);
ipin_rr_node_.resize(num_sides);
ipin_rr_node_grid_side_.resize(num_sides);
opin_rr_node_.resize(num_sides);
opin_rr_node_grid_side_.resize(num_sides);
return;
}
/* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */
void RRSwitchBlock::add_chan_node(t_rr_node* node, enum e_side node_side, enum PORTS node_direction) {
Side side_manager(node_side);
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_rr_node_[side_manager.to_size_t()].size()) {
chan_rr_node_[side_manager.to_size_t()].resize(node->ptc_num + 1); /* resize to the maximum */
chan_rr_node_direction_[side_manager.to_size_t()].resize(node->ptc_num + 1); /* resize to the maximum */
}
/* fill the dedicated element in the vector */
chan_rr_node_[side_manager.to_size_t()][node->ptc_num] = node;
chan_rr_node_direction_[side_manager.to_size_t()][node->ptc_num] = node_direction;
return;
}
/* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */
void RRSwitchBlock::add_ipin_node(t_rr_node* node, enum e_side node_side, enum e_side grid_side) {
Side side_manager(node_side);
assert(validate_side(node_side));
/* push pack the dedicated element in the vector */
ipin_rr_node_[side_manager.to_size_t()].push_back(node);
ipin_rr_node_grid_side_[side_manager.to_size_t()].push_back(grid_side);
return;
}
/* Add a node to the chan_rr_node_ list and also assign its direction in chan_rr_node_direction_ */
void RRSwitchBlock::add_opin_node(t_rr_node* node, enum e_side node_side, enum e_side grid_side) {
Side side_manager(node_side);
assert(validate_side(node_side));
/* push pack the dedicated element in the vector */
opin_rr_node_[side_manager.to_size_t()].push_back(node);
opin_rr_node_grid_side_[side_manager.to_size_t()].push_back(grid_side);
return;
}
void RRSwitchBlock::set_num_reserved_conf_bits(size_t num_reserved_conf_bits) {
num_reserved_conf_bits_ = num_reserved_conf_bits;
return;
}
void RRSwitchBlock::set_num_conf_bits(size_t num_conf_bits) {
num_conf_bits_ = num_conf_bits;
return;
}
void RRSwitchBlock::clear() {
/* Clean all the vectors */
assert(validate_num_sides());
/* Clear the inner vector of each matrix */
for (size_t side = 0; side < get_num_sides(); ++side) {
chan_rr_node_direction_[side].clear();
chan_rr_node_[side].clear();
ipin_rr_node_[side].clear();
ipin_rr_node_grid_side_[side].clear();
opin_rr_node_[side].clear();
opin_rr_node_grid_side_[side].clear();
}
chan_rr_node_direction_.clear();
chan_rr_node_.clear();
ipin_rr_node_.clear();
ipin_rr_node_grid_side_.clear();
opin_rr_node_.clear();
opin_rr_node_grid_side_.clear();
set_num_reserved_conf_bits(0);
set_num_conf_bits(0);
return;
}
/* Clean the chan_width of a side */
void RRSwitchBlock::clear_chan_nodes(enum e_side node_side) {
Side side_manager(node_side);
assert(validate_side(node_side));
chan_rr_node_[side_manager.to_size_t()].clear();
chan_rr_node_direction_[side_manager.to_size_t()].clear();
return;
}
/* Clean the number of IPINs of a side */
void RRSwitchBlock::clear_ipin_nodes(enum e_side node_side) {
Side side_manager(node_side);
assert(validate_side(node_side));
ipin_rr_node_[side_manager.to_size_t()].clear();
ipin_rr_node_grid_side_[side_manager.to_size_t()].clear();
return;
}
/* Clean the number of OPINs of a side */
void RRSwitchBlock::clear_opin_nodes(enum e_side node_side) {
Side side_manager(node_side);
assert(validate_side(node_side));
opin_rr_node_[side_manager.to_size_t()].clear();
opin_rr_node_grid_side_[side_manager.to_size_t()].clear();
return;
}
/* Clean chan/opin/ipin nodes at one side */
void RRSwitchBlock::clear_one_side(enum e_side node_side) {
clear_chan_nodes(node_side);
clear_ipin_nodes(node_side);
clear_opin_nodes(node_side);
return;
}
/* Internal functions for validation */
/* check if two rr_nodes have a similar set of drive_rr_nodes
* for each drive_rr_node:
@ -665,3 +792,151 @@ bool RRSwitchBlock::validate_track_id(enum e_side side, size_t track_id) const {
return false;
}
/* Member Functions of Class RRChan */
/* Accessors */
/* get the max coordinator of the switch block array */
DeviceCoordinator DeviceRRSwitchBlock::get_switch_block_range() const {
size_t max_y = 0;
/* Get the largest size of sub-arrays */
for (size_t x = 0; x < rr_switch_block_.size(); ++x) {
max_y = std::max(max_y, rr_switch_block_[x].size());
}
DeviceCoordinator coordinator(rr_switch_block_.size(), max_y);
return coordinator;
}
/* Get a rr switch block in the array with a coordinator */
RRSwitchBlock DeviceRRSwitchBlock::get_switch_block(DeviceCoordinator coordinator) const {
assert(validate_coordinator(coordinator));
return rr_switch_block_[coordinator.get_x()][coordinator.get_y()];
}
/* Get a rr switch block in the array with a coordinator */
RRSwitchBlock DeviceRRSwitchBlock::get_switch_block(size_t x, size_t y) const {
DeviceCoordinator coordinator(x, y);
return get_switch_block(coordinator);
}
/* get the number of unique mirrors of switch blocks */
size_t DeviceRRSwitchBlock::get_num_unique_mirror() const {
return unique_mirror_.size();
}
/* get the number of rotatable mirrors of switch blocks */
size_t DeviceRRSwitchBlock::get_num_rotatable_mirror() const {
return rotatable_mirror_.size();
}
/* Get a rr switch block which a unique mirror */
RRSwitchBlock DeviceRRSwitchBlock::get_unique_mirror(size_t index) const {
assert (validate_unique_mirror_index(index));
return rr_switch_block_[unique_mirror_[index].get_x()][unique_mirror_[index].get_y()];
}
/* Get a rr switch block which a unique mirror */
RRSwitchBlock DeviceRRSwitchBlock::get_rotatable_mirror(size_t index) const {
assert (validate_rotatable_mirror_index(index));
return rr_switch_block_[rotatable_mirror_[index].get_x()][rotatable_mirror_[index].get_y()];
}
/* Public Mutators */
/* Pre-allocate the rr_switch_block array that the device requires */
void DeviceRRSwitchBlock::reserve(DeviceCoordinator& coordinator) {
rr_switch_block_.reserve(coordinator.get_x());
for (size_t x = 0; x < coordinator.get_x(); ++x) {
rr_switch_block_[x].reserve(coordinator.get_y());
}
return;
}
/* Resize rr_switch_block array is needed*/
void DeviceRRSwitchBlock::resize_upon_need(DeviceCoordinator& coordinator) {
if (coordinator.get_x() + 1 > rr_switch_block_.capacity()) {
rr_switch_block_.resize(coordinator.get_x());
}
if (coordinator.get_y() + 1 > rr_switch_block_[coordinator.get_x()].capacity()) {
rr_switch_block_[coordinator.get_x()].resize(coordinator.get_y());
}
return;
}
/* Add a switch block to the array, which will automatically identify and update the lists of unique mirrors and rotatable mirrors */
void DeviceRRSwitchBlock::add_rr_switch_block(DeviceCoordinator& coordinator,
RRSwitchBlock& rr_switch_block) {
bool is_unique_mirror = true;
/* Resize upon needs*/
resize_upon_need(coordinator);
/* Add the switch block into array */
rr_switch_block_[coordinator.get_x()][coordinator.get_y()] = rr_switch_block;
/* Traverse the unique_mirror list and check it is an mirror of another */
for (size_t mirror_id = 0; mirror_id < get_num_unique_mirror(); ++mirror_id) {
if (true == get_switch_block(unique_mirror_[mirror_id]).is_mirror(rr_switch_block)) {
/* This is a mirror, raise the flag and we finish */
is_unique_mirror = false;
break;
}
}
/* Add to list if this is a unique mirror*/
if (true == is_unique_mirror) {
unique_mirror_.push_back(coordinator);
}
/* TODO: add rotatable mirror support */
return;
}
/* clean the content */
void DeviceRRSwitchBlock::clear() {
/* clean rr_switch_block array */
for (size_t x = 0; x < rr_switch_block_.size(); ++x) {
rr_switch_block_[x].clear();
}
rr_switch_block_.clear();
/* clean unique mirror */
unique_mirror_.clear();
/* clean unique mirror */
rotatable_mirror_.clear();
return;
}
/* Validate if the (x,y) is the range of this device */
bool DeviceRRSwitchBlock::validate_coordinator(DeviceCoordinator& coordinator) const {
if (coordinator.get_x() >= rr_switch_block_.capacity()) {
return false;
}
if (coordinator.get_y() >= rr_switch_block_[coordinator.get_x()].capacity()) {
return false;
}
return true;
}
/* Validate if the index in the range of unique_mirror vector*/
bool DeviceRRSwitchBlock::validate_unique_mirror_index(size_t index) const {
if (index >= unique_mirror_.size()) {
return false;
}
return true;
}
/* Validate if the index in the range of unique_mirror vector*/
bool DeviceRRSwitchBlock::validate_rotatable_mirror_index(size_t index) const {
if (index >= rotatable_mirror_.size()) {
return false;
}
return true;
}

View File

@ -14,6 +14,7 @@
/* Standard header files required go first */
#include <vector>
#include "device_coordinator.h"
#include "vpr_types.h"
/* RRChan coordinator class */
@ -134,6 +135,18 @@ class RRSwitchBlock {
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 */
public: /* Mutators */
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_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);
void set_num_conf_bits(size_t num_conf_bits);
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 */
private: /* internal functions */
bool is_node_mirror (RRSwitchBlock& cand, enum e_side node_side, size_t track_id) const;
bool validate_num_sides() const;
@ -150,5 +163,38 @@ class RRSwitchBlock {
size_t num_conf_bits_;
};
/* Object Device Routing Resource Switch Block
* This includes:
* 1. a collection of RRSwitch blocks, each of which can be used to instance Switch blocks in the top-level netlists
* 2. a collection of unique mirrors of RRSwitchBlocks, which can be used to output Verilog / SPICE modules
* 3. a colleciton of unique rotatable of RRSwitchBlocks, which can be used to output Verilog / SPICE modules
* The rotatable RRSwitchBlocks are more generic mirrors, which allow SwitchBlocks to be wired by rotating the pins,
* further reduce the number of Verilog/SPICE modules outputted. This will lead to rapid layout generation
*/
class DeviceRRSwitchBlock {
public: /* Contructors */
public: /* Accessors */
DeviceCoordinator get_switch_block_range() const; /* get the max coordinator of the switch block array */
RRSwitchBlock get_switch_block(DeviceCoordinator coordinator) const; /* Get a rr switch block in the array with a coordinator */
RRSwitchBlock get_switch_block(size_t x, size_t y) const; /* Get a rr switch block in the array with a coordinator */
size_t get_num_unique_mirror() const; /* get the number of unique mirrors of switch blocks */
size_t get_num_rotatable_mirror() const; /* get the number of rotatable mirrors of switch blocks */
RRSwitchBlock get_unique_mirror(size_t index) const; /* Get a rr switch block which a unique mirror */
RRSwitchBlock get_rotatable_mirror(size_t index) const; /* Get a rr switch block which a unique mirror */
public: /* Mutators */
void reserve(DeviceCoordinator& coordinator); /* Pre-allocate the rr_switch_block array that the device requires */
void resize_upon_need(DeviceCoordinator& coordinator); /* Resize the rr_switch_block array if needed */
void add_rr_switch_block(DeviceCoordinator& coordinator, RRSwitchBlock& rr_switch_block); /* Add a switch block to the array, which will automatically identify and update the lists of unique mirrors and rotatable mirrors */
void clear(); /* clean the content */
private: /* Validators */
bool validate_coordinator(DeviceCoordinator& coordinator) const; /* Validate if the (x,y) is the range of this device */
bool validate_unique_mirror_index(size_t index) const; /* Validate if the index in the range of unique_mirror vector*/
bool validate_rotatable_mirror_index(size_t index) const; /* Validate if the index in the range of unique_mirror vector*/
private: /* Internal Data */
std::vector< std::vector<RRSwitchBlock> > rr_switch_block_;
std::vector<DeviceCoordinator> unique_mirror_;
std::vector<DeviceCoordinator> rotatable_mirror_;
};
#endif