VPR-6.0

vpr/SRC/pack/cluster_legality.c

Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <assert.h>
00003 #include <string.h>
00004 
00005 #include "util.h"
00006 #include "physical_types.h"
00007 #include "vpr_types.h"
00008 #include "globals.h"
00009 #include "mst.h"
00010 #include "route_export.h"
00011 #include "route_common.h"
00012 #include "cluster_legality.h"
00013 #include "rr_graph.h"
00014 
00015 static struct s_linked_vptr *rr_mem_chunk_list_head = NULL;
00016 static int chunk_bytes_avail = 0;
00017 static char *chunk_next_avail_mem = NULL;
00018 static struct s_trace **best_routing; 
00019 
00020 /** nets_in_cluster: array of all nets contained in the cluster */
00021 static int *nets_in_cluster;    /**< [0..num_nets_in_cluster-1] */
00022 static int num_nets_in_cluster;
00023 static int curr_cluster_index;
00024 
00025 static int ext_input_rr_node_index, ext_output_rr_node_index, ext_clock_rr_node_index, max_ext_index;
00026 static int **saved_net_rr_terminals;
00027 static float pres_fac;
00028 static float *rr_intrinsic_cost;
00029 static int num_rr_intrinsic_cost = 0;
00030    
00031 
00032 /********************* Subroutines local to this module *********************/
00033 static boolean is_net_in_cluster(INP int inet);
00034 
00035 static boolean add_net_rr_terminal_cluster(int iblk_net, t_pb * primitive, int ilogical_block, t_model_ports * model_port, int ipin);
00036 
00037 static boolean reload_ext_net_rr_terminal_cluster();
00038 
00039 static boolean try_breadth_first_route_cluster();
00040 
00041 static boolean breadth_first_route_net_cluster(int inet);
00042 
00043 static void breadth_first_expand_trace_segment_cluster(struct s_trace *start_ptr,
00044                                                int remaining_connections_to_sink);
00045 
00046 static void breadth_first_expand_neighbours_cluster(int inode,
00047                                             float pcost,
00048                                             int inet,
00049                                                 boolean first_time);
00050 
00051 static void breadth_first_add_source_to_heap_cluster(int inet);
00052 
00053 static void alloc_net_rr_terminals_cluster();
00054 
00055 static void save_and_reset_routing_cluster();
00056 
00057 static void restore_routing_cluster();
00058 
00059 static int get_num_violated_nets();
00060 
00061 static void mark_ends_cluster(int inet);
00062 
00063 static void print_intra_cluster_route(char *route_file);
00064 
00065 static float rr_node_intrinsic_cost(int inode);
00066 
00067 
00068 /************************ Subroutine definitions ****************************/
00069 
00070 /** load rr_node for source and sinks of net if exists, return FALSE otherwise.
00071  * Todo: Note this is an inefficient way to determine port, better to use a lookup, worry about this if runtime becomes an issue 
00072  */
00073 static boolean is_net_in_cluster(INP int inet) {
00074         int i;
00075         for(i = 0; i < num_nets_in_cluster; i++) {
00076                 if(nets_in_cluster[i] == inet) {
00077                         return TRUE;
00078                 }
00079         }
00080         return FALSE;
00081 }
00082 
00083 /** Ensure at most one external input/clock source and one external output sink for net */
00084 static boolean add_net_rr_terminal_cluster(int iblk_net, t_pb * primitive, int ilogical_block, t_model_ports * model_port, int ipin) {
00085         int i, net_pin;
00086         t_port *prim_port;
00087         const t_pb_type *pb_type;
00088         boolean found;
00089 
00090         int input_port;
00091         int output_port;
00092         int clock_port;
00093 
00094         input_port = output_port = clock_port = 0;
00095 
00096         pb_type = primitive->pb_graph_node->pb_type;
00097         prim_port = NULL;
00098 
00099         assert(pb_type->num_modes == 0);
00100 
00101         found = FALSE;
00102         /* TODO: This is inelegant design, I should change the primitive ports in pb_type to be input, output, or clock instead of this lookup */
00103         for(i = 0; i < pb_type->num_ports && !found; i++) {
00104                 prim_port = &pb_type->ports[i];
00105                 if(pb_type->ports[i].model_port == model_port) {
00106                         found = TRUE;
00107                 } else {
00108                         if(prim_port->is_clock) {
00109                                 clock_port++;
00110                                 assert(prim_port->type == IN_PORT);
00111                         } else if(prim_port->type == IN_PORT) {
00112                                 input_port++;
00113                         } else if(prim_port->type == OUT_PORT) {
00114                                 output_port++;
00115                         } else {
00116                                 assert(0);
00117                         }
00118                 }
00119         }
00120         if(!found) {
00121                 return FALSE;
00122         }
00123 
00124         if(ipin >= prim_port->num_pins) {
00125                 return FALSE;
00126         } else {
00127                 net_pin = OPEN;
00128                 if(prim_port->is_clock) {
00129                         for(i = 1; i <= vpack_net[iblk_net].num_sinks; i++) {
00130                                 if(vpack_net[iblk_net].node_block[i] == ilogical_block &&
00131                                         vpack_net[iblk_net].node_block_port[i] == model_port->index &&
00132                                         vpack_net[iblk_net].node_block_pin[i] == ipin) {
00133                                         net_pin = i;
00134                                         break;
00135                                 }
00136                         }
00137                         assert(net_pin != OPEN);
00138                         net_rr_terminals[iblk_net][net_pin] = 
00139                                 primitive->pb_graph_node->clock_pins[clock_port][ipin].pin_count_in_cluster;
00140                 } else if(prim_port->type == IN_PORT) {
00141                         for(i = 1; i <= vpack_net[iblk_net].num_sinks; i++) {
00142                                 if(vpack_net[iblk_net].node_block[i] == ilogical_block &&
00143                                         vpack_net[iblk_net].node_block_port[i] == model_port->index &&
00144                                         vpack_net[iblk_net].node_block_pin[i] == ipin) {
00145                                         net_pin = i;
00146                                         break;
00147                                 }
00148                         }
00149                         assert(net_pin != OPEN);
00150                         net_rr_terminals[iblk_net][net_pin] = 
00151                                 primitive->pb_graph_node->input_pins[input_port][ipin].pin_count_in_cluster;
00152                 } else if(prim_port->type == OUT_PORT) {
00153                         i = 0;
00154                         if(vpack_net[iblk_net].node_block[i] == ilogical_block &&
00155                                 vpack_net[iblk_net].node_block_port[i] == model_port->index &&
00156                                 vpack_net[iblk_net].node_block_pin[i] == ipin) {
00157                                 net_pin = i;
00158                         }
00159                         assert(net_pin != OPEN);
00160                         net_rr_terminals[iblk_net][net_pin] = 
00161                                 primitive->pb_graph_node->output_pins[output_port][ipin].pin_count_in_cluster;
00162                 } else {
00163                         assert(0);
00164                 }
00165                 return TRUE;
00166         }       
00167 }
00168 
00169 static boolean reload_ext_net_rr_terminal_cluster() {
00170         int i, j, net_index;
00171         boolean has_ext_sink, has_ext_source;
00172         int curr_ext_output, curr_ext_input, curr_ext_clock;
00173 
00174         curr_ext_input = ext_input_rr_node_index;
00175         curr_ext_output = ext_output_rr_node_index;
00176         curr_ext_clock = ext_clock_rr_node_index;
00177 
00178         for(i = 0; i < num_nets_in_cluster; i++)
00179         {
00180                 net_index = nets_in_cluster[i];
00181                 has_ext_sink = FALSE;
00182                 has_ext_source = (logical_block[vpack_net[net_index].node_block[0]].clb_index != curr_cluster_index);
00183                 if(has_ext_source) {
00184                         /* Instantiate a source of this net */
00185                         if(vpack_net[net_index].is_global) {
00186                                 net_rr_terminals[net_index][0] = curr_ext_clock;
00187                                 curr_ext_clock++;
00188                         } else {
00189                                 net_rr_terminals[net_index][0] = curr_ext_input;
00190                                 curr_ext_input++;
00191                         }
00192                 }
00193                 for(j = 1; j <= vpack_net[net_index].num_sinks; j++) {
00194                         if(logical_block[vpack_net[net_index].node_block[j]].clb_index != curr_cluster_index) {
00195                                 if(has_ext_sink || has_ext_source) {
00196                                         /* Only need one node driving external routing, either this cluster drives external routing or another cluster does it */
00197                                         net_rr_terminals[net_index][j] = OPEN;
00198                                 } else {
00199                                         /* External sink, only need to route once, externally routing will take care of the rest */
00200                                         net_rr_terminals[net_index][j] = curr_ext_output;
00201                                         curr_ext_output++;
00202                                         has_ext_sink = TRUE;
00203                                 }
00204                         } 
00205                 }
00206 
00207                 if( curr_ext_input > ext_output_rr_node_index || 
00208                         curr_ext_output > ext_clock_rr_node_index ||
00209                         curr_ext_clock > max_ext_index) {
00210                         /* failed, not enough pins of proper type, overran index */
00211                         return FALSE;
00212                 }
00213         }
00214 
00215         return TRUE;
00216 }
00217 
00218 void alloc_and_load_cluster_legality_checker() {
00219         best_routing = (struct s_trace **)my_calloc(num_logical_nets, sizeof(struct s_trace *));
00220         nets_in_cluster = my_malloc(num_logical_nets * sizeof(int));
00221         num_nets_in_cluster = 0;
00222         num_nets = num_logical_nets;
00223 
00224         /* inside a cluster, I do not consider rr_indexed_data cost, set to 1 since other costs are multiplied by it */
00225         num_rr_indexed_data = 1;
00226         rr_indexed_data = my_calloc(1, sizeof(t_rr_indexed_data));
00227         rr_indexed_data[0].base_cost = 1;
00228 
00229         /* alloc routing structures */
00230         alloc_route_static_structs();
00231         alloc_net_rr_terminals_cluster();
00232 }
00233 
00234 
00235 void free_cluster_legality_checker() {
00236         int inet;
00237         free(rr_indexed_data);
00238         free_rr_node_route_structs();
00239         free_route_structs(NULL);
00240         free_trace_structs();
00241 
00242         free_chunk_memory(rr_mem_chunk_list_head);
00243         rr_mem_chunk_list_head = NULL;
00244 
00245     for(inet = 0; inet < num_logical_nets; inet++)
00246         {
00247             free(saved_net_rr_terminals[inet]);
00248         }
00249         free(net_rr_terminals);
00250         free(saved_net_rr_terminals);
00251 }
00252 
00253 
00254 void alloc_and_load_rr_graph_for_pb_graph_node(INP t_pb_graph_node *pb_graph_node, INP const t_arch* arch, int mode) {
00255 
00256         int i, j, k, index;
00257         boolean is_primitive;
00258 
00259         is_primitive = (pb_graph_node->pb_type->num_modes == 0);
00260 
00261         for(i = 0; i < pb_graph_node->num_input_ports; i++) {
00262                 for(j = 0; j < pb_graph_node->num_input_pins[i]; j++) {
00263                         index = pb_graph_node->input_pins[i][j].pin_count_in_cluster;
00264                         rr_node[index].pb_graph_pin = &pb_graph_node->input_pins[i][j];
00265                         rr_node[index].fan_in = pb_graph_node->input_pins[i][j].num_input_edges;
00266                         rr_node[index].num_edges = pb_graph_node->input_pins[i][j].num_output_edges;
00267                         rr_node[index].pack_intrinsic_cost = 1 + (float)rr_node[index].num_edges / 5; /* need to normalize better than 5 */
00268                         rr_node[index].edges = my_malloc(rr_node[index].num_edges * sizeof(int));
00269                         rr_node[index].switches = my_calloc(rr_node[index].num_edges, sizeof(int));
00270                         rr_node[index].net_num = OPEN;
00271                         rr_node[index].prev_node = OPEN;
00272                         rr_node[index].prev_edge = OPEN;
00273                         if(mode == 0) { /* default mode is the first mode */
00274                                 rr_node[index].capacity = 1;
00275                         } else {
00276                                 rr_node[index].capacity = 0;
00277                         }
00278                         for(k = 0; k < pb_graph_node->input_pins[i][j].num_output_edges; k++) {
00279                                 /* TODO: Intention was to do bus-based implementation here */
00280                                 rr_node[index].edges[k] = pb_graph_node->input_pins[i][j].output_edges[k]->output_pins[0]->pin_count_in_cluster;
00281                                 rr_node[index].switches[k] = arch->num_switches - 1; /* last switch in arch switch properties is a delayless switch */
00282                                 assert(pb_graph_node->input_pins[i][j].output_edges[k]->num_output_pins == 1);
00283                         }
00284                         rr_node[index].type = INTRA_CLUSTER_EDGE;
00285                         if(is_primitive) {
00286                                 rr_node[index].type = SINK;
00287                         }
00288                 }
00289         }
00290 
00291         for(i = 0; i < pb_graph_node->num_output_ports; i++) {
00292                 for(j = 0; j < pb_graph_node->num_output_pins[i]; j++) {
00293                         index = pb_graph_node->output_pins[i][j].pin_count_in_cluster;
00294                         rr_node[index].pb_graph_pin = &pb_graph_node->output_pins[i][j];
00295                         rr_node[index].fan_in = pb_graph_node->output_pins[i][j].num_input_edges;
00296                         rr_node[index].num_edges = pb_graph_node->output_pins[i][j].num_output_edges;
00297                         rr_node[index].pack_intrinsic_cost = 1 + (float)rr_node[index].num_edges / 5; /* need to normalize better than 5 */
00298                         rr_node[index].edges = my_malloc(rr_node[index].num_edges * sizeof(int));
00299                         rr_node[index].switches = my_calloc(rr_node[index].num_edges, sizeof(int));
00300                         rr_node[index].net_num = OPEN;
00301                         rr_node[index].prev_node = OPEN;
00302                         rr_node[index].prev_edge = OPEN;
00303                         if(mode == 0) { /* Default mode is the first mode */
00304                                 rr_node[index].capacity = 1;
00305                         } else {
00306                                 rr_node[index].capacity = 0;
00307                         }
00308                         for(k = 0; k < pb_graph_node->output_pins[i][j].num_output_edges; k++) {
00309                                 /* TODO: Intention was to do bus-based implementation here */
00310                                 rr_node[index].edges[k] = pb_graph_node->output_pins[i][j].output_edges[k]->output_pins[0]->pin_count_in_cluster;
00311                                 rr_node[index].switches[k] = arch->num_switches - 1;
00312                                 assert(pb_graph_node->output_pins[i][j].output_edges[k]->num_output_pins == 1);
00313                         }
00314                         rr_node[index].type = INTRA_CLUSTER_EDGE;
00315                         if(is_primitive) {
00316                                 rr_node[index].type = SOURCE;
00317                         }
00318                 }
00319         }
00320 
00321         for(i = 0; i < pb_graph_node->num_clock_ports; i++) {
00322                 for(j = 0; j < pb_graph_node->num_clock_pins[i]; j++) {
00323                         index = pb_graph_node->clock_pins[i][j].pin_count_in_cluster;
00324                         rr_node[index].pb_graph_pin = &pb_graph_node->clock_pins[i][j];
00325                         rr_node[index].fan_in = pb_graph_node->clock_pins[i][j].num_input_edges;
00326                         rr_node[index].num_edges = pb_graph_node->clock_pins[i][j].num_output_edges;
00327                         rr_node[index].pack_intrinsic_cost = 1 + (float)rr_node[index].num_edges / 5; /* need to normalize better than 5 */
00328                         rr_node[index].edges = my_malloc(rr_node[index].num_edges * sizeof(int));
00329                         rr_node[index].switches = my_calloc(rr_node[index].num_edges, sizeof(int));
00330                         rr_node[index].net_num = OPEN;
00331                         rr_node[index].prev_node = OPEN;
00332                         rr_node[index].prev_edge = OPEN;
00333                         if(mode == 0) { /* default mode is the first mode (useful for routing */
00334                                 rr_node[index].capacity = 1;
00335                         } else {
00336                                 rr_node[index].capacity = 0;
00337                         }
00338                         for(k = 0; k < pb_graph_node->clock_pins[i][j].num_output_edges; k++) {
00339                                 /* TODO: Intention was to do bus-based implementation here */
00340                                 rr_node[index].edges[k] = pb_graph_node->clock_pins[i][j].output_edges[k]->output_pins[0]->pin_count_in_cluster;
00341                                 rr_node[index].switches[k] = arch->num_switches - 1;
00342                                 assert(pb_graph_node->clock_pins[i][j].output_edges[k]->num_output_pins == 1);
00343                         }
00344                         rr_node[index].type = INTRA_CLUSTER_EDGE;
00345                         if(is_primitive) {
00346                                 rr_node[index].type = SINK;
00347                         }
00348                 }
00349         }
00350 
00351         for(i = 0; i < pb_graph_node->pb_type->num_modes; i++) {
00352                 for(j = 0; j < pb_graph_node->pb_type->modes[i].num_pb_type_children; j++) {
00353                         for(k = 0; k < pb_graph_node->pb_type->modes[i].pb_type_children[j].num_pb; k++) {
00354                                 alloc_and_load_rr_graph_for_pb_graph_node(&pb_graph_node->child_pb_graph_nodes[i][j][k], arch, i);
00355                         }
00356                 }
00357         }
00358 
00359 }
00360 
00361 
00362 /**
00363  * Structure: Model external routing and internal routing
00364  * 
00365  * 1.  Model external routing
00366  *   num input pins == num external sources for input pins, fully connect them to input pins (simulates external routing)
00367  *   num output pins == num external sinks for output pins, fully connect them to output pins (simulates external routing)
00368  *   num clock pins == num external sources for clock pins, fully connect them to clock pins (simulates external routing)
00369  * 2.  Model internal routing
00370  * 
00371  */
00372 void alloc_and_load_legalizer_for_cluster(INP t_block* clb, INP int clb_index, INP const t_arch *arch) {
00373     /* make each rr_node one correspond with pin and correspond with pin's index pin_count_in_cluster */
00374     int i, j, k, m, index, pb_graph_rr_index;
00375         int count_pins;
00376         t_pb_type * pb_type;
00377         t_pb_graph_node *pb_graph_node;
00378         int ipin;
00379 
00380         /* Create rr_graph */
00381         pb_type = clb->type->pb_type;
00382         pb_graph_node = clb->type->pb_graph_head;
00383         num_rr_nodes = pb_graph_node->total_pb_pins + pb_type->num_input_pins + 
00384                                         pb_type->num_output_pins + pb_type->num_clock_pins;
00385         if(num_rr_nodes > num_rr_intrinsic_cost) {
00386                 free(rr_intrinsic_cost);
00387                 rr_intrinsic_cost = my_calloc(num_rr_nodes, sizeof(float));
00388                 num_rr_intrinsic_cost = num_rr_nodes;
00389         }
00390         rr_node = my_calloc(num_rr_nodes, sizeof(t_rr_node));
00391         clb->pb->rr_graph = rr_node;
00392         
00393         alloc_and_load_rr_graph_for_pb_graph_node(pb_graph_node, arch, 0);
00394 
00395         curr_cluster_index = clb_index;
00396 
00397         /*   Alloc and load rr_graph external sources and sinks */
00398         ext_input_rr_node_index = pb_graph_node->total_pb_pins;
00399         ext_output_rr_node_index = pb_type->num_input_pins + pb_graph_node->total_pb_pins;
00400         ext_clock_rr_node_index = pb_type->num_input_pins + pb_type->num_output_pins + pb_graph_node->total_pb_pins;
00401         max_ext_index = pb_type->num_input_pins + pb_type->num_output_pins + pb_type->num_clock_pins + pb_graph_node->total_pb_pins;
00402         
00403         for(i = 0; i < pb_type->num_input_pins; i++) {
00404                 index = i + pb_graph_node->total_pb_pins;
00405                 rr_node[index].type = SOURCE;
00406                 rr_node[index].fan_in = 0;
00407                 rr_node[index].num_edges = pb_type->num_input_pins;
00408                 rr_node[index].pack_intrinsic_cost = 1 + (float)rr_node[index].num_edges / 5; /* need to normalize better than 5 */
00409                 rr_node[index].edges = my_malloc(rr_node[index].num_edges * sizeof(int));
00410                 rr_node[index].switches = my_calloc(rr_node[index].num_edges, sizeof(int));
00411                 rr_node[index].capacity = 1;
00412                 rr_intrinsic_cost[index] = 0;
00413         }
00414 
00415         for(i = 0; i < pb_type->num_output_pins; i++) {
00416                 index = i + pb_type->num_input_pins + pb_graph_node->total_pb_pins;
00417                 rr_node[index].type = SINK;
00418                 rr_node[index].fan_in = pb_type->num_output_pins;
00419                 rr_node[index].num_edges = 0;
00420                 rr_node[index].pack_intrinsic_cost = 1 + (float)rr_node[index].num_edges / 5; /* need to normalize better than 5 */
00421                 rr_node[index].capacity = 1;
00422                 rr_intrinsic_cost[index] = 0;
00423         }
00424 
00425         for(i = 0; i < pb_type->num_clock_pins; i++) {
00426                 index = i + pb_type->num_input_pins + pb_type->num_output_pins + pb_graph_node->total_pb_pins;
00427                 rr_node[index].type = SOURCE;
00428                 rr_node[index].fan_in = 0;
00429                 rr_node[index].num_edges = pb_type->num_clock_pins;
00430                 rr_node[index].pack_intrinsic_cost = 1 + (float)rr_node[index].num_edges / 5; /* need to normalize better than 5 */
00431                 rr_node[index].edges = my_malloc(rr_node[index].num_edges * sizeof(int));
00432                 rr_node[index].switches = my_calloc(rr_node[index].num_edges, sizeof(int));
00433                 rr_node[index].capacity = 1;
00434                 rr_intrinsic_cost[index] = 0;
00435         }
00436 
00437         ipin = 0;
00438         for(i = 0; i < pb_graph_node->num_input_ports; i++) {
00439                 for(j = 0; j < pb_graph_node->num_input_pins[i]; j++) {
00440                         pb_graph_rr_index = pb_graph_node->input_pins[i][j].pin_count_in_cluster;
00441                         for(k = 0; k < pb_type->num_input_pins; k++) {
00442                                 index = k + pb_graph_node->total_pb_pins;
00443                                 rr_node[index].edges[ipin] = pb_graph_rr_index; 
00444                                 rr_node[index].switches[ipin] = arch->num_switches - 1;
00445                         }
00446                         rr_node[pb_graph_rr_index].pack_intrinsic_cost = MAX_SHORT; /* using an input pin should be made costly */
00447                         ipin++;
00448                 }
00449         }
00450 
00451         /* Must attach output pins to input pins because if a connection cannot fit using intra-cluster routing, it can also use external routing */
00452         for(i = 0; i < pb_graph_node->num_output_ports; i++) {
00453                 for(j = 0; j < pb_graph_node->num_output_pins[i]; j++) {
00454                         count_pins = pb_graph_node->output_pins[i][j].num_output_edges + pb_type->num_output_pins + pb_type->num_input_pins;
00455                         pb_graph_rr_index = pb_graph_node->output_pins[i][j].pin_count_in_cluster;
00456                         rr_node[pb_graph_rr_index].edges = my_realloc(rr_node[pb_graph_rr_index].edges,
00457                                 (count_pins) * sizeof(int));
00458                         rr_node[pb_graph_rr_index].switches = my_realloc(rr_node[pb_graph_rr_index].switches,
00459                                 (count_pins) * sizeof(int));
00460 
00461                         ipin = 0;
00462                         for(k = 0; k < pb_graph_node->num_input_ports; k++) {
00463                                 for(m = 0; m < pb_graph_node->num_input_pins[k]; m++) {
00464                                         index = pb_graph_node->input_pins[k][m].pin_count_in_cluster;
00465                                         rr_node[pb_graph_rr_index].edges[ipin + pb_graph_node->output_pins[i][j].num_output_edges] = index;
00466                                         rr_node[pb_graph_rr_index].switches[ipin + pb_graph_node->output_pins[i][j].num_output_edges] = arch->num_switches - 1;
00467                                         ipin++;
00468                                 }
00469                         }
00470                         for(k = 0; k < pb_type->num_output_pins; k++) {
00471                                 index = k + pb_type->num_input_pins + pb_graph_node->total_pb_pins;
00472                                 rr_node[pb_graph_rr_index].edges[k + pb_type->num_input_pins + pb_graph_node->output_pins[i][j].num_output_edges] = index;
00473                                 rr_node[pb_graph_rr_index].switches[k + pb_type->num_input_pins + pb_graph_node->output_pins[i][j].num_output_edges] = arch->num_switches - 1;
00474                         }
00475                         rr_node[pb_graph_rr_index].num_edges += pb_type->num_output_pins + pb_type->num_input_pins;
00476                         rr_node[pb_graph_rr_index].pack_intrinsic_cost = 1 + (float)rr_node[pb_graph_rr_index].num_edges / 5; /* need to normalize better than 5 */
00477                 }
00478         }
00479 
00480         ipin = 0;
00481         for(i = 0; i < pb_graph_node->num_clock_ports; i++) {
00482                 for(j = 0; j < pb_graph_node->num_clock_pins[i]; j++) {
00483                         for(k = 0; k < pb_type->num_clock_pins; k++) {
00484                                 index = k + pb_type->num_input_pins + pb_type->num_output_pins + pb_graph_node->total_pb_pins;
00485                                 pb_graph_rr_index = pb_graph_node->clock_pins[i][j].pin_count_in_cluster;
00486                                 rr_node[index].edges[ipin] = pb_graph_rr_index; 
00487                                 rr_node[index].switches[ipin] = arch->num_switches - 1;
00488                         }
00489                         ipin++;
00490                 }
00491         }
00492 
00493         alloc_and_load_rr_node_route_structs();
00494         num_nets_in_cluster = 0;
00495 
00496 }
00497 
00498 
00499 
00500 void free_legalizer_for_cluster(INP t_block* clb) {
00501         int i;
00502 
00503         free_rr_node_route_structs();
00504         for(i = 0; i < num_rr_nodes; i++) {
00505                 if(clb->pb->rr_graph[i].edges != NULL) {
00506                         free(clb->pb->rr_graph[i].edges);
00507                 }
00508                 if(clb->pb->rr_graph[i].switches != NULL) {
00509                         free(clb->pb->rr_graph[i].switches);
00510                 }
00511         }
00512         free(clb->pb->rr_graph);
00513 }
00514 
00515 void reset_legalizer_for_cluster(t_block *clb) {
00516         int i;
00517         for(i = 0; i < num_nets_in_cluster; i++) {
00518                 free_traceback(nets_in_cluster[i]);
00519                 trace_head[nets_in_cluster[i]] = best_routing[nets_in_cluster[i]];
00520                 free_traceback(nets_in_cluster[i]);             
00521                 best_routing[nets_in_cluster[i]] = NULL;
00522         }
00523 
00524         free_rr_node_route_structs();
00525         num_nets_in_cluster = 0;
00526 }
00527 
00528 
00529 /** 
00530  * 
00531  * internal_nets: index of nets to route [0..num_internal_nets - 1]
00532  */
00533 /** Iterated maze router ala Pathfinder Negotiated Congestion algorithm,  
00534  * (FPGA 95 p. 111).  Returns TRUE if it can route this FPGA, FALSE if   
00535  * it can't.                                                             
00536  */
00537 static boolean try_breadth_first_route_cluster()
00538 {
00539 
00540  /* For different modes, when a mode is turned on, I set the max occupancy of all rr_nodes in the mode to 1 and all others to 0 */
00541         /* TODO: There is a bug for route-throughs where edges in route-throughs do not get turned off because the rr_edge is in a particular mode but the two rr_nodes are outside */
00542 
00543     boolean success, is_routable;
00544     int itry, inet, net_index;
00545         struct s_router_opts router_opts;
00546 
00547         
00548 /* Usually the first iteration uses a very small (or 0) pres_fac to find  *
00549  * the shortest path and get a congestion map.  For fast compiles, I set  *
00550  * pres_fac high even for the first iteration.                            */
00551 
00552         /* sets up a fast breadth-first router */
00553     router_opts.first_iter_pres_fac = 10;
00554         router_opts.max_router_iterations = 20;
00555         router_opts.initial_pres_fac = 10;
00556         router_opts.pres_fac_mult = 2;
00557         router_opts.acc_fac = 1;
00558 
00559     pres_fac = router_opts.first_iter_pres_fac;
00560 
00561     for(itry = 1; itry <= router_opts.max_router_iterations; itry++)
00562         {
00563             for(inet = 0; inet < num_nets_in_cluster; inet++)
00564                 {
00565                         net_index = nets_in_cluster[inet];
00566 
00567                     pathfinder_update_one_cost(trace_head[net_index], -1,
00568                                                pres_fac);
00569 
00570                     is_routable =
00571                         breadth_first_route_net_cluster(net_index);
00572 
00573                     /* Impossible to route? (disconnected rr_graph) */
00574 
00575                     if(!is_routable)
00576                         {
00577                                 /* TODO: Inelegant, can be more intelligent */
00578                                 printf("Failed routing net %s\n", vpack_net[net_index].name);
00579                             printf("Routing failed. Disconnected rr_graph\n");
00580                             return FALSE; 
00581                         }
00582 
00583                     pathfinder_update_one_cost(trace_head[net_index], 1,
00584                                                pres_fac);
00585 
00586                 }
00587 
00588 
00589             success = feasible_routing();
00590             if(success)
00591                 {
00592                     return (TRUE);
00593                 }
00594 
00595             if(itry == 1)
00596                         pres_fac = router_opts.initial_pres_fac;
00597             else
00598                         pres_fac *= router_opts.pres_fac_mult;
00599 
00600                 pres_fac = min (pres_fac, HUGE_FLOAT / 1e5);
00601 
00602             pathfinder_update_cost(pres_fac, router_opts.acc_fac);
00603         }
00604 
00605         return (FALSE);
00606 }
00607 
00608 
00609 /** Uses a maze routing (Dijkstra's) algorithm to route a net.  The net       
00610  * begins at the net output, and expands outward until it hits a target      
00611  * pin.  The algorithm is then restarted with the entire first wire segment  
00612  * included as part of the source this time.  For an n-pin net, the maze     
00613  * router is invoked n-1 times to complete all the connections.  Inet is     
00614  * the index of the net to be routed.                                
00615  * If this routine finds that a net *cannot* be connected (due to a complete 
00616  * lack of potential paths, rather than congestion), it returns FALSE, as    
00617  * routing is impossible on this architecture.  Otherwise it returns TRUE.   
00618  */
00619 static boolean
00620 breadth_first_route_net_cluster(int inet)
00621 {
00622     int i, inode, prev_node, remaining_connections_to_sink;
00623     float pcost, new_pcost;
00624     struct s_heap *current;
00625     struct s_trace *tptr;
00626         boolean first_time;
00627 
00628     free_traceback(inet);
00629     breadth_first_add_source_to_heap_cluster(inet);
00630     mark_ends_cluster(inet);
00631 
00632     tptr = NULL;
00633     remaining_connections_to_sink = 0;
00634 
00635     for(i = 1; i <= vpack_net[inet].num_sinks; i++)
00636         {                       /* Need n-1 wires to connect n pins */
00637 
00638                 /* Do not connect open terminals */
00639                 if(net_rr_terminals[inet][i] == OPEN)
00640                         continue;
00641                 /* Expand and begin routing */
00642             breadth_first_expand_trace_segment_cluster(tptr,
00643                                                remaining_connections_to_sink);
00644             current = get_heap_head();
00645 
00646             if(current == NULL)
00647                 {               /* Infeasible routing.  No possible path for net. */
00648                     reset_path_costs(); /* Clean up before leaving. */
00649                     return (FALSE);
00650                 }
00651 
00652             inode = current->index;
00653 
00654             while(rr_node_route_inf[inode].target_flag == 0)
00655                 {
00656                     pcost = rr_node_route_inf[inode].path_cost;
00657                     new_pcost = current->cost;
00658                     if(pcost > new_pcost)
00659                         {       /* New path is lowest cost. */
00660                             rr_node_route_inf[inode].path_cost = new_pcost;
00661                             prev_node = current->u.prev_node;
00662                             rr_node_route_inf[inode].prev_node = prev_node;
00663                             rr_node_route_inf[inode].prev_edge =
00664                                 current->prev_edge;
00665                                 first_time = FALSE;
00666 
00667                                 if(pcost > 0.99 * HUGE_FLOAT)   /* First time touched. */ {
00668                                         add_to_mod_list(&rr_node_route_inf[inode].
00669                                                 path_cost);
00670                                         first_time = TRUE;
00671                                 }
00672 
00673                             breadth_first_expand_neighbours_cluster(inode, new_pcost, inet, first_time);
00674                         }
00675 
00676                     free_heap_data(current);
00677                     current = get_heap_head();
00678 
00679                     if(current == NULL)
00680                         {       /* Impossible routing. No path for net. */
00681                             reset_path_costs();
00682                             return (FALSE);
00683                         }
00684 
00685                     inode = current->index;
00686                 }
00687 
00688             rr_node_route_inf[inode].target_flag--;     /* Connected to this SINK. */
00689             remaining_connections_to_sink =
00690                 rr_node_route_inf[inode].target_flag;
00691             tptr = update_traceback(current, inet);
00692             free_heap_data(current);
00693         }
00694 
00695     empty_heap();
00696     reset_path_costs();
00697     return (TRUE);
00698 }
00699 
00700 /** Adds all the rr_nodes in the traceback segment starting at tptr (and    
00701  * continuing to the end of the traceback) to the heap with a cost of zero. 
00702  * This allows expansion to begin from the existing wiring.  The            
00703  * remaining_connections_to_sink value is 0 if the route segment ending     
00704  * at this location is the last one to connect to the SINK ending the route 
00705  * segment.  This is the usual case.  If it is not the last connection this 
00706  * net must make to this SINK, I have a hack to ensure the next connection  
00707  * to this SINK goes through a different IPIN.  Without this hack, the      
00708  * router would always put all the connections from this net to this SINK   
00709  * through the same IPIN.  With LUTs or cluster-based logic blocks, you     
00710  * should never have a net connecting to two logically-equivalent pins on   
00711  * the same logic block, so the hack will never execute.  If your logic     
00712  * block is an and-gate, however, nets might connect to two and-inputs on   
00713  * the same logic block, and since the and-inputs are logically-equivalent, 
00714  * this means two connections to the same SINK.                             
00715  */
00716 static void
00717 breadth_first_expand_trace_segment_cluster(struct s_trace *start_ptr,
00718                                    int remaining_connections_to_sink)
00719 {
00720     struct s_trace *tptr;
00721 
00722     tptr = start_ptr;
00723 
00724         /* For intra-cluster routing, logical equivalence does not occur, so it is impossible to get a value bigger than 0 */
00725         assert(remaining_connections_to_sink == 0);
00726 
00727     while(tptr != NULL)
00728         {
00729             node_to_heap(tptr->index, 0., NO_PREVIOUS, NO_PREVIOUS,
00730                          OPEN, OPEN);
00731             tptr = tptr->next;
00732         }
00733 }
00734 
00735 
00736 /** Puts all the rr_nodes adjacent to inode on the heap.  rr_nodes outside   
00737  * the expanded bounding box specified in route_bb are not added to the     
00738  * heap.  pcost is the path_cost to get to inode.                           
00739  */
00740 static void
00741 breadth_first_expand_neighbours_cluster(int inode,
00742                                 float pcost,
00743                                 int inet,
00744                                 boolean first_time)
00745 {
00746     int iconn, to_node, num_edges;
00747     float tot_cost;
00748 
00749     num_edges = rr_node[inode].num_edges;
00750     for(iconn = 0; iconn < num_edges; iconn++)
00751         {
00752             to_node = rr_node[inode].edges[iconn];
00753                 /*if(first_time) { */
00754                         tot_cost = pcost + get_rr_cong_cost(to_node) * rr_node_intrinsic_cost(to_node);
00755                         /*
00756                 } else {
00757                         tot_cost = pcost + get_rr_cong_cost(to_node);
00758                 }*/
00759             node_to_heap(to_node, tot_cost, inode, iconn, OPEN, OPEN);
00760         }
00761 }
00762 
00763 
00764 /** Adds the SOURCE of this net to the heap.  Used to start a net's routing. */
00765 static void
00766 breadth_first_add_source_to_heap_cluster(int inet)
00767 {
00768     int inode;
00769     float cost;
00770 
00771     inode = net_rr_terminals[inet][0];  /* SOURCE */
00772     cost = get_rr_cong_cost(inode);
00773 
00774     node_to_heap(inode, cost, NO_PREVIOUS, NO_PREVIOUS, OPEN, OPEN);
00775 }
00776 
00777 /** Mark all the SINKs of this net as targets by setting their target flags  
00778  * to the number of times the net must connect to each SINK.  Note that     
00779  * this number can occassionally be greater than 1 -- think of connecting   
00780  * the same net to two inputs of an and-gate (and-gate inputs are logically 
00781  * equivalent, so both will connect to the same SINK).                      
00782  */
00783 static void 
00784 mark_ends_cluster(int inet)
00785 {
00786     int ipin, inode;
00787 
00788     for(ipin = 1; ipin <= vpack_net[inet].num_sinks; ipin++)
00789         {
00790             inode = net_rr_terminals[inet][ipin];
00791                 if(inode == OPEN)
00792                         continue;
00793             rr_node_route_inf[inode].target_flag++;
00794                 assert(rr_node_route_inf[inode].target_flag == 1);
00795         }
00796 }
00797 
00798 
00799 static void
00800 alloc_net_rr_terminals_cluster()
00801 {
00802     int inet;
00803 
00804     net_rr_terminals = (int **)my_malloc(num_logical_nets * sizeof(int *));
00805         saved_net_rr_terminals = (int **)my_malloc(num_logical_nets * sizeof(int *));
00806 
00807     for(inet = 0; inet < num_logical_nets; inet++)
00808         {
00809             net_rr_terminals[inet] =
00810                 (int *)my_chunk_malloc((vpack_net[inet].num_sinks + 1) *
00811                                        sizeof(int), &rr_mem_chunk_list_head,
00812                                        &chunk_bytes_avail,
00813                                        &chunk_next_avail_mem);
00814 
00815                 saved_net_rr_terminals[inet] = (int *)my_malloc((vpack_net[inet].num_sinks + 1) * sizeof(int));
00816         }
00817 }
00818 
00819 
00820 /** Allocates and loads the net_rr_terminals data structure.  For each net   
00821  * it stores the rr_node index of the SOURCE of the net and all the SINKs   
00822  * of the net.  [0..num_logical_nets-1][0..num_pins-1].   
00823  */
00824 enum e_block_pack_status
00825 try_add_block_to_current_cluster_and_primitive(INP int iblock, INP t_pb *primitive)
00826 {
00827     int ipin, iblk_net;
00828         int orig_num_nets_in_cluster;
00829         boolean success, found;
00830         t_model_ports *port;
00831 
00832         success = FALSE;
00833         found = FALSE;
00834 
00835         assert(primitive->pb_graph_node->pb_type->num_modes == 0); /* check if primitive */
00836         assert(primitive->logical_block == OPEN && logical_block[iblock].clb_index == NO_CLUSTER); /* check if primitive and block is open */
00837 
00838         /* check if block type matches primitive type */
00839         if(logical_block[iblock].model != primitive->pb_graph_node->pb_type->model) {
00840                 /* End early, model is incompatible */
00841                 return BLK_FAILED_FEASIBLE;
00842         }
00843 
00844         orig_num_nets_in_cluster = num_nets_in_cluster;
00845         save_and_reset_routing_cluster();
00846 
00847         /* try pack it in */
00848         assert(primitive->logical_block == OPEN);
00849         assert(logical_block[iblock].clb_index == NO_CLUSTER);
00850 
00851         primitive->logical_block = iblock;
00852         logical_block[iblock].pb = primitive;
00853         logical_block[iblock].clb_index = curr_cluster_index;
00854         
00855         /* for each net of logical block, check if it is in cluster, if not add it */
00856         /*   also check if pins on primitive can fit logical block */
00857         
00858         port = logical_block[iblock].model->inputs;
00859         success = TRUE;
00860         
00861         while(port && success) {
00862                 for(ipin = 0; ipin < port->size && success; ipin++) {
00863                         if(port->is_clock) {
00864                                 assert(port->size == 1);
00865                                 iblk_net = logical_block[iblock].clock_net;
00866                         } else {
00867                                 iblk_net = logical_block[iblock].input_nets[port->index][ipin];
00868                         }
00869                         if(iblk_net == OPEN) {
00870                                 continue;
00871                         }
00872                         if(!is_net_in_cluster(iblk_net)){
00873                                 nets_in_cluster[num_nets_in_cluster] = iblk_net;
00874                                 num_nets_in_cluster++;
00875                         }
00876                         success = add_net_rr_terminal_cluster(iblk_net, primitive, iblock, port, ipin);
00877                 }
00878                 port = port->next;
00879         }
00880 
00881         port = logical_block[iblock].model->outputs;
00882         while(port && success) {
00883                 for(ipin = 0; ipin < port->size && success; ipin++) {
00884                         iblk_net = logical_block[iblock].output_nets[port->index][ipin];
00885                         if(iblk_net == OPEN) {
00886                                 continue;
00887                         }
00888                         if(!is_net_in_cluster(iblk_net)){
00889                                 nets_in_cluster[num_nets_in_cluster] = iblk_net;
00890                                 num_nets_in_cluster++;
00891                         }
00892                         success = add_net_rr_terminal_cluster(iblk_net, primitive, iblock, port, ipin);
00893                 }
00894                 port = port->next;
00895         }
00896 
00897         if(success) {
00898                 success = reload_ext_net_rr_terminal_cluster();
00899         }
00900 
00901         if(success) {
00902                 /* route it */
00903                 reset_rr_node_route_structs(); /* Clear all prior rr_graph history */
00904                 success = try_breadth_first_route_cluster(); /* route from scratch */
00905         }
00906 
00907         if(success) {
00908                 return BLK_PASSED;
00909         } else {
00910                 /* Cannot pack, restore cluster */
00911                 primitive->logical_block = OPEN;
00912                 logical_block[iblock].pb = NULL;
00913                 logical_block[iblock].clb_index = NO_CLUSTER;
00914                 restore_routing_cluster();
00915                 num_nets_in_cluster = orig_num_nets_in_cluster;
00916                 return BLK_FAILED_ROUTE;
00917         }
00918 }
00919 
00920 
00921 /** This routing frees any routing currently held in best routing,       
00922  * then copies over the current routing (held in trace_head), and       
00923  * finally sets trace_head and trace_tail to all NULLs so that the      
00924  * connection to the saved routing is broken.  This is necessary so     
00925  * that the next iteration of the router does not free the saved        
00926  * routing elements.  Also, the routing path costs and net_rr_terminals is stripped from the
00927  * existing rr_graph so that the saved routing does not affect the graph 
00928  */
00929 static void
00930 save_and_reset_routing_cluster() {
00931 
00932     int inet, i, j;
00933     struct s_trace *tempptr;
00934 
00935     for(i = 0; i < num_nets_in_cluster; i++)
00936         {
00937                 inet = nets_in_cluster[i];
00938                 for(j = 0; j <= vpack_net[inet].num_sinks; j++) {
00939                         saved_net_rr_terminals[inet][j] = net_rr_terminals[inet][j];
00940                 }
00941                 
00942 /* Free any previously saved routing.  It is no longer best. */
00943 /* Also Save a pointer to the current routing in best_routing. */
00944 
00945                 pathfinder_update_one_cost(trace_head[inet], -1, pres_fac);
00946                 tempptr = trace_head[inet];
00947             trace_head[inet] = best_routing[inet];
00948             free_traceback(inet);
00949                 best_routing[inet] = tempptr;
00950 
00951 /* Set the current (working) routing to NULL so the current trace       *
00952  * elements won't be reused by the memory allocator.                    */
00953 
00954             trace_head[inet] = NULL;
00955             trace_tail[inet] = NULL;
00956         }
00957 }
00958 
00959 /** Deallocates any current routing in trace_head, and replaces it with    
00960  * the routing in best_routing.  Best_routing is set to NULL to show that 
00961  * it no longer points to a valid routing.  NOTE:  trace_tail is not      
00962  * restored -- it is set to all NULLs since it is only used in            
00963  * update_traceback.  If you need trace_tail restored, modify this        
00964  * routine.  Also restores the locally used opin data.                    
00965  */
00966 static void
00967 restore_routing_cluster()
00968 {
00969     int inet, i, j;
00970 
00971     for(i = 0; i < num_nets_in_cluster; i++)
00972         {
00973                 inet = nets_in_cluster[i];
00974 
00975                 pathfinder_update_one_cost(trace_head[inet], -1, pres_fac);
00976 
00977             /* Free any current routing. */
00978             free_traceback(inet);
00979 
00980             /* Set the current routing to the saved one. */
00981             trace_head[inet] = best_routing[inet];
00982             best_routing[inet] = NULL;  /* No stored routing. */
00983 
00984                 /* restore net terminals */
00985                 for(j = 0; j <= vpack_net[inet].num_sinks; j++) {
00986                         net_rr_terminals[inet][j] = saved_net_rr_terminals[inet][j];
00987                 }
00988 
00989                 /* restore old routing */
00990                 pathfinder_update_one_cost(trace_head[inet], 1, pres_fac);
00991         }
00992 }
00993 
00994 /** This routine updates the occupancy and pres_cost of the rr_nodes that are 
00995  * affected by the portion of the routing of one net that starts at          
00996  * route_segment_start.  If route_segment_start is trace_head[inet], the     
00997  * cost of all the nodes in the routing of net inet are updated.  If         
00998  * add_or_sub is -1 the net (or net portion) is ripped up, if it is 1 the    
00999  * net is added to the routing.  The size of pres_fac determines how severly 
01000  * oversubscribed rr_nodes are penalized.                                    
01001  */
01002 void save_cluster_solution()
01003 {
01004         int i, j, net_index;
01005     struct s_trace *tptr, *prev;
01006     int inode;
01007         for(i = 0; i < max_ext_index; i++) {
01008                 rr_node[i].net_num = OPEN;
01009                 rr_node[i].prev_edge = OPEN;
01010                 rr_node[i].prev_node = OPEN;
01011         }
01012         for(i = 0; i < num_nets_in_cluster; i++) {
01013                 prev = NULL;
01014                 net_index = nets_in_cluster[i];
01015                 tptr = trace_head[net_index];
01016                 if(tptr == NULL)                /* No routing yet. */
01017                 return;
01018 
01019                 for(;;)
01020                 {
01021                         inode = tptr->index;
01022                         rr_node[inode].net_num = net_index;
01023                         if(prev != NULL) {
01024                                 rr_node[inode].prev_node = prev->index;
01025                                 for(j = 0; j < rr_node[prev->index].num_edges; j++) {
01026                                         if(rr_node[prev->index].edges[j] == inode) {
01027                                                 rr_node[inode].prev_edge = j;
01028                                                 break;
01029                                         }
01030                                 }
01031                                 assert(j != rr_node[prev->index].num_edges);
01032                         } else {
01033                                 rr_node[inode].prev_node = OPEN;
01034                                 rr_node[inode].prev_edge = OPEN;
01035                         }
01036 
01037                         if(rr_node[inode].type == SINK)
01038                         {
01039                                 tptr = tptr->next;      /* Skip next segment. */
01040                                 if(tptr == NULL)
01041                                 break;
01042                         }
01043 
01044                         prev = tptr;
01045                         tptr = tptr->next;
01046 
01047                 }                       /* End while loop -- did an entire traceback. */
01048         }
01049 }
01050 
01051 boolean is_pin_open(int i) {
01052         return (rr_node[i].occ == 0);
01053 }
01054 
01055 
01056 /** Prints out the routing to file route_file.  */
01057 void
01058 print_intra_cluster_route(char *route_file)
01059 {
01060     int inet, inode;
01061     t_rr_type rr_type;
01062     struct s_trace *tptr;
01063     char *name_type[] =
01064         { "SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY", "INTRA_CLUSTER_EDGE" };
01065     FILE *fp;
01066 
01067     fp = my_fopen(route_file, "w", 0);
01068 
01069     fprintf(fp, "\nRouting:");
01070     for(inet = 0; inet < num_nets; inet++)
01071         {
01072             
01073                 if(vpack_net[inet].num_sinks == FALSE)
01074                 {
01075                         fprintf(fp, "\n\nNet %d (%s)\n\n", inet, vpack_net[inet].name);
01076                         fprintf(fp, "\n\n Used in local cluster only, reserved one CLB pin\n\n");
01077                 } else if(trace_head[inet]){
01078                         fprintf(fp, "\n\nNet %d (%s)\n\n", inet, vpack_net[inet].name);
01079                         tptr = trace_head[inet];
01080 
01081                         while(tptr != NULL)
01082                         {
01083                                 inode = tptr->index;
01084                                 rr_type = rr_node[inode].type;
01085 
01086                                 fprintf(fp, "%6s %d ", name_type[rr_type], inode);
01087 
01088 
01089 
01090 /* Uncomment line below if you're debugging and want to see the switch types *
01091  * used in the routing.                                                      */
01092 /*          fprintf (fp, "Switch: %d", tptr->iswitch);    */
01093 
01094                                 fprintf(fp, "\n");
01095 
01096                                 tptr = tptr->next;
01097                         }
01098                 }
01099         }
01100 
01101     fclose(fp);
01102 }
01103 
01104 /** This is a tie breaker to avoid using nodes with more edges whenever possible */
01105 static float rr_node_intrinsic_cost(int inode) {
01106         float value;
01107         value = rr_node[inode].pack_intrinsic_cost;
01108         return value;
01109 }
01110 
01111 /** turns on mode for a pb by setting capacity of its rr_nodes to 1 */
01112 void set_pb_mode(t_pb *pb, int mode, int isOn) {
01113         int i, j, index;
01114         int i_pb_type, i_pb_inst;
01115         const t_pb_type *pb_type;
01116         t_pb_graph_node *pb_graph_node;
01117 
01118         pb_type = pb->pb_graph_node->pb_type;
01119         for(i_pb_type = 0; i_pb_type < pb_type->modes[mode].num_pb_type_children; i_pb_type++) {
01120                 for(i_pb_inst = 0; i_pb_inst < pb_type->modes[mode].pb_type_children[i_pb_type].num_pb; i_pb_inst++) {
01121                         pb_graph_node = &pb->pb_graph_node->child_pb_graph_nodes[mode][i_pb_type][i_pb_inst];
01122                         for(i = 0; i < pb_graph_node->num_input_ports; i++) {
01123                                 for(j = 0; j < pb_graph_node->num_input_pins[i]; j++) {
01124                                         index = pb_graph_node->input_pins[i][j].pin_count_in_cluster;
01125                                         rr_node[index].capacity = isOn;
01126                                 }
01127                         }
01128 
01129                         for(i = 0; i < pb_graph_node->num_output_ports; i++) {
01130                                 for(j = 0; j < pb_graph_node->num_output_pins[i]; j++) {
01131                                         index = pb_graph_node->output_pins[i][j].pin_count_in_cluster;
01132                                         rr_node[index].capacity = isOn;                 
01133                                 }
01134                         }
01135 
01136                         for(i = 0; i < pb_graph_node->num_clock_ports; i++) {
01137                                 for(j = 0; j < pb_graph_node->num_clock_pins[i]; j++) {
01138                                         index = pb_graph_node->clock_pins[i][j].pin_count_in_cluster;
01139                                         rr_node[index].capacity = isOn;
01140                                 }
01141                         }       
01142                 }
01143         }
01144 }