VPR-6.0

vpr/SRC/pack/output_blif.c

Go to the documentation of this file.
00001 /*
00002  * @file
00003  *
00004  * Jason Luu 2008
00005  * Print blif representation of circuit
00006  * Assumptions: Assumes first valid rr input to node is the correct rr input
00007  *               Assumes clocks are routed globally
00008  */
00009 
00010 #include <assert.h>
00011 #include <stdio.h>
00012 #include <stdlib.h>
00013 #include <string.h>
00014 #include "util.h"
00015 #include "vpr_types.h"
00016 #include "globals.h"
00017 #include "output_blif.h"
00018 
00019 #define LINELENGTH 1024
00020 #define TABLENGTH 1
00021 
00022 
00023 /****************** Subroutines local to this module ************************/
00024 
00025 
00026 /**************** Subroutine definitions ************************************/
00027 
00028 /** Prints string without making any lines longer than LINELENGTH.  Column  
00029  * points to the column in which the next character will go (both used and 
00030  * updated), and fpout points to the output file.                          
00031  */
00032 static void
00033 print_string(char *str_ptr,
00034              int *column,
00035              FILE * fpout)
00036 {
00037     int len;
00038 
00039     len = strlen(str_ptr);
00040     if(len + 3 > LINELENGTH)
00041         {
00042             printf
00043                 ("Error in print_string: String %s is too long for desired\n"
00044                  "maximum line length.\n", str_ptr);
00045             exit(1);
00046         }
00047 
00048     if(*column + len + 2 > LINELENGTH)
00049         {
00050             fprintf(fpout, "\\ \n");
00051             *column = TABLENGTH;
00052         }
00053 
00054     fprintf(fpout, "%s ", str_ptr);
00055     *column += len + 1;
00056 }
00057 
00058 
00059 /** This routine prints out the vpack_net name (or open) and limits the   
00060  * length of a line to LINELENGTH characters by using \ to continue 
00061  * lines.  net_num is the index of the vpack_net to be printed, while     
00062  * column points to the current printing column (column is both     
00063  * used and updated by this routine).  fpout is the output file     
00064  * pointer.                                                         
00065  */
00066 static void
00067 print_net_name(int inet,
00068                int *column,
00069                FILE * fpout)
00070 {
00071     char *str_ptr;
00072 
00073     if(inet == OPEN)
00074                 str_ptr = "open";
00075     else
00076                 str_ptr = vpack_net[inet].name;
00077 
00078     print_string(str_ptr, column, fpout);
00079 }
00080 
00081 /** finds first fanin rr_node */
00082 static int find_fanin_rr_node(t_pb *cur_pb, enum PORTS type, int rr_node_index) {
00083         t_pb *parent, *sibling, *child;
00084         int net_num, irr_node;
00085         int i, j, k, ichild_type, ichild_inst;
00086         int hack_empty_route_through;
00087         t_pb_graph_node *hack_empty_pb_graph_node;
00088 
00089         hack_empty_route_through = OPEN;
00090 
00091         net_num = rr_node[rr_node_index].net_num;
00092 
00093         parent = cur_pb->parent_pb;
00094 
00095         if(net_num == OPEN) {
00096                 return OPEN;
00097         }
00098 
00099         if (type == IN_PORT) {
00100                 /* check parent inputs for valid connection */
00101                 for(i = 0; i < parent->pb_graph_node->num_input_ports; i++) {
00102                         for(j = 0; j < parent->pb_graph_node->num_input_pins[i]; j++) {
00103                                 irr_node = parent->pb_graph_node->input_pins[i][j].pin_count_in_cluster;
00104                                 if(rr_node[irr_node].net_num == net_num) {
00105                                         if(cur_pb->pb_graph_node->pb_type->model && strcmp(cur_pb->pb_graph_node->pb_type->model->name, MODEL_LATCH) == 0) {
00106                                                 /* HACK: latches are special becuase LUTs can be set to route-through mode for them 
00107                                                    I will assume that the input to a LATCH can always come from a parent input pin
00108                                                    this only works for hierarchical soft logic structures that follow LUT -> LATCH design
00109                                                    must do it better later
00110                                                 */
00111                                                 return irr_node;
00112                                         }
00113                                         hack_empty_route_through = irr_node;
00114                                         for(k = 0; k < rr_node[irr_node].num_edges; k++) {
00115                                                 if(rr_node[irr_node].edges[k] == rr_node_index) {
00116                                                         return irr_node;
00117                                                 }
00118                                         }
00119                                 }
00120                         }
00121                 }
00122                 /* check parent clocks for valid connection */
00123                 for(i = 0; i < parent->pb_graph_node->num_clock_ports; i++) {
00124                         for(j = 0; j < parent->pb_graph_node->num_clock_pins[i]; j++) {
00125                                 irr_node = parent->pb_graph_node->clock_pins[i][j].pin_count_in_cluster;
00126                                 if(rr_node[irr_node].net_num == net_num) {
00127                                         for(k = 0; k < rr_node[irr_node].num_edges; k++) {
00128                                                 if(rr_node[irr_node].edges[k] == rr_node_index) {
00129                                                         return irr_node;
00130                                                 }
00131                                         }
00132                                 }
00133                         }
00134                 }
00135                 /* check siblings for connection */
00136                 if(parent) {
00137                         for(ichild_type = 0; ichild_type < parent->pb_graph_node->pb_type->modes[parent->mode].num_pb_type_children; ichild_type++) {
00138                                 for(ichild_inst = 0; ichild_inst < parent->pb_graph_node->pb_type->modes[parent->mode].pb_type_children[ichild_type].num_pb; ichild_inst++) {
00139                                         if(parent->child_pbs[ichild_type] && parent->child_pbs[ichild_type][ichild_inst].name != NULL) {
00140                                                 sibling = &parent->child_pbs[ichild_type][ichild_inst];
00141                                                 for(i = 0; i < sibling->pb_graph_node->num_output_ports; i++) {
00142                                                         for(j = 0; j < sibling->pb_graph_node->num_output_pins[i]; j++) {
00143                                                                 irr_node = sibling->pb_graph_node->output_pins[i][j].pin_count_in_cluster;
00144                                                                 if(rr_node[irr_node].net_num == net_num) {
00145                                                                         for(k = 0; k < rr_node[irr_node].num_edges; k++) {
00146                                                                                 if(rr_node[irr_node].edges[k] == rr_node_index) {
00147                                                                                         return irr_node;
00148                                                                                 }
00149                                                                         }
00150                                                                 }
00151                                                         }
00152                                                 }                                               
00153                                         } else {
00154                                                 /* hack just in case routing is down through an empty cluster */
00155                                                 hack_empty_pb_graph_node = &parent->pb_graph_node->child_pb_graph_nodes[ichild_type][0][ichild_inst];
00156                                                 for(i = 0; i < hack_empty_pb_graph_node->num_output_ports; i++) {
00157                                                         for(j = 0; j < hack_empty_pb_graph_node->num_output_pins[i]; j++) {
00158                                                                 irr_node = hack_empty_pb_graph_node->output_pins[i][j].pin_count_in_cluster;
00159                                                                 if(rr_node[irr_node].net_num == net_num) {
00160                                                                         for(k = 0; k < rr_node[irr_node].num_edges; k++) {
00161                                                                                 if(rr_node[irr_node].edges[k] == rr_node_index) {
00162                                                                                         return irr_node;
00163                                                                                 }
00164                                                                         }
00165                                                                 }
00166                                                         }
00167                                                 }                       
00168                                         }
00169                                 }
00170                         }
00171                 }
00172         } else {
00173                 assert(type == OUT_PORT);
00174                 
00175                 /* check children for connection */
00176                 for(ichild_type = 0; ichild_type < cur_pb->pb_graph_node->pb_type->modes[cur_pb->mode].num_pb_type_children; ichild_type++) {
00177                         for(ichild_inst = 0; ichild_inst < cur_pb->pb_graph_node->pb_type->modes[cur_pb->mode].pb_type_children[ichild_type].num_pb; ichild_inst++) {
00178                                 if(cur_pb->child_pbs[ichild_type] && cur_pb->child_pbs[ichild_type][ichild_inst].name != NULL) {
00179                                         child = &cur_pb->child_pbs[ichild_type][ichild_inst];
00180                                         for(i = 0; i < child->pb_graph_node->num_output_ports; i++) {
00181                                                 for(j = 0; j < child->pb_graph_node->num_output_pins[i]; j++) {
00182                                                         irr_node = child->pb_graph_node->output_pins[i][j].pin_count_in_cluster;
00183                                                         if(rr_node[irr_node].net_num == net_num) {
00184                                                                 for(k = 0; k < rr_node[irr_node].num_edges; k++) {
00185                                                                         if(rr_node[irr_node].edges[k] == rr_node_index) {
00186                                                                                 return irr_node;
00187                                                                         }
00188                                                                 }
00189                                                                 hack_empty_route_through = irr_node;
00190                                                         }
00191                                                 }
00192                                         }                                               
00193                                 }
00194                         }
00195                 }
00196 
00197                 /* If not in children, check current pb inputs for valid connection */
00198                 for(i = 0; i < cur_pb->pb_graph_node->num_input_ports; i++) {
00199                         for(j = 0; j < cur_pb->pb_graph_node->num_input_pins[i]; j++) {
00200                                 irr_node = cur_pb->pb_graph_node->input_pins[i][j].pin_count_in_cluster;
00201                                 if(rr_node[irr_node].net_num == net_num) {
00202                                         hack_empty_route_through = irr_node;
00203                                         for(k = 0; k < rr_node[irr_node].num_edges; k++) {
00204                                                 if(rr_node[irr_node].edges[k] == rr_node_index) {
00205                                                         return irr_node;
00206                                                 }
00207                                         }
00208                                 }
00209                         }
00210                 }
00211         }
00212 
00213         /* TODO: Once I find a way to output routing in empty blocks then code should never reach here, for now, return OPEN */
00214         printf("Can't find connecting net %s #%d for pb %s type %s\n", vpack_net[net_num].name, net_num, 
00215                 cur_pb->name, cur_pb->pb_graph_node->pb_type->name);
00216                 
00217         assert(hack_empty_route_through != OPEN);
00218         return hack_empty_route_through;
00219 }
00220 
00221 static void print_primitive(FILE *fpout, int iblk) {
00222         t_pb *pb;
00223         int clb_index;
00224         int i, j, column, node_index;
00225         int in_port_index, out_port_index, clock_port_index;
00226         struct s_linked_vptr *truth_table;
00227         const t_pb_type *pb_type;
00228 
00229         pb = logical_block[iblk].pb;
00230         pb_type = pb->pb_graph_node->pb_type;
00231         clb_index = logical_block[iblk].clb_index;
00232 
00233 
00234         column = 7;
00235         if(logical_block[iblk].type == VPACK_INPAD || logical_block[iblk].type == VPACK_OUTPAD) {
00236                 /* do nothing */
00237         } else if(logical_block[iblk].type == VPACK_LATCH) {
00238                 fprintf(fpout, ".latch ");
00239                 
00240                 in_port_index = 0;
00241                 out_port_index = 0;
00242                 clock_port_index = 0;
00243                 for(i = 0; i < pb_type->num_ports; i++) {
00244                         if(pb_type->ports[i].type == IN_PORT && pb_type->ports[i].is_clock == FALSE) {
00245                                 assert(pb_type->ports[i].num_pins == 1);
00246                                 assert(logical_block[iblk].input_nets[i][0] != OPEN);
00247                                 node_index = pb->pb_graph_node->input_pins[in_port_index][0].pin_count_in_cluster;
00248                                 fprintf(fpout, "clb_%d_rr_node_%d ", clb_index, find_fanin_rr_node(pb, pb_type->ports[i].type, node_index));
00249                                 in_port_index++;
00250                         }
00251                 }
00252                 for(i = 0; i < pb_type->num_ports; i++) {
00253                         if(pb_type->ports[i].type == OUT_PORT) {
00254                                 assert(pb_type->ports[i].num_pins == 1 && out_port_index == 0);
00255                                 node_index = pb->pb_graph_node->output_pins[out_port_index][0].pin_count_in_cluster;
00256                                 fprintf(fpout, "clb_%d_rr_node_%d re ", clb_index, node_index);
00257                                 out_port_index++;
00258                         }
00259                 }
00260                 for(i = 0; i < pb_type->num_ports; i++) {
00261                         if(pb_type->ports[i].type == IN_PORT && pb_type->ports[i].is_clock == TRUE) {
00262                                 assert(logical_block[iblk].clock_net != OPEN);
00263                                 node_index = pb->pb_graph_node->clock_pins[clock_port_index][0].pin_count_in_cluster;
00264                                 fprintf(fpout, "clb_%d_rr_node_%d 2", clb_index, find_fanin_rr_node(pb, pb_type->ports[i].type, node_index));
00265                                 clock_port_index++;
00266                         }
00267                 }
00268                 fprintf(fpout, "\n");                           
00269         } else if(logical_block[iblk].type == VPACK_COMB) {
00270                 if(strcmp(logical_block[iblk].model->name, ".names")) {
00271                         fprintf(fpout, ".names ");
00272                         in_port_index = 0;
00273                         out_port_index = 0;
00274                         for(i = 0; i < pb_type->num_ports; i++) {
00275                                 if(pb_type->ports[i].type == IN_PORT && pb_type->ports[i].is_clock == FALSE) {
00276                                         for(j = 0; j < pb_type->ports[i].num_pins; j++) {
00277                                                 if(logical_block[iblk].input_nets[i][j] != OPEN) {
00278                                                         node_index = pb->pb_graph_node->input_pins[in_port_index][j].pin_count_in_cluster;
00279                                                         fprintf(fpout, "clb_%d_rr_node_%d ", clb_index, find_fanin_rr_node(pb, pb_type->ports[i].type, node_index));
00280                                                 }
00281                                         }
00282                                         in_port_index++;
00283                                 }
00284                         }
00285                         for(i = 0; i < pb_type->num_ports; i++) {
00286                                 if(pb_type->ports[i].type == OUT_PORT) {
00287                                         for(j = 0; j < pb_type->ports[i].num_pins; j++) {
00288                                                 node_index = pb->pb_graph_node->output_pins[out_port_index][j].pin_count_in_cluster;
00289                                                 fprintf(fpout, "clb_%d_rr_node_%d\n", clb_index, node_index);
00290                                         }
00291                                         out_port_index++;
00292                                 }
00293                         }
00294                         truth_table = logical_block[iblk].truth_table;
00295                         while(truth_table) {
00296                                 fprintf(fpout, "%s\n", (char *)truth_table->data_vptr);
00297                                 truth_table = truth_table->next;
00298                         }
00299                 } else {
00300                         assert(0);
00301                 }
00302         }
00303 }
00304 
00305 static void print_pb(FILE *fpout, t_pb * pb, int clb_index) {
00306 
00307         int column;
00308         int i, j;
00309         const t_pb_type *pb_type;
00310         t_mode *mode;
00311         int in_port_index, out_port_index, node_index;
00312 
00313         pb_type = pb->pb_graph_node->pb_type;
00314         mode = &pb_type->modes[pb->mode];
00315         column = 0;     
00316         if(pb_type->num_modes == 0) {
00317                 print_primitive(fpout, pb->logical_block);
00318         } else {
00319                 in_port_index = 0;
00320                 out_port_index = 0;
00321                 for(i = 0; i < pb_type->num_ports; i++) {
00322                         if(!pb_type->ports[i].is_clock) {
00323                                 for(j = 0; j < pb_type->ports[i].num_pins; j++) {
00324                                         /* print .blif buffer to represent routing */
00325                                         column = 0;
00326                                         if(pb_type->ports[i].type == OUT_PORT) {
00327                                                 node_index = pb->pb_graph_node->output_pins[out_port_index][j].pin_count_in_cluster;
00328                                                 if(rr_node[node_index].net_num != OPEN) {
00329                                                         fprintf(fpout, ".names clb_%d_rr_node_%d ",
00330                                                                 clb_index, find_fanin_rr_node(pb, pb_type->ports[i].type, node_index));
00331                                                         if(pb->parent_pb) {
00332                                                                 fprintf(fpout, "clb_%d_rr_node_%d ", clb_index, node_index);
00333                                                         } else {
00334                                                                 print_net_name(rr_node[node_index].net_num, &column, fpout);
00335                                                         }
00336                                                         fprintf(fpout, "\n1 1\n");
00337                                                 }
00338                 
00339                                         } else { 
00340                                                 node_index = pb->pb_graph_node->input_pins[in_port_index][j].pin_count_in_cluster;
00341                                                 if(rr_node[node_index].net_num != OPEN) {
00342                                                 
00343                                                         fprintf(fpout, ".names ");
00344                                                         if(pb->parent_pb) {
00345                                                                 fprintf(fpout, "clb_%d_rr_node_%d ", clb_index, find_fanin_rr_node(pb, pb_type->ports[i].type, node_index));
00346                                                         } else {
00347                                                                 print_net_name(rr_node[node_index].net_num, &column, fpout);
00348                                                         }
00349                                                         fprintf(fpout, "clb_%d_rr_node_%d", clb_index, node_index);
00350                                                         fprintf(fpout, "\n1 1\n");
00351                                                 }
00352                                         }
00353                                 }
00354                         }
00355                         if(pb_type->ports[i].type == OUT_PORT) {
00356                                 out_port_index++;
00357                         } else {
00358                                 in_port_index++;
00359                         }                               
00360                 }
00361                 for(i = 0; i < mode->num_pb_type_children; i++) {
00362                         for(j = 0; j < mode->pb_type_children[i].num_pb; j++) {
00363                                 /* If child pb is not used but routing is used, I must print things differently */
00364                                 if((pb->child_pbs[i] != NULL) && 
00365                                         (pb->child_pbs[i][j].name != NULL)) {
00366                                         print_pb(fpout, &pb->child_pbs[i][j], clb_index);
00367                                 } else {
00368                                         /* do nothing for now, we'll print something later if needed */
00369                                 }
00370                         }
00371                 }
00372         }
00373 }
00374 
00375 /** Prints out one cluster (clb).  Both the external pins and the 
00376  * internal connections are printed out.                         
00377  */
00378 static void
00379 print_clusters(
00380            t_block *clb,
00381            int num_clusters,
00382            FILE * fpout)
00383 {
00384     int icluster;
00385     
00386         for(icluster = 0; icluster < num_clusters; icluster++)
00387         {
00388                 rr_node = clb[icluster].pb->rr_graph;
00389 #if 0
00390                 dump_rr_graph("cluster_rr_graph.echo"); 
00391 #endif
00392                 if(clb[icluster].type != IO_TYPE)
00393                         print_pb(fpout, clb[icluster].pb, icluster);
00394         }
00395 }
00396 
00397 /** 
00398  * This routine dumps out the output netlist in a format suitable for  
00399  * input to vpr.  This routine also dumps out the internal structure of   
00400  * the cluster, in essentially a graph based format.                           
00401  */
00402 void
00403 output_blif(
00404                   t_block *clb,
00405                   int num_clusters,
00406                   boolean global_clocks,
00407                   boolean * is_clock,
00408                   char *out_fname,
00409                   boolean skip_clustering)
00410 {
00411 
00412 
00413     FILE *fpout;
00414     int bnum, column;
00415         struct s_linked_vptr *p_io_removed;
00416 
00417         fpout = my_fopen(out_fname, "w", 0);
00418 
00419         column = 0;
00420         fprintf(fpout, ".model %s\n", blif_circuit_name);
00421                 
00422 
00423         /* Print out all input and output pads. */
00424         fprintf(fpout, "\n.inputs ");
00425     for(bnum = 0; bnum < num_logical_blocks; bnum++)
00426         {       
00427                 if(logical_block[bnum].type == VPACK_INPAD) {
00428                         print_string(logical_block[bnum].name, &column, fpout);
00429                 }
00430         }
00431         p_io_removed = circuit_p_io_removed;
00432         while(p_io_removed) {
00433                 print_string((char*)p_io_removed->data_vptr, &column, fpout);
00434                 p_io_removed = p_io_removed->next;
00435         }
00436 
00437         column = 0;
00438         fprintf(fpout, "\n.outputs ");
00439         for(bnum = 0; bnum < num_logical_blocks; bnum++)
00440         {       
00441                 if(logical_block[bnum].type == VPACK_OUTPAD) {
00442                         /* remove output prefix "out:" */
00443                         print_string(logical_block[bnum].name + 4, &column, fpout);
00444                 }
00445         }
00446 
00447         column = 0;
00448 
00449         fprintf(fpout, "\n\n");
00450         
00451         print_clusters(clb, num_clusters, fpout);
00452         fprintf(fpout, "\n.end\n");
00453 
00454     fclose(fpout);
00455 }