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,167 @@ 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
+ * @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
+
2647
2789
} // namespace
2648
2790
2649
2791
//
2650
2792
// Externally Accessible Functions
2651
2793
//
2652
2794
2653
2795
// /@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) {
2655
2802
std::string verilog_filename = basename + " _post_synthesis.v" ;
2656
2803
std::string blif_filename = basename + " _post_synthesis.blif" ;
2657
2804
std::string sdf_filename = basename + " _post_synthesis.sdf" ;
2658
2805
2659
2806
VTR_LOG (" Writing Implementation Netlist: %s\n " , verilog_filename.c_str ());
2660
2807
VTR_LOG (" Writing Implementation Netlist: %s\n " , blif_filename.c_str ());
2661
2808
VTR_LOG (" Writing Implementation SDF : %s\n " , sdf_filename.c_str ());
2662
-
2663
2809
std::ofstream verilog_os (verilog_filename);
2664
2810
std::ofstream blif_os (blif_filename);
2665
2811
std::ofstream sdf_os (sdf_filename);
@@ -2669,6 +2815,16 @@ void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDe
2669
2815
NetlistWalker nl_walker (visitor);
2670
2816
2671
2817
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
+ }
2672
2828
}
2673
2829
2674
2830
// /@brief Main routine for this file. See netlist_writer.h for details.
0 commit comments