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 << " #\t Version: " << 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.
0 commit comments