Correct handling of unconnected ports in output Verilog netlist...

...so that outputs are not connected to constants.

Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
This commit is contained in:
Maciej Kurc 2022-06-30 12:57:05 +02:00 committed by Paweł Czarnecki
parent 782cdfd8e1
commit 721ac99696
1 changed files with 80 additions and 45 deletions

View File

@ -125,6 +125,9 @@ std::string join_identifier(std::string lhs, std::string rhs);
// //
// //
// Unconnected net prefix
const std::string unconn_prefix = "__vpr__unconn";
//A combinational timing arc //A combinational timing arc
class Arc { class Arc {
public: public:
@ -945,6 +948,16 @@ class NetlistWriterVisitor : public NetlistVisitor {
inst->print_verilog(verilog_os_, unconn_count, depth + 1); inst->print_verilog(verilog_os_, unconn_count, depth + 1);
} }
//Unconnected wires
if (unconn_count) {
verilog_os_ << "\n";
verilog_os_ << indent(depth + 1) << "//Unconnected wires\n";
for (size_t i = 0; i < unconn_count; ++i) {
auto name = unconn_prefix + std::to_string(i);
verilog_os_ << indent(depth + 1) << "wire " << escape_verilog_identifier(name) << ";\n";
}
}
verilog_os_ << "\n"; verilog_os_ << "\n";
verilog_os_ << indent(depth) << "endmodule\n"; verilog_os_ << indent(depth) << "endmodule\n";
} }
@ -2126,7 +2139,7 @@ double get_delay_ps(double delay_sec) {
std::string create_unconn_net(size_t& unconn_count) { std::string create_unconn_net(size_t& unconn_count) {
//We increment unconn_count by reference so each //We increment unconn_count by reference so each
//call generates a unique name //call generates a unique name
return "__vpr__unconn" + std::to_string(unconn_count++); return unconn_prefix + std::to_string(unconn_count++);
} }
/** /**
@ -2169,6 +2182,30 @@ void print_blif_port(std::ostream& os, size_t& unconn_count, const std::string&
* Handles special cases like multi-bit and disconnected ports * 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, struct t_analysis_opts& opts) { 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) {
auto unconn_inp_name = [&]() {
switch (opts.post_synth_netlist_unconn_input_handling) {
case e_post_synth_netlist_unconn_handling::GND:
return std::string("1'b0");
case e_post_synth_netlist_unconn_handling::VCC:
return std::string("1'b1");
case e_post_synth_netlist_unconn_handling::NETS:
return create_unconn_net(unconn_count);
case e_post_synth_netlist_unconn_handling::UNCONNECTED:
default:
return std::string("1'bX");
}
};
auto unconn_out_name = [&]() {
switch (opts.post_synth_netlist_unconn_output_handling) {
case e_post_synth_netlist_unconn_handling::NETS:
return create_unconn_net(unconn_count);
case e_post_synth_netlist_unconn_handling::UNCONNECTED:
default:
return std::string();
}
};
//Port name //Port name
os << indent(depth) << "." << port_name << "("; os << indent(depth) << "." << port_name << "(";
@ -2178,60 +2215,58 @@ void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::strin
if (nets[0].empty()) { if (nets[0].empty()) {
//Disconnected //Disconnected
if (type == PortType::INPUT || type == PortType::CLOCK) { if (type == PortType::INPUT || type == PortType::CLOCK) {
switch (opts.post_synth_netlist_unconn_input_handling) { os << unconn_inp_name();
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 { } else {
VTR_ASSERT(type == PortType::OUTPUT); VTR_ASSERT(type == PortType::OUTPUT);
switch (opts.post_synth_netlist_unconn_output_handling) { os << unconn_out_name();
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 { } else {
//Connected //Connected
os << escape_verilog_identifier(nets[0]); os << escape_verilog_identifier(nets[0]);
} }
} else { } else {
//A multi-bit port, we explicitly concat the single-bit nets to build the port, // Check if all pins are unconnected
//taking care to print MSB on left and LSB on right bool all_unconnected = true;
os << "{" for (size_t i = 0; i < nets.size(); ++i) {
<< "\n"; if (!nets[i].empty()) {
for (int ipin = (int)nets.size() - 1; ipin >= 0; --ipin) { //Reverse order to match endianess all_unconnected = false;
os << indent(depth + 1); break;
if (nets[ipin].empty()) {
//Disconnected
if (type == PortType::INPUT || type == PortType::CLOCK) {
os << "1'b0";
} else {
VTR_ASSERT(type == PortType::OUTPUT);
os << "";
}
} else {
//Connected
os << escape_verilog_identifier(nets[ipin]);
}
if (ipin != 0) {
os << ",";
os << "\n";
} }
} }
os << "}";
//A multi-bit port, we explicitly concat the single-bit nets to build the port,
//taking care to print MSB on left and LSB on right
if (all_unconnected && type == PortType::OUTPUT && opts.post_synth_netlist_unconn_output_handling == e_post_synth_netlist_unconn_handling::UNCONNECTED) {
// Empty connection
} else {
// Individual bits
os << "{"
<< "\n";
for (int ipin = (int)nets.size() - 1; ipin >= 0; --ipin) { //Reverse order to match endianess
os << indent(depth + 1);
if (nets[ipin].empty()) {
//Disconnected
if (type == PortType::INPUT || type == PortType::CLOCK) {
os << unconn_inp_name();
} else {
VTR_ASSERT(type == PortType::OUTPUT);
// When concatenating output connection there cannot
// be an empty placeholder so we have to create a
// dummy net.
os << create_unconn_net(unconn_count);
}
} else {
//Connected
os << escape_verilog_identifier(nets[ipin]);
}
if (ipin != 0) {
os << ",";
}
os << "\n";
}
os << indent(depth) + " }";
}
} }
os << ")"; os << ")";
} }