-
Notifications
You must be signed in to change notification settings - Fork 409
[STA] Generating SDC Commands Post-Implementation #3016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,6 +72,7 @@ | |
#include <vector> | ||
#include "atom_netlist.h" | ||
#include "atom_netlist_utils.h" | ||
#include "clock_modeling.h" | ||
#include "globals.h" | ||
#include "logic_vec.h" | ||
#include "netlist_walker.h" | ||
|
@@ -2644,22 +2645,145 @@ std::string join_identifier(std::string lhs, std::string rhs) { | |
return lhs + '_' + rhs; | ||
} | ||
|
||
/** | ||
* @brief Add the original SDC constraints that VPR used during its flow to the | ||
* given SDC file. | ||
*/ | ||
void add_original_sdc_to_post_implemented_sdc_file(std::ofstream& sdc_os, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. static method? Or move comment to header file. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment if you append to the sdc_os stream, or expect it to be empty. |
||
const t_timing_inf& timing_info) { | ||
// Open the original SDC file provided to VPR. | ||
std::ifstream original_sdc_file; | ||
original_sdc_file.open(timing_info.SDCFile); | ||
if (!original_sdc_file.is_open()) { | ||
// TODO: VPR automatically creates SDC constraints by default if no SDC | ||
// file is provided. These can be replicated here if needed. | ||
VPR_FATAL_ERROR(VPR_ERROR_IMPL_NETLIST_WRITER, | ||
"No SDC files provided to VPR, currently cannot generate " | ||
"post-implementation SDC file without it"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. VPR, currently --> VPR; currently ... (add period at end). |
||
} | ||
|
||
// Write a header to declare where these commands came from. | ||
sdc_os << "\n"; | ||
sdc_os << "#******************************************************************************#\n"; | ||
sdc_os << "# The following SDC commands were provided to VPR from the given SDC file:\n"; | ||
sdc_os << "# \t" << timing_info.SDCFile << "\n"; | ||
sdc_os << "#******************************************************************************#\n"; | ||
|
||
// Append the original SDC file to the post-implementation SDC file. | ||
sdc_os << original_sdc_file.rdbuf(); | ||
} | ||
|
||
/** | ||
* @brief Add propagated clock commands to the given SDC file based on the set | ||
* clock modeling. | ||
* | ||
* This is necessary since VPR decides if clocks are routed or not, which has | ||
* affects on how timing analysis is performed on the clocks. | ||
*/ | ||
void add_propagated_clocks_to_sdc_file(std::ofstream& sdc_os, | ||
e_clock_modeling clock_modeling) { | ||
|
||
// Ideal and routed clocks are handled by the code below. Other clock models | ||
// like dedicated routing are not supported yet. | ||
if (clock_modeling != e_clock_modeling::ROUTED_CLOCK && clock_modeling != e_clock_modeling::IDEAL_CLOCK) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should work. We should already extract the delays and your code path presumably already writes those out as propagated clock delays. |
||
VPR_FATAL_ERROR(VPR_ERROR_IMPL_NETLIST_WRITER, | ||
"Only ideal and routed clock modeling are currentlt " | ||
"supported for post-implementation SDC file generation"); | ||
} | ||
|
||
// The timing constraints contain information on all the clocks in the circuit | ||
// (provided by the user-provided SDC file). | ||
const auto timing_constraints = g_vpr_ctx.timing().constraints; | ||
|
||
// Collect the non-virtual clocks. Virtual clocks are not routed and | ||
// do not get propageted. | ||
std::vector<tatum::DomainId> non_virtual_clocks; | ||
for (tatum::DomainId clock_domain_id : timing_constraints->clock_domains()) { | ||
if (!timing_constraints->is_virtual_clock(clock_domain_id)) { | ||
non_virtual_clocks.push_back(clock_domain_id); | ||
} | ||
} | ||
|
||
// If there are no non-virtual clocks, no extra commands needed, any other | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does this comment mean? virtual clocks are ideal? (clarify) |
||
// clocks will be set to be ideal. | ||
if (non_virtual_clocks.empty()) { | ||
return; | ||
} | ||
|
||
// Append a header to explain why these commands are added. | ||
sdc_os << "\n"; | ||
sdc_os << "#******************************************************************************#\n"; | ||
sdc_os << "# The following are clock domains in VPR which have delays on their edges.\n"; | ||
sdc_os << "#\n"; | ||
sdc_os << "# Clocks that have been routed or whose input signal have been placed to an\n"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can make the comment more general. "Any non-virtual clock has its delay determined and written out as part of a propagated clock command. If VPR was instructed not to route the clock, this delay will be an underestimate." |
||
sdc_os << "# input pad have delays on their signals. Thus, they should be treated as\n"; | ||
sdc_os << "# propageted (non-ideal) clocks.\n"; | ||
sdc_os << "#\n"; | ||
sdc_os << "# Note: Virtual clocks do not get routed and are treated as ideal.\n"; | ||
sdc_os << "#******************************************************************************#\n"; | ||
|
||
// Add the SDC commands to set the non-virtual clocks as propagated (non-ideal); | ||
// Note: It was decided that "ideal" clock modeling in VPR should still | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "ideal (don't route)" |
||
// set the clocks as propagated to allow for the input pad delays of | ||
// clocks to be included. The SDF delay annotations on clock signals | ||
// should make this safe to do. | ||
for (tatum::DomainId clock_domain_id : non_virtual_clocks) { | ||
sdc_os << "set_propagated_clock "; | ||
sdc_os << timing_constraints->clock_domain_name(clock_domain_id); | ||
sdc_os << "\n"; | ||
} | ||
} | ||
|
||
/** | ||
* @brief Generates a post-implementation SDC file with the given file name | ||
* based on the timing info and clock modeling set for VPR. | ||
*/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make methods static or move comments to the header file. |
||
void generate_post_implementation_sdc(const std::string& sdc_filename, | ||
const t_timing_inf& timing_info, | ||
e_clock_modeling clock_modeling) { | ||
if (!timing_info.timing_analysis_enabled) { | ||
VTR_LOG_WARN("Timing analysis is disabled. Post-implementation SDC file " | ||
"will not be generated.\n"); | ||
return; | ||
} | ||
|
||
// Begin writing the post-implementation SDC file. | ||
std::ofstream sdc_os(sdc_filename); | ||
|
||
// Print a header declaring that this file is auto-generated and what version | ||
// of VTR produced it. | ||
sdc_os << "#******************************************************************************#\n"; | ||
sdc_os << "# SDC automatically generated by VPR from a post-place-and-route implementation.\n"; | ||
sdc_os << "#\tVersion: " << vtr::VERSION << "\n"; | ||
sdc_os << "#******************************************************************************#\n"; | ||
|
||
// Add the original SDC that VPR used during its flow. | ||
add_original_sdc_to_post_implemented_sdc_file(sdc_os, timing_info); | ||
|
||
// Add propagated clocks to SDC file if needed. | ||
add_propagated_clocks_to_sdc_file(sdc_os, clock_modeling); | ||
} | ||
|
||
} // namespace | ||
|
||
// | ||
// Externally Accessible Functions | ||
// | ||
|
||
///@brief Main routine for this file. See netlist_writer.h for details. | ||
void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDelayCalculator> delay_calc, const LogicalModels& models, t_analysis_opts opts) { | ||
void netlist_writer(const std::string basename, | ||
std::shared_ptr<const AnalysisDelayCalculator> delay_calc, | ||
const LogicalModels& models, | ||
const t_timing_inf& timing_info, | ||
e_clock_modeling clock_modeling, | ||
t_analysis_opts opts) { | ||
std::string verilog_filename = basename + "_post_synthesis.v"; | ||
std::string blif_filename = basename + "_post_synthesis.blif"; | ||
std::string sdf_filename = basename + "_post_synthesis.sdf"; | ||
|
||
VTR_LOG("Writing Implementation Netlist: %s\n", verilog_filename.c_str()); | ||
VTR_LOG("Writing Implementation Netlist: %s\n", blif_filename.c_str()); | ||
VTR_LOG("Writing Implementation SDF : %s\n", sdf_filename.c_str()); | ||
|
||
std::ofstream verilog_os(verilog_filename); | ||
std::ofstream blif_os(blif_filename); | ||
std::ofstream sdf_os(sdf_filename); | ||
|
@@ -2669,6 +2793,16 @@ void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDe | |
NetlistWalker nl_walker(visitor); | ||
|
||
nl_walker.walk(); | ||
|
||
if (opts.gen_post_implementation_sdc) { | ||
std::string sdc_filename = basename + "_post_synthesis.sdc"; | ||
|
||
VTR_LOG("Writing Implementation SDC : %s\n", sdc_filename.c_str()); | ||
|
||
generate_post_implementation_sdc(sdc_filename, | ||
timing_info, | ||
clock_modeling); | ||
} | ||
} | ||
|
||
///@brief Main routine for this file. See netlist_writer.h for details. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,12 @@ class LogicalModels; | |
* All written filenames end in {basename}_post_synthesis.{fmt} where {basename} is the | ||
* basename argument and {fmt} is the file format (e.g. v, blif, sdf) | ||
*/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you have the energy for it, you could document the parameters. |
||
void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDelayCalculator> delay_calc, const LogicalModels& models, t_analysis_opts opts); | ||
void netlist_writer(const std::string basename, | ||
std::shared_ptr<const AnalysisDelayCalculator> delay_calc, | ||
const LogicalModels& models, | ||
const t_timing_inf& timing_info, | ||
e_clock_modeling clock_modeling, | ||
t_analysis_opts opts); | ||
|
||
/** | ||
* @brief Writes out the post implementation netlist in Verilog format. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2945,6 +2945,16 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio | |
.default_value("off") | ||
.show_in(argparse::ShowIn::HELP_ONLY); | ||
|
||
analysis_grp.add_argument<bool, ParseOnOff>(args.generate_post_implementation_sdc, "--gen_post_implementation_sdc") | ||
.help( | ||
"Generates an SDC file including a list of constraints that would " | ||
"replicate the timing constraints that the timing analysis within " | ||
"VPR followed during the flow. This file is expected to be used " | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Match the .rst text comment. |
||
"by external timing analyzers to get the same result as VPR's " | ||
"timing analysis.") | ||
.default_value("off") | ||
.show_in(argparse::ShowIn::HELP_ONLY); | ||
|
||
analysis_grp.add_argument(args.timing_report_npaths, "--timing_report_npaths") | ||
.help("Controls how many timing paths are reported.") | ||
.default_value("100") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd replace the last sentence: This can be helpful for flows that use external timing analysis tools that have additional capabilities or more detailed delay models than VPR uses.