VPR-6.0

vpr/SRC/timing/net_delay.c

Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include "util.h"
00003 #include "vpr_types.h"
00004 #include "globals.h"
00005 #include "net_delay.h"
00006 
00007 
00008 /***************** Types and defines local to this module ********************/
00009 
00010 /* Linked list listing the children of an rc_node.                           
00011  * - child:  Pointer to an rc_node (child of the current node).                
00012  * - iswitch:  Index of the switch type used to connect to the child node.     
00013  * - next:   Pointer to the next linked_rc_edge in the linked list (allows     
00014  *         you to get the next child of the current rc_node).                
00015  */
00016 struct s_linked_rc_edge
00017 {
00018     struct s_rc_node *child;
00019     short iswitch;
00020     struct s_linked_rc_edge *next;
00021 };
00022 
00023 typedef struct s_linked_rc_edge t_linked_rc_edge;
00024 
00025 
00026 /** Structure describing one node in an RC tree (used to get net delays).     
00027  * - u.child_list:  Pointer to a linked list of linked_rc_edge.  Each one of   
00028  *                the linked list entries gives a child of this node.        
00029  * - u.next:  Used only when this node is on the free list.  Gives the next    
00030  *          node on the free list.                                           
00031  * - inode:  index (ID) of the rr_node that corresponds to this rc_node.       
00032  * - C_downstream:  Total downstream capacitance from this rc_node.  That is,  
00033  *                the total C of the subtree rooted at the current node,     
00034  *                including the C of the current node.                       
00035  * - Tdel:  Time delay for the signal to get from the net source to this node. 
00036  *        Includes the time to go through this node.                         
00037  */
00038 struct s_rc_node
00039 {
00040     union
00041     {
00042         t_linked_rc_edge *child_list;
00043         struct s_rc_node *next;
00044     }
00045     u;
00046     int inode;
00047     float C_downstream;
00048     float Tdel;
00049 };
00050 
00051 typedef struct s_rc_node t_rc_node;
00052 
00053 
00054 /** Linked list of pointers to rc_nodes.                                      
00055  * - rc_node:  Pointer to an rc_node.                                          
00056  * - next:  Next list element.                                                 
00057  */
00058 struct s_linked_rc_ptr
00059 {
00060     struct s_rc_node *rc_node;
00061     struct s_linked_rc_ptr *next;
00062 };
00063 
00064 typedef struct s_linked_rc_ptr t_linked_rc_ptr;
00065 
00066 
00067 
00068 
00069 /*********************** Subroutines local to this module ********************/
00070 
00071 static t_rc_node *alloc_and_load_rc_tree(int inet,
00072                                          t_rc_node ** rc_node_free_list_ptr,
00073                                          t_linked_rc_edge **
00074                                          rc_edge_free_list_ptr,
00075                                          t_linked_rc_ptr *
00076                                          rr_node_to_rc_node);
00077 
00078 static void add_to_rc_tree(t_rc_node * parent_rc,
00079                            t_rc_node * child_rc,
00080                            short iswitch,
00081                            int inode,
00082                            t_linked_rc_edge ** rc_edge_free_list_ptr);
00083 
00084 static t_rc_node *alloc_rc_node(t_rc_node ** rc_node_free_list_ptr);
00085 
00086 static void free_rc_node(t_rc_node * rc_node,
00087                          t_rc_node ** rc_node_free_list_ptr);
00088 
00089 static t_linked_rc_edge *alloc_linked_rc_edge(t_linked_rc_edge
00090                                               ** rc_edge_free_list_ptr);
00091 
00092 static void free_linked_rc_edge(t_linked_rc_edge * rc_edge,
00093                                 t_linked_rc_edge ** rc_edge_free_list_ptr);
00094 
00095 static float load_rc_tree_C(t_rc_node * rc_node);
00096 
00097 static void load_rc_tree_T(t_rc_node * rc_node,
00098                            float T_arrival);
00099 
00100 static void load_one_net_delay(float **net_delay,
00101                                int inet,
00102                                    struct s_net *nets,
00103                                t_linked_rc_ptr * rr_node_to_rc_node);
00104 
00105 static void load_one_constant_net_delay(float **net_delay,
00106                                         int inet,
00107                                         struct s_net *nets,
00108                                         float delay_value);
00109 
00110 static void free_rc_tree(t_rc_node * rc_root,
00111                          t_rc_node ** rc_node_free_list_ptr,
00112                          t_linked_rc_edge ** rc_edge_free_list_ptr);
00113 
00114 static void reset_rr_node_to_rc_node(t_linked_rc_ptr * rr_node_to_rc_node,
00115                                      int inet);
00116 
00117 static void free_rc_node_free_list(t_rc_node * rc_node_free_list);
00118 
00119 static void free_rc_edge_free_list(t_linked_rc_edge * rc_edge_free_list);
00120 
00121 
00122 
00123 /*************************** Subroutine definitions **************************/
00124 
00125 /** Allocates space for the net_delay data structure                          
00126  * [0..num_nets-1][1..num_pins-1].  I chunk the data to save space on large  
00127  * problems.                                                                 
00128  */
00129 float **
00130 alloc_net_delay(struct s_linked_vptr **chunk_list_head_ptr, struct s_net *nets, int n_nets)
00131 {
00132 
00133     float **net_delay;          /* [0..num_nets-1][1..num_pins-1] */
00134     float *tmp_ptr;
00135     int inet;
00136     int chunk_bytes_avail;
00137     char *chunk_next_avail_mem;
00138 
00139     *chunk_list_head_ptr = NULL;
00140     chunk_bytes_avail = 0;
00141     chunk_next_avail_mem = NULL;
00142 
00143     net_delay = (float **)my_malloc(n_nets * sizeof(float *));
00144 
00145     for(inet = 0; inet < n_nets; inet++)
00146         {
00147             tmp_ptr =
00148                 (float *)my_chunk_malloc(((nets[inet].num_sinks + 1) - 1) *
00149                                          sizeof(float), chunk_list_head_ptr,
00150                                          &chunk_bytes_avail,
00151                                          &chunk_next_avail_mem);
00152                 
00153             net_delay[inet] = tmp_ptr - 1;      /* [1..num_pins-1] */
00154         }
00155 
00156     return (net_delay);
00157 }
00158 
00159 
00160 /** Frees the net_delay structure.  Assumes it was chunk allocated.          */
00161 void
00162 free_net_delay(float **net_delay,
00163                struct s_linked_vptr **chunk_list_head_ptr)
00164 {
00165     free(net_delay);
00166     free_chunk_memory(*chunk_list_head_ptr);
00167     *chunk_list_head_ptr = NULL;
00168 }
00169 
00170 /** This routine loads net_delay[0..num_nets-1][1..num_pins-1].  Each entry   
00171  * is the Elmore delay from the net source to the appropriate sink.  Both    
00172  * the rr_graph and the routing traceback must be completely constructed     
00173  * before this routine is called, and the net_delay array must have been     
00174  * allocated.                                                                
00175  */
00176 void
00177 load_net_delay_from_routing(float **net_delay, struct s_net *nets, int n_nets)
00178 {
00179 
00180 
00181     t_rc_node *rc_node_free_list, *rc_root;
00182     t_linked_rc_edge *rc_edge_free_list;
00183     int inet;
00184     t_linked_rc_ptr *rr_node_to_rc_node;        /* [0..num_rr_nodes-1]  */
00185 
00186     rr_node_to_rc_node = (t_linked_rc_ptr *) my_calloc(num_rr_nodes,
00187                                                        sizeof
00188                                                        (t_linked_rc_ptr));
00189 
00190     rc_node_free_list = NULL;
00191     rc_edge_free_list = NULL;
00192 
00193     for(inet = 0; inet < n_nets; inet++)
00194         {
00195             if(nets[inet].is_global)
00196                 {
00197                     load_one_constant_net_delay(net_delay, inet, nets, 0.);
00198                 }
00199             else
00200                 {
00201                     rc_root = alloc_and_load_rc_tree(inet, &rc_node_free_list,
00202                                                      &rc_edge_free_list,
00203                                                      rr_node_to_rc_node);
00204                     load_rc_tree_C(rc_root);
00205                     load_rc_tree_T(rc_root, 0.);
00206                     load_one_net_delay(net_delay, inet, nets, rr_node_to_rc_node);
00207                     free_rc_tree(rc_root, &rc_node_free_list,
00208                                  &rc_edge_free_list);
00209                     reset_rr_node_to_rc_node(rr_node_to_rc_node, inet);
00210                 }
00211         }
00212 
00213     free_rc_node_free_list(rc_node_free_list);
00214     free_rc_edge_free_list(rc_edge_free_list);
00215     free(rr_node_to_rc_node);
00216 }
00217 
00218 /** Loads the net_delay array with delay_value for every source - sink        
00219  * connection that is not on a global resource, and with 0. for every source 
00220  * - sink connection on a global net.  (This can be used to allow timing     
00221  * analysis before routing is done with a constant net delay model).         
00222  */
00223 void
00224 load_constant_net_delay(float **net_delay,
00225                         float delay_value, struct s_net *nets, int n_nets)
00226 {
00227 
00228     int inet;
00229 
00230     for(inet = 0; inet < n_nets; inet++)
00231         {
00232             if(nets[inet].is_global)
00233                 {
00234                     load_one_constant_net_delay(net_delay, inet, nets, 0.);
00235                 }
00236             else
00237                 {
00238                     load_one_constant_net_delay(net_delay, inet, nets, delay_value);
00239                 }
00240         }
00241 }
00242 
00243 /** Builds a tree describing the routing of net inet.  Allocates all the data 
00244  * and inserts all the connections in the tree.                              
00245  */
00246 static t_rc_node *
00247 alloc_and_load_rc_tree(int inet,
00248                        t_rc_node ** rc_node_free_list_ptr,
00249                        t_linked_rc_edge ** rc_edge_free_list_ptr,
00250                        t_linked_rc_ptr * rr_node_to_rc_node)
00251 {
00252 
00253     t_rc_node *curr_rc, *prev_rc, *root_rc;
00254     struct s_trace *tptr;
00255     int inode, prev_node;
00256     short iswitch;
00257     t_linked_rc_ptr *linked_rc_ptr;
00258 
00259     root_rc = alloc_rc_node(rc_node_free_list_ptr);
00260     tptr = trace_head[inet];
00261 
00262     if(tptr == NULL)
00263         {
00264             printf
00265                 ("Error in alloc_and_load_rc_tree:  Traceback for net %d doesn't "
00266                  "exist.\n", inet);
00267             exit(1);
00268         }
00269 
00270     inode = tptr->index;
00271     iswitch = tptr->iswitch;
00272     root_rc->inode = inode;
00273     root_rc->u.child_list = NULL;
00274     rr_node_to_rc_node[inode].rc_node = root_rc;
00275 
00276     prev_rc = root_rc;
00277     tptr = tptr->next;
00278 
00279     while(tptr != NULL)
00280         {
00281             inode = tptr->index;
00282 
00283 /* Is this node a "stitch-in" point to part of the existing routing or a   *
00284  * new piece of routing along the current routing "arm?"                   */
00285 
00286             if(rr_node_to_rc_node[inode].rc_node == NULL)
00287                 {               /* Part of current "arm" */
00288                     curr_rc = alloc_rc_node(rc_node_free_list_ptr);
00289                     add_to_rc_tree(prev_rc, curr_rc, iswitch, inode,
00290                                    rc_edge_free_list_ptr);
00291                     rr_node_to_rc_node[inode].rc_node = curr_rc;
00292                     prev_rc = curr_rc;
00293                 }
00294 
00295             else if(rr_node[inode].type != SINK)
00296                 {               /* Connection to old stuff. */
00297 
00298 #ifdef DEBUG
00299                     prev_node = prev_rc->inode;
00300                     if(rr_node[prev_node].type != SINK)
00301                         {
00302                             printf
00303                                 ("Error in alloc_and_load_rc_tree:  Routing of net %d is "
00304                                  "not a tree.\n", inet);
00305                             exit(1);
00306                         }
00307 #endif
00308 
00309                     prev_rc = rr_node_to_rc_node[inode].rc_node;
00310                 }
00311 
00312             else
00313                 {               /* SINK that this net has connected to more than once. */
00314 
00315                     /* I can connect to a SINK node more than once in some weird architectures. *
00316                      * That means the routing isn't really a tree -- there is reconvergent      *
00317                      * fanout from two or more IPINs into one SINK.  I convert this structure   *
00318                      * into a true RC tree on the fly by creating a new rc_node each time I hit *
00319                      * the same sink.  This means I need to keep a linked list of the rc_nodes  *
00320                      * associated with the rr_node (inode) associated with that SINK.           */
00321 
00322                     curr_rc = alloc_rc_node(rc_node_free_list_ptr);
00323                     add_to_rc_tree(prev_rc, curr_rc, iswitch, inode,
00324                                    rc_edge_free_list_ptr);
00325 
00326                     linked_rc_ptr = (t_linked_rc_ptr *)
00327                         my_malloc(sizeof(t_linked_rc_ptr));
00328                     linked_rc_ptr->next = rr_node_to_rc_node[inode].next;
00329                     rr_node_to_rc_node[inode].next = linked_rc_ptr;
00330                     linked_rc_ptr->rc_node = curr_rc;
00331 
00332                     prev_rc = curr_rc;
00333                 }
00334             iswitch = tptr->iswitch;
00335             tptr = tptr->next;
00336         }
00337 
00338     return (root_rc);
00339 }
00340 
00341 /** Adds child_rc to the child list of parent_rc, and sets the switch between 
00342  * them to iswitch.  This routine also intitializes the child_rc properly    
00343  * and sets its node value to inode.                                         
00344  */
00345 static void
00346 add_to_rc_tree(t_rc_node * parent_rc,
00347                t_rc_node * child_rc,
00348                short iswitch,
00349                int inode,
00350                t_linked_rc_edge ** rc_edge_free_list_ptr)
00351 {
00352 
00353     t_linked_rc_edge *linked_rc_edge;
00354 
00355     linked_rc_edge = alloc_linked_rc_edge(rc_edge_free_list_ptr);
00356 
00357     linked_rc_edge->next = parent_rc->u.child_list;
00358     parent_rc->u.child_list = linked_rc_edge;
00359 
00360     linked_rc_edge->child = child_rc;
00361     linked_rc_edge->iswitch = iswitch;
00362 
00363     child_rc->u.child_list = NULL;
00364     child_rc->inode = inode;
00365 }
00366 
00367 /** Allocates a new rc_node, from the free list if possible, from the free   
00368  * store otherwise.                                                         
00369  */
00370 static t_rc_node *
00371 alloc_rc_node(t_rc_node ** rc_node_free_list_ptr)
00372 {
00373 
00374     t_rc_node *rc_node;
00375 
00376     rc_node = *rc_node_free_list_ptr;
00377 
00378     if(rc_node != NULL)
00379         {
00380             *rc_node_free_list_ptr = rc_node->u.next;
00381         }
00382     else
00383         {
00384             rc_node = (t_rc_node *) my_malloc(sizeof(t_rc_node));
00385         }
00386 
00387     return (rc_node);
00388 }
00389 
00390 
00391 /** Adds rc_node to the proper free list.          */
00392 static void
00393 free_rc_node(t_rc_node * rc_node,
00394              t_rc_node ** rc_node_free_list_ptr)
00395 {
00396     rc_node->u.next = *rc_node_free_list_ptr;
00397     *rc_node_free_list_ptr = rc_node;
00398 }
00399 
00400 /** Allocates a new linked_rc_edge, from the free list if possible, from the  
00401  * free store otherwise.                                                     
00402  */
00403 static t_linked_rc_edge *
00404 alloc_linked_rc_edge(t_linked_rc_edge ** rc_edge_free_list_ptr)
00405 {
00406 
00407     t_linked_rc_edge *linked_rc_edge;
00408 
00409     linked_rc_edge = *rc_edge_free_list_ptr;
00410 
00411     if(linked_rc_edge != NULL)
00412         {
00413             *rc_edge_free_list_ptr = linked_rc_edge->next;
00414         }
00415     else
00416         {
00417             linked_rc_edge = (t_linked_rc_edge *) my_malloc(sizeof
00418                                                             (t_linked_rc_edge));
00419         }
00420 
00421     return (linked_rc_edge);
00422 }
00423 
00424 
00425 /** Adds the rc_edge to the rc_edge free list.                       */
00426 static void
00427 free_linked_rc_edge(t_linked_rc_edge * rc_edge,
00428                     t_linked_rc_edge ** rc_edge_free_list_ptr)
00429 {
00430     rc_edge->next = *rc_edge_free_list_ptr;
00431     *rc_edge_free_list_ptr = rc_edge;
00432 }
00433 
00434 /** Does a post-order traversal of the rc tree to load each node's           
00435  * C_downstream with the proper sum of all the downstream capacitances.     
00436  * This routine calls itself recursively to perform the traversal.          
00437  */
00438 static float
00439 load_rc_tree_C(t_rc_node * rc_node)
00440 {
00441 
00442     t_linked_rc_edge *linked_rc_edge;
00443     t_rc_node *child_node;
00444     int inode;
00445     short iswitch;
00446     float C, C_downstream;
00447 
00448     linked_rc_edge = rc_node->u.child_list;
00449     inode = rc_node->inode;
00450     C = rr_node[inode].C;
00451 
00452     while(linked_rc_edge != NULL)
00453         {                       /* For all children */
00454             iswitch = linked_rc_edge->iswitch;
00455             child_node = linked_rc_edge->child;
00456             C_downstream = load_rc_tree_C(child_node);
00457 
00458             if(switch_inf[iswitch].buffered == FALSE)
00459                 C += C_downstream;
00460 
00461             linked_rc_edge = linked_rc_edge->next;
00462         }
00463 
00464     rc_node->C_downstream = C;
00465     return (C);
00466 }
00467 
00468 /** This routine does a pre-order depth-first traversal of the rc tree to    
00469  * compute the Tdel to each node in the rc tree.  The T_arrival is the time 
00470  * at which the signal hits the input to this node.  This routine calls     
00471  * itself recursively to perform the traversal.                             
00472  */
00473 static void
00474 load_rc_tree_T(t_rc_node * rc_node,
00475                float T_arrival)
00476 {
00477 
00478     float Tdel, Rmetal, Tchild;
00479     t_linked_rc_edge *linked_rc_edge;
00480     t_rc_node *child_node;
00481     short iswitch;
00482     int inode;
00483 
00484     Tdel = T_arrival;
00485     inode = rc_node->inode;
00486     Rmetal = rr_node[inode].R;
00487 
00488 /* NB:  rr_node[inode].C gives the capacitance of this node, while          *
00489  * rc_node->C_downstream gives the unbuffered downstream capacitance rooted *
00490  * at this node, including the C of the node itself.  I want to multiply    *
00491  * the C of this node by 0.5 Rmetal, since it's a distributed RC line.      *
00492  * Hence 0.5 Rmetal * Cnode is a pessimistic estimate of delay (i.e. end to *
00493  * end).  For the downstream capacitance rooted at this node (not including *
00494  * the capacitance of the node itself), I assume it is, on average,         *
00495  * connected halfway along the line, so I also multiply by 0.5 Rmetal.  To  *
00496  * be totally pessimistic I would multiply the downstream part of the       *
00497  * capacitance by Rmetal.  Play with this equation if you like.             */
00498 
00499 /* Rmetal is distributed so x0.5 */
00500     Tdel += 0.5 * rc_node->C_downstream * Rmetal;
00501     rc_node->Tdel = Tdel;
00502 
00503 /* Now expand the children of this node to load their Tdel values.       */
00504 
00505     linked_rc_edge = rc_node->u.child_list;
00506 
00507     while(linked_rc_edge != NULL)
00508         {                       /* For all children */
00509             iswitch = linked_rc_edge->iswitch;
00510             child_node = linked_rc_edge->child;
00511 
00512             Tchild = Tdel + switch_inf[iswitch].R * child_node->C_downstream;
00513             Tchild += switch_inf[iswitch].Tdel; /* Intrinsic switch delay. */
00514             load_rc_tree_T(child_node, Tchild);
00515 
00516             linked_rc_edge = linked_rc_edge->next;
00517         }
00518 }
00519 
00520 /** Loads the net delay array for net inet.  The rc tree for that net must  
00521  * have already been completely built and loaded.                          
00522  */
00523 static void
00524 load_one_net_delay(float **net_delay,
00525                    int inet,
00526                    struct s_net* nets,
00527                    t_linked_rc_ptr * rr_node_to_rc_node)
00528 {
00529     int ipin, inode;
00530     float Tmax;
00531     t_rc_node *rc_node;
00532     t_linked_rc_ptr *linked_rc_ptr, *next_ptr;
00533 
00534     for(ipin = 1; ipin < (nets[inet].num_sinks + 1); ipin++)
00535         {
00536 
00537             inode = net_rr_terminals[inet][ipin];
00538 
00539 
00540             linked_rc_ptr = rr_node_to_rc_node[inode].next;
00541             rc_node = rr_node_to_rc_node[inode].rc_node;
00542             Tmax = rc_node->Tdel;
00543 
00544             /* If below only executes when one net connects several times to the      *
00545              * same SINK.  In this case, I can't tell which net pin each connection   *
00546              * to this SINK corresponds to (I can just choose arbitrarily).  To make  *
00547              * sure the timing behaviour converges, I pessimistically set the delay   *
00548              * for all of the connections to this SINK by this net to be the max. of  *
00549              * the delays from this net to this SINK.  NB:  This code only occurs     *
00550              * when a net connect more than once to the same pin class on the same    *
00551              * logic block.  Only a weird architecture would allow this.              */
00552 
00553             if(linked_rc_ptr != NULL)
00554                 {
00555 
00556                     /* The first time I hit a multiply-used SINK, I choose the largest delay  *
00557                      * from this net to this SINK and use it for every connection to this     *
00558                      * SINK by this net.                                                      */
00559 
00560                     do
00561                         {
00562                             rc_node = linked_rc_ptr->rc_node;
00563                             if(rc_node->Tdel > Tmax)
00564                                 {
00565                                     Tmax = rc_node->Tdel;
00566                                     rr_node_to_rc_node[inode].rc_node =
00567                                         rc_node;
00568                                 }
00569                             next_ptr = linked_rc_ptr->next;
00570                             free(linked_rc_ptr);
00571                             linked_rc_ptr = next_ptr;
00572                         }
00573                     while(linked_rc_ptr != NULL);       /* End do while */
00574 
00575                     rr_node_to_rc_node[inode].next = NULL;
00576                 }
00577             /* End of if multiply-used SINK */
00578             net_delay[inet][ipin] = Tmax;
00579         }
00580 }
00581 
00582 
00583 /** Sets each entry of the net_delay array for net inet to delay_value.     */
00584 static void
00585 load_one_constant_net_delay(float **net_delay,
00586                             int inet, 
00587                                 struct s_net *nets,
00588                             float delay_value)
00589 {
00590     int ipin;
00591 
00592     for(ipin = 1; ipin < (nets[inet].num_sinks + 1); ipin++)
00593         net_delay[inet][ipin] = delay_value;
00594 }
00595 
00596 /** Puts the rc tree pointed to by rc_root back on the free list.  Depth-     
00597  * first post-order traversal via recursion.                                 
00598  */
00599 static void
00600 free_rc_tree(t_rc_node * rc_root,
00601              t_rc_node ** rc_node_free_list_ptr,
00602              t_linked_rc_edge ** rc_edge_free_list_ptr)
00603 {
00604 
00605     t_rc_node *rc_node, *child_node;
00606     t_linked_rc_edge *rc_edge, *next_edge;
00607 
00608     rc_node = rc_root;
00609     rc_edge = rc_node->u.child_list;
00610 
00611     while(rc_edge != NULL)
00612         {                       /* For all children */
00613             child_node = rc_edge->child;
00614             free_rc_tree(child_node, rc_node_free_list_ptr,
00615                          rc_edge_free_list_ptr);
00616             next_edge = rc_edge->next;
00617             free_linked_rc_edge(rc_edge, rc_edge_free_list_ptr);
00618             rc_edge = next_edge;
00619         }
00620 
00621     free_rc_node(rc_node, rc_node_free_list_ptr);
00622 }
00623 
00624 /** Resets the rr_node_to_rc_node mapping entries that were set during       
00625  * construction of the RC tree for net inet.  Any extra linked list entries 
00626  * added to deal with a SINK being connected to multiple times have already 
00627  * been freed by load_one_net_delay.                                        
00628  */
00629 static void
00630 reset_rr_node_to_rc_node(t_linked_rc_ptr * rr_node_to_rc_node,
00631                          int inet)
00632 {
00633 
00634     struct s_trace *tptr;
00635     int inode;
00636 
00637     tptr = trace_head[inet];
00638 
00639     while(tptr != NULL)
00640         {
00641             inode = tptr->index;
00642             rr_node_to_rc_node[inode].rc_node = NULL;
00643             tptr = tptr->next;
00644         }
00645 }
00646 
00647 
00648 /** Really frees (i.e. calls free()) all the rc_nodes on the free list.   */
00649 static void
00650 free_rc_node_free_list(t_rc_node * rc_node_free_list)
00651 {
00652     t_rc_node *rc_node, *next_node;
00653 
00654     rc_node = rc_node_free_list;
00655 
00656     while(rc_node != NULL)
00657         {
00658             next_node = rc_node->u.next;
00659             free(rc_node);
00660             rc_node = next_node;
00661         }
00662 }
00663 
00664 
00665 
00666 /** Really frees (i.e. calls free()) all the rc_edges on the free list.   */
00667 static void
00668 free_rc_edge_free_list(t_linked_rc_edge * rc_edge_free_list)
00669 {
00670     t_linked_rc_edge *rc_edge, *next_edge;
00671 
00672     rc_edge = rc_edge_free_list;
00673 
00674     while(rc_edge != NULL)
00675         {
00676             next_edge = rc_edge->next;
00677             free(rc_edge);
00678             rc_edge = next_edge;
00679         }
00680 }
00681 
00682 
00683 /** Dumps the net delays into file fname.   */
00684 void
00685 print_net_delay(float **net_delay,
00686                 char *fname, struct s_net *nets, int n_nets)
00687 {
00688     FILE *fp;
00689     int inet, ipin;
00690 
00691     fp = my_fopen(fname, "w", 0);
00692 
00693     for(inet = 0; inet < n_nets; inet++)
00694         {
00695             fprintf(fp, "Net: %d.\n", inet);
00696             fprintf(fp, "Delays:");
00697 
00698             for(ipin = 1; ipin < (nets[inet].num_sinks + 1); ipin++)
00699                 fprintf(fp, " %g", net_delay[inet][ipin]);
00700 
00701             fprintf(fp, "\n\n");
00702         }
00703 
00704     fclose(fp);
00705 }