VPR-6.0
|
00001 #include <assert.h> 00002 #include "util.h" 00003 #include "vpr_types.h" 00004 #include "globals.h" 00005 #include "path_delay2.h" 00006 #include "read_xml_arch_file.h" 00007 00008 /************* Variables (globals) shared by all path_delay modules **********/ 00009 00010 /** [0..num_nets - 1]. Gives the index of the tnode that drives each net. */ 00011 int *net_to_driver_tnode; 00012 00013 00014 /** [0..num__tnode_levels - 1]. Count and list of tnodes at each level of 00015 * the timing graph, to make breadth-first searches easier. 00016 */ 00017 struct s_ivec *tnodes_at_level; 00018 int num_tnode_levels; /**< Number of levels in the timing graph. */ 00019 00020 00021 00022 /******************* Subroutines local to this module ************************/ 00023 00024 static int *alloc_and_load_tnode_fanin_and_check_edges(int *num_sinks_ptr); 00025 00026 00027 00028 /************************** Subroutine definitions ***************************/ 00029 00030 /** Allocates an array and fills it with the number of in-edges (inputs) to 00031 * each tnode. While doing this it also checks that each edge in the timing 00032 * graph points to a valid tnode. Also counts the number of sinks. 00033 */ 00034 static int * 00035 alloc_and_load_tnode_fanin_and_check_edges(int *num_sinks_ptr) 00036 { 00037 00038 int inode, iedge, to_node, num_edges, error, num_sinks; 00039 int *tnode_num_fanin; 00040 t_tedge *tedge; 00041 00042 tnode_num_fanin = (int *)my_calloc(num_tnodes, sizeof(int)); 00043 error = 0; 00044 num_sinks = 0; 00045 00046 for(inode = 0; inode < num_tnodes; inode++) 00047 { 00048 num_edges = tnode[inode].num_edges; 00049 00050 if(num_edges > 0) 00051 { 00052 tedge = tnode[inode].out_edges; 00053 for(iedge = 0; iedge < num_edges; iedge++) 00054 { 00055 to_node = tedge[iedge].to_node; 00056 if(to_node < 0 || to_node >= num_tnodes) 00057 { 00058 printf 00059 ("Error in alloc_and_load_tnode_fanin_and_check_edges:\n" 00060 "tnode #%d edge #%d goes to illegal node #%d.\n", 00061 inode, iedge, to_node); 00062 error++; 00063 } 00064 00065 tnode_num_fanin[to_node]++; 00066 } 00067 } 00068 00069 else if(num_edges == 0) 00070 { 00071 num_sinks++; 00072 } 00073 00074 else 00075 { 00076 printf 00077 ("Error in alloc_and_load_tnode_fanin_and_check_edges: \n" 00078 "tnode #%d has %d edges.\n", inode, num_edges); 00079 error++; 00080 } 00081 00082 } 00083 00084 if(error != 0) 00085 { 00086 printf("Found %d Errors in the timing graph. Aborting.\n", 00087 error); 00088 exit(1); 00089 } 00090 00091 *num_sinks_ptr = num_sinks; 00092 return (tnode_num_fanin); 00093 } 00094 00095 /** Does a breadth-first search through the timing graph in order to levelize 00096 * it. This allows subsequent breadth-first traversals to be faster. Also 00097 * returns the number of sinks in the graph (nodes with no fanout). 00098 */ 00099 int 00100 alloc_and_load_timing_graph_levels(void) 00101 { 00102 00103 t_linked_int *free_list_head, *nodes_at_level_head; 00104 int inode, num_at_level, iedge, to_node, num_edges, num_sinks, 00105 num_levels, i; 00106 t_tedge *tedge; 00107 00108 /* [0..num_tnodes-1]. # of in-edges to each tnode that have not yet been * 00109 * seen in this traversal. */ 00110 00111 int *tnode_fanin_left; 00112 00113 00114 tnode_fanin_left = alloc_and_load_tnode_fanin_and_check_edges(&num_sinks); 00115 00116 free_list_head = NULL; 00117 nodes_at_level_head = NULL; 00118 00119 /* Very conservative -> max number of levels = num_tnodes. Realloc later. * 00120 * Temporarily need one extra level on the end because I look at the first * 00121 * empty level. */ 00122 00123 tnodes_at_level = (struct s_ivec *)my_malloc((num_tnodes + 1) * 00124 sizeof(struct s_ivec)); 00125 00126 /* Scan through the timing graph, putting all the primary input nodes (no * 00127 * fanin) into level 0 of the level structure. */ 00128 00129 num_at_level = 0; 00130 00131 for(inode = 0; inode < num_tnodes; inode++) 00132 { 00133 if(tnode_fanin_left[inode] == 0) 00134 { 00135 num_at_level++; 00136 nodes_at_level_head = 00137 insert_in_int_list(nodes_at_level_head, inode, 00138 &free_list_head); 00139 } 00140 } 00141 00142 alloc_ivector_and_copy_int_list(&nodes_at_level_head, num_at_level, 00143 &tnodes_at_level[0], &free_list_head); 00144 00145 num_levels = 0; 00146 00147 while(num_at_level != 0) 00148 { /* Until there's nothing in the queue. */ 00149 num_levels++; 00150 num_at_level = 0; 00151 00152 for(i = 0; i < tnodes_at_level[num_levels - 1].nelem; i++) 00153 { 00154 inode = tnodes_at_level[num_levels - 1].list[i]; 00155 tedge = tnode[inode].out_edges; 00156 num_edges = tnode[inode].num_edges; 00157 00158 for(iedge = 0; iedge < num_edges; iedge++) 00159 { 00160 to_node = tedge[iedge].to_node; 00161 tnode_fanin_left[to_node]--; 00162 00163 if(tnode_fanin_left[to_node] == 0) 00164 { 00165 num_at_level++; 00166 nodes_at_level_head = 00167 insert_in_int_list 00168 (nodes_at_level_head, to_node, 00169 &free_list_head); 00170 } 00171 } 00172 } 00173 00174 alloc_ivector_and_copy_int_list(&nodes_at_level_head, 00175 num_at_level, 00176 &tnodes_at_level[num_levels], 00177 &free_list_head); 00178 } 00179 00180 tnodes_at_level = 00181 (struct s_ivec *)my_realloc(tnodes_at_level, 00182 num_levels * sizeof(struct s_ivec)); 00183 num_tnode_levels = num_levels; 00184 00185 free(tnode_fanin_left); 00186 free_int_list(&free_list_head); 00187 return (num_sinks); 00188 } 00189 00190 /** Checks the timing graph to see that: (1) all the tnodes have been put 00191 * into some level of the timing graph; 00192 */ 00193 void 00194 check_timing_graph(int num_sinks) 00195 { 00196 00197 /* Addition error checks that need to be done but not yet implemented: (2) the number of primary inputs * 00198 * to the timing graph is equal to the number of input pads + the number of * 00199 * constant generators; and (3) the number of sinks (nodes with no fanout) * 00200 * equals the number of output pads + the number of flip flops. */ 00201 00202 int num_tnodes_check, ilevel, error, num_p_inputs, num_p_outputs; 00203 00204 error = 0; 00205 num_tnodes_check = 0; 00206 num_p_inputs = 0; 00207 num_p_outputs = 0; 00208 /* TODO: Rework error checks for I/Os*/ 00209 00210 for(ilevel = 0; ilevel < num_tnode_levels; ilevel++) 00211 num_tnodes_check += tnodes_at_level[ilevel].nelem; 00212 00213 if(num_tnodes_check != num_tnodes) 00214 { 00215 printf 00216 ("Error in check_timing_graph: %d tnodes appear in the tnode level " 00217 "structure. Expected %d.\n", num_tnodes_check, num_tnodes); 00218 printf("Check the netlist for combinational cycles.\n"); 00219 error++; 00220 } 00221 /* Todo: Add error checks that # of flip-flops, memories, and other 00222 black boxes match # of sinks/sources*/ 00223 00224 if(error != 0) 00225 { 00226 printf("Found %d Errors in the timing graph. Aborting.\n", 00227 error); 00228 exit(1); 00229 } 00230 } 00231 00232 /** Prints one tnode on the critical path out to fp. Returns the delay to 00233 * the next node. 00234 */ 00235 float 00236 print_critical_path_node(FILE * fp, 00237 t_linked_int * critical_path_node) 00238 { 00239 00240 int inode, iblk, inet, downstream_node; 00241 t_pb_graph_pin * pb_graph_pin; 00242 t_tnode_type type; 00243 static char *tnode_type_names[] = { "INPAD_SOURCE", "INPAD_OPIN", "OUTPAD_IPIN", "OUTPAD_SINK", 00244 "CB_IPIN", "CB_OPIN", "INTERMEDIATE_NODE", "PRIMITIVE_IPIN", "PRIMITIVE_OPIN", 00245 "FF_IPIN", "FF_OPIN", 00246 "FF_SINK", "FF_SOURCE", 00247 "CONSTANT_GEN_SOURCE"}; 00248 00249 t_linked_int *next_crit_node; 00250 float Tdel; 00251 00252 inode = critical_path_node->data; 00253 type = tnode[inode].type; 00254 iblk = tnode[inode].block; 00255 pb_graph_pin = tnode[inode].pb_graph_pin; 00256 00257 00258 fprintf(fp, "Node: %d %s Block #%d (%s)\n", inode, 00259 tnode_type_names[type], iblk, block[iblk].name); 00260 00261 if(pb_graph_pin == NULL) { 00262 assert(type == INPAD_SOURCE || type == OUTPAD_SINK || type == FF_SOURCE || type == FF_SINK ); 00263 } 00264 00265 if(pb_graph_pin != NULL) { 00266 fprintf(fp, "Pin: %s.%s[%d] ", pb_graph_pin->parent_node->pb_type->name, 00267 pb_graph_pin->port->name, pb_graph_pin->pin_number); 00268 } 00269 if(type != INPAD_SOURCE && type != OUTPAD_SINK) 00270 { 00271 fprintf(fp, "\n"); 00272 } 00273 00274 fprintf(fp, "T_arr: %g T_req: %g ", tnode[inode].T_arr, 00275 tnode[inode].T_req); 00276 00277 next_crit_node = critical_path_node->next; 00278 if(next_crit_node != NULL) 00279 { 00280 downstream_node = next_crit_node->data; 00281 Tdel = tnode[downstream_node].T_arr - tnode[inode].T_arr; 00282 fprintf(fp, "Tdel: %g\n", Tdel); 00283 } 00284 else 00285 { /* last node, no Tdel. */ 00286 Tdel = 0.; 00287 fprintf(fp, "\n"); 00288 } 00289 00290 if(type == CB_OPIN) { 00291 inet = block[iblk].pb->rr_graph[pb_graph_pin->pin_count_in_cluster].net_num; 00292 inet = vpack_to_clb_net_mapping[inet]; 00293 fprintf(fp, "External-to-Block Net: #%d (%s). Pins on net: %d.\n", 00294 inet, clb_net[inet].name, (clb_net[inet].num_sinks + 1)); 00295 } else if (pb_graph_pin != NULL) { 00296 inet = block[iblk].pb->rr_graph[pb_graph_pin->pin_count_in_cluster].net_num; 00297 fprintf(fp, "Internal Net: #%d (%s). Pins on net: %d.\n", 00298 inet, vpack_net[inet].name, (vpack_net[inet].num_sinks + 1)); 00299 } 00300 00301 00302 fprintf(fp, "\n"); 00303 return (Tdel); 00304 }