blob: c1422304c8e7e193fa00c6d22760a256bc9fe527 [file] [log] [blame]
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include "util.h"
#include "vpr_types.h"
#include "globals.h"
#include "graphics.h"
#include "read_netlist.h"
#include "check_netlist.h"
#include "print_netlist.h"
#include "draw.h"
#include "place_and_route.h"
#include "pack.h"
#include "SetupGrid.h"
#include "stats.h"
#include "path_delay.h"
#include "OptionTokens.h"
#include "ReadOptions.h"
#include "read_xml_arch_file.h"
#include "SetupVPR.h"
#include "rr_graph.h"
#include "pb_type_graph.h"
/******** Global variables ********/
int Fs_seed = -1;
int W_seed = -1;
int binary_search = -1;
float grid_logic_tile_area = 0;
float ipin_mux_trans_size = 0;
/* t-vpack globals begin */
int num_logical_nets = 0, num_logical_blocks = 0, num_saved_logical_blocks = 0, num_saved_logical_nets = 0, num_subckts = 0;
int num_p_inputs = 0, num_p_outputs = 0, num_luts = 0, num_latches = 0;
struct s_net *vpack_net = NULL, *saved_logical_nets = NULL;
struct s_logical_block *logical_block = NULL, *saved_logical_blocks = NULL;
struct s_subckt *subckt = NULL;
char *blif_circuit_name = NULL;
/* t-vpack globals end */
/******** Netlist to be mapped stuff ********/
int num_nets = 0;
struct s_net *clb_net = NULL;
int num_blocks = 0;
struct s_block *block = NULL;
int num_ff = 0;
int num_const_gen = 0;
int *clb_to_vpack_net_mapping = NULL; /* [0..num_clb_nets - 1] */
int *vpack_to_clb_net_mapping = NULL; /* [0..num_vpack_nets - 1] */
/* This identifies the t_type_ptr of an IO block */
int num_types = 0;
struct s_type_descriptor *type_descriptors = NULL;
t_type_ptr IO_TYPE = NULL;
t_type_ptr EMPTY_TYPE = NULL;
t_type_ptr FILL_TYPE = NULL;
/******** Physical architecture stuff ********/
int nx = 0;
int ny = 0;
/* TRUE if this is a global clb pin -- an input pin to which the netlist can *
* connect global signals, but which does not connect into the normal *
* routing via muxes etc. Marking pins like this (only clocks in my work) *
* stops them from screwing up the input switch pattern in the rr_graph *
* generator and from creating extra switches that the area model would *
* count. */
int *chan_width_x = NULL; /* [0..ny] */
int *chan_width_y = NULL; /* [0..nx] */
struct s_grid_tile **grid = NULL; /* [0..(nx+1)][0..(ny+1)] Physical block list */
/******** Structures defining the routing ********/
/* Linked list start pointers. Define the routing. */
struct s_trace **trace_head = NULL; /* [0..(num_nets-1)] */
struct s_trace **trace_tail = NULL; /* [0..(num_nets-1)] */
/******** Structures defining the FPGA routing architecture ********/
int num_rr_nodes = 0;
t_rr_node *rr_node = NULL; /* [0..(num_rr_nodes-1)] */
t_ivec ***rr_node_indices = NULL;
int num_rr_indexed_data = 0;
t_rr_indexed_data *rr_indexed_data = NULL; /* [0..(num_rr_indexed_data-1)] */
/* Gives the rr_node indices of net terminals. */
int **net_rr_terminals = NULL; /* [0..num_nets-1][0..num_pins-1] */
/* Gives information about all the switch types *
* (part of routing architecture, but loaded in read_arch.c */
struct s_switch_inf *switch_inf = NULL; /* [0..(det_routing_arch.num_switch-1)] */
/* Stores the SOURCE and SINK nodes of all CLBs (not valid for pads). */
int **rr_blk_source = NULL; /* [0..(num_blocks-1)][0..(num_class-1)] */
/* primiary inputs removed from circuit */
struct s_linked_vptr *circuit_p_io_removed = NULL;
/********** Structures representing timing graph information */
t_tnode *tnode = NULL; /* [0..num_tnodes - 1] */
int num_tnodes = 0; /* Number of nodes (pins) in the timing graph */
float pb_max_internal_delay = UNDEFINED; /* biggest internal delay of physical block */
const t_pb_type *pbtype_max_internal_delay = NULL; /* physical block type with highest internal delay */
/********************** Subroutines local to this module ********************/
static void PrintUsage();
static void PrintTitle();
static void freeArch(t_arch* Arch);
static void freeOptions(t_options *options);
static void InitArch(INP t_arch Arch);
static void free_pb_type(t_pb_type *pb_type);
static void free_complex_block_types();
/************************* Subroutine definitions ***************************/
/**
* VPR program
* Generate FPGA architecture given architecture description
* Pack, place, and route circuit into FPGA architecture
* Electrical timing analysis on results
*
* Overall steps
* 1. Initialization
* 2. Pack
* 3. Place-and-route and timing analysis
*/
int
main(int argc,
char **argv)
{
t_options Options;
t_arch Arch;
t_model *user_models, *library_models;
enum e_operation Operation;
struct s_file_name_opts FileNameOpts;
struct s_packer_opts PackerOpts;
struct s_placer_opts PlacerOpts;
struct s_annealing_sched AnnealSched;
struct s_router_opts RouterOpts;
struct s_det_routing_arch RoutingArch;
t_segment_inf *Segments;
t_timing_inf Timing;
boolean ShowGraphics;
boolean TimingEnabled;
int GraphPause;
clock_t begin, end;
/* Print title message */
PrintTitle();
/* Print usage message if no args */
if(argc < 2)
{
PrintUsage();
exit(1);
}
/* Read in available inputs */
ReadOptions(argc, argv, &Options);
/* Determine whether timing is on or off */
TimingEnabled = IsTimingEnabled(Options);
/* Use inputs to configure VPR */
memset(&Arch, 0, sizeof(t_arch));
SetupVPR(Options, TimingEnabled, &FileNameOpts, &Arch, &Operation, &user_models,
&library_models, &PackerOpts, &PlacerOpts,
&AnnealSched, &RouterOpts, &RoutingArch, &Segments,
&Timing, &ShowGraphics, &GraphPause);
/* Check inputs are reasonable */
CheckOptions(Options, TimingEnabled);
CheckArch(Arch, TimingEnabled);
/* Verify settings don't conflict or otherwise not make sense */
CheckSetup(Operation, PlacerOpts, AnnealSched, RouterOpts,
RoutingArch, Segments, Timing, Arch.Chans);
fflush(stdout);
/* Packing stage */
if(PackerOpts.doPacking) {
begin = clock();
try_pack(&PackerOpts, &Arch, user_models, library_models);
end = clock();
#ifdef CLOCKS_PER_SEC
printf("Packing took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC);
#else
printf("Packing took %g seconds\n", (float)(end - begin) / CLK_PER_SEC);
#endif
/* Free logical blocks and nets */
if(logical_block != NULL) {
free_logical_blocks();
free_logical_nets();
}
if(!PlacerOpts.doPlacement && !RouterOpts.doRouting) {
return 0;
}
}
/* Packing stage complete */
fflush(stdout);
/* Read in netlist file for placement and routing */
if(FileNameOpts.NetFile)
{
read_netlist(FileNameOpts.NetFile, &Arch, &num_blocks, &block, &num_nets, &clb_net);
/* This is done so that all blocks have subblocks and can be treated the same */
check_netlist();
}
/* Output the current settings to console. */
ShowSetup(Options, Arch, TimingEnabled, Operation, FileNameOpts, PlacerOpts,
AnnealSched, RouterOpts, RoutingArch, Segments, Timing);
if(Operation == TIMING_ANALYSIS_ONLY) {
do_constant_net_delay_timing_analysis(
Timing, Options.constant_net_delay);
return 0;
}
InitArch(Arch);
fflush(stdout);
/* Startup X graphics */
set_graphics_state(ShowGraphics, GraphPause, RouterOpts.route_type);
if(ShowGraphics)
{
init_graphics("VPR: Versatile Place and Route for FPGAs");
alloc_draw_structs();
}
/* Do placement and routing */
place_and_route(Operation, PlacerOpts, FileNameOpts.PlaceFile,
FileNameOpts.NetFile, FileNameOpts.ArchFile, FileNameOpts.RouteFile,
AnnealSched, RouterOpts, RoutingArch,
Segments, Timing, Arch.Chans, Arch.models);
fflush(stdout);
/* Close down X Display */
if(ShowGraphics)
close_graphics();
/* free data structures */
freeOptions(&Options);
/* Free logical blocks and nets */
if(logical_block != NULL) {
free_logical_blocks();
free_logical_nets();
}
freeArch(&Arch);
free_complex_block_types();
/* Return 0 to single success to scripts */
return 0;
}
/* Outputs usage message */
static void
PrintUsage()
{
puts("Usage: vpr fpga_architecture.xml circuit_name [Options ...]");
puts("");
puts("General Options: [--nodisp] [--auto <int>] [--pack]");
puts("\t[--place] [--route] [--timing_analyze_only_with_net_delay <float>]");
puts("\t[--fast] [--full_stats] [--timing_analysis on | off] [--outfile_prefix <string>]");
puts("\t[--blif_file <string>][--net_file <string>][--place_file <string>][--route_file <string>]");
puts("");
puts("Packer Options:");
/* puts("\t[-global_clocks on|off]");
puts("\t[-hill_climbing on|off]");
puts("\t[-sweep_hanging_nets_and_inputs on|off]"); */
puts("\t[--timing_driven_clustering on|off]");
puts("\t[--cluster_seed_type timing|max_inputs] [--alpha_clustering <float>] [--beta_clustering <float>]");
/* puts("\t[-recompute_timing_after <int>] [-cluster_block_delay <float>]"); */
puts("\t[--allow_unrelated_clustering on|off]");
/* puts("\t[-allow_early_exit on|off]");
puts("\t[-intra_cluster_net_delay <float>] ");
puts("\t[-inter_cluster_net_delay <float>] "); */
puts("\t[--connection_driven_clustering on|off] ");
/* puts("\t[-packer_algorithm greedy|brute_force]");
puts("\t[-hack_no_legal_frac_lut]");
puts("\t[-hack_safe_latch]"); */
puts("");
puts("Placer Options:");
puts("\t[--place_algorithm bounding_box | net_timing_driven | path_timing_driven]");
puts("\t[--init_t <float>] [--exit_t <float>]");
puts("\t[--alpha_t <float>] [--inner_num <float>] [--seed <int>]");
puts("\t[--place_cost_exp <float>] [--place_cost_type linear | nonlinear]");
puts("\t[--place_chan_width <int>] [--num_regions <int>] ");
puts("\t[--fix_pins random | <file.pads>]");
puts("\t[--enable_timing_computations on | off]");
puts("\t[--block_dist <int>]");
puts("");
puts("Placement Options Valid Only for Timing-Driven Placement:");
puts("\t[--timing_tradeoff <float>]");
puts("\t[--recompute_crit_iter <int>]");
puts("\t[--inner_loop_recompute_divider <int>]");
puts("\t[--td_place_exp_first <float>]");
puts("\t[--td_place_exp_last <float>]");
puts("");
puts("Router Options: [-max_router_iterations <int>] [-bb_factor <int>]");
puts("\t[--initial_pres_fac <float>] [--pres_fac_mult <float>]");
puts("\t[--acc_fac <float>] [--first_iter_pres_fac <float>]");
puts("\t[--bend_cost <float>] [--route_type global | detailed]");
puts("\t[--verify_binary_search] [--route_chan_width <int>]");
puts("\t[--router_algorithm breadth_first | timing_driven | directed_search]");
puts("\t[--base_cost_type intrinsic_delay | delay_normalized | demand_only]");
puts("");
puts("Routing options valid only for timing-driven routing:");
puts("\t[--astar_fac <float>] [--max_criticality <float>]");
puts("\t[--criticality_exp <float>]");
puts("");
}
static void
PrintTitle()
{
puts("");
puts("VPR FPGA Placement and Routing.");
puts("Version: Version " VPR_VERSION);
puts("Compiled: " __DATE__ ".");
puts("Original VPR by V. Betz.");
puts("Timing-driven placement enhancements by A. Marquardt.");
puts("Single-drivers enhancements by Andy Ye with additions by.");
puts("Mark Fang, Jason Luu, Ted Campbell");
puts("Heterogeneous stucture support by Jason Luu and Ted Campbell.");
puts("T-VPack clustering integration by Jason Luu.");
puts("Area-driven AAPack added by Jason Luu.");
puts("This is free open source code under MIT license.");
puts("");
}
static void freeArch(t_arch* Arch)
{
int i;
t_model *model, *prev;
t_model_ports *port, *prev_port;
struct s_linked_vptr *vptr, *vptr_prev;
for(i = 0; i < Arch->num_switches; i++) {
if(Arch->Switches->name != NULL) {
free(Arch->Switches[i].name);
}
}
free(Arch->Switches);
for(i = 0; i < Arch->num_segments; i++) {
if(Arch->Segments->cb != NULL) {
free(Arch->Segments[i].cb);
}
if(Arch->Segments->sb != NULL) {
free(Arch->Segments[i].sb);
}
}
free(Arch->Segments);
model = Arch->models;
while(model) {
port = model->inputs;
while(port) {
prev_port = port;
port = port->next;
free(prev_port->name);
free(prev_port);
}
port = model->outputs;
while(port) {
prev_port = port;
port = port->next;
free(prev_port->name);
free(prev_port);
}
vptr = model->pb_types;
while(vptr) {
vptr_prev = vptr;
vptr = vptr->next;
free(vptr_prev);
}
prev = model;
model = model->next;
if(prev->instances)
free(prev->instances);
free(prev->name);
free(prev);
}
for(i = 0; i < 4; i++) {
vptr = Arch->model_library[i].pb_types;
while(vptr) {
vptr_prev = vptr;
vptr = vptr->next;
free(vptr_prev);
}
}
free(Arch->model_library[0].name);
free(Arch->model_library[0].outputs->name);
free(Arch->model_library[0].outputs);
free(Arch->model_library[1].inputs->name);
free(Arch->model_library[1].inputs);
free(Arch->model_library[1].name);
free(Arch->model_library[2].name);
free(Arch->model_library[2].inputs[0].name);
free(Arch->model_library[2].inputs[1].name);
free(Arch->model_library[2].inputs);
free(Arch->model_library[2].outputs->name);
free(Arch->model_library[2].outputs);
free(Arch->model_library[3].name);
free(Arch->model_library[3].inputs->name);
free(Arch->model_library[3].inputs);
free(Arch->model_library[3].outputs->name);
free(Arch->model_library[3].outputs);
free(Arch->model_library);
}
static void free_complex_block_types() {
int i, j, k, m;
free_all_pb_graph_nodes();
for(i = 0; i < num_types; i++) {
if(&type_descriptors[i] == EMPTY_TYPE) {
continue;
}
free(type_descriptors[i].name);
for(j = 0; j < type_descriptors[i].height; j++) {
for(k = 0; k < 4; k ++) {
for(m = 0; m < type_descriptors[i].num_pin_loc_assignments[j][k]; m++) {
if(type_descriptors[i].pin_loc_assignments[j][k][m])
free(type_descriptors[i].pin_loc_assignments[j][k][m]);
}
free(type_descriptors[i].pinloc[j][k]);
free(type_descriptors[i].pin_loc_assignments[j][k]);
}
free(type_descriptors[i].pinloc[j]);
free(type_descriptors[i].pin_loc_assignments[j]);
free(type_descriptors[i].num_pin_loc_assignments[j]);
}
free(type_descriptors[i].pinloc);
free(type_descriptors[i].pin_loc_assignments);
free(type_descriptors[i].num_pin_loc_assignments);
free(type_descriptors[i].pin_height);
free_pb_type(type_descriptors[i].pb_type);
free(type_descriptors[i].pb_type);
}
}
static void free_pb_type(t_pb_type *pb_type) {
int i, j, k, m;
struct s_linked_vptr *vptr, *prev;
free(pb_type->name);
if(pb_type->blif_model)
free(pb_type->blif_model);
for(i = 0; i < pb_type->num_modes; i++) {
for(j = 0; j < pb_type->modes[i].num_pb_type_children; j++) {
free_pb_type(&pb_type->modes[i].pb_type_children[j]);
}
free(pb_type->modes[i].pb_type_children);
free(pb_type->modes[i].name);
for(j = 0; j < pb_type->modes[i].num_interconnect; j++) {
free(pb_type->modes[i].interconnect[j].input_string);
free(pb_type->modes[i].interconnect[j].output_string);
free(pb_type->modes[i].interconnect[j].name);
for(k = 0; k < pb_type->modes[i].interconnect[j].num_annotations; k++) {
if(pb_type->modes[i].interconnect[j].annotations[k].clock)
free(pb_type->modes[i].interconnect[j].annotations[k].clock);
if(pb_type->modes[i].interconnect[j].annotations[k].input_pins) {
free(pb_type->modes[i].interconnect[j].annotations[k].input_pins);
}
if(pb_type->modes[i].interconnect[j].annotations[k].output_pins) {
free(pb_type->modes[i].interconnect[j].annotations[k].output_pins);
}
for(m = 0; m < pb_type->modes[i].interconnect[j].annotations[k].num_value_prop_pairs; m++) {
free(pb_type->modes[i].interconnect[j].annotations[k].value[m]);
}
free(pb_type->modes[i].interconnect[j].annotations[k].prop);
free(pb_type->modes[i].interconnect[j].annotations[k].value);
}
free(pb_type->modes[i].interconnect[j].annotations);
}
if(pb_type->modes[i].interconnect)
free(pb_type->modes[i].interconnect);
}
if(pb_type->modes)
free(pb_type->modes);
for(i = 0; i < pb_type->num_annotations; i++) {
for(j = 0; j < pb_type->annotations[i].num_value_prop_pairs; j++) {
free(pb_type->annotations[i].value[j]);
}
free(pb_type->annotations[i].value);
free(pb_type->annotations[i].prop);
if(pb_type->annotations[i].input_pins) {
free(pb_type->annotations[i].input_pins);
}
if(pb_type->annotations[i].output_pins) {
free(pb_type->annotations[i].output_pins);
}
if(pb_type->annotations[i].clock) {
free(pb_type->annotations[i].clock);
}
}
if(pb_type->num_annotations > 0) {
free(pb_type->annotations);
}
vptr = pb_type->models_contained;
while(vptr) {
prev = vptr;
vptr = vptr->next;
free(prev);
}
for(i = 0; i < pb_type->num_ports; i++) {
free(pb_type->ports[i].name);
if(pb_type->ports[i].port_class) {
free(pb_type->ports[i].port_class);
}
}
free(pb_type->ports);
}
/* This is a modification of the init_arch function to use Arch as param.
* Sets globals: nx, ny
* Allocs globals: chan_width_x, chan_width_y, grid
* Depends on num_clbs, pins_per_clb */
static void
InitArch(INP t_arch Arch)
{
int *num_instances_type, *num_blocks_type;
int i;
int current, high, low;
boolean fit;
current = nint(sqrt(num_blocks)); /* current is the value of the smaller side of the FPGA */
low = 1;
high = -1;
num_instances_type = my_calloc(num_types, sizeof(int));
num_blocks_type = my_calloc(num_types, sizeof(int));
for(i = 0; i < num_blocks; i++)
{
num_blocks_type[block[i].type->index]++;
}
if(Arch.clb_grid.IsAuto)
{
/* Auto-size FPGA, perform a binary search */
while(high == -1 || low < high)
{
/* Generate grid */
if(Arch.clb_grid.Aspect >= 1.0)
{
ny = current;
nx = nint(current * Arch.clb_grid.Aspect);
}
else
{
nx = current;
ny = nint(current / Arch.clb_grid.Aspect);
}
#if DEBUG
printf("Auto-sizing FPGA, try x = %d y = %d\n", nx, ny);
#endif
alloc_and_load_grid(num_instances_type);
freeGrid();
/* Test if netlist fits in grid */
fit = TRUE;
for(i = 0; i < num_types; i++)
{
if(num_blocks_type[i] > num_instances_type[i])
{
fit = FALSE;
break;
}
}
/* get next value */
if(!fit)
{
/* increase size of max */
if(high == -1)
{
current = current * 2;
if(current > MAX_SHORT)
{
printf(ERRTAG
"FPGA required is too large for current architecture settings\n");
exit(1);
}
}
else
{
if(low == current)
current++;
low = current;
current = low + ((high - low) / 2);
}
}
else
{
high = current;
current = low + ((high - low) / 2);
}
}
/* Generate grid */
if(Arch.clb_grid.Aspect >= 1.0)
{
ny = current;
nx = nint(current * Arch.clb_grid.Aspect);
}
else
{
nx = current;
ny = nint(current / Arch.clb_grid.Aspect);
}
alloc_and_load_grid(num_instances_type);
printf("FPGA auto-sized to, x = %d y = %d\n", nx, ny);
}
else
{
nx = Arch.clb_grid.W;
ny = Arch.clb_grid.H;
alloc_and_load_grid(num_instances_type);
}
printf("The circuit will be mapped into a %d x %d array of clbs.\n",
nx, ny);
/* Test if netlist fits in grid */
fit = TRUE;
for(i = 0; i < num_types; i++)
{
if(num_blocks_type[i] > num_instances_type[i])
{
fit = FALSE;
break;
}
}
if(!fit)
{
printf(ERRTAG "Not enough physical locations for type %s, "
"number of blocks is %d but number of locations is %d\n",
type_descriptors[i].name, num_blocks_type[i], num_instances_type[i]);
exit(1);
}
printf("\nResource Usage:\n");
for(i = 0; i < num_types; i++)
{
printf("Netlist %d\tblocks of type %s\n",
num_blocks_type[i], type_descriptors[i].name);
printf("Architecture %d\tblocks of type %s\n",
num_instances_type[i], type_descriptors[i].name);
}
printf("\n");
chan_width_x = (int *)my_malloc((ny + 1) * sizeof(int));
chan_width_y = (int *)my_malloc((nx + 1) * sizeof(int));
free(num_blocks_type);
free(num_instances_type);
}
static void freeOptions(t_options *options) {
free(options->ArchFile);
free(options->CircuitName);
if(options->BlifFile)
free(options->BlifFile);
if(options->NetFile)
free(options->NetFile);
if(options->PlaceFile)
free(options->PlaceFile);
if(options->RouteFile)
free(options->RouteFile);
if(options->OutFilePrefix)
free(options->OutFilePrefix);
if(options->PinFile)
free(options->PinFile);
}