From 641b86d25f5baa898bf5fca3d1a8f2fd4f5954e6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 11:45:31 -0700 Subject: [PATCH 01/15] Fix up ExclusiveDatabase with @cliffordwolf's help --- passes/opt/muxpack.cc | 65 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 33 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; + bool query(const SigSpec &sig) const + { + SigSpec nonconst_sig; + pool const_values; - for (auto bit2 : sig2.bits()) { - auto jt = sig_cmp_prev.find(bit2); - if (jt == sig_cmp_prev.end()) - return false; + for (auto bit : sig.bits()) { + auto it = sig_cmp_prev.find(bit); + if (it == sig_cmp_prev.end()) + return false; - if (it->second != jt->second) - 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; } From 6ec816098153c733b97410ebc6aef166db8affd8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 11:45:53 -0700 Subject: [PATCH 02/15] 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 From d89d663c92853fcd7f9d75b392ec4133ba2f1d89 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 11:52:28 -0700 Subject: [PATCH 03/15] 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 From 15535112b7b4caa1da75274397c5a3ba885a7349 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 11:52:51 -0700 Subject: [PATCH 04/15] Fix spacing --- passes/opt/muxpack.cc | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 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()); - } - } + 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; + 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; + 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 (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; - } + if (!const_values.insert(it->second.second).second) + return false; + } return true; } From ae8305ffcc0c812488163bcc35365d473ce1345d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 12:13:00 -0700 Subject: [PATCH 05/15] 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 From 32f637ffdb0c0641b51227fad92bc80e284740d2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 12:31:04 -0700 Subject: [PATCH 06/15] 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) - //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 = 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) + 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 From 545cfbbe0dcc36f18dce6429498f4d87112879e2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 21 Jun 2019 12:31:14 -0700 Subject: [PATCH 07/15] 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; From a701a2accf36abb6d0d1a90dc1811eb15708d5db Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 24 Jun 2019 18:32:58 -0700 Subject: [PATCH 08/15] 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 From b7deaceadde865fa8bca47cfeeb43a82dc936076 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 24 Jun 2019 18:33:06 -0700 Subject: [PATCH 09/15] 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); From d2fed0a7f1bb72ee285657b974f4996c77641a23 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 24 Jun 2019 23:37:01 -0700 Subject: [PATCH 10/15] nullptr check --- passes/techmap/abc9.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index cd7954427..52ca47a49 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -124,6 +124,7 @@ void handle_loops(RTLIL::Design *design) RTLIL::SigSpec sig; for (auto b : it->second) { Wire *w = b.wire; + if (!w) continue; if (w->port_output) { log_assert(w->get_bool_attribute("\\abc_scc_break")); w = module->wire(stringf("%s.abci", w->name.c_str())); From c4e4902098153a4ab90d383ffc00987fc06ff072 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 25 Jun 2019 08:29:55 -0700 Subject: [PATCH 11/15] 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); From 42720ef6fefdf7645db47b97cd914008d68b00a9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 25 Jun 2019 08:33:17 -0700 Subject: [PATCH 12/15] 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) { From ab6e8ce0f00bc9fcf38dc62ae9de26405f7b59d7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 25 Jun 2019 08:43:58 -0700 Subject: [PATCH 13/15] 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: Mon, 24 Jun 2019 22:54:35 -0700 Subject: [PATCH 14/15] Add RAM32X1D box info --- techlibs/xilinx/abc_xc7.box | 11 +++++++++-- techlibs/xilinx/cells_sim.v | 5 +++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/techlibs/xilinx/abc_xc7.box b/techlibs/xilinx/abc_xc7.box index 8c046cdbc..1a7243f54 100644 --- a/techlibs/xilinx/abc_xc7.box +++ b/techlibs/xilinx/abc_xc7.box @@ -30,16 +30,23 @@ CARRY4 3 1 10 8 592 540 520 356 - 512 548 292 - 228 580 526 507 398 385 508 528 378 380 114 +# SLICEM/A6LUT +# Inputs: A0 A1 A2 A3 A4 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 WCLK WE +# Outputs: DPO SPO +RAM32X1D 4 0 13 2 +- - - - - - 124 124 124 124 124 - - +124 124 124 124 124 - - - - - - - - + # SLICEM/A6LUT # Inputs: A0 A1 A2 A3 A4 A5 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 WCLK WE # Outputs: DPO SPO -RAM64X1D 4 0 15 2 +RAM64X1D 5 0 15 2 - - - - - - - 642 631 472 407 238 127 - - 642 631 472 407 238 127 - - - - - - - - - # SLICEM/A6LUT + F7[AB]MUX # Inputs: A0 A1 A2 A3 A4 A5 A6 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 DPRA6 WCLK WE # Outputs: DPO SPO -RAM128X1D 5 0 17 2 +RAM128X1D 6 0 17 2 - - - - - - - - 1009 998 839 774 605 494 450 - - 1047 1036 877 812 643 532 478 - - - - - - - - - - diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 67b221c95..04381e3b9 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -281,6 +281,7 @@ 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 +(* abc_box_id = 4, abc_scc_break="D" *) module RAM32X1D ( output DPO, SPO, input D, WCLK, WE, @@ -298,7 +299,7 @@ module RAM32X1D ( always @(posedge clk) if (WE) mem[a] <= D; endmodule -(* abc_box_id = 4, abc_scc_break="D" *) +(* abc_box_id = 5, abc_scc_break="D" *) module RAM64X1D ( output DPO, SPO, input D, WCLK, WE, @@ -316,7 +317,7 @@ module RAM64X1D ( always @(posedge clk) if (WE) mem[a] <= D; endmodule -(* abc_box_id = 5, abc_scc_break="D" *) +(* abc_box_id = 6, abc_scc_break="D" *) module RAM128X1D ( output DPO, SPO, input D, WCLK, WE, From 480a04cb3c3b6a2eb097a78f68fa9ff79caad24e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 24 Jun 2019 23:05:28 -0700 Subject: [PATCH 15/15] Realistic delays for RAM32X1D too --- techlibs/xilinx/abc_xc7.box | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/xilinx/abc_xc7.box b/techlibs/xilinx/abc_xc7.box index 1a7243f54..96966a71c 100644 --- a/techlibs/xilinx/abc_xc7.box +++ b/techlibs/xilinx/abc_xc7.box @@ -34,8 +34,8 @@ CARRY4 3 1 10 8 # Inputs: A0 A1 A2 A3 A4 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 WCLK WE # Outputs: DPO SPO RAM32X1D 4 0 13 2 -- - - - - - 124 124 124 124 124 - - -124 124 124 124 124 - - - - - - - - +- - - - - - 631 472 407 238 127 - - +631 472 407 238 127 - - - - - - - - # SLICEM/A6LUT # Inputs: A0 A1 A2 A3 A4 A5 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 WCLK WE