blob: 48becd06dcc7cced1073189d83b096868a48f214 [file] [log] [blame]
#include <assert.h>
#include <string.h>
#include "util.h"
#include "vpr_types.h"
#include "check_netlist.h"
#include "OptionTokens.h"
#include "ReadOptions.h"
#include "read_netlist.h"
#include "globals.h"
#include "xml_arch.h"
#include "SetupVPR.h"
static void SetupOperation(IN t_options Options,
OUT enum e_operation *Operation);
static void SetupPlacerOpts(IN t_options Options,
IN boolean TimingEnabled,
OUT struct s_placer_opts *PlacerOpts);
static void SetupAnnealSched(IN t_options Options,
OUT struct s_annealing_sched *AnnealSched);
static void SetupRouterOpts(IN t_options Options,
IN boolean TimingEnabled,
OUT struct s_router_opts *RouterOpts);
static void SetupGlobalRoutingArch(OUT struct s_det_routing_arch *RoutingArch,
OUT t_segment_inf ** Segments);
static void SetupRoutingArch(IN t_arch Arch,
OUT struct s_det_routing_arch *RoutingArch);
static void SetupTiming(IN t_options Options,
IN t_arch Arch,
IN boolean TimingEnabled,
IN enum e_operation Operation,
IN struct s_placer_opts PlacerOpts,
IN struct s_router_opts RouterOpts,
OUT t_timing_inf * Timing);
static void load_subblock_info_to_type(INOUT t_subblock_data * subblocks,
INOUT t_type_ptr type);
static void InitArch(IN t_arch Arch);
static void alloc_and_load_grid(INOUT int *num_instances_type); /* [0..num_types-1] */
static void freeGrid();
static void CheckGrid(void);
static t_type_ptr find_type_col(IN int x);
static void SetupSwitches(IN t_arch Arch,
INOUT struct s_det_routing_arch *RoutingArch,
IN struct s_switch_inf *ArchSwitches,
IN int NumArchSwitches);
/* Sets VPR parameters and defaults. Does not do any error checking
* as this should have been done by the various input checkers */
void
SetupVPR(IN t_options Options,
IN boolean TimingEnabled,
OUT t_arch * Arch,
OUT enum e_operation *Operation,
OUT struct s_placer_opts *PlacerOpts,
OUT struct s_annealing_sched *AnnealSched,
OUT struct s_router_opts *RouterOpts,
OUT struct s_det_routing_arch *RoutingArch,
OUT t_segment_inf ** Segments,
OUT t_timing_inf * Timing,
OUT t_subblock_data * Subblocks,
OUT boolean * ShowGraphics,
OUT int *GraphPause)
{
SetupOperation(Options, Operation);
SetupPlacerOpts(Options, TimingEnabled, PlacerOpts);
SetupAnnealSched(Options, AnnealSched);
SetupRouterOpts(Options, TimingEnabled, RouterOpts);
XmlReadArch(Options.ArchFile, TimingEnabled, Arch,
&type_descriptors, &num_types);
*Segments = Arch->Segments;
RoutingArch->num_segment = Arch->num_segments;
SetupSwitches(*Arch, RoutingArch, Arch->Switches, Arch->num_switches);
SetupRoutingArch(*Arch, RoutingArch);
SetupTiming(Options, *Arch, TimingEnabled, *Operation,
*PlacerOpts, *RouterOpts, Timing);
/* init global variables */
OutFilePrefix = Options.OutFilePrefix;
grid_logic_tile_area = Arch->grid_logic_tile_area;
ipin_mux_trans_size = Arch->ipin_mux_trans_size;
/* Set seed for pseudo-random placement, default seed to 1 */
PlacerOpts->seed = 1;
if(Options.Count[OT_SEED])
{
PlacerOpts->seed = Options.Seed;
}
my_srandom(PlacerOpts->seed);
*GraphPause = 1; /* DEFAULT */
if(Options.Count[OT_AUTO])
{
*GraphPause = Options.GraphPause;
}
#ifdef NO_GRAPHICS
*ShowGraphics = FALSE; /* DEFAULT */
#else /* NO_GRAPHICS */
*ShowGraphics = TRUE; /* DEFAULT */
if(Options.Count[OT_NODISP])
{
*ShowGraphics = FALSE;
}
#endif /* NO_GRAPHICS */
#ifdef CREATE_ECHO_FILES
EchoArch("arch.echo", type_descriptors, num_types);
#endif
if(Options.NetFile)
{
read_netlist(Options.NetFile, num_types, type_descriptors,
IO_TYPE, 0, 1, Subblocks, &num_blocks, &block,
&num_nets, &net);
/* This is done so that all blocks have subblocks and can be treated the same */
load_subblock_info_to_type(Subblocks, IO_TYPE);
check_netlist(Subblocks);
}
InitArch(*Arch);
}
/* 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(IN 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);
}
/* 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",
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);
}
/* Create and fill FPGA architecture grid. */
static void
alloc_and_load_grid(INOUT int *num_instances_type)
{
int i, j;
t_type_ptr type;
#ifdef SHOW_ARCH
FILE *dump;
#endif
/* If both nx and ny are 1, we only have one valid location for a clb. *
* That's a major problem, as won't be able to move the clb and the *
* find_to routine that tries moves in the placer will go into an *
* infinite loop trying to move it. Exit with an error message *
* instead. */
if((nx == 1) && (ny == 1) && (num_blocks > 0))
{
printf("Error:\n");
printf
("Sorry, can't place a circuit with only one valid location\n");
printf("for a logic block (clb).\n");
printf("Try me with a more realistic circuit!\n");
exit(1);
}
/* To remove this limitation, change ylow etc. in t_rr_node to *
* * be ints instead. Used shorts to save memory. */
if((nx > 32766) || (ny > 32766))
{
printf("Error: nx and ny must be less than 32767, since the \n");
printf("router uses shorts (16-bit) to store coordinates.\n");
printf("nx: %d. ny: %d.\n", nx, ny);
exit(1);
}
assert(nx >= 1 && ny >= 1);
grid = (struct s_grid_tile **)alloc_matrix(0, (nx + 1),
0, (ny + 1),
sizeof(struct s_grid_tile));
/* Clear the full grid to have no type (NULL), no capacity, etc */
for(i = 0; i <= (nx + 1); ++i)
{
for(j = 0; j <= (ny + 1); ++j)
{
memset(&grid[i][j], 0, (sizeof(struct s_grid_tile)));
}
}
for(i = 0; i < num_types; i++)
{
num_instances_type[i] = 0;
}
/* Nothing goes in the corners. */
grid[0][0].type = grid[nx + 1][0].type = EMPTY_TYPE;
grid[0][ny + 1].type = grid[nx + 1][ny + 1].type = EMPTY_TYPE;
num_instances_type[EMPTY_TYPE->index] = 4;
for(i = 1; i <= nx; i++)
{
grid[i][0].blocks =
(int *)my_malloc(sizeof(int) * IO_TYPE->capacity);
grid[i][0].type = IO_TYPE;
grid[i][ny + 1].blocks =
(int *)my_malloc(sizeof(int) * IO_TYPE->capacity);
grid[i][ny + 1].type = IO_TYPE;
for(j = 0; j < IO_TYPE->capacity; j++)
{
grid[i][0].blocks[j] = EMPTY;
grid[i][ny + 1].blocks[j] = EMPTY;
}
}
for(i = 1; i <= ny; i++)
{
grid[0][i].blocks =
(int *)my_malloc(sizeof(int) * IO_TYPE->capacity);
grid[0][i].type = IO_TYPE;
grid[nx + 1][i].blocks =
(int *)my_malloc(sizeof(int) * IO_TYPE->capacity);
grid[nx + 1][i].type = IO_TYPE;
for(j = 0; j < IO_TYPE->capacity; j++)
{
grid[0][i].blocks[j] = EMPTY;
grid[nx + 1][i].blocks[j] = EMPTY;
}
}
num_instances_type[IO_TYPE->index] = 2 * IO_TYPE->capacity * (nx + ny);
for(i = 1; i <= nx; i++)
{ /* Interior (LUT) cells */
type = find_type_col(i);
for(j = 1; j <= ny; j++)
{
grid[i][j].type = type;
grid[i][j].offset = (j - 1) % type->height;
if(j + grid[i][j].type->height - 1 - grid[i][j].offset >
ny)
{
grid[i][j].type = EMPTY_TYPE;
grid[i][j].offset = 0;
}
if(type->capacity > 1)
{
printf(ERRTAG
"In FillArch() expected core blocks to have capacity <= 1 but "
"(%d, %d) has type '%s' and capacity %d\n",
i, j, grid[i][j].type->name,
grid[i][j].type->capacity);
exit(1);
}
grid[i][j].blocks = (int *)my_malloc(sizeof(int));
grid[i][j].blocks[0] = EMPTY;
if(grid[i][j].offset == 0)
{
num_instances_type[grid[i][j].type->index]++;
}
}
}
CheckGrid();
#ifdef SHOW_ARCH
/* DEBUG code */
dump = my_fopen("grid_type_dump.txt", "w");
for(j = (ny + 1); j >= 0; --j)
{
for(i = 0; i <= (nx + 1); ++i)
{
fprintf(dump, "%c", grid[i][j].type->name[1]);
}
fprintf(dump, "\n");
}
fclose(dump);
#endif
}
static void
freeGrid()
{
int i, j;
for(i = 0; i <= (nx + 1); ++i)
{
for(j = 0; j <= (ny + 1); ++j)
{
free(grid[i][j].blocks);
}
}
free_matrix(grid, 0, nx + 1, 0, sizeof(struct s_grid_tile));
}
static void
CheckGrid()
{
int i, j;
/* Check grid is valid */
for(i = 0; i <= (nx + 1); ++i)
{
for(j = 0; j <= (ny + 1); ++j)
{
if(NULL == grid[i][j].type)
{
printf(ERRTAG "grid[%d][%d] has no type.\n", i,
j);
exit(1);
}
if(grid[i][j].usage != 0)
{
printf(ERRTAG
"grid[%d][%d] has non-zero usage (%d) "
"before netlist load.\n", i, j,
grid[i][j].usage);
exit(1);
}
if((grid[i][j].offset < 0) ||
(grid[i][j].offset >= grid[i][j].type->height))
{
printf(ERRTAG
"grid[%d][%d] has invalid offset (%d)\n",
i, j, grid[i][j].offset);
exit(1);
}
if((NULL == grid[i][j].blocks) &&
(grid[i][j].type->capacity > 0))
{
printf(ERRTAG
"grid[%d][%d] has no block list allocated.\n",
i, j);
exit(1);
}
}
}
}
static t_type_ptr
find_type_col(IN int x)
{
int i, j;
int start, repeat;
float rel;
boolean match;
int priority, num_loc;
t_type_ptr column_type;
priority = FILL_TYPE->grid_loc_def[0].priority;
column_type = FILL_TYPE;
for(i = 0; i < num_types; i++)
{
if(&type_descriptors[i] == IO_TYPE ||
&type_descriptors[i] == EMPTY_TYPE ||
&type_descriptors[i] == FILL_TYPE)
continue;
num_loc = type_descriptors[i].num_grid_loc_def;
for(j = 0; j < num_loc; j++)
{
if(priority <
type_descriptors[i].grid_loc_def[j].priority)
{
match = FALSE;
if(type_descriptors[i].grid_loc_def[j].
grid_loc_type == COL_REPEAT)
{
start =
type_descriptors[i].grid_loc_def[j].
start_col;
repeat =
type_descriptors[i].grid_loc_def[j].
repeat;
if(start < 0)
{
start += (nx + 1);
}
if(x == start)
{
match = TRUE;
}
else if(repeat > 0 && x > start
&& start > 0)
{
if((x - start) % repeat == 0)
{
match = TRUE;
}
}
}
else if(type_descriptors[i].grid_loc_def[j].
grid_loc_type == COL_REL)
{
rel =
type_descriptors[i].grid_loc_def[j].
col_rel;
if(nint(rel * nx) == x)
{
match = TRUE;
}
}
if(match)
{
priority =
type_descriptors[i].grid_loc_def[j].
priority;
column_type = &type_descriptors[i];
}
}
}
}
return column_type;
}
static void
SetupTiming(IN t_options Options,
IN t_arch Arch,
IN boolean TimingEnabled,
IN enum e_operation Operation,
IN struct s_placer_opts PlacerOpts,
IN struct s_router_opts RouterOpts,
OUT t_timing_inf * Timing)
{
/* Don't do anything if they don't want timing */
if(FALSE == TimingEnabled)
{
memset(Timing, 0, sizeof(t_timing_inf));
Timing->timing_analysis_enabled = FALSE;
return;
}
Timing->C_ipin_cblock = Arch.C_ipin_cblock;
Timing->T_ipin_cblock = Arch.T_ipin_cblock;
Timing->timing_analysis_enabled = TimingEnabled;
}
/* This loads up VPR's switch_inf data by combining the switches from
* the arch file with the special switches that VPR needs. */
static void
SetupSwitches(IN t_arch Arch,
INOUT struct s_det_routing_arch *RoutingArch,
IN struct s_switch_inf *ArchSwitches,
IN int NumArchSwitches)
{
RoutingArch->num_switch = NumArchSwitches;
/* Depends on RoutingArch->num_switch */
RoutingArch->wire_to_ipin_switch = RoutingArch->num_switch;
++RoutingArch->num_switch;
/* Depends on RoutingArch->num_switch */
RoutingArch->delayless_switch = RoutingArch->num_switch;
RoutingArch->global_route_switch = RoutingArch->delayless_switch;
++RoutingArch->num_switch;
/* Alloc the list now that we know the final num_switch value */
switch_inf =
(struct s_switch_inf *)my_malloc(sizeof(struct s_switch_inf) *
RoutingArch->num_switch);
/* Copy the switch data from architecture file */
memcpy(switch_inf, ArchSwitches,
sizeof(struct s_switch_inf) * NumArchSwitches);
/* Delayless switch for connecting sinks and sources with their pins. */
switch_inf[RoutingArch->delayless_switch].buffered = TRUE;
switch_inf[RoutingArch->delayless_switch].R = 0.;
switch_inf[RoutingArch->delayless_switch].Cin = 0.;
switch_inf[RoutingArch->delayless_switch].Cout = 0.;
switch_inf[RoutingArch->delayless_switch].Tdel = 0.;
/* The wire to ipin switch for all types. Curently all types
* must share ipin switch. Some of the timing code would
* need to be changed otherwise. */
switch_inf[RoutingArch->wire_to_ipin_switch].buffered = TRUE;
switch_inf[RoutingArch->wire_to_ipin_switch].R = 0.;
switch_inf[RoutingArch->wire_to_ipin_switch].Cin = Arch.C_ipin_cblock;
switch_inf[RoutingArch->wire_to_ipin_switch].Cout = 0.;
switch_inf[RoutingArch->wire_to_ipin_switch].Tdel = Arch.T_ipin_cblock;
}
/* Sets up routing structures. Since checks are already done, this
* just copies values across */
static void
SetupRoutingArch(IN t_arch Arch,
OUT struct s_det_routing_arch *RoutingArch)
{
RoutingArch->switch_block_type = Arch.SBType;
RoutingArch->R_minW_nmos = Arch.R_minW_nmos;
RoutingArch->R_minW_pmos = Arch.R_minW_pmos;
RoutingArch->Fs = Arch.Fs;
RoutingArch->directionality = BI_DIRECTIONAL;
if(Arch.Segments)
RoutingArch->directionality = Arch.Segments[0].directionality;
}
static void
SetupRouterOpts(IN t_options Options,
IN boolean TimingEnabled,
OUT struct s_router_opts *RouterOpts)
{
RouterOpts->astar_fac = 1.2; /* DEFAULT */
if(Options.Count[OT_ASTAR_FAC])
{
RouterOpts->astar_fac = Options.astar_fac;
}
RouterOpts->bb_factor = 3; /* DEFAULT */
if(Options.Count[OT_FAST])
{
RouterOpts->bb_factor = 0; /* DEFAULT */
}
if(Options.Count[OT_BB_FACTOR])
{
RouterOpts->bb_factor = Options.bb_factor;
}
RouterOpts->criticality_exp = 1.0; /* DEFAULT */
if(Options.Count[OT_CRITICALITY_EXP])
{
RouterOpts->criticality_exp = Options.criticality_exp;
}
RouterOpts->max_criticality = 0.99; /* DEFAULT */
if(Options.Count[OT_MAX_CRITICALITY])
{
RouterOpts->max_criticality = Options.max_criticality;
}
RouterOpts->max_router_iterations = 50; /* DEFAULT */
if(Options.Count[OT_FAST])
{
RouterOpts->max_router_iterations = 10;
}
if(Options.Count[OT_MAX_ROUTER_ITERATIONS])
{
RouterOpts->max_router_iterations = Options.max_router_iterations;
}
RouterOpts->pres_fac_mult = 1.3; /* DEFAULT */
if(Options.Count[OT_PRES_FAC_MULT])
{
RouterOpts->pres_fac_mult = Options.pres_fac_mult;
}
RouterOpts->route_type = DETAILED; /* DEFAULT */
if(Options.Count[OT_ROUTE_TYPE])
{
RouterOpts->route_type = Options.RouteType;
}
RouterOpts->full_stats = FALSE; /* DEFAULT */
if(Options.Count[OT_FULL_STATS])
{
RouterOpts->full_stats = TRUE;
}
RouterOpts->verify_binary_search = FALSE; /* DEFAULT */
if(Options.Count[OT_VERIFY_BINARY_SEARCH])
{
RouterOpts->verify_binary_search = TRUE;
}
/* Depends on RouteOpts->route_type */
RouterOpts->router_algorithm = DIRECTED_SEARCH; /* DEFAULT */
if(TimingEnabled)
{
RouterOpts->router_algorithm = TIMING_DRIVEN; /* DEFAULT */
}
if(GLOBAL == RouterOpts->route_type)
{
RouterOpts->router_algorithm = DIRECTED_SEARCH; /* DEFAULT */
}
if(Options.Count[OT_ROUTER_ALGORITHM])
{
RouterOpts->router_algorithm = Options.RouterAlgorithm;
}
RouterOpts->fixed_channel_width = NO_FIXED_CHANNEL_WIDTH; /* DEFAULT */
if(Options.Count[OT_ROUTE_CHAN_WIDTH])
{
RouterOpts->fixed_channel_width = Options.RouteChanWidth;
}
/* Depends on RouterOpts->router_algorithm */
RouterOpts->initial_pres_fac = 0.5; /* DEFAULT */
if(DIRECTED_SEARCH == RouterOpts->router_algorithm ||
Options.Count[OT_FAST])
{
RouterOpts->initial_pres_fac = 10000.0; /* DEFAULT */
}
if(Options.Count[OT_INITIAL_PRES_FAC])
{
RouterOpts->initial_pres_fac = Options.initial_pres_fac;
}
/* Depends on RouterOpts->router_algorithm */
RouterOpts->base_cost_type = DELAY_NORMALIZED; /* DEFAULT */
if(BREADTH_FIRST == RouterOpts->router_algorithm)
{
RouterOpts->base_cost_type = DEMAND_ONLY; /* DEFAULT */
}
if(DIRECTED_SEARCH == RouterOpts->router_algorithm)
{
RouterOpts->base_cost_type = DEMAND_ONLY; /* DEFAULT */
}
if(Options.Count[OT_BASE_COST_TYPE])
{
RouterOpts->base_cost_type = Options.base_cost_type;
}
/* Depends on RouterOpts->router_algorithm */
RouterOpts->first_iter_pres_fac = 0.5; /* DEFAULT */
if(BREADTH_FIRST == RouterOpts->router_algorithm)
{
RouterOpts->first_iter_pres_fac = 0.0; /* DEFAULT */
}
if(DIRECTED_SEARCH == RouterOpts->router_algorithm ||
Options.Count[OT_FAST])
{
RouterOpts->first_iter_pres_fac = 10000.0; /* DEFAULT */
}
if(Options.Count[OT_FIRST_ITER_PRES_FAC])
{
RouterOpts->first_iter_pres_fac = Options.first_iter_pres_fac;
}
/* Depends on RouterOpts->router_algorithm */
RouterOpts->acc_fac = 1.0;
if(BREADTH_FIRST == RouterOpts->router_algorithm)
{
RouterOpts->acc_fac = 0.2;
}
if(Options.Count[OT_ACC_FAC])
{
RouterOpts->acc_fac = Options.acc_fac;
}
/* Depends on RouterOpts->route_type */
RouterOpts->bend_cost = 0.0; /* DEFAULT */
if(GLOBAL == RouterOpts->route_type)
{
RouterOpts->bend_cost = 1.0; /* DEFAULT */
}
if(Options.Count[OT_BEND_COST])
{
RouterOpts->bend_cost = Options.bend_cost;
}
}
static void
SetupAnnealSched(IN t_options Options,
OUT struct s_annealing_sched *AnnealSched)
{
AnnealSched->alpha_t = 0.8; /* DEFAULT */
if(Options.Count[OT_ALPHA_T])
{
AnnealSched->alpha_t = Options.PlaceAlphaT;
}
if(AnnealSched->alpha_t >= 1 || AnnealSched->alpha_t <= 0)
{
printf(ERRTAG "alpha_t must be between 0 and 1 exclusive\n");
exit(1);
}
AnnealSched->exit_t = 0.01; /* DEFAULT */
if(Options.Count[OT_EXIT_T])
{
AnnealSched->exit_t = Options.PlaceExitT;
}
if(AnnealSched->exit_t <= 0)
{
printf(ERRTAG "exit_t must be greater than 0\n");
exit(1);
}
AnnealSched->init_t = 100.0; /* DEFAULT */
if(Options.Count[OT_INIT_T])
{
AnnealSched->init_t = Options.PlaceInitT;
}
if(AnnealSched->init_t <= 0)
{
printf(ERRTAG "init_t must be greater than 0\n");
exit(1);
}
if(AnnealSched->init_t < AnnealSched->exit_t)
{
printf(ERRTAG "init_t must be greater or equal to than exit_t\n");
exit(1);
}
AnnealSched->inner_num = 10.0; /* DEFAULT */
if(Options.Count[OT_FAST]) {
AnnealSched->inner_num = 1.0; /* DEFAULT for fast*/
}
if(Options.Count[OT_INNER_NUM])
{
AnnealSched->inner_num = Options.PlaceInnerNum;
}
if(AnnealSched->inner_num <= 0)
{
printf(ERRTAG "init_t must be greater than 0\n");
exit(1);
}
AnnealSched->type = AUTO_SCHED; /* DEFAULT */
if((Options.Count[OT_ALPHA_T]) ||
(Options.Count[OT_EXIT_T]) || (Options.Count[OT_INIT_T]))
{
AnnealSched->type = USER_SCHED;
}
}
/* Sets up the s_placer_opts structure based on users input. Error checking,
* such as checking for conflicting params is assumed to be done beforehand */
static void
SetupPlacerOpts(IN t_options Options,
IN boolean TimingEnabled,
OUT struct s_placer_opts *PlacerOpts)
{
PlacerOpts->block_dist = 1; /* DEFAULT */
if(Options.Count[OT_BLOCK_DIST])
{
PlacerOpts->block_dist = Options.block_dist;
}
PlacerOpts->inner_loop_recompute_divider = 0; /* DEFAULT */
if(Options.Count[OT_INNER_LOOP_RECOMPUTE_DIVIDER])
{
PlacerOpts->inner_loop_recompute_divider = Options.inner_loop_recompute_divider;
}
PlacerOpts->place_cost_exp = 1.0; /* DEFAULT */
if(Options.Count[OT_PLACE_COST_EXP])
{
PlacerOpts->place_cost_exp = Options.place_cost_exp;
}
PlacerOpts->td_place_exp_first = 1; /* DEFAULT */
if(Options.Count[OT_TD_PLACE_EXP_FIRST])
{
PlacerOpts->td_place_exp_first = Options.place_exp_first;
}
PlacerOpts->td_place_exp_last = 8; /* DEFAULT */
if(Options.Count[OT_TD_PLACE_EXP_LAST])
{
PlacerOpts->td_place_exp_last = Options.place_exp_last;
}
PlacerOpts->place_cost_type = LINEAR_CONG; /* DEFAULT */
if(Options.Count[OT_PLACE_COST_TYPE])
{
PlacerOpts->place_cost_type = Options.PlaceCostType;
}
/* Depends on PlacerOpts->place_cost_type */
PlacerOpts->place_algorithm = BOUNDING_BOX_PLACE; /* DEFAULT */
if(TimingEnabled)
{
PlacerOpts->place_algorithm = PATH_TIMING_DRIVEN_PLACE; /* DEFAULT */
}
if(NONLINEAR_CONG == PlacerOpts->place_cost_type)
{
PlacerOpts->place_algorithm = BOUNDING_BOX_PLACE; /* DEFAULT */
}
if(Options.Count[OT_PLACE_ALGORITHM])
{
PlacerOpts->place_algorithm = Options.PlaceAlgorithm;
}
PlacerOpts->num_regions = 4; /* DEFAULT */
if(Options.Count[OT_NUM_REGIONS])
{
PlacerOpts->num_regions = Options.PlaceNonlinearRegions;
}
PlacerOpts->pad_loc_file = NULL; /* DEFAULT */
if(Options.Count[OT_FIX_PINS])
{
if(Options.PinFile)
{
PlacerOpts->pad_loc_file = my_strdup(Options.PinFile);
}
}
PlacerOpts->pad_loc_type = FREE; /* DEFAULT */
if(Options.Count[OT_FIX_PINS])
{
PlacerOpts->pad_loc_type = (Options.PinFile ? USER : RANDOM);
}
/* Depends on PlacerOpts->place_cost_type */
PlacerOpts->place_chan_width = 100; /* DEFAULT */
if((NONLINEAR_CONG == PlacerOpts->place_cost_type) &&
(Options.Count[OT_ROUTE_CHAN_WIDTH]))
{
PlacerOpts->place_chan_width = Options.RouteChanWidth;
}
if(Options.Count[OT_PLACE_CHAN_WIDTH])
{
PlacerOpts->place_chan_width = Options.PlaceChanWidth;
}
PlacerOpts->recompute_crit_iter = 1; /* DEFAULT */
if(Options.Count[OT_RECOMPUTE_CRIT_ITER])
{
PlacerOpts->recompute_crit_iter = Options.RecomputeCritIter;
}
PlacerOpts->timing_tradeoff = 0.5; /* DEFAULT */
if(Options.Count[OT_TIMING_TRADEOFF])
{
PlacerOpts->timing_tradeoff = Options.PlaceTimingTradeoff;
}
/* Depends on PlacerOpts->place_algorithm */
PlacerOpts->enable_timing_computations = FALSE; /* DEFAULT */
if((PlacerOpts->place_algorithm == PATH_TIMING_DRIVEN_PLACE) ||
(PlacerOpts->place_algorithm == NET_TIMING_DRIVEN_PLACE))
{
PlacerOpts->enable_timing_computations = TRUE; /* DEFAULT */
}
if(Options.Count[OT_ENABLE_TIMING_COMPUTATIONS])
{
PlacerOpts->enable_timing_computations = Options.ShowPlaceTiming;
}
/* Depends on PlacerOpts->place_cost_type */
PlacerOpts->place_freq = PLACE_ONCE; /* DEFAULT */
if(NONLINEAR_CONG == PlacerOpts->place_cost_type)
{
PlacerOpts->place_freq = PLACE_ALWAYS; /* DEFAULT */
}
if((Options.Count[OT_ROUTE_CHAN_WIDTH]) ||
(Options.Count[OT_PLACE_CHAN_WIDTH]))
{
PlacerOpts->place_freq = PLACE_ONCE;
}
if(Options.Count[OT_ROUTE_ONLY])
{
PlacerOpts->place_freq = PLACE_NEVER;
}
}
static void
SetupOperation(IN t_options Options,
OUT enum e_operation *Operation)
{
*Operation = PLACE_AND_ROUTE; /* DEFAULT */
if(Options.Count[OT_ROUTE_ONLY])
{
*Operation = ROUTE_ONLY;
}
if(Options.Count[OT_PLACE_ONLY])
{
*Operation = PLACE_ONLY;
}
if(Options.Count[OT_TIMING_ANALYZE_ONLY_WITH_NET_DELAY])
{
*Operation = TIMING_ANALYSIS_ONLY;
}
}
/* Determines whether timing analysis should be on or off.
Unless otherwise specified, always default to timing.
*/
boolean
IsTimingEnabled(IN t_options Options)
{
/* First priority to the '--timing_analysis' flag */
if(Options.Count[OT_TIMING_ANALYSIS])
{
return Options.TimingAnalysis;
}
return TRUE;
}
/* If a block for a given type does not have subblocks, this creates a subblock for it.
This is used to setup I/Os because I/Os have no subblocks in the netlist */
static void
load_subblock_info_to_type(INOUT t_subblock_data * subblocks,
INOUT t_type_ptr type)
{
int iblk, i;
int *num_subblocks_per_block;
t_subblock **subblock_inf;
num_subblocks_per_block = subblocks->num_subblocks_per_block;
subblock_inf = subblocks->subblock_inf;
/* This is also a hack, IO's have subblocks prespecified */
if(type != IO_TYPE)
{
type_descriptors[type->index].max_subblock_inputs =
type->num_receivers;
type_descriptors[type->index].max_subblock_outputs =
type->num_drivers;
type_descriptors[type->index].max_subblocks = 1;
}
for(iblk = 0; iblk < num_blocks; iblk++)
{
if(block[iblk].type == type)
{
subblock_inf[iblk] =
(t_subblock *) my_malloc(sizeof(t_subblock));
num_subblocks_per_block[iblk] = 1;
subblock_inf[iblk][0].name = block[iblk].name;
subblock_inf[iblk][0].inputs =
(int *)my_malloc(type->max_subblock_inputs *
sizeof(int));
subblock_inf[iblk][0].outputs =
(int *)my_malloc(type->max_subblock_outputs *
sizeof(int));
for(i = 0; i < type->num_pins; i++)
{
if(i < type->max_subblock_inputs)
{
subblock_inf[iblk][0].inputs[i] =
(block[iblk].nets[i] ==
OPEN) ? OPEN : i;
}
else if(i <
type->max_subblock_inputs +
type->max_subblock_outputs)
{
subblock_inf[iblk][0].outputs[i -
type->
max_subblock_inputs]
=
(block[iblk].nets[i] ==
OPEN) ? OPEN : i;
}
else
{
subblock_inf[iblk][0].clock =
(block[iblk].nets[i] ==
OPEN) ? OPEN : i;
}
}
}
}
}