Add Class for RRSwtichBlock and plug-in to replace the old t_sb

This commit is contained in:
tangxifan 2019-05-22 12:34:06 -06:00
parent b4c97f86a3
commit efbc454cdd
5 changed files with 497 additions and 14 deletions

View File

@ -13,7 +13,7 @@ project("libarchfpga")
#Collect the source files
file(GLOB_RECURSE EXEC_SOURCES SRC/main.c)
file(GLOB_RECURSE LIB_SOURCES SRC/*.c SRC/*/*.c)
file(GLOB_RECURSE LIB_SOURCES SRC/*.c SRC/*/*.c SRC/*.cpp SRC/*/*.cpp)
file(GLOB_RECURSE LIB_HEADERS SRC/*.h SRC/*/*.h)
files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS)

View File

@ -33,6 +33,7 @@
/* END */
/* SPICE model Support: Xifan TANG*/
#include "spice_types.h"
#include "sides.h"
/* END */
typedef struct s_clock_arch t_clock_arch;
@ -63,10 +64,11 @@ enum e_interconnect {
COMPLETE_INTERC = 1, DIRECT_INTERC = 2, MUX_INTERC = 3
};
/* Orientations. */
/* Orientations.
enum e_side {
TOP = 0, RIGHT = 1, BOTTOM = 2, LEFT = 3
};
*/
/* pin location distributions */
enum e_pin_location_distr {

View File

@ -0,0 +1,42 @@
#ifndef SIDES_H
#define SIDES_H
/* Define a class for the sides of a physical block in FPGA architecture
* Basically, each block has four sides :
* TOP, RIGHT, BOTTOM, LEFT
* This class aims to provide a easy proctol for manipulating a side
*/
#include <cstddef>
/* Orientations. */
enum e_side {
TOP = 0,
RIGHT = 1,
BOTTOM = 2,
LEFT = 3,
NUM_SIDES
};
class Side {
public: /* Constructor */
Side(enum e_side side);
Side();
Side(size_t side);
public: /* Accessors */
enum e_side get_side() const;
enum e_side get_opposite() const;
enum e_side get_rotate_clockwise() const;
enum e_side get_rotate_counterclockwise() const;
bool validate() const;
size_t to_size_t() const;
public: /* Mutators */
void set_side(size_t side);
void set_side(enum e_side side);
void set_opposite();
void rotate_clockwise();
void rotate_counterclockwise();
private: /* internal data */
enum e_side side_;
};
#endif

View File

@ -101,7 +101,7 @@ void RRChan::reserve_node(size_t node_size) {
/* add a node to the array */
void RRChan::add_node(t_rr_node* node, size_t node_segment) {
/* resize the array if needed, node is placed in the sequence of node->ptc_num */
if (node->ptc_num + 1 > nodes_.size()) {
if (size_t(node->ptc_num + 1) > nodes_.size()) {
nodes_.resize(node->ptc_num + 1); /* resize to the maximum */
node_segments_.resize(node->ptc_num + 1); /* resize to the maximum */
}
@ -146,9 +146,9 @@ RRChan DeviceRRChan::get_module(t_rr_type chan_type, size_t module_id) const {
if (CHANX == chan_type) {
return chanx_modules_[module_id];
} else if (CHANY == chan_type) {
return chany_modules_[module_id];
}
assert (CHANY == chan_type);
return chany_modules_[module_id];
}
RRChan DeviceRRChan::get_module_with_coordinator(t_rr_type chan_type, size_t x, size_t y) const {
@ -163,9 +163,9 @@ size_t DeviceRRChan::get_num_modules(t_rr_type chan_type) const {
if (CHANX == chan_type) {
return chanx_modules_.size();
} else if (CHANY == chan_type) {
return chany_modules_.size();
}
assert (CHANY == chan_type);
return chany_modules_.size();
}
size_t DeviceRRChan::get_module_id(t_rr_type chan_type, size_t x, size_t y) const {
@ -173,9 +173,9 @@ size_t DeviceRRChan::get_module_id(t_rr_type chan_type, size_t x, size_t y) cons
if (CHANX == chan_type) {
return chanx_module_ids_[x][y];
} else if (CHANY == chan_type) {
return chany_module_ids_[x][y];
}
assert (CHANY == chan_type);
return chany_module_ids_[x][y];
}
void DeviceRRChan::init_module_ids(size_t device_width, size_t device_height) {
@ -266,17 +266,17 @@ bool DeviceRRChan::valid_coordinator(t_rr_type chan_type, size_t x, size_t y) co
assert(valid_chan_type(chan_type));
if (CHANX == chan_type) {
if ( (0 > x) || (x > chanx_module_ids_.size() - 1 )) {
if (x > chanx_module_ids_.size() - 1 ) {
return false;
}
if ( (0 > y) || (y > chanx_module_ids_[x].size() - 1) ) {
if (y > chanx_module_ids_[x].size() - 1) {
return false;
}
} else if (CHANY == chan_type) {
if ( (0 > x) && (x > chany_module_ids_.size() - 1) ) {
if (x > chany_module_ids_.size() - 1) {
return false;
}
if ( (0 > y) && (y > chany_module_ids_[x].size() - 1) ) {
if (y > chany_module_ids_[x].size() - 1) {
return false;
}
}
@ -301,3 +301,367 @@ bool DeviceRRChan::valid_module_id(t_rr_type chan_type, size_t module_id) const
return false;
}
/* Member Functions of Class RRSwitchBlock*/
/* Accessors */
/* Get the number of sides of this SB */
size_t RRSwitchBlock::get_num_sides() const {
assert (validate_num_sides());
return chan_rr_node_direction_.size();
}
/* Get the number of routing tracks on a side */
size_t RRSwitchBlock::get_chan_width(enum e_side side) const {
Side side_manager(side);
assert(side_manager.validate());
return chan_rr_node_[side_manager.to_size_t()].size();
}
/* Get the direction of a rr_node at a given side and track_id */
enum PORTS RRSwitchBlock::get_chan_node_direction(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_rr_node_direction_[side_manager.to_size_t()][track_id];
}
/* get a rr_node at a given side and track_id */
t_rr_node* RRSwitchBlock::get_chan_node(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_rr_node_[side_manager.to_size_t()][track_id];
}
/* Get the number of IPIN rr_nodes on a side */
size_t RRSwitchBlock::get_num_ipin_rr_nodes(enum e_side side) const {
Side side_manager(side);
assert(side_manager.validate());
return ipin_rr_node_[side_manager.to_size_t()].size();
}
/* Get the number of OPIN rr_nodes on a side */
size_t RRSwitchBlock::get_num_opin_rr_nodes(enum e_side side) const {
Side side_manager(side);
assert(side_manager.validate());
return opin_rr_node_[side_manager.to_size_t()].size();
}
/* Get the node index in the array, return -1 if not found */
int RRSwitchBlock::get_node_index(t_rr_node* node,
enum e_side node_side,
enum PORTS node_direction) const {
size_t cnt;
int ret;
Side side_manager(node_side);
cnt = 0;
ret = -1;
/* Depending on the type of rr_node, we search different arrays */
switch (node->type) {
case CHANX:
case CHANY:
for (size_t inode = 0; inode < get_chan_width(node_side); ++inode) {
if ((node == chan_rr_node_[side_manager.to_size_t()][inode])
/* Check if direction meets specification */
&&(node_direction == chan_rr_node_direction_[side_manager.to_size_t()][inode])) {
cnt++;
ret = inode;
}
}
break;
case IPIN:
for (size_t inode = 0; inode < get_num_ipin_rr_nodes(node_side); ++inode) {
if (node == ipin_rr_node_[side_manager.to_size_t()][inode]) {
cnt++;
ret = inode;
}
}
break;
case OPIN:
for (size_t inode = 0; inode < get_num_opin_rr_nodes(node_side); ++inode) {
if (node == opin_rr_node_[side_manager.to_size_t()][inode]) {
cnt++;
ret = inode;
}
}
break;
default:
vpr_printf(TIO_MESSAGE_ERROR, "(File:%s, [LINE%d])Invalid cur_rr_node type! Should be [CHANX|CHANY|IPIN|OPIN]\n", __FILE__, __LINE__);
exit(1);
}
assert((0 == cnt)||(1 == cnt));
return ret; /* Return an invalid value: nonthing is found*/
}
/* Check if the node exist in the opposite side of this Switch Block */
bool RRSwitchBlock::is_node_exist_opposite_side(t_rr_node* node,
enum e_side node_side) const {
Side side_manager(node_side);
int index;
assert((CHANX == node->type) || (CHANY == node->type));
/* 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(node, side_manager.get_opposite(), IN_PORT);
if (-1 != index) {
return true;
}
return false;
}
/* Get the side of a node in this SB */
void RRSwitchBlock::get_node_side_and_index(t_rr_node* node,
enum PORTS node_direction,
enum e_side* node_side,
int* node_index) const {
size_t side;
Side 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(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;
assert(-1 == (*node_index));
return;
}
(*node_side) = side_manager.get_side();
assert(-1 != (*node_index));
return;
}
size_t RRSwitchBlock::get_num_reserved_conf_bits() const {
return num_reserved_conf_bits_;
}
size_t RRSwitchBlock::get_num_conf_bits() const {
return num_conf_bits_;
}
/* Check if the node imply a short connection inside the SB, which happens to long wires across a FPGA fabric */
bool RRSwitchBlock::is_node_imply_short_connection(t_rr_node* src_node) const {
assert((CHANX == src_node->type) || (CHANY == src_node->type));
for (size_t inode = 0; inode < size_t(src_node->num_drive_rr_nodes); ++inode) {
enum e_side side;
int index;
get_node_side_and_index(src_node->drive_rr_nodes[inode], IN_PORT, &side, &index);
/* We need to be sure that drive_rr_node is part of the SB */
if (((-1 == index) || (NUM_SIDES == side))
&& ((CHANX == src_node->drive_rr_nodes[inode]->type) || (CHANY == src_node->drive_rr_nodes[inode]->type))) {
return true;
}
}
return false;
}
/* 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 RRSwitchBlock::is_mirror(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;
}
for (size_t itrack = 0; itrack < get_chan_width(side_manager.get_side()); ++itrack) {
/* Check the directionality of each node */
if (get_chan_node_direction(side_manager.get_side(), itrack) != cand.get_chan_node_direction(side_manager.get_side(), itrack)) {
return false;
}
/* Check the track_id of each node */
if (get_chan_node(side_manager.get_side(), itrack)->ptc_num != cand.get_chan_node(side_manager.get_side(), itrack)->ptc_num) {
return false;
}
/* For OUT_PORT rr_node, we need to check fan-in */
if (OUT_PORT != get_chan_node_direction(side_manager.get_side(), itrack)) {
continue; /* skip IN_PORT */
}
if (false == is_node_mirror(cand, side_manager.get_side(), itrack)) {
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_ipin_rr_nodes(side_manager.get_side()) != cand.get_num_ipin_rr_nodes(side_manager.get_side())) {
return false;
}
}
/* Make sure the number of conf bits are the same */
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;
}
/* Internal functions */
/* 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 RRSwitchBlock::is_node_mirror(RRSwitchBlock& cand,
enum e_side node_side,
size_t track_id) const {
/* Ensure rr_nodes are either the output of short-connection or multiplexer */
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;
}
/* Find the driving rr_node in this sb */
if (true == is_short_conkt) {
/* Ensure we have the same track id for the driving nodes */
if ( this->is_node_exist_opposite_side(node, node_side)
!= cand.is_node_exist_opposite_side(cand_node, node_side)) {
return false;
}
} else { /* check driving rr_nodes */
if ( node->num_drive_rr_nodes != cand_node->num_drive_rr_nodes ) {
return false;
}
for (size_t inode = 0; inode < size_t(node->num_drive_rr_nodes); ++inode) {
/* node type should be the same */
if ( node->drive_rr_nodes[inode]->type
!= cand_node->drive_rr_nodes[inode]->type) {
return false;
}
/* switch type should be the same */
if ( node->drive_switches[inode]
!= cand_node->drive_switches[inode]) {
return false;
}
int src_node_id, des_node_id;
enum e_side src_node_side, des_node_side;
this->get_node_side_and_index(node->drive_rr_nodes[inode], OUT_PORT, &src_node_side, &src_node_id);
cand.get_node_side_and_index(cand_node->drive_rr_nodes[inode], 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;
}
/* Validate if the number of sides are consistent among internal data arrays ! */
bool RRSwitchBlock::validate_num_sides() const {
size_t num_sides = chan_rr_node_direction_.size();
if ( num_sides != chan_rr_node_.size() ) {
return false;
}
if ( num_sides != ipin_rr_node_.size() ) {
return false;
}
if ( num_sides != ipin_rr_node_grid_side_.size() ) {
return false;
}
if ( num_sides != opin_rr_node_.size() ) {
return false;
}
if ( num_sides != opin_rr_node_grid_side_.size() ) {
return false;
}
return true;
}
/* Check if the side valid in the context: does the switch block have the side? */
bool RRSwitchBlock::validate_side(enum e_side side) const {
Side side_manager(side);
if ( side_manager.to_size_t() < get_num_sides() ) {
return true;
}
return false;
}
/* Check the track_id is valid for chan_rr_node_ and chan_rr_node_direction_ */
bool RRSwitchBlock::validate_track_id(enum e_side side, size_t track_id) const {
Side side_manager(side);
if (false == validate_side(side)) {
return false;
}
if ( track_id < chan_rr_node_[side_manager.to_size_t()].size() ) {
return true;
}
return false;
}

View File

@ -18,7 +18,22 @@
/* RRChan coordinator class */
/* Object of a channel in a routing resource graph */
/* Object of a routing channel in a routing resource graph
* This is a collection of rr_nodes, which may be replaced with RRNodeId in new RRGraph
* Each routing channel is categorized in terms of directionality,
* being either X-direction or Y-direction
* ------------- ------
* | | | |
* | | | Y |
* | CLB | | Chan |
* | | | |
* | | | |
* ------------- ------
* -------------
* | X |
* | Channel |
* -------------
*/
class RRChan {
public: /* Accessors */
t_rr_type get_type() const;
@ -75,5 +90,65 @@ class DeviceRRChan {
std::vector<RRChan> chany_modules_; /* Detailed internal structure of each unique module */
};
/* Object Switch Block
* This is a collection of rr_nodes, which may be replaced with RRNodeId in new RRGraph
* TOP SIDE
* ---------------------------------
* | OPIN_NODE CHAN_NODES OPIN_NODES |
* | |
* | OPIN_NODES OPIN_NODES |
* | |
* LEFT SIDE | Switch Block | RIGHT SIDE
* | |
* | CHAN_NODES CHAN_NODES |
* | |
* | OPIN_NODES OPIN_NODES |
* | |
* | OPIN_NODE CHAN_NODES OPIN_NODES |
* ---------------------------------
* BOTTOM SIDE
* num_sides: number of sides of this switch block
* chan_rr_node: a collection of rr_nodes as routing tracks locating at each side of the Switch block <0..num_sides-1><0..chan_width-1>
* chan_rr_node_direction: Indicate if this rr_node is an input or an output of the Switch block <0..num_sides-1><0..chan_width-1>
* ipin_rr_node: a collection of rr_nodes as IPIN of a GRID locating at each side of the Switch block <0..num_sides-1><0..num_ipin_rr_nodes-1>
* ipin_rr_node_grid_side: specify the side of the input pins on which side of a GRID <0..num_sides-1><0..num_ipin_rr_nodes-1>
* opin_rr_node: a collection of rr_nodes as OPIN of a GRID locating at each side of the Switch block <0..num_sides-1><0..num_opin_rr_nodes-1>
* opin_rr_node_grid_side: specify the side of the output pins on which side of a GRID <0..num_sides-1><0..num_opin_rr_nodes-1>
* num_reserved_conf_bits: number of reserved configuration bits this switch block requires (mainly due to RRAM-based multiplexers)
* num_conf_bits: number of configuration bits this switch block requires
*/
class RRSwitchBlock {
public: /* Contructors */
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 */
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_num_ipin_rr_nodes(enum e_side side) const; /* Get the number of IPIN rr_nodes on a side */
size_t get_num_opin_rr_nodes(enum e_side side) const; /* Get the number of OPIN rr_nodes on a side */
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_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 */
size_t get_num_reserved_conf_bits() const;
size_t get_num_conf_bits() 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 */
public: /* 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;
bool validate_side(enum e_side side) const;
bool validate_track_id(enum e_side side, size_t track_id) const;
private: /* Internal Data */
std::vector< std::vector<enum PORTS> > chan_rr_node_direction_;
std::vector< std::vector<t_rr_node*> > chan_rr_node_;
std::vector< std::vector<t_rr_node*> > ipin_rr_node_;
std::vector< std::vector<enum e_side> > ipin_rr_node_grid_side_;
std::vector< std::vector<t_rr_node*> > opin_rr_node_;
std::vector< std::vector<enum e_side> > opin_rr_node_grid_side_;
size_t num_reserved_conf_bits_;
size_t num_conf_bits_;
};
#endif