VPR-6.0
|
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "vpr_types.h"
#include "globals.h"
#include "output_clustering.h"
#include "read_xml_arch_file.h"
Go to the source code of this file.
Defines | |
#define | LINELENGTH 1024 |
#define | TAB_LENGTH 4 |
Functions | |
static void | print_tabs (FILE *fpout, int num_tabs) |
static void | print_string (char *str_ptr, int *column, int num_tabs, FILE *fpout) |
static void | print_net_name (int inet, int *column, int num_tabs, FILE *fpout) |
static void | print_interconnect (int inode, int *column, int num_tabs, FILE *fpout) |
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) |
static void | print_basic_pb (FILE *fpout, int bnum) |
static void | print_pb (FILE *fpout, t_pb *pb, int pb_index, int tab_depth) |
static void | print_clusters (t_block *clb, int num_clusters, FILE *fpout) |
static void | print_stats (t_block *clb, int num_clusters) |
void | output_clustering (t_block *clb, int num_clusters, boolean global_clocks, boolean *is_clock, char *out_fname, boolean skip_clustering) |
#define LINELENGTH 1024 |
Definition at line 18 of file output_clustering.c.
#define TAB_LENGTH 4 |
Definition at line 19 of file output_clustering.c.
void output_clustering | ( | t_block * | clb, |
int | num_clusters, | ||
boolean | global_clocks, | ||
boolean * | is_clock, | ||
char * | out_fname, | ||
boolean | skip_clustering | ||
) |
This routine dumps out the output netlist in a format suitable for input to vpr. This routine also dumps out the internal structure of the cluster, in essentially a graph based format.
Definition at line 556 of file output_clustering.c.
{ FILE *fpout; int bnum, netnum, column; fpout = fopen(out_fname, "w"); fprintf(fpout, "<block name=\"%s\" instance=\"FPGA_packed_netlist[0]\">\n", out_fname); fprintf(fpout, "\t<inputs>\n\t\t"); column = 2*TAB_LENGTH; /* Organize whitespace to ident data inside block */ for(bnum = 0; bnum < num_logical_blocks; bnum++) { if(logical_block[bnum].type == VPACK_INPAD) { print_string(logical_block[bnum].name, &column, 2, fpout); } } fprintf(fpout, "\n\t</inputs>\n"); fprintf(fpout, "\n\t<outputs>\n\t\t"); column = 2*TAB_LENGTH; for(bnum = 0; bnum < num_logical_blocks; bnum++) { if(logical_block[bnum].type == VPACK_OUTPAD) { print_string(logical_block[bnum].name, &column, 2, fpout); } } fprintf(fpout, "\n\t</outputs>\n"); column = 2*TAB_LENGTH; if(global_clocks) { fprintf(fpout, "\n\t<globals>\n\t\t"); for(netnum = 0; netnum < num_logical_nets; netnum++) { if(is_clock[netnum]) { print_string(vpack_net[netnum].name, &column, 2, fpout); } } fprintf(fpout, "\n\t</globals>\n\n"); } /* Print out all input and output pads. */ for(bnum = 0; bnum < num_logical_blocks; bnum++) { switch (logical_block[bnum].type) { case VPACK_INPAD: case VPACK_OUTPAD: case VPACK_COMB: case VPACK_LATCH: if(skip_clustering) { assert(0); } break; case VPACK_EMPTY: printf("Error in output_netlist -- logical_block %d is VPACK_EMPTY.\n", bnum); exit(1); break; default: printf ("Error in output_netlist. Unexpected type %d for logical_block" "%d.\n", logical_block[bnum].type, bnum); } } if(skip_clustering == FALSE) print_clusters(clb, num_clusters, fpout); fprintf(fpout, "</block>\n\n"); fclose(fpout); print_stats(clb, num_clusters); }
static void print_basic_pb | ( | FILE * | fpout, |
int | bnum | ||
) | [static] |
Prints out the pb connectivity. Used only when the -no_clustering option is selected -- prints out basically redundant connection info for a VPACK_LUT + FF logic logical_block.
Definition at line 285 of file output_clustering.c.
{ assert(0); }
static void print_clusters | ( | t_block * | clb, |
int | num_clusters, | ||
FILE * | fpout | ||
) | [static] |
Prints out one cluster (clb). Both the external pins and the internal connections are printed out.
Definition at line 416 of file output_clustering.c.
{ int icluster; for(icluster = 0; icluster < num_clusters; icluster++) { rr_node = clb[icluster].pb->rr_graph; /* TODO: Must do check that total CLB pins match top-level pb pins, perhaps check this earlier? */ print_pb(fpout, clb[icluster].pb, icluster, 1); } }
static void print_interconnect | ( | int | inode, |
int * | column, | ||
int | num_tabs, | ||
FILE * | fpout | ||
) | [static] |
This routine prints out the vpack_net name (or open) and limits the length of a line to LINELENGTH characters by using \ to continue lines. net_num is the index of the vpack_net to be printed, while column points to the current printing column (column is both used and updated by this routine). fpout is the output file pointer.
Definition at line 99 of file output_clustering.c.
{ char *str_ptr, *name; int prev_node, prev_edge; int len; if(rr_node[inode].net_num == OPEN) { print_string("open", column, num_tabs, fpout); } else { str_ptr = NULL; prev_node = rr_node[inode].prev_node; prev_edge = rr_node[inode].prev_edge; if(prev_node == OPEN && rr_node[inode].pb_graph_pin->port->parent_pb_type->num_modes == 0 && rr_node[inode].pb_graph_pin->port->type == OUT_PORT) { /* This is a primitive output */ print_net_name(rr_node[inode].net_num, column, num_tabs, fpout); } else { name = rr_node[prev_node].pb_graph_pin->output_edges[prev_edge]->interconnect->name; if(rr_node[prev_node].pb_graph_pin->port->parent_pb_type->depth >= rr_node[inode].pb_graph_pin->port->parent_pb_type->depth) { /* Connections from siblings or children should have an explicit index, connections from parent does not need an explicit index */ len = strlen(rr_node[prev_node].pb_graph_pin->parent_node->pb_type->name) + rr_node[prev_node].pb_graph_pin->parent_node->placement_index / 10 + strlen(rr_node[prev_node].pb_graph_pin->port->name) + rr_node[prev_node].pb_graph_pin->pin_number / 10 + strlen(name) + 11; str_ptr = my_malloc(len * sizeof(char)); sprintf(str_ptr, "%s[%d].%s[%d]->%s ", rr_node[prev_node].pb_graph_pin->parent_node->pb_type->name, rr_node[prev_node].pb_graph_pin->parent_node->placement_index, rr_node[prev_node].pb_graph_pin->port->name, rr_node[prev_node].pb_graph_pin->pin_number, name); } else { len = strlen(rr_node[prev_node].pb_graph_pin->parent_node->pb_type->name) + strlen(rr_node[prev_node].pb_graph_pin->port->name) + rr_node[prev_node].pb_graph_pin->pin_number / 10 + strlen(name) + 8; str_ptr = my_malloc(len * sizeof(char)); sprintf(str_ptr, "%s.%s[%d]->%s ", rr_node[prev_node].pb_graph_pin->parent_node->pb_type->name, rr_node[prev_node].pb_graph_pin->port->name, rr_node[prev_node].pb_graph_pin->pin_number, name); } print_string(str_ptr, column, num_tabs, fpout); } if(str_ptr) free(str_ptr); } }
static void print_net_name | ( | int | inet, |
int * | column, | ||
int | num_tabs, | ||
FILE * | fpout | ||
) | [static] |
This routine prints out the vpack_net name (or open) and limits the length of a line to LINELENGTH characters by using \ to continue lines. net_num is the index of the vpack_net to be printed, while column points to the current printing column (column is both used and updated by this routine). fpout is the output file pointer.
Definition at line 75 of file output_clustering.c.
{ char *str_ptr; if(inet == OPEN) str_ptr = "open"; else str_ptr = vpack_net[inet].name; print_string(str_ptr, column, num_tabs, fpout); }
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 | ||
) | [static] |
Definition at line 153 of file output_clustering.c.
{ int column = 0; int i, j, k, m; const t_pb_type * pb_type, * child_pb_type; t_mode * mode = NULL; int prev_edge, prev_node; t_pb_graph_pin *pb_graph_pin; int mode_of_edge, port_index, node_index; mode_of_edge = UNDEFINED; pb_type = pb_graph_node->pb_type; print_tabs(fpout, tab_depth); if(is_used) { /* Determine mode if applicable */ port_index = 0; for(i = 0; i < pb_type->num_ports; i++) { if(pb_type->ports[i].type == OUT_PORT) { assert(!pb_type->ports[i].is_clock); for(j = 0; j < pb_type->ports[i].num_pins; j++) { node_index = pb_graph_node->output_pins[port_index][j].pin_count_in_cluster; if(pb_type->num_modes > 0 && rr_node[node_index].net_num != OPEN) { prev_edge = rr_node[node_index].prev_edge; prev_node = rr_node[node_index].prev_node; pb_graph_pin = rr_node[prev_node].pb_graph_pin; mode_of_edge = pb_graph_pin->output_edges[prev_edge]->interconnect->parent_mode_index; assert(mode == NULL || &pb_type->modes[mode_of_edge] == mode); mode = &pb_type->modes[mode_of_edge]; } } port_index++; } } assert(mode != NULL && mode_of_edge != UNDEFINED); fprintf(fpout, "<block name=\"open\" instance=\"%s[%d]\" mode=\"%s\">\n", pb_graph_node->pb_type->name, pb_index, mode->name); print_tabs(fpout, tab_depth); fprintf(fpout, "\t<inputs>\n"); port_index = 0; for(i = 0; i < pb_type->num_ports; i++) { if(!pb_type->ports[i].is_clock && pb_type->ports[i].type == IN_PORT) { print_tabs(fpout, tab_depth); fprintf(fpout, "\t\t<port name=\"%s\">", pb_graph_node->pb_type->ports[i].name); for(j = 0; j < pb_type->ports[i].num_pins; j++) { node_index = pb_graph_node->input_pins[port_index][j].pin_count_in_cluster; print_interconnect(node_index, &column, tab_depth + 2, fpout); } fprintf(fpout, "</port>\n"); port_index++; } } print_tabs(fpout, tab_depth); fprintf(fpout, "\t</inputs>\n"); column = tab_depth * TAB_LENGTH + 8; /* Next column I will write to. */ print_tabs(fpout, tab_depth); fprintf(fpout, "\t<outputs>\n"); port_index = 0; for(i = 0; i < pb_type->num_ports; i++) { if(pb_type->ports[i].type == OUT_PORT) { print_tabs(fpout, tab_depth); fprintf(fpout, "\t\t<port name=\"%s\">", pb_graph_node->pb_type->ports[i].name); assert(!pb_type->ports[i].is_clock); for(j = 0; j < pb_type->ports[i].num_pins; j++) { node_index = pb_graph_node->output_pins[port_index][j].pin_count_in_cluster; print_interconnect(node_index, &column, tab_depth + 2, fpout); } fprintf(fpout, "</port>\n"); port_index++; } } print_tabs(fpout, tab_depth); fprintf(fpout, "\t</outputs>\n"); column = tab_depth * TAB_LENGTH + 8; /* Next column I will write to. */ print_tabs(fpout, tab_depth); fprintf(fpout, "\t<globals>\n"); port_index = 0; for(i = 0; i < pb_type->num_ports; i++) { if(pb_type->ports[i].is_clock && pb_type->ports[i].type == IN_PORT) { print_tabs(fpout, tab_depth); fprintf(fpout, "\t\t<port name=\"%s\">", pb_graph_node->pb_type->ports[i].name); for(j = 0; j < pb_type->ports[i].num_pins; j++) { node_index = pb_graph_node->clock_pins[port_index][j].pin_count_in_cluster; print_interconnect(node_index, &column, tab_depth + 2, fpout); } fprintf(fpout, "</port>\n"); port_index++; } } print_tabs(fpout, tab_depth); fprintf(fpout, "\t</globals>\n"); if(pb_type->num_modes > 0) { for(i = 0; i < mode->num_pb_type_children; i++) { child_pb_type = &mode->pb_type_children[i]; for(j = 0; j < mode->pb_type_children[i].num_pb; j++) { port_index = 0; is_used = FALSE; for(k = 0; k < child_pb_type->num_ports && !is_used; k++) { if(child_pb_type->ports[k].type == OUT_PORT) { for(m = 0; m < child_pb_type->ports[k].num_pins; m++) { node_index = pb_graph_node->child_pb_graph_nodes[mode_of_edge][i][j].output_pins[port_index][m].pin_count_in_cluster; if(rr_node[node_index].net_num != OPEN) { is_used = TRUE; break; } } port_index++; } } print_open_pb_graph_node(&pb_graph_node->child_pb_graph_nodes[mode_of_edge][i][j], j, is_used, tab_depth+1, fpout); } } } print_tabs(fpout, tab_depth); fprintf(fpout, "</block>\n"); } else { fprintf(fpout, "<block name=\"open\" instance=\"%s[%d]\"/>\n", pb_graph_node->pb_type->name, pb_index); } }
static void print_pb | ( | FILE * | fpout, |
t_pb * | pb, | ||
int | pb_index, | ||
int | tab_depth | ||
) | [static] |
Definition at line 293 of file output_clustering.c.
{ int column; int i, j, k, m; const t_pb_type *pb_type, *child_pb_type; t_pb_graph_node *pb_graph_node; t_mode *mode; int port_index, node_index; boolean is_used; pb_type = pb->pb_graph_node->pb_type; pb_graph_node = pb->pb_graph_node; mode = &pb_type->modes[pb->mode]; column = tab_depth * TAB_LENGTH + 8; /* Next column I will write to. */ print_tabs(fpout, tab_depth); if(pb_type->num_modes == 0) { fprintf(fpout, "<block name=\"%s\" instance=\"%s[%d]\">\n", pb->name, pb_type->name, pb_index); } else { fprintf(fpout, "<block name=\"%s\" instance=\"%s[%d]\" mode=\"%s\">\n", pb->name, pb_type->name, pb_index, mode->name); } print_tabs(fpout, tab_depth); fprintf(fpout, "\t<inputs>\n"); port_index = 0; for(i = 0; i < pb_type->num_ports; i++) { if(!pb_type->ports[i].is_clock && pb_type->ports[i].type == IN_PORT) { print_tabs(fpout, tab_depth); fprintf(fpout, "\t\t<port name=\"%s\">", pb_graph_node->pb_type->ports[i].name); for(j = 0; j < pb_type->ports[i].num_pins; j++) { node_index = pb->pb_graph_node->input_pins[port_index][j].pin_count_in_cluster; if(pb_type->parent_mode == NULL) { print_net_name(rr_node[node_index].net_num, &column, tab_depth, fpout); } else { print_interconnect(node_index, &column, tab_depth + 2, fpout); } } fprintf(fpout, "</port>\n"); port_index++; } } print_tabs(fpout, tab_depth); fprintf(fpout, "\t</inputs>\n"); column = tab_depth * TAB_LENGTH + 8; /* Next column I will write to. */ print_tabs(fpout, tab_depth); fprintf(fpout, "\t<outputs>\n"); port_index = 0; for(i = 0; i < pb_type->num_ports; i++) { if(pb_type->ports[i].type == OUT_PORT) { assert(!pb_type->ports[i].is_clock); print_tabs(fpout, tab_depth); fprintf(fpout, "\t\t<port name=\"%s\">", pb_graph_node->pb_type->ports[i].name); for(j = 0; j < pb_type->ports[i].num_pins; j++) { node_index = pb->pb_graph_node->output_pins[port_index][j].pin_count_in_cluster; print_interconnect(node_index, &column, tab_depth + 2, fpout); } fprintf(fpout, "</port>\n"); port_index++; } } print_tabs(fpout, tab_depth); fprintf(fpout, "\t</outputs>\n"); column = tab_depth * TAB_LENGTH + 8; /* Next column I will write to. */ print_tabs(fpout, tab_depth); fprintf(fpout, "\t<globals>\n"); port_index = 0; for(i = 0; i < pb_type->num_ports; i++) { if(pb_type->ports[i].is_clock && pb_type->ports[i].type == IN_PORT) { print_tabs(fpout, tab_depth); fprintf(fpout, "\t\t<port name=\"%s\">", pb_graph_node->pb_type->ports[i].name); for(j = 0; j < pb_type->ports[i].num_pins; j++) { node_index = pb->pb_graph_node->clock_pins[port_index][j].pin_count_in_cluster; if(pb_type->parent_mode == NULL) { print_net_name(rr_node[node_index].net_num, &column, tab_depth, fpout); } else { print_interconnect(node_index, &column, tab_depth + 2, fpout); } } fprintf(fpout, "</port>\n"); port_index++; } } print_tabs(fpout, tab_depth); fprintf(fpout, "\t</globals>\n"); if(pb_type->num_modes > 0) { for(i = 0; i < mode->num_pb_type_children; i++) { for(j = 0; j < mode->pb_type_children[i].num_pb; j++) { /* If child pb is not used but routing is used, I must print things differently */ if((pb->child_pbs[i] != NULL) && (pb->child_pbs[i][j].name != NULL)) { print_pb(fpout, &pb->child_pbs[i][j], j, tab_depth + 1); } else { is_used = FALSE; child_pb_type = &mode->pb_type_children[i]; port_index = 0; for(k = 0; k < child_pb_type->num_ports && !is_used; k++) { if(child_pb_type->ports[k].type == OUT_PORT) { for(m = 0; m < child_pb_type->ports[k].num_pins; m++) { node_index = pb_graph_node->child_pb_graph_nodes[pb->mode][i][j].output_pins[port_index][m].pin_count_in_cluster; if(rr_node[node_index].net_num != OPEN) { is_used = TRUE; break; } } port_index++; } } print_open_pb_graph_node(&pb_graph_node->child_pb_graph_nodes[pb->mode][i][j], j, is_used, tab_depth+1, fpout); } } } } print_tabs(fpout, tab_depth); fprintf(fpout, "</block>\n"); }
static void print_stats | ( | t_block * | clb, |
int | num_clusters | ||
) | [static] |
Prints out one cluster (clb). Both the external pins and the internal connections are printed out.
Definition at line 437 of file output_clustering.c.
{ int ipin, icluster, itype, inet, iblk, num_pins, i; int MAX_LUT_INPUTS; int unabsorbable_ffs, total_ffs; int num_luts_total; int total_nets_absorbed; boolean* nets_absorbed; int *num_clb_types, *num_clb_inputs_used, *num_clb_outputs_used, *num_lut_of_size; nets_absorbed = NULL; num_clb_types = num_clb_inputs_used = num_clb_outputs_used = NULL; num_clb_types = (int*)my_calloc(num_types, sizeof(int)); num_clb_inputs_used = (int*)my_calloc(num_types, sizeof(int)); num_clb_outputs_used = (int*)my_calloc(num_types, sizeof(int)); MAX_LUT_INPUTS = 0; for(iblk = 0; iblk < num_logical_blocks; iblk++) { if(strcmp(logical_block[iblk].model->name, "names") == 0) { MAX_LUT_INPUTS = logical_block[iblk].model->inputs->size; break; } } num_lut_of_size = (int*)my_calloc(MAX_LUT_INPUTS + 1, sizeof(int)); nets_absorbed = (boolean *)my_calloc(num_logical_nets, sizeof(boolean)); for(inet = 0; inet < num_logical_nets; inet++) { nets_absorbed[inet] = TRUE; } unabsorbable_ffs = 0; total_ffs = 0; for(iblk = 0; iblk < num_logical_blocks; iblk++) { if(strcmp(logical_block[iblk].model->name, "names") == 0) { num_pins = 0; for(ipin = 0; ipin < logical_block[iblk].model->inputs->size; ipin++) { if(logical_block[iblk].input_nets[0][ipin] != OPEN) { num_pins++; } } num_lut_of_size[num_pins]++; } else if(strcmp(logical_block[iblk].model->name, "latch") == 0) { if(vpack_net[logical_block[iblk].input_nets[0][0]].num_sinks > 1 || strcmp(logical_block[vpack_net[logical_block[iblk].input_nets[0][0]].node_block[0]].model->name, "names") != 0) { unabsorbable_ffs++; } total_ffs++; } } printf("\n"); num_luts_total = 0; for(i = 0; i <= MAX_LUT_INPUTS; i++) { printf("%d LUTs of size %d\n", num_lut_of_size[i], i); num_luts_total += num_lut_of_size[i]; } printf("%d LUTs in input netlist\n", num_luts_total); printf("%d FFs in input netlist\n", total_ffs); printf("%d FFs in input netlist not absorbable\n", unabsorbable_ffs); /* Counters used only for statistics purposes. */ for(icluster = 0; icluster < num_clusters; icluster++) { for(ipin = 0; ipin < clb[icluster].type->num_pins; ipin++) { if(clb[icluster].nets[ipin] != OPEN) { nets_absorbed[clb[icluster].nets[ipin]] = FALSE; if(clb[icluster].type->class_inf[clb[icluster].type->pin_class[ipin]].type == RECEIVER) { num_clb_inputs_used[clb[icluster].type->index]++; } else if(clb[icluster].type->class_inf[clb[icluster].type->pin_class[ipin]].type == DRIVER){ num_clb_outputs_used[clb[icluster].type->index]++; } } } num_clb_types[clb[icluster].type->index]++; } for(itype = 0; itype < num_types; itype++) { if(num_clb_types[itype] == 0) { printf("\t%s: # blocks %d, avg # input + clock pins used %g, avg # output pins used %g\n", type_descriptors[itype].name, num_clb_types[itype], 0.0, 0.0); } else { printf("\t%s: # blocks %d, avg # input + clock pins used %g, avg # output pins used %g\n", type_descriptors[itype].name, num_clb_types[itype], (float)num_clb_inputs_used[itype] / (float)num_clb_types[itype], (float)num_clb_outputs_used[itype] / (float)num_clb_types[itype]); } } total_nets_absorbed = 0; for(inet = 0; inet < num_logical_nets; inet++) { if(nets_absorbed[inet] == TRUE) { total_nets_absorbed++; } } 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); free(nets_absorbed); free(num_lut_of_size); free(num_clb_types); free(num_clb_inputs_used); free(num_clb_outputs_used); /* TODO: print more stats */ }
static void print_string | ( | char * | str_ptr, |
int * | column, | ||
int | num_tabs, | ||
FILE * | fpout | ||
) | [static] |
Prints string without making any lines longer than LINELENGTH. Column points to the column in which the next character will go (both used and updated), and fpout points to the output file.
Definition at line 38 of file output_clustering.c.
{ int len; len = strlen(str_ptr); if(len + 3 > LINELENGTH) { printf ("Error in print_string: String %s is too long for desired\n" "maximum line length.\n", str_ptr); exit(1); } if(*column + len + 2 > LINELENGTH) { fprintf(fpout, "\n"); print_tabs(fpout, num_tabs); *column = num_tabs * TAB_LENGTH; } fprintf(fpout, "%s ", str_ptr); *column += len + 1; }
static void print_tabs | ( | FILE * | fpout, |
int | num_tabs | ||
) | [static] |
Definition at line 26 of file output_clustering.c.
{ int i; for(i = 0; i < num_tabs; i++) { fprintf(fpout, "\t"); } }