Skip to content

Commit 369623f

Browse files
Merge pull request #3016 from AlexandreSinger/feature-open-sta
[STA] Generating SDC Commands Post-Implementation
2 parents 28aedc1 + 0b1a577 commit 369623f

9 files changed

+203
-4
lines changed

doc/src/vpr/command_line_usage.rst

+10
Original file line numberDiff line numberDiff line change
@@ -1830,6 +1830,16 @@ Analysis Options
18301830

18311831
**Default:** ``off``
18321832

1833+
.. option:: --gen_post_implementation_sdc { on | off }
1834+
1835+
Generates an SDC file including a list of constraints that would
1836+
replicate the timing constraints that the timing analysis within
1837+
VPR followed during the flow. This can be helpful for flows that
1838+
use external timing analysis tools that have additional capabilities
1839+
or more detailed delay models than what VPR uses.
1840+
1841+
**Default:** ``off``
1842+
18331843
.. option:: --post_synth_netlist_unconn_inputs { unconnected | nets | gnd | vcc }
18341844

18351845
Controls how unconnected input cell ports are handled in the post-synthesis netlist

vpr/src/base/SetupVPR.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,7 @@ static void SetupAnalysisOpts(const t_options& Options, t_analysis_opts& analysi
704704

705705
analysis_opts.gen_post_synthesis_netlist = Options.Generate_Post_Synthesis_Netlist;
706706
analysis_opts.gen_post_implementation_merged_netlist = Options.Generate_Post_Implementation_Merged_Netlist;
707+
analysis_opts.gen_post_implementation_sdc = Options.generate_post_implementation_sdc.value();
707708

708709
analysis_opts.timing_report_npaths = Options.timing_report_npaths;
709710
analysis_opts.timing_report_detail = Options.timing_report_detail;

vpr/src/base/ShowSetup.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,8 @@ static void ShowNetlistOpts(const t_netlist_opts& NetlistOpts) {
677677

678678
static void ShowAnalysisOpts(const t_analysis_opts& AnalysisOpts) {
679679
VTR_LOG("AnalysisOpts.gen_post_synthesis_netlist: %s\n", (AnalysisOpts.gen_post_synthesis_netlist) ? "true" : "false");
680+
VTR_LOG("AnalysisOpts.gen_post_implementation_merged_netlist: %s\n", AnalysisOpts.gen_post_implementation_merged_netlist ? "true" : "false");
681+
VTR_LOG("AnalysisOpts.gen_post_implementation_sdc: %s\n", AnalysisOpts.gen_post_implementation_sdc ? "true" : "false");
680682
VTR_LOG("AnalysisOpts.timing_report_npaths: %d\n", AnalysisOpts.timing_report_npaths);
681683
VTR_LOG("AnalysisOpts.timing_report_skew: %s\n", AnalysisOpts.timing_report_skew ? "true" : "false");
682684
VTR_LOG("AnalysisOpts.echo_dot_timing_graph_node: %s\n", AnalysisOpts.echo_dot_timing_graph_node.c_str());

vpr/src/base/netlist_writer.cpp

+158-2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
#include <vector>
7373
#include "atom_netlist.h"
7474
#include "atom_netlist_utils.h"
75+
#include "clock_modeling.h"
7576
#include "globals.h"
7677
#include "logic_vec.h"
7778
#include "netlist_walker.h"
@@ -2644,22 +2645,167 @@ std::string join_identifier(std::string lhs, std::string rhs) {
26442645
return lhs + '_' + rhs;
26452646
}
26462647

2648+
/**
2649+
* @brief Add the original SDC constraints that VPR used during its flow to the
2650+
* given SDC file.
2651+
*
2652+
* @param sdc_os
2653+
* Output stream for the target SDC file. The original SDC file passed into
2654+
* VPR will be appended to this file.
2655+
* @param timing_info
2656+
* Information on the timing within VPR. This is used to get the file path
2657+
* to the original SDC file.
2658+
*/
2659+
void add_original_sdc_to_post_implemented_sdc_file(std::ofstream& sdc_os,
2660+
const t_timing_inf& timing_info) {
2661+
// Open the original SDC file provided to VPR.
2662+
std::ifstream original_sdc_file;
2663+
original_sdc_file.open(timing_info.SDCFile);
2664+
if (!original_sdc_file.is_open()) {
2665+
// TODO: VPR automatically creates SDC constraints by default if no SDC
2666+
// file is provided. These can be replicated here if needed.
2667+
VPR_FATAL_ERROR(VPR_ERROR_IMPL_NETLIST_WRITER,
2668+
"No SDC files provided to VPR; currently cannot generate "
2669+
"post-implementation SDC file without it");
2670+
}
2671+
2672+
// Write a header to declare where these commands came from.
2673+
sdc_os << "\n";
2674+
sdc_os << "#******************************************************************************#\n";
2675+
sdc_os << "# The following SDC commands were provided to VPR from the given SDC file:\n";
2676+
sdc_os << "# \t" << timing_info.SDCFile << "\n";
2677+
sdc_os << "#******************************************************************************#\n";
2678+
2679+
// Append the original SDC file to the post-implementation SDC file.
2680+
sdc_os << original_sdc_file.rdbuf();
2681+
}
2682+
2683+
/**
2684+
* @brief Add propagated clock commands to the given SDC file based on the set
2685+
* clock modeling.
2686+
*
2687+
* This is necessary since VPR decides if clocks are routed or not, which has
2688+
* affects on how timing analysis is performed on the clocks.
2689+
*
2690+
* @param sdc_os
2691+
* The file stream to add the propagated clock commands to.
2692+
* @param clock_modeling
2693+
* The type of clock modeling used by VPR during the CAD flow.
2694+
*/
2695+
void add_propagated_clocks_to_sdc_file(std::ofstream& sdc_os,
2696+
e_clock_modeling clock_modeling) {
2697+
2698+
// Ideal and routed clocks are handled by the code below. Other clock models
2699+
// like dedicated routing are not supported yet.
2700+
// TODO: Supporting dedicated routing should be simple; however it should
2701+
// be investigated. Tried quickly but found that the delays produced
2702+
// were off by 0.003 ns. Need to investigate why.
2703+
if (clock_modeling != e_clock_modeling::ROUTED_CLOCK && clock_modeling != e_clock_modeling::IDEAL_CLOCK) {
2704+
VPR_FATAL_ERROR(VPR_ERROR_IMPL_NETLIST_WRITER,
2705+
"Only ideal and routed clock modeling are currentlt "
2706+
"supported for post-implementation SDC file generation");
2707+
}
2708+
2709+
// The timing constraints contain information on all the clocks in the circuit
2710+
// (provided by the user-provided SDC file).
2711+
const auto timing_constraints = g_vpr_ctx.timing().constraints;
2712+
2713+
// Collect the non-virtual clocks. Virtual clocks are not routed and
2714+
// do not get propageted.
2715+
std::vector<tatum::DomainId> non_virtual_clocks;
2716+
for (tatum::DomainId clock_domain_id : timing_constraints->clock_domains()) {
2717+
if (!timing_constraints->is_virtual_clock(clock_domain_id)) {
2718+
non_virtual_clocks.push_back(clock_domain_id);
2719+
}
2720+
}
2721+
2722+
// If there are no non-virtual clocks, no extra commands needed. Virtual
2723+
// clocks are ideal.
2724+
if (non_virtual_clocks.empty()) {
2725+
return;
2726+
}
2727+
2728+
// Append a header to explain why these commands are added.
2729+
sdc_os << "\n";
2730+
sdc_os << "#******************************************************************************#\n";
2731+
sdc_os << "# The following are clock domains in VPR which have delays on their edges.\n";
2732+
sdc_os << "#\n";
2733+
sdc_os << "# Any non-virtual clock has its delay determined and written out as part of a";
2734+
sdc_os << "# propagated clock command. If VPR was instructed not to route the clock, this";
2735+
sdc_os << "# delay will be an underestimate.\n";
2736+
sdc_os << "#\n";
2737+
sdc_os << "# Note: Virtual clocks do not get routed and are treated as ideal.\n";
2738+
sdc_os << "#******************************************************************************#\n";
2739+
2740+
// Add the SDC commands to set the non-virtual clocks as propagated (non-ideal);
2741+
// Note: It was decided that "ideal" (dont route) clock modeling in VPR should still
2742+
// set the clocks as propagated to allow for the input pad delays of
2743+
// clocks to be included. The SDF delay annotations on clock signals
2744+
// should make this safe to do.
2745+
for (tatum::DomainId clock_domain_id : non_virtual_clocks) {
2746+
sdc_os << "set_propagated_clock ";
2747+
sdc_os << timing_constraints->clock_domain_name(clock_domain_id);
2748+
sdc_os << "\n";
2749+
}
2750+
}
2751+
2752+
/**
2753+
* @brief Generates a post-implementation SDC file with the given file name
2754+
* based on the timing info and clock modeling set for VPR.
2755+
*
2756+
* @param sdc_filename
2757+
* The file name of the SDC file to generate.
2758+
* @param timing_info
2759+
* Information on the timing used in the VPR flow.
2760+
* @param clock_modeling
2761+
* The type of clock modeling used by VPR during its flow.
2762+
*/
2763+
void generate_post_implementation_sdc(const std::string& sdc_filename,
2764+
const t_timing_inf& timing_info,
2765+
e_clock_modeling clock_modeling) {
2766+
if (!timing_info.timing_analysis_enabled) {
2767+
VTR_LOG_WARN("Timing analysis is disabled. Post-implementation SDC file "
2768+
"will not be generated.\n");
2769+
return;
2770+
}
2771+
2772+
// Begin writing the post-implementation SDC file.
2773+
std::ofstream sdc_os(sdc_filename);
2774+
2775+
// Print a header declaring that this file is auto-generated and what version
2776+
// of VTR produced it.
2777+
sdc_os << "#******************************************************************************#\n";
2778+
sdc_os << "# SDC automatically generated by VPR from a post-place-and-route implementation.\n";
2779+
sdc_os << "#\tVersion: " << vtr::VERSION << "\n";
2780+
sdc_os << "#******************************************************************************#\n";
2781+
2782+
// Add the original SDC that VPR used during its flow.
2783+
add_original_sdc_to_post_implemented_sdc_file(sdc_os, timing_info);
2784+
2785+
// Add propagated clocks to SDC file if needed.
2786+
add_propagated_clocks_to_sdc_file(sdc_os, clock_modeling);
2787+
}
2788+
26472789
} // namespace
26482790

26492791
//
26502792
// Externally Accessible Functions
26512793
//
26522794

26532795
///@brief Main routine for this file. See netlist_writer.h for details.
2654-
void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDelayCalculator> delay_calc, const LogicalModels& models, t_analysis_opts opts) {
2796+
void netlist_writer(const std::string basename,
2797+
std::shared_ptr<const AnalysisDelayCalculator> delay_calc,
2798+
const LogicalModels& models,
2799+
const t_timing_inf& timing_info,
2800+
e_clock_modeling clock_modeling,
2801+
t_analysis_opts opts) {
26552802
std::string verilog_filename = basename + "_post_synthesis.v";
26562803
std::string blif_filename = basename + "_post_synthesis.blif";
26572804
std::string sdf_filename = basename + "_post_synthesis.sdf";
26582805

26592806
VTR_LOG("Writing Implementation Netlist: %s\n", verilog_filename.c_str());
26602807
VTR_LOG("Writing Implementation Netlist: %s\n", blif_filename.c_str());
26612808
VTR_LOG("Writing Implementation SDF : %s\n", sdf_filename.c_str());
2662-
26632809
std::ofstream verilog_os(verilog_filename);
26642810
std::ofstream blif_os(blif_filename);
26652811
std::ofstream sdf_os(sdf_filename);
@@ -2669,6 +2815,16 @@ void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDe
26692815
NetlistWalker nl_walker(visitor);
26702816

26712817
nl_walker.walk();
2818+
2819+
if (opts.gen_post_implementation_sdc) {
2820+
std::string sdc_filename = basename + "_post_synthesis.sdc";
2821+
2822+
VTR_LOG("Writing Implementation SDC : %s\n", sdc_filename.c_str());
2823+
2824+
generate_post_implementation_sdc(sdc_filename,
2825+
timing_info,
2826+
clock_modeling);
2827+
}
26722828
}
26732829

26742830
///@brief Main routine for this file. See netlist_writer.h for details.

vpr/src/base/netlist_writer.h

+19-1
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,26 @@ class LogicalModels;
1515
*
1616
* All written filenames end in {basename}_post_synthesis.{fmt} where {basename} is the
1717
* basename argument and {fmt} is the file format (e.g. v, blif, sdf)
18+
*
19+
* @param basename
20+
* The basename prefix used for the generated files.
21+
* @param delay_calc
22+
* The delay calculator used to get the timing of edges in the timing graph.
23+
* @param models
24+
* The logical models in the architecture.
25+
* @param timing_info
26+
* Information on the timing used in the VPR flow.
27+
* @param clock_modeling
28+
* The type of clock modeling used in the VPR flow.
29+
* @param opts
30+
* The analysis options.
1831
*/
19-
void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDelayCalculator> delay_calc, const LogicalModels& models, t_analysis_opts opts);
32+
void netlist_writer(const std::string basename,
33+
std::shared_ptr<const AnalysisDelayCalculator> delay_calc,
34+
const LogicalModels& models,
35+
const t_timing_inf& timing_info,
36+
e_clock_modeling clock_modeling,
37+
t_analysis_opts opts);
2038

2139
/**
2240
* @brief Writes out the post implementation netlist in Verilog format.

vpr/src/base/read_options.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -3012,6 +3012,16 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
30123012
.default_value("off")
30133013
.show_in(argparse::ShowIn::HELP_ONLY);
30143014

3015+
analysis_grp.add_argument<bool, ParseOnOff>(args.generate_post_implementation_sdc, "--gen_post_implementation_sdc")
3016+
.help(
3017+
"Generates an SDC file including a list of constraints that would "
3018+
"replicate the timing constraints that the timing analysis within "
3019+
"VPR followed during the flow. This can be helpful for flows that "
3020+
"use external timing analysis tools that have additional capabilities "
3021+
"or more detailed delay models than what VPR uses")
3022+
.default_value("off")
3023+
.show_in(argparse::ShowIn::HELP_ONLY);
3024+
30153025
analysis_grp.add_argument(args.timing_report_npaths, "--timing_report_npaths")
30163026
.help("Controls how many timing paths are reported.")
30173027
.default_value("100")

vpr/src/base/read_options.h

+1
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ struct t_options {
263263
argparse::ArgValue<bool> full_stats;
264264
argparse::ArgValue<bool> Generate_Post_Synthesis_Netlist;
265265
argparse::ArgValue<bool> Generate_Post_Implementation_Merged_Netlist;
266+
argparse::ArgValue<bool> generate_post_implementation_sdc;
266267
argparse::ArgValue<int> timing_report_npaths;
267268
argparse::ArgValue<e_timing_report_detail> timing_report_detail;
268269
argparse::ArgValue<bool> timing_report_skew;

vpr/src/base/vpr_api.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1467,7 +1467,7 @@ void vpr_analysis(const Netlist<>& net_list,
14671467
//Write the post-synthesis netlist
14681468
if (vpr_setup.AnalysisOpts.gen_post_synthesis_netlist) {
14691469
netlist_writer(atom_ctx.netlist().netlist_name(), analysis_delay_calc,
1470-
Arch.models, vpr_setup.AnalysisOpts);
1470+
Arch.models, vpr_setup.Timing, vpr_setup.clock_modeling, vpr_setup.AnalysisOpts);
14711471
}
14721472

14731473
//Write the post-implementation merged netlist

vpr/src/base/vpr_types.h

+1
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,7 @@ struct t_analysis_opts {
13421342

13431343
bool gen_post_synthesis_netlist;
13441344
bool gen_post_implementation_merged_netlist;
1345+
bool gen_post_implementation_sdc;
13451346
e_post_synth_netlist_unconn_handling post_synth_netlist_unconn_input_handling;
13461347
e_post_synth_netlist_unconn_handling post_synth_netlist_unconn_output_handling;
13471348
bool post_synth_netlist_module_parameters;

0 commit comments

Comments
 (0)