VPR-6.0
|
00001 /* 00002 * @file 00003 * 00004 * Jason Luu 2008 00005 * Print complex block information to a file 00006 */ 00007 00008 #include <assert.h> 00009 #include <stdio.h> 00010 #include <stdlib.h> 00011 #include <string.h> 00012 #include "util.h" 00013 #include "vpr_types.h" 00014 #include "globals.h" 00015 #include "output_clustering.h" 00016 #include "read_xml_arch_file.h" 00017 00018 #define LINELENGTH 1024 00019 #define TAB_LENGTH 4 00020 00021 /****************** Subroutines local to this module ************************/ 00022 00023 00024 /**************** Subroutine definitions ************************************/ 00025 00026 static void print_tabs(FILE *fpout, int num_tabs) { 00027 int i; 00028 for(i = 0; i < num_tabs; i++) { 00029 fprintf(fpout, "\t"); 00030 } 00031 } 00032 00033 /** Prints string without making any lines longer than LINELENGTH. Column 00034 * points to the column in which the next character will go (both used and 00035 * updated), and fpout points to the output file. 00036 */ 00037 static void 00038 print_string(char *str_ptr, 00039 int *column, 00040 int num_tabs, 00041 FILE * fpout) 00042 { 00043 00044 int len; 00045 00046 len = strlen(str_ptr); 00047 if(len + 3 > LINELENGTH) 00048 { 00049 printf 00050 ("Error in print_string: String %s is too long for desired\n" 00051 "maximum line length.\n", str_ptr); 00052 exit(1); 00053 } 00054 00055 if(*column + len + 2 > LINELENGTH) 00056 { 00057 fprintf(fpout, "\n"); 00058 print_tabs(fpout, num_tabs); 00059 *column = num_tabs * TAB_LENGTH; 00060 } 00061 00062 fprintf(fpout, "%s ", str_ptr); 00063 *column += len + 1; 00064 } 00065 00066 00067 /** This routine prints out the vpack_net name (or open) and limits the 00068 * length of a line to LINELENGTH characters by using \ to continue 00069 * lines. net_num is the index of the vpack_net to be printed, while 00070 * column points to the current printing column (column is both 00071 * used and updated by this routine). fpout is the output file 00072 * pointer. 00073 */ 00074 static void 00075 print_net_name(int inet, 00076 int *column, 00077 int num_tabs, 00078 FILE * fpout) 00079 { 00080 00081 char *str_ptr; 00082 00083 if(inet == OPEN) 00084 str_ptr = "open"; 00085 else 00086 str_ptr = vpack_net[inet].name; 00087 00088 print_string(str_ptr, column, num_tabs, fpout); 00089 } 00090 00091 /** This routine prints out the vpack_net name (or open) and limits the 00092 * length of a line to LINELENGTH characters by using \ to continue 00093 * lines. net_num is the index of the vpack_net to be printed, while 00094 * column points to the current printing column (column is both 00095 * used and updated by this routine). fpout is the output file 00096 * pointer. 00097 */ 00098 static void 00099 print_interconnect(int inode, 00100 int *column, 00101 int num_tabs, 00102 FILE * fpout) 00103 { 00104 00105 char *str_ptr, *name; 00106 int prev_node, prev_edge; 00107 int len; 00108 00109 if(rr_node[inode].net_num == OPEN) { 00110 print_string("open", column, num_tabs, fpout); 00111 } else { 00112 str_ptr = NULL; 00113 prev_node = rr_node[inode].prev_node; 00114 prev_edge = rr_node[inode].prev_edge; 00115 00116 if(prev_node == OPEN && 00117 rr_node[inode].pb_graph_pin->port->parent_pb_type->num_modes == 0 && 00118 rr_node[inode].pb_graph_pin->port->type == OUT_PORT) { /* This is a primitive output */ 00119 print_net_name(rr_node[inode].net_num, column, num_tabs, fpout); 00120 } else { 00121 name = rr_node[prev_node].pb_graph_pin->output_edges[prev_edge]->interconnect->name; 00122 if(rr_node[prev_node].pb_graph_pin->port->parent_pb_type->depth >= rr_node[inode].pb_graph_pin->port->parent_pb_type->depth) { 00123 /* Connections from siblings or children should have an explicit index, connections from parent does not need an explicit index */ 00124 len = strlen(rr_node[prev_node].pb_graph_pin->parent_node->pb_type->name) + 00125 rr_node[prev_node].pb_graph_pin->parent_node->placement_index / 10 + 00126 strlen(rr_node[prev_node].pb_graph_pin->port->name) + 00127 rr_node[prev_node].pb_graph_pin->pin_number / 10 + 00128 strlen(name) + 11; 00129 str_ptr = my_malloc(len * sizeof(char)); 00130 sprintf(str_ptr, "%s[%d].%s[%d]->%s ", rr_node[prev_node].pb_graph_pin->parent_node->pb_type->name, 00131 rr_node[prev_node].pb_graph_pin->parent_node->placement_index, 00132 rr_node[prev_node].pb_graph_pin->port->name, 00133 rr_node[prev_node].pb_graph_pin->pin_number, 00134 name); 00135 } else { 00136 len = strlen(rr_node[prev_node].pb_graph_pin->parent_node->pb_type->name) + 00137 strlen(rr_node[prev_node].pb_graph_pin->port->name) + 00138 rr_node[prev_node].pb_graph_pin->pin_number / 10 + 00139 strlen(name) + 8; 00140 str_ptr = my_malloc(len * sizeof(char)); 00141 sprintf(str_ptr, "%s.%s[%d]->%s ", rr_node[prev_node].pb_graph_pin->parent_node->pb_type->name, 00142 rr_node[prev_node].pb_graph_pin->port->name, 00143 rr_node[prev_node].pb_graph_pin->pin_number, 00144 name); 00145 } 00146 print_string(str_ptr, column, num_tabs, fpout); 00147 } 00148 if(str_ptr) 00149 free(str_ptr); 00150 } 00151 } 00152 00153 static void print_open_pb_graph_node(t_pb_graph_node * pb_graph_node, int pb_index, boolean is_used, int tab_depth, FILE * fpout) { 00154 int column = 0; 00155 int i, j, k, m; 00156 const t_pb_type * pb_type, * child_pb_type; 00157 t_mode * mode = NULL; 00158 int prev_edge, prev_node; 00159 t_pb_graph_pin *pb_graph_pin; 00160 int mode_of_edge, port_index, node_index; 00161 00162 mode_of_edge = UNDEFINED; 00163 00164 pb_type = pb_graph_node->pb_type; 00165 00166 print_tabs(fpout, tab_depth); 00167 00168 if(is_used) { 00169 /* Determine mode if applicable */ 00170 port_index = 0; 00171 for(i = 0; i < pb_type->num_ports; i++) { 00172 if(pb_type->ports[i].type == OUT_PORT) { 00173 assert(!pb_type->ports[i].is_clock); 00174 for(j = 0; j < pb_type->ports[i].num_pins; j++) { 00175 node_index = pb_graph_node->output_pins[port_index][j].pin_count_in_cluster; 00176 if(pb_type->num_modes > 0 && rr_node[node_index].net_num != OPEN) { 00177 prev_edge = rr_node[node_index].prev_edge; 00178 prev_node = rr_node[node_index].prev_node; 00179 pb_graph_pin = rr_node[prev_node].pb_graph_pin; 00180 mode_of_edge = pb_graph_pin->output_edges[prev_edge]->interconnect->parent_mode_index; 00181 assert(mode == NULL || &pb_type->modes[mode_of_edge] == mode); 00182 mode = &pb_type->modes[mode_of_edge]; 00183 } 00184 } 00185 port_index++; 00186 } 00187 } 00188 00189 assert(mode != NULL && mode_of_edge != UNDEFINED); 00190 fprintf(fpout, "<block name=\"open\" instance=\"%s[%d]\" mode=\"%s\">\n", pb_graph_node->pb_type->name, pb_index, mode->name); 00191 00192 print_tabs(fpout, tab_depth); 00193 fprintf(fpout, "\t<inputs>\n"); 00194 port_index = 0; 00195 for(i = 0; i < pb_type->num_ports; i++) { 00196 if(!pb_type->ports[i].is_clock && pb_type->ports[i].type == IN_PORT) { 00197 print_tabs(fpout, tab_depth); 00198 fprintf(fpout, "\t\t<port name=\"%s\">", pb_graph_node->pb_type->ports[i].name); 00199 for(j = 0; j < pb_type->ports[i].num_pins; j++) { 00200 node_index = pb_graph_node->input_pins[port_index][j].pin_count_in_cluster; 00201 print_interconnect(node_index, &column, tab_depth + 2, fpout); 00202 } 00203 fprintf(fpout, "</port>\n"); 00204 port_index++; 00205 } 00206 } 00207 print_tabs(fpout, tab_depth); 00208 fprintf(fpout, "\t</inputs>\n"); 00209 00210 column = tab_depth * TAB_LENGTH + 8; /* Next column I will write to. */ 00211 print_tabs(fpout, tab_depth); 00212 fprintf(fpout, "\t<outputs>\n"); 00213 port_index = 0; 00214 for(i = 0; i < pb_type->num_ports; i++) { 00215 if(pb_type->ports[i].type == OUT_PORT) { 00216 print_tabs(fpout, tab_depth); 00217 fprintf(fpout, "\t\t<port name=\"%s\">", pb_graph_node->pb_type->ports[i].name); 00218 assert(!pb_type->ports[i].is_clock); 00219 for(j = 0; j < pb_type->ports[i].num_pins; j++) { 00220 node_index = pb_graph_node->output_pins[port_index][j].pin_count_in_cluster; 00221 print_interconnect(node_index, &column, tab_depth + 2, fpout); 00222 } 00223 fprintf(fpout, "</port>\n"); 00224 port_index++; 00225 } 00226 } 00227 print_tabs(fpout, tab_depth); 00228 fprintf(fpout, "\t</outputs>\n"); 00229 00230 column = tab_depth * TAB_LENGTH + 8; /* Next column I will write to. */ 00231 print_tabs(fpout, tab_depth); 00232 fprintf(fpout, "\t<globals>\n"); 00233 port_index = 0; 00234 for(i = 0; i < pb_type->num_ports; i++) { 00235 if(pb_type->ports[i].is_clock && pb_type->ports[i].type == IN_PORT) { 00236 print_tabs(fpout, tab_depth); 00237 fprintf(fpout, "\t\t<port name=\"%s\">", pb_graph_node->pb_type->ports[i].name); 00238 for(j = 0; j < pb_type->ports[i].num_pins; j++) { 00239 node_index = pb_graph_node->clock_pins[port_index][j].pin_count_in_cluster; 00240 print_interconnect(node_index, &column, tab_depth + 2, fpout); 00241 } 00242 fprintf(fpout, "</port>\n"); 00243 port_index++; 00244 } 00245 } 00246 print_tabs(fpout, tab_depth); 00247 fprintf(fpout, "\t</globals>\n"); 00248 00249 if(pb_type->num_modes > 0) { 00250 for(i = 0; i < mode->num_pb_type_children; i++) { 00251 child_pb_type = &mode->pb_type_children[i]; 00252 for(j = 0; j < mode->pb_type_children[i].num_pb; j++) { 00253 port_index = 0; 00254 is_used = FALSE; 00255 for(k = 0; k < child_pb_type->num_ports && !is_used; k++) { 00256 if(child_pb_type->ports[k].type == OUT_PORT) { 00257 for(m = 0; m < child_pb_type->ports[k].num_pins; m++) { 00258 node_index = pb_graph_node->child_pb_graph_nodes[mode_of_edge][i][j].output_pins[port_index][m].pin_count_in_cluster; 00259 if(rr_node[node_index].net_num != OPEN) { 00260 is_used = TRUE; 00261 break; 00262 } 00263 } 00264 port_index++; 00265 } 00266 } 00267 print_open_pb_graph_node(&pb_graph_node->child_pb_graph_nodes[mode_of_edge][i][j], j, is_used, tab_depth+1, fpout); 00268 } 00269 } 00270 } 00271 00272 print_tabs(fpout, tab_depth); 00273 fprintf(fpout, "</block>\n"); 00274 } else { 00275 fprintf(fpout, "<block name=\"open\" instance=\"%s[%d]\"/>\n", pb_graph_node->pb_type->name, pb_index); 00276 } 00277 } 00278 00279 /** Prints out the pb connectivity. Used only when 00280 * the -no_clustering option is selected -- prints out 00281 * basically redundant connection info for a VPACK_LUT + FF 00282 * logic logical_block. 00283 */ 00284 static void 00285 print_basic_pb(FILE * fpout, 00286 int bnum) 00287 { 00288 assert(0); 00289 } 00290 00291 00292 00293 static void print_pb(FILE *fpout, t_pb * pb, int pb_index, int tab_depth) { 00294 00295 int column; 00296 int i, j, k, m; 00297 const t_pb_type *pb_type, *child_pb_type; 00298 t_pb_graph_node *pb_graph_node; 00299 t_mode *mode; 00300 int port_index, node_index; 00301 boolean is_used; 00302 00303 pb_type = pb->pb_graph_node->pb_type; 00304 pb_graph_node = pb->pb_graph_node; 00305 mode = &pb_type->modes[pb->mode]; 00306 column = tab_depth * TAB_LENGTH + 8; /* Next column I will write to. */ 00307 print_tabs(fpout, tab_depth); 00308 if(pb_type->num_modes == 0) { 00309 fprintf(fpout, "<block name=\"%s\" instance=\"%s[%d]\">\n", pb->name, pb_type->name, pb_index); 00310 } else { 00311 fprintf(fpout, "<block name=\"%s\" instance=\"%s[%d]\" mode=\"%s\">\n", pb->name, pb_type->name, pb_index, mode->name); 00312 } 00313 00314 print_tabs(fpout, tab_depth); 00315 fprintf(fpout, "\t<inputs>\n"); 00316 port_index = 0; 00317 for(i = 0; i < pb_type->num_ports; i++) { 00318 if(!pb_type->ports[i].is_clock && pb_type->ports[i].type == IN_PORT) { 00319 print_tabs(fpout, tab_depth); 00320 fprintf(fpout, "\t\t<port name=\"%s\">", pb_graph_node->pb_type->ports[i].name); 00321 for(j = 0; j < pb_type->ports[i].num_pins; j++) { 00322 node_index = pb->pb_graph_node->input_pins[port_index][j].pin_count_in_cluster; 00323 if(pb_type->parent_mode == NULL) { 00324 print_net_name(rr_node[node_index].net_num, &column, tab_depth, fpout); 00325 } else { 00326 print_interconnect(node_index, &column, tab_depth + 2, fpout); 00327 } 00328 } 00329 fprintf(fpout, "</port>\n"); 00330 port_index++; 00331 } 00332 } 00333 print_tabs(fpout, tab_depth); 00334 fprintf(fpout, "\t</inputs>\n"); 00335 00336 column = tab_depth * TAB_LENGTH + 8; /* Next column I will write to. */ 00337 print_tabs(fpout, tab_depth); 00338 fprintf(fpout, "\t<outputs>\n"); 00339 port_index = 0; 00340 for(i = 0; i < pb_type->num_ports; i++) { 00341 if(pb_type->ports[i].type == OUT_PORT) { 00342 assert(!pb_type->ports[i].is_clock); 00343 print_tabs(fpout, tab_depth); 00344 fprintf(fpout, "\t\t<port name=\"%s\">", pb_graph_node->pb_type->ports[i].name); 00345 for(j = 0; j < pb_type->ports[i].num_pins; j++) { 00346 node_index = pb->pb_graph_node->output_pins[port_index][j].pin_count_in_cluster; 00347 print_interconnect(node_index, &column, tab_depth + 2, fpout); 00348 } 00349 fprintf(fpout, "</port>\n"); 00350 port_index++; 00351 } 00352 } 00353 print_tabs(fpout, tab_depth); 00354 fprintf(fpout, "\t</outputs>\n"); 00355 00356 column = tab_depth * TAB_LENGTH + 8; /* Next column I will write to. */ 00357 print_tabs(fpout, tab_depth); 00358 fprintf(fpout, "\t<globals>\n"); 00359 port_index = 0; 00360 for(i = 0; i < pb_type->num_ports; i++) { 00361 if(pb_type->ports[i].is_clock && pb_type->ports[i].type == IN_PORT) { 00362 print_tabs(fpout, tab_depth); 00363 fprintf(fpout, "\t\t<port name=\"%s\">", pb_graph_node->pb_type->ports[i].name); 00364 for(j = 0; j < pb_type->ports[i].num_pins; j++) { 00365 node_index = pb->pb_graph_node->clock_pins[port_index][j].pin_count_in_cluster; 00366 if(pb_type->parent_mode == NULL) { 00367 print_net_name(rr_node[node_index].net_num, &column, tab_depth, fpout); 00368 } else { 00369 print_interconnect(node_index, &column, tab_depth + 2, fpout); 00370 } 00371 } 00372 fprintf(fpout, "</port>\n"); 00373 port_index++; 00374 } 00375 } 00376 print_tabs(fpout, tab_depth); 00377 fprintf(fpout, "\t</globals>\n"); 00378 00379 if(pb_type->num_modes > 0) { 00380 for(i = 0; i < mode->num_pb_type_children; i++) { 00381 for(j = 0; j < mode->pb_type_children[i].num_pb; j++) { 00382 /* If child pb is not used but routing is used, I must print things differently */ 00383 if((pb->child_pbs[i] != NULL) && 00384 (pb->child_pbs[i][j].name != NULL)) { 00385 print_pb(fpout, &pb->child_pbs[i][j], j, tab_depth + 1); 00386 } else { 00387 is_used = FALSE; 00388 child_pb_type = &mode->pb_type_children[i]; 00389 port_index = 0; 00390 00391 for(k = 0; k < child_pb_type->num_ports && !is_used; k++) { 00392 if(child_pb_type->ports[k].type == OUT_PORT) { 00393 for(m = 0; m < child_pb_type->ports[k].num_pins; m++) { 00394 node_index = pb_graph_node->child_pb_graph_nodes[pb->mode][i][j].output_pins[port_index][m].pin_count_in_cluster; 00395 if(rr_node[node_index].net_num != OPEN) { 00396 is_used = TRUE; 00397 break; 00398 } 00399 } 00400 port_index++; 00401 } 00402 } 00403 print_open_pb_graph_node(&pb_graph_node->child_pb_graph_nodes[pb->mode][i][j], j, is_used, tab_depth+1, fpout); 00404 } 00405 } 00406 } 00407 } 00408 print_tabs(fpout, tab_depth); 00409 fprintf(fpout, "</block>\n"); 00410 } 00411 00412 /** Prints out one cluster (clb). Both the external pins and the 00413 * internal connections are printed out. 00414 */ 00415 static void 00416 print_clusters( 00417 t_block *clb, 00418 int num_clusters, 00419 FILE * fpout) 00420 { 00421 int icluster; 00422 00423 for(icluster = 0; icluster < num_clusters; icluster++) 00424 { 00425 rr_node = clb[icluster].pb->rr_graph; 00426 00427 /* TODO: Must do check that total CLB pins match top-level pb pins, perhaps check this earlier? */ 00428 00429 print_pb(fpout, clb[icluster].pb, icluster, 1); 00430 } 00431 } 00432 00433 /** Prints out one cluster (clb). Both the external pins and the 00434 * internal connections are printed out. 00435 */ 00436 static void 00437 print_stats( 00438 t_block *clb, 00439 int num_clusters) { 00440 00441 int ipin, icluster, itype, inet, iblk, num_pins, i; 00442 int MAX_LUT_INPUTS; 00443 int unabsorbable_ffs, total_ffs; 00444 int num_luts_total; 00445 int total_nets_absorbed; 00446 boolean* nets_absorbed; 00447 00448 int *num_clb_types, *num_clb_inputs_used, *num_clb_outputs_used, *num_lut_of_size; 00449 00450 nets_absorbed = NULL; 00451 num_clb_types = num_clb_inputs_used = num_clb_outputs_used = NULL; 00452 00453 num_clb_types = (int*)my_calloc(num_types, sizeof(int)); 00454 num_clb_inputs_used = (int*)my_calloc(num_types, sizeof(int)); 00455 num_clb_outputs_used = (int*)my_calloc(num_types, sizeof(int)); 00456 00457 MAX_LUT_INPUTS = 0; 00458 for(iblk = 0; iblk < num_logical_blocks; iblk++) { 00459 if(strcmp(logical_block[iblk].model->name, "names") == 0) { 00460 MAX_LUT_INPUTS = logical_block[iblk].model->inputs->size; 00461 break; 00462 } 00463 } 00464 num_lut_of_size = (int*)my_calloc(MAX_LUT_INPUTS + 1, sizeof(int)); 00465 00466 00467 nets_absorbed = (boolean *)my_calloc(num_logical_nets, sizeof(boolean)); 00468 for(inet = 0; inet < num_logical_nets; inet++) { 00469 nets_absorbed[inet] = TRUE; 00470 } 00471 00472 unabsorbable_ffs = 0; 00473 total_ffs = 0; 00474 for(iblk = 0; iblk < num_logical_blocks; iblk++) { 00475 if(strcmp(logical_block[iblk].model->name, "names") == 0) { 00476 num_pins = 0; 00477 for(ipin = 0; ipin < logical_block[iblk].model->inputs->size; ipin++) { 00478 if(logical_block[iblk].input_nets[0][ipin] != OPEN) { 00479 num_pins++; 00480 } 00481 } 00482 num_lut_of_size[num_pins]++; 00483 } else if(strcmp(logical_block[iblk].model->name, "latch") == 0) { 00484 if(vpack_net[logical_block[iblk].input_nets[0][0]].num_sinks > 1 || 00485 strcmp(logical_block[vpack_net[logical_block[iblk].input_nets[0][0]].node_block[0]].model->name, "names") != 0) { 00486 unabsorbable_ffs++; 00487 } 00488 total_ffs++; 00489 } 00490 } 00491 printf("\n"); 00492 num_luts_total = 0; 00493 for(i = 0; i <= MAX_LUT_INPUTS; i++) { 00494 printf("%d LUTs of size %d\n", num_lut_of_size[i], i); 00495 num_luts_total += num_lut_of_size[i]; 00496 } 00497 printf("%d LUTs in input netlist\n", num_luts_total); 00498 printf("%d FFs in input netlist\n", total_ffs); 00499 printf("%d FFs in input netlist not absorbable\n", unabsorbable_ffs); 00500 00501 00502 /* Counters used only for statistics purposes. */ 00503 00504 for(icluster = 0; icluster < num_clusters; icluster++) 00505 { 00506 for(ipin = 0; ipin < clb[icluster].type->num_pins; ipin++) { 00507 if(clb[icluster].nets[ipin] != OPEN) { 00508 nets_absorbed[clb[icluster].nets[ipin]] = FALSE; 00509 if(clb[icluster].type->class_inf[clb[icluster].type->pin_class[ipin]].type == RECEIVER) { 00510 num_clb_inputs_used[clb[icluster].type->index]++; 00511 } else if(clb[icluster].type->class_inf[clb[icluster].type->pin_class[ipin]].type == DRIVER){ 00512 num_clb_outputs_used[clb[icluster].type->index]++; 00513 } 00514 } 00515 } 00516 num_clb_types[clb[icluster].type->index]++; 00517 } 00518 00519 for(itype = 0; itype < num_types; itype++) { 00520 if(num_clb_types[itype] == 0) { 00521 printf("\t%s: # blocks %d, avg # input + clock pins used %g, avg # output pins used %g\n", 00522 type_descriptors[itype].name, 00523 num_clb_types[itype], 00524 0.0, 00525 0.0); 00526 } else { 00527 printf("\t%s: # blocks %d, avg # input + clock pins used %g, avg # output pins used %g\n", 00528 type_descriptors[itype].name, 00529 num_clb_types[itype], 00530 (float)num_clb_inputs_used[itype] / (float)num_clb_types[itype], 00531 (float)num_clb_outputs_used[itype] / (float)num_clb_types[itype]); 00532 } 00533 } 00534 00535 total_nets_absorbed = 0; 00536 for(inet = 0; inet < num_logical_nets; inet++) { 00537 if(nets_absorbed[inet] == TRUE) { 00538 total_nets_absorbed++; 00539 } 00540 } 00541 printf("Absorbed logical nets %d out of %d nets, %d nets not absorbed\n", total_nets_absorbed, num_logical_nets, num_logical_nets - total_nets_absorbed); 00542 free(nets_absorbed); 00543 free(num_lut_of_size); 00544 free(num_clb_types); 00545 free(num_clb_inputs_used); 00546 free(num_clb_outputs_used); 00547 /* TODO: print more stats */ 00548 } 00549 00550 /** 00551 * This routine dumps out the output netlist in a format suitable for 00552 * input to vpr. This routine also dumps out the internal structure of 00553 * the cluster, in essentially a graph based format. 00554 */ 00555 void 00556 output_clustering( 00557 t_block *clb, 00558 int num_clusters, 00559 boolean global_clocks, 00560 boolean * is_clock, 00561 char *out_fname, 00562 boolean skip_clustering) 00563 { 00564 00565 FILE *fpout; 00566 int bnum, netnum, column; 00567 00568 fpout = fopen(out_fname, "w"); 00569 00570 fprintf(fpout, "<block name=\"%s\" instance=\"FPGA_packed_netlist[0]\">\n", out_fname); 00571 fprintf(fpout, "\t<inputs>\n\t\t"); 00572 00573 column = 2*TAB_LENGTH; /* Organize whitespace to ident data inside block */ 00574 for(bnum = 0; bnum < num_logical_blocks; bnum++) 00575 { 00576 if(logical_block[bnum].type == VPACK_INPAD) { 00577 print_string(logical_block[bnum].name, &column, 2, fpout); 00578 } 00579 } 00580 fprintf(fpout, "\n\t</inputs>\n"); 00581 fprintf(fpout, "\n\t<outputs>\n\t\t"); 00582 00583 column = 2*TAB_LENGTH; 00584 for(bnum = 0; bnum < num_logical_blocks; bnum++) 00585 { 00586 if(logical_block[bnum].type == VPACK_OUTPAD) { 00587 print_string(logical_block[bnum].name, &column, 2, fpout); 00588 } 00589 } 00590 fprintf(fpout, "\n\t</outputs>\n"); 00591 00592 column = 2*TAB_LENGTH; 00593 if(global_clocks) 00594 { 00595 fprintf(fpout, "\n\t<globals>\n\t\t"); 00596 00597 for(netnum = 0; netnum < num_logical_nets; netnum++) 00598 { 00599 if(is_clock[netnum]) 00600 { 00601 print_string(vpack_net[netnum].name, &column, 2, fpout); 00602 } 00603 } 00604 fprintf(fpout, "\n\t</globals>\n\n"); 00605 } 00606 00607 /* Print out all input and output pads. */ 00608 00609 for(bnum = 0; bnum < num_logical_blocks; bnum++) 00610 { 00611 switch (logical_block[bnum].type) 00612 { 00613 case VPACK_INPAD: 00614 case VPACK_OUTPAD: 00615 case VPACK_COMB: 00616 case VPACK_LATCH: 00617 if(skip_clustering) 00618 { 00619 assert(0); 00620 } 00621 break; 00622 00623 case VPACK_EMPTY: 00624 printf("Error in output_netlist -- logical_block %d is VPACK_EMPTY.\n", 00625 bnum); 00626 exit(1); 00627 break; 00628 00629 default: 00630 printf 00631 ("Error in output_netlist. Unexpected type %d for logical_block" 00632 "%d.\n", logical_block[bnum].type, bnum); 00633 } 00634 } 00635 00636 if(skip_clustering == FALSE) 00637 print_clusters(clb, num_clusters, fpout); 00638 00639 fprintf(fpout, "</block>\n\n"); 00640 00641 fclose(fpout); 00642 00643 print_stats(clb, num_clusters); 00644 }