blob: 2bd43848964d5064e161bbe9afc937452b846131 [file] [log] [blame]
#include <cstring>
#include <vector>
#include <sstream>
#include "vtr_assert.h"
#include "vtr_util.h"
#include "vtr_random.h"
#include "vtr_log.h"
#include "vtr_memory.h"
#include "vtr_time.h"
#include "vpr_types.h"
#include "vpr_error.h"
#include "vpr_utils.h"
#include "globals.h"
#include "read_xml_arch_file.h"
#include "SetupVPR.h"
#include "pb_type_graph.h"
#include "pack_types.h"
#include "lb_type_rr_graph.h"
#include "rr_graph_area.h"
#include "echo_arch.h"
#include "read_options.h"
#include "echo_files.h"
#include "clock_modeling.h"
static void SetupNetlistOpts(const t_options& Options, t_netlist_opts& NetlistOpts);
static void SetupPackerOpts(const t_options& Options,
t_packer_opts* PackerOpts);
static void SetupPlacerOpts(const t_options& Options,
t_placer_opts* PlacerOpts);
static void SetupAnnealSched(const t_options& Options,
t_annealing_sched* AnnealSched);
static void SetupRouterOpts(const t_options& Options, t_router_opts* RouterOpts);
static void SetupRoutingArch(const t_arch& Arch, t_det_routing_arch* RoutingArch);
static void SetupTiming(const t_options& Options, const bool TimingEnabled, t_timing_inf* Timing);
static void SetupSwitches(const t_arch& Arch,
t_det_routing_arch* RoutingArch,
const t_arch_switch_inf* ArchSwitches,
int NumArchSwitches);
static void SetupAnalysisOpts(const t_options& Options, t_analysis_opts& analysis_opts);
static void SetupPowerOpts(const t_options& Options, t_power_opts* power_opts, t_arch* Arch);
static int find_ipin_cblock_switch_index(const t_arch& Arch);
/* Sets VPR parameters and defaults. Does not do any error checking
* as this should have been done by the various input checkers */
void SetupVPR(const t_options* Options,
const bool TimingEnabled,
const bool readArchFile,
t_file_name_opts* FileNameOpts,
t_arch* Arch,
t_model** user_models,
t_model** library_models,
t_netlist_opts* NetlistOpts,
t_packer_opts* PackerOpts,
t_placer_opts* PlacerOpts,
t_annealing_sched* AnnealSched,
t_router_opts* RouterOpts,
t_analysis_opts* AnalysisOpts,
t_det_routing_arch* RoutingArch,
std::vector<t_lb_type_rr_node>** PackerRRGraphs,
std::vector<t_segment_inf>& Segments,
t_timing_inf* Timing,
bool* ShowGraphics,
int* GraphPause,
bool* SaveGraphics,
t_power_opts* PowerOpts) {
using argparse::Provenance;
auto& device_ctx = g_vpr_ctx.mutable_device();
if (Options->CircuitName.value() == "") {
VPR_FATAL_ERROR(VPR_ERROR_BLIF_F,
"No blif file found in arguments (did you specify an architecture file?)\n");
}
alloc_and_load_output_file_names(Options->CircuitName);
//TODO: Move FileNameOpts setup into separate function
FileNameOpts->CircuitName = Options->CircuitName;
FileNameOpts->ArchFile = Options->ArchFile;
FileNameOpts->BlifFile = Options->BlifFile;
FileNameOpts->NetFile = Options->NetFile;
FileNameOpts->PlaceFile = Options->PlaceFile;
FileNameOpts->RouteFile = Options->RouteFile;
FileNameOpts->ActFile = Options->ActFile;
FileNameOpts->PowerFile = Options->PowerFile;
FileNameOpts->CmosTechFile = Options->CmosTechFile;
FileNameOpts->out_file_prefix = Options->out_file_prefix;
FileNameOpts->verify_file_digests = Options->verify_file_digests;
SetupNetlistOpts(*Options, *NetlistOpts);
SetupPlacerOpts(*Options, PlacerOpts);
SetupAnnealSched(*Options, AnnealSched);
SetupRouterOpts(*Options, RouterOpts);
SetupAnalysisOpts(*Options, *AnalysisOpts);
SetupPowerOpts(*Options, PowerOpts, Arch);
if (readArchFile == true) {
vtr::ScopedStartFinishTimer t("Loading Architecture Description");
XmlReadArch(Options->ArchFile.value().c_str(),
TimingEnabled,
Arch,
device_ctx.physical_tile_types,
device_ctx.logical_block_types);
}
*user_models = Arch->models;
*library_models = Arch->model_library;
/* TODO: this is inelegant, I should be populating this information in XmlReadArch */
device_ctx.EMPTY_TYPE = nullptr;
for (const auto& type : device_ctx.physical_tile_types) {
if (strcmp(type.name, EMPTY_BLOCK_NAME) == 0) {
VTR_ASSERT(device_ctx.EMPTY_TYPE == nullptr);
device_ctx.EMPTY_TYPE = &type;
} else {
if (block_type_contains_blif_model(logical_block_type(&type), MODEL_INPUT)) {
device_ctx.input_types.insert(&type);
}
if (block_type_contains_blif_model(logical_block_type(&type), MODEL_OUTPUT)) {
device_ctx.output_types.insert(&type);
}
}
}
VTR_ASSERT(device_ctx.EMPTY_TYPE != nullptr);
if (device_ctx.input_types.empty()) {
VPR_ERROR(VPR_ERROR_ARCH,
"Architecture contains no top-level block type containing '.input' models");
}
if (device_ctx.output_types.empty()) {
VPR_ERROR(VPR_ERROR_ARCH,
"Architecture contains no top-level block type containing '.output' models");
}
Segments = Arch->Segments;
SetupSwitches(*Arch, RoutingArch, Arch->Switches, Arch->num_switches);
SetupRoutingArch(*Arch, RoutingArch);
SetupTiming(*Options, TimingEnabled, Timing);
SetupPackerOpts(*Options, PackerOpts);
RoutingArch->write_rr_graph_filename = Options->write_rr_graph_file;
RoutingArch->read_rr_graph_filename = Options->read_rr_graph_file;
//Setup the default flow, if no specific stages specified
//do all
if (!Options->do_packing
&& !Options->do_placement
&& !Options->do_routing
&& !Options->do_analysis) {
//run all stages if none specified
PackerOpts->doPacking = STAGE_DO;
PlacerOpts->doPlacement = STAGE_DO;
RouterOpts->doRouting = STAGE_DO;
AnalysisOpts->doAnalysis = STAGE_AUTO; //Deferred until implementation status known
} else {
//We run all stages up to the specified stage
//Note that by checking in reverse order (i.e. analysis to packing)
//we ensure that earlier stages override the default 'LOAD' action
//set by later stages
if (Options->do_analysis) {
PackerOpts->doPacking = STAGE_LOAD;
PlacerOpts->doPlacement = STAGE_LOAD;
RouterOpts->doRouting = STAGE_LOAD;
AnalysisOpts->doAnalysis = STAGE_DO;
}
if (Options->do_routing) {
PackerOpts->doPacking = STAGE_LOAD;
PlacerOpts->doPlacement = STAGE_LOAD;
RouterOpts->doRouting = STAGE_DO;
AnalysisOpts->doAnalysis = ((Options->do_analysis) ? STAGE_DO : STAGE_AUTO); //Always run analysis after routing
}
if (Options->do_placement) {
PackerOpts->doPacking = STAGE_LOAD;
PlacerOpts->doPlacement = STAGE_DO;
}
if (Options->do_packing) {
PackerOpts->doPacking = STAGE_DO;
}
}
/* init global variables */
vtr::out_file_prefix = Options->out_file_prefix;
/* Set seed for pseudo-random placement, default seed to 1 */
PlacerOpts->seed = Options->Seed;
vtr::srandom(PlacerOpts->seed);
{
vtr::ScopedStartFinishTimer t("Building complex block graph");
alloc_and_load_all_pb_graphs(PowerOpts->do_power);
*PackerRRGraphs = alloc_and_load_all_lb_type_rr_graph();
}
if ((Options->clock_modeling == ROUTED_CLOCK) || (Options->clock_modeling == DEDICATED_NETWORK)) {
ClockModeling::treat_clock_pins_as_non_globals();
}
if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_LB_TYPE_RR_GRAPH)) {
echo_lb_type_rr_graphs(getEchoFileName(E_ECHO_LB_TYPE_RR_GRAPH), *PackerRRGraphs);
}
if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_PB_GRAPH)) {
echo_pb_graph(getEchoFileName(E_ECHO_PB_GRAPH));
}
*GraphPause = Options->GraphPause;
*ShowGraphics = Options->show_graphics;
*SaveGraphics = Options->save_graphics;
if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_ARCH)) {
EchoArch(getEchoFileName(E_ECHO_ARCH), device_ctx.physical_tile_types, device_ctx.logical_block_types, Arch);
}
}
static void SetupTiming(const t_options& Options, const bool TimingEnabled, t_timing_inf* Timing) {
/* Don't do anything if they don't want timing */
if (false == TimingEnabled) {
Timing->timing_analysis_enabled = false;
return;
}
Timing->timing_analysis_enabled = TimingEnabled;
Timing->SDCFile = Options.SDCFile;
}
/* This loads up VPR's arch_switch_inf data by combining the switches from
* the arch file with the special switches that VPR needs. */
static void SetupSwitches(const t_arch& Arch,
t_det_routing_arch* RoutingArch,
const t_arch_switch_inf* ArchSwitches,
int NumArchSwitches) {
auto& device_ctx = g_vpr_ctx.mutable_device();
int switches_to_copy = NumArchSwitches;
device_ctx.num_arch_switches = NumArchSwitches;
RoutingArch->wire_to_arch_ipin_switch = find_ipin_cblock_switch_index(Arch);
/* Depends on device_ctx.num_arch_switches */
RoutingArch->delayless_switch = device_ctx.num_arch_switches++;
/* Alloc the list now that we know the final num_arch_switches value */
device_ctx.arch_switch_inf = new t_arch_switch_inf[device_ctx.num_arch_switches];
for (int iswitch = 0; iswitch < switches_to_copy; iswitch++) {
device_ctx.arch_switch_inf[iswitch] = ArchSwitches[iswitch];
}
/* Delayless switch for connecting sinks and sources with their pins. */
device_ctx.arch_switch_inf[RoutingArch->delayless_switch].set_type(SwitchType::MUX);
device_ctx.arch_switch_inf[RoutingArch->delayless_switch].name = vtr::strdup("__vpr_delayless_switch__");
device_ctx.arch_switch_inf[RoutingArch->delayless_switch].R = 0.;
device_ctx.arch_switch_inf[RoutingArch->delayless_switch].Cin = 0.;
device_ctx.arch_switch_inf[RoutingArch->delayless_switch].Cout = 0.;
device_ctx.arch_switch_inf[RoutingArch->delayless_switch].set_Tdel(t_arch_switch_inf::UNDEFINED_FANIN, 0.);
device_ctx.arch_switch_inf[RoutingArch->delayless_switch].power_buffer_type = POWER_BUFFER_TYPE_NONE;
device_ctx.arch_switch_inf[RoutingArch->delayless_switch].mux_trans_size = 0.;
device_ctx.arch_switch_inf[RoutingArch->delayless_switch].buf_size_type = BufferSize::ABSOLUTE;
device_ctx.arch_switch_inf[RoutingArch->delayless_switch].buf_size = 0.;
VTR_ASSERT_MSG(device_ctx.arch_switch_inf[RoutingArch->delayless_switch].buffered(), "Delayless switch expected to be buffered (isolating)");
VTR_ASSERT_MSG(device_ctx.arch_switch_inf[RoutingArch->delayless_switch].configurable(), "Delayless switch expected to be configurable");
RoutingArch->global_route_switch = RoutingArch->delayless_switch;
//Warn about non-zero Cout values for the ipin switch, since these values have no effect.
//VPR do not model the R/C's of block internal routing connectsion.
//
//Note that we don't warn about the R value as it may be used to size the buffer (if buf_size_type is AUTO)
if (device_ctx.arch_switch_inf[RoutingArch->wire_to_arch_ipin_switch].Cout != 0.) {
VTR_LOG_WARN("Non-zero switch output capacitance (%g) has no effect when switch '%s' is used for connection block inputs\n",
device_ctx.arch_switch_inf[RoutingArch->wire_to_arch_ipin_switch].Cout, Arch.ipin_cblock_switch_name.c_str());
}
}
/* Sets up routing structures. Since checks are already done, this
* just copies values across */
static void SetupRoutingArch(const t_arch& Arch,
t_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.size()) {
RoutingArch->directionality = Arch.Segments[0].directionality;
}
/* copy over the switch block information */
RoutingArch->switchblocks = Arch.switchblocks;
}
static void SetupRouterOpts(const t_options& Options, t_router_opts* RouterOpts) {
RouterOpts->astar_fac = Options.astar_fac;
RouterOpts->bb_factor = Options.bb_factor;
RouterOpts->criticality_exp = Options.criticality_exp;
RouterOpts->max_criticality = Options.max_criticality;
RouterOpts->max_router_iterations = Options.max_router_iterations;
RouterOpts->init_wirelength_abort_threshold = Options.router_init_wirelength_abort_threshold;
RouterOpts->min_incremental_reroute_fanout = Options.min_incremental_reroute_fanout;
RouterOpts->incr_reroute_delay_ripup = Options.incr_reroute_delay_ripup;
RouterOpts->pres_fac_mult = Options.pres_fac_mult;
RouterOpts->route_type = Options.RouteType;
RouterOpts->full_stats = Options.full_stats;
//TODO document these?
RouterOpts->congestion_analysis = Options.full_stats;
RouterOpts->fanout_analysis = Options.full_stats;
RouterOpts->switch_usage_analysis = Options.full_stats;
RouterOpts->verify_binary_search = Options.verify_binary_search;
RouterOpts->router_algorithm = Options.RouterAlgorithm;
RouterOpts->fixed_channel_width = Options.RouteChanWidth;
RouterOpts->min_channel_width_hint = Options.min_route_chan_width_hint;
//TODO document these?
RouterOpts->trim_empty_channels = false; /* DEFAULT */
RouterOpts->trim_obs_channels = false; /* DEFAULT */
RouterOpts->initial_pres_fac = Options.initial_pres_fac;
RouterOpts->base_cost_type = Options.base_cost_type;
RouterOpts->first_iter_pres_fac = Options.first_iter_pres_fac;
RouterOpts->acc_fac = Options.acc_fac;
RouterOpts->bend_cost = Options.bend_cost;
if (Options.do_routing) {
RouterOpts->doRouting = STAGE_DO;
}
RouterOpts->routing_failure_predictor = Options.routing_failure_predictor;
RouterOpts->routing_budgets_algorithm = Options.routing_budgets_algorithm;
RouterOpts->save_routing_per_iteration = Options.save_routing_per_iteration;
RouterOpts->congested_routing_iteration_threshold_frac = Options.congested_routing_iteration_threshold_frac;
RouterOpts->route_bb_update = Options.route_bb_update;
RouterOpts->clock_modeling = Options.clock_modeling;
RouterOpts->high_fanout_threshold = Options.router_high_fanout_threshold;
RouterOpts->router_debug_net = Options.router_debug_net;
RouterOpts->router_debug_sink_rr = Options.router_debug_sink_rr;
RouterOpts->lookahead_type = Options.router_lookahead_type;
RouterOpts->max_convergence_count = Options.router_max_convergence_count;
RouterOpts->reconvergence_cpd_threshold = Options.router_reconvergence_cpd_threshold;
RouterOpts->first_iteration_timing_report_file = Options.router_first_iteration_timing_report_file;
RouterOpts->strict_checks = Options.strict_checks;
RouterOpts->write_router_lookahead = Options.write_router_lookahead;
RouterOpts->read_router_lookahead = Options.read_router_lookahead;
}
static void SetupAnnealSched(const t_options& Options,
t_annealing_sched* AnnealSched) {
AnnealSched->alpha_t = Options.PlaceAlphaT;
if (AnnealSched->alpha_t >= 1 || AnnealSched->alpha_t <= 0) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER, "alpha_t must be between 0 and 1 exclusive.\n");
}
AnnealSched->exit_t = Options.PlaceExitT;
if (AnnealSched->exit_t <= 0) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER, "exit_t must be greater than 0.\n");
}
AnnealSched->init_t = Options.PlaceInitT;
if (AnnealSched->init_t <= 0) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER, "init_t must be greater than 0.\n");
}
if (AnnealSched->init_t < AnnealSched->exit_t) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER, "init_t must be greater or equal to than exit_t.\n");
}
AnnealSched->inner_num = Options.PlaceInnerNum;
if (AnnealSched->inner_num <= 0) {
VPR_FATAL_ERROR(VPR_ERROR_OTHER, "inner_num must be greater than 0.\n");
}
AnnealSched->type = Options.anneal_sched_type;
}
/* Sets up the s_packer_opts structure baesd on users inputs and on the architecture specified.
* Error checking, such as checking for conflicting params is assumed to be done beforehand
*/
void SetupPackerOpts(const t_options& Options,
t_packer_opts* PackerOpts) {
PackerOpts->output_file = Options.NetFile;
PackerOpts->blif_file_name = Options.BlifFile;
if (Options.do_packing) {
PackerOpts->doPacking = STAGE_DO;
}
//TODO: document?
PackerOpts->global_clocks = true; /* DEFAULT */
PackerOpts->hill_climbing_flag = false; /* DEFAULT */
PackerOpts->allow_unrelated_clustering = Options.allow_unrelated_clustering;
PackerOpts->connection_driven = Options.connection_driven_clustering;
PackerOpts->timing_driven = Options.timing_driven_clustering;
PackerOpts->cluster_seed_type = Options.cluster_seed_type;
PackerOpts->alpha = Options.alpha_clustering;
PackerOpts->beta = Options.beta_clustering;
PackerOpts->pack_verbosity = Options.pack_verbosity;
PackerOpts->enable_pin_feasibility_filter = Options.enable_clustering_pin_feasibility_filter;
PackerOpts->balance_block_type_utilization = Options.balance_block_type_utilization;
PackerOpts->target_external_pin_util = Options.target_external_pin_util;
PackerOpts->target_device_utilization = Options.target_device_utilization;
PackerOpts->prioritize_transitive_connectivity = Options.pack_prioritize_transitive_connectivity;
PackerOpts->high_fanout_threshold = Options.pack_high_fanout_threshold;
PackerOpts->transitive_fanout_threshold = Options.pack_transitive_fanout_threshold;
PackerOpts->feasible_block_array_size = Options.pack_feasible_block_array_size;
//TODO: document?
PackerOpts->inter_cluster_net_delay = 1.0; /* DEFAULT */
PackerOpts->auto_compute_inter_cluster_net_delay = true;
PackerOpts->packer_algorithm = PACK_GREEDY; /* DEFAULT */
PackerOpts->device_layout = Options.device_layout;
}
static void SetupNetlistOpts(const t_options& Options, t_netlist_opts& NetlistOpts) {
NetlistOpts.const_gen_inference = Options.const_gen_inference;
NetlistOpts.absorb_buffer_luts = Options.absorb_buffer_luts;
NetlistOpts.sweep_dangling_primary_ios = Options.sweep_dangling_primary_ios;
NetlistOpts.sweep_dangling_nets = Options.sweep_dangling_nets;
NetlistOpts.sweep_dangling_blocks = Options.sweep_dangling_blocks;
NetlistOpts.sweep_constant_primary_outputs = Options.sweep_constant_primary_outputs;
NetlistOpts.netlist_verbosity = Options.netlist_verbosity;
}
/* 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(const t_options& Options, t_placer_opts* PlacerOpts) {
if (Options.do_placement) {
PlacerOpts->doPlacement = STAGE_DO;
}
PlacerOpts->inner_loop_recompute_divider = Options.inner_loop_recompute_divider;
//TODO: document?
PlacerOpts->place_cost_exp = 1;
PlacerOpts->td_place_exp_first = Options.place_exp_first;
PlacerOpts->td_place_exp_last = Options.place_exp_last;
PlacerOpts->place_algorithm = Options.PlaceAlgorithm;
PlacerOpts->pad_loc_file = Options.pad_loc_file;
PlacerOpts->pad_loc_type = Options.pad_loc_type;
PlacerOpts->place_chan_width = Options.PlaceChanWidth;
PlacerOpts->recompute_crit_iter = Options.RecomputeCritIter;
PlacerOpts->timing_tradeoff = Options.PlaceTimingTradeoff;
/* Depends on PlacerOpts->place_algorithm */
PlacerOpts->enable_timing_computations = Options.ShowPlaceTiming;
PlacerOpts->delay_offset = Options.place_delay_offset;
PlacerOpts->delay_ramp_delta_threshold = Options.place_delay_ramp_delta_threshold;
PlacerOpts->delay_ramp_slope = Options.place_delay_ramp_slope;
PlacerOpts->tsu_rel_margin = Options.place_tsu_rel_margin;
PlacerOpts->tsu_abs_margin = Options.place_tsu_abs_margin;
PlacerOpts->delay_model_type = Options.place_delay_model;
PlacerOpts->delay_model_reducer = Options.place_delay_model_reducer;
//TODO: document?
PlacerOpts->place_freq = PLACE_ONCE; /* DEFAULT */
PlacerOpts->post_place_timing_report_file = Options.post_place_timing_report_file;
PlacerOpts->rlim_escape_fraction = Options.place_rlim_escape_fraction;
PlacerOpts->move_stats_file = Options.place_move_stats_file;
PlacerOpts->strict_checks = Options.strict_checks;
PlacerOpts->write_placement_delay_lookup = Options.write_placement_delay_lookup;
PlacerOpts->read_placement_delay_lookup = Options.read_placement_delay_lookup;
PlacerOpts->allowed_tiles_for_delay_model = Options.allowed_tiles_for_delay_model;
}
static void SetupAnalysisOpts(const t_options& Options, t_analysis_opts& analysis_opts) {
if (Options.do_analysis) {
analysis_opts.doAnalysis = STAGE_DO;
}
analysis_opts.gen_post_synthesis_netlist = Options.Generate_Post_Synthesis_Netlist;
analysis_opts.timing_report_npaths = Options.timing_report_npaths;
analysis_opts.timing_report_detail = Options.timing_report_detail;
analysis_opts.timing_report_skew = Options.timing_report_skew;
}
static void SetupPowerOpts(const t_options& Options, t_power_opts* power_opts, t_arch* Arch) {
auto& device_ctx = g_vpr_ctx.mutable_device();
power_opts->do_power = Options.do_power;
if (power_opts->do_power) {
if (!Arch->power)
Arch->power = (t_power_arch*)vtr::malloc(sizeof(t_power_arch));
if (!Arch->clocks)
Arch->clocks = (t_clock_arch*)vtr::malloc(sizeof(t_clock_arch));
device_ctx.clock_arch = Arch->clocks;
} else {
Arch->power = nullptr;
Arch->clocks = nullptr;
device_ctx.clock_arch = nullptr;
}
}
static int find_ipin_cblock_switch_index(const t_arch& Arch) {
int ipin_cblock_switch_index = UNDEFINED;
for (int i = 0; i < Arch.num_switches; ++i) {
if (Arch.Switches[i].name == Arch.ipin_cblock_switch_name) {
if (ipin_cblock_switch_index != UNDEFINED) {
VPR_FATAL_ERROR(VPR_ERROR_ARCH, "Found duplicate switches named '%s'\n", Arch.ipin_cblock_switch_name.c_str());
} else {
ipin_cblock_switch_index = i;
}
}
}
if (ipin_cblock_switch_index == UNDEFINED) {
VPR_FATAL_ERROR(VPR_ERROR_ARCH, "Failed to find connection block input pin switch named '%s'\n", Arch.ipin_cblock_switch_name.c_str());
}
return ipin_cblock_switch_index;
}