From 0f2a8fe0be57128928693578d31185531329e5cf Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Tue, 18 May 2021 18:08:24 +0200 Subject: [PATCH 1/4] vpr: base: options: Add handling of unconnected ports in post-synthesis netlist Co-authored-by: Alessandro Comodi Co-authored-by: Pawel Czarnecki Signed-off-by: Maciej Kurc --- vpr/src/base/SetupVPR.cpp | 3 ++ vpr/src/base/ShowSetup.cpp | 25 ++++++++++ vpr/src/base/read_options.cpp | 92 +++++++++++++++++++++++++++++++++++ vpr/src/base/read_options.h | 2 + vpr/src/base/vpr_types.h | 9 ++++ 5 files changed, 131 insertions(+) diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index 794abdbe6d2..13fe483f477 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -623,6 +623,9 @@ static void SetupAnalysisOpts(const t_options& Options, t_analysis_opts& analysi analysis_opts.timing_report_skew = Options.timing_report_skew; analysis_opts.echo_dot_timing_graph_node = Options.echo_dot_timing_graph_node; + 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; + analysis_opts.timing_update_type = Options.timing_update_type; } diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp index dbffe184086..c50afc01a68 100644 --- a/vpr/src/base/ShowSetup.cpp +++ b/vpr/src/base/ShowSetup.cpp @@ -604,6 +604,31 @@ static void ShowAnalysisOpts(const t_analysis_opts& AnalysisOpts) { default: VPR_FATAL_ERROR(VPR_ERROR_UNKNOWN, "Unknown timing_report_detail\n"); } + + 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/read_options.cpp b/vpr/src/base/read_options.cpp index 45ed25c4faa..09f4647ff41 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -1111,6 +1111,76 @@ struct ParseTimingUpdateType { } }; +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 = "Implements the specified circuit onto the target FPGA architecture" @@ -2472,6 +2542,28 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg .default_value("-1") .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 7e8fed79752..922699d2c93 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -208,6 +208,8 @@ struct t_options { argparse::ArgValue timing_report_detail; argparse::ArgValue timing_report_skew; argparse::ArgValue echo_dot_timing_graph_node; + 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_types.h b/vpr/src/base/vpr_types.h index 944cc9da9c2..26aa1212bd9 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1191,6 +1191,13 @@ enum class e_timing_report_detail { DEBUG, //Show additional internal debugging information }; +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) +}; + struct t_timing_analysis_profile_info { double timing_analysis_wallclock_time() const { return sta_wallclock_time + slack_wallclock_time; @@ -1286,6 +1293,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; From 511c2e969736358d53da3b6808572ab9285ec5f6 Mon Sep 17 00:00:00 2001 From: Tomasz Jurtsch Date: Fri, 4 Jun 2021 13:04:48 +0200 Subject: [PATCH 2/4] vpr: base: netlist writer: handle unconnected ports in verilog writer Co-authored-by: Alessandro Comodi Co-authored-by: Pawel Czarnecki --- vpr/src/base/netlist_writer.cpp | 83 ++++++++++++++++++++++----------- vpr/src/base/netlist_writer.h | 2 +- vpr/src/base/vpr_api.cpp | 3 +- 3 files changed, 60 insertions(+), 28 deletions(-) diff --git a/vpr/src/base/netlist_writer.cpp b/vpr/src/base/netlist_writer.cpp index f51bad8c8ac..af700fe499e 100644 --- a/vpr/src/base/netlist_writer.cpp +++ b/vpr/src/base/netlist_writer.cpp @@ -18,6 +18,7 @@ #include "vtr_version.h" #include "vpr_error.h" +#include "vpr_types.h" #include "netlist_walker.h" #include "netlist_writer.h" @@ -110,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, 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); @@ -187,7 +188,7 @@ class Instance { virtual void print_blif(std::ostream& os, size_t& unconn_count, int depth = 0) = 0; ///@brief Print the current instanse in Verilog, see print_blif() for argument descriptions - virtual void print_verilog(std::ostream& os, int depth = 0) = 0; + virtual void print_verilog(std::ostream& os, size_t& unconn_count, int depth = 0) = 0; ///@brief Print the current instanse in SDF, see print_blif() for argument descriptions virtual void print_sdf(std::ostream& os, int depth = 0) = 0; @@ -200,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 { @@ -462,7 +466,7 @@ class LatchInst : public Instance { os << "\n"; } - void print_verilog(std::ostream& os, int depth = 0) override { + void print_verilog(std::ostream& os, size_t& /*unconn_count*/, int depth = 0) override { //Currently assume a standard DFF VTR_ASSERT(type_ == Type::RISING_EDGE); @@ -560,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, 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 << ","; } @@ -644,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, 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 << ","; } @@ -755,6 +761,7 @@ class BlackBoxInst : public Instance { std::map ports_tsu_; std::map ports_thld_; std::map ports_tcq_; + struct t_analysis_opts opts_; }; /** @@ -793,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 @@ -931,10 +940,11 @@ class NetlistWriterVisitor : public NetlistVisitor { } //All the cell instances + size_t unconn_count = 0; verilog_os_ << "\n"; verilog_os_ << indent(depth + 1) << "//Cell instances\n"; for (auto& inst : cell_instances_) { - inst->print_verilog(verilog_os_, depth + 1); + inst->print_verilog(verilog_os_, unconn_count, depth + 1); } verilog_os_ << "\n"; @@ -1213,7 +1223,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 +1423,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 +1519,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 +1619,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 +1757,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 +2077,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 +2085,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 +2098,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 +2180,30 @@ void print_verilog_port(std::ostream& os, const std::string& port_name, const st 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 << "DummyOut"; + 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 diff --git a/vpr/src/base/netlist_writer.h b/vpr/src/base/netlist_writer.h index 8f3b4e8a6ff..9c4306de756 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/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 3b3b8dbe15e..529d0cc60f0 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -1277,7 +1277,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 From a812abf951da505c908086571feb7d3f4092a3a8 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 19 Jan 2022 14:02:48 +0100 Subject: [PATCH 3/4] vpr: base: netlist writer: don't write DummyOut wires in verilog netlist Signed-off-by: Pawel Czarnecki --- vpr/src/base/netlist_writer.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vpr/src/base/netlist_writer.cpp b/vpr/src/base/netlist_writer.cpp index af700fe499e..19d7d0388cb 100644 --- a/vpr/src/base/netlist_writer.cpp +++ b/vpr/src/base/netlist_writer.cpp @@ -912,8 +912,6 @@ class NetlistWriterVisitor : public NetlistVisitor { } } - verilog_os_ << indent(depth + 1) << "wire DummyOut;\n"; - //connections between primary I/Os and their internal wires verilog_os_ << "\n"; verilog_os_ << indent(depth + 1) << "//IO assignments\n"; @@ -2222,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 << "DummyOut"; + os << ""; } } else { //Connected From c425978191b922e9d8ba1c855f66c0decb8ae2f0 Mon Sep 17 00:00:00 2001 From: Pawel Czarnecki Date: Wed, 19 Jan 2022 14:29:46 +0100 Subject: [PATCH 4/4] doc: vpr: cmd: add info on unconnected ports handling in verilog netlist Signed-off-by: Pawel Czarnecki --- doc/src/vpr/command_line_usage.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/src/vpr/command_line_usage.rst b/doc/src/vpr/command_line_usage.rst index f3f9f5caa0f..04b0e543538 100644 --- a/doc/src/vpr/command_line_usage.rst +++ b/doc/src/vpr/command_line_usage.rst @@ -1237,6 +1237,26 @@ Analysis Options **Default:** ``off`` +.. option:: --post_synth_netlist_unconn_inputs { unconnected | nets | gnd | vcc } + + Controls how unconnected input cell ports are handled in the post-synthesis netlist + + * unconnected: leave unconnected + * nets: connect each unconnected input pin to its own separate undriven net named: ``__vpr__unconn``, where ```` is index assigned to this occurrence of unconnected port in design + * gnd: tie all to ground (``1'b0``) + * vcc: tie all to VCC (``1'b1``) + + **Default:** ``unconnected`` + +.. option:: --post_synth_netlist_unconn_outputs { unconnected | nets } + + Controls how unconnected output cell ports are handled in the post-synthesis netlist + + * unconnected: leave unconnected + * nets: connect each unconnected output pin to its own separate undriven net named: ``__vpr__unconn``, where ```` is index assigned to this occurrence of unconnected port in design + + **Default:** ``unconnected`` + .. option:: --timing_report_npaths Controls how many timing paths are reported.