72
72
#include < vector>
73
73
#include " atom_netlist.h"
74
74
#include " atom_netlist_utils.h"
75
+ #include " clock_modeling.h"
75
76
#include " globals.h"
76
77
#include " logic_vec.h"
77
78
#include " netlist_walker.h"
@@ -2644,22 +2645,144 @@ std::string join_identifier(std::string lhs, std::string rhs) {
2644
2645
return lhs + ' _' + rhs;
2645
2646
}
2646
2647
2648
+ /* *
2649
+ * @brief Add the original SDC constraints that VPR used during its flow to the
2650
+ * given SDC file.
2651
+ */
2652
+ void add_original_sdc_to_post_implemented_sdc_file (std::ofstream& sdc_os,
2653
+ const t_timing_inf& timing_info) {
2654
+ // Open the original SDC file provided to VPR.
2655
+ std::ifstream original_sdc_file;
2656
+ original_sdc_file.open (timing_info.SDCFile );
2657
+ if (!original_sdc_file.is_open ()) {
2658
+ // TODO: VPR automatically creates SDC constraints by default if no SDC
2659
+ // file is provided. These can be replicated here if needed.
2660
+ VPR_FATAL_ERROR (VPR_ERROR_IMPL_NETLIST_WRITER,
2661
+ " No SDC files provided to VPR, currently cannot generate "
2662
+ " post-implementation SDC file without it" );
2663
+ }
2664
+
2665
+ // Write a header to declare where these commands came from.
2666
+ sdc_os << " \n " ;
2667
+ sdc_os << " #******************************************************************************#\n " ;
2668
+ sdc_os << " # The following SDC commands were provided to VPR from the given SDC file:\n " ;
2669
+ sdc_os << " # \t " << timing_info.SDCFile << " \n " ;
2670
+ sdc_os << " #******************************************************************************#\n " ;
2671
+
2672
+ // Append the original SDC file to the post-implementation SDC file.
2673
+ sdc_os << original_sdc_file.rdbuf ();
2674
+ }
2675
+
2676
+ /* *
2677
+ * @brief Add propagated clock commands to the given SDC file based on the set
2678
+ * clock modeling.
2679
+ *
2680
+ * This is necessary since VPR decides if clocks are routed or not, which has
2681
+ * affects on how timing analysis is performed on the clocks.
2682
+ */
2683
+ void add_propagated_clocks_to_sdc_file (std::ofstream& sdc_os,
2684
+ e_clock_modeling clock_modeling) {
2685
+
2686
+ // If all clocks are treated as ideal clocks by VPR, do not add any extra SDC
2687
+ // commands. By default, clocks are treated as ideal by many tools.
2688
+ if (clock_modeling == e_clock_modeling::IDEAL_CLOCK) {
2689
+ return ;
2690
+ }
2691
+
2692
+ if (clock_modeling != e_clock_modeling::ROUTED_CLOCK) {
2693
+ VPR_FATAL_ERROR (VPR_ERROR_IMPL_NETLIST_WRITER,
2694
+ " Only ideal and routed clock modeling are currentlt "
2695
+ " supported for post-implementation SDC file generation" );
2696
+ }
2697
+
2698
+ // The timing constraints contain information on all the clocks in the circuit
2699
+ // (provided by the user-provided SDC file).
2700
+ const auto timing_constraints = g_vpr_ctx.timing ().constraints ;
2701
+
2702
+ // Collect the non-virtual clocks. Virtual clocks are not routed and
2703
+ // do not get propageted.
2704
+ std::vector<tatum::DomainId> non_virtual_clocks;
2705
+ for (tatum::DomainId clock_domain_id : timing_constraints->clock_domains ()) {
2706
+ if (!timing_constraints->is_virtual_clock (clock_domain_id)) {
2707
+ non_virtual_clocks.push_back (clock_domain_id);
2708
+ }
2709
+ }
2710
+
2711
+ // If there are no non-virtual clocks, no extra commands needed, any other
2712
+ // clocks will be set to be ideal.
2713
+ if (non_virtual_clocks.empty ()) {
2714
+ return ;
2715
+ }
2716
+
2717
+ // Append a header to explain why these commands are added.
2718
+ sdc_os << " \n " ;
2719
+ sdc_os << " #******************************************************************************#\n " ;
2720
+ sdc_os << " # The following are clock domains in VPR which have been routed.\n " ;
2721
+ sdc_os << " #\n " ;
2722
+ sdc_os << " # Since these clocks have been routed, they have delays on their signals.\n " ;
2723
+ sdc_os << " # Thus, they should be treated as propageted (non-ideal) clocks.\n " ;
2724
+ sdc_os << " #\n " ;
2725
+ sdc_os << " # Note: Virtual clocks do not get routed and are treated as ideal.\n " ;
2726
+ sdc_os << " #******************************************************************************#\n " ;
2727
+
2728
+ // Add the SDC commands to set the non-virtual clocks as propagated (non-ideal);
2729
+ for (tatum::DomainId clock_domain_id : non_virtual_clocks) {
2730
+ sdc_os << " set_propagated_clock " ;
2731
+ sdc_os << timing_constraints->clock_domain_name (clock_domain_id);
2732
+ sdc_os << " \n " ;
2733
+ }
2734
+ }
2735
+
2736
+ /* *
2737
+ * @brief Generates a post-implementation SDC file with the given file name
2738
+ * based on the timing info and clock modeling set for VPR.
2739
+ */
2740
+ void generate_post_implementation_sdc (const std::string& sdc_filename,
2741
+ const t_timing_inf& timing_info,
2742
+ e_clock_modeling clock_modeling) {
2743
+ if (!timing_info.timing_analysis_enabled ) {
2744
+ VTR_LOG_WARN (" Timing analysis is disabled. Post-implementation SDC file "
2745
+ " will not be generated.\n " );
2746
+ return ;
2747
+ }
2748
+
2749
+ // Begin writing the post-implementation SDC file.
2750
+ std::ofstream sdc_os (sdc_filename);
2751
+
2752
+ // Print a header declaring that this file is auto-generated and what version
2753
+ // of VTR produced it.
2754
+ sdc_os << " #******************************************************************************#\n " ;
2755
+ sdc_os << " # SDC automatically generated by VPR from a post-place-and-route implementation.\n " ;
2756
+ sdc_os << " #\t Version: " << vtr::VERSION << " \n " ;
2757
+ sdc_os << " #******************************************************************************#\n " ;
2758
+
2759
+ // Add the original SDC that VPR used during its flow.
2760
+ add_original_sdc_to_post_implemented_sdc_file (sdc_os, timing_info);
2761
+
2762
+ // Add propagated clocks to SDC file if needed.
2763
+ add_propagated_clocks_to_sdc_file (sdc_os, clock_modeling);
2764
+ }
2765
+
2647
2766
} // namespace
2648
2767
2649
2768
//
2650
2769
// Externally Accessible Functions
2651
2770
//
2652
2771
2653
2772
// /@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) {
2773
+ void netlist_writer (const std::string basename,
2774
+ std::shared_ptr<const AnalysisDelayCalculator> delay_calc,
2775
+ const LogicalModels& models,
2776
+ const t_timing_inf& timing_info,
2777
+ e_clock_modeling clock_modeling,
2778
+ t_analysis_opts opts) {
2655
2779
std::string verilog_filename = basename + " _post_synthesis.v" ;
2656
2780
std::string blif_filename = basename + " _post_synthesis.blif" ;
2657
2781
std::string sdf_filename = basename + " _post_synthesis.sdf" ;
2658
2782
2659
2783
VTR_LOG (" Writing Implementation Netlist: %s\n " , verilog_filename.c_str ());
2660
2784
VTR_LOG (" Writing Implementation Netlist: %s\n " , blif_filename.c_str ());
2661
2785
VTR_LOG (" Writing Implementation SDF : %s\n " , sdf_filename.c_str ());
2662
-
2663
2786
std::ofstream verilog_os (verilog_filename);
2664
2787
std::ofstream blif_os (blif_filename);
2665
2788
std::ofstream sdf_os (sdf_filename);
@@ -2669,6 +2792,16 @@ void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDe
2669
2792
NetlistWalker nl_walker (visitor);
2670
2793
2671
2794
nl_walker.walk ();
2795
+
2796
+ if (opts.gen_post_implementation_sdc ) {
2797
+ std::string sdc_filename = basename + " _post_synthesis.sdc" ;
2798
+
2799
+ VTR_LOG (" Writing Implementation SDC : %s\n " , sdc_filename.c_str ());
2800
+
2801
+ generate_post_implementation_sdc (sdc_filename,
2802
+ timing_info,
2803
+ clock_modeling);
2804
+ }
2672
2805
}
2673
2806
2674
2807
// /@brief Main routine for this file. See netlist_writer.h for details.
0 commit comments