From 7bd1c664a6f0d9a20a2f3f0c0f136403918afacf Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 10:51:02 -0700 Subject: Initial adaptation of muxpack from shregmap --- passes/techmap/Makefile.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index cf9e198ad..561636080 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -37,6 +37,7 @@ OBJS += passes/techmap/attrmap.o OBJS += passes/techmap/zinit.o OBJS += passes/techmap/dff2dffs.o OBJS += passes/techmap/flowmap.o +OBJS += passes/techmap/muxpack.o endif GENFILES += passes/techmap/techmap.inc -- cgit v1.2.3 From 543dd11c7e46f9c88bd1f0d21474bac95d1ab6d1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 11:03:45 -0700 Subject: Missing file --- passes/techmap/muxpack.cc | 232 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 passes/techmap/muxpack.cc diff --git a/passes/techmap/muxpack.cc b/passes/techmap/muxpack.cc new file mode 100644 index 000000000..4945affb0 --- /dev/null +++ b/passes/techmap/muxpack.cc @@ -0,0 +1,232 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * 2019 Eddie Hung + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct MuxpackWorker +{ + Module *module; + SigMap sigmap; + + int mux_count, pmux_count; + + pool remove_cells; + + dict sig_chain_next; + dict sig_chain_prev; + pool sigbit_with_non_chain_users; + pool chain_start_cells; + + void make_sig_chain_next_prev() + { + for (auto wire : module->wires()) + { + if (wire->port_output || wire->get_bool_attribute("\\keep")) { + for (auto bit : sigmap(wire)) { + sigbit_with_non_chain_users.insert(bit); + } + } + } + + for (auto cell : module->cells()) + { + if (cell->type.in("$mux") && !cell->get_bool_attribute("\\keep")) + { + SigSpec a_sig = sigmap(cell->getPort("\\A")); + SigSpec y_sig = sigmap(cell->getPort("\\Y")); + + if (sig_chain_next.count(a_sig)) + for (auto a_bit : a_sig.bits()) + sigbit_with_non_chain_users.insert(a_bit); + else + sig_chain_next[a_sig] = cell; + + sig_chain_prev[y_sig] = cell; + continue; + } + + for (auto conn : cell->connections()) + if (cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) + sigbit_with_non_chain_users.insert(bit); + } + } + + void find_chain_start_cells() + { + for (auto it : sig_chain_next) + { + for (auto bit : it.first.bits()) + if (sigbit_with_non_chain_users.count(bit)) + goto start_cell; + + if (sig_chain_prev.count(it.first) != 0) + { + Cell *c1 = sig_chain_prev.at(it.first); + Cell *c2 = it.second; + + if (c1->type != c2->type) + goto start_cell; + + if (c1->parameters != c2->parameters) + goto start_cell; + + continue; + } + + start_cell: + chain_start_cells.insert(it.second); + } + } + + vector create_chain(Cell *start_cell) + { + vector chain; + + Cell *c = start_cell; + while (c != nullptr) + { + chain.push_back(c); + + SigSpec y_sig = sigmap(c->getPort("\\Y")); + + if (sig_chain_next.count(y_sig) == 0) + break; + + c = sig_chain_next.at(y_sig); + if (chain_start_cells.count(c) != 0) + break; + } + + return chain; + } + + void process_chain(vector &chain) + { + if (GetSize(chain) < 2) + return; + + int cursor = 0; + while (cursor < GetSize(chain)) + { + int cases = GetSize(chain) - cursor; + + Cell *first_cell = chain[cursor]; + dict taps_dict; + + if (cases < 2) { + cursor++; + continue; + } + + Cell *last_cell = chain[cursor+cases-1]; + + log("Converting %s.%s ... %s.%s to a pmux with %d cases.\n", + log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), cases); + + mux_count += cases; + pmux_count += 1; + + first_cell->type = "$pmux"; + SigSpec b_sig = first_cell->getPort("\\B"); + SigSpec s_sig = first_cell->getPort("\\S"); + + for (int i = 1; i < cases; i++) { + Cell* cursor_cell = chain[cursor+i]; + b_sig.append(cursor_cell->getPort("\\B")); + s_sig.append(cursor_cell->getPort("\\S")); + remove_cells.insert(cursor_cell); + } + + first_cell->setPort("\\B", b_sig); + first_cell->setPort("\\S", s_sig); + first_cell->setParam("\\S_WIDTH", GetSize(s_sig)); + first_cell->setPort("\\Y", last_cell->getPort("\\Y")); + + cursor += cases; + } + } + + void cleanup() + { + for (auto cell : remove_cells) + module->remove(cell); + + remove_cells.clear(); + sig_chain_next.clear(); + sig_chain_prev.clear(); + chain_start_cells.clear(); + } + + MuxpackWorker(Module *module) : + module(module), sigmap(module), mux_count(0), pmux_count(0) + { + make_sig_chain_next_prev(); + find_chain_start_cells(); + + for (auto c : chain_start_cells) { + vector chain = create_chain(c); + process_chain(chain); + } + + cleanup(); + } +}; + +struct MuxpackPass : public Pass { + MuxpackPass() : Pass("muxpack", "TODO") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" muxpack [options] [selection]\n"); + log("\n"); + log("TODO"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing MUXPACK pass (TODO).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + break; + } + extra_args(args, argidx, design); + + int mux_count = 0; + int pmux_count = 0; + + for (auto module : design->selected_modules()) { + MuxpackWorker worker(module); + mux_count += worker.mux_count; + pmux_count += worker.pmux_count; + } + + log("Converted %d (p)mux cells into %d pmux cells.\n", mux_count, pmux_count); + } +} MuxpackPass; + +PRIVATE_NAMESPACE_END -- cgit v1.2.3 From 3e76e3a6fa4355e7223b10bba394f986d6821551 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 11:54:38 -0700 Subject: Add tests, fix for != --- passes/techmap/muxpack.cc | 41 ++++++++++++++++++++++++++++++++--------- tests/various/muxpack.v | 36 ++++++++++++++++++++++++++++++++++++ tests/various/muxpack.ys | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 9 deletions(-) create mode 100644 tests/various/muxpack.v create mode 100644 tests/various/muxpack.ys diff --git a/passes/techmap/muxpack.cc b/passes/techmap/muxpack.cc index 4945affb0..54c52150a 100644 --- a/passes/techmap/muxpack.cc +++ b/passes/techmap/muxpack.cc @@ -54,14 +54,21 @@ struct MuxpackWorker if (cell->type.in("$mux") && !cell->get_bool_attribute("\\keep")) { SigSpec a_sig = sigmap(cell->getPort("\\A")); + SigSpec b_sig = sigmap(cell->getPort("\\B")); SigSpec y_sig = sigmap(cell->getPort("\\Y")); if (sig_chain_next.count(a_sig)) for (auto a_bit : a_sig.bits()) sigbit_with_non_chain_users.insert(a_bit); - else + else sig_chain_next[a_sig] = cell; + if (sig_chain_next.count(b_sig)) + for (auto b_bit : b_sig.bits()) + sigbit_with_non_chain_users.insert(b_bit); + else + sig_chain_next[b_sig] = cell; + sig_chain_prev[y_sig] = cell; continue; } @@ -77,13 +84,22 @@ struct MuxpackWorker { for (auto it : sig_chain_next) { + SigSpec next_sig; + for (auto bit : it.first.bits()) if (sigbit_with_non_chain_users.count(bit)) goto start_cell; - if (sig_chain_prev.count(it.first) != 0) + next_sig = it.second->getPort("\\A"); + if (sig_chain_prev.count(next_sig) == 0) { + next_sig = it.second->getPort("\\B"); + if (sig_chain_prev.count(next_sig) == 0) + next_sig = SigSpec(); + } + + if (!next_sig.empty()) { - Cell *c1 = sig_chain_prev.at(it.first); + Cell *c1 = sig_chain_prev.at(next_sig); Cell *c2 = it.second; if (c1->type != c2->type) @@ -149,15 +165,22 @@ struct MuxpackWorker pmux_count += 1; first_cell->type = "$pmux"; - SigSpec b_sig = first_cell->getPort("\\B"); - SigSpec s_sig = first_cell->getPort("\\S"); + SigSpec b_sig = first_cell->getPort("\\B"); + SigSpec s_sig = first_cell->getPort("\\S"); for (int i = 1; i < cases; i++) { - Cell* cursor_cell = chain[cursor+i]; - b_sig.append(cursor_cell->getPort("\\B")); - s_sig.append(cursor_cell->getPort("\\S")); + Cell* prev_cell = chain[cursor+i-1]; + Cell* cursor_cell = chain[cursor+i]; + if (sigmap(prev_cell->getPort("\\Y")) == sigmap(cursor_cell->getPort("\\A"))) { + b_sig.append(cursor_cell->getPort("\\B")); + s_sig.append(cursor_cell->getPort("\\S")); + } + else { + b_sig.append(cursor_cell->getPort("\\A")); + s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort("\\S"))); + } remove_cells.insert(cursor_cell); - } + } first_cell->setPort("\\B", b_sig); first_cell->setPort("\\S", s_sig); diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v new file mode 100644 index 000000000..abc87ba44 --- /dev/null +++ b/tests/various/muxpack.v @@ -0,0 +1,36 @@ +module mux_if_unbal_4_1 #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* + if (s == 0) o <= i[0*W+:W]; + else if (s == 1) o <= i[1*W+:W]; + else if (s == 2) o <= i[2*W+:W]; + else if (s == 3) o <= i[3*W+:W]; + else o <= {W{1'bx}}; + +endmodule + +module mux_if_unbal_5_3 #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + if (s == 0) o <= i[0*W+:W]; + if (s == 1) o <= i[1*W+:W]; + if (s == 2) o <= i[2*W+:W]; + if (s == 3) o <= i[3*W+:W]; + if (s == 4) o <= i[4*W+:W]; +end + +endmodule + +module mux_if_unbal_5_3_invert #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* + if (s != 0) + if (s != 1) + if (s != 2) + if (s != 3) + if (s != 4) o <= i[4*W+:W]; + else o <= i[0*W+:W]; + else o <= i[3*W+:W]; + else o <= i[2*W+:W]; + else o <= i[1*W+:W]; + else o <= {W{1'bx}}; + +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys new file mode 100644 index 000000000..58c01cf05 --- /dev/null +++ b/tests/various/muxpack.ys @@ -0,0 +1,42 @@ +read_verilog muxpack.v +design -save read +hierarchy -top mux_if_unbal_4_1 +prep +design -save gold +muxpack +opt +stat +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_5_3 +prep +design -save gold +muxpack +opt +stat +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_5_3_invert +prep +design -save gold +muxpack +opt +stat +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter -- cgit v1.2.3 From 5d4eca5a298d2f98de220cfd0efe5452ab4052d8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 11:59:41 -0700 Subject: Add a few more special case tests --- tests/various/muxpack.v | 23 +++++++++++++++++++++++ tests/various/muxpack.ys | 28 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index abc87ba44..333908fcb 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -34,3 +34,26 @@ always @* else o <= {W{1'bx}}; endmodule + +module mux_if_unbal_5_3_width_mismatch #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + if (s == 0) o <= i[0*W+:W]; + if (s == 1) o <= i[1*W+:W]; + if (s == 2) o[W-2:0] <= i[2*W+:W-1]; + if (s == 3) o <= i[3*W+:W]; + if (s == 4) o <= i[4*W+:W]; +end + +endmodule + +module mux_if_unbal_5_3_missing #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + if (s == 0) o <= i[0*W+:W]; +// else if (s == 1) o <= i[1*W+:W]; +// else if (s == 2) o <= i[2*W+:W]; + else if (s == 3) o <= i[3*W+:W]; + else o <= {W{1'bx}}; +end + +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index 58c01cf05..174eea74b 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -40,3 +40,31 @@ design -import gold -as gold design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_5_3_width_mismatch +prep +design -save gold +muxpack +opt +stat +select -assert-count 2 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_5_3_missing +prep +design -save gold +muxpack +opt +stat +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter -- cgit v1.2.3 From b8620f7b3dde4460e5a8ed3ea7fd7aef54aa7da1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:03:44 -0700 Subject: One more and tidy up --- tests/various/muxpack.v | 18 +++++++++++++----- tests/various/muxpack.ys | 16 +++++++++++++++- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index 333908fcb..c2c2537a0 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -5,7 +5,6 @@ always @* else if (s == 2) o <= i[2*W+:W]; else if (s == 3) o <= i[3*W+:W]; else o <= {W{1'bx}}; - endmodule module mux_if_unbal_5_3 #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); @@ -17,7 +16,6 @@ always @* begin if (s == 3) o <= i[3*W+:W]; if (s == 4) o <= i[4*W+:W]; end - endmodule module mux_if_unbal_5_3_invert #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); @@ -32,7 +30,6 @@ always @* else o <= i[2*W+:W]; else o <= i[1*W+:W]; else o <= {W{1'bx}}; - endmodule module mux_if_unbal_5_3_width_mismatch #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); @@ -44,10 +41,9 @@ always @* begin if (s == 3) o <= i[3*W+:W]; if (s == 4) o <= i[4*W+:W]; end - endmodule -module mux_if_unbal_5_3_missing #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +module mux_if_unbal_4_1_missing #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); always @* begin if (s == 0) o <= i[0*W+:W]; // else if (s == 1) o <= i[1*W+:W]; @@ -55,5 +51,17 @@ always @* begin else if (s == 3) o <= i[3*W+:W]; else o <= {W{1'bx}}; end +endmodule +module mux_if_unbal_5_3_order #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + if (s == 3) o <= i[3*W+:W]; + if (s == 2) o <= i[2*W+:W]; + if (s == 1) o <= i[1*W+:W]; + if (s == 4) o <= i[4*W+:W]; + if (s == 0) o <= i[0*W+:W]; +end endmodule + + diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index 174eea74b..a967ddfef 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -56,7 +56,21 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter design -load read -hierarchy -top mux_if_unbal_5_3_missing +hierarchy -top mux_if_unbal_4_1_missing +prep +design -save gold +muxpack +opt +stat +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_5_3_order prep design -save gold muxpack -- cgit v1.2.3 From 030f1d30e9cd04b4412114bdc93a15a39a4597c4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:04:42 -0700 Subject: Add to CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 36b64e111..e67d9c903 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ Yosys 0.8 .. Yosys 0.8-dev - Added "gate2lut.v" techmap rule - Added "rename -src" - Added "equiv_opt" pass + - Added "muxpack" pass - "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx" -- cgit v1.2.3 From 3dd0682f298cec18f60c2d9da6417e287a385dd4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:11:59 -0700 Subject: Update doc --- passes/techmap/muxpack.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/passes/techmap/muxpack.cc b/passes/techmap/muxpack.cc index 54c52150a..9668b0d43 100644 --- a/passes/techmap/muxpack.cc +++ b/passes/techmap/muxpack.cc @@ -218,19 +218,20 @@ struct MuxpackWorker }; struct MuxpackPass : public Pass { - MuxpackPass() : Pass("muxpack", "TODO") { } + MuxpackPass() : Pass("muxpack", "$mux cell cascades to $pmux") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" muxpack [options] [selection]\n"); + log(" muxpack [selection]\n"); log("\n"); - log("TODO"); + log("This pass converts cascaded chains of $mux cells (e.g. those created by if-else\n"); + log("constructs) into $pmux cells.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - log_header(design, "Executing MUXPACK pass (TODO).\n"); + log_header(design, "Executing MUXPACK pass ($mux cell cascades to $pmux).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) -- cgit v1.2.3 From 83450a94898321a239f67f92e05fb9a246f4dd6d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:15:13 -0700 Subject: Move muxpack from passes/techmap to passes/opt --- passes/opt/Makefile.inc | 1 + passes/opt/muxpack.cc | 256 ++++++++++++++++++++++++++++++++++++++++++++ passes/techmap/Makefile.inc | 1 - passes/techmap/muxpack.cc | 256 -------------------------------------------- 4 files changed, 257 insertions(+), 257 deletions(-) create mode 100644 passes/opt/muxpack.cc delete mode 100644 passes/techmap/muxpack.cc diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc index 337fee9e4..ea3646330 100644 --- a/passes/opt/Makefile.inc +++ b/passes/opt/Makefile.inc @@ -14,5 +14,6 @@ OBJS += passes/opt/opt_demorgan.o OBJS += passes/opt/rmports.o OBJS += passes/opt/opt_lut.o OBJS += passes/opt/pmux2shiftx.o +OBJS += passes/opt/muxpack.o endif diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc new file mode 100644 index 000000000..9668b0d43 --- /dev/null +++ b/passes/opt/muxpack.cc @@ -0,0 +1,256 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * 2019 Eddie Hung + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct MuxpackWorker +{ + Module *module; + SigMap sigmap; + + int mux_count, pmux_count; + + pool remove_cells; + + dict sig_chain_next; + dict sig_chain_prev; + pool sigbit_with_non_chain_users; + pool chain_start_cells; + + void make_sig_chain_next_prev() + { + for (auto wire : module->wires()) + { + if (wire->port_output || wire->get_bool_attribute("\\keep")) { + for (auto bit : sigmap(wire)) { + sigbit_with_non_chain_users.insert(bit); + } + } + } + + for (auto cell : module->cells()) + { + if (cell->type.in("$mux") && !cell->get_bool_attribute("\\keep")) + { + SigSpec a_sig = sigmap(cell->getPort("\\A")); + SigSpec b_sig = sigmap(cell->getPort("\\B")); + SigSpec y_sig = sigmap(cell->getPort("\\Y")); + + if (sig_chain_next.count(a_sig)) + for (auto a_bit : a_sig.bits()) + sigbit_with_non_chain_users.insert(a_bit); + else + sig_chain_next[a_sig] = cell; + + if (sig_chain_next.count(b_sig)) + for (auto b_bit : b_sig.bits()) + sigbit_with_non_chain_users.insert(b_bit); + else + sig_chain_next[b_sig] = cell; + + sig_chain_prev[y_sig] = cell; + continue; + } + + for (auto conn : cell->connections()) + if (cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) + sigbit_with_non_chain_users.insert(bit); + } + } + + void find_chain_start_cells() + { + for (auto it : sig_chain_next) + { + SigSpec next_sig; + + for (auto bit : it.first.bits()) + if (sigbit_with_non_chain_users.count(bit)) + goto start_cell; + + next_sig = it.second->getPort("\\A"); + if (sig_chain_prev.count(next_sig) == 0) { + next_sig = it.second->getPort("\\B"); + if (sig_chain_prev.count(next_sig) == 0) + next_sig = SigSpec(); + } + + if (!next_sig.empty()) + { + Cell *c1 = sig_chain_prev.at(next_sig); + Cell *c2 = it.second; + + if (c1->type != c2->type) + goto start_cell; + + if (c1->parameters != c2->parameters) + goto start_cell; + + continue; + } + + start_cell: + chain_start_cells.insert(it.second); + } + } + + vector create_chain(Cell *start_cell) + { + vector chain; + + Cell *c = start_cell; + while (c != nullptr) + { + chain.push_back(c); + + SigSpec y_sig = sigmap(c->getPort("\\Y")); + + if (sig_chain_next.count(y_sig) == 0) + break; + + c = sig_chain_next.at(y_sig); + if (chain_start_cells.count(c) != 0) + break; + } + + return chain; + } + + void process_chain(vector &chain) + { + if (GetSize(chain) < 2) + return; + + int cursor = 0; + while (cursor < GetSize(chain)) + { + int cases = GetSize(chain) - cursor; + + Cell *first_cell = chain[cursor]; + dict taps_dict; + + if (cases < 2) { + cursor++; + continue; + } + + Cell *last_cell = chain[cursor+cases-1]; + + log("Converting %s.%s ... %s.%s to a pmux with %d cases.\n", + log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), cases); + + mux_count += cases; + pmux_count += 1; + + first_cell->type = "$pmux"; + SigSpec b_sig = first_cell->getPort("\\B"); + SigSpec s_sig = first_cell->getPort("\\S"); + + for (int i = 1; i < cases; i++) { + Cell* prev_cell = chain[cursor+i-1]; + Cell* cursor_cell = chain[cursor+i]; + if (sigmap(prev_cell->getPort("\\Y")) == sigmap(cursor_cell->getPort("\\A"))) { + b_sig.append(cursor_cell->getPort("\\B")); + s_sig.append(cursor_cell->getPort("\\S")); + } + else { + b_sig.append(cursor_cell->getPort("\\A")); + s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort("\\S"))); + } + remove_cells.insert(cursor_cell); + } + + first_cell->setPort("\\B", b_sig); + first_cell->setPort("\\S", s_sig); + first_cell->setParam("\\S_WIDTH", GetSize(s_sig)); + first_cell->setPort("\\Y", last_cell->getPort("\\Y")); + + cursor += cases; + } + } + + void cleanup() + { + for (auto cell : remove_cells) + module->remove(cell); + + remove_cells.clear(); + sig_chain_next.clear(); + sig_chain_prev.clear(); + chain_start_cells.clear(); + } + + MuxpackWorker(Module *module) : + module(module), sigmap(module), mux_count(0), pmux_count(0) + { + make_sig_chain_next_prev(); + find_chain_start_cells(); + + for (auto c : chain_start_cells) { + vector chain = create_chain(c); + process_chain(chain); + } + + cleanup(); + } +}; + +struct MuxpackPass : public Pass { + MuxpackPass() : Pass("muxpack", "$mux cell cascades to $pmux") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" muxpack [selection]\n"); + log("\n"); + log("This pass converts cascaded chains of $mux cells (e.g. those created by if-else\n"); + log("constructs) into $pmux cells.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing MUXPACK pass ($mux cell cascades to $pmux).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + break; + } + extra_args(args, argidx, design); + + int mux_count = 0; + int pmux_count = 0; + + for (auto module : design->selected_modules()) { + MuxpackWorker worker(module); + mux_count += worker.mux_count; + pmux_count += worker.pmux_count; + } + + log("Converted %d (p)mux cells into %d pmux cells.\n", mux_count, pmux_count); + } +} MuxpackPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 561636080..cf9e198ad 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -37,7 +37,6 @@ OBJS += passes/techmap/attrmap.o OBJS += passes/techmap/zinit.o OBJS += passes/techmap/dff2dffs.o OBJS += passes/techmap/flowmap.o -OBJS += passes/techmap/muxpack.o endif GENFILES += passes/techmap/techmap.inc diff --git a/passes/techmap/muxpack.cc b/passes/techmap/muxpack.cc deleted file mode 100644 index 9668b0d43..000000000 --- a/passes/techmap/muxpack.cc +++ /dev/null @@ -1,256 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * 2019 Eddie Hung - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct MuxpackWorker -{ - Module *module; - SigMap sigmap; - - int mux_count, pmux_count; - - pool remove_cells; - - dict sig_chain_next; - dict sig_chain_prev; - pool sigbit_with_non_chain_users; - pool chain_start_cells; - - void make_sig_chain_next_prev() - { - for (auto wire : module->wires()) - { - if (wire->port_output || wire->get_bool_attribute("\\keep")) { - for (auto bit : sigmap(wire)) { - sigbit_with_non_chain_users.insert(bit); - } - } - } - - for (auto cell : module->cells()) - { - if (cell->type.in("$mux") && !cell->get_bool_attribute("\\keep")) - { - SigSpec a_sig = sigmap(cell->getPort("\\A")); - SigSpec b_sig = sigmap(cell->getPort("\\B")); - SigSpec y_sig = sigmap(cell->getPort("\\Y")); - - if (sig_chain_next.count(a_sig)) - for (auto a_bit : a_sig.bits()) - sigbit_with_non_chain_users.insert(a_bit); - else - sig_chain_next[a_sig] = cell; - - if (sig_chain_next.count(b_sig)) - for (auto b_bit : b_sig.bits()) - sigbit_with_non_chain_users.insert(b_bit); - else - sig_chain_next[b_sig] = cell; - - sig_chain_prev[y_sig] = cell; - continue; - } - - for (auto conn : cell->connections()) - if (cell->input(conn.first)) - for (auto bit : sigmap(conn.second)) - sigbit_with_non_chain_users.insert(bit); - } - } - - void find_chain_start_cells() - { - for (auto it : sig_chain_next) - { - SigSpec next_sig; - - for (auto bit : it.first.bits()) - if (sigbit_with_non_chain_users.count(bit)) - goto start_cell; - - next_sig = it.second->getPort("\\A"); - if (sig_chain_prev.count(next_sig) == 0) { - next_sig = it.second->getPort("\\B"); - if (sig_chain_prev.count(next_sig) == 0) - next_sig = SigSpec(); - } - - if (!next_sig.empty()) - { - Cell *c1 = sig_chain_prev.at(next_sig); - Cell *c2 = it.second; - - if (c1->type != c2->type) - goto start_cell; - - if (c1->parameters != c2->parameters) - goto start_cell; - - continue; - } - - start_cell: - chain_start_cells.insert(it.second); - } - } - - vector create_chain(Cell *start_cell) - { - vector chain; - - Cell *c = start_cell; - while (c != nullptr) - { - chain.push_back(c); - - SigSpec y_sig = sigmap(c->getPort("\\Y")); - - if (sig_chain_next.count(y_sig) == 0) - break; - - c = sig_chain_next.at(y_sig); - if (chain_start_cells.count(c) != 0) - break; - } - - return chain; - } - - void process_chain(vector &chain) - { - if (GetSize(chain) < 2) - return; - - int cursor = 0; - while (cursor < GetSize(chain)) - { - int cases = GetSize(chain) - cursor; - - Cell *first_cell = chain[cursor]; - dict taps_dict; - - if (cases < 2) { - cursor++; - continue; - } - - Cell *last_cell = chain[cursor+cases-1]; - - log("Converting %s.%s ... %s.%s to a pmux with %d cases.\n", - log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), cases); - - mux_count += cases; - pmux_count += 1; - - first_cell->type = "$pmux"; - SigSpec b_sig = first_cell->getPort("\\B"); - SigSpec s_sig = first_cell->getPort("\\S"); - - for (int i = 1; i < cases; i++) { - Cell* prev_cell = chain[cursor+i-1]; - Cell* cursor_cell = chain[cursor+i]; - if (sigmap(prev_cell->getPort("\\Y")) == sigmap(cursor_cell->getPort("\\A"))) { - b_sig.append(cursor_cell->getPort("\\B")); - s_sig.append(cursor_cell->getPort("\\S")); - } - else { - b_sig.append(cursor_cell->getPort("\\A")); - s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort("\\S"))); - } - remove_cells.insert(cursor_cell); - } - - first_cell->setPort("\\B", b_sig); - first_cell->setPort("\\S", s_sig); - first_cell->setParam("\\S_WIDTH", GetSize(s_sig)); - first_cell->setPort("\\Y", last_cell->getPort("\\Y")); - - cursor += cases; - } - } - - void cleanup() - { - for (auto cell : remove_cells) - module->remove(cell); - - remove_cells.clear(); - sig_chain_next.clear(); - sig_chain_prev.clear(); - chain_start_cells.clear(); - } - - MuxpackWorker(Module *module) : - module(module), sigmap(module), mux_count(0), pmux_count(0) - { - make_sig_chain_next_prev(); - find_chain_start_cells(); - - for (auto c : chain_start_cells) { - vector chain = create_chain(c); - process_chain(chain); - } - - cleanup(); - } -}; - -struct MuxpackPass : public Pass { - MuxpackPass() : Pass("muxpack", "$mux cell cascades to $pmux") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" muxpack [selection]\n"); - log("\n"); - log("This pass converts cascaded chains of $mux cells (e.g. those created by if-else\n"); - log("constructs) into $pmux cells.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log_header(design, "Executing MUXPACK pass ($mux cell cascades to $pmux).\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - break; - } - extra_args(args, argidx, design); - - int mux_count = 0; - int pmux_count = 0; - - for (auto module : design->selected_modules()) { - MuxpackWorker worker(module); - mux_count += worker.mux_count; - pmux_count += worker.pmux_count; - } - - log("Converted %d (p)mux cells into %d pmux cells.\n", mux_count, pmux_count); - } -} MuxpackPass; - -PRIVATE_NAMESPACE_END -- cgit v1.2.3 From 705388eb24022d2a310ae72cd81e67a2f0ce7586 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:44:06 -0700 Subject: Add non exclusive test --- tests/various/muxpack.v | 20 ++++++++++++++++++++ tests/various/muxpack.ys | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index c2c2537a0..e847fef27 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -64,4 +64,24 @@ always @* begin end endmodule +module mux_if_unbal_4_1_nonexcl #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* + if (s == 0) o <= i[0*W+:W]; + else if (s == 1) o <= i[1*W+:W]; + else if (s == 2) o <= i[2*W+:W]; + else if (s == 3) o <= i[3*W+:W]; + else if (s == 0) o <= {W{1'b0}}; + else o <= {W{1'bx}}; +endmodule +module mux_if_unbal_5_3_nonexcl #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + if (s == 0) o <= i[0*W+:W]; + if (s == 1) o <= i[1*W+:W]; + if (s == 2) o <= i[2*W+:W]; + if (s == 3) o <= i[3*W+:W]; + if (s == 4) o <= i[4*W+:W]; + if (s == 0) o <= i[2*W+:W]; +end +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index a967ddfef..178860b88 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -6,6 +6,7 @@ design -save gold muxpack opt stat +select -assert-count 0 t:$mux select -assert-count 1 t:$pmux design -stash gate design -import gold -as gold @@ -20,6 +21,7 @@ design -save gold muxpack opt stat +select -assert-count 0 t:$mux select -assert-count 1 t:$pmux design -stash gate design -import gold -as gold @@ -34,6 +36,7 @@ design -save gold muxpack opt stat +select -assert-count 0 t:$mux select -assert-count 1 t:$pmux design -stash gate design -import gold -as gold @@ -48,6 +51,7 @@ design -save gold muxpack opt stat +select -assert-count 0 t:$mux select -assert-count 2 t:$pmux design -stash gate design -import gold -as gold @@ -62,6 +66,7 @@ design -save gold muxpack opt stat +select -assert-count 0 t:$mux select -assert-count 1 t:$pmux design -stash gate design -import gold -as gold @@ -76,6 +81,37 @@ design -save gold muxpack opt stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_4_1_nonexcl +prep +design -save gold +muxpack +opt +stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_unbal_5_3_nonexcl +prep +design -save gold +muxpack +opt +stat +select -assert-count 0 t:$mux select -assert-count 1 t:$pmux design -stash gate design -import gold -as gold -- cgit v1.2.3 From d2172c6846f710e9a362708e3308dd302110deb2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:44:50 -0700 Subject: Non chain user check using next_sig --- passes/opt/muxpack.cc | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index 9668b0d43..963083107 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -84,19 +84,17 @@ struct MuxpackWorker { for (auto it : sig_chain_next) { - SigSpec next_sig; - - for (auto bit : it.first.bits()) - if (sigbit_with_non_chain_users.count(bit)) - goto start_cell; - - next_sig = it.second->getPort("\\A"); + SigSpec next_sig = it.second->getPort("\\A"); if (sig_chain_prev.count(next_sig) == 0) { next_sig = it.second->getPort("\\B"); if (sig_chain_prev.count(next_sig) == 0) next_sig = SigSpec(); } + for (auto bit : next_sig.bits()) + if (sigbit_with_non_chain_users.count(bit)) + goto start_cell; + if (!next_sig.empty()) { Cell *c1 = sig_chain_prev.at(next_sig); -- cgit v1.2.3 From 978fda94f684185a7d583a3865b7a68459344e46 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:46:42 -0700 Subject: Fix spacing --- passes/opt/muxpack.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index 963083107..cb13a45b0 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -43,9 +43,8 @@ struct MuxpackWorker for (auto wire : module->wires()) { if (wire->port_output || wire->get_bool_attribute("\\keep")) { - for (auto bit : sigmap(wire)) { + for (auto bit : sigmap(wire)) sigbit_with_non_chain_users.insert(bit); - } } } @@ -58,8 +57,8 @@ struct MuxpackWorker SigSpec y_sig = sigmap(cell->getPort("\\Y")); if (sig_chain_next.count(a_sig)) - for (auto a_bit : a_sig.bits()) - sigbit_with_non_chain_users.insert(a_bit); + for (auto a_bit : a_sig.bits()) + sigbit_with_non_chain_users.insert(a_bit); else sig_chain_next[a_sig] = cell; @@ -70,7 +69,7 @@ struct MuxpackWorker sig_chain_next[b_sig] = cell; sig_chain_prev[y_sig] = cell; - continue; + continue; } for (auto conn : cell->connections()) @@ -182,7 +181,7 @@ struct MuxpackWorker first_cell->setPort("\\B", b_sig); first_cell->setPort("\\S", s_sig); - first_cell->setParam("\\S_WIDTH", GetSize(s_sig)); + first_cell->setParam("\\S_WIDTH", GetSize(s_sig)); first_cell->setPort("\\Y", last_cell->getPort("\\Y")); cursor += cases; -- cgit v1.2.3 From dc7b8c4b942f9d9bc61a87a81291244d0b73843b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 12:56:34 -0700 Subject: More cleanup --- passes/opt/muxpack.cc | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index cb13a45b0..ae4b67db2 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -37,6 +37,7 @@ struct MuxpackWorker dict sig_chain_prev; pool sigbit_with_non_chain_users; pool chain_start_cells; + pool candidate_cells; void make_sig_chain_next_prev() { @@ -59,14 +60,18 @@ struct MuxpackWorker if (sig_chain_next.count(a_sig)) for (auto a_bit : a_sig.bits()) sigbit_with_non_chain_users.insert(a_bit); - else + else { sig_chain_next[a_sig] = cell; + candidate_cells.insert(cell); + } if (sig_chain_next.count(b_sig)) for (auto b_bit : b_sig.bits()) sigbit_with_non_chain_users.insert(b_bit); - else + else { sig_chain_next[b_sig] = cell; + candidate_cells.insert(cell); + } sig_chain_prev[y_sig] = cell; continue; @@ -81,35 +86,34 @@ struct MuxpackWorker void find_chain_start_cells() { - for (auto it : sig_chain_next) + for (auto cell : candidate_cells) { - SigSpec next_sig = it.second->getPort("\\A"); + SigSpec next_sig = cell->getPort("\\A"); if (sig_chain_prev.count(next_sig) == 0) { - next_sig = it.second->getPort("\\B"); + next_sig = cell->getPort("\\B"); if (sig_chain_prev.count(next_sig) == 0) - next_sig = SigSpec(); - } - - for (auto bit : next_sig.bits()) - if (sigbit_with_non_chain_users.count(bit)) goto start_cell; + } - if (!next_sig.empty()) { + for (auto bit : next_sig.bits()) + if (sigbit_with_non_chain_users.count(bit)) + goto start_cell; + Cell *c1 = sig_chain_prev.at(next_sig); - Cell *c2 = it.second; + Cell *c2 = cell; if (c1->type != c2->type) goto start_cell; if (c1->parameters != c2->parameters) goto start_cell; - - continue; } + continue; + start_cell: - chain_start_cells.insert(it.second); + chain_start_cells.insert(cell); } } @@ -197,6 +201,7 @@ struct MuxpackWorker sig_chain_next.clear(); sig_chain_prev.clear(); chain_start_cells.clear(); + candidate_cells.clear(); } MuxpackWorker(Module *module) : -- cgit v1.2.3 From ccdf989025e57da7dfd5ab609676ebe3cfb2c2d6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 13:51:22 -0700 Subject: Support cascading $pmux.A with $mux.A and $mux.B --- passes/opt/muxpack.cc | 42 +++++++++++++++++++++++++----------------- tests/various/muxpack.v | 25 +++++++++++++++++++++++++ tests/various/muxpack.ys | 15 +++++++++++++++ 3 files changed, 65 insertions(+), 17 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index ae4b67db2..f9e5c8f09 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -51,10 +51,12 @@ struct MuxpackWorker for (auto cell : module->cells()) { - if (cell->type.in("$mux") && !cell->get_bool_attribute("\\keep")) + if (cell->type.in("$mux", "$pmux") && !cell->get_bool_attribute("\\keep")) { SigSpec a_sig = sigmap(cell->getPort("\\A")); - SigSpec b_sig = sigmap(cell->getPort("\\B")); + SigSpec b_sig; + if (cell->type == "$mux") + b_sig = sigmap(cell->getPort("\\B")); SigSpec y_sig = sigmap(cell->getPort("\\Y")); if (sig_chain_next.count(a_sig)) @@ -65,12 +67,14 @@ struct MuxpackWorker candidate_cells.insert(cell); } - if (sig_chain_next.count(b_sig)) - for (auto b_bit : b_sig.bits()) - sigbit_with_non_chain_users.insert(b_bit); - else { - sig_chain_next[b_sig] = cell; - candidate_cells.insert(cell); + if (!b_sig.empty()) { + if (sig_chain_next.count(b_sig)) + for (auto b_bit : b_sig.bits()) + sigbit_with_non_chain_users.insert(b_bit); + else { + sig_chain_next[b_sig] = cell; + candidate_cells.insert(cell); + } } sig_chain_prev[y_sig] = cell; @@ -88,10 +92,16 @@ struct MuxpackWorker { for (auto cell : candidate_cells) { + log_debug("Considering %s (%s)\n", log_id(cell), log_id(cell->type)); + SigSpec next_sig = cell->getPort("\\A"); if (sig_chain_prev.count(next_sig) == 0) { - next_sig = cell->getPort("\\B"); - if (sig_chain_prev.count(next_sig) == 0) + if (cell->type == "$mux") { + next_sig = cell->getPort("\\B"); + if (sig_chain_prev.count(next_sig) == 0) + goto start_cell; + } + else goto start_cell; } @@ -103,10 +113,7 @@ struct MuxpackWorker Cell *c1 = sig_chain_prev.at(next_sig); Cell *c2 = cell; - if (c1->type != c2->type) - goto start_cell; - - if (c1->parameters != c2->parameters) + if (c1->getParam("\\WIDTH") != c2->getParam("\\WIDTH")) goto start_cell; } @@ -220,15 +227,16 @@ struct MuxpackWorker }; struct MuxpackPass : public Pass { - MuxpackPass() : Pass("muxpack", "$mux cell cascades to $pmux") { } + MuxpackPass() : Pass("muxpack", "$mux/$pmux cascades to $pmux") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" muxpack [selection]\n"); log("\n"); - log("This pass converts cascaded chains of $mux cells (e.g. those created by if-else\n"); - log("constructs) into $pmux cells.\n"); + log("This pass converts cascaded chains of $pmux cells (e.g. those create from case\n"); + log("constructs) and $mux cells (e.g. those created by if-else constructs) into \n"); + log("into $pmux cells.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index e847fef27..fe0150532 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -85,3 +85,28 @@ always @* begin if (s == 0) o <= i[2*W+:W]; end endmodule + +module mux_case_unbal_7_7#(parameter N=7, parameter W=7) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + case (s) + 0: o <= i[0*W+:W]; + default: + case (s) + 1: o <= i[1*W+:W]; + 2: o <= i[2*W+:W]; + default: + case (s) + 3: o <= i[3*W+:W]; + 4: o <= i[4*W+:W]; + 5: o <= i[5*W+:W]; + default: + case (s) + 6: o <= i[6*W+:W]; + default: o <= i[7*W+:W]; + endcase + endcase + endcase + endcase +end +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index 178860b88..4dcb9ed89 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -118,3 +118,18 @@ design -import gold -as gold design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_case_unbal_7_7 +prep +design -save gold +muxpack +opt +stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter -- cgit v1.2.3 From 0a66720f6f67b087fe6342d01d45944506240942 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 14:01:42 -0700 Subject: Fix warnings --- tests/various/muxpack.v | 4 ++-- tests/various/muxpack.ys | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index fe0150532..7c189fff8 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -74,7 +74,7 @@ always @* else o <= {W{1'bx}}; endmodule -module mux_if_unbal_5_3_nonexcl #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +module mux_if_unbal_5_3_nonexcl #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); always @* begin o <= {W{1'bx}}; if (s == 0) o <= i[0*W+:W]; @@ -86,7 +86,7 @@ always @* begin end endmodule -module mux_case_unbal_7_7#(parameter N=7, parameter W=7) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +module mux_case_unbal_8_7#(parameter N=8, parameter W=7) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); always @* begin o <= {W{1'bx}}; case (s) diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index 4dcb9ed89..0c5b82818 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -120,7 +120,7 @@ miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter design -load read -hierarchy -top mux_case_unbal_7_7 +hierarchy -top mux_case_unbal_8_7 prep design -save gold muxpack -- cgit v1.2.3 From 5c277c6325b78bfe18cf294b63ea69ff272e69c5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Jun 2019 14:21:34 -0700 Subject: Fix and test for balanced case --- passes/opt/muxpack.cc | 24 ++++++++++++++---------- tests/various/muxpack.v | 26 ++++++++++++++++++++++++++ tests/various/muxpack.ys | 15 +++++++++++++++ 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index f9e5c8f09..8c4db4e4d 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -94,23 +94,27 @@ struct MuxpackWorker { log_debug("Considering %s (%s)\n", log_id(cell), log_id(cell->type)); - SigSpec next_sig = cell->getPort("\\A"); - if (sig_chain_prev.count(next_sig) == 0) { - if (cell->type == "$mux") { - next_sig = cell->getPort("\\B"); - if (sig_chain_prev.count(next_sig) == 0) - goto start_cell; - } - else + SigSpec a_sig = cell->getPort("\\A"); + if (cell->type == "$mux") { + SigSpec b_sig = cell->getPort("\\B"); + if (sig_chain_prev.count(a_sig) + sig_chain_prev.count(b_sig) != 1) + goto start_cell; + + if (!sig_chain_prev.count(a_sig)) + a_sig = b_sig; + } + else if (cell->type == "$pmux") { + if (!sig_chain_prev.count(a_sig)) goto start_cell; } + else log_abort(); { - for (auto bit : next_sig.bits()) + for (auto bit : a_sig.bits()) if (sigbit_with_non_chain_users.count(bit)) goto start_cell; - Cell *c1 = sig_chain_prev.at(next_sig); + Cell *c1 = sig_chain_prev.at(a_sig); Cell *c2 = cell; if (c1->getParam("\\WIDTH") != c2->getParam("\\WIDTH")) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index 7c189fff8..f1bd5ea8e 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -110,3 +110,29 @@ always @* begin endcase end endmodule + +module mux_if_bal_8_2 #(parameter N=8, parameter W=2) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* + if (s[0] == 1'b0) + if (s[1] == 1'b0) + if (s[2] == 1'b0) + o <= i[0*W+:W]; + else + o <= i[1*W+:W]; + else + if (s[2] == 1'b0) + o <= i[2*W+:W]; + else + o <= i[3*W+:W]; + else + if (s[1] == 1'b0) + if (s[2] == 1'b0) + o <= i[4*W+:W]; + else + o <= i[5*W+:W]; + else + if (s[2] == 1'b0) + o <= i[6*W+:W]; + else + o <= i[7*W+:W]; +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index 0c5b82818..9ea743b9f 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -133,3 +133,18 @@ design -import gold -as gold design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_bal_8_2 +prep +design -save gold +muxpack +opt +stat +select -assert-count 7 t:$mux +select -assert-count 0 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter -- cgit v1.2.3 From 0f6e914ef63d06ae77b54d246b61118c19647f26 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Jun 2019 08:34:58 -0700 Subject: Another muxpack test --- tests/various/muxpack.v | 17 +++++++++++++++++ tests/various/muxpack.ys | 15 +++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index f1bd5ea8e..41dfed396 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -136,3 +136,20 @@ always @* else o <= i[7*W+:W]; endmodule + +module mux_if_bal_5_1 #(parameter N=5, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* + if (s[0] == 1'b0) + if (s[1] == 1'b0) + if (s[2] == 1'b0) + o <= i[0*W+:W]; + else + o <= i[1*W+:W]; + else + if (s[2] == 1'b0) + o <= i[2*W+:W]; + else + o <= i[3*W+:W]; + else + o <= i[4*W+:W]; +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index 9ea743b9f..dd3c143d8 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -148,3 +148,18 @@ design -import gold -as gold design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top mux_if_bal_5_1 +prep +design -save gold +muxpack +opt +stat +select -assert-count 2 t:$mux +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter -- cgit v1.2.3 From 5ab59cd59ee90abc4b6991486854dbe4c3f4d0a4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Jun 2019 11:36:19 -0700 Subject: Resolve @cliffordwolf comment on sigmap --- passes/opt/muxpack.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index 8c4db4e4d..b060389e3 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -94,9 +94,9 @@ struct MuxpackWorker { log_debug("Considering %s (%s)\n", log_id(cell), log_id(cell->type)); - SigSpec a_sig = cell->getPort("\\A"); + SigSpec a_sig = sigmap(cell->getPort("\\A")); if (cell->type == "$mux") { - SigSpec b_sig = cell->getPort("\\B"); + SigSpec b_sig = sigmap(cell->getPort("\\B")); if (sig_chain_prev.count(a_sig) + sig_chain_prev.count(b_sig) != 1) goto start_cell; -- cgit v1.2.3 From 887df8914c64220b9f306b7d21f199fa247224fd Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Jun 2019 11:37:52 -0700 Subject: Resolve @cliffordwolf comment on redundant check --- passes/opt/muxpack.cc | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index b060389e3..15a646e2e 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -109,17 +109,9 @@ struct MuxpackWorker } else log_abort(); - { - for (auto bit : a_sig.bits()) - if (sigbit_with_non_chain_users.count(bit)) - goto start_cell; - - Cell *c1 = sig_chain_prev.at(a_sig); - Cell *c2 = cell; - - if (c1->getParam("\\WIDTH") != c2->getParam("\\WIDTH")) + for (auto bit : a_sig.bits()) + if (sigbit_with_non_chain_users.count(bit)) goto start_cell; - } continue; -- cgit v1.2.3 From e263bc249b905195120fbc074c6f80d03fb21cf8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Jun 2019 11:54:29 -0700 Subject: Add nonexclusive test from @cliffordwolf --- tests/various/muxpack.v | 13 +++++++++++++ tests/various/muxpack.ys | 15 +++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index 41dfed396..f3c25db8d 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -153,3 +153,16 @@ always @* else o <= i[4*W+:W]; endmodule + +module cliffordwolf_nonexclusive_select ( + input wire x, y, z, + input wire a, b, c, d, + output reg o +); + always @* begin + o = a; + if (x) o = b; + if (y) o = c; + if (z) o = d; + end +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index dd3c143d8..7c3fe5070 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -163,3 +163,18 @@ design -import gold -as gold design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top cliffordwolf_nonexclusive_select +prep +design -save gold +muxpack +opt +stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter -- cgit v1.2.3 From 1da12c5071a738504d22e68d66cab7c5c5afb07e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Jun 2019 12:12:11 -0700 Subject: Add @cliffordwolf freduce testcase --- tests/various/muxpack.v | 13 +++++++++++++ tests/various/muxpack.ys | 17 +++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index f3c25db8d..d45ce4045 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -166,3 +166,16 @@ module cliffordwolf_nonexclusive_select ( if (z) o = d; end endmodule + +module cliffordwolf_freduce ( + input wire [1:0] s, + input wire a, b, c, d, + output reg [3:0] o +); + always @* begin + o = {4{a}}; + if (s == 0) o = {3{b}}; + if (s == 1) o = {2{c}}; + if (s == 2) o = d; + end +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index 7c3fe5070..afdacdf30 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -178,3 +178,20 @@ design -import gold -as gold design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top cliffordwolf_freduce +prep +design -save gold +proc; opt; freduce; opt +write_verilog -noexpr -norename +muxpack +opt +stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter -- cgit v1.2.3 From 9b408838f191bb0390b6edff55770cab8e8ca15d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Jun 2019 14:18:17 -0700 Subject: Add ExclusiveDatabase to check exclusive $eq/$logic_not cell results --- passes/opt/muxpack.cc | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index 15a646e2e..0cf9e0e30 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -24,6 +24,58 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +struct ExclusiveDatabase +{ + Module *module; + const SigMap &sigmap; + + dict sig_cmp_prev; + dict> sig_exclusive; + + ExclusiveDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap) + { + SigSpec a_port, b_port, y_port; + for (auto cell : module->cells()) { + if (cell->type == "$eq") { + a_port = sigmap(cell->getPort("\\A")); + b_port = sigmap(cell->getPort("\\B")); + if (!b_port.is_fully_const()) { + if (!a_port.is_fully_const()) + continue; + std::swap(a_port, b_port); + } + y_port = sigmap(cell->getPort("\\Y")); + } + else if (cell->type == "$logic_not") { + a_port = sigmap(cell->getPort("\\A")); + b_port = Const(RTLIL::S0, GetSize(a_port)); + y_port = sigmap(cell->getPort("\\Y")); + } + else continue; + + auto r = sig_exclusive[a_port].insert(b_port.as_const()); + if (!r.second) + continue; + sig_cmp_prev[y_port] = a_port; + } + } + + bool query(const SigSpec& sig1, const SigSpec& sig2) const + { + auto it = sig_cmp_prev.find(sig1); + if (it == sig_cmp_prev.end()) + return false; + + auto jt = sig_cmp_prev.find(sig2); + if (jt == sig_cmp_prev.end()) + return false; + + log("query = %s %s\n", log_signal(it->second), log_signal(jt->second)); + return it->second == jt->second; + } +}; + + struct MuxpackWorker { Module *module; @@ -39,6 +91,8 @@ struct MuxpackWorker pool chain_start_cells; pool candidate_cells; + ExclusiveDatabase excl_db; + void make_sig_chain_next_prev() { for (auto wire : module->wires()) @@ -90,6 +144,7 @@ struct MuxpackWorker void find_chain_start_cells() { + Cell* first_cell = nullptr; for (auto cell : candidate_cells) { log_debug("Considering %s (%s)\n", log_id(cell), log_id(cell->type)); @@ -102,6 +157,13 @@ struct MuxpackWorker if (!sig_chain_prev.count(a_sig)) a_sig = b_sig; + + if (first_cell) { + SigSpec s_sig = sigmap(cell->getPort("\\S")); + SigSpec prev_s_sig = sigmap(first_cell->getPort("\\S")); + if (!excl_db.query(prev_s_sig, s_sig)) + goto start_cell; + } } else if (cell->type == "$pmux") { if (!sig_chain_prev.count(a_sig)) @@ -117,6 +179,7 @@ struct MuxpackWorker start_cell: chain_start_cells.insert(cell); + first_cell = cell; } } @@ -208,7 +271,7 @@ struct MuxpackWorker } MuxpackWorker(Module *module) : - module(module), sigmap(module), mux_count(0), pmux_count(0) + module(module), sigmap(module), mux_count(0), pmux_count(0), excl_db(module, sigmap) { make_sig_chain_next_prev(); find_chain_start_cells(); -- cgit v1.2.3 From ba52d9b4716b287b0a469597b748f9859e897329 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Jun 2019 15:34:16 -0700 Subject: Extend ExclusiveDatabase to query SigSpec-s (for $pmux) --- passes/opt/muxpack.cc | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index 0cf9e0e30..4b02df394 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -29,7 +29,7 @@ struct ExclusiveDatabase Module *module; const SigMap &sigmap; - dict sig_cmp_prev; + dict sig_cmp_prev; dict> sig_exclusive; ExclusiveDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap) @@ -62,16 +62,23 @@ struct ExclusiveDatabase bool query(const SigSpec& sig1, const SigSpec& sig2) const { - auto it = sig_cmp_prev.find(sig1); - if (it == sig_cmp_prev.end()) - return false; - - auto jt = sig_cmp_prev.find(sig2); - if (jt == sig_cmp_prev.end()) - return false; + // FIXME: O(N) + for (auto bit1 : sig1.bits()) { + auto it = sig_cmp_prev.find(bit1); + if (it == sig_cmp_prev.end()) + return false; + + for (auto bit2 : sig2.bits()) { + auto jt = sig_cmp_prev.find(bit2); + if (jt == sig_cmp_prev.end()) + return false; + + if (it->second != jt->second) + return false; + } + } - log("query = %s %s\n", log_signal(it->second), log_signal(jt->second)); - return it->second == jt->second; + return true; } }; @@ -144,7 +151,6 @@ struct MuxpackWorker void find_chain_start_cells() { - Cell* first_cell = nullptr; for (auto cell : candidate_cells) { log_debug("Considering %s (%s)\n", log_id(cell), log_id(cell->type)); @@ -157,13 +163,6 @@ struct MuxpackWorker if (!sig_chain_prev.count(a_sig)) a_sig = b_sig; - - if (first_cell) { - SigSpec s_sig = sigmap(cell->getPort("\\S")); - SigSpec prev_s_sig = sigmap(first_cell->getPort("\\S")); - if (!excl_db.query(prev_s_sig, s_sig)) - goto start_cell; - } } else if (cell->type == "$pmux") { if (!sig_chain_prev.count(a_sig)) @@ -175,11 +174,19 @@ struct MuxpackWorker if (sigbit_with_non_chain_users.count(bit)) goto start_cell; + { + Cell *prev_cell = sig_chain_prev.at(a_sig); + log_assert(prev_cell); + SigSpec s_sig = sigmap(cell->getPort("\\S")); + SigSpec next_s_sig = sigmap(prev_cell->getPort("\\S")); + if (!excl_db.query(s_sig, next_s_sig)) + goto start_cell; + } + continue; start_cell: chain_start_cells.insert(cell); - first_cell = cell; } } @@ -243,6 +250,7 @@ struct MuxpackWorker s_sig.append(cursor_cell->getPort("\\S")); } else { + log_assert(cursor_cell->type == "$mux"); b_sig.append(cursor_cell->getPort("\\A")); s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort("\\S"))); } -- cgit v1.2.3 From b959bf79c004fdf81ccc397d5aa774b67a09d6da Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Jun 2019 15:35:15 -0700 Subject: Add nonexcl case test, comment out two others --- tests/various/muxpack.v | 18 ++++++++++++++ tests/various/muxpack.ys | 61 +++++++++++++++++++++++++++++++----------------- 2 files changed, 57 insertions(+), 22 deletions(-) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index d45ce4045..3a1086dbf 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -179,3 +179,21 @@ module cliffordwolf_freduce ( if (s == 2) o = d; end endmodule + +module case_nonexclusive_select ( + input wire [1:0] x, y, + input wire a, b, c, d, e, + output reg o +); + always @* begin + case (x) + 0, 2: o = b; + 1: o = c; + default: begin + o = a; + if (y == 0) o = d; + if (y == 1) o = e; + end + endcase + end +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index afdacdf30..579dad8d3 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -1,5 +1,6 @@ read_verilog muxpack.v design -save read + hierarchy -top mux_if_unbal_4_1 prep design -save gold @@ -29,20 +30,21 @@ design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter -design -load read -hierarchy -top mux_if_unbal_5_3_invert -prep -design -save gold -muxpack -opt -stat -select -assert-count 0 t:$mux -select -assert-count 1 t:$pmux -design -stash gate -design -import gold -as gold -design -import gate -as gate -miter -equiv -flatten -make_assert -make_outputs gold gate miter -sat -verify -prove-asserts -show-ports miter +# TODO: Currently ExclusiveDatabase only analyses $eq cells +#design -load read +#hierarchy -top mux_if_unbal_5_3_invert +#prep +#design -save gold +#muxpack +#opt +#stat +#select -assert-count 0 t:$mux +#select -assert-count 1 t:$pmux +#design -stash gate +#design -import gold -as gold +#design -import gate -as gate +#miter -equiv -flatten -make_assert -make_outputs gold gate miter +#sat -verify -prove-asserts -show-ports miter design -load read hierarchy -top mux_if_unbal_5_3_width_mismatch @@ -156,8 +158,8 @@ design -save gold muxpack opt stat -select -assert-count 2 t:$mux -select -assert-count 1 t:$pmux +select -assert-count 4 t:$mux +select -assert-count 0 t:$pmux design -stash gate design -import gold -as gold design -import gate -as gate @@ -171,25 +173,40 @@ design -save gold muxpack opt stat -select -assert-count 0 t:$mux -select -assert-count 1 t:$pmux +select -assert-count 3 t:$mux +select -assert-count 0 t:$pmux design -stash gate design -import gold -as gold design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter +#design -load read +#hierarchy -top cliffordwolf_freduce +#prep +#design -save gold +#proc; opt; freduce; opt +#show +#muxpack +#opt +#stat +#select -assert-count 0 t:$mux +#select -assert-count 1 t:$pmux +#design -stash gate +#design -import gold -as gold +#design -import gate -as gate +#miter -equiv -flatten -make_assert -make_outputs gold gate miter +#sat -verify -prove-asserts -show-ports miter + design -load read -hierarchy -top cliffordwolf_freduce +hierarchy -top case_nonexclusive_select prep design -save gold -proc; opt; freduce; opt -write_verilog -noexpr -norename muxpack opt stat select -assert-count 0 t:$mux -select -assert-count 1 t:$pmux +select -assert-count 2 t:$pmux design -stash gate design -import gold -as gold design -import gate -as gate -- cgit v1.2.3 From f705f6a0b5d19d38cf41ba5f782847de54110463 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Jun 2019 15:39:12 -0700 Subject: Comment O(N) -> O(N^2) --- passes/opt/muxpack.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index 4b02df394..f01d5474d 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -62,7 +62,7 @@ struct ExclusiveDatabase bool query(const SigSpec& sig1, const SigSpec& sig2) const { - // FIXME: O(N) + // FIXME: O(N^2) for (auto bit1 : sig1.bits()) { auto it = sig_cmp_prev.find(bit1); if (it == sig_cmp_prev.end()) -- cgit v1.2.3 From 5b999ae68decef5646ef0ccac53463f22fe18d8f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 10 Jun 2019 10:32:19 -0700 Subject: Elaborate muxpack doc --- passes/opt/muxpack.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index f01d5474d..b6f3313bf 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -302,8 +302,12 @@ struct MuxpackPass : public Pass { log(" muxpack [selection]\n"); log("\n"); log("This pass converts cascaded chains of $pmux cells (e.g. those create from case\n"); - log("constructs) and $mux cells (e.g. those created by if-else constructs) into \n"); - log("into $pmux cells.\n"); + log("constructs) and $mux cells (e.g. those created by if-else constructs) into\n"); + log("$pmux cells.\n"); + log("\n"); + log("This optimisation is conservative --- it will only pack $mux or $pmux cells with\n"); + log("other such cells if it can be certain that the select lines are mutually\n"); + log("exclusive.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE -- cgit v1.2.3 From c314ca3c51579a9c5305cbf9a69635e123db0423 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 10 Jun 2019 16:16:26 -0700 Subject: Add test --- tests/various/shregmap.v | 22 ++++++++++++++++++++++ tests/various/shregmap.ys | 31 +++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 tests/various/shregmap.v create mode 100644 tests/various/shregmap.ys diff --git a/tests/various/shregmap.v b/tests/various/shregmap.v new file mode 100644 index 000000000..56e05c2c0 --- /dev/null +++ b/tests/various/shregmap.v @@ -0,0 +1,22 @@ +module shregmap_test(input i, clk, output [1:0] q); +reg head = 1'b0; +reg [3:0] shift1 = 4'b0000; +reg [3:0] shift2 = 4'b0000; + +always @(posedge clk) begin + head <= i; + shift1 <= {shift1[2:0], head}; + shift2 <= {shift2[2:0], head}; +end + +assign q = {shift2[3], shift1[3]}; +endmodule + +module $__SHREG_DFF_P_(input C, D, output Q); +parameter DEPTH = 1; +parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}}; +reg [DEPTH-1:0] r = INIT; +always @(posedge C) + r <= { r[DEPTH-2:0], D }; +assign Q = r[DEPTH-1]; +endmodule diff --git a/tests/various/shregmap.ys b/tests/various/shregmap.ys new file mode 100644 index 000000000..ca7f47015 --- /dev/null +++ b/tests/various/shregmap.ys @@ -0,0 +1,31 @@ +read_verilog shregmap.v +design -copy-to model $__SHREG_DFF_P_ +hierarchy -top shregmap_test +prep +design -save gold + +techmap +shregmap -init + +opt + +stat +# show -width +select -assert-count 1 t:$_DFF_P_ +select -assert-count 2 t:$__SHREG_DFF_P_ + +design -stash gate + +design -import gold -as gold +design -import gate -as gate +design -copy-from model -as $__SHREG_DFF_P_ \$__SHREG_DFF_P_ +prep + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports -seq 5 miter + +design -load gold +stat + +design -load gate +stat -- cgit v1.2.3 From f19aa8d989df9e443d26cf6beaf389c2f3d6a424 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 10 Jun 2019 16:16:40 -0700 Subject: If d_bit already in sigbit_chain_next, create extra wire --- passes/techmap/shregmap.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 21dfe9619..46f6a79fb 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -293,10 +293,13 @@ struct ShregmapWorker if (opts.init || sigbit_init.count(q_bit) == 0) { - if (sigbit_chain_next.count(d_bit)) { + auto r = sigbit_chain_next.insert(std::make_pair(d_bit, cell)); + if (!r.second) { sigbit_with_non_chain_users.insert(d_bit); - } else - sigbit_chain_next[d_bit] = cell; + Wire *wire = module->addWire(NEW_ID); + module->connect(wire, d_bit); + sigbit_chain_next.insert(std::make_pair(wire, cell)); + } sigbit_chain_prev[q_bit] = cell; continue; -- cgit v1.2.3 From 2f427acc9ed23c77e89386f4fbf53ac580bf0f0b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 11 Jun 2019 15:48:20 -0700 Subject: Try way that doesn't involve creating a new wire --- passes/techmap/shregmap.cc | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 46f6a79fb..3adcd8968 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -294,12 +294,8 @@ struct ShregmapWorker if (opts.init || sigbit_init.count(q_bit) == 0) { auto r = sigbit_chain_next.insert(std::make_pair(d_bit, cell)); - if (!r.second) { + if (!r.second) sigbit_with_non_chain_users.insert(d_bit); - Wire *wire = module->addWire(NEW_ID); - module->connect(wire, d_bit); - sigbit_chain_next.insert(std::make_pair(wire, cell)); - } sigbit_chain_prev[q_bit] = cell; continue; @@ -319,14 +315,14 @@ struct ShregmapWorker { for (auto it : sigbit_chain_next) { + Cell *c1, *c2 = it.second; + if (opts.tech == nullptr && sigbit_with_non_chain_users.count(it.first)) goto start_cell; - if (sigbit_chain_prev.count(it.first) != 0) + c1 = sigbit_chain_prev.at(it.first, nullptr); + if (c1 != nullptr) { - Cell *c1 = sigbit_chain_prev.at(it.first); - Cell *c2 = it.second; - if (c1->type != c2->type) goto start_cell; @@ -336,6 +332,15 @@ struct ShregmapWorker IdString d_port = opts.ffcells.at(c1->type).first; IdString q_port = opts.ffcells.at(c1->type).second; + // If the previous cell's D has other non chain users, + // then it is possible that this previous cell could + // be a start of the chain + SigBit d_bit = sigmap(c1->getPort(d_port).as_bit()); + if (sigbit_with_non_chain_users.count(d_bit)) { + c2 = c1; + goto start_cell; + } + auto c1_conn = c1->connections(); auto c2_conn = c1->connections(); @@ -352,7 +357,7 @@ struct ShregmapWorker } start_cell: - chain_start_cells.insert(it.second); + chain_start_cells.insert(c2); } } -- cgit v1.2.3 From 6cdea93724b69695938ca021fd3841f644b478bf Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 11 Jun 2019 16:05:42 -0700 Subject: Revert "Try way that doesn't involve creating a new wire" This reverts commit 2f427acc9ed23c77e89386f4fbf53ac580bf0f0b. --- passes/techmap/shregmap.cc | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 3adcd8968..46f6a79fb 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -294,8 +294,12 @@ struct ShregmapWorker if (opts.init || sigbit_init.count(q_bit) == 0) { auto r = sigbit_chain_next.insert(std::make_pair(d_bit, cell)); - if (!r.second) + if (!r.second) { sigbit_with_non_chain_users.insert(d_bit); + Wire *wire = module->addWire(NEW_ID); + module->connect(wire, d_bit); + sigbit_chain_next.insert(std::make_pair(wire, cell)); + } sigbit_chain_prev[q_bit] = cell; continue; @@ -315,14 +319,14 @@ struct ShregmapWorker { for (auto it : sigbit_chain_next) { - Cell *c1, *c2 = it.second; - if (opts.tech == nullptr && sigbit_with_non_chain_users.count(it.first)) goto start_cell; - c1 = sigbit_chain_prev.at(it.first, nullptr); - if (c1 != nullptr) + if (sigbit_chain_prev.count(it.first) != 0) { + Cell *c1 = sigbit_chain_prev.at(it.first); + Cell *c2 = it.second; + if (c1->type != c2->type) goto start_cell; @@ -332,15 +336,6 @@ struct ShregmapWorker IdString d_port = opts.ffcells.at(c1->type).first; IdString q_port = opts.ffcells.at(c1->type).second; - // If the previous cell's D has other non chain users, - // then it is possible that this previous cell could - // be a start of the chain - SigBit d_bit = sigmap(c1->getPort(d_port).as_bit()); - if (sigbit_with_non_chain_users.count(d_bit)) { - c2 = c1; - goto start_cell; - } - auto c1_conn = c1->connections(); auto c2_conn = c1->connections(); @@ -357,7 +352,7 @@ struct ShregmapWorker } start_cell: - chain_start_cells.insert(c2); + chain_start_cells.insert(it.second); } } -- cgit v1.2.3 From 45c2a5f87694a83e0cf96477ede02567a93b32a8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 12 Jun 2019 08:34:06 -0700 Subject: Add shregmap -tech xilinx test --- tests/various/shregmap.v | 28 +++++++++++++++++++++++++++- tests/various/shregmap.ys | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/tests/various/shregmap.v b/tests/various/shregmap.v index 56e05c2c0..604c2c976 100644 --- a/tests/various/shregmap.v +++ b/tests/various/shregmap.v @@ -1,4 +1,4 @@ -module shregmap_test(input i, clk, output [1:0] q); +module shregmap_static_test(input i, clk, output [1:0] q); reg head = 1'b0; reg [3:0] shift1 = 4'b0000; reg [3:0] shift2 = 4'b0000; @@ -20,3 +20,29 @@ always @(posedge C) r <= { r[DEPTH-2:0], D }; assign Q = r[DEPTH-1]; endmodule + +module shregmap_variable_test(input i, clk, input [1:0] l1, l2, output [1:0] q); +reg head = 1'b0; +reg [3:0] shift1 = 4'b0000; +reg [3:0] shift2 = 4'b0000; + +always @(posedge clk) begin + head <= i; + shift1 <= {shift1[2:0], head}; + shift2 <= {shift2[2:0], head}; +end + +assign q = {shift2[l2], shift1[l1]}; +endmodule + +module $__XILINX_SHREG_(input C, D, input [1:0] L, output Q); +parameter CLKPOL = 1; +parameter ENPOL = 1; +parameter DEPTH = 1; +parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}}; +reg [DEPTH-1:0] r = INIT; +wire clk = C ^ CLKPOL; +always @(posedge C) + r <= { r[DEPTH-2:0], D }; +assign Q = r[L]; +endmodule diff --git a/tests/various/shregmap.ys b/tests/various/shregmap.ys index ca7f47015..d644a88aa 100644 --- a/tests/various/shregmap.ys +++ b/tests/various/shregmap.ys @@ -1,6 +1,8 @@ read_verilog shregmap.v +design -save read + design -copy-to model $__SHREG_DFF_P_ -hierarchy -top shregmap_test +hierarchy -top shregmap_static_test prep design -save gold @@ -29,3 +31,36 @@ stat design -load gate stat + +########## + +design -load read +design -copy-to model $__XILINX_SHREG_ +hierarchy -top shregmap_variable_test +prep +design -save gold + +simplemap t:$dff t:$dffe +shregmap -tech xilinx + +stat +# show -width +write_verilog -noexpr -norename +select -assert-count 1 t:$_DFF_P_ +select -assert-count 2 t:$__XILINX_SHREG_ + +design -stash gate + +design -import gold -as gold +design -import gate -as gate +design -copy-from model -as $__XILINX_SHREG_ \$__XILINX_SHREG_ +prep + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports -seq 5 miter + +design -load gold +stat + +design -load gate +stat -- cgit v1.2.3 From a8c85d1b4b810e2ea31770e37e1414b7f1a15283 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 20 Jun 2019 14:27:57 +0200 Subject: Update some .gitignore files Signed-off-by: Clifford Wolf --- tests/aiger/.gitignore | 3 +-- tests/various/.gitignore | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/aiger/.gitignore b/tests/aiger/.gitignore index 073f46157..9a26bb8f4 100644 --- a/tests/aiger/.gitignore +++ b/tests/aiger/.gitignore @@ -1,2 +1 @@ -*.log -*.out +/*_ref.v diff --git a/tests/various/.gitignore b/tests/various/.gitignore index 397b4a762..7b3e8c68e 100644 --- a/tests/various/.gitignore +++ b/tests/various/.gitignore @@ -1 +1,2 @@ -*.log +/*.log +/*.out -- cgit v1.2.3 From 06eb87bcb795b44dc0c9e42c0b2a495c05d23881 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 20 Jun 2019 15:23:55 +0200 Subject: Improve shregmap help message, fixes #1113 Signed-off-by: Clifford Wolf --- passes/techmap/shregmap.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 21dfe9619..18e60fa6b 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -605,9 +605,11 @@ struct ShregmapPass : public Pass { log("\n"); log(" -tech greenpak4\n"); log(" map to greenpak4 shift registers.\n"); + log(" this option also implies -clkpol pos -zinit\n"); log("\n"); log(" -tech xilinx\n"); log(" map to xilinx dynamic-length shift registers.\n"); + log(" this option also implies -params -init\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE -- cgit v1.2.3 From 477e566e8d203ec7754c90fc845d7f3f759f2974 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 20 Jun 2019 15:34:52 +0200 Subject: Fix typo, fixes #1095 Signed-off-by: Clifford Wolf --- passes/cmds/write_file.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/cmds/write_file.cc b/passes/cmds/write_file.cc index 9613b462b..64a762d7c 100644 --- a/passes/cmds/write_file.cc +++ b/passes/cmds/write_file.cc @@ -62,7 +62,7 @@ struct WriteFileFrontend : public Frontend { if (argidx < args.size() && args[argidx].rfind("-", 0) != 0) output_filename = args[argidx++]; else - log_cmd_error("Missing putput filename.\n"); + log_cmd_error("Missing output filename.\n"); extra_args(f, filename, args, argidx); -- cgit v1.2.3 From 0221f3e1c5b427678c5679027ee47ec7c0b8321d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 20 Jun 2019 10:04:42 -0700 Subject: Fix sign extension when sign is 1'bx --- kernel/rtlil.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index a09f4a0d1..95a24c93f 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3437,7 +3437,7 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) if (width_ < width) { RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::Sx; - if (!is_signed) + if (padding != RTLIL::State::Sx && !is_signed) padding = RTLIL::State::S0; while (width_ < width) append(padding); -- cgit v1.2.3 From b98276fa61be7a1c589d6dac661d31982cfab16b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 20 Jun 2019 10:10:43 -0700 Subject: Add test --- tests/various/signext.ys | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/various/signext.ys diff --git a/tests/various/signext.ys b/tests/various/signext.ys new file mode 100644 index 000000000..26dab13a6 --- /dev/null +++ b/tests/various/signext.ys @@ -0,0 +1,24 @@ + +read_verilog -formal < Date: Thu, 20 Jun 2019 10:15:04 -0700 Subject: Remove leftover comment --- tests/various/signext.ys | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/various/signext.ys b/tests/various/signext.ys index 26dab13a6..ae44a0e06 100644 --- a/tests/various/signext.ys +++ b/tests/various/signext.ys @@ -5,9 +5,6 @@ assign o = 1'bx; endmodule EOT - -## Example usage for "pmuxtree" and "muxcover" - proc ## Equivalence checking -- cgit v1.2.3 From 8767ec3fbdc0986854107de9cf178953ef09f1db Mon Sep 17 00:00:00 2001 From: Ben Widawsky Date: Thu, 20 Jun 2019 10:27:59 -0700 Subject: Add a few more filename rewrites This now allows a full pipeline to work, something such as: yosys -p "synth_ecp5 -json ~/work/fpga/prjtrellis/examples/ecp5_evn/blinky.v" Otherwise, you will get something along the lines of: ERROR: Can't open output file `~/work/fpga/prjtrellis/examples/ecp5_evn/blinky.v' for writing: No such file or directory Signed-off-by: Ben Widawsky --- kernel/register.cc | 1 + passes/sat/sat.cc | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/kernel/register.cc b/kernel/register.cc index 71eb6b187..26da96b95 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -545,6 +545,7 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vectoropen(filename.c_str(), std::ofstream::trunc); yosys_output_files.insert(filename); diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index cbba738f0..e4654d835 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -659,6 +659,7 @@ struct SatHelper void dump_model_to_vcd(std::string vcd_file_name) { + rewrite_filename(vcd_file_name); FILE *f = fopen(vcd_file_name.c_str(), "w"); if (!f) log_cmd_error("Can't open output file `%s' for writing: %s\n", vcd_file_name.c_str(), strerror(errno)); @@ -761,6 +762,7 @@ struct SatHelper void dump_model_to_json(std::string json_file_name) { + rewrite_filename(json_file_name); FILE *f = fopen(json_file_name.c_str(), "w"); if (!f) log_cmd_error("Can't open output file `%s' for writing: %s\n", json_file_name.c_str(), strerror(errno)); @@ -1505,6 +1507,7 @@ struct SatPass : public Pass { { if (!cnf_file_name.empty()) { + rewrite_filename(cnf_file_name); FILE *f = fopen(cnf_file_name.c_str(), "w"); if (!f) log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno)); @@ -1608,6 +1611,7 @@ struct SatPass : public Pass { if (!cnf_file_name.empty()) { + rewrite_filename(cnf_file_name); FILE *f = fopen(cnf_file_name.c_str(), "w"); if (!f) log_cmd_error("Can't open output file `%s' for writing: %s\n", cnf_file_name.c_str(), strerror(errno)); -- cgit v1.2.3 From e33cbb0dde72b292002a9fc7158857b19803effe Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 20 Jun 2019 12:40:05 -0700 Subject: Revert "Fix sign extension when sign is 1'bx" This reverts commit 0221f3e1c5b427678c5679027ee47ec7c0b8321d. --- kernel/rtlil.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 95a24c93f..a09f4a0d1 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3437,7 +3437,7 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) if (width_ < width) { RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::Sx; - if (padding != RTLIL::State::Sx && !is_signed) + if (!is_signed) padding = RTLIL::State::S0; while (width_ < width) append(padding); -- cgit v1.2.3 From 20119ee50e0cefbcd89275101c8710febd5afd32 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 20 Jun 2019 12:43:39 -0700 Subject: Maintain "is_unsized" state of constants --- frontends/verilog/const2ast.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 57d366dbf..3a3634d34 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -204,7 +204,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn { std::vector data; bool is_signed = false; - bool is_unsized = false; + bool is_unsized = len_in_bits < 0; if (*(endptr+1) == 's') { is_signed = true; endptr++; @@ -213,25 +213,25 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn { case 'b': case 'B': - my_strtobin(data, endptr+2, len_in_bits, 2, case_type, false); + my_strtobin(data, endptr+2, len_in_bits, 2, case_type, is_unsized); break; case 'o': case 'O': - my_strtobin(data, endptr+2, len_in_bits, 8, case_type, false); + my_strtobin(data, endptr+2, len_in_bits, 8, case_type, is_unsized); break; case 'd': case 'D': - my_strtobin(data, endptr+2, len_in_bits, 10, case_type, false); + my_strtobin(data, endptr+2, len_in_bits, 10, case_type, is_unsized); break; case 'h': case 'H': - my_strtobin(data, endptr+2, len_in_bits, 16, case_type, false); + my_strtobin(data, endptr+2, len_in_bits, 16, case_type, is_unsized); break; default: char next_char = char(tolower(*(endptr+1))); if (next_char == '0' || next_char == '1' || next_char == 'x' || next_char == 'z') { - my_strtobin(data, endptr+1, 1, 2, case_type, true); is_unsized = true; + my_strtobin(data, endptr+1, 1, 2, case_type, is_unsized); } else { return NULL; } -- cgit v1.2.3 From d0bbf9e4d4a508179b55a0cc7793d984f3318f7c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 20 Jun 2019 12:43:59 -0700 Subject: Extend sign extension tests --- tests/various/signext.ys | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tests/various/signext.ys b/tests/various/signext.ys index ae44a0e06..0c8d671e7 100644 --- a/tests/various/signext.ys +++ b/tests/various/signext.ys @@ -1,7 +1,13 @@ read_verilog -formal < Date: Thu, 20 Jun 2019 12:45:40 -0700 Subject: Add CHANGELOG entry --- CHANGELOG | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 4c38f6e6e..496a521be 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,7 @@ Yosys 0.8 .. Yosys 0.8-dev - Added "read_aiger" frontend - Extended "muxcover -mux{4,8,16}=" - "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx" + - Fixed sign extension of unsized constants with 'bx and 'bz MSB Yosys 0.7 .. Yosys 0.8 @@ -32,7 +33,7 @@ Yosys 0.7 .. Yosys 0.8 - Added "write_verilog -decimal" - Added "scc -set_attr" - Added "verilog_defines" command - - Remeber defines from one read_verilog to next + - Remember defines from one read_verilog to next - Added support for hierarchical defparam - Added FIRRTL back-end - Improved ABC default scripts -- cgit v1.2.3 From c27ab609faeeb3ae9372ea4cf85e5ac6ba029646 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 20 Jun 2019 16:04:12 -0700 Subject: Make genvar a signed type --- frontends/verilog/verilog_parser.y | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 4895d0302..d89b2dc88 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -517,6 +517,7 @@ wire_type_token: TOK_GENVAR { astbuf3->type = AST_GENVAR; astbuf3->is_reg = true; + astbuf3->is_signed = true; astbuf3->range_left = 31; astbuf3->range_right = 0; } | -- cgit v1.2.3 From c20adc52638b0f3ba3b1c39e5286ae92e901005d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 20 Jun 2019 16:07:22 -0700 Subject: Add test --- tests/simple/generate.v | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/simple/generate.v b/tests/simple/generate.v index 3c55682cb..0e353ad9b 100644 --- a/tests/simple/generate.v +++ b/tests/simple/generate.v @@ -148,3 +148,14 @@ generate endgenerate assign out = steps[WIDTH].outer[0].val; endmodule + +// ------------------------------------------ + +module gen_test6(output [3:0] o); +generate + genvar i; + for (i = 3; i >= 0; i = i-1) begin + assign o[i] = 1'b0; + end +endgenerate +endmodule -- cgit v1.2.3 From 9c61fb0e0c23f00bacf316f7efd358c66f2f6397 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 20 Jun 2019 16:57:54 -0700 Subject: Add comment as per @cliffordwolf --- passes/techmap/shregmap.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 46f6a79fb..8881ba468 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -295,7 +295,18 @@ struct ShregmapWorker { auto r = sigbit_chain_next.insert(std::make_pair(d_bit, cell)); if (!r.second) { + // Insertion not successful means that d_bit is already + // connected to another register, thus mark it as a + // non chain user ... sigbit_with_non_chain_users.insert(d_bit); + // ... and clone d_bit into another wire, and use that + // wire as a different key in the d_bit-to-cell dictionary + // so that it can be identified as another chain + // (omitting this common flop) + // Link: https://github.com/YosysHQ/yosys/pull/1085 + // NB: This relies on us not updating sigmap with this + // alias otherwise it would think they are the same + // wire Wire *wire = module->addWire(NEW_ID); module->connect(wire, d_bit); sigbit_chain_next.insert(std::make_pair(wire, cell)); -- cgit v1.2.3 From e63324f5ef2ebb14fa0cc88544f577406f95b223 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 20 Jun 2019 17:03:05 -0700 Subject: Actually, there might not be any harm in updating sigmap... --- passes/techmap/shregmap.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 8881ba468..d9d1e257b 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -304,11 +304,9 @@ struct ShregmapWorker // so that it can be identified as another chain // (omitting this common flop) // Link: https://github.com/YosysHQ/yosys/pull/1085 - // NB: This relies on us not updating sigmap with this - // alias otherwise it would think they are the same - // wire Wire *wire = module->addWire(NEW_ID); module->connect(wire, d_bit); + sigmap.add(wire, d_bit); sigbit_chain_next.insert(std::make_pair(wire, cell)); } -- cgit v1.2.3 From 40188457d1af9bd4d905c83b29a3bf696b8666f0 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 19 Jun 2019 13:15:54 +0200 Subject: Add support for partial matches to muxcover, fixes #1091 Signed-off-by: Clifford Wolf --- passes/techmap/muxcover.cc | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index 8e44be148..78272b0c4 100644 --- a/passes/techmap/muxcover.cc +++ b/passes/techmap/muxcover.cc @@ -57,6 +57,7 @@ struct MuxcoverWorker bool use_mux8; bool use_mux16; bool nodecode; + bool nopartial; int cost_mux2; int cost_mux4; @@ -69,6 +70,7 @@ struct MuxcoverWorker use_mux8 = false; use_mux16 = false; nodecode = false; + nopartial = false; cost_mux2 = COST_MUX2; cost_mux4 = COST_MUX4; cost_mux8 = COST_MUX8; @@ -133,13 +135,20 @@ struct MuxcoverWorker log(" Finished treeification: Found %d trees.\n", GetSize(tree_list)); } - bool follow_muxtree(SigBit &ret_bit, tree_t &tree, SigBit bit, const char *path) + bool follow_muxtree(SigBit &ret_bit, tree_t &tree, SigBit bit, const char *path, bool first_layer = true) { if (*path) { - if (tree.muxes.count(bit) == 0) - return false; + if (tree.muxes.count(bit) == 0) { + if (first_layer || nopartial) + return false; + if (path[0] == 'S') + ret_bit = State::Sx; + else + ret_bit = bit; + return true; + } char port_name[3] = {'\\', *path, 0}; - return follow_muxtree(ret_bit, tree, sigmap(tree.muxes.at(bit)->getPort(port_name)), path+1); + return follow_muxtree(ret_bit, tree, sigmap(tree.muxes.at(bit)->getPort(port_name)), path+1, false); } else { ret_bit = bit; return true; @@ -148,7 +157,7 @@ struct MuxcoverWorker int prepare_decode_mux(SigBit &A, SigBit B, SigBit sel, SigBit bit) { - if (A == B) + if (A == B || sel == State::Sx) return 0; tuple key(A, B, sel); @@ -166,6 +175,9 @@ struct MuxcoverWorker if (std::get<2>(entry)) return 0; + if (A == State::Sx || B == State::Sx) + return 0; + return cost_mux2 / GetSize(std::get<1>(entry)); } @@ -183,9 +195,15 @@ struct MuxcoverWorker implement_decode_mux(std::get<0>(key)); implement_decode_mux(std::get<1>(key)); - module->addMuxGate(NEW_ID, std::get<0>(key), std::get<1>(key), std::get<2>(key), ctrl_bit); + if (std::get<0>(key) == State::Sx) { + module->addBufGate(NEW_ID, std::get<1>(key), ctrl_bit); + } else if (std::get<1>(key) == State::Sx) { + module->addBufGate(NEW_ID, std::get<0>(key), ctrl_bit); + } else { + module->addMuxGate(NEW_ID, std::get<0>(key), std::get<1>(key), std::get<2>(key), ctrl_bit); + decode_mux_counter++; + } std::get<2>(entry) = true; - decode_mux_counter++; } int find_best_cover(tree_t &tree, SigBit bit) @@ -598,6 +616,7 @@ struct MuxcoverPass : public Pass { bool use_mux8 = false; bool use_mux16 = false; bool nodecode = false; + bool nopartial = false; int cost_mux4 = COST_MUX4; int cost_mux8 = COST_MUX8; int cost_mux16 = COST_MUX16; @@ -634,6 +653,10 @@ struct MuxcoverPass : public Pass { nodecode = true; continue; } + if (arg == "-nopartial") { + nopartial = true; + continue; + } break; } extra_args(args, argidx, design); @@ -654,6 +677,7 @@ struct MuxcoverPass : public Pass { worker.cost_mux8 = cost_mux8; worker.cost_mux16 = cost_mux16; worker.nodecode = nodecode; + worker.nopartial = nopartial; worker.run(); } } -- cgit v1.2.3 From 75375a3fbce622b5c4cb6f4464379bb0e66a1107 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 19 Jun 2019 10:07:34 -0700 Subject: Add test --- tests/various/muxcover.ys | 137 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/tests/various/muxcover.ys b/tests/various/muxcover.ys index 7ac460f13..d55a35b8c 100644 --- a/tests/various/muxcover.ys +++ b/tests/various/muxcover.ys @@ -13,7 +13,7 @@ read_verilog -formal < Date: Wed, 19 Jun 2019 10:15:41 -0700 Subject: Missing a `clean` and `opt_expr -mux_bool` in test --- tests/various/muxcover.ys | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/various/muxcover.ys b/tests/various/muxcover.ys index d55a35b8c..8ef619b46 100644 --- a/tests/various/muxcover.ys +++ b/tests/various/muxcover.ys @@ -115,6 +115,8 @@ design -save gold techmap muxcover -mux4=150 -mux8=200 +clean +opt_expr -mux_bool select -assert-count 0 t:$_MUX_ select -assert-count 0 t:$_MUX4_ select -assert-count 1 t:$_MUX8_ @@ -171,6 +173,8 @@ design -save gold techmap muxcover -mux4=150 -mux8=200 -mux16=250 +clean +opt_expr -mux_bool select -assert-count 0 t:$_MUX_ select -assert-count 0 t:$_MUX4_ select -assert-count 0 t:$_MUX8_ -- cgit v1.2.3 From 891ea6512e5254803b36a2a22121bc2733ac8b9e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 20 Jun 2019 11:30:27 +0200 Subject: Improvements in muxcover - Slightly under-estimate cost of decoder muxes - Prefer larger muxes at tree root at same cost - Don't double-count input cost for partial muxes - Add debug log output --- passes/techmap/muxcover.cc | 93 +++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index 78272b0c4..e952b04b6 100644 --- a/passes/techmap/muxcover.cc +++ b/passes/techmap/muxcover.cc @@ -178,7 +178,7 @@ struct MuxcoverWorker if (A == State::Sx || B == State::Sx) return 0; - return cost_mux2 / GetSize(std::get<1>(entry)); + return std::max((cost_mux2 / GetSize(std::get<1>(entry))) - 1, 1); } void implement_decode_mux(SigBit ctrl_bit) @@ -206,6 +206,23 @@ struct MuxcoverWorker std::get<2>(entry) = true; } + void find_best_covers(tree_t &tree, const vector &bits) + { + for (auto bit : bits) + find_best_cover(tree, bit); + } + + int sum_best_covers(tree_t &tree, const vector &bits) + { + int sum = 0; + for (auto bit : pool(bits.begin(), bits.end())) { + int cost = tree.newmuxes.at(bit).cost; + log_debug(" Best cost for %s: %d\n", log_signal(bit), cost); + sum += cost; + } + return sum; + } + int find_best_cover(tree_t &tree, SigBit bit) { if (tree.newmuxes.count(bit)) { @@ -236,9 +253,13 @@ struct MuxcoverWorker mux.inputs.push_back(B); mux.selects.push_back(S1); + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux2 at %s: %d\n", log_signal(bit), mux.cost); + mux.cost += cost_mux2; - mux.cost += find_best_cover(tree, A); - mux.cost += find_best_cover(tree, B); + mux.cost += sum_best_covers(tree, mux.inputs); + + log_debug(" Cost of mux2 at %s: %d\n", log_signal(bit), mux.cost); best_mux = mux; } @@ -274,13 +295,15 @@ struct MuxcoverWorker mux.selects.push_back(S1); mux.selects.push_back(T1); + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux4 at %s: %d\n", log_signal(bit), mux.cost); + mux.cost += cost_mux4; - mux.cost += find_best_cover(tree, A); - mux.cost += find_best_cover(tree, B); - mux.cost += find_best_cover(tree, C); - mux.cost += find_best_cover(tree, D); + mux.cost += sum_best_covers(tree, mux.inputs); - if (best_mux.cost > mux.cost) + log_debug(" Cost of mux4 at %s: %d\n", log_signal(bit), mux.cost); + + if (best_mux.cost >= mux.cost) best_mux = mux; } } @@ -337,17 +360,15 @@ struct MuxcoverWorker mux.selects.push_back(T1); mux.selects.push_back(U1); + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux8 at %s: %d\n", log_signal(bit), mux.cost); + mux.cost += cost_mux8; - mux.cost += find_best_cover(tree, A); - mux.cost += find_best_cover(tree, B); - mux.cost += find_best_cover(tree, C); - mux.cost += find_best_cover(tree, D); - mux.cost += find_best_cover(tree, E); - mux.cost += find_best_cover(tree, F); - mux.cost += find_best_cover(tree, G); - mux.cost += find_best_cover(tree, H); - - if (best_mux.cost > mux.cost) + mux.cost += sum_best_covers(tree, mux.inputs); + + log_debug(" Cost of mux8 at %s: %d\n", log_signal(bit), mux.cost); + + if (best_mux.cost >= mux.cost) best_mux = mux; } } @@ -441,25 +462,15 @@ struct MuxcoverWorker mux.selects.push_back(U1); mux.selects.push_back(V1); + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux16 at %s: %d\n", log_signal(bit), mux.cost); + mux.cost += cost_mux16; - mux.cost += find_best_cover(tree, A); - mux.cost += find_best_cover(tree, B); - mux.cost += find_best_cover(tree, C); - mux.cost += find_best_cover(tree, D); - mux.cost += find_best_cover(tree, E); - mux.cost += find_best_cover(tree, F); - mux.cost += find_best_cover(tree, G); - mux.cost += find_best_cover(tree, H); - mux.cost += find_best_cover(tree, I); - mux.cost += find_best_cover(tree, J); - mux.cost += find_best_cover(tree, K); - mux.cost += find_best_cover(tree, L); - mux.cost += find_best_cover(tree, M); - mux.cost += find_best_cover(tree, N); - mux.cost += find_best_cover(tree, O); - mux.cost += find_best_cover(tree, P); - - if (best_mux.cost > mux.cost) + mux.cost += sum_best_covers(tree, mux.inputs); + + log_debug(" Cost of mux16 at %s: %d\n", log_signal(bit), mux.cost); + + if (best_mux.cost >= mux.cost) best_mux = mux; } } @@ -555,6 +566,7 @@ struct MuxcoverWorker void treecover(tree_t &tree) { int count_muxes_by_type[4] = {0, 0, 0, 0}; + log_debug(" Searching for best cover for tree at %s.\n", log_signal(tree.root)); find_best_cover(tree, tree.root); implement_best_cover(tree, tree.root, count_muxes_by_type); log(" Replaced tree at %s: %d MUX2, %d MUX4, %d MUX8, %d MUX16\n", log_signal(tree.root), @@ -571,12 +583,13 @@ struct MuxcoverWorker log(" Covering trees:\n"); - // pre-fill cache of decoder muxes - if (!nodecode) + if (!nodecode) { + log_debug(" Populating cache of decoder muxes.\n"); for (auto &tree : tree_list) { find_best_cover(tree, tree.root); tree.newmuxes.clear(); } + } for (auto &tree : tree_list) treecover(tree); @@ -607,6 +620,10 @@ struct MuxcoverPass : public Pass { log(" substitutions, but guarantees that the resulting circuit is not\n"); log(" less efficient than the original circuit.\n"); log("\n"); + log(" -nopartial\n"); + log(" Do not consider mappings that use $_MUX_ to select from less\n"); + log(" than different signals.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { -- cgit v1.2.3 From c4ea6fff65d6b2e69a31649af7e10b129c6ae0f5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 20 Jun 2019 21:56:02 -0700 Subject: Fix gcc invalidation behaviour for write_aiger --- backends/aiger/aiger.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backends/aiger/aiger.cc b/backends/aiger/aiger.cc index d685c5638..6863b40fa 100644 --- a/backends/aiger/aiger.cc +++ b/backends/aiger/aiger.cc @@ -89,7 +89,8 @@ struct AigerWriter aig_map[bit] = mkgate(a0, a1); } else if (alias_map.count(bit)) { - aig_map[bit] = bit2aig(alias_map.at(bit)); + int a = bit2aig(alias_map.at(bit)); + aig_map[bit] = a; } if (bit == State::Sx || bit == State::Sz) -- cgit v1.2.3 From 9286b6f013db06b473d009dfabb5e7c1526387b1 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 21 Jun 2019 10:02:10 +0200 Subject: Add "muxcover -freedecode" Signed-off-by: Clifford Wolf --- passes/techmap/muxcover.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index e952b04b6..7fa89bbe3 100644 --- a/passes/techmap/muxcover.cc +++ b/passes/techmap/muxcover.cc @@ -57,6 +57,7 @@ struct MuxcoverWorker bool use_mux8; bool use_mux16; bool nodecode; + bool freedecode; bool nopartial; int cost_mux2; @@ -70,6 +71,7 @@ struct MuxcoverWorker use_mux8 = false; use_mux16 = false; nodecode = false; + freedecode = false; nopartial = false; cost_mux2 = COST_MUX2; cost_mux4 = COST_MUX4; @@ -178,6 +180,9 @@ struct MuxcoverWorker if (A == State::Sx || B == State::Sx) return 0; + if (freedecode) + return 0; + return std::max((cost_mux2 / GetSize(std::get<1>(entry))) - 1, 1); } @@ -620,6 +625,9 @@ struct MuxcoverPass : public Pass { log(" substitutions, but guarantees that the resulting circuit is not\n"); log(" less efficient than the original circuit.\n"); log("\n"); + log(" -freedecode\n"); + log(" Do not count cost for generated decode logic\n"); + log("\n"); log(" -nopartial\n"); log(" Do not consider mappings that use $_MUX_ to select from less\n"); log(" than different signals.\n"); @@ -633,6 +641,7 @@ struct MuxcoverPass : public Pass { bool use_mux8 = false; bool use_mux16 = false; bool nodecode = false; + bool freedecode = false; bool nopartial = false; int cost_mux4 = COST_MUX4; int cost_mux8 = COST_MUX8; @@ -670,6 +679,10 @@ struct MuxcoverPass : public Pass { nodecode = true; continue; } + if (arg == "-freedecode") { + freedecode = true; + continue; + } if (arg == "-nopartial") { nopartial = true; continue; @@ -694,6 +707,7 @@ struct MuxcoverPass : public Pass { worker.cost_mux8 = cost_mux8; worker.cost_mux16 = cost_mux16; worker.nodecode = nodecode; + worker.freedecode = freedecode; worker.nopartial = nopartial; worker.run(); } -- cgit v1.2.3 From a0d3d2bb41cd11b5b33620e16cb67c6568b16847 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 21 Jun 2019 09:44:13 +0100 Subject: ecp5: Improve mapping of $alu when BI is used Signed-off-by: David Shah --- techlibs/ecp5/arith_map.v | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/techlibs/ecp5/arith_map.v b/techlibs/ecp5/arith_map.v index eb7947601..17bde0497 100644 --- a/techlibs/ecp5/arith_map.v +++ b/techlibs/ecp5/arith_map.v @@ -50,20 +50,21 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO); wire [Y_WIDTH2-1:0] AA = A_buf; wire [Y_WIDTH2-1:0] BB = BI ? ~B_buf : B_buf; + wire [Y_WIDTH2-1:0] BX = B_buf; wire [Y_WIDTH2-1:0] C = {CO, CI}; wire [Y_WIDTH2-1:0] FCO, Y1; genvar i; generate for (i = 0; i < Y_WIDTH2; i = i + 2) begin:slice CCU2C #( - .INIT0(16'b0110011010101010), - .INIT1(16'b0110011010101010), + .INIT0(16'b1001011010101010), + .INIT1(16'b1001011010101010), .INJECT1_0("NO"), .INJECT1_1("NO") ) ccu2c_i ( .CIN(C[i]), - .A0(AA[i]), .B0(BB[i]), .C0(1'b0), .D0(1'b1), - .A1(AA[i+1]), .B1(BB[i+1]), .C1(1'b0), .D1(1'b1), + .A0(AA[i]), .B0(BX[i]), .C0(BI), .D0(1'b1), + .A1(AA[i+1]), .B1(BX[i+1]), .C1(BI), .D1(1'b1), .S0(Y[i]), .S1(Y1[i]), .COUT(FCO[i]) ); -- cgit v1.2.3 From f15def325c7f2621cf8299ca61b5eeb3ddd3667e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 21 Jun 2019 15:22:17 +0200 Subject: Added JSON upto and offset Signed-off-by: Clifford Wolf --- backends/json/json.cc | 4 ++++ frontends/json/jsonparse.cc | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/backends/json/json.cc b/backends/json/json.cc index 5022d5da1..1781a28cd 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -189,6 +189,10 @@ struct JsonWriter f << stringf(" %s: {\n", get_name(w->name).c_str()); f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0"); f << stringf(" \"bits\": %s,\n", get_bits(w).c_str()); + if (w->start_offset) + f << stringf(" \"offset\": %d,\n", w->start_offset); + if (w->upto) + f << stringf(" \"upto\": 1,\n"); f << stringf(" \"attributes\": {"); write_parameters(w->attributes); f << stringf("\n }\n"); diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc index 82361ea9b..344b8c2c8 100644 --- a/frontends/json/jsonparse.cc +++ b/frontends/json/jsonparse.cc @@ -372,6 +372,18 @@ void json_import(Design *design, string &modname, JsonNode *node) if (wire == nullptr) wire = module->addWire(net_name, GetSize(bits_node->data_array)); + if (net_node->data_dict.count("upto") != 0) { + JsonNode *val = net_node->data_dict.at("offset"); + if (val->type == 'N') + wire->upto = val->data_number != 0; + } + + if (net_node->data_dict.count("offset") != 0) { + JsonNode *val = net_node->data_dict.at("offset"); + if (val->type == 'N') + wire->start_offset = val->data_number; + } + for (int i = 0; i < GetSize(bits_node->data_array); i++) { JsonNode *bitval_node = bits_node->data_array.at(i); -- cgit v1.2.3 From 3775763f51ffb16ecf750833d30192a493ca2ade Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 21 Jun 2019 19:09:34 +0200 Subject: Fix typo --- frontends/json/jsonparse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc index 344b8c2c8..b74d41dd2 100644 --- a/frontends/json/jsonparse.cc +++ b/frontends/json/jsonparse.cc @@ -373,7 +373,7 @@ void json_import(Design *design, string &modname, JsonNode *node) wire = module->addWire(net_name, GetSize(bits_node->data_array)); if (net_node->data_dict.count("upto") != 0) { - JsonNode *val = net_node->data_dict.at("offset"); + JsonNode *val = net_node->data_dict.at("upto"); if (val->type == 'N') wire->upto = val->data_number != 0; } -- cgit v1.2.3 From ec979475e7f6bce65a4b6768cc3488a3ab02826d Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 21 Jun 2019 19:24:41 +0200 Subject: Replace "muxcover -freedecode" with "muxcover -dmux=cost" Signed-off-by: Clifford Wolf --- passes/techmap/muxcover.cc | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index 7fa89bbe3..b0722134e 100644 --- a/passes/techmap/muxcover.cc +++ b/passes/techmap/muxcover.cc @@ -23,6 +23,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +#define COST_DMUX 90 #define COST_MUX2 100 #define COST_MUX4 220 #define COST_MUX8 460 @@ -57,9 +58,9 @@ struct MuxcoverWorker bool use_mux8; bool use_mux16; bool nodecode; - bool freedecode; bool nopartial; + int cost_dmux; int cost_mux2; int cost_mux4; int cost_mux8; @@ -71,8 +72,8 @@ struct MuxcoverWorker use_mux8 = false; use_mux16 = false; nodecode = false; - freedecode = false; nopartial = false; + cost_dmux = COST_DMUX; cost_mux2 = COST_MUX2; cost_mux4 = COST_MUX4; cost_mux8 = COST_MUX8; @@ -180,10 +181,7 @@ struct MuxcoverWorker if (A == State::Sx || B == State::Sx) return 0; - if (freedecode) - return 0; - - return std::max((cost_mux2 / GetSize(std::get<1>(entry))) - 1, 1); + return cost_dmux / GetSize(std::get<1>(entry)); } void implement_decode_mux(SigBit ctrl_bit) @@ -620,14 +618,15 @@ struct MuxcoverPass : public Pass { log(" Default costs: $_MUX_ = %d, $_MUX4_ = %d,\n", COST_MUX2, COST_MUX4); log(" $_MUX8_ = %d, $_MUX16_ = %d\n", COST_MUX8, COST_MUX16); log("\n"); + log(" -dmux=cost\n"); + log(" Use the specified cost for $_MUX_ cells used in decoders.\n"); + log(" Default cost: %d\n", COST_DMUX); + log("\n"); log(" -nodecode\n"); log(" Do not insert decoder logic. This reduces the number of possible\n"); log(" substitutions, but guarantees that the resulting circuit is not\n"); log(" less efficient than the original circuit.\n"); log("\n"); - log(" -freedecode\n"); - log(" Do not count cost for generated decode logic\n"); - log("\n"); log(" -nopartial\n"); log(" Do not consider mappings that use $_MUX_ to select from less\n"); log(" than different signals.\n"); @@ -641,8 +640,8 @@ struct MuxcoverPass : public Pass { bool use_mux8 = false; bool use_mux16 = false; bool nodecode = false; - bool freedecode = false; bool nopartial = false; + int cost_dmux = COST_DMUX; int cost_mux4 = COST_MUX4; int cost_mux8 = COST_MUX8; int cost_mux16 = COST_MUX16; @@ -675,12 +674,12 @@ struct MuxcoverPass : public Pass { } continue; } - if (arg == "-nodecode") { - nodecode = true; + if (arg.size() >= 6 && arg.substr(0,6) == "-dmux=") { + cost_dmux = atoi(arg.substr(6).c_str()); continue; } - if (arg == "-freedecode") { - freedecode = true; + if (arg == "-nodecode") { + nodecode = true; continue; } if (arg == "-nopartial") { @@ -703,11 +702,11 @@ struct MuxcoverPass : public Pass { worker.use_mux4 = use_mux4; worker.use_mux8 = use_mux8; worker.use_mux16 = use_mux16; + worker.cost_dmux = cost_dmux; worker.cost_mux4 = cost_mux4; worker.cost_mux8 = cost_mux8; worker.cost_mux16 = cost_mux16; worker.nodecode = nodecode; - worker.freedecode = freedecode; worker.nopartial = nopartial; worker.run(); } -- cgit v1.2.3 From 50e72210772f3a1c34f5fe80b19c65f6d304b71a Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 21 Jun 2019 19:47:25 +0200 Subject: Add upto and offset to JSON ports --- backends/json/json.cc | 4 ++++ frontends/json/jsonparse.cc | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/backends/json/json.cc b/backends/json/json.cc index 1781a28cd..eb59e5eba 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -127,6 +127,10 @@ struct JsonWriter f << stringf(" %s: {\n", get_name(n).c_str()); f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output"); f << stringf(" \"bits\": %s\n", get_bits(w).c_str()); + if (w->start_offset) + f << stringf(" \"offset\": %d,\n", w->start_offset); + if (w->upto) + f << stringf(" \"upto\": 1,\n"); f << stringf(" }"); first = false; } diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc index b74d41dd2..f5ae8eb72 100644 --- a/frontends/json/jsonparse.cc +++ b/frontends/json/jsonparse.cc @@ -292,6 +292,18 @@ void json_import(Design *design, string &modname, JsonNode *node) if (port_wire == nullptr) port_wire = module->addWire(port_name, GetSize(port_bits_node->data_array)); + if (port_node->data_dict.count("upto") != 0) { + JsonNode *val = port_node->data_dict.at("upto"); + if (val->type == 'N') + port_wire->upto = val->data_number != 0; + } + + if (port_node->data_dict.count("offset") != 0) { + JsonNode *val = port_node->data_dict.at("offset"); + if (val->type == 'N') + port_wire->start_offset = val->data_number; + } + if (port_direction_node->data_string == "input") { port_wire->port_input = true; } else -- cgit v1.2.3 From fde90f7f8eb4150c7f806ab4baa53057a56bc160 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 21 Jun 2019 20:01:40 +0200 Subject: Fix json formatting --- backends/json/json.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/json/json.cc b/backends/json/json.cc index eb59e5eba..dda4dfedd 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -126,11 +126,11 @@ struct JsonWriter f << stringf("%s\n", first ? "" : ","); f << stringf(" %s: {\n", get_name(n).c_str()); f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output"); - f << stringf(" \"bits\": %s\n", get_bits(w).c_str()); if (w->start_offset) f << stringf(" \"offset\": %d,\n", w->start_offset); if (w->upto) f << stringf(" \"upto\": 1,\n"); + f << stringf(" \"bits\": %s\n", get_bits(w).c_str()); f << stringf(" }"); first = false; } -- cgit v1.2.3 From 641b86d25f5baa898bf5fca3d1a8f2fd4f5954e6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 11:45:31 -0700 Subject: Fix up ExclusiveDatabase with @cliffordwolf's help --- passes/opt/muxpack.cc | 69 +++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index b6f3313bf..ae4f7ba9c 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -29,54 +29,53 @@ struct ExclusiveDatabase Module *module; const SigMap &sigmap; - dict sig_cmp_prev; - dict> sig_exclusive; + dict> sig_cmp_prev; ExclusiveDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap) { - SigSpec a_port, b_port, y_port; + SigSpec const_sig, nonconst_sig, y_port; for (auto cell : module->cells()) { if (cell->type == "$eq") { - a_port = sigmap(cell->getPort("\\A")); - b_port = sigmap(cell->getPort("\\B")); - if (!b_port.is_fully_const()) { - if (!a_port.is_fully_const()) + nonconst_sig = sigmap(cell->getPort("\\A")); + const_sig = sigmap(cell->getPort("\\B")); + if (!const_sig.is_fully_const()) { + if (!nonconst_sig.is_fully_const()) continue; - std::swap(a_port, b_port); + std::swap(nonconst_sig, const_sig); } y_port = sigmap(cell->getPort("\\Y")); } else if (cell->type == "$logic_not") { - a_port = sigmap(cell->getPort("\\A")); - b_port = Const(RTLIL::S0, GetSize(a_port)); + nonconst_sig = sigmap(cell->getPort("\\A")); + const_sig = Const(RTLIL::S0, GetSize(nonconst_sig)); y_port = sigmap(cell->getPort("\\Y")); } else continue; - auto r = sig_exclusive[a_port].insert(b_port.as_const()); - if (!r.second) - continue; - sig_cmp_prev[y_port] = a_port; - } - } + log_assert(!nonconst_sig.empty()); + log_assert(!const_sig.empty()); + sig_cmp_prev[y_port] = std::make_pair(nonconst_sig,const_sig.as_const()); + } + } - bool query(const SigSpec& sig1, const SigSpec& sig2) const - { - // FIXME: O(N^2) - for (auto bit1 : sig1.bits()) { - auto it = sig_cmp_prev.find(bit1); - if (it == sig_cmp_prev.end()) - return false; - - for (auto bit2 : sig2.bits()) { - auto jt = sig_cmp_prev.find(bit2); - if (jt == sig_cmp_prev.end()) - return false; - - if (it->second != jt->second) - return false; - } - } + bool query(const SigSpec &sig) const + { + SigSpec nonconst_sig; + pool const_values; + + for (auto bit : sig.bits()) { + auto it = sig_cmp_prev.find(bit); + if (it == sig_cmp_prev.end()) + return false; + + if (nonconst_sig.empty()) + nonconst_sig = it->second.first; + else if (nonconst_sig != it->second.first) + return false; + + if (!const_values.insert(it->second.second).second) + return false; + } return true; } @@ -178,8 +177,8 @@ struct MuxpackWorker Cell *prev_cell = sig_chain_prev.at(a_sig); log_assert(prev_cell); SigSpec s_sig = sigmap(cell->getPort("\\S")); - SigSpec next_s_sig = sigmap(prev_cell->getPort("\\S")); - if (!excl_db.query(s_sig, next_s_sig)) + s_sig.append(sigmap(prev_cell->getPort("\\S"))); + if (!excl_db.query(s_sig)) goto start_cell; } -- cgit v1.2.3 From 6ec816098153c733b97410ebc6aef166db8affd8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 11:45:53 -0700 Subject: Add more muxpack tests, with overlapping entries --- tests/various/muxpack.v | 55 +++++++++++++++++++++++++++++++++++++++++++++++- tests/various/muxpack.ys | 30 ++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index 3a1086dbf..7a658d754 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -187,7 +187,9 @@ module case_nonexclusive_select ( ); always @* begin case (x) - 0, 2: o = b; + //0, 2: o = b; + 0: o = b; + 2: o = b; 1: o = c; default: begin o = a; @@ -197,3 +199,54 @@ module case_nonexclusive_select ( endcase end endmodule + +module case_nonoverlap ( + input wire [2:0] x, + input wire a, b, c, d, e, f, g, + output reg o +); + always @* begin + case (x) + //0, 2: o = b; // Creates $reduce_or + //0: o = b; 2: o = b; // Creates $reduce_or + 0: o = b; + 2: o = f; + 1: o = c; + default: + case (x) + //3, 4: o = d; // Creates $reduce_or + //3: o = d; 4: o = d; // Creates $reduce_or + 3: o = d; + 4: o = g; + 5: o = e; + default: o = 1'b0; + endcase + endcase + end +endmodule + +module case_overlap ( + input wire [2:0] x, + input wire a, b, c, d, e, f, g, + output reg o +); + always @* begin + case (x) + //0, 2: o = b; // Creates $reduce_or + //0: o = b; 2: o = b; // Creates $reduce_or + 0: o = b; + 2: o = f; + 1: o = c; + default: + case (x) + //3, 4: o = d; // Creates $reduce_or + //3: o = d; 4: o = d; // Creates $reduce_or + 2: o = 1'b1; // Overlaps with previous $pmux + 3: o = d; + 4: o = g; + 5: o = e; + default: o = 1'b0; + endcase + endcase + end +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index 579dad8d3..ef8a6dab9 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -212,3 +212,33 @@ design -import gold -as gold design -import gate -as gate miter -equiv -flatten -make_assert -make_outputs gold gate miter sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top case_nonoverlap +prep +design -save gold +muxpack +opt +stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top case_overlap +prep +design -save gold +muxpack +#opt # Do not opt otherwise $pmux's overlapping entry will get removed +stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter -- cgit v1.2.3 From d89d663c92853fcd7f9d75b392ec4133ba2f1d89 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 11:52:28 -0700 Subject: Add doc --- passes/opt/muxpack.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index ae4f7ba9c..c8b226c78 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -304,9 +304,9 @@ struct MuxpackPass : public Pass { log("constructs) and $mux cells (e.g. those created by if-else constructs) into\n"); log("$pmux cells.\n"); log("\n"); - log("This optimisation is conservative --- it will only pack $mux or $pmux cells with\n"); - log("other such cells if it can be certain that the select lines are mutually\n"); - log("exclusive.\n"); + log("This optimisation is conservative --- it will only pack $mux or $pmux cells\n"); + log("whose select lines are driven by '$eq' cells with other such cells if it can be\n"); + log("certain that their select inputs are mutually exclusive.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE -- cgit v1.2.3 From 15535112b7b4caa1da75274397c5a3ba885a7349 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 11:52:51 -0700 Subject: Fix spacing --- passes/opt/muxpack.cc | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index c8b226c78..4468e8734 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -52,30 +52,30 @@ struct ExclusiveDatabase } else continue; - log_assert(!nonconst_sig.empty()); - log_assert(!const_sig.empty()); - sig_cmp_prev[y_port] = std::make_pair(nonconst_sig,const_sig.as_const()); - } - } - - bool query(const SigSpec &sig) const - { - SigSpec nonconst_sig; - pool const_values; - - for (auto bit : sig.bits()) { - auto it = sig_cmp_prev.find(bit); - if (it == sig_cmp_prev.end()) - return false; - - if (nonconst_sig.empty()) - nonconst_sig = it->second.first; - else if (nonconst_sig != it->second.first) - return false; - - if (!const_values.insert(it->second.second).second) - return false; - } + log_assert(!nonconst_sig.empty()); + log_assert(!const_sig.empty()); + sig_cmp_prev[y_port] = std::make_pair(nonconst_sig,const_sig.as_const()); + } + } + + bool query(const SigSpec &sig) const + { + SigSpec nonconst_sig; + pool const_values; + + for (auto bit : sig.bits()) { + auto it = sig_cmp_prev.find(bit); + if (it == sig_cmp_prev.end()) + return false; + + if (nonconst_sig.empty()) + nonconst_sig = it->second.first; + else if (nonconst_sig != it->second.first) + return false; + + if (!const_values.insert(it->second.second).second) + return false; + } return true; } -- cgit v1.2.3 From ae8305ffcc0c812488163bcc35365d473ce1345d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 12:13:00 -0700 Subject: Fix testcase --- tests/various/muxpack.ys | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index ef8a6dab9..de5eec87f 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -230,13 +230,14 @@ sat -verify -prove-asserts -show-ports miter design -load read hierarchy -top case_overlap -prep +#prep # Do not prep otherwise $pmux's overlapping entry will get removed +proc design -save gold muxpack -#opt # Do not opt otherwise $pmux's overlapping entry will get removed +opt stat select -assert-count 0 t:$mux -select -assert-count 1 t:$pmux +select -assert-count 2 t:$pmux design -stash gate design -import gold -as gold design -import gate -as gate -- cgit v1.2.3 From 32f637ffdb0c0641b51227fad92bc80e284740d2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 12:31:04 -0700 Subject: Add more tests --- tests/various/muxpack.v | 47 +++++++++++++++++++++++++++-------------------- tests/various/muxpack.ys | 25 ++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v index 7a658d754..33ece1f16 100644 --- a/tests/various/muxpack.v +++ b/tests/various/muxpack.v @@ -187,7 +187,6 @@ module case_nonexclusive_select ( ); always @* begin case (x) - //0, 2: o = b; 0: o = b; 2: o = b; 1: o = c; @@ -202,22 +201,16 @@ endmodule module case_nonoverlap ( input wire [2:0] x, - input wire a, b, c, d, e, f, g, + input wire a, b, c, d, e, output reg o ); always @* begin case (x) - //0, 2: o = b; // Creates $reduce_or - //0: o = b; 2: o = b; // Creates $reduce_or - 0: o = b; - 2: o = f; + 0, 2: o = b; // Creates $reduce_or 1: o = c; default: case (x) - //3, 4: o = d; // Creates $reduce_or - //3: o = d; 4: o = d; // Creates $reduce_or - 3: o = d; - 4: o = g; + 3: o = d; 4: o = d; // Creates $reduce_or 5: o = e; default: o = 1'b0; endcase @@ -227,23 +220,37 @@ endmodule module case_overlap ( input wire [2:0] x, - input wire a, b, c, d, e, f, g, + input wire a, b, c, d, e, output reg o ); always @* begin case (x) - //0, 2: o = b; // Creates $reduce_or - //0: o = b; 2: o = b; // Creates $reduce_or - 0: o = b; - 2: o = f; + 0, 2: o = b; // Creates $reduce_or + 1: o = c; + default: + case (x) + 0: o = 1'b1; // OVERLAP! + 3, 4: o = d; // Creates $reduce_or + 5: o = e; + default: o = 1'b0; + endcase + endcase + end +endmodule + +module case_overlap2 ( + input wire [2:0] x, + input wire a, b, c, d, e, + output reg o +); + always @* begin + case (x) + 0: o = b; 2: o = b; // Creates $reduce_or 1: o = c; default: case (x) - //3, 4: o = d; // Creates $reduce_or - //3: o = d; 4: o = d; // Creates $reduce_or - 2: o = 1'b1; // Overlaps with previous $pmux - 3: o = d; - 4: o = g; + 0: o = d; 2: o = d; // Creates $reduce_or + 3: o = d; 4: o = d; // Creates $reduce_or 5: o = e; default: o = 1'b0; endcase diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys index de5eec87f..af23fcec8 100644 --- a/tests/various/muxpack.ys +++ b/tests/various/muxpack.ys @@ -215,8 +215,11 @@ sat -verify -prove-asserts -show-ports miter design -load read hierarchy -top case_nonoverlap -prep +#prep # Do not prep otherwise $pmux's overlapping entry will get removed +proc design -save gold +opt -fast -mux_undef +select -assert-count 2 t:$pmux muxpack opt stat @@ -233,6 +236,26 @@ hierarchy -top case_overlap #prep # Do not prep otherwise $pmux's overlapping entry will get removed proc design -save gold +opt -fast -mux_undef +select -assert-count 2 t:$pmux +muxpack +opt +stat +select -assert-count 0 t:$mux +select -assert-count 2 t:$pmux +design -stash gate +design -import gold -as gold +design -import gate -as gate +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load read +hierarchy -top case_overlap2 +#prep # Do not prep otherwise $pmux's overlapping entry will get removed +proc +design -save gold +opt -fast -mux_undef +select -assert-count 2 t:$pmux muxpack opt stat -- cgit v1.2.3 From 545cfbbe0dcc36f18dce6429498f4d87112879e2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 12:31:14 -0700 Subject: Cope with $reduce_or common in case --- passes/opt/muxpack.cc | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc index 4468e8734..6697d6ca1 100644 --- a/passes/opt/muxpack.cc +++ b/passes/opt/muxpack.cc @@ -29,11 +29,13 @@ struct ExclusiveDatabase Module *module; const SigMap &sigmap; - dict> sig_cmp_prev; + dict>> sig_cmp_prev; ExclusiveDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap) { - SigSpec const_sig, nonconst_sig, y_port; + SigSpec const_sig, nonconst_sig; + SigBit y_port; + pool reduce_or; for (auto cell : module->cells()) { if (cell->type == "$eq") { nonconst_sig = sigmap(cell->getPort("\\A")); @@ -50,11 +52,40 @@ struct ExclusiveDatabase const_sig = Const(RTLIL::S0, GetSize(nonconst_sig)); y_port = sigmap(cell->getPort("\\Y")); } + else if (cell->type == "$reduce_or") { + reduce_or.insert(cell); + continue; + } else continue; log_assert(!nonconst_sig.empty()); log_assert(!const_sig.empty()); - sig_cmp_prev[y_port] = std::make_pair(nonconst_sig,const_sig.as_const()); + sig_cmp_prev[y_port] = std::make_pair(nonconst_sig,std::vector{const_sig.as_const()}); + } + + for (auto cell : reduce_or) { + nonconst_sig = SigSpec(); + std::vector values; + SigSpec a_port = sigmap(cell->getPort("\\A")); + for (auto bit : a_port) { + auto it = sig_cmp_prev.find(bit); + if (it == sig_cmp_prev.end()) { + nonconst_sig = SigSpec(); + break; + } + if (nonconst_sig.empty()) + nonconst_sig = it->second.first; + else if (nonconst_sig != it->second.first) { + nonconst_sig = SigSpec(); + break; + } + for (auto value : it->second.second) + values.push_back(value); + } + if (nonconst_sig.empty()) + continue; + y_port = sigmap(cell->getPort("\\Y")); + sig_cmp_prev[y_port] = std::make_pair(nonconst_sig,std::move(values)); } } @@ -73,8 +104,9 @@ struct ExclusiveDatabase else if (nonconst_sig != it->second.first) return false; - if (!const_values.insert(it->second.second).second) - return false; + for (auto value : it->second.second) + if (!const_values.insert(value).second) + return false; } return true; -- cgit v1.2.3 From fb8fab4a29e5a3978cadf2b1bd8920b772150028 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 20:30:24 -0700 Subject: Add 'muxcover -dmux=' and '-nopartial' to CHANGELOG --- CHANGELOG | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 496a521be..128f6c6ff 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,7 +17,9 @@ Yosys 0.8 .. Yosys 0.8-dev - Added "rename -src" - Added "equiv_opt" pass - Added "read_aiger" frontend - - Extended "muxcover -mux{4,8,16}=" + - Added "muxcover -mux{4,8,16}=" + - Added "muxcover -dmux=" + - Added "muxcover -nopartial" - "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx" - Fixed sign extension of unsized constants with 'bx and 'bz MSB -- cgit v1.2.3 From efd04880dbeb2021c503c82ad962fe8c5d6802d4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 24 Jun 2019 16:16:50 -0700 Subject: Add RAM32X1D support --- techlibs/xilinx/cells_sim.v | 17 +++++++++++++++++ techlibs/xilinx/cells_xtra.sh | 4 ++-- techlibs/xilinx/cells_xtra.v | 18 ------------------ techlibs/xilinx/drams.txt | 20 ++++++++++++++++++++ techlibs/xilinx/drams_map.v | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 73 insertions(+), 20 deletions(-) diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 3a4540b83..50d588a9e 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -278,6 +278,23 @@ module FDPE_1 (output reg Q, input C, CE, D, PRE); always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; endmodule +module RAM32X1D ( + output DPO, SPO, + input D, WCLK, WE, + input A0, A1, A2, A3, A4, + input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, +); + parameter INIT = 32'h0; + parameter IS_WCLK_INVERTED = 1'b0; + wire [4:0] a = {A4, A3, A2, A1, A0}; + wire [4:0] dpra = {DPRA4, DPRA3, DPRA2, DPRA1, DPRA0}; + reg [31:0] mem = INIT; + assign SPO = mem[a]; + assign DPO = mem[dpra]; + wire clk = WCLK ^ IS_WCLK_INVERTED; + always @(posedge clk) if (WE) mem[a] <= D; +endmodule + module RAM64X1D ( output DPO, SPO, input D, WCLK, WE, diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh index 8e39b440d..83863bf0b 100644 --- a/techlibs/xilinx/cells_xtra.sh +++ b/techlibs/xilinx/cells_xtra.sh @@ -116,11 +116,11 @@ function xtract_cell_decl() xtract_cell_decl PS7 "(* keep *)" xtract_cell_decl PULLDOWN xtract_cell_decl PULLUP - xtract_cell_decl RAM128X1D + #xtract_cell_decl RAM128X1D xtract_cell_decl RAM128X1S xtract_cell_decl RAM256X1S xtract_cell_decl RAM32M - xtract_cell_decl RAM32X1D + #xtract_cell_decl RAM32X1D xtract_cell_decl RAM32X1S xtract_cell_decl RAM32X1S_1 xtract_cell_decl RAM32X2S diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v index fbcc74682..6220da703 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/cells_xtra.v @@ -3655,17 +3655,6 @@ module PULLUP (...); output O; endmodule -module RAM128X1D (...); - parameter [127:0] INIT = 128'h00000000000000000000000000000000; - parameter [0:0] IS_WCLK_INVERTED = 1'b0; - output DPO, SPO; - input [6:0] A; - input [6:0] DPRA; - input D; - input WCLK; - input WE; -endmodule - module RAM128X1S (...); parameter [127:0] INIT = 128'h00000000000000000000000000000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; @@ -3705,13 +3694,6 @@ module RAM32M (...); input WE; endmodule -module RAM32X1D (...); - parameter [31:0] INIT = 32'h00000000; - parameter [0:0] IS_WCLK_INVERTED = 1'b0; - output DPO, SPO; - input A0, A1, A2, A3, A4, D, DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, WCLK, WE; -endmodule - module RAM32X1S (...); parameter [31:0] INIT = 32'h00000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; diff --git a/techlibs/xilinx/drams.txt b/techlibs/xilinx/drams.txt index 91632bcee..2613c206c 100644 --- a/techlibs/xilinx/drams.txt +++ b/techlibs/xilinx/drams.txt @@ -1,4 +1,17 @@ +bram $__XILINX_RAM32X1D + init 1 + abits 5 + dbits 1 + groups 2 + ports 1 1 + wrmode 0 1 + enable 0 1 + transp 0 0 + clocks 0 1 + clkpol 0 2 +endbram + bram $__XILINX_RAM64X1D init 1 abits 6 @@ -25,6 +38,13 @@ bram $__XILINX_RAM128X1D clkpol 0 2 endbram +match $__XILINX_RAM32X1D + min bits 3 + min wports 1 + make_outreg + or_next_if_better +endmatch + match $__XILINX_RAM64X1D min bits 5 min wports 1 diff --git a/techlibs/xilinx/drams_map.v b/techlibs/xilinx/drams_map.v index 47476b592..77041ca86 100644 --- a/techlibs/xilinx/drams_map.v +++ b/techlibs/xilinx/drams_map.v @@ -1,4 +1,38 @@ +module \$__XILINX_RAM32X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); + parameter [31:0] INIT = 32'bx; + parameter CLKPOL2 = 1; + input CLK1; + + input [4:0] A1ADDR; + output A1DATA; + + input [4:0] B1ADDR; + input B1DATA; + input B1EN; + + RAM32X1D #( + .INIT(INIT), + .IS_WCLK_INVERTED(!CLKPOL2) + ) _TECHMAP_REPLACE_ ( + .DPRA0(A1ADDR[0]), + .DPRA1(A1ADDR[1]), + .DPRA2(A1ADDR[2]), + .DPRA3(A1ADDR[3]), + .DPRA4(A1ADDR[4]), + .DPO(A1DATA), + + .A0(B1ADDR[0]), + .A1(B1ADDR[1]), + .A2(B1ADDR[2]), + .A3(B1ADDR[3]), + .A4(B1ADDR[4]), + .D(B1DATA), + .WCLK(CLK1), + .WE(B1EN) + ); +endmodule + module \$__XILINX_RAM64X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); parameter [63:0] INIT = 64'bx; parameter CLKPOL2 = 1; -- cgit v1.2.3 From a701a2accf36abb6d0d1a90dc1811eb15708d5db Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 24 Jun 2019 18:32:58 -0700 Subject: Add test --- tests/memories/issue00710.v | 17 +++++++++++++++++ tests/memories/run-test.sh | 6 +++++- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/memories/issue00710.v diff --git a/tests/memories/issue00710.v b/tests/memories/issue00710.v new file mode 100644 index 000000000..7a5fad1c2 --- /dev/null +++ b/tests/memories/issue00710.v @@ -0,0 +1,17 @@ +// expect-wr-ports 1 +// expect-rd-ports 1 +// expect-rd-clk \clk + +module top(input clk, input we, re, reset, input [7:0] addr, wdata, output reg [7:0] rdata); + +reg [7:0] bram[0:255]; +(* keep *) reg dummy; + +always @(posedge clk) + if (reset) + dummy <= 1'b0; + else if (re) + rdata <= bram[addr]; + else if (we) + bram[addr] <= wdata; +endmodule diff --git a/tests/memories/run-test.sh b/tests/memories/run-test.sh index 734a96682..d0537bb98 100755 --- a/tests/memories/run-test.sh +++ b/tests/memories/run-test.sh @@ -14,7 +14,7 @@ shift "$((OPTIND-1))" bash ../tools/autotest.sh $seed -G *.v -for f in `egrep -l 'expect-(wr|rd)-ports' *.v`; do +for f in `egrep -l 'expect-(wr-ports|rd-ports|rd-clk)' *.v`; do echo -n "Testing expectations for $f .." ../../yosys -qp "proc; opt; memory -nomap;; dump -outfile ${f%.v}.dmp t:\$mem" $f if grep -q expect-wr-ports $f; then @@ -25,6 +25,10 @@ for f in `egrep -l 'expect-(wr|rd)-ports' *.v`; do grep -q "parameter \\\\RD_PORTS $(gawk '/expect-rd-ports/ { print $3; }' $f)\$" ${f%.v}.dmp || { echo " ERROR: Unexpected number of read ports."; false; } fi + if grep -q expect-rd-clk $f; then + grep -q "connect \\\\RD_CLK \\$(gawk '/expect-rd-clk/ { print $3; }' $f)\$" ${f%.v}.dmp || + { echo " ERROR: Unexpected read clock."; false; } + fi echo " ok." done -- cgit v1.2.3 From b7deaceadde865fa8bca47cfeeb43a82dc936076 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 24 Jun 2019 18:33:06 -0700 Subject: Walk through as many muxes as exist for rd_en --- passes/memory/memory_dff.cc | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc index 220d29295..d37cac28e 100644 --- a/passes/memory/memory_dff.cc +++ b/passes/memory/memory_dff.cc @@ -182,20 +182,28 @@ struct MemoryDffWorker if (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data)) { - bool enable_invert = mux_cells_a.count(sig_data) != 0; - Cell *mux = enable_invert ? mux_cells_a.at(sig_data) : mux_cells_b.at(sig_data); - SigSpec check_q = sigmap(mux->getPort(enable_invert ? "\\B" : "\\A")); + RTLIL::SigSpec en; + RTLIL::SigSpec check_q; - sig_data = sigmap(mux->getPort("\\Y")); - for (auto bit : sig_data) - if (sigbit_users_count[bit] > 1) - goto skip_ff_after_read_merging; + do { + bool enable_invert = mux_cells_a.count(sig_data) != 0; + Cell *mux = enable_invert ? mux_cells_a.at(sig_data) : mux_cells_b.at(sig_data); + check_q = sigmap(mux->getPort(enable_invert ? "\\B" : "\\A")); + + sig_data = sigmap(mux->getPort("\\Y")); + for (auto bit : sig_data) + if (sigbit_users_count[bit] > 1) { + goto skip_ff_after_read_merging; + } + + en.append(enable_invert ? module->LogicNot(NEW_ID, mux->getPort("\\S")) : mux->getPort("\\S")); + } while (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data)); if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx) && sig_data == check_q) { disconnect_dff(sig_data); cell->setPort("\\CLK", clk_data); - cell->setPort("\\EN", enable_invert ? module->LogicNot(NEW_ID, mux->getPort("\\S")) : mux->getPort("\\S")); + cell->setPort("\\EN", en.size() > 1 ? module->ReduceAnd(NEW_ID, en) : en); cell->setPort("\\DATA", sig_data); cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1); cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity); -- cgit v1.2.3 From c4e4902098153a4ab90d383ffc00987fc06ff072 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 25 Jun 2019 08:29:55 -0700 Subject: Move only one consumer check outside of while loop --- passes/memory/memory_dff.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc index d37cac28e..91ae38fa3 100644 --- a/passes/memory/memory_dff.cc +++ b/passes/memory/memory_dff.cc @@ -189,16 +189,15 @@ struct MemoryDffWorker bool enable_invert = mux_cells_a.count(sig_data) != 0; Cell *mux = enable_invert ? mux_cells_a.at(sig_data) : mux_cells_b.at(sig_data); check_q = sigmap(mux->getPort(enable_invert ? "\\B" : "\\A")); - sig_data = sigmap(mux->getPort("\\Y")); - for (auto bit : sig_data) - if (sigbit_users_count[bit] > 1) { - goto skip_ff_after_read_merging; - } - en.append(enable_invert ? module->LogicNot(NEW_ID, mux->getPort("\\S")) : mux->getPort("\\S")); } while (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data)); + for (auto bit : sig_data) + if (sigbit_users_count[bit] > 1) { + goto skip_ff_after_read_merging; + } + if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx) && sig_data == check_q) { disconnect_dff(sig_data); -- cgit v1.2.3 From 42720ef6fefdf7645db47b97cd914008d68b00a9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 25 Jun 2019 08:33:17 -0700 Subject: Fix spacing --- passes/memory/memory_dff.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc index 91ae38fa3..5215cce44 100644 --- a/passes/memory/memory_dff.cc +++ b/passes/memory/memory_dff.cc @@ -193,10 +193,9 @@ struct MemoryDffWorker en.append(enable_invert ? module->LogicNot(NEW_ID, mux->getPort("\\S")) : mux->getPort("\\S")); } while (mux_cells_a.count(sig_data) || mux_cells_b.count(sig_data)); - for (auto bit : sig_data) - if (sigbit_users_count[bit] > 1) { - goto skip_ff_after_read_merging; - } + for (auto bit : sig_data) + if (sigbit_users_count[bit] > 1) + goto skip_ff_after_read_merging; if (find_sig_before_dff(sig_data, clk_data, clk_polarity, true) && clk_data != RTLIL::SigSpec(RTLIL::State::Sx) && sig_data == check_q) { -- cgit v1.2.3 From ab6e8ce0f00bc9fcf38dc62ae9de26405f7b59d7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 25 Jun 2019 08:43:58 -0700 Subject: Add testcase from #335, fixed by #1130 --- tests/memories/issue00335.v | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/memories/issue00335.v diff --git a/tests/memories/issue00335.v b/tests/memories/issue00335.v new file mode 100644 index 000000000..f3b6e5dfe --- /dev/null +++ b/tests/memories/issue00335.v @@ -0,0 +1,28 @@ +// expect-wr-ports 1 +// expect-rd-ports 1 +// expect-rd-clk \clk + +module ram2 (input clk, + input sel, + input we, + input [SIZE-1:0] adr, + input [63:0] dat_i, + output reg [63:0] dat_o); + parameter SIZE = 5; // Address size + + reg [63:0] mem [0:(1 << SIZE)-1]; + integer i; + + initial begin + for (i = 0; i < (1< Date: Tue, 25 Jun 2019 16:37:36 +0000 Subject: Add more ECP5 Diamond flip-flops. This includes all I/O registers, and a few more regular FFs where it was convenient. --- techlibs/ecp5/cells_map.v | 40 +++++++++++++++++++++-- techlibs/ecp5/cells_sim.v | 81 +++++++++++++++++++++++++++++++---------------- 2 files changed, 91 insertions(+), 30 deletions(-) diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v index f6c71a03d..a90d5e034 100644 --- a/techlibs/ecp5/cells_map.v +++ b/techlibs/ecp5/cells_map.v @@ -47,6 +47,28 @@ module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED" module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule +// TODO: Diamond flip-flops +// module FD1P3AX(); endmodule +// module FD1P3AY(); endmodule +// module FD1P3BX(); endmodule +// module FD1P3DX(); endmodule +// module FD1P3IX(); endmodule +// module FD1P3JX(); endmodule +// module FD1S3AX(); endmodule +// module FD1S3AY(); endmodule +module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule +module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule +module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule +module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule +// module FL1P3AY(); endmodule +// module FL1P3AZ(); endmodule +// module FL1P3BX(); endmodule +// module FL1P3DX(); endmodule +// module FL1P3IY(); endmodule +// module FL1P3JY(); endmodule +// module FL1S3AX(); endmodule +// module FL1S3AY(); endmodule + // Diamond I/O buffers module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule @@ -62,8 +84,22 @@ module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #( module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule -// For Diamond compatibility, FIXME: add all Diamond flipflop mappings -module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule +// Diamond I/O registers +module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule + +module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule + +// TODO: Diamond I/O latches +// module IFS1S1B(input PD, D, SCLK, output Q); endmodule +// module IFS1S1D(input CD, D, SCLK, output Q); endmodule +// module IFS1S1I(input PD, D, SCLK, output Q); endmodule +// module IFS1S1J(input CD, D, SCLK, output Q); endmodule `ifndef NO_LUT module \$lut (A, Y); diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index 1e4002ee0..2458c1ca0 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -250,18 +250,6 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); endgenerate endmodule -// --------------------------------------- - -module OBZ(input I, T, output O); -assign O = T ? 1'bz : I; -endmodule - -// --------------------------------------- - -module IB(input I, output O); -assign O = I; -endmodule - // --------------------------------------- (* keep *) module TRELLIS_IO( @@ -558,19 +546,56 @@ module DP16KD( parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; endmodule -// For Diamond compatibility, FIXME: add all Diamond flipflop mappings -module FD1S3BX(input PD, D, CK, output Q); - TRELLIS_FF #( - .GSR("DISABLED"), - .CEMUX("1"), - .CLKMUX("CLK"), - .LSRMUX("LSR"), - .REGSET("SET"), - .SRMODE("ASYNC") - ) tff_i ( - .CLK(CK), - .LSR(PD), - .DI(D), - .Q(Q) - ); -endmodule +// TODO: Diamond flip-flops +// module FD1P3AX(); endmodule +// module FD1P3AY(); endmodule +// module FD1P3BX(); endmodule +// module FD1P3DX(); endmodule +// module FD1P3IX(); endmodule +// module FD1P3JX(); endmodule +// module FD1S3AX(); endmodule +// module FD1S3AY(); endmodule +module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule +module FD1S3DX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule +module FD1S3IX(input CD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule +module FD1S3JX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule +// module FL1P3AY(); endmodule +// module FL1P3AZ(); endmodule +// module FL1P3BX(); endmodule +// module FL1P3DX(); endmodule +// module FL1P3IY(); endmodule +// module FL1P3JY(); endmodule +// module FL1S3AX(); endmodule +// module FL1S3AY(); endmodule + +// Diamond I/O buffers +module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule +module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule +module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) tio (.B(I), .O(O)); endmodule +module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I)); endmodule +module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule +module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule +module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(O), .I(I), .T(T)); endmodule +module OBCO (input I, output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule +module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule +module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule +module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) tio (.B(B), .I(I), .O(O), .T(T)); endmodule +module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) tio (.B(A), .O(Z)); endmodule +module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) tio (.B(Z), .I(A)); endmodule + +// Diamond I/O registers +module IFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule + +module OFS1P3BX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3DX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3IX(input CD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3JX(input PD, D, SP, SCLK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) tff (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule + +// TODO: Diamond I/O latches +// module IFS1S1B(input PD, D, SCLK, output Q); endmodule +// module IFS1S1D(input CD, D, SCLK, output Q); endmodule +// module IFS1S1I(input PD, D, SCLK, output Q); endmodule +// module IFS1S1J(input CD, D, SCLK, output Q); endmodule -- cgit v1.2.3 From b3c36b444808be36a4fb35a3d78ba3f9691b3da0 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 26 Jun 2019 10:58:39 +0200 Subject: Escape scope names starting with dollar sign in smtio.py Signed-off-by: Clifford Wolf --- backends/smt2/smtio.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index cea0fc56c..ae7968a1b 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -1043,7 +1043,10 @@ class MkVcd: scope = scope[:-1] while uipath[:-1] != scope: - print("$scope module %s $end" % uipath[len(scope)], file=self.f) + scopename = uipath[len(scope)] + if scopename.startswith("$"): + scopename = "\\" + scopename + print("$scope module %s $end" % scopename, file=self.f) scope.append(uipath[len(scope)]) if path in self.clocks and self.clocks[path][1] == "event": -- cgit v1.2.3 From 8e9ef891febb47f512710de591401539ad521634 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 26 Jun 2019 11:00:44 +0200 Subject: Do not clean up buffer cells with "keep" attribute, closes #1128 Signed-off-by: Clifford Wolf --- passes/opt/opt_clean.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index cfb0f788a..5f75288e2 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -480,7 +480,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool std::vector delcells; for (auto cell : module->cells()) - if (cell->type.in("$pos", "$_BUF_")) { + if (cell->type.in("$pos", "$_BUF_") && !cell->has_keep_attr()) { bool is_signed = cell->type == "$pos" && cell->getParam("\\A_SIGNED").as_bool(); RTLIL::SigSpec a = cell->getPort("\\A"); RTLIL::SigSpec y = cell->getPort("\\Y"); -- cgit v1.2.3 From f6053b88103bfc652dec1959f30bfb1880613f61 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 26 Jun 2019 11:09:43 +0200 Subject: Fix segfault on failed VERILOG_FRONTEND::const2ast, closes #1131 Signed-off-by: Clifford Wolf --- frontends/verilog/const2ast.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 3a3634d34..f6a17b242 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -153,7 +153,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn { if (warn_z) { AstNode *ret = const2ast(code, case_type); - if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end()) + if (ret != nullptr && std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end()) log_warning("Yosys has only limited support for tri-state logic at the moment. (%s:%d)\n", current_filename.c_str(), get_line_num()); return ret; -- cgit v1.2.3 From 1b49380f6bd79cb037fb36a3d06adf386968dc47 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 26 Jun 2019 17:42:00 +0200 Subject: Improve BTOR2 handling of undriven wires Signed-off-by: Clifford Wolf --- backends/btor/btor.cc | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 511a11942..a507b120b 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -17,6 +17,11 @@ * */ +// [[CITE]] Btor2 , BtorMC and Boolector 3.0 +// Aina Niemetz, Mathias Preiner, Clifford Wolf, Armin Biere +// Computer Aided Verification - 30th International Conference, CAV 2018 +// https://cs.stanford.edu/people/niemetz/publication/2018/niemetzpreinerwolfbiere-cav18/ + #include "kernel/rtlil.h" #include "kernel/register.h" #include "kernel/sigtools.h" @@ -875,9 +880,28 @@ struct BtorWorker else { if (bit_cell.count(bit) == 0) - log_error("No driver for signal bit %s.\n", log_signal(bit)); - export_cell(bit_cell.at(bit)); - log_assert(bit_nid.count(bit)); + { + SigSpec s = bit; + + while (i+GetSize(s) < GetSize(sig) && sig[i+GetSize(s)].wire != nullptr && + bit_cell.count(sig[i+GetSize(s)]) == 0) + s.append(sig[i+GetSize(s)]); + + log_warning("No driver for signal %s.\n", log_signal(s)); + + int sid = get_bv_sid(GetSize(s)); + int nid = next_nid++; + btorf("%d input %d %s\n", nid, sid); + nid_width[nid] = GetSize(s); + + i += GetSize(s)-1; + continue; + } + else + { + export_cell(bit_cell.at(bit)); + log_assert(bit_nid.count(bit)); + } } } -- cgit v1.2.3 From 0b7d648c6a71594f8a17e78aef8f62b6f6448390 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 26 Jun 2019 17:54:17 +0200 Subject: Improve opt_clean handling of unused public wires Signed-off-by: Clifford Wolf --- passes/opt/opt_clean.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 5f75288e2..a8a8e0bc7 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -326,8 +326,8 @@ bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) { // do not delete anything with "keep" or module ports or initialized wires } else - if (!purge_mode && check_public_name(wire->name)) { - // do not get rid of public names unless in purge mode + if (!purge_mode && check_public_name(wire->name) && (raw_used_signals.check_any(s1) || used_signals.check_any(s2) || s1 != s2)) { + // do not get rid of public names unless in purge mode or if the wire is entirely unused, not even aliased } else if (!raw_used_signals.check_any(s1)) { // delete wires that aren't used by anything directly -- cgit v1.2.3 From ea0b6258ab392b6186ee5d75a75da944b25d0392 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 26 Jun 2019 18:34:34 +0200 Subject: Simulation model verilog fix --- techlibs/ecp5/cells_sim.v | 13 ------------- techlibs/xilinx/cells_sim.v | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index 2458c1ca0..07fadfa10 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -281,19 +281,6 @@ endmodule // --------------------------------------- -module OB(input I, output O); -assign O = I; -endmodule - -// --------------------------------------- - -module BB(input I, T, output O, inout B); -assign B = T ? 1'bz : I; -assign O = B; -endmodule - -// --------------------------------------- - module INV(input A, output Z); assign Z = !A; endmodule diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 50d588a9e..f4598dcf4 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -282,7 +282,7 @@ module RAM32X1D ( output DPO, SPO, input D, WCLK, WE, input A0, A1, A2, A3, A4, - input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, + input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4 ); parameter INIT = 32'h0; parameter IS_WCLK_INVERTED = 1'b0; -- cgit v1.2.3