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