VPR-6.0

vpr/SRC/pack/output_clustering.c

Go to the documentation of this file.
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 }