From 782cdfd8e1e6c4d4d0a2f6e7d0d1b950d2c9d0e4 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Tue, 28 Jun 2022 17:24:15 +0200 Subject: [PATCH] Added VPR commandline options that control unconnected port handling in the output Verilog netlist Signed-off-by: Maciej Kurc --- vpr/src/base/SetupVPR.cpp | 3 ++ vpr/src/base/ShowSetup.cpp | 25 +++++++++ vpr/src/base/netlist_writer.cpp | 73 ++++++++++++++++++-------- vpr/src/base/netlist_writer.h | 2 +- vpr/src/base/read_options.cpp | 91 +++++++++++++++++++++++++++++++++ vpr/src/base/read_options.h | 2 + vpr/src/base/vpr_api.cpp | 3 +- vpr/src/base/vpr_types.h | 9 ++++ 8 files changed, 184 insertions(+), 24 deletions(-) diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index 8e806d515..ca7ec3bf7 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -528,6 +528,9 @@ static void SetupAnalysisOpts(const t_options& Options, t_analysis_opts& analysi analysis_opts.timing_report_npaths = Options.timing_report_npaths; analysis_opts.timing_report_detail = Options.timing_report_detail; analysis_opts.timing_report_skew = Options.timing_report_skew; + + analysis_opts.post_synth_netlist_unconn_input_handling = Options.post_synth_netlist_unconn_input_handling; + analysis_opts.post_synth_netlist_unconn_output_handling = Options.post_synth_netlist_unconn_output_handling; } static void SetupPowerOpts(const t_options& Options, t_power_opts* power_opts, t_arch* Arch) { diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp index 05501cc9c..cdbf9afdf 100644 --- a/vpr/src/base/ShowSetup.cpp +++ b/vpr/src/base/ShowSetup.cpp @@ -384,6 +384,31 @@ static void ShowNetlistOpts(const t_netlist_opts& NetlistOpts) { static void ShowAnalysisOpts(const t_analysis_opts& AnalysisOpts) { VTR_LOG("AnalysisOpts.gen_post_synthesis_netlist: %s\n", (AnalysisOpts.gen_post_synthesis_netlist) ? "true" : "false"); + + const auto opts = { + std::make_tuple(&AnalysisOpts.post_synth_netlist_unconn_input_handling, "post_synth_netlist_unconn_input_handling"), + std::make_tuple(&AnalysisOpts.post_synth_netlist_unconn_output_handling, "post_synth_netlist_unconn_output_handling"), + }; + for (const auto& opt : opts) { + auto value = *std::get<0>(opt); + VTR_LOG("AnalysisOpts.%s: ", std::get<1>(opt)); + switch (value) { + case e_post_synth_netlist_unconn_handling::UNCONNECTED: + VTR_LOG("UNCONNECTED\n"); + break; + case e_post_synth_netlist_unconn_handling::NETS: + VTR_LOG("NETS\n"); + break; + case e_post_synth_netlist_unconn_handling::GND: + VTR_LOG("GND\n"); + break; + case e_post_synth_netlist_unconn_handling::VCC: + VTR_LOG("VCC\n"); + break; + default: + VPR_FATAL_ERROR(VPR_ERROR_UNKNOWN, "Unknown post_synth_netlist_unconn_handling\n"); + } + } VTR_LOG("\n"); } diff --git a/vpr/src/base/netlist_writer.cpp b/vpr/src/base/netlist_writer.cpp index 41fcf09dd..19d7d0388 100644 --- a/vpr/src/base/netlist_writer.cpp +++ b/vpr/src/base/netlist_writer.cpp @@ -111,7 +111,7 @@ std::string indent(size_t depth); double get_delay_ps(double delay_sec); void print_blif_port(std::ostream& os, size_t& unconn_count, const std::string& port_name, const std::vector& nets, int depth); -void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::string& port_name, const std::vector& nets, PortType type, int depth); +void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::string& port_name, const std::vector& nets, PortType type, int depth, struct t_analysis_opts& opts); std::string create_unconn_net(size_t& unconn_count); std::string escape_verilog_identifier(const std::string id); @@ -201,13 +201,15 @@ class LutInst : public Instance { LogicVec lut_mask, ///> port_conns, /// timing_arc_values) /// timing_arc_values, ///> port_conns_; std::vector timing_arcs_; + struct t_analysis_opts opts_; }; class LatchInst : public Instance { @@ -561,7 +564,8 @@ class BlackBoxInst : public Instance { std::vector timing_arcs, /// ports_tsu, /// ports_thld, /// ports_tcq) /// ports_tcq, ///first; auto& nets = iter->second; - print_verilog_port(os, unconn_count, port_name, nets, PortType::INPUT, depth + 1); + print_verilog_port(os, unconn_count, port_name, nets, PortType::INPUT, depth + 1, opts_); if (!(iter == --input_port_conns_.end() && output_port_conns_.empty())) { os << ","; } @@ -645,7 +650,7 @@ class BlackBoxInst : public Instance { for (auto iter = output_port_conns_.begin(); iter != output_port_conns_.end(); ++iter) { auto& port_name = iter->first; auto& nets = iter->second; - print_verilog_port(os, unconn_count, port_name, nets, PortType::OUTPUT, depth + 1); + print_verilog_port(os, unconn_count, port_name, nets, PortType::OUTPUT, depth + 1, opts_); if (!(iter == --output_port_conns_.end())) { os << ","; } @@ -756,6 +761,7 @@ class BlackBoxInst : public Instance { std::map ports_tsu_; std::map ports_thld_; std::map ports_tcq_; + struct t_analysis_opts opts_; }; /** @@ -794,11 +800,13 @@ class NetlistWriterVisitor : public NetlistVisitor { NetlistWriterVisitor(std::ostream& verilog_os, /// delay_calc) + std::shared_ptr delay_calc, + struct t_analysis_opts opts) : verilog_os_(verilog_os) , blif_os_(blif_os) , sdf_os_(sdf_os) - , delay_calc_(delay_calc) { + , delay_calc_(delay_calc) + , opts_(opts) { auto& atom_ctx = g_vpr_ctx.atom(); //Initialize the pin to tnode look-up @@ -1213,7 +1221,7 @@ class NetlistWriterVisitor : public NetlistVisitor { port_conns["out"].push_back(net); } - auto inst = std::make_shared(lut_size, lut_mask, inst_name, port_conns, timing_arcs); + auto inst = std::make_shared(lut_size, lut_mask, inst_name, port_conns, timing_arcs, opts_); return inst; } @@ -1413,7 +1421,7 @@ class NetlistWriterVisitor : public NetlistVisitor { } } - return std::make_shared(type, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq); + return std::make_shared(type, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq, opts_); } ///@brief Returns an Instance object representing a Multiplier @@ -1509,7 +1517,7 @@ class NetlistWriterVisitor : public NetlistVisitor { VTR_ASSERT(pb_graph_node->num_clock_ports == 0); //No clocks - return std::make_shared(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq); + return std::make_shared(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq, opts_); } ///@brief Returns an Instance object representing an Adder @@ -1609,7 +1617,7 @@ class NetlistWriterVisitor : public NetlistVisitor { } } - return std::make_shared(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq); + return std::make_shared(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq, opts_); } std::shared_ptr make_blackbox_instance(const t_pb* atom) { @@ -1747,7 +1755,7 @@ class NetlistWriterVisitor : public NetlistVisitor { attrs[attr.first] = attr.second; } - return std::make_shared(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq); + return std::make_shared(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq, opts_); } ///@brief Returns the top level pb_route associated with the given pb @@ -2067,6 +2075,7 @@ class NetlistWriterVisitor : public NetlistVisitor { std::map, tatum::NodeId> pin_id_to_tnode_lookup_; std::shared_ptr delay_calc_; + struct t_analysis_opts opts_; }; // @@ -2074,7 +2083,7 @@ class NetlistWriterVisitor : public NetlistVisitor { // ///@brief Main routing for this file. See netlist_writer.h for details. -void netlist_writer(const std::string basename, std::shared_ptr delay_calc) { +void netlist_writer(const std::string basename, std::shared_ptr delay_calc, struct 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"; @@ -2087,7 +2096,7 @@ void netlist_writer(const std::string basename, std::shared_ptr& nets, PortType type, int depth) { +void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::string& port_name, const std::vector& nets, PortType type, int depth, struct t_analysis_opts& opts) { //Port name os << indent(depth) << "." << port_name << "("; @@ -2169,10 +2178,30 @@ void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::strin if (nets[0].empty()) { //Disconnected if (type == PortType::INPUT || type == PortType::CLOCK) { - os << "1'b0"; + switch (opts.post_synth_netlist_unconn_input_handling) { + case e_post_synth_netlist_unconn_handling::GND: + os << "1'b0"; + break; + case e_post_synth_netlist_unconn_handling::VCC: + os << "1'b1"; + break; + case e_post_synth_netlist_unconn_handling::NETS: + os << create_unconn_net(unconn_count); + break; + case e_post_synth_netlist_unconn_handling::UNCONNECTED: + default: + os << "1'bX"; + } } else { VTR_ASSERT(type == PortType::OUTPUT); - os << create_unconn_net(unconn_count); + switch (opts.post_synth_netlist_unconn_output_handling) { + case e_post_synth_netlist_unconn_handling::NETS: + os << create_unconn_net(unconn_count); + break; + case e_post_synth_netlist_unconn_handling::UNCONNECTED: + default: + os << "1'bX"; + } } } else { //Connected @@ -2191,7 +2220,7 @@ void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::strin os << "1'b0"; } else { VTR_ASSERT(type == PortType::OUTPUT); - os << create_unconn_net(unconn_count); + os << ""; } } else { //Connected diff --git a/vpr/src/base/netlist_writer.h b/vpr/src/base/netlist_writer.h index 8f3b4e8a6..9c4306de7 100644 --- a/vpr/src/base/netlist_writer.h +++ b/vpr/src/base/netlist_writer.h @@ -15,6 +15,6 @@ * 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) */ -void netlist_writer(const std::string basename, std::shared_ptr delay_calc); +void netlist_writer(const std::string basename, std::shared_ptr delay_calc, struct t_analysis_opts opts); #endif diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 5f654445e..0e0af27f4 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -755,6 +755,75 @@ struct ParseReducer { return {"min", "max", "median", "arithmean", "geomean"}; } }; +struct ParsePostSynthNetlistUnconnInputHandling { + ConvertedValue from_str(std::string str) { + ConvertedValue conv_value; + if (str == "unconnected") + conv_value.set_value(e_post_synth_netlist_unconn_handling::UNCONNECTED); + else if (str == "nets") + conv_value.set_value(e_post_synth_netlist_unconn_handling::NETS); + else if (str == "gnd") + conv_value.set_value(e_post_synth_netlist_unconn_handling::GND); + else if (str == "vcc") + conv_value.set_value(e_post_synth_netlist_unconn_handling::VCC); + else { + std::stringstream msg; + msg << "Invalid conversion from '" << str << "' to e_post_synth_netlist_unconn_handling (expected one of: " << argparse::join(default_choices(), ", ") << ")"; + conv_value.set_error(msg.str()); + } + return conv_value; + } + + ConvertedValue to_str(e_post_synth_netlist_unconn_handling val) { + ConvertedValue conv_value; + if (val == e_post_synth_netlist_unconn_handling::NETS) + conv_value.set_value("nets"); + else if (val == e_post_synth_netlist_unconn_handling::GND) + conv_value.set_value("gnd"); + else if (val == e_post_synth_netlist_unconn_handling::VCC) + conv_value.set_value("vcc"); + else { + VTR_ASSERT(val == e_post_synth_netlist_unconn_handling::UNCONNECTED); + conv_value.set_value("unconnected"); + } + return conv_value; + } + + std::vector default_choices() { + return {"unconnected", "nets", "gnd", "vcc"}; + } +}; + +struct ParsePostSynthNetlistUnconnOutputHandling { + ConvertedValue from_str(std::string str) { + ConvertedValue conv_value; + if (str == "unconnected") + conv_value.set_value(e_post_synth_netlist_unconn_handling::UNCONNECTED); + else if (str == "nets") + conv_value.set_value(e_post_synth_netlist_unconn_handling::NETS); + else { + std::stringstream msg; + msg << "Invalid conversion from '" << str << "' to e_post_synth_netlist_unconn_handling (expected one of: " << argparse::join(default_choices(), ", ") << ")"; + conv_value.set_error(msg.str()); + } + return conv_value; + } + + ConvertedValue to_str(e_post_synth_netlist_unconn_handling val) { + ConvertedValue conv_value; + if (val == e_post_synth_netlist_unconn_handling::NETS) + conv_value.set_value("nets"); + else { + VTR_ASSERT(val == e_post_synth_netlist_unconn_handling::UNCONNECTED); + conv_value.set_value("unconnected"); + } + return conv_value; + } + + std::vector default_choices() { + return {"unconnected", "nets"}; + } +}; argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& args) { std::string description = @@ -1675,6 +1744,28 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg .default_value("off") .show_in(argparse::ShowIn::HELP_ONLY); + analysis_grp.add_argument(args.post_synth_netlist_unconn_input_handling, "--post_synth_netlist_unconn_inputs") + .help( + "Controls how unconnected input cell ports are handled in the post-synthesis netlist\n" + " * unconnected: leave unconnected\n" + " * nets: connect each unconnected input pin to its own separate\n" + " undriven net named: __vpr__unconn, where is index\n" + " assigned to this occurrence of unconnected port in design\n" + " * gnd: tie all to ground (1'b0)\n" + " * vcc: tie all to VCC (1'b1)\n") + .default_value("unconnected") + .show_in(argparse::ShowIn::HELP_ONLY); + + analysis_grp.add_argument(args.post_synth_netlist_unconn_output_handling, "--post_synth_netlist_unconn_outputs") + .help( + "Controls how unconnected output cell ports are handled in the post-synthesis netlist\n" + " * unconnected: leave unconnected\n" + " * nets: connect each unconnected input pin to its own separate\n" + " undriven net named: __vpr__unconn, where is index\n" + " assigned to this occurrence of unconnected port in design\n") + .default_value("unconnected") + .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 97d320abb..a4ee70993 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -159,6 +159,8 @@ struct t_options { argparse::ArgValue timing_report_npaths; argparse::ArgValue timing_report_detail; argparse::ArgValue timing_report_skew; + argparse::ArgValue post_synth_netlist_unconn_input_handling; + argparse::ArgValue post_synth_netlist_unconn_output_handling; }; argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& args); diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 846c0779a..266c8ba9b 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -1195,7 +1195,8 @@ void vpr_analysis(t_vpr_setup& vpr_setup, const t_arch& Arch, const RouteStatus& //Write the post-syntesis netlist if (vpr_setup.AnalysisOpts.gen_post_synthesis_netlist) { - netlist_writer(atom_ctx.nlist.netlist_name().c_str(), analysis_delay_calc); + netlist_writer(atom_ctx.nlist.netlist_name().c_str(), analysis_delay_calc, + vpr_setup.AnalysisOpts); } //Do power analysis diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index f6696dd9f..13a7aa2f3 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -900,6 +900,13 @@ enum class e_timing_report_detail { DETAILED_ROUTING, //Show inter-block routing resources used }; +enum class e_post_synth_netlist_unconn_handling { + UNCONNECTED, // Leave unrouted ports unconnected + NETS, // Leave unrouted ports unconnected but add new named nets to each of them + GND, // Tie unrouted ports to ground (only for input ports) + VCC // Tie unrouted ports to VCC (only for input ports) +}; + enum class e_incr_reroute_delay_ripup { ON, OFF, @@ -959,6 +966,8 @@ struct t_analysis_opts { e_stage_action doAnalysis; bool gen_post_synthesis_netlist; + e_post_synth_netlist_unconn_handling post_synth_netlist_unconn_input_handling; + e_post_synth_netlist_unconn_handling post_synth_netlist_unconn_output_handling; int timing_report_npaths; e_timing_report_detail timing_report_detail;