Added VPR commandline options that control unconnected port handling in the output Verilog netlist

Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
This commit is contained in:
Maciej Kurc 2022-06-28 17:24:15 +02:00 committed by Paweł Czarnecki
parent 3f0e53c960
commit 782cdfd8e1
8 changed files with 184 additions and 24 deletions

View File

@ -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) {

View File

@ -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");
}

View File

@ -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<std::string>& nets, int depth);
void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::string& port_name, const std::vector<std::string>& nets, PortType type, int depth);
void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::string& port_name, const std::vector<std::string>& 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, ///<The LUT mask representing the logic function
std::string inst_name, ///<The name of this instance
std::map<std::string, std::vector<std::string>> port_conns, ///<The port connections of this instance. Key: port name, Value: connected nets
std::vector<Arc> timing_arc_values) ///<The timing arcs of this instance
std::vector<Arc> timing_arc_values, ///<The timing arcs of this instance
struct t_analysis_opts opts)
: type_("LUT_K")
, lut_size_(lut_size)
, lut_mask_(lut_mask)
, inst_name_(inst_name)
, port_conns_(port_conns)
, timing_arcs_(timing_arc_values) {
, timing_arcs_(timing_arc_values)
, opts_(opts) {
}
//Accessors
@ -232,10 +234,10 @@ class LutInst : public Instance {
VTR_ASSERT(port_conns_.count("out"));
VTR_ASSERT(port_conns_.size() == 2);
print_verilog_port(os, unconn_count, "in", port_conns_["in"], PortType::INPUT, depth + 1);
print_verilog_port(os, unconn_count, "in", port_conns_["in"], PortType::INPUT, depth + 1, opts_);
os << ","
<< "\n";
print_verilog_port(os, unconn_count, "out", port_conns_["out"], PortType::OUTPUT, depth + 1);
print_verilog_port(os, unconn_count, "out", port_conns_["out"], PortType::OUTPUT, depth + 1, opts_);
os << "\n";
os << indent(depth) << ");\n\n";
@ -377,6 +379,7 @@ class LutInst : public Instance {
std::string inst_name_;
std::map<std::string, std::vector<std::string>> port_conns_;
std::vector<Arc> timing_arcs_;
struct t_analysis_opts opts_;
};
class LatchInst : public Instance {
@ -561,7 +564,8 @@ class BlackBoxInst : public Instance {
std::vector<Arc> timing_arcs, ///<Combinational timing arcs
std::map<std::string, sequential_port_delay_pair> ports_tsu, ///<Port setup checks
std::map<std::string, sequential_port_delay_pair> ports_thld, ///<Port hold checks
std::map<std::string, sequential_port_delay_pair> ports_tcq) ///<Port clock-to-q delays
std::map<std::string, sequential_port_delay_pair> ports_tcq, ///<Port clock-to-q delays
struct t_analysis_opts opts)
: type_name_(type_name)
, inst_name_(inst_name)
, params_(params)
@ -571,7 +575,8 @@ class BlackBoxInst : public Instance {
, timing_arcs_(timing_arcs)
, ports_tsu_(ports_tsu)
, ports_thld_(ports_thld)
, ports_tcq_(ports_tcq) {}
, ports_tcq_(ports_tcq)
, opts_(opts) {}
void print_blif(std::ostream& os, size_t& unconn_count, int depth = 0) override {
os << indent(depth) << ".subckt " << type_name_ << " \\"
@ -634,7 +639,7 @@ class BlackBoxInst : public Instance {
for (auto iter = input_port_conns_.begin(); iter != input_port_conns_.end(); ++iter) {
auto& port_name = iter->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<std::string, sequential_port_delay_pair> ports_tsu_;
std::map<std::string, sequential_port_delay_pair> ports_thld_;
std::map<std::string, sequential_port_delay_pair> ports_tcq_;
struct t_analysis_opts opts_;
};
/**
@ -794,11 +800,13 @@ class NetlistWriterVisitor : public NetlistVisitor {
NetlistWriterVisitor(std::ostream& verilog_os, ///<Output stream for verilog netlist
std::ostream& blif_os, ///<Output stream for blif netlist
std::ostream& sdf_os, ///<Output stream for SDF
std::shared_ptr<const AnalysisDelayCalculator> delay_calc)
std::shared_ptr<const AnalysisDelayCalculator> 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<LutInst>(lut_size, lut_mask, inst_name, port_conns, timing_arcs);
auto inst = std::make_shared<LutInst>(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<BlackBoxInst>(type, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq);
return std::make_shared<BlackBoxInst>(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<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq);
return std::make_shared<BlackBoxInst>(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<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq);
return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq, opts_);
}
std::shared_ptr<Instance> make_blackbox_instance(const t_pb* atom) {
@ -1747,7 +1755,7 @@ class NetlistWriterVisitor : public NetlistVisitor {
attrs[attr.first] = attr.second;
}
return std::make_shared<BlackBoxInst>(type_name, inst_name, params, attrs, input_port_conns, output_port_conns, timing_arcs, ports_tsu, ports_thld, ports_tcq);
return std::make_shared<BlackBoxInst>(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<std::pair<ClusterBlockId, int>, tatum::NodeId> pin_id_to_tnode_lookup_;
std::shared_ptr<const AnalysisDelayCalculator> 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<const AnalysisDelayCalculator> delay_calc) {
void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDelayCalculator> 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<const AnalysisDe
std::ofstream blif_os(blif_filename);
std::ofstream sdf_os(sdf_filename);
NetlistWriterVisitor visitor(verilog_os, blif_os, sdf_os, delay_calc);
NetlistWriterVisitor visitor(verilog_os, blif_os, sdf_os, delay_calc, opts);
NetlistWalker nl_walker(visitor);
@ -2159,7 +2168,7 @@ void print_blif_port(std::ostream& os, size_t& unconn_count, const std::string&
*
* Handles special cases like multi-bit and disconnected ports
*/
void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::string& port_name, const std::vector<std::string>& nets, PortType type, int depth) {
void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::string& port_name, const std::vector<std::string>& 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

View File

@ -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<const AnalysisDelayCalculator> delay_calc);
void netlist_writer(const std::string basename, std::shared_ptr<const AnalysisDelayCalculator> delay_calc, struct t_analysis_opts opts);
#endif

View File

@ -755,6 +755,75 @@ struct ParseReducer {
return {"min", "max", "median", "arithmean", "geomean"};
}
};
struct ParsePostSynthNetlistUnconnInputHandling {
ConvertedValue<e_post_synth_netlist_unconn_handling> from_str(std::string str) {
ConvertedValue<e_post_synth_netlist_unconn_handling> 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<std::string> to_str(e_post_synth_netlist_unconn_handling val) {
ConvertedValue<std::string> 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<std::string> default_choices() {
return {"unconnected", "nets", "gnd", "vcc"};
}
};
struct ParsePostSynthNetlistUnconnOutputHandling {
ConvertedValue<e_post_synth_netlist_unconn_handling> from_str(std::string str) {
ConvertedValue<e_post_synth_netlist_unconn_handling> 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<std::string> to_str(e_post_synth_netlist_unconn_handling val) {
ConvertedValue<std::string> 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<std::string> 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<e_post_synth_netlist_unconn_handling, ParsePostSynthNetlistUnconnInputHandling>(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<ID>, where <ID> 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<e_post_synth_netlist_unconn_handling, ParsePostSynthNetlistUnconnOutputHandling>(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<ID>, where <ID> 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<bool, ParseOnOff>(args.do_power, "--power")

View File

@ -159,6 +159,8 @@ struct t_options {
argparse::ArgValue<int> timing_report_npaths;
argparse::ArgValue<e_timing_report_detail> timing_report_detail;
argparse::ArgValue<bool> timing_report_skew;
argparse::ArgValue<e_post_synth_netlist_unconn_handling> post_synth_netlist_unconn_input_handling;
argparse::ArgValue<e_post_synth_netlist_unconn_handling> post_synth_netlist_unconn_output_handling;
};
argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& args);

View File

@ -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

View File

@ -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;