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