VPR-6.0
|
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 }