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