Skip to content

Commit cd8fb2b

Browse files
authored
Merge pull request #2002 from antmicro/fix-post-verilog-port-handling
Corrected handling of unconnected ports in output Verilog netlist
2 parents 980b450 + 97fb515 commit cd8fb2b

9 files changed

+1632
-40
lines changed

vpr/src/base/netlist_writer.cpp

Lines changed: 74 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ std::string join_identifier(std::string lhs, std::string rhs);
127127
//
128128
//
129129

130+
// Unconnected net prefix
131+
const std::string unconn_prefix = "__vpr__unconn";
132+
130133
//A combinational timing arc
131134
class Arc {
132135
public:
@@ -953,6 +956,16 @@ class NetlistWriterVisitor : public NetlistVisitor {
953956
inst->print_verilog(verilog_os_, unconn_count, depth + 1);
954957
}
955958

959+
//Unconnected wires
960+
if (unconn_count) {
961+
verilog_os_ << "\n";
962+
verilog_os_ << indent(depth + 1) << "//Unconnected wires\n";
963+
for (size_t i = 0; i < unconn_count; ++i) {
964+
auto name = unconn_prefix + std::to_string(i);
965+
verilog_os_ << indent(depth + 1) << "wire " << escape_verilog_identifier(name) << ";\n";
966+
}
967+
}
968+
956969
verilog_os_ << "\n";
957970
verilog_os_ << indent(depth) << "endmodule\n";
958971
}
@@ -2134,7 +2147,7 @@ double get_delay_ps(double delay_sec) {
21342147
std::string create_unconn_net(size_t& unconn_count) {
21352148
//We increment unconn_count by reference so each
21362149
//call generates a unique name
2137-
return "__vpr__unconn" + std::to_string(unconn_count++);
2150+
return unconn_prefix + std::to_string(unconn_count++);
21382151
}
21392152

21402153
/**
@@ -2177,6 +2190,30 @@ void print_blif_port(std::ostream& os, size_t& unconn_count, const std::string&
21772190
* Handles special cases like multi-bit and disconnected ports
21782191
*/
21792192
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) {
2193+
auto unconn_inp_name = [&]() {
2194+
switch (opts.post_synth_netlist_unconn_input_handling) {
2195+
case e_post_synth_netlist_unconn_handling::GND:
2196+
return std::string("1'b0");
2197+
case e_post_synth_netlist_unconn_handling::VCC:
2198+
return std::string("1'b1");
2199+
case e_post_synth_netlist_unconn_handling::NETS:
2200+
return create_unconn_net(unconn_count);
2201+
case e_post_synth_netlist_unconn_handling::UNCONNECTED:
2202+
default:
2203+
return std::string("1'bX");
2204+
}
2205+
};
2206+
2207+
auto unconn_out_name = [&]() {
2208+
switch (opts.post_synth_netlist_unconn_output_handling) {
2209+
case e_post_synth_netlist_unconn_handling::NETS:
2210+
return create_unconn_net(unconn_count);
2211+
case e_post_synth_netlist_unconn_handling::UNCONNECTED:
2212+
default:
2213+
return std::string();
2214+
}
2215+
};
2216+
21802217
//Port name
21812218
os << indent(depth) << "." << port_name << "(";
21822219

@@ -2186,60 +2223,57 @@ void print_verilog_port(std::ostream& os, size_t& unconn_count, const std::strin
21862223
if (nets[0].empty()) {
21872224
//Disconnected
21882225
if (type == PortType::INPUT || type == PortType::CLOCK) {
2189-
switch (opts.post_synth_netlist_unconn_input_handling) {
2190-
case e_post_synth_netlist_unconn_handling::GND:
2191-
os << "1'b0";
2192-
break;
2193-
case e_post_synth_netlist_unconn_handling::VCC:
2194-
os << "1'b1";
2195-
break;
2196-
case e_post_synth_netlist_unconn_handling::NETS:
2197-
os << create_unconn_net(unconn_count);
2198-
break;
2199-
case e_post_synth_netlist_unconn_handling::UNCONNECTED:
2200-
default:
2201-
os << "1'bX";
2202-
}
2226+
os << unconn_inp_name();
22032227
} else {
22042228
VTR_ASSERT(type == PortType::OUTPUT);
2205-
switch (opts.post_synth_netlist_unconn_output_handling) {
2206-
case e_post_synth_netlist_unconn_handling::NETS:
2207-
os << create_unconn_net(unconn_count);
2208-
break;
2209-
case e_post_synth_netlist_unconn_handling::UNCONNECTED:
2210-
default:
2211-
os << "1'bX";
2212-
}
2229+
os << unconn_out_name();
22132230
}
22142231
} else {
22152232
//Connected
22162233
os << escape_verilog_identifier(nets[0]);
22172234
}
22182235
} else {
2236+
// Check if all pins are unconnected
2237+
bool all_unconnected = true;
2238+
for (size_t i = 0; i < nets.size(); ++i) {
2239+
if (!nets[i].empty()) {
2240+
all_unconnected = false;
2241+
break;
2242+
}
2243+
}
2244+
22192245
//A multi-bit port, we explicitly concat the single-bit nets to build the port,
22202246
//taking care to print MSB on left and LSB on right
2221-
os << "{"
2222-
<< "\n";
2223-
for (int ipin = (int)nets.size() - 1; ipin >= 0; --ipin) { //Reverse order to match endianess
2224-
os << indent(depth + 1);
2225-
if (nets[ipin].empty()) {
2226-
//Disconnected
2227-
if (type == PortType::INPUT || type == PortType::CLOCK) {
2228-
os << "1'b0";
2247+
if (all_unconnected && type == PortType::OUTPUT && opts.post_synth_netlist_unconn_output_handling == e_post_synth_netlist_unconn_handling::UNCONNECTED) {
2248+
// Empty connection
2249+
} else {
2250+
// Individual bits
2251+
os << "{"
2252+
<< "\n";
2253+
for (int ipin = (int)nets.size() - 1; ipin >= 0; --ipin) { //Reverse order to match endianess
2254+
os << indent(depth + 1);
2255+
if (nets[ipin].empty()) {
2256+
//Disconnected
2257+
if (type == PortType::INPUT || type == PortType::CLOCK) {
2258+
os << unconn_inp_name();
2259+
} else {
2260+
VTR_ASSERT(type == PortType::OUTPUT);
2261+
// When concatenating output connection there cannot
2262+
// be an empty placeholder so we have to create a
2263+
// dummy net.
2264+
os << create_unconn_net(unconn_count);
2265+
}
22292266
} else {
2230-
VTR_ASSERT(type == PortType::OUTPUT);
2231-
os << "";
2267+
//Connected
2268+
os << escape_verilog_identifier(nets[ipin]);
2269+
}
2270+
if (ipin != 0) {
2271+
os << ",";
22322272
}
2233-
} else {
2234-
//Connected
2235-
os << escape_verilog_identifier(nets[ipin]);
2236-
}
2237-
if (ipin != 0) {
2238-
os << ",";
22392273
os << "\n";
22402274
}
2275+
os << indent(depth) + " }";
22412276
}
2242-
os << "}";
22432277
}
22442278
os << ")";
22452279
}

vpr/test/test_post_verilog.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#include "catch2/catch_test_macros.hpp"
2+
3+
#include "vpr_api.h"
4+
#include "timing_place_lookup.h"
5+
6+
#include <fstream>
7+
8+
namespace {
9+
10+
static constexpr const char kArchFile[] = "test_post_verilog_arch.xml";
11+
static constexpr const char kCircuitFile[] = "unconnected.eblif";
12+
13+
void do_vpr_flow(const char* input_unc_opt, const char* output_unc_opt) {
14+
// Minimal setup
15+
auto options = t_options();
16+
auto arch = t_arch();
17+
auto vpr_setup = t_vpr_setup();
18+
19+
// Command line arguments
20+
const char* argv[] = {
21+
"test_vpr",
22+
kArchFile,
23+
kCircuitFile,
24+
"--route_chan_width", "100",
25+
"--gen_post_synthesis_netlist", "on",
26+
"--post_synth_netlist_unconn_inputs", input_unc_opt,
27+
"--post_synth_netlist_unconn_outputs", output_unc_opt};
28+
29+
vpr_init(sizeof(argv) / sizeof(argv[0]), argv,
30+
&options, &vpr_setup, &arch);
31+
32+
bool flow_succeeded = vpr_flow(vpr_setup, arch);
33+
34+
free_routing_structs();
35+
vpr_free_all(arch, vpr_setup);
36+
37+
REQUIRE(flow_succeeded == true);
38+
}
39+
40+
void compare_files(const std::string& output_fname, const std::string& golden_fname) {
41+
printf("Comparing '%s' vs. '%s'\n", output_fname.c_str(), golden_fname.c_str());
42+
43+
std::ifstream output_file(output_fname);
44+
std::ifstream golden_file(golden_fname);
45+
46+
REQUIRE(output_file.good());
47+
REQUIRE(golden_file.good());
48+
49+
auto read_lines = [](std::ifstream& fp) {
50+
std::vector<std::string> lines;
51+
while (fp.good()) {
52+
std::string line;
53+
std::getline(fp, line);
54+
lines.push_back(line);
55+
}
56+
57+
return lines;
58+
};
59+
60+
auto output_data = read_lines(output_file);
61+
auto golden_data = read_lines(golden_file);
62+
63+
REQUIRE(!output_data.empty());
64+
REQUIRE(!golden_data.empty());
65+
REQUIRE(output_data.size() == golden_data.size());
66+
67+
// Skip the first line as it contains a comment with build SHA
68+
output_data.erase(output_data.begin());
69+
golden_data.erase(golden_data.begin());
70+
71+
REQUIRE(output_data == golden_data);
72+
}
73+
74+
TEST_CASE("post_verilog", "[vpr]") {
75+
do_vpr_flow("unconnected", "unconnected");
76+
compare_files("unconnected_post_synthesis.v", "test_post_verilog_i_unconnected_o_unconnected.golden.v");
77+
78+
do_vpr_flow("unconnected", "nets");
79+
compare_files("unconnected_post_synthesis.v", "test_post_verilog_i_unconnected_o_nets.golden.v");
80+
81+
do_vpr_flow("vcc", "unconnected");
82+
compare_files("unconnected_post_synthesis.v", "test_post_verilog_i_vcc_o_unconnected.golden.v");
83+
84+
do_vpr_flow("gnd", "unconnected");
85+
compare_files("unconnected_post_synthesis.v", "test_post_verilog_i_gnd_o_unconnected.golden.v");
86+
87+
do_vpr_flow("nets", "unconnected");
88+
compare_files("unconnected_post_synthesis.v", "test_post_verilog_i_nets_o_unconnected.golden.v");
89+
}
90+
91+
} // namespace

0 commit comments

Comments
 (0)