VPR-6.0

vpr/SRC/route/rr_graph_timing_params.c

Go to the documentation of this file.
00001 #include <assert.h>
00002 #include "util.h"
00003 #include "vpr_types.h"
00004 #include "globals.h"
00005 #include "rr_graph.h"
00006 #include "rr_graph_util.h"
00007 #include "rr_graph2.h"
00008 #include "rr_graph_timing_params.h"
00009 
00010 
00011 
00012 /****************** Subroutine definitions *********************************/
00013 
00014 /** This routine finishes loading the C elements of the rr_graph. It assumes 
00015  * that when you call it the CHANX and CHANY nodes have had their C set to  
00016  * their metal capacitance, and everything else has C set to 0.  The graph  
00017  * connectivity (edges, switch types etc.) must all be loaded too.  This    
00018  * routine will add in the capacitance on the CHANX and CHANY nodes due to: 
00019  *                                                                          
00020  * - 1) The output capacitance of the switches coming from OPINs;             
00021  * - 2) The input and output capacitance of the switches between the various  
00022  *    wiring (CHANX and CHANY) segments; and                                
00023  * - 3) The input capacitance of the buffers separating routing tracks from   
00024  *    the connection block inputs.                                          
00025  */
00026 void
00027 add_rr_graph_C_from_switches(float C_ipin_cblock)
00028 {
00029     int inode, iedge, switch_index, to_node, maxlen;
00030     int icblock, isblock, iseg_low, iseg_high;
00031     float Cin, Cout;
00032     t_rr_type from_rr_type, to_rr_type;
00033     boolean *cblock_counted;    /* [0..max(nx,ny)] -- 0th element unused. */
00034     float *buffer_Cin;          /* [0..max(nx,ny)] */
00035     boolean buffered;
00036     float *Couts_to_add;        /* UDSD */
00037 
00038     maxlen = max(nx, ny) + 1;
00039     cblock_counted = (boolean *) my_calloc(maxlen, sizeof(boolean));
00040     buffer_Cin = (float *)my_calloc(maxlen, sizeof(float));
00041 
00042     for(inode = 0; inode < num_rr_nodes; inode++)
00043         {
00044 
00045             from_rr_type = rr_node[inode].type;
00046 
00047             if(from_rr_type == CHANX || from_rr_type == CHANY)
00048                 {
00049 
00050                     for(iedge = 0; iedge < rr_node[inode].num_edges; iedge++)
00051                         {
00052 
00053                             to_node = rr_node[inode].edges[iedge];
00054                             to_rr_type = rr_node[to_node].type;
00055 
00056                             if(to_rr_type == CHANX || to_rr_type == CHANY)
00057                                 {
00058 
00059                                     switch_index =
00060                                         rr_node[inode].switches[iedge];
00061                                     Cin = switch_inf[switch_index].Cin;
00062                                     Cout = switch_inf[switch_index].Cout;
00063                                     buffered =
00064                                         switch_inf[switch_index].buffered;
00065 
00066                                     /* If both the switch from inode to to_node and the switch from *
00067                                      * to_node back to inode use bidirectional switches (i.e. pass  *
00068                                      * transistors), there will only be one physical switch for     *
00069                                      * both edges.  Hence, I only want to count the capacitance of  *
00070                                      * that switch for one of the two edges.  (Note:  if there is   *
00071                                      * a pass transistor edge from x to y, I always build the graph *
00072                                      * so that there is a corresponding edge using the same switch  *
00073                                      * type from y to x.) So, I arbitrarily choose to add in the    *
00074                                      * capacitance in that case of a pass transistor only when      *
00075                                      * processing the the lower inode number.                       *
00076                                      * If an edge uses a buffer I always have to add in the output  *
00077                                      * capacitance.  I assume that buffers are shared at the same   *
00078                                      * (i,j) location, so only one input capacitance needs to be    *
00079                                      * added for all the buffered switches at that location.  If    *
00080                                      * the buffers at that location have different sizes, I use the *
00081                                      * input capacitance of the largest one.                        */
00082 
00083                                     if(!buffered && inode < to_node)
00084                                         {       /* Pass transistor. */
00085                                             rr_node[inode].C += Cin;
00086                                             rr_node[to_node].C += Cout;
00087                                         }
00088 
00089                                     else if(buffered)
00090                                         {
00091                                             /* Prevent double counting of capacitance for UDSD */
00092                                             if(rr_node[to_node].drivers !=
00093                                                SINGLE)
00094                                                 {
00095                                                     /* For multiple-driver architectures the output capacitance can
00096                                                      * be added now since each edge is actually a driver */
00097                                                     rr_node[to_node].C +=
00098                                                         Cout;
00099                                                 }
00100                                             isblock =
00101                                                 seg_index_of_sblock(inode,
00102                                                                     to_node);
00103                                             buffer_Cin[isblock] =
00104                                                 max(buffer_Cin[isblock], Cin);
00105                                         }
00106 
00107                                 }
00108                             /* End edge to CHANX or CHANY node. */
00109                             else if(to_rr_type == IPIN)
00110                                 {
00111 
00112                                     /* Code below implements sharing of the track to connection     *
00113                                      * box buffer.  I assume there is one such buffer at every      *
00114                                      * segment of the wire at which at least one logic block input  *
00115                                      * connects.                                                    */
00116 
00117                                     icblock =
00118                                         seg_index_of_cblock(from_rr_type,
00119                                                             to_node);
00120                                     if(cblock_counted[icblock] == FALSE)
00121                                         {
00122                                             rr_node[inode].C += C_ipin_cblock;
00123                                             cblock_counted[icblock] = TRUE;
00124                                         }
00125                                 }
00126                         }       /* End loop over all edges of a node. */
00127 
00128                     /* Reset the cblock_counted and buffer_Cin arrays, and add buf Cin. */
00129 
00130                     /* Method below would be faster for very unpopulated segments, but I  *
00131                      * think it would be slower overall for most FPGAs, so commented out. */
00132 
00133                     /*   for (iedge=0;iedge<rr_node[inode].num_edges;iedge++) {
00134                      * to_node = rr_node[inode].edges[iedge];
00135                      * if (rr_node[to_node].type == IPIN) {
00136                      * icblock = seg_index_of_cblock (from_rr_type, to_node);
00137                      * cblock_counted[icblock] = FALSE;
00138                      * }
00139                      * }     */
00140 
00141                     if(from_rr_type == CHANX)
00142                         {
00143                             iseg_low = rr_node[inode].xlow;
00144                             iseg_high = rr_node[inode].xhigh;
00145                         }
00146                     else
00147                         {       /* CHANY */
00148                             iseg_low = rr_node[inode].ylow;
00149                             iseg_high = rr_node[inode].yhigh;
00150                         }
00151 
00152                     for(icblock = iseg_low; icblock <= iseg_high; icblock++)
00153                         {
00154                             cblock_counted[icblock] = FALSE;
00155                         }
00156 
00157                     for(isblock = iseg_low - 1; isblock <= iseg_high;
00158                         isblock++)
00159                         {
00160                             rr_node[inode].C += buffer_Cin[isblock];    /* Biggest buf Cin at loc */
00161                             buffer_Cin[isblock] = 0.;
00162                         }
00163 
00164                 }
00165             /* End node is CHANX or CHANY */
00166             else if(from_rr_type == OPIN)
00167                 {
00168 
00169                     for(iedge = 0; iedge < rr_node[inode].num_edges; iedge++)
00170                         {
00171                             switch_index = rr_node[inode].switches[iedge];
00172                             /* UDSD by ICK Start */
00173                             to_node = rr_node[inode].edges[iedge];
00174                             to_rr_type = rr_node[to_node].type;
00175                             assert(to_rr_type == CHANX
00176                                    || to_rr_type == CHANY);
00177                             if(rr_node[to_node].drivers != SINGLE)
00178                                 {
00179                                     Cout = switch_inf[switch_index].Cout;
00180                                     to_node = rr_node[inode].edges[iedge];      /* Will be CHANX or CHANY */
00181                                     rr_node[to_node].C += Cout;
00182                                 }
00183                         }
00184                 }
00185             /* End node is OPIN. */
00186         }                       /* End for all nodes. */
00187 
00188     /* Now we need to add any cout loads for nets that we previously didn't process
00189      * Current structures only keep switch information from a node to the next node and
00190      * not the reverse.  Therefore I need to go through all the possible edges to figure 
00191      * out what the Cout's should be */
00192     Couts_to_add = (float *)my_calloc(num_rr_nodes, sizeof(float));
00193     for(inode = 0; inode < num_rr_nodes; inode++)
00194         {
00195             for(iedge = 0; iedge < rr_node[inode].num_edges; iedge++)
00196                 {
00197                     switch_index = rr_node[inode].switches[iedge];
00198                     to_node = rr_node[inode].edges[iedge];
00199                     to_rr_type = rr_node[to_node].type;
00200                     if(to_rr_type == CHANX || to_rr_type == CHANY)
00201                         {
00202                             if(rr_node[to_node].drivers == SINGLE)
00203                                 {
00204                                     /* Cout was not added in these cases */
00205                                     if(Couts_to_add[to_node] != 0)
00206                                         {
00207                                             /* We've already found a Cout to add to this node
00208                                              * We could take the max of all possibilities but
00209                                              * instead I will fail if there are conflicting Couts */
00210                                             if(Couts_to_add[to_node] !=
00211                                                switch_inf[switch_index].Cout)
00212                                                 {
00213                                                     printf
00214                                                         ("Error: A single driver resource (%i) is driven by different Cout's (%e!=%e)\n",
00215                                                          to_node,
00216                                                          Couts_to_add
00217                                                          [to_node],
00218                                                          switch_inf
00219                                                          [switch_index].Cout);
00220                                                     exit(1);
00221                                                 }
00222                                         }
00223                                     Couts_to_add[to_node] =
00224                                         switch_inf[switch_index].Cout;
00225 
00226                                 }
00227                         }
00228                 }
00229         }
00230     for(inode = 0; inode < num_rr_nodes; inode++)
00231         {
00232             rr_node[inode].C += Couts_to_add[inode];
00233         }
00234     free(Couts_to_add);
00235     free(cblock_counted);
00236     free(buffer_Cin);
00237 }