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