VPR-6.0

vpr/SRC/timing/path_delay.c

Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <string.h>
00003 
00004 #include "util.h"
00005 #include "vpr_types.h"
00006 #include "globals.h"
00007 #include "path_delay.h"
00008 #include "path_delay2.h"
00009 #include "net_delay.h"
00010 #include "vpr_utils.h"
00011 #include <assert.h>
00012 #include "read_xml_arch_file.h"
00013 
00014 /****************** Timing graph Structure ************************************
00015  *                                                                            *
00016  * In the timing graph I create, input pads and constant generators have no   *
00017  * inputs; everything else has inputs.  Every input pad and output pad is     *
00018  * represented by two tnodes -- an input pin and an output pin.  For an input *
00019  * pad the input pin comes from off chip and has no fanin, while the output   *
00020  * pin drives outpads and/or CBs.  For output pads, the input node is driven *
00021  * by a CB or input pad, and the output node goes off chip and has no        *
00022  * fanout (out-edges).  I need two nodes to respresent things like pads       *
00023  * because I mark all delay on tedges, not on tnodes.                         *
00024  *                                                                            *
00025  * Every used (not OPEN) CB pin becomes a timing node.  As well, every used  *
00026  * subblock pin within a CB also becomes a timing node.  Unused (OPEN) pins  *
00027  * don't create any timing nodes. If a subblock is used in combinational mode *
00028  * (i.e. its clock pin is open), I just hook the subblock input tnodes to the *
00029  * subblock output tnode.  If the subblock is used in sequential mode, I      *
00030  * create two extra tnodes.  One is just the subblock clock pin, which is     *
00031  * connected to the subblock output.  This means that FFs don't generate      *
00032  * their output until their clock arrives.  For global clocks coming from an  *
00033  * input pad, the delay of the clock is 0, so the FFs generate their outputs  *
00034  * at T = 0, as usual.  For locally-generated or gated clocks, however, the   *
00035  * clock will arrive later, and the FF output will be generated later.  This  *
00036  * lets me properly model things like ripple counters and gated clocks.  The  *
00037  * other extra node is the FF storage node (i.e. a sink), which connects to   *
00038  * the subblock inputs and has no fanout.                                     *
00039  *                                                                            *
00040  * One other subblock that needs special attention is a constant generator.   *
00041  * This has no used inputs, but its output is used.  I create an extra tnode, *
00042  * a dummy input, in addition to the output pin tnode.  The dummy tnode has   *
00043  * no fanin.  Since constant generators really generate their outputs at T =  *
00044  * -infinity, I set the delay from the input tnode to the output to a large-  *
00045  * magnitude negative number.  This guarantees every block that needs the     *
00046  * output of a constant generator sees it available very early.               *
00047  *                                                                            *
00048  * For this routine to work properly, subblocks whose outputs are unused must *
00049  * be completely empty -- all their input pins and their clock pin must be    *
00050  * OPEN.  Check_netlist checks the input netlist to guarantee this -- don't   *
00051  * disable that check.                                                        *
00052  *                                                                            *
00053  * NB:  The discussion below is only relevant for circuits with multiple      *
00054  * clocks.  For circuits with a single clock, everything I do is exactly      *
00055  * correct.                                                                   *
00056  *                                                                            *
00057  * A note about how I handle FFs:  By hooking the clock pin up to the FF      *
00058  * output, I properly model the time at which the FF generates its output.    *
00059  * I don't do a completely rigorous job of modelling required arrival time at *
00060  * the FF input, however.  I assume every FF and outpad needs its input at    *
00061  * T = 0, which is when the earliest clock arrives.  This can be conservative *
00062  * -- a fuller analysis would be to do a fast path analysis of the clock      *
00063  * feeding each FF and subtract its earliest arrival time from the delay of   *
00064  * the D signal to the FF input.  This is too much work, so I'm not doing it. *
00065  * Alternatively, when one has N clocks, it might be better to just do N      *
00066  * separate timing analyses, with only signals from FFs clocked on clock i    *
00067  * being propagated forward on analysis i, and only FFs clocked on i being    *
00068  * considered as sinks.  This gives all the critical paths within clock       *
00069  * domains, but ignores interactions.  Instead, I assume all the clocks are   *
00070  * more-or-less synchronized (they might be gated or locally-generated, but   *
00071  * they all have the same frequency) and explore all interactions.  Tough to  *
00072  * say what's the better way.  Since multiple clocks aren't important for my  *
00073  * work, it's not worth bothering about much.                                 *
00074  *                                                                            *
00075  ******************************************************************************/
00076 
00077 #define T_CONSTANT_GENERATOR -1000      /**< Essentially -ve infinity */
00078 
00079 /***************** Types local to this module ***************************/
00080 
00081 enum e_subblock_pin_type
00082 { SUB_INPUT = 0, SUB_OUTPUT, SUB_CLOCK, NUM_SUB_PIN_TYPES };
00083 
00084 /***************** Variables local to this module ***************************/
00085 
00086 /**@{*/
00087 /** Variables for "chunking" the tedge memory.  If the head pointer is NULL, 
00088  * no timing graph exists now.                                              
00089  */
00090 static struct s_linked_vptr *tedge_ch_list_head = NULL;
00091 static int tedge_ch_bytes_avail = 0;
00092 static char *tedge_ch_next_avail = NULL;
00093 /**@}*/
00094 
00095 static struct s_net *timing_nets = NULL;
00096 static int num_timing_nets = 0;
00097 
00098 /***************** Subroutines local to this module *************************/
00099 
00100 static float **alloc_net_slack();
00101 
00102 static void compute_net_slacks(float **net_slack);
00103 
00104 static void build_cb_tnodes(int iblk);
00105 
00106 static void alloc_and_load_tnodes(t_timing_inf timing_inf);
00107 
00108 static void alloc_and_load_tnodes_from_prepacked_netlist(float block_delay, float inter_cluster_net_delay);
00109 
00110 static void load_tnode(INP t_pb_graph_pin *pb_graph_pin, INP int iblock, INOUTP int *inode, INP t_timing_inf timing_inf);
00111 
00112 static void normalize_costs(float t_crit, long max_critical_input_paths, long max_critical_output_paths);
00113 
00114 static void print_primitive_as_blif (FILE *fpout, int iblk);
00115 
00116 
00117 
00118 /********************* Subroutine definitions *******************************/
00119 
00120 /** This routine builds the graph used for timing analysis.  Every cb pin is a 
00121  * timing node (tnode).  The connectivity between pins is 
00122  * represented by timing edges (tedges).  All delay is marked on edges, not 
00123  * on nodes.  This routine returns an array that will store slack values:   
00124  * net_slack[0..num_nets-1][1..num_pins-1].                                 
00125  */
00126 float **
00127 alloc_and_load_timing_graph(t_timing_inf timing_inf)
00128 {
00129 
00130 /* The are below are valid only for CBs, not pads.                  */
00131 
00132 /* Array for mapping from a pin on a block to a tnode index. For pads, only *
00133  * the first two pin locations are used (input to pad is first, output of   *
00134  * pad is second).  For CLBs, all OPEN pins on the cb have their mapping   *
00135  * set to OPEN so I won't use it by mistake.                                */
00136 
00137     int num_sinks;
00138     float **net_slack;          /* [0..num_nets-1][1..num_pins-1]. */
00139 
00140 /************* End of variable declarations ********************************/
00141 
00142     if(tedge_ch_list_head != NULL)
00143         {
00144             printf("Error in alloc_and_load_timing_graph:\n"
00145                    "\tAn old timing graph still exists.\n");
00146             exit(1);
00147         }
00148         num_timing_nets = num_nets;
00149         timing_nets = clb_net;
00150 
00151         alloc_and_load_tnodes(timing_inf);
00152 
00153     num_sinks = alloc_and_load_timing_graph_levels();
00154 
00155         #ifdef CREATE_ECHO_FILES
00156                 print_timing_graph("initial_timing_graph.echo");
00157         #endif
00158 
00159         check_timing_graph(num_sinks);
00160         
00161     net_slack = alloc_net_slack();
00162 
00163         return (net_slack);
00164 }
00165 
00166 /** This routine builds the graph used for timing analysis.  Every technology mapped netlist pin is a 
00167  * timing node (tnode).  The connectivity between pins is 
00168  * represented by timing edges (tedges).  All delay is marked on edges, not 
00169  * on nodes.  This routine returns an array that will store slack values:   
00170  * net_slack[0..num_nets-1][1..num_pins-1].                                 
00171  */
00172 float** alloc_and_load_pre_packing_timing_graph(float block_delay, float inter_cluster_net_delay, t_model *models)
00173 {
00174 
00175 /* The are below are valid only for CBs, not pads.                  */
00176     
00177 /* Array for mapping from a pin on a block to a tnode index. For pads, only *
00178  * the first two pin locations are used (input to pad is first, output of   *
00179  * pad is second).  For CLBs, all OPEN pins on the cb have their mapping   *
00180  * set to OPEN so I won't use it by mistake.                                */
00181 
00182     int num_sinks;
00183 
00184         float **net_slack;
00185 
00186 /************* End of variable declarations ********************************/
00187 
00188     if(tedge_ch_list_head != NULL)
00189         {
00190             printf("Error in alloc_and_load_timing_graph:\n"
00191                    "\tAn old timing graph still exists.\n");
00192             exit(1);
00193         }
00194 
00195         num_timing_nets = num_logical_nets;
00196         timing_nets = vpack_net;
00197 
00198         alloc_and_load_tnodes_from_prepacked_netlist(block_delay, inter_cluster_net_delay);
00199 
00200     num_sinks = alloc_and_load_timing_graph_levels();
00201 
00202         net_slack = alloc_net_slack();
00203 
00204         #ifdef CREATE_ECHO_FILES
00205                 print_timing_graph("pre_packing_timing_graph.echo");
00206                 print_timing_graph_as_blif("pre_packing_timing_graph_as_blif.blif", models);
00207         #endif
00208 
00209         check_timing_graph(num_sinks);
00210 
00211         return net_slack;
00212 }
00213 
00214 
00215 /** Allocates the net_slack structure.  Chunk allocated to save space.      */
00216 static float **
00217 alloc_net_slack()
00218 {
00219     float **net_slack;          /* [0..num_nets-1][1..num_pins-1]  */
00220     int inet, j;
00221 
00222     net_slack = (float **)my_malloc(num_timing_nets * sizeof(float *));
00223 
00224     for(inet = 0; inet < num_timing_nets; inet++)
00225         {
00226             net_slack[inet] = (float *)my_chunk_malloc((timing_nets[inet].num_sinks + 1) *
00227                                          sizeof(float), &tedge_ch_list_head,
00228                                          &tedge_ch_bytes_avail,
00229                                          &tedge_ch_next_avail);
00230                 for(j = 0; j <= timing_nets[inet].num_sinks; j++) {
00231                         net_slack[inet][j] = UNDEFINED;
00232                 }
00233         }
00234 
00235     return (net_slack);
00236 }
00237 
00238 /** Sets the delays of the inter-CLB nets to the values specified by          
00239  * net_delay[0..num_nets-1][1..num_pins-1].  These net delays should have    
00240  * been allocated and loaded with the net_delay routines.  This routine      
00241  * marks the corresponding edges in the timing graph with the proper delay.  
00242  */
00243 void
00244 load_timing_graph_net_delays(float **net_delay)
00245 {
00246     int inet, ipin, inode;
00247     t_tedge *tedge;
00248 
00249     for(inet = 0; inet < num_timing_nets; inet++)
00250         {
00251             inode = net_to_driver_tnode[inet];
00252             tedge = tnode[inode].out_edges;
00253 
00254 /* Note that the edges of a tnode corresponding to a CLB or INPAD opin must  *
00255  * be in the same order as the pins of the net driven by the tnode.          */
00256 
00257             for(ipin = 1; ipin < (timing_nets[inet].num_sinks + 1); ipin++)
00258                 tedge[ipin - 1].Tdel = net_delay[inet][ipin];
00259         }
00260 }
00261 
00262 
00263 /** Frees the timing graph data. */
00264 void
00265 free_timing_graph(float **net_slack)
00266 {
00267     if(tedge_ch_list_head == NULL)
00268         {
00269             printf("Error in free_timing_graph: No timing graph to free.\n");
00270             exit(1);
00271         }
00272 
00273     free_chunk_memory(tedge_ch_list_head);
00274     free(tnode);
00275     free(net_to_driver_tnode);
00276     free_ivec_vector(tnodes_at_level, 0, num_tnode_levels - 1);
00277     free(net_slack);
00278 
00279     tedge_ch_list_head = NULL;
00280     tedge_ch_bytes_avail = 0;
00281     tedge_ch_next_avail = NULL;
00282 
00283     tnode = NULL;
00284     num_tnodes = 0;
00285     net_to_driver_tnode = NULL;
00286     tnodes_at_level = NULL;
00287     num_tnode_levels = 0;
00288 }
00289 
00290 
00291 /** Prints the net slacks into a file.                                     */
00292 void
00293 print_net_slack(char *fname,
00294                 float **net_slack)
00295 {
00296     int inet, ipin;
00297     FILE *fp;
00298 
00299     fp = my_fopen(fname, "w", 0);
00300 
00301     fprintf(fp, "Net #\tSlacks\n\n");
00302 
00303     for(inet = 0; inet < num_timing_nets; inet++)
00304         {
00305             fprintf(fp, "%5d", inet);
00306             for(ipin = 1; ipin < (timing_nets[inet].num_sinks + 1); ipin++)
00307                 {
00308                     fprintf(fp, "\t%g", net_slack[inet][ipin]);
00309                 }
00310             fprintf(fp, "\n");
00311         }
00312 }
00313 
00314 /** Count # of tnodes, allocates space, and loads the tnodes and its associated edges */
00315 static void alloc_and_load_tnodes(t_timing_inf timing_inf) {
00316         int i, j, k;
00317         int inode;
00318         int num_nodes_in_block;
00319         int count;
00320         int iblock, irr_node;
00321         int inet, dport, dpin, dblock, dnode;
00322         int normalized_pin, normalization;
00323         t_pb_graph_pin *ipb_graph_pin;
00324         t_rr_node *local_rr_graph, *d_rr_graph;
00325 
00326         net_to_driver_tnode = my_malloc(num_timing_nets * sizeof(int));
00327 
00328         for(i = 0; i < num_timing_nets; i++) {
00329                 net_to_driver_tnode[i] = OPEN;
00330         }
00331 
00332         /* allocate space for tnodes */
00333         num_tnodes = 0;
00334         for(i = 0; i < num_blocks; i++) {
00335                 num_nodes_in_block = 0;
00336                 for(j = 0; j < block[i].pb->pb_graph_node->total_pb_pins; j++) {
00337                         if(block[i].pb->rr_graph[j].net_num != OPEN) {
00338                                 if(block[i].pb->rr_graph[j].pb_graph_pin->type == PB_PIN_INPAD ||
00339                                    block[i].pb->rr_graph[j].pb_graph_pin->type == PB_PIN_OUTPAD ||
00340                                    block[i].pb->rr_graph[j].pb_graph_pin->type == PB_PIN_SEQUENTIAL) {
00341                                         num_nodes_in_block += 2;
00342                                 } else {
00343                                         num_nodes_in_block++;
00344                                 }
00345                         }
00346                 }
00347                 num_tnodes += num_nodes_in_block;
00348         }
00349         tnode = my_calloc(num_tnodes, sizeof(t_tnode));
00350 
00351         /* load tnodes with all info except edge info */
00352         /* populate tnode lookups for edge info */
00353         inode = 0;
00354         for(i = 0; i < num_blocks; i++) {
00355                 for(j = 0; j < block[i].pb->pb_graph_node->total_pb_pins; j++) {
00356                         if(block[i].pb->rr_graph[j].net_num != OPEN) {
00357                                 assert(tnode[inode].pb_graph_pin == NULL);
00358                                 load_tnode(block[i].pb->rr_graph[j].pb_graph_pin, i, &inode, timing_inf);                       
00359                         }
00360                 }
00361         }
00362         assert(inode == num_tnodes);
00363 
00364         /* load edge delays */
00365         for(i = 0; i < num_tnodes; i++) {
00366                 /* 3 primary scenarios for edge delays
00367                 1.  Point-to-point delays inside block
00368                 2.  
00369                 */
00370                 count = 0;
00371                 iblock = tnode[i].block;
00372                 switch (tnode[i].type) {
00373                         case INPAD_OPIN:
00374                         case INTERMEDIATE_NODE:
00375                         case PRIMITIVE_OPIN:
00376                         case FF_OPIN:
00377                         case CB_IPIN:
00378                                 /* fanout is determined by intra-cluster connections */
00379                                 /* Allocate space for edges  */
00380                                 irr_node = tnode[i].pb_graph_pin->pin_count_in_cluster;
00381                                 local_rr_graph = block[iblock].pb->rr_graph;
00382                                 ipb_graph_pin = local_rr_graph[irr_node].pb_graph_pin;
00383 
00384                                 if(ipb_graph_pin->parent_node->pb_type->max_internal_delay != UNDEFINED) {
00385                                         if(pb_max_internal_delay == UNDEFINED) {
00386                                                 pb_max_internal_delay = ipb_graph_pin->parent_node->pb_type->max_internal_delay;
00387                                                 pbtype_max_internal_delay = ipb_graph_pin->parent_node->pb_type;
00388                                         } else if(pb_max_internal_delay < ipb_graph_pin->parent_node->pb_type->max_internal_delay) {
00389                                                 pb_max_internal_delay = ipb_graph_pin->parent_node->pb_type->max_internal_delay;
00390                                                 pbtype_max_internal_delay = ipb_graph_pin->parent_node->pb_type;
00391                                         }
00392                                 }
00393 
00394                                 for(j = 0; j < block[iblock].pb->rr_graph[irr_node].num_edges; j++) {
00395                                         dnode = local_rr_graph[irr_node].edges[j];
00396                                         if((local_rr_graph[dnode].prev_node == irr_node) && (j == local_rr_graph[dnode].prev_edge)) {
00397                                                 count++;
00398                                         }
00399                                 }
00400                                 assert(count > 0);
00401                                 tnode[i].num_edges = count;
00402                                 tnode[i].out_edges = (t_tedge *) my_chunk_malloc(count *
00403                                                             sizeof(t_tedge),
00404                                                             &tedge_ch_list_head,
00405                                                             &tedge_ch_bytes_avail,
00406                                                             &tedge_ch_next_avail);
00407 
00408                                 /* Load edges */
00409                                 count = 0;
00410                                 for(j = 0; j < local_rr_graph[irr_node].num_edges; j++) {
00411                                         dnode = local_rr_graph[irr_node].edges[j];
00412                                         if((local_rr_graph[dnode].prev_node == irr_node) && (j == local_rr_graph[dnode].prev_edge)) {
00413                                                 assert((ipb_graph_pin->output_edges[j]->num_output_pins == 1) &&
00414                                                         (local_rr_graph[ipb_graph_pin->output_edges[j]->output_pins[0]->pin_count_in_cluster].net_num == local_rr_graph[irr_node].net_num));
00415 
00416 
00417                                                 tnode[i].out_edges[count].Tdel = ipb_graph_pin->output_edges[j]->delay_max;
00418                                                 tnode[i].out_edges[count].to_node = local_rr_graph[dnode].tnode->index;
00419                                                 
00420                                                 if(vpack_net[local_rr_graph[irr_node].net_num].is_const_gen == TRUE && tnode[i].type == PRIMITIVE_OPIN) {
00421                                                         tnode[i].out_edges[count].Tdel = T_CONSTANT_GENERATOR;
00422                                                         tnode[i].type = CONSTANT_GEN_SOURCE;
00423                                                 }
00424                                                 
00425                                                 count++;
00426                                         }
00427                                 }
00428                                 assert(count > 0);
00429 
00430                                 break;
00431                         case PRIMITIVE_IPIN:
00432                                 /* Pin info comes from pb_graph block delays
00433                                 */
00434                                 irr_node = tnode[i].pb_graph_pin->pin_count_in_cluster;
00435                                 local_rr_graph = block[iblock].pb->rr_graph;
00436                                 ipb_graph_pin = local_rr_graph[irr_node].pb_graph_pin;
00437                                 tnode[i].num_edges = ipb_graph_pin->num_pin_timing;
00438                                 tnode[i].out_edges = (t_tedge *) my_chunk_malloc(ipb_graph_pin->num_pin_timing *
00439                                                                                                 sizeof(t_tedge),
00440                                                                                                 &tedge_ch_list_head,
00441                                                                                                 &tedge_ch_bytes_avail,
00442                                                                                                 &tedge_ch_next_avail);                                  
00443                                 k = 0;
00444 
00445                                 for(j = 0; j < tnode[i].num_edges; j++) {
00446                                         /* Some outpins aren't used, ignore these.  Only consider output pins that are used */
00447                                         if(local_rr_graph[ipb_graph_pin->pin_timing[j]->pin_count_in_cluster].net_num != OPEN) {
00448                                                 tnode[i].out_edges[k].Tdel = ipb_graph_pin->pin_timing_del_max[j];
00449                                                 tnode[i].out_edges[k].to_node = local_rr_graph[ipb_graph_pin->pin_timing[j]->pin_count_in_cluster].tnode->index;
00450                                                 assert(tnode[i].out_edges[k].to_node != OPEN);
00451                                                 k++;
00452                                         }
00453                                 }
00454                                 tnode[i].num_edges -= (j - k); /* remove unused edges */
00455                                 if(tnode[i].num_edges == 0) {
00456                                         printf(ERRTAG "No timing information for pin %s.%s[%d]\n", tnode[i].pb_graph_pin->parent_node->pb_type->name, tnode[i].pb_graph_pin->port->name,tnode[i].pb_graph_pin->pin_number);
00457                                         exit(1);
00458                                 }
00459                                 break;
00460                         case CB_OPIN:
00461                                 /* load up net info */
00462                                 irr_node = tnode[i].pb_graph_pin->pin_count_in_cluster;
00463                                 local_rr_graph = block[iblock].pb->rr_graph;
00464                                 ipb_graph_pin = local_rr_graph[irr_node].pb_graph_pin;
00465                                 assert(local_rr_graph[irr_node].net_num != OPEN);
00466                                 inet = vpack_to_clb_net_mapping[local_rr_graph[irr_node].net_num];
00467                                 assert(inet != OPEN);
00468                                 net_to_driver_tnode[inet] = i;
00469                                 tnode[i].num_edges = clb_net[inet].num_sinks;
00470                                 tnode[i].out_edges = (t_tedge *) my_chunk_malloc(clb_net[inet].num_sinks *
00471                                                                                                 sizeof(t_tedge),
00472                                                                                                 &tedge_ch_list_head,
00473                                                                                                 &tedge_ch_bytes_avail,
00474                                                                                                 &tedge_ch_next_avail);                                  
00475                                 for(j = 1; j <= clb_net[inet].num_sinks; j++) {
00476                                         dblock = clb_net[inet].node_block[j];
00477                                         normalization = block[dblock].type->num_pins / block[dblock].type->capacity;
00478                                         normalized_pin = clb_net[inet].node_block_pin[j] % normalization;
00479                                         d_rr_graph = block[dblock].pb->rr_graph;
00480                                         dpin = OPEN;
00481                                         dport = OPEN;
00482                                         count = 0;
00483 
00484                                         for(k = 0; k < block[dblock].pb->pb_graph_node->num_input_ports && dpin == OPEN; k++) {
00485                                                 if(normalized_pin >= count && (count + block[dblock].pb->pb_graph_node->num_input_pins[k] > normalized_pin)) {
00486                                                         dpin = normalized_pin - count;
00487                                                         dport = k;
00488                                                         break;
00489                                                 }
00490                                                 count += block[dblock].pb->pb_graph_node->num_input_pins[k];
00491                                         }
00492                                         if(dpin == OPEN) {
00493                                                 for(k = 0; k < block[dblock].pb->pb_graph_node->num_output_ports && dpin == OPEN; k++) {
00494                                                         count += block[dblock].pb->pb_graph_node->num_output_pins[k];
00495                                                 }
00496                                                 for(k = 0; k < block[dblock].pb->pb_graph_node->num_clock_ports && dpin == OPEN; k++) {
00497                                                         if(normalized_pin >= count && (count + block[dblock].pb->pb_graph_node->num_clock_pins[k] > normalized_pin)) {
00498                                                                 dpin = normalized_pin - count;
00499                                                                 dport = k;                                                              
00500                                                         }
00501                                                         count += block[dblock].pb->pb_graph_node->num_clock_pins[k];
00502                                                 }
00503                                                 assert(dpin != OPEN);
00504                                                 assert(inet == vpack_to_clb_net_mapping[d_rr_graph[block[dblock].pb->pb_graph_node->clock_pins[dport][dpin].pin_count_in_cluster].net_num]);                                            
00505                                                 tnode[i].out_edges[j-1].to_node = d_rr_graph[block[dblock].pb->pb_graph_node->clock_pins[dport][dpin].pin_count_in_cluster].tnode->index;
00506                                         } else {
00507                                                 assert(dpin != OPEN);
00508                                                 assert(inet == vpack_to_clb_net_mapping[d_rr_graph[block[dblock].pb->pb_graph_node->input_pins[dport][dpin].pin_count_in_cluster].net_num]);
00509                                                 /* delays are assigned post routing */
00510                                                 tnode[i].out_edges[j-1].to_node = d_rr_graph[block[dblock].pb->pb_graph_node->input_pins[dport][dpin].pin_count_in_cluster].tnode->index;
00511                                         }
00512                                         assert(inet != OPEN);
00513                                 }
00514                                 break;
00515                         case OUTPAD_IPIN:
00516                         case INPAD_SOURCE:
00517                         case OUTPAD_SINK:
00518                         case FF_SINK:
00519                         case FF_SOURCE:
00520                         case FF_IPIN:
00521                                 break;
00522                         default:
00523                                 printf(ERRTAG "Consistency check failed: Unknown tnode type %d\n", tnode[i].type);
00524                                 assert(0);
00525                         break;
00526                 }
00527         }
00528 }
00529 
00530 /** Allocate timing graph for pre packed netlist.
00531  * Count number of tnodes first.
00532  * Then connect up tnodes with edges.
00533  */
00534 static void alloc_and_load_tnodes_from_prepacked_netlist(float block_delay, float inter_cluster_net_delay) {
00535         int i, j, k;
00536         t_model *model;
00537         t_model_ports *model_port;
00538         int inode, inet, iblock;
00539         int incr;
00540         int count;
00541 
00542         net_to_driver_tnode = my_malloc(num_logical_nets * sizeof(int));
00543 
00544         for(i = 0; i < num_logical_nets; i++) {
00545                 net_to_driver_tnode[i] = OPEN;
00546         }
00547 
00548         
00549         /* allocate space for tnodes */
00550         num_tnodes = 0;
00551         for(i = 0; i < num_logical_blocks; i++) {
00552                 model = logical_block[i].model;
00553                 logical_block[i].clock_net_tnode = NULL;
00554                 if(logical_block[i].type == VPACK_INPAD) {
00555                         logical_block[i].output_net_tnodes = my_calloc(1, sizeof(t_tnode**));
00556                         num_tnodes += 2;
00557                 } else if(logical_block[i].type == VPACK_OUTPAD) {
00558                         logical_block[i].input_net_tnodes = my_calloc(1, sizeof(t_tnode**));
00559                         num_tnodes += 2;
00560                 } else {                
00561                         if(logical_block[i].clock_net == OPEN) {
00562                                 incr = 1;
00563                         } else {
00564                                 incr = 2;
00565                         }
00566                         j = 0;
00567                         model_port = model->inputs;
00568                         while(model_port) {
00569                                 if(model_port->is_clock == FALSE) {
00570                                         for(k = 0; k < model_port->size; k++) {
00571                                                 if(logical_block[i].input_nets[j][k] != OPEN) {
00572                                                         num_tnodes += incr;
00573                                                 }
00574                                         }
00575                                         j++;
00576                                 } else {
00577                                         num_tnodes++;
00578                                 }                               
00579                                 model_port = model_port->next;
00580                         }
00581                         logical_block[i].input_net_tnodes = my_calloc(j, sizeof(t_tnode**));
00582                         
00583                         j = 0;
00584                         model_port = model->outputs;
00585                         while(model_port) {
00586                                 for(k = 0; k < model_port->size; k++) {
00587                                         if(logical_block[i].output_nets[j][k] != OPEN) {
00588                                                 num_tnodes += incr;
00589                                         }
00590                                 }
00591                                 j++;
00592                                 model_port = model_port->next;
00593                         }
00594                         logical_block[i].output_net_tnodes = my_calloc(j, sizeof(t_tnode**));
00595                 }
00596         }
00597         tnode = my_calloc(num_tnodes, sizeof(t_tnode));
00598         for(i = 0; i < num_tnodes; i++) {
00599                 tnode[i].index = i;
00600         }
00601 
00602         /* load tnodes, alloc edges for tnodes, load all known tnodes */
00603         inode = 0;
00604         for(i = 0; i < num_logical_blocks; i++) {
00605                 model = logical_block[i].model;
00606                 if(logical_block[i].type == VPACK_INPAD) {
00607                         logical_block[i].output_net_tnodes[0] = my_calloc(1, sizeof(t_tnode*));
00608                         logical_block[i].output_net_tnodes[0][0] = &tnode[inode];
00609                         net_to_driver_tnode[logical_block[i].output_nets[0][0]] = inode;
00610                         tnode[inode].model_pin = 0;
00611                         tnode[inode].model_port = 0;
00612                         tnode[inode].block = i;
00613                         tnode[inode].type = INPAD_OPIN;
00614                         
00615                         tnode[inode].num_edges = vpack_net[logical_block[i].output_nets[0][0]].num_sinks;
00616                         tnode[inode].out_edges = 
00617                                                                 (t_tedge *) my_chunk_malloc(tnode[inode].num_edges *
00618                                                                                                 sizeof(t_tedge),
00619                                                                                                 &tedge_ch_list_head,
00620                                                                                                 &tedge_ch_bytes_avail,
00621                                                                                                 &tedge_ch_next_avail);
00622                         tnode[inode + 1].num_edges = 1;
00623                         tnode[inode + 1].out_edges = 
00624                                 (t_tedge *) my_chunk_malloc(1 *
00625                                                             sizeof(t_tedge),
00626                                                             &tedge_ch_list_head,
00627                                                             &tedge_ch_bytes_avail,
00628                                                             &tedge_ch_next_avail);
00629                         tnode[inode + 1].out_edges->Tdel = 0;
00630                         tnode[inode + 1].out_edges->to_node = inode;
00631                         tnode[inode + 1].T_req = 0;
00632                         tnode[inode + 1].T_arr = 0;
00633                         tnode[inode + 1].type = INPAD_SOURCE;
00634                         tnode[inode + 1].block = i;
00635                         inode += 2;
00636                 } else if (logical_block[i].type == VPACK_OUTPAD) {
00637                         logical_block[i].input_net_tnodes[0] = my_calloc(1, sizeof(t_tnode*));
00638                         logical_block[i].input_net_tnodes[0][0] = &tnode[inode];
00639                         tnode[inode].model_pin = 0;
00640                         tnode[inode].model_port = 0;
00641                         tnode[inode].block = i;
00642                         tnode[inode].type = OUTPAD_IPIN;
00643                         tnode[inode].num_edges = 1;
00644                         tnode[inode].out_edges = 
00645                                 (t_tedge *) my_chunk_malloc(1 *
00646                                                             sizeof(t_tedge),
00647                                                             &tedge_ch_list_head,
00648                                                             &tedge_ch_bytes_avail,
00649                                                             &tedge_ch_next_avail);
00650                         tnode[inode].out_edges->Tdel = 0;
00651                         tnode[inode].out_edges->to_node = inode + 1;
00652                         tnode[inode + 1].T_req = 0;
00653                         tnode[inode + 1].T_arr = 0;
00654                         tnode[inode + 1].type = OUTPAD_SINK;
00655                         tnode[inode + 1].block = i;
00656                         tnode[inode + 1].num_edges = 0;
00657                         tnode[inode + 1].out_edges = NULL;
00658                         tnode[inode + 1].index = inode + 1;
00659                         inode += 2;
00660                 } else {                
00661                         j = 0;
00662                         model_port = model->outputs;
00663                         count = 0;
00664                         while(model_port) {
00665                                 logical_block[i].output_net_tnodes[j] = my_calloc(model_port->size, sizeof(t_tnode*));
00666                                 for(k = 0; k < model_port->size; k++) {
00667                                         if(logical_block[i].output_nets[j][k] != OPEN) {
00668                                                 count++;
00669                                                 tnode[inode].model_pin = k;
00670                                                 tnode[inode].model_port = j;
00671                                                 tnode[inode].block = i;
00672                                                 net_to_driver_tnode[logical_block[i].output_nets[j][k]] = inode;
00673                                                 logical_block[i].output_net_tnodes[j][k] = &tnode[inode];
00674                                                         
00675                                                 tnode[inode].num_edges = vpack_net[logical_block[i].output_nets[j][k]].num_sinks;
00676                                                 tnode[inode].out_edges = 
00677                                                                 (t_tedge *) my_chunk_malloc(tnode[inode].num_edges *
00678                                                                                                 sizeof(t_tedge),
00679                                                                                                 &tedge_ch_list_head,
00680                                                                                                 &tedge_ch_bytes_avail,
00681                                                                                                 &tedge_ch_next_avail);
00682                                                 
00683                                                 if (logical_block[i].clock_net == OPEN) {
00684                                                         tnode[inode].type = PRIMITIVE_OPIN;
00685                                                         inode++;
00686                                                 } else {
00687                                                         tnode[inode].type = FF_OPIN;
00688                                                         tnode[inode + 1].num_edges = 1;
00689                                                         tnode[inode + 1].out_edges = 
00690                                                                 (t_tedge *) my_chunk_malloc(1 *
00691                                                                                                 sizeof(t_tedge),
00692                                                                                                 &tedge_ch_list_head,
00693                                                                                                 &tedge_ch_bytes_avail,
00694                                                                                                 &tedge_ch_next_avail);
00695                                                         tnode[inode + 1].out_edges->to_node = inode;
00696                                                         tnode[inode + 1].out_edges->Tdel = 0;
00697                                                         tnode[inode + 1].type = FF_SOURCE;
00698                                                         tnode[inode + 1].block = i;
00699                                                         inode += 2;
00700                                                 }
00701                                         }
00702                                 }
00703                                 j++;
00704                                 model_port = model_port->next;
00705                         }
00706 
00707                         j = 0;                  
00708                         model_port = model->inputs;
00709                         while(model_port) {
00710                                 if(model_port->is_clock == FALSE) {
00711                                         logical_block[i].input_net_tnodes[j] = my_calloc(model_port->size, sizeof(t_tnode*));
00712                                         for(k = 0; k < model_port->size; k++) {
00713                                                 if(logical_block[i].input_nets[j][k] != OPEN) {
00714                                                         tnode[inode].model_pin = k;
00715                                                         tnode[inode].model_port = j;
00716                                                         tnode[inode].block = i;
00717                                                         logical_block[i].input_net_tnodes[j][k] = &tnode[inode];
00718                                                                 
00719                                                         if (logical_block[i].clock_net == OPEN) {
00720                                                                 tnode[inode].type = PRIMITIVE_IPIN;
00721                                                                 tnode[inode].out_edges = 
00722                                                                                 (t_tedge *) my_chunk_malloc(count *
00723                                                                                                                 sizeof(t_tedge),
00724                                                                                                                 &tedge_ch_list_head,
00725                                                                                                                 &tedge_ch_bytes_avail,
00726                                                                                                                 &tedge_ch_next_avail);
00727                                                                 tnode[inode].num_edges = count;
00728                                                                 inode++;
00729                                                         } else {
00730                                                                 tnode[inode].type = FF_IPIN;
00731                                                                 tnode[inode].num_edges = 1;
00732                                                                 tnode[inode].out_edges = 
00733                                                                         (t_tedge *) my_chunk_malloc(1 *
00734                                                                                                         sizeof(t_tedge),
00735                                                                                                         &tedge_ch_list_head,
00736                                                                                                         &tedge_ch_bytes_avail,
00737                                                                                                         &tedge_ch_next_avail);
00738                                                                 tnode[inode].out_edges->to_node = inode + 1;
00739                                                                 tnode[inode].out_edges->Tdel = 0;
00740                                                                 tnode[inode + 1].type = FF_SINK;
00741                                                                 tnode[inode + 1].num_edges = 0;
00742                                                                 tnode[inode + 1].out_edges = NULL;
00743                                                                 inode += 2;
00744                                                         }
00745                                                 }
00746                                         }                                       
00747                                         j++;
00748                                 } else {
00749                                         if(logical_block[i].clock_net != OPEN) {
00750                                                 assert(logical_block[i].clock_net_tnode == NULL);
00751                                                 logical_block[i].clock_net_tnode = &tnode[inode];
00752                                                 tnode[inode].block = i;
00753                                                 tnode[inode].model_pin = 0;
00754                                                 tnode[inode].model_port = 0;
00755                                                 tnode[inode].num_edges = 0;
00756                                                 tnode[inode].out_edges = NULL;
00757                                                 tnode[inode].type = FF_SINK;
00758                                                 inode++;
00759                                         }
00760                                 }
00761                                 model_port = model_port->next;
00762                         }
00763                 }
00764         }
00765         assert(inode == num_tnodes);
00766 
00767         /* load edge delays */
00768         for(i = 0; i < num_tnodes; i++) {
00769                 /* 3 primary scenarios for edge delays
00770                 1.  Point-to-point delays inside block
00771                 2.  
00772                 */
00773                 count = 0;
00774                 iblock = tnode[i].block;
00775                 switch (tnode[i].type) {
00776                         case INPAD_OPIN:
00777                         case PRIMITIVE_OPIN:
00778                         case FF_OPIN:
00779                                 /* fanout is determined by intra-cluster connections */
00780                                 /* Allocate space for edges  */
00781                                 inet = logical_block[tnode[i].block].output_nets[tnode[i].model_port][tnode[i].model_pin];
00782                                 assert(inet != OPEN);
00783                 
00784                                 for(j = 1; j <= vpack_net[inet].num_sinks; j++) {
00785                                         if(vpack_net[inet].is_const_gen) {
00786                                                 tnode[i].out_edges[j - 1].Tdel = T_CONSTANT_GENERATOR;
00787                                                 tnode[i].type = CONSTANT_GEN_SOURCE;
00788                                         } else {
00789                                                 tnode[i].out_edges[j - 1].Tdel = inter_cluster_net_delay;                                               
00790                                         }
00791                                         assert(logical_block[vpack_net[inet].node_block[j]].input_net_tnodes[vpack_net[inet].node_block_port[j]][vpack_net[inet].node_block_pin[j]] != NULL);
00792                                         if(vpack_net[inet].is_global) {
00793                                                 assert(logical_block[vpack_net[inet].node_block[j]].clock_net == inet);
00794                                                 tnode[i].out_edges[j - 1].to_node = logical_block[vpack_net[inet].node_block[j]].clock_net_tnode->index;
00795                                         } else {
00796                                                 tnode[i].out_edges[j - 1].to_node = logical_block[vpack_net[inet].node_block[j]].input_net_tnodes[vpack_net[inet].node_block_port[j]][vpack_net[inet].node_block_pin[j]]->index;
00797                                         }
00798                                 }
00799                                 assert(tnode[i].num_edges == vpack_net[inet].num_sinks);
00800                                 break;
00801                         case PRIMITIVE_IPIN:
00802                                 model_port = logical_block[iblock].model->outputs;
00803                                 count = 0;
00804                                 j = 0;
00805                                 while(model_port) {
00806                                         for(k = 0; k < model_port->size; k++) {
00807                                                 if(logical_block[iblock].output_nets[j][k] != OPEN) {
00808                                                         tnode[i].out_edges[count].Tdel = block_delay;
00809                                                         tnode[i].out_edges[count].to_node = logical_block[iblock].output_net_tnodes[j][k]->index;
00810                                                         count++;                                                        
00811                                                 }
00812                                                 else {
00813                                                         assert(logical_block[iblock].output_net_tnodes[j][k] == NULL);
00814                                                 }
00815                                         }
00816                                         j++;
00817                                         model_port = model_port->next;
00818                                 }
00819                                 assert(count == tnode[i].num_edges);
00820                                 break;
00821                         case OUTPAD_IPIN:
00822                         case INPAD_SOURCE:
00823                         case OUTPAD_SINK:
00824                         case FF_SINK:
00825                         case FF_SOURCE:
00826                         case FF_IPIN:
00827                                 break;
00828                         default:
00829                                 printf(ERRTAG "Consistency check failed: Unknown tnode type %d\n", tnode[i].type);
00830                                 assert(0);
00831                         break;
00832                 }
00833         }
00834 
00835         for(i = 0; i < num_logical_nets; i++) {
00836                 assert(net_to_driver_tnode[i] != OPEN);
00837         }
00838 }
00839 
00840 static void load_tnode(INP t_pb_graph_pin *pb_graph_pin, INP int iblock, INOUTP int *inode, INP t_timing_inf timing_inf) {
00841         int i;
00842         i = *inode;
00843         tnode[i].pb_graph_pin = pb_graph_pin;
00844         tnode[i].block = iblock;
00845         tnode[i].index = i;
00846         block[iblock].pb->rr_graph[pb_graph_pin->pin_count_in_cluster].tnode = &tnode[i];
00847         if(tnode[i].pb_graph_pin->parent_node->pb_type->blif_model == NULL) {
00848                 assert(tnode[i].pb_graph_pin->type == PB_PIN_NORMAL);
00849                 if(tnode[i].pb_graph_pin->parent_node->parent_pb_graph_node == NULL) {
00850                         if(tnode[i].pb_graph_pin->port->type == IN_PORT) {
00851                                 tnode[i].type = CB_IPIN;                                
00852                         } else {
00853                                 assert(tnode[i].pb_graph_pin->port->type == OUT_PORT);
00854                                 tnode[i].type = CB_OPIN;
00855                         }
00856                 } else {
00857                         tnode[i].type = INTERMEDIATE_NODE;
00858                 }
00859         } else {
00860                 if(tnode[i].pb_graph_pin->type == PB_PIN_INPAD) {
00861                         assert(tnode[i].pb_graph_pin->port->type == OUT_PORT);
00862                         tnode[i].type = INPAD_OPIN;
00863                         tnode[i + 1].num_edges = 1;
00864                         tnode[i + 1].out_edges = 
00865                                 (t_tedge *) my_chunk_malloc(1 *
00866                                                             sizeof(t_tedge),
00867                                                             &tedge_ch_list_head,
00868                                                             &tedge_ch_bytes_avail,
00869                                                             &tedge_ch_next_avail);
00870                         tnode[i + 1].out_edges->Tdel = 0;
00871                         tnode[i + 1].out_edges->to_node = i;
00872                         tnode[i + 1].pb_graph_pin = NULL;
00873                         tnode[i + 1].T_req = 0;
00874                         tnode[i + 1].T_arr = 0;
00875                         tnode[i + 1].type = INPAD_SOURCE;
00876                         tnode[i + 1].block = iblock;
00877                         tnode[i + 1].index = i + 1;
00878                         (*inode)++;
00879                 } else if(tnode[i].pb_graph_pin->type == PB_PIN_OUTPAD) {
00880                         assert(tnode[i].pb_graph_pin->port->type == IN_PORT);
00881                         tnode[i].type = OUTPAD_IPIN;
00882                         tnode[i].num_edges = 1;
00883                         tnode[i].out_edges = 
00884                                 (t_tedge *) my_chunk_malloc(1 *
00885                                                             sizeof(t_tedge),
00886                                                             &tedge_ch_list_head,
00887                                                             &tedge_ch_bytes_avail,
00888                                                             &tedge_ch_next_avail);
00889                         tnode[i].out_edges->Tdel = 0;
00890                         tnode[i].out_edges->to_node = i + 1;
00891                         tnode[i + 1].pb_graph_pin = NULL;
00892                         tnode[i + 1].T_req = 0;
00893                         tnode[i + 1].T_arr = 0;
00894                         tnode[i + 1].type = OUTPAD_SINK;
00895                         tnode[i + 1].block = iblock;
00896                         tnode[i + 1].num_edges = 0;
00897                         tnode[i + 1].out_edges = NULL;
00898                         tnode[i + 1].index = i + 1;
00899                         (*inode)++;
00900                 } else if(tnode[i].pb_graph_pin->type == PB_PIN_SEQUENTIAL) {
00901                         if(tnode[i].pb_graph_pin->port->type == IN_PORT) {
00902                                 tnode[i].type = FF_IPIN;
00903                                 tnode[i].num_edges = 1;
00904                                 tnode[i].out_edges = (t_tedge *) my_chunk_malloc(1 *
00905                                                             sizeof(t_tedge),
00906                                                             &tedge_ch_list_head,
00907                                                             &tedge_ch_bytes_avail,
00908                                                             &tedge_ch_next_avail);
00909                                 tnode[i].out_edges->Tdel = pb_graph_pin->tsu_tco;
00910                                 tnode[i].out_edges->to_node = i + 1;
00911                                 tnode[i + 1].pb_graph_pin = NULL;
00912                                 tnode[i + 1].T_req = 0;
00913                                 tnode[i + 1].T_arr = 0;
00914                                 tnode[i + 1].type = FF_SINK;
00915                                 tnode[i + 1].block = iblock;
00916                                 tnode[i + 1].num_edges = 0;
00917                                 tnode[i + 1].out_edges = NULL;
00918                                 tnode[i + 1].index = i + 1;
00919                         } else {
00920                                 assert(tnode[i].pb_graph_pin->port->type == OUT_PORT);
00921                                 tnode[i].type = FF_OPIN;
00922                                 tnode[i + 1].num_edges = 1;
00923                                 tnode[i + 1].out_edges = (t_tedge *) my_chunk_malloc(1 *
00924                                                             sizeof(t_tedge),
00925                                                             &tedge_ch_list_head,
00926                                                             &tedge_ch_bytes_avail,
00927                                                             &tedge_ch_next_avail);
00928                                 tnode[i + 1].out_edges->Tdel = pb_graph_pin->tsu_tco;
00929                                 tnode[i + 1].out_edges->to_node = i;
00930                                 tnode[i + 1].pb_graph_pin = NULL;
00931                                 tnode[i + 1].T_req = 0;
00932                                 tnode[i + 1].T_arr = 0;
00933                                 tnode[i + 1].type = FF_SOURCE;
00934                                 tnode[i + 1].block = iblock;
00935                                 tnode[i + 1].index = i + 1;
00936                         }
00937                         (*inode)++;
00938                 } else if (tnode[i].pb_graph_pin->type == PB_PIN_CLOCK) {
00939                         tnode[i].type = FF_SINK;
00940                         tnode[i].num_edges = 0;
00941                         tnode[i].out_edges = NULL;                              
00942                 } else {
00943                         if(tnode[i].pb_graph_pin->port->type == IN_PORT) {
00944                                 assert(tnode[i].pb_graph_pin->type == PB_PIN_TERMINAL);
00945                                 tnode[i].type = PRIMITIVE_IPIN;
00946                         } else {
00947                                 assert(tnode[i].pb_graph_pin->port->type == OUT_PORT);
00948                                 assert(tnode[i].pb_graph_pin->type == PB_PIN_TERMINAL);
00949                                 tnode[i].type = PRIMITIVE_OPIN;
00950                         }
00951                 }
00952         }
00953         (*inode)++;
00954 }
00955 
00956 /** Prints the timing graph into a file.           */
00957 void
00958 print_timing_graph(char *fname)
00959 {
00960     FILE *fp;
00961     int inode, iedge, ilevel, i;
00962     t_tedge *tedge;
00963     t_tnode_type itype;
00964     char *tnode_type_names[] = { "INPAD_SOURCE", "INPAD_OPIN", "OUTPAD_IPIN", 
00965                 "OUTPAD_SINK", "CB_IPIN", "CB_OPIN", "INTERMEDIATE_NODE", "PRIMITIVE_IPIN", "PRIMITIVE_OPIN", 
00966                 "FF_IPIN", "FF_OPIN",
00967                 "FF_SINK", "FF_SOURCE",
00968                 "CONSTANT_GEN_SOURCE"
00969     };
00970 
00971 
00972     fp = my_fopen(fname, "w", 0);
00973 
00974     fprintf(fp, "num_tnodes: %d\n", num_tnodes);
00975     fprintf(fp, "Node #\tType\t\tipin\tiblk\t# edges\t"
00976             "Edges (to_node, Tdel)\n\n");
00977 
00978         
00979     for(inode = 0; inode < num_tnodes; inode++)
00980         {
00981             fprintf(fp, "%d\t", inode);
00982 
00983             itype = tnode[inode].type;
00984             fprintf(fp, "%-15.15s\t", tnode_type_names[itype]);
00985 
00986                 if(tnode[inode].pb_graph_pin != NULL) {
00987                         fprintf(fp, "%d\t%d\t", tnode[inode].pb_graph_pin->pin_count_in_cluster,
00988                     tnode[inode].block);
00989                 } else {
00990                         fprintf(fp, "%d\t",  tnode[inode].block);
00991                 }
00992 
00993             fprintf(fp, "%d\t", tnode[inode].num_edges);
00994 
00995                 
00996             tedge = tnode[inode].out_edges;
00997                 for(iedge = 0; iedge < tnode[inode].num_edges; iedge++)
00998                 {
00999                         fprintf(fp, "\t(%4d,%7.3g)", tedge[iedge].to_node,
01000                             tedge[iedge].Tdel);
01001                 }
01002             fprintf(fp, "\n");
01003         }
01004 
01005     fprintf(fp, "\n\nnum_tnode_levels: %d\n", num_tnode_levels);
01006 
01007     for(ilevel = 0; ilevel < num_tnode_levels; ilevel++)
01008         {
01009             fprintf(fp, "\n\nLevel: %d  Num_nodes: %d\nNodes:", ilevel,
01010                     tnodes_at_level[ilevel].nelem);
01011             for(i = 0; i < tnodes_at_level[ilevel].nelem; i++)
01012                 fprintf(fp, "\t%d", tnodes_at_level[ilevel].list[i]);
01013         }
01014 
01015     fprintf(fp, "\n");
01016     fprintf(fp, "\n\nNet #\tNet_to_driver_tnode\n");
01017 
01018     for(i = 0; i < num_nets; i++)
01019         fprintf(fp, "%4d\t%6d\n", i, net_to_driver_tnode[i]);
01020 
01021     fprintf(fp, "\n\nNode #\t\tT_arr\t\tT_req\n\n");
01022 
01023         for(inode = 0; inode < num_tnodes; inode++) {
01024                 fprintf(fp, "%d\t%12g\t%12g\n", inode, tnode[inode].T_arr,
01025                         tnode[inode].T_req);
01026         }
01027 
01028     fclose(fp);
01029 }
01030 
01031 /** Determines the slack of every source-sink pair of block pins in the      
01032  * circuit.  The timing graph must have already been built.  target_cycle_  
01033  * time is the target delay for the circuit -- if 0, the target_cycle_time  
01034  * is set to the critical path found in the timing graph.  This routine     
01035  * loads net_slack, and returns the current critical path delay.            
01036  */
01037 float
01038 load_net_slack(float **net_slack,
01039                float target_cycle_time)
01040 {
01041 
01042     float T_crit, T_arr, Tdel, T_cycle, T_req;
01043     int inode, ilevel, num_at_level, i, num_edges, iedge, to_node;
01044         int total;
01045     t_tedge *tedge;
01046 
01047 /* Reset all arrival times to -ve infinity.  Can't just set to zero or the   *
01048  * constant propagation (constant generators work at -ve infinity) won't     *
01049  * work.                                                                     */
01050 
01051         long max_critical_input_paths = 0;
01052         long max_critical_output_paths = 0;
01053 
01054     for(inode = 0; inode < num_tnodes; inode++)
01055         tnode[inode].T_arr = T_CONSTANT_GENERATOR;
01056 
01057 /* Compute all arrival times with a breadth-first analysis from inputs to   *
01058  * outputs.  Also compute critical path (T_crit).                           */
01059 
01060     T_crit = 0.;
01061 
01062 /* Primary inputs arrive at T = 0. */
01063 
01064     num_at_level = tnodes_at_level[0].nelem;
01065     for(i = 0; i < num_at_level; i++)
01066         {
01067             inode = tnodes_at_level[0].list[i];
01068             tnode[inode].T_arr = 0.;
01069         }
01070 
01071         total = 0;
01072     for(ilevel = 0; ilevel < num_tnode_levels; ilevel++)
01073         {
01074             num_at_level = tnodes_at_level[ilevel].nelem;
01075                 total += num_at_level;
01076 
01077             for(i = 0; i < num_at_level; i++)
01078                 {
01079                     inode = tnodes_at_level[ilevel].list[i];
01080                         if(i == 0) {
01081                                 tnode[i].num_critical_input_paths = 1;
01082                         }
01083                     T_arr = tnode[inode].T_arr;
01084                     num_edges = tnode[inode].num_edges;
01085                     tedge = tnode[inode].out_edges;
01086                     T_crit = max(T_crit, T_arr);
01087 
01088                     for(iedge = 0; iedge < num_edges; iedge++)
01089                         {
01090                             to_node = tedge[iedge].to_node;
01091                             Tdel = tedge[iedge].Tdel;
01092 
01093                                 /* Update number of near critical paths entering tnode */
01094                                         /*check for approximate equality*/
01095                                 if (fabs(tnode[to_node].T_arr - (T_arr + Tdel)) < EQUAL_DEF){
01096                                         tnode[to_node].num_critical_input_paths += tnode[inode].num_critical_input_paths;
01097                                 }
01098                                 else if (tnode[to_node].T_arr < T_arr + Tdel) {
01099                                         tnode[to_node].num_critical_input_paths = tnode[inode].num_critical_input_paths;
01100                                 }
01101 
01102                                 if (tnode[to_node].num_critical_input_paths > max_critical_input_paths)
01103                                         max_critical_input_paths = tnode[to_node].num_critical_input_paths;
01104 
01105 
01106                             tnode[to_node].T_arr =
01107                                 max(tnode[to_node].T_arr, T_arr + Tdel);
01108                         }
01109                 }
01110 
01111         }
01112         assert(total == num_tnodes);
01113 
01114     if(target_cycle_time > 0.)  /* User specified target cycle time */
01115         T_cycle = target_cycle_time;
01116     else                        /* Otherwise, target = critical path */
01117         T_cycle = T_crit;
01118 
01119 /* Compute the required arrival times with a backward breadth-first analysis *
01120  * from sinks (output pads, etc.) to primary inputs.                         */
01121 
01122     for(ilevel = num_tnode_levels - 1; ilevel >= 0; ilevel--)
01123         {
01124             num_at_level = tnodes_at_level[ilevel].nelem;
01125 
01126             for(i = 0; i < num_at_level; i++)
01127                 {
01128                     inode = tnodes_at_level[ilevel].list[i];
01129                     num_edges = tnode[inode].num_edges;
01130 
01131                         if(ilevel == 0) {                               
01132                                 assert(tnode[inode].type == INPAD_SOURCE || tnode[inode].type == FF_SOURCE || tnode[inode].type == CONSTANT_GEN_SOURCE);
01133                         } else {
01134                                 assert(!(tnode[inode].type == INPAD_SOURCE || tnode[inode].type == FF_SOURCE || tnode[inode].type == CONSTANT_GEN_SOURCE));
01135                         }
01136 
01137                     if(num_edges == 0)
01138                         {       /* sink */
01139                                 assert(tnode[inode].type == OUTPAD_SINK || tnode[inode].type == FF_SINK);
01140                             tnode[inode].T_req = T_cycle;
01141                                 tnode[inode].num_critical_output_paths = 1;
01142                         }
01143                     else
01144                         {
01145                                 assert(!(tnode[inode].type == OUTPAD_SINK || tnode[inode].type == FF_SINK));
01146                             tedge = tnode[inode].out_edges;
01147                             to_node = tedge[0].to_node;
01148                             Tdel = tedge[0].Tdel;
01149                             T_req = tnode[to_node].T_req - Tdel;
01150 
01151                                 tnode[inode].num_critical_output_paths = tnode[to_node].num_critical_output_paths;
01152                                 if (tnode[to_node].num_critical_output_paths > max_critical_output_paths)
01153                                         max_critical_output_paths = tnode[to_node].num_critical_output_paths;
01154 
01155                             for(iedge = 1; iedge < num_edges; iedge++)
01156                                 {
01157                                     to_node = tedge[iedge].to_node;
01158                                     Tdel = tedge[iedge].Tdel;
01159 
01160                                         /* Update number of near critical paths affected by output of tnode */
01161                                                 /*check for approximate equality*/
01162                                         if (fabs(tnode[to_node].T_req - Tdel - T_req) < EQUAL_DEF){
01163                                                 tnode[inode].num_critical_output_paths += tnode[to_node].num_critical_output_paths;
01164                                         }
01165                                         else if (tnode[to_node].T_req - Tdel < T_req) {
01166                                                 tnode[inode].num_critical_output_paths = tnode[to_node].num_critical_output_paths;
01167                                         }
01168 
01169                                         if (tnode[to_node].num_critical_output_paths > max_critical_output_paths)
01170                                                 max_critical_output_paths = tnode[to_node].num_critical_output_paths;
01171 
01172                                     T_req =
01173                                         min(T_req,
01174                                             tnode[to_node].T_req - Tdel);
01175                                 }
01176 
01177                             tnode[inode].T_req = T_req;
01178                         }
01179                 }
01180         }
01181 
01182         normalize_costs(T_crit, max_critical_input_paths, max_critical_output_paths);
01183 
01184     compute_net_slacks(net_slack);
01185 
01186     return (T_crit);
01187 }
01188 
01189 
01190 /** Puts the slack of each source-sink pair of block pins in net_slack.     */
01191 static void
01192 compute_net_slacks(float **net_slack)
01193 {
01194     int inet, iedge, inode, to_node, num_edges;
01195     t_tedge *tedge;
01196     float T_arr, Tdel, T_req;
01197 
01198     for(inet = 0; inet < num_timing_nets; inet++)
01199         {
01200             inode = net_to_driver_tnode[inet];
01201             T_arr = tnode[inode].T_arr;
01202             num_edges = tnode[inode].num_edges;
01203             tedge = tnode[inode].out_edges;
01204 
01205             for(iedge = 0; iedge < num_edges; iedge++)
01206                 {
01207                     to_node = tedge[iedge].to_node;
01208                     Tdel = tedge[iedge].Tdel;
01209                     T_req = tnode[to_node].T_req;
01210                     net_slack[inet][iedge + 1] = T_req - T_arr - Tdel;
01211                 }
01212         }
01213 }
01214 
01215 
01216 /** Prints out the critical path to a file.  */
01217 void
01218 print_critical_path(char *fname)
01219 {
01220     t_linked_int *critical_path_head, *critical_path_node;
01221     FILE *fp;
01222     int non_global_nets_on_crit_path, global_nets_on_crit_path;
01223     int tnodes_on_crit_path, inode, iblk, inet;
01224     t_tnode_type type;
01225     float total_net_delay, total_logic_delay, Tdel;
01226 
01227     critical_path_head = allocate_and_load_critical_path();
01228     critical_path_node = critical_path_head;
01229 
01230     fp = my_fopen(fname, "w", 0);
01231 
01232     non_global_nets_on_crit_path = 0;
01233     global_nets_on_crit_path = 0;
01234     tnodes_on_crit_path = 0;
01235     total_net_delay = 0.;
01236     total_logic_delay = 0.;
01237 
01238     while(critical_path_node != NULL)
01239         {
01240             Tdel =
01241                 print_critical_path_node(fp, critical_path_node);
01242             inode = critical_path_node->data;
01243             type = tnode[inode].type;
01244             tnodes_on_crit_path++;
01245 
01246             if(type == CB_OPIN)
01247                 {
01248                     get_tnode_block_and_output_net(inode, &iblk, &inet);
01249 
01250                     if(!timing_nets[inet].is_global)
01251                         non_global_nets_on_crit_path++;
01252                     else
01253                         global_nets_on_crit_path++;
01254 
01255                     total_net_delay += Tdel;
01256                 }
01257             else
01258                 {
01259                     total_logic_delay += Tdel;
01260                 }
01261 
01262             critical_path_node = critical_path_node->next;
01263         }
01264 
01265     fprintf(fp,
01266             "\nTnodes on crit. path: %d  Non-global nets on crit. path: %d."
01267             "\n", tnodes_on_crit_path, non_global_nets_on_crit_path);
01268     fprintf(fp, "Global nets on crit. path: %d.\n", global_nets_on_crit_path);
01269     fprintf(fp, "Total logic delay: %g (s)  Total net delay: %g (s)\n",
01270             total_logic_delay, total_net_delay);
01271 
01272     printf("Nets on crit. path: %d normal, %d global.\n",
01273            non_global_nets_on_crit_path, global_nets_on_crit_path);
01274 
01275     printf("Total logic delay: %g (s)  Total net delay: %g (s)\n",
01276            total_logic_delay, total_net_delay);
01277 
01278     fclose(fp);
01279     free_int_list(&critical_path_head);
01280 }
01281 
01282 /** Finds the critical path and puts a list of the tnodes on the critical    
01283  * path in a linked list, from the path SOURCE to the path SINK.            
01284  */
01285 t_linked_int *
01286 allocate_and_load_critical_path(void)
01287 {
01288 
01289     t_linked_int *critical_path_head, *curr_crit_node, *prev_crit_node;
01290     int inode, iedge, to_node, num_at_level, i, crit_node, num_edges;
01291     float min_slack, slack;
01292     t_tedge *tedge;
01293 
01294     num_at_level = tnodes_at_level[0].nelem;
01295     min_slack = HUGE_FLOAT;
01296     crit_node = OPEN;           /* Stops compiler warnings. */
01297 
01298     for(i = 0; i < num_at_level; i++)
01299         {                       /* Path must start at SOURCE (no inputs) */
01300             inode = tnodes_at_level[0].list[i];
01301             slack = tnode[inode].T_req - tnode[inode].T_arr;
01302 
01303             if(slack < min_slack)
01304                 {
01305                     crit_node = inode;
01306                     min_slack = slack;
01307                 }
01308         }
01309 
01310     critical_path_head = (t_linked_int *) my_malloc(sizeof(t_linked_int));
01311     critical_path_head->data = crit_node;
01312     prev_crit_node = critical_path_head;
01313     num_edges = tnode[crit_node].num_edges;
01314 
01315     while(num_edges != 0)
01316         {                       /* Path will end at SINK (no fanout) */
01317             curr_crit_node = (t_linked_int *) my_malloc(sizeof(t_linked_int));
01318             prev_crit_node->next = curr_crit_node;
01319             tedge = tnode[crit_node].out_edges;
01320             min_slack = HUGE_FLOAT;
01321 
01322             for(iedge = 0; iedge < num_edges; iedge++)
01323                 {
01324                     to_node = tedge[iedge].to_node;
01325                     slack = tnode[to_node].T_req - tnode[to_node].T_arr;
01326 
01327                     if(slack < min_slack)
01328                         {
01329                             crit_node = to_node;
01330                             min_slack = slack;
01331                         }
01332                 }
01333 
01334             curr_crit_node->data = crit_node;
01335             prev_crit_node = curr_crit_node;
01336             num_edges = tnode[crit_node].num_edges;
01337         }
01338 
01339     prev_crit_node->next = NULL;
01340     return (critical_path_head);
01341 }
01342 
01343 /** Returns the index of the block that this tnode is part of.  If the tnode 
01344  * is a CB_OPIN or INPAD_OPIN (i.e. if it drives a net), the net index is  
01345  * returned via inet_ptr.  Otherwise inet_ptr points at OPEN.               
01346  */
01347 void
01348 get_tnode_block_and_output_net(int inode,
01349                                int *iblk_ptr,
01350                                int *inet_ptr)
01351 {
01352 
01353     int inet, ipin, iblk;
01354     t_tnode_type tnode_type;
01355 
01356     iblk = tnode[inode].block;
01357     tnode_type = tnode[inode].type;
01358 
01359     if(tnode_type == CB_OPIN)
01360         {
01361             ipin = tnode[inode].pb_graph_pin->pin_count_in_cluster;
01362                 inet = block[iblk].pb->rr_graph[ipin].net_num;
01363                 assert(inet != OPEN);
01364                 inet = vpack_to_clb_net_mapping[inet];
01365         }
01366     else
01367         {
01368             inet = OPEN;
01369         }
01370 
01371     *iblk_ptr = iblk;
01372     *inet_ptr = inet;
01373 }
01374 
01375 /** Does a timing analysis (simple) where it assumes that each net has a      
01376  * constant delay value.  Used only when operation == TIMING_ANALYSIS_ONLY.  
01377  */
01378 void
01379 do_constant_net_delay_timing_analysis(t_timing_inf timing_inf,
01380                                       float constant_net_delay_value)
01381 {
01382 
01383     struct s_linked_vptr *net_delay_chunk_list_head;
01384     float **net_delay, **net_slack;
01385 
01386     float T_crit;
01387 
01388     net_slack = alloc_and_load_timing_graph(timing_inf);
01389     net_delay = alloc_net_delay(&net_delay_chunk_list_head, timing_nets, num_timing_nets);
01390 
01391     load_constant_net_delay(net_delay, constant_net_delay_value, timing_nets, num_timing_nets);
01392     load_timing_graph_net_delays(net_delay);
01393     T_crit = load_net_slack(net_slack, 0);
01394 
01395     printf("\n");
01396     printf("\nCritical Path: %g (s)\n", T_crit);
01397 
01398 #ifdef CREATE_ECHO_FILES
01399     print_critical_path("critical_path.echo");
01400     print_timing_graph("timing_graph.echo");
01401     print_net_slack("net_slack.echo", net_slack);
01402     print_net_delay(net_delay, "net_delay.echo", timing_nets, num_timing_nets);
01403 #endif /* CREATE_ECHO_FILES */
01404 
01405     free_timing_graph(net_slack);
01406     free_net_delay(net_delay, &net_delay_chunk_list_head);
01407 }
01408 
01409 static void normalize_costs(float t_crit, long max_critical_input_paths, long max_critical_output_paths) {
01410         int i;
01411         for(i = 0; i < num_tnodes; i++) {
01412                 tnode[i].normalized_slack = ((float)tnode[i].T_req - tnode[i].T_arr) / t_crit;
01413                 tnode[i].normalized_T_arr = (float)tnode[i].T_arr/(float)t_crit;
01414                 tnode[i].normalized_total_critical_paths = ((float)tnode[i].num_critical_input_paths + tnode[i].num_critical_output_paths) / ((float)max_critical_input_paths + max_critical_output_paths);
01415         }
01416 }
01417 
01418 
01419 
01420 
01421 /** Prints out the critical path to a file.  */
01422 void
01423 print_timing_graph_as_blif(char *fname, t_model *models)
01424 {
01425         struct s_model_ports *port;
01426         struct s_linked_vptr *p_io_removed;
01427 
01428     FILE *fp;
01429         int i, j;
01430 
01431     fp = my_fopen(fname, "w", 0);
01432 
01433         fprintf(fp, ".model %s\n", blif_circuit_name);
01434         
01435         fprintf(fp, ".inputs ");
01436         for(i = 0; i < num_logical_blocks; i++) {
01437                 if(logical_block[i].type == VPACK_INPAD) {
01438                         fprintf(fp, "\\\n%s ", logical_block[i].name);
01439                 }
01440         }
01441         p_io_removed = circuit_p_io_removed;
01442         while(p_io_removed) {
01443                 fprintf(fp, "\\\n%s ", (char *) p_io_removed->data_vptr);
01444                 p_io_removed = p_io_removed->next;
01445         }
01446 
01447         fprintf(fp, "\n");
01448         
01449         fprintf(fp, ".outputs ");
01450         for(i = 0; i < num_logical_blocks; i++) {
01451                 if(logical_block[i].type == VPACK_OUTPAD) {
01452                         /* Outputs have a "out:" prepended to them, must remove */
01453                         fprintf(fp, "\\\n%s ", &logical_block[i].name[4]);
01454                 }
01455         }
01456         fprintf(fp, "\n");
01457         fprintf(fp, ".names unconn\n");
01458         fprintf(fp, " 0\n\n");
01459 
01460         /* Print out primitives */
01461         for(i = 0; i < num_logical_blocks; i++) {
01462                 print_primitive_as_blif(fp, i);
01463         }
01464 
01465         /* Print out tnode connections */
01466         for(i = 0; i < num_tnodes; i++) {
01467                 if(tnode[i].type != PRIMITIVE_IPIN && tnode[i].type != FF_SOURCE && tnode[i].type != INPAD_SOURCE && tnode[i].type != OUTPAD_IPIN) {
01468                         for(j = 0; j < tnode[i].num_edges; j++) {
01469                                 fprintf(fp, ".names tnode_%d tnode_%d\n", i, tnode[i].out_edges[j]);
01470                                 fprintf(fp, "1 1\n\n");
01471                         }
01472                 }
01473         }
01474         
01475         fprintf(fp, ".end\n\n");
01476 
01477         /* Print out .subckt models */
01478         while(models) {
01479                 fprintf(fp, ".model %s\n", models->name);
01480                 fprintf(fp, ".inputs ");
01481                 port = models->inputs;
01482                 while(port) {
01483                         if(port->size > 1) {
01484                                 for(j = 0; j < port->size; j++) {
01485                                         fprintf(fp, "%s[%d] ", port->name, j);
01486                                 }
01487                         } else {
01488                                 fprintf(fp, "%s ", port->name);
01489                         }
01490                         port = port->next;
01491                 }
01492                 fprintf(fp, "\n");
01493                 fprintf(fp, ".outputs ");
01494                 port = models->outputs;
01495                 while(port) {
01496                         if(port->size > 1) {
01497                                 for(j = 0; j < port->size; j++) {
01498                                         fprintf(fp, "%s[%d] ", port->name, j);
01499                                 }
01500                         } else {
01501                                 fprintf(fp, "%s ", port->name);
01502                         }
01503                         port = port->next;
01504                 }
01505                 fprintf(fp, "\n.blackbox\n.end\n\n");
01506                 fprintf(fp, "\n\n");
01507                 models = models->next;
01508         }
01509     fclose(fp);
01510 }
01511 
01512 /** Print primitives found in timing graph in blif format based on whether this is a logical primitive or a physical primitive */
01513 static void print_primitive_as_blif (FILE *fpout, int iblk) {
01514         int i, j;
01515         struct s_model_ports *port;
01516         struct s_linked_vptr *truth_table;
01517         t_rr_node *irr_graph;
01518         t_pb_graph_node *pb_graph_node;
01519         int node;
01520 
01521         
01522         if(logical_block[iblk].type == VPACK_INPAD) {
01523                 if(logical_block[iblk].pb == NULL) {
01524                         fprintf(fpout, ".names %s tnode_%d\n", logical_block[iblk].name, logical_block[iblk].output_net_tnodes[0][0]->index);
01525                 } else {
01526                         fprintf(fpout, ".names %s tnode_%d\n", logical_block[iblk].name, 
01527                                 logical_block[iblk].pb->rr_graph[logical_block[iblk].pb->pb_graph_node->output_pins[0][0].pin_count_in_cluster].tnode->index);
01528                 }
01529                 fprintf(fpout, "1 1\n\n");
01530         } else if(logical_block[iblk].type == VPACK_OUTPAD) {
01531                 /* outputs have the symbol out: automatically prepended to it, must remove */
01532                 if(logical_block[iblk].pb == NULL) {
01533                         fprintf(fpout, ".names tnode_%d %s\n", logical_block[iblk].input_net_tnodes[0][0]->index, &logical_block[iblk].name[4]);
01534                 } else {
01535                         /* avoid the out: from output pad naming */
01536                         fprintf(fpout, ".names tnode_%d %s\n", 
01537                                 logical_block[iblk].pb->rr_graph[logical_block[iblk].pb->pb_graph_node->input_pins[0][0].pin_count_in_cluster].tnode->index,
01538                                 (logical_block[iblk].name + 4));
01539                 }
01540                 fprintf(fpout, "1 1\n\n");
01541         } else if(strcmp(logical_block[iblk].model->name, "latch") == 0) {
01542                 fprintf(fpout, ".latch ");
01543                 node = OPEN;
01544                 
01545                 if(logical_block[iblk].pb == NULL) {
01546                         i = 0;
01547                         port = logical_block[iblk].model->inputs;
01548                         while(port) {
01549                                 if(!port->is_clock) {
01550                                         assert(port->size == 1);
01551                                         for(j = 0; j < port->size; j++) {
01552                                                 if(logical_block[iblk].input_net_tnodes[i][j] != NULL) {
01553                                                         fprintf(fpout, "tnode_%d ", logical_block[iblk].input_net_tnodes[i][j]->index);
01554                                                 } else {
01555                                                         assert(0);
01556                                                 }
01557                                         }
01558                                         i++;
01559                                 }
01560                                 port = port->next;
01561                         }
01562                         assert(i == 1);
01563 
01564                         i = 0;
01565                         port = logical_block[iblk].model->outputs;
01566                         while(port) {
01567                                 assert(port->size == 1);
01568                                 for(j = 0; j < port->size; j++) {
01569                                         if(logical_block[iblk].output_net_tnodes[i][j] != NULL) {
01570                                                 node = logical_block[iblk].output_net_tnodes[i][j]->index;
01571                                                 fprintf(fpout, "latch_%s re ", logical_block[iblk].name);
01572                                         } else {
01573                                                 assert(0);
01574                                         }
01575                                 }
01576                                 i++;
01577                                 port = port->next;
01578                         }
01579                         assert(i == 1);
01580 
01581                         i = 0;
01582                         port = logical_block[iblk].model->inputs;
01583                         while(port) {
01584                                 if(port->is_clock) {
01585                                         for(j = 0; j < port->size; j++) {
01586                                                 if(logical_block[iblk].clock_net_tnode != NULL) {
01587                                                         fprintf(fpout, "tnode_%d 0\n\n", logical_block[iblk].clock_net_tnode->index);
01588                                                 } else {
01589                                                         assert(0);
01590                                                 }
01591                                         }
01592                                         i++;
01593                                 }
01594                                 port = port->next;
01595                         }
01596                         assert(i == 1);
01597                 } else {
01598                         irr_graph = logical_block[iblk].pb->rr_graph;
01599                         assert(irr_graph[logical_block[iblk].pb->pb_graph_node->input_pins[0][0].pin_count_in_cluster].net_num != OPEN);
01600                         fprintf(fpout, "tnode_%d ", irr_graph[logical_block[iblk].pb->pb_graph_node->input_pins[0][0].pin_count_in_cluster].tnode->index);
01601                         node = irr_graph[logical_block[iblk].pb->pb_graph_node->output_pins[0][0].pin_count_in_cluster].tnode->index;
01602                         fprintf(fpout, "latch_%s re ", logical_block[iblk].name);
01603                         assert(irr_graph[logical_block[iblk].pb->pb_graph_node->clock_pins[0][0].pin_count_in_cluster].net_num != OPEN);
01604                         fprintf(fpout, "tnode_%d 0\n\n", irr_graph[logical_block[iblk].pb->pb_graph_node->clock_pins[0][0].pin_count_in_cluster].tnode->index);
01605                 }
01606                 assert(node != OPEN);
01607                 fprintf(fpout, ".names latch_%s tnode_%d\n", logical_block[iblk].name, node);
01608                 fprintf(fpout, "1 1\n\n");
01609         } else if(strcmp(logical_block[iblk].model->name, "names") == 0) {
01610                 fprintf(fpout, ".names ");
01611                 node = OPEN;
01612 
01613                 if(logical_block[iblk].pb == NULL) {
01614                         i = 0;
01615                         port = logical_block[iblk].model->inputs;
01616                         while(port) {
01617                                 assert(!port->is_clock);
01618                                 for(j = 0; j < port->size; j++) {
01619                                         if(logical_block[iblk].input_net_tnodes[i][j] != NULL) {
01620                                                 fprintf(fpout, "tnode_%d ", logical_block[iblk].input_net_tnodes[i][j]->index);
01621                                         } else {
01622                                                 break;
01623                                         }
01624                                 }
01625                                 i++;
01626                                 port = port->next;
01627                         }
01628                         assert(i == 1);
01629 
01630                         i = 0;
01631                         port = logical_block[iblk].model->outputs;
01632                         while(port) {
01633                                 assert(port->size == 1);
01634                                 fprintf(fpout, "lut_%s\n", logical_block[iblk].name);
01635                                 node = logical_block[iblk].output_net_tnodes[0][0]->index;
01636                                 assert(node != OPEN);                   
01637                                 i++;
01638                                 port = port->next;
01639                         }
01640                         assert(i == 1);
01641                 } else {
01642                         irr_graph = logical_block[iblk].pb->rr_graph;
01643                         assert(logical_block[iblk].pb->pb_graph_node->num_input_ports == 1);
01644                         for(i = 0; i < logical_block[iblk].pb->pb_graph_node->num_input_pins[0]; i++) {
01645                                 if(irr_graph[logical_block[iblk].pb->pb_graph_node->input_pins[0][i].pin_count_in_cluster].net_num != OPEN) {
01646                                         fprintf(fpout, "tnode_%d ", irr_graph[logical_block[iblk].pb->pb_graph_node->input_pins[0][i].pin_count_in_cluster].tnode->index);
01647                                 } else {
01648                                         if(i > 0 && i < logical_block[iblk].pb->pb_graph_node->num_input_pins[0] - 1) {
01649                                                 assert(irr_graph[logical_block[iblk].pb->pb_graph_node->input_pins[0][i + 1].pin_count_in_cluster].net_num == OPEN);
01650                                         }
01651                                 }
01652                         }
01653                         assert(logical_block[iblk].pb->pb_graph_node->num_output_ports == 1);
01654                         assert(logical_block[iblk].pb->pb_graph_node->num_output_pins[0] == 1);
01655                         fprintf(fpout, "lut_%s\n", logical_block[iblk].name);
01656                         node = irr_graph[logical_block[iblk].pb->pb_graph_node->output_pins[0][0].pin_count_in_cluster].tnode->index;
01657                 }
01658                 assert(node != OPEN);
01659                 truth_table = logical_block[iblk].truth_table;
01660                 while(truth_table) {
01661                         fprintf(fpout, "%s\n", (char*)truth_table->data_vptr);
01662                         truth_table = truth_table->next;
01663                 }
01664                 fprintf(fpout, "\n");
01665                 fprintf(fpout, ".names lut_%s tnode_%d\n", logical_block[iblk].name, node);
01666                 fprintf(fpout, "1 1\n\n");
01667         } else {
01668                 /* This is a standard .subckt blif structure */
01669                 fprintf(fpout, ".subckt %s ", logical_block[iblk].model->name);
01670                 if(logical_block[iblk].pb == NULL) {
01671                         i = 0;
01672                         port = logical_block[iblk].model->inputs;
01673                         while(port) {
01674                                 if(!port->is_clock) {
01675                                         for(j = 0; j < port->size; j++) {
01676                                                 if(logical_block[iblk].input_net_tnodes[i][j] != NULL) {
01677                                                         if(port->size > 1) {
01678                                                                 fprintf(fpout, "\\\n%s[%d]=tnode_%d ", port->name, j, logical_block[iblk].input_net_tnodes[i][j]->index);
01679                                                         } else {
01680                                                                 fprintf(fpout, "\\\n%s=tnode_%d ", port->name, logical_block[iblk].input_net_tnodes[i][j]->index);
01681                                                         }
01682                                                 } else {
01683                                                         if(port->size > 1) {
01684                                                                 fprintf(fpout, "\\\n%s[%d]=unconn ", port->name, j);
01685                                                         } else {
01686                                                                 fprintf(fpout, "\\\n%s=unconn ", port->name);
01687                                                         }
01688                                                 }
01689                                         }
01690                                         i++;
01691                                 }               
01692                                 port = port->next;
01693                         }
01694 
01695                         i = 0;
01696                         port = logical_block[iblk].model->outputs;
01697                         while(port) {
01698                                 for(j = 0; j < port->size; j++) {
01699                                         if(logical_block[iblk].output_net_tnodes[i][j] != NULL) {
01700                                                 if(port->size > 1) {
01701                                                         fprintf(fpout, "\\\n%s[%d]=%s ", port->name, j, vpack_net[logical_block[iblk].output_nets[i][j]].name);
01702                                                 } else {
01703                                                         fprintf(fpout, "\\\n%s=%s ", port->name, vpack_net[logical_block[iblk].output_nets[i][j]].name);
01704                                                 }
01705                                         } else {
01706                                                 if(port->size > 1) {
01707                                                         fprintf(fpout, "\\\n%s[%d]=unconn_%d_%s_%d ", port->name, j, iblk, port->name, j);
01708                                                 } else {
01709                                                         fprintf(fpout, "\\\n%s=unconn_%d_%s_%d ", port->name, iblk, port->name);
01710                                                 }
01711                                         }
01712                                 }
01713                                 i++;
01714                                 port = port->next;
01715                         }
01716 
01717 
01718                         i = 0;
01719                         port = logical_block[iblk].model->inputs;
01720                         while(port) {
01721                                 if(port->is_clock) {
01722                                         assert(port->size == 1);
01723                                         if(logical_block[iblk].clock_net_tnode != NULL) {
01724                                                 fprintf(fpout, "\\\n%s=tnode_%d ", port->name, logical_block[iblk].clock_net_tnode->index);
01725                                         } else {
01726                                                 fprintf(fpout, "\\\n%s=unconn ", port->name);
01727                                         }
01728                                         i++;
01729                                 }               
01730                                 port = port->next;
01731                         }
01732 
01733                         fprintf(fpout, "\n\n");
01734 
01735                         
01736                         i = 0;
01737                         port = logical_block[iblk].model->outputs;
01738                         while(port) {
01739                                 for(j = 0; j < port->size; j++) {
01740                                         if(logical_block[iblk].output_net_tnodes[i][j] != NULL) {
01741                                                 fprintf(fpout, ".names %s tnode_%d\n", vpack_net[logical_block[iblk].output_nets[i][j]].name, logical_block[iblk].output_net_tnodes[i][j]->index);
01742                                                 fprintf(fpout, "1 1\n\n");
01743                                         }
01744                                 }
01745                                 i++;
01746                                 port = port->next;
01747                         }
01748                 } else {
01749                         irr_graph = logical_block[iblk].pb->rr_graph;
01750                         pb_graph_node = logical_block[iblk].pb->pb_graph_node;
01751                         for(i = 0; i < pb_graph_node->num_input_ports; i++) {
01752                                 for(j = 0; j < pb_graph_node->num_input_pins[i]; j++) {
01753                                         if(irr_graph[pb_graph_node->input_pins[i][j].pin_count_in_cluster].net_num != OPEN) {
01754                                                 if(pb_graph_node->num_input_pins[i] > 1) {
01755                                                         fprintf(fpout, "\\\n%s[%d]=tnode_%d ", pb_graph_node->input_pins[i][j].port->name, j, irr_graph[pb_graph_node->input_pins[i][j].pin_count_in_cluster].tnode->index);
01756                                                 } else {
01757                                                         fprintf(fpout, "\\\n%s=tnode_%d ", pb_graph_node->input_pins[i][j].port->name, irr_graph[pb_graph_node->input_pins[i][j].pin_count_in_cluster].tnode->index);
01758                                                 }
01759                                         } else {
01760                                                 if(pb_graph_node->num_input_pins[i] > 1) {
01761                                                         fprintf(fpout, "\\\n%s[%d]=unconn ", pb_graph_node->input_pins[i][j].port->name, j);
01762                                                 } else {
01763                                                         fprintf(fpout, "\\\n%s=unconn ", pb_graph_node->input_pins[i][j].port->name);
01764                                                 }
01765                                         }
01766                                 }
01767                         }
01768                         for(i = 0; i < pb_graph_node->num_output_ports; i++) {
01769                                 for(j = 0; j < pb_graph_node->num_output_pins[i]; j++) {
01770                                         if(irr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].net_num != OPEN) {
01771                                                 if(pb_graph_node->num_output_pins[i] > 1) {
01772                                                         fprintf(fpout, "\\\n%s[%d]=%s ", pb_graph_node->output_pins[i][j].port->name, j, 
01773                                                                 vpack_net[irr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].net_num].name);
01774                                                 } else {
01775                                                         fprintf(fpout, "\\\n%s=%s ", pb_graph_node->output_pins[i][j].port->name, 
01776                                                                 vpack_net[irr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].tnode->index].name);
01777                                                 }
01778                                         } else {
01779                                                 if(pb_graph_node->num_output_pins[i] > 1) {
01780                                                         fprintf(fpout, "\\\n%s[%d]=unconn ", pb_graph_node->output_pins[i][j].port->name, j);
01781                                                 } else {
01782                                                         fprintf(fpout, "\\\n%s=unconn ", pb_graph_node->output_pins[i][j].port->name);
01783                                                 }
01784                                         }
01785                                 }
01786                         }
01787                         for(i = 0; i < pb_graph_node->num_clock_ports; i++) {
01788                                 for(j = 0; j < pb_graph_node->num_clock_pins[i]; j++) {
01789                                         if(irr_graph[pb_graph_node->clock_pins[i][j].pin_count_in_cluster].net_num != OPEN) {
01790                                                 if(pb_graph_node->num_clock_pins[i] > 1) {
01791                                                         fprintf(fpout, "\\\n%s[%d]=tnode_%d ", pb_graph_node->clock_pins[i][j].port->name, j, irr_graph[pb_graph_node->clock_pins[i][j].pin_count_in_cluster].tnode->index);
01792                                                 } else {
01793                                                         fprintf(fpout, "\\\n%s=tnode_%d ", pb_graph_node->clock_pins[i][j].port->name, irr_graph[pb_graph_node->clock_pins[i][j].pin_count_in_cluster].tnode->index);
01794                                                 }
01795                                         } else {
01796                                                 if(pb_graph_node->num_clock_pins[i] > 1) {
01797                                                         fprintf(fpout, "\\\n%s[%d]=unconn ", pb_graph_node->clock_pins[i][j].port->name, j);
01798                                                 } else {
01799                                                         fprintf(fpout, "\\\n%s=unconn ", pb_graph_node->clock_pins[i][j].port->name);
01800                                                 }
01801                                         }
01802                                 }
01803                         }
01804 
01805                         fprintf(fpout, "\n\n");
01806                         /* connect up output port names to output tnodes */
01807                         for(i = 0; i < pb_graph_node->num_output_ports; i++) {
01808                                 for(j = 0; j < pb_graph_node->num_output_pins[i]; j++) {
01809                                         if(irr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].net_num != OPEN) {
01810                                                 fprintf(fpout, ".names %s tnode_%d\n", vpack_net[irr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].net_num].name, irr_graph[pb_graph_node->output_pins[i][j].pin_count_in_cluster].tnode->index);
01811                                                 fprintf(fpout, "1 1\n\n");
01812                                         }
01813                                 }
01814                         }
01815                 }
01816         }
01817 }