diff --git a/vpr/src/analysis/timing_reports.cpp b/vpr/src/analysis/timing_reports.cpp index 281a40b67a..0062aff5d8 100644 --- a/vpr/src/analysis/timing_reports.cpp +++ b/vpr/src/analysis/timing_reports.cpp @@ -1,7 +1,13 @@ #include "timing_reports.h" +#include +#include + +#include "timing_reports.h" + #include "tatum/TimingReporter.hpp" +#include "vtr_version.h" #include "vpr_types.h" #include "globals.h" @@ -61,3 +67,69 @@ void generate_hold_timing_stats(const std::string& prefix, timing_reporter.report_unconstrained_hold(prefix + "report_unconstrained_timing.hold.rpt", *timing_info.hold_analyzer()); } + +void generate_net_timing_report(const std::string& prefix, + const SetupHoldTimingInfo& timing_info, + const AnalysisDelayCalculator& delay_calc) { + /* Create a report file for net timing information */ + std::ofstream os(prefix + "report_net_timing.rpt"); + const auto& atom_netlist = g_vpr_ctx.atom().netlist(); + const auto& atom_lookup = g_vpr_ctx.atom().lookup(); + + const auto& timing_ctx = g_vpr_ctx.timing(); + const auto& timing_graph = timing_ctx.graph; + + os << "# This file is generated by VTR" << std::endl; + os << "# Version: " << vtr::VERSION << std::endl; + os << "# Revision: " << vtr::VCS_REVISION << std::endl; + os << "# For each net, the timing information is reported in the following format:" << std::endl; + os << "# netname : Fanout : source_instance : " + << " : " + << " : ..." + << std::endl; + + os << std::endl; + + for (const auto& net : atom_netlist.nets()) { + /* Skip constant nets */ + if (atom_netlist.net_is_constant(net)) { + continue; + } + + const auto& net_name = atom_netlist.net_name(net); + + /* Get source pin and its timing information */ + const auto& source_pin = *atom_netlist.net_pins(net).begin(); + auto source_pin_slack = timing_info.setup_pin_slack(source_pin); + /* Timing graph node id corresponding to the net's source pin */ + auto tg_source_node = atom_lookup.atom_pin_tnode(source_pin); + VTR_ASSERT(tg_source_node.is_valid()); + + const size_t fanout = atom_netlist.net_sinks(net).size(); + os << net_name << " : " << fanout << " : " << atom_netlist.pin_name(source_pin).c_str() << " " << source_pin_slack << " : "; + + /* Iterate over all fanout pins and print their timing information */ + for (size_t net_pin_index = 1; net_pin_index <= fanout; ++net_pin_index) { + const auto& pin = *(atom_netlist.net_pins(net).begin() + net_pin_index); + + /* Get timing graph node id corresponding to the fanout pin */ + const auto& tg_sink_node = atom_lookup.atom_pin_tnode(pin); + VTR_ASSERT(tg_sink_node.is_valid()); + + /* Get timing graph edge id between atom pins */ + const auto& tg_edge_id = timing_graph->find_edge(tg_source_node, tg_sink_node); + VTR_ASSERT(tg_edge_id.is_valid()); + + /* Get timing information for the fanout pin */ + const auto& pin_setup_slack = timing_info.setup_pin_slack(pin); + const auto& pin_delay = delay_calc.max_edge_delay(*timing_graph, tg_edge_id); + + const auto& pin_name = atom_netlist.pin_name(pin); + os << pin_name << " " << std::scientific << pin_setup_slack << " " << pin_delay; + if (net_pin_index < fanout) { + os << " : "; + } + } + os << "," << std::endl; + } +} diff --git a/vpr/src/analysis/timing_reports.h b/vpr/src/analysis/timing_reports.h index 72e1013dec..e127335849 100644 --- a/vpr/src/analysis/timing_reports.h +++ b/vpr/src/analysis/timing_reports.h @@ -21,4 +21,19 @@ void generate_hold_timing_stats(const std::string& prefix, bool is_flat, const BlkLocRegistry& blk_loc_registry); +/** + * @brief Generates timing information for each net in atom netlist. For each net, the timing information + * is reported in the following format: + * netname : Fanout : source_instance : + * : + * : ... + * + * @param prefix The prefix for the report file to be added to filename: report_net_timing.rpt + * @param timing_info Updated timing information + * @param delay_calc Delay calculator + */ +void generate_net_timing_report(const std::string& prefix, + const SetupHoldTimingInfo& timing_info, + const AnalysisDelayCalculator& delay_calc); + #endif diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index 07a826598b..26c4adb654 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -716,6 +716,7 @@ static void SetupAnalysisOpts(const t_options& Options, t_analysis_opts& analysi analysis_opts.timing_update_type = Options.timing_update_type; analysis_opts.write_timing_summary = Options.write_timing_summary; + analysis_opts.generate_net_timing_report = Options.generate_net_timing_report; } static void SetupPowerOpts(const t_options& Options, t_power_opts* power_opts, t_arch* Arch) { diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 82de8cc0ef..f33c052bd9 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -3078,6 +3078,11 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .help("Writes implemented design final timing summary to the specified JSON, XML or TXT file.") .show_in(argparse::ShowIn::HELP_ONLY); + analysis_grp.add_argument(args.generate_net_timing_report, "--generate_net_timing_report") + .help("Generates a net timing report for each net in the design.") + .default_value("off") + .show_in(argparse::ShowIn::HELP_ONLY); + auto& power_grp = parser.add_argument_group("power analysis options"); power_grp.add_argument(args.do_power, "--power") diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index 9056cdbf9f..9da2c12c4f 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -271,6 +271,7 @@ struct t_options { argparse::ArgValue post_synth_netlist_unconn_output_handling; argparse::ArgValue post_synth_netlist_module_parameters; argparse::ArgValue write_timing_summary; + argparse::ArgValue generate_net_timing_report; }; argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_options& args); diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 97f8f16463..8828139324 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -1475,6 +1475,10 @@ void vpr_analysis(const Netlist<>& net_list, merged_netlist_writer(atom_ctx.netlist().netlist_name(), analysis_delay_calc, Arch.models, vpr_setup.AnalysisOpts); } + if (vpr_setup.AnalysisOpts.generate_net_timing_report) { + generate_net_timing_report(/*prefix=*/"", *timing_info, *analysis_delay_calc); + } + //Do power analysis // TODO: Still assumes that cluster net list is used if (vpr_setup.PowerOpts.do_power) { diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index d19496411f..16bb20007d 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1351,6 +1351,7 @@ struct t_analysis_opts { bool timing_report_skew; std::string echo_dot_timing_graph_node; std::string write_timing_summary; + bool generate_net_timing_report; e_timing_update_type timing_update_type; };