OpenFPGA/vpr7_x2p/vpr/SRC/route/rr_graph_swseg.c

705 lines
30 KiB
C

#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <string.h>
#include "util.h"
#include "vpr_types.h"
#include "globals.h"
#include "rr_graph_util.h"
#include "rr_graph.h"
#include "rr_graph2.h"
#include "rr_graph_sbox.h"
#include "check_rr_graph.h"
#include "rr_graph_timing_params.h"
#include "rr_graph_indexed_data.h"
#include "vpr_utils.h"
#include "read_xml_arch_file.h"
#include "ReadOptions.h"
#include "rr_graph_swseg.h"
/* Switch Segment Pattern Support
* Xifan TANG,
* EPFL-IC-ISIM-LSI
* July 2014
*/
enum ret_track_swseg_pattern {
RET_SWSEG_TRACK_DIR_UNMATCH,
RET_SWSEG_TRACK_NON_SEG_LEN_PATTERN,
RET_SWSEG_TRACK_APPLIED
};
/** Basic idea:
* Add unbuffered multiplexers(switches) to the length-n segments
* For example:
* clb clb clb clb
* sb ------sb-------sb--------sb--------sb
* BUF BUF BUF BUF BUF
* The above is a length-1 wire. All the multiplexers in thes segments are buffered.
* In this work, we adapt the segments to the following story:
* clb clb clb clb
* sb ------sb-------sb--------sb--------sb
* BUF UNBUF BUF UNBUF BUF
*
* This is called a pattern. The length of the pattern is 2.
* Of cource, we can generalize it to length-n wire and define a pattern
* Pattern: 0 1 1 1 0, Segment length: 1, Pattern length 5
* The results are as follows:
* clb clb clb clb
* sb ------sb-------sb--------sb--------sb
* BUF UNBUF UNBUF UNBUF BUF
*/
/** We check the routing tracks one by one to apply the pattern.
* Start from the source of coordinate systems
*/
/* The numbering relation between the channels and clbs is: *
* *
* | IO | chan_ | CLB | chan_ | CLB | *
* |grid[0][2] | y[0][2] |grid[1][2] | y[1][2] | grid[2][2]| *
* +-----------+ +-----------+ +-----------+ *
* } capacity in *
* No channel chan_x[1][1] chan_x[2][1] } chan_width *
* } _x[1] *
* +-----------+ +-----------+ +-----------+ *
* | | chan_ | | chan_ | | *
* | IO | y[0][1] | CLB | y[1][1] | CLB | *
* |grid[0][1] | |grid[1][1] | |grid[2][1] | *
* | | | | | | *
* +-----------+ +-----------+ +-----------+ *
* } capacity in *
* chan_x[1][0] chan_x[2][0] } chan_width *
* } _x[0] *
* +-----------+ +-----------+ *
* No | | No | | *
* Channel | IO | Channel | IO | *
* |grid[1][0] | |grid[2][0] | *
* | | | | *
* +-----------+ +-----------+ *
* *
* {=======} {=======} *
* Capacity in Capacity in *
* chan_width_y[0] chan_width_y[1] *
* */
/****************************************************************************
* =========chan_x [ix][iy]========= *
* || *---------------* || *
* || | | || *
* || | | || *
* chan_y | CLB | chan_y *
* [ix-1][iy] | [ix][iy] | [ix][iy] *
* || | | || *
* || | | || *
* || *---------------* || *
* ========chan_x [ix][iy-1]======== *
****************************************************************************
* Directionality *
* /|\ *
* | INC *
* | *
* <--------- ----------> *
* DEC | INC *
* | *
* | DEC *
* \|/ *
****************************************************************************
*/
/* We spot a routing track in channel (inx,iny). And start check its segment
* length. When we got the segment length, then apply the pattern to this routing track.
* And move on to the next.
* So, we would check the channels from [0][0] to [0][ny], [nx][0], [nx][ny]
*/
/*****Subroutine Declaration*****/
static
int init_chan_seg_detail_params(INP char* chan_type,
INP int curx,
INP int cury,
INP int nx, // Width of FPGA
INP int ny, // Height of FPGA
INP t_seg_details* seg_details_x,
INP t_seg_details* seg_details_y,
OUTP int* seg_num,
OUTP int* chan_num,
//OUTP short* direction,
OUTP t_seg_details* seg_details,
OUTP int* max_len);
static t_swseg_pattern_inf*
search_swseg_pattern_seg_len(INP int num_swseg_pattern,
INP t_swseg_pattern_inf* swseg_patterns,
INP int seg_len);
static enum ret_track_swseg_pattern
apply_swseg_pattern_chanx_track(INP int track_id,
INP int chanx_y,
INP int start_x,
INP int end_x,
INP int max_x,
INP int max_y,
INP short direction,
INP int num_swseg_pattern,
INP t_swseg_pattern_inf* swseg_patterns,
INP t_ivec*** L_rr_node_indices,
INP t_seg_details* seg_details_x,
INP t_seg_details* seg_details_y,
INP int* num_changed_chanx);
static enum ret_track_swseg_pattern
apply_swseg_pattern_chany_track(INP int track_id,
INP int chany_x,
INP int start_y,
INP int end_y,
INP int max_x,
INP int max_y,
INP short direction,
INP int num_swseg_pattern,
INP t_swseg_pattern_inf* swseg_patterns,
INP t_ivec*** L_rr_node_indices,
INP t_seg_details* seg_details_x,
INP t_seg_details* seg_details_y,
INP int* num_changed_chany);
static int swseg_pattern_change_switch_type(int inode,
t_rr_type chan_type,
t_swseg_pattern_inf swseg_pattern,
int* num_unbuf_mux);
/*Update the driver_switch of all rr_nodes*/
void update_rr_nodes_driver_switch(enum e_directionality directionality);
static boolean* rotate_shift_swseg_pattern(int pattern_length,
boolean* pattern,
int rotate_shift_length);
/*Start : The top function*/
int add_rr_graph_switch_segment_pattern(enum e_directionality directionality,
INP int nodes_per_chan,
INP int num_swseg_pattern,
INP t_swseg_pattern_inf* swseg_patterns,
INP t_ivec*** L_rr_node_indices,
INP t_seg_details* seg_details_x,
INP t_seg_details* seg_details_y) {
int ix, iy, itrack;
int num_changed_chanx, num_changed_chany;
t_seg_details* seg_details;
/*Initialization*/
seg_details = NULL;
num_changed_chanx = 0;
num_changed_chany = 0;
// Initialization
update_rr_nodes_driver_switch(directionality);
/* CHAN_X segments
* We start from chan_x [1...nx-1][0] to chan_x [1...nx-1][ny-1].
* They are the start points of routing tracks in CHANX
*/
/* Ensure we have channel width > 0*/
assert(nodes_per_chan > 0);
seg_details = seg_details_x;
for (iy = 0; iy < (ny + 1); iy++) {
/* Check each routing track in a channel*/
for (itrack = 0; itrack < nodes_per_chan; itrack++) {
if (INC_DIRECTION == seg_details[itrack].direction) {
apply_swseg_pattern_chanx_track(itrack, iy, 0, nx, nx, ny, INC_DIRECTION,
num_swseg_pattern, swseg_patterns, L_rr_node_indices, seg_details_x, seg_details_y,
&num_changed_chanx);
} else if (DEC_DIRECTION == seg_details[itrack].direction) {
apply_swseg_pattern_chanx_track(itrack, iy, nx, 0, nx, ny, DEC_DIRECTION,
num_swseg_pattern, swseg_patterns, L_rr_node_indices, seg_details_x, seg_details_y,
&num_changed_chanx);
}
} // Time to change another channel§
}
/* CHAN_Y segments
* We start from chan_y [0][1...ny-1] to chan_y [nx-1][1...ny-1].
* They are the start points of routing tracks in CHANX
*/
seg_details = seg_details_y;
for (ix = 0; ix < (nx + 1); ix++) {
/* Check each routing track in a channel*/
for (itrack = 0; itrack < nodes_per_chan; itrack++) {
if (INC_DIRECTION == seg_details[itrack].direction) {
apply_swseg_pattern_chany_track(itrack, ix, 0, ny, nx, ny, INC_DIRECTION,
num_swseg_pattern, swseg_patterns, L_rr_node_indices, seg_details_x, seg_details_y,
&num_changed_chany);
} else if (DEC_DIRECTION == seg_details[itrack].direction) {
apply_swseg_pattern_chany_track(itrack, ix, ny, 0, nx, ny, DEC_DIRECTION,
num_swseg_pattern, swseg_patterns, L_rr_node_indices, seg_details_x, seg_details_y,
&num_changed_chany);
}
} // Time to change another channel§
}
// Show Statistics
vpr_printf(TIO_MESSAGE_INFO,"Switch Segment Pattern applied to %d Channel X.\n",num_changed_chanx);
vpr_printf(TIO_MESSAGE_INFO,"Switch Segment Pattern applied to %d Channel Y.\n",num_changed_chany);
return 1; // Success
}
// This part copied from function: view_mux_size_distribution
/* Determine seg_num, chan_num, direction, seg_details, max_len
* according to the side of FPGA
*/
static int init_chan_seg_detail_params(INP char* chan_type,
INP int curx,
INP int cury,
INP int max_x, // Width of FPGA
INP int max_y, // Height of FPGA
INP t_seg_details* seg_details_x,
INP t_seg_details* seg_details_y,
OUTP int* seg_num,
OUTP int* chan_num,
//OUTP short* direction,
OUTP t_seg_details* seg_details,
OUTP int* max_len) {
/*Initialization*/
(*seg_num) = 0;
(*chan_num) = 0;
//(*direction) = 0;
seg_details = NULL;
(*max_len) = 0;
if (0 == strcmp(chan_type,"chanx_inc")) {
(*seg_num) = curx;
(*chan_num) = cury;
//(*direction) = INC_DIRECTION;
seg_details = seg_details_x;
(*max_len) = max_x;
} else if (0 == strcmp(chan_type,"chanx_dec")) {
(*seg_num) = curx;
(*chan_num) = cury;
//(*direction) = DEC_DIRECTION;
seg_details = seg_details_x;
(*max_len) = max_x;
} else if (0 == strcmp(chan_type,"chany_inc")) {
(*seg_num) = cury;
(*chan_num) = curx;
//(*direction) = INC_DIRECTION;
seg_details = seg_details_y;
(*max_len) = max_y;
} else if (0 == strcmp(chan_type,"chany_dec")) {
(*seg_num) = cury;
(*chan_num) = curx;
//(*direction) = DEC_DIRECTION;
seg_details = seg_details_y;
(*max_len) = max_y;
} else {
vpr_printf(TIO_MESSAGE_ERROR, "Input channel type: %s. Expect [chanx_inc|chanx_dec|chany_inc|chany_dec].\n",chan_type);
exit(1);
}
return 1;
}
/** Select a pattern according to the segment length.
* Return NULL if nothing found
*/
static
t_swseg_pattern_inf* search_swseg_pattern_seg_len(INP int num_swseg_pattern,
INP t_swseg_pattern_inf* swseg_patterns,
INP int seg_len) {
int ipattern;
t_swseg_pattern_inf* ret = NULL;
for (ipattern = 0; ipattern < num_swseg_pattern; ipattern++) {
if (seg_len == swseg_patterns[ipattern].seg_length) {
ret = &swseg_patterns[ipattern];
}
}
return ret;
}
/** Apply patterns to all the segments of a track in a chanx
*/
static enum ret_track_swseg_pattern
apply_swseg_pattern_chanx_track(INP int track_id,
INP int chanx_y,
INP int start_x,
INP int end_x,
INP int max_x,
INP int max_y,
INP short direction,
INP int num_swseg_pattern,
INP t_swseg_pattern_inf* swseg_patterns,
INP t_ivec*** L_rr_node_indices,
INP t_seg_details* seg_details_x,
INP t_seg_details* seg_details_y,
INP int* num_changed_chanx) {
int ix, start, end, seg_len;
int seg_num, chan_num, max_len, inode;
t_seg_details* seg_details;
t_swseg_pattern_inf* select_swseg_pattern;
int swseg_offset;
boolean* rotated_pattern;
/*Initialization*/
seg_len = 0;
seg_details = seg_details_x;
seg_num = 0;
chan_num = 0;
max_len = 0;
select_swseg_pattern = NULL;
swseg_offset = 0;
rotated_pattern = NULL;
/* Check directions and ranges*/
assert((INC_DIRECTION == direction)||(DEC_DIRECTION == direction));
if (INC_DIRECTION == direction) {
assert((!(start_x < 0))&&(!(end_x > max_x))&&(start_x < end_x));
} else {
assert((!(end_x < 0))&&(!(start_x > max_x))&&(start_x > end_x)&&(DEC_DIRECTION == direction));
}
// Check if the track direction matches
if (direction != seg_details[track_id].direction) {
return RET_SWSEG_TRACK_DIR_UNMATCH; // Direction does not match. Ignore the track
}
// Direction match, try to apply the Switch Segment Pattern
if (INC_DIRECTION == direction) {
for (ix = start_x; ix < (end_x + 1); ix++) {
init_chan_seg_detail_params("chanx_inc", ix, chanx_y, max_x, max_y, seg_details_x, seg_details_y, /* INPUT list */
&seg_num, &chan_num, seg_details, &max_len); /* OUTPUT list */
/* Get the start point and end point of the segment*/
start = get_seg_start(seg_details, track_id, chan_num, seg_num);
end = get_seg_end(seg_details, track_id, start, chan_num, max_len);
assert((start > 0)||(0 == start));
assert((end > 0)||(0 == end));
/* Get the segment length*/
seg_len = end - start + 1;
/* Search a pattern*/
select_swseg_pattern = search_swseg_pattern_seg_len(num_swseg_pattern, swseg_patterns, seg_len);
/* Nothing found, continue to the next track*/
if (NULL == select_swseg_pattern) {
return RET_SWSEG_TRACK_NON_SEG_LEN_PATTERN; // Do not need to apply any pattern
}
/* Rotate it*/
rotated_pattern = rotate_shift_swseg_pattern(select_swseg_pattern->pattern_length,select_swseg_pattern->patterns,chanx_y);
/* Check it the segment starts here*/
if ((start == seg_num)&&(direction == INC_DIRECTION)) {
/* Get the corresponding rr_node index of CHANX MUX*/
inode = get_rr_node_index(seg_num, chan_num, CHANX, track_id, L_rr_node_indices);
/* Check if we need to change the switch to a unbuffered one*/
if (TRUE == rotated_pattern[swseg_offset]) {
swseg_pattern_change_switch_type(inode,CHANX,(*select_swseg_pattern), num_changed_chanx);
}
/* Update the swseg_offset*/
swseg_offset++;
if ((swseg_offset > select_swseg_pattern->pattern_length)
||(swseg_offset == select_swseg_pattern->pattern_length)) {
swseg_offset = 0;
}
}
if ((rotated_pattern != NULL)&&(rotated_pattern != select_swseg_pattern->patterns)) {
free(rotated_pattern);
}
}
} else if (DEC_DIRECTION == direction) {
for (ix = start_x; ix > (end_x - 1); ix--) {
init_chan_seg_detail_params("chanx_dec", ix, chanx_y, max_x, max_y, seg_details_x, seg_details_y, /* INPUT list */
&seg_num, &chan_num, seg_details, &max_len); /* OUTPUT list */
/* Get the start point and end point of the segment*/
start = get_seg_start(seg_details, track_id, chan_num, seg_num);
end = get_seg_end(seg_details, track_id, start, chan_num, max_len);
assert((start > 0)||(0 == start));
assert((end > 0)||(0 == end));
/* Get the segment length*/
seg_len = end - start + 1;
/* Search a pattern*/
select_swseg_pattern = search_swseg_pattern_seg_len(num_swseg_pattern, swseg_patterns, seg_len);
/* Nothing found, continue to the next track*/
if (NULL == select_swseg_pattern) {
return RET_SWSEG_TRACK_NON_SEG_LEN_PATTERN; // Do not need to apply any pattern
}
/* Rotate it*/
rotated_pattern = rotate_shift_swseg_pattern(select_swseg_pattern->pattern_length,select_swseg_pattern->patterns,chanx_y);
/* Check it the segment starts here*/
if ((end == seg_num)&&(direction == DEC_DIRECTION)) {
/* Get the corresponding rr_node index of CHANX MUX*/
inode = get_rr_node_index(seg_num, chan_num, CHANX, track_id, L_rr_node_indices);
/* Check if we need to change the switch to a unbuffered one*/
if (TRUE == rotated_pattern[swseg_offset]) {
swseg_pattern_change_switch_type(inode,CHANX,(*select_swseg_pattern), num_changed_chanx);
}
/* Update the swseg_offset*/
swseg_offset++;
if ((swseg_offset > select_swseg_pattern->pattern_length)
||(swseg_offset == select_swseg_pattern->pattern_length)) {
swseg_offset = 0;
}
}
if ((rotated_pattern != NULL)&&(rotated_pattern != select_swseg_pattern->patterns)) {
free(rotated_pattern);
}
}
}
return RET_SWSEG_TRACK_APPLIED;
}
/** Apply patterns to all the segments of a track in a chany
*/
static enum ret_track_swseg_pattern
apply_swseg_pattern_chany_track(INP int track_id,
INP int chany_x,
INP int start_y,
INP int end_y,
INP int max_x,
INP int max_y,
INP short direction,
INP int num_swseg_pattern,
INP t_swseg_pattern_inf* swseg_patterns,
INP t_ivec*** L_rr_node_indices,
INP t_seg_details* seg_details_x,
INP t_seg_details* seg_details_y,
INP int* num_changed_chany) {
int iy, start, end, seg_len;
int seg_num, chan_num, max_len, inode;
t_seg_details* seg_details;
t_swseg_pattern_inf* select_swseg_pattern;
int swseg_offset;
boolean* rotated_pattern= NULL;
/*Initialization*/
seg_len = 0;
seg_details = seg_details_y;
seg_num = 0;
chan_num = 0;
max_len = 0;
select_swseg_pattern = NULL;
swseg_offset = 0;
/* Check directions and ranges*/
assert((INC_DIRECTION == direction)||(DEC_DIRECTION == direction));
if (INC_DIRECTION == direction) {
assert((!(start_y < 0))&&(!(end_y > max_y))&&(start_y < end_y));
} else {
assert((!(end_y < 0))&&(!(start_y > max_y))&&(start_y > end_y)&&(DEC_DIRECTION == direction));
}
// Check if the track direction matches
if (direction != seg_details[track_id].direction) {
return RET_SWSEG_TRACK_DIR_UNMATCH; // Direction does not match. Ignore the track
}
// Direction match, try to apply the Switch Segment Pattern
if (INC_DIRECTION == direction) {
for (iy = start_y; iy < (end_y + 1); iy++) {
init_chan_seg_detail_params("chany_inc", chany_x, iy, max_x, max_y, seg_details_x, seg_details_y, /* INPUT list */
&seg_num, &chan_num, seg_details, &max_len); /* OUTPUT list */
/* Get the start point and end point of the segment*/
start = get_seg_start(seg_details, track_id, chan_num, seg_num);
end = get_seg_end(seg_details, track_id, start, chan_num, max_len);
assert((start > 0)||(0 == start));
assert((end > 0)||(0 == end));
/* Get the segment length*/
seg_len = end - start + 1;
/* Search a pattern*/
select_swseg_pattern = search_swseg_pattern_seg_len(num_swseg_pattern, swseg_patterns, seg_len);
/* Nothing found, continue to the next track*/
if (NULL == select_swseg_pattern) {
return RET_SWSEG_TRACK_NON_SEG_LEN_PATTERN; // Do not need to apply any pattern
}
/* Rotate it*/
rotated_pattern = rotate_shift_swseg_pattern(select_swseg_pattern->pattern_length,select_swseg_pattern->patterns,chany_x);
/* Check it the segment starts here*/
if ((start == seg_num)&&(direction == INC_DIRECTION)) {
/* Get the corresponding rr_node index of CHANX MUX*/
inode = get_rr_node_index(chan_num, seg_num, CHANY, track_id, L_rr_node_indices);
/* Check if we need to change the switch to a unbuffered one*/
if (TRUE == rotated_pattern[swseg_offset]) {
swseg_pattern_change_switch_type(inode,CHANY,(*select_swseg_pattern), num_changed_chany);
}
/* Update the swseg_offset*/
swseg_offset++;
if ((swseg_offset > select_swseg_pattern->pattern_length)
||(swseg_offset == select_swseg_pattern->pattern_length)) {
swseg_offset = 0;
}
}
if ((rotated_pattern != NULL)&&(rotated_pattern != select_swseg_pattern->patterns)) {
free(rotated_pattern);
}
}
} else if (DEC_DIRECTION == direction) {
for (iy = start_y; iy > (end_y - 1); iy--) {
init_chan_seg_detail_params("chany_dec", chany_x, iy, max_x, max_y, seg_details_x, seg_details_y, /* INPUT list */
&seg_num, &chan_num, seg_details, &max_len); /* OUTPUT list */
/* Get the start point and end point of the segment*/
start = get_seg_start(seg_details, track_id, chan_num, seg_num);
end = get_seg_end(seg_details, track_id, start, chan_num, max_len);
assert((start > 0)||(0 == start));
assert((end > 0)||(0 == end));
/* Get the segment length*/
seg_len = end - start + 1;
/* Search a pattern*/
select_swseg_pattern = search_swseg_pattern_seg_len(num_swseg_pattern, swseg_patterns, seg_len);
/* Nothing found, continue to the next track*/
if (NULL == select_swseg_pattern) {
return RET_SWSEG_TRACK_NON_SEG_LEN_PATTERN; // Do not need to apply any pattern
}
/* Rotate it*/
rotated_pattern = rotate_shift_swseg_pattern(select_swseg_pattern->pattern_length,select_swseg_pattern->patterns,chany_x);
/* Check it the segment starts here*/
if ((end == seg_num)&&(direction == DEC_DIRECTION)) {
/* Get the corresponding rr_node index of CHANX MUX*/
inode = get_rr_node_index(chan_num, seg_num, CHANY, track_id, L_rr_node_indices);
/* Check if we need to change the switch to a unbuffered one*/
if (TRUE == rotated_pattern[swseg_offset]) {
swseg_pattern_change_switch_type(inode,CHANY,(*select_swseg_pattern), num_changed_chany);
}
/* Update the swseg_offset*/
swseg_offset++;
if ((swseg_offset > select_swseg_pattern->pattern_length)
||(swseg_offset == select_swseg_pattern->pattern_length)) {
swseg_offset = 0;
}
}
if ((rotated_pattern != NULL)&&(rotated_pattern != select_swseg_pattern->patterns)) {
free(rotated_pattern);
}
}
}
return RET_SWSEG_TRACK_APPLIED;
}
/* Change the type of switch to a unbuffered one*/
static
int swseg_pattern_change_switch_type(int cur_node,
t_rr_type chan_type,
t_swseg_pattern_inf swseg_pattern,
int* num_unbuf_mux) {
int iedge, jedge;
int inode, to_node;
assert((CHANX == chan_type)||(CHANY == chan_type));
/*Find the rr_node*/
assert(rr_node+cur_node);
for (iedge = 0; iedge < rr_node[cur_node].num_edges; iedge++) {
to_node = rr_node[cur_node].edges[iedge];
if (chan_type == rr_node[to_node].type) { // Only apply to the matched type
rr_node[cur_node].switches[iedge] = swseg_pattern.unbuf_switch;
// Define the driver switch for routing stats
rr_node[to_node].unbuf_switched = 1;
rr_node[to_node].driver_switch = rr_node[cur_node].switches[iedge];
(*num_unbuf_mux)++;
/* We should change the switches for other rr_nodes that drives this rr_node*/
for(inode = 0; inode < num_rr_nodes; inode++) {
for (jedge = 0; jedge < rr_node[inode].num_edges; jedge++) {
if (to_node == rr_node[inode].edges[jedge]) {
rr_node[inode].switches[jedge] = rr_node[to_node].driver_switch;
}
}
}
}
}
return 1;
}
void update_rr_nodes_driver_switch(enum e_directionality directionality) {
int inode, iedge;
t_rr_type inode_rr_type;
int to_node;
if (UNI_DIRECTIONAL != directionality) {
vpr_printf(TIO_MESSAGE_ERROR,"(File:%s,LINE[%d])Update_rr_nodes_driver_switch is only valid for uni-directional routing architecture.\n",
__FILE__, __LINE__);
exit(1);
}
/* Initial all the driver_switch to -1*/
for (inode = 0; inode < num_rr_nodes; inode++) {
rr_node[inode].driver_switch = -1;
}
for (inode = 0; inode < num_rr_nodes; inode++) {
inode_rr_type = rr_node[inode].type;
switch (inode_rr_type) {
// We care only switch boxes
case CHANX:
case CHANY:
for (iedge = 0; iedge < rr_node[inode].num_edges; iedge++) {
to_node = rr_node[inode].edges[iedge];
/* if to_node is a Channel, this is a switch box,
* if to_node is a IPIN, this is a connection box
*/
if ((CHANX == rr_node[to_node].type)
||(CHANY == rr_node[to_node].type)
||(IPIN == rr_node[to_node].type)) {
/* We should consider if driver_switch is the same or not*/
if (-1 == rr_node[to_node].driver_switch) {
rr_node[to_node].driver_switch = rr_node[inode].switches[iedge];
} else {
assert(rr_node[to_node].driver_switch == rr_node[inode].switches[iedge]);
}
}
}
break;
case OPIN:
for (iedge = 0; iedge < rr_node[inode].num_edges; iedge++) {
to_node = rr_node[inode].edges[iedge];
/* We care only to_node is a Channel
* Actually, in single driver routing, the switch is a delayless
* However, we have to update all switches
*/
if ((CHANX == rr_node[to_node].type)
||(CHANY == rr_node[to_node].type)) {
/* We should consider if driver_switch is the same or not*/
if (-1 == rr_node[to_node].driver_switch) {
rr_node[to_node].driver_switch = rr_node[inode].switches[iedge];
} else {
assert(rr_node[to_node].driver_switch == rr_node[inode].switches[iedge]);
}
}
}
break;
case IPIN:
/* This is a sink... There is no to_node*/
default:
break;
}
}
}
/* Rotate the switch segmentpattern
* Original: 1 0 0 , rotated_shift = 2, return: 0 0 1
*/
static
boolean* rotate_shift_swseg_pattern(int pattern_length,
boolean* pattern,
int rotate_shift_length) {
boolean* ret = NULL;
int shift_length;
/* There is no need to do anything if input is NULL*/
if ((pattern_length == 0)||(pattern_length < 0)) {
return NULL;
}
/* if rotate_shift_length exceeds the pattern lenght, we use mod */
shift_length = rotate_shift_length % pattern_length;
/* Direct return the pattern */
if (0 == shift_length) {
return pattern;
}
/*Alloc*/
ret = (boolean*)my_malloc(pattern_length*sizeof(boolean));
/* Initialization*/
memset(ret, 0, pattern_length*sizeof(boolean));
/*Rotate, rotated pattern: shifted part, orignal part*/
/* Step 1: fill the shifted part*/
memcpy(ret, pattern+pattern_length-shift_length, sizeof(boolean)*shift_length);
/* Step 2 : fill the rest*/
memcpy(ret+shift_length, pattern, sizeof(boolean)*(pattern_length-shift_length));
/* Return*/
return ret;
}