#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; 
}