VPR-6.0

vpr/SRC/timing/path_delay2.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 "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 }