aboutsummaryrefslogtreecommitdiffstats
path: root/passes
diff options
context:
space:
mode:
Diffstat (limited to 'passes')
-rw-r--r--passes/cmds/Makefile.inc1
-rw-r--r--passes/cmds/autoname.cc134
-rw-r--r--passes/fsm/fsm_detect.cc16
-rw-r--r--passes/opt/wreduce.cc14
-rw-r--r--passes/pmgen/Makefile.inc4
-rw-r--r--passes/pmgen/generate.h140
-rw-r--r--passes/pmgen/peepopt.cc76
-rw-r--r--passes/pmgen/peepopt_dffmux.pmg64
-rw-r--r--passes/pmgen/pmgen.py16
-rw-r--r--passes/pmgen/test_pmgen.cc129
-rw-r--r--passes/pmgen/xilinx_dsp.pmg12
-rw-r--r--passes/pmgen/xilinx_dsp_CREG.pmg8
-rw-r--r--passes/techmap/extract_fa.cc12
-rw-r--r--passes/techmap/flowmap.cc5
14 files changed, 449 insertions, 182 deletions
diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc
index cf9663d1d..c7edc30fb 100644
--- a/passes/cmds/Makefile.inc
+++ b/passes/cmds/Makefile.inc
@@ -5,6 +5,7 @@ OBJS += passes/cmds/design.o
OBJS += passes/cmds/select.o
OBJS += passes/cmds/show.o
OBJS += passes/cmds/rename.o
+OBJS += passes/cmds/autoname.o
OBJS += passes/cmds/connect.o
OBJS += passes/cmds/scatter.o
OBJS += passes/cmds/setundef.o
diff --git a/passes/cmds/autoname.cc b/passes/cmds/autoname.cc
new file mode 100644
index 000000000..4614a8153
--- /dev/null
+++ b/passes/cmds/autoname.cc
@@ -0,0 +1,134 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+int autoname_worker(Module *module)
+{
+ dict<Cell*, pair<int, IdString>> proposed_cell_names;
+ dict<Wire*, pair<int, IdString>> proposed_wire_names;
+ dict<Wire*, int> wire_score;
+ int best_score = -1;
+
+ for (auto cell : module->selected_cells())
+ for (auto &conn : cell->connections())
+ for (auto bit : conn.second)
+ if (bit.wire != nullptr)
+ wire_score[bit.wire]++;
+
+ for (auto cell : module->selected_cells()) {
+ if (cell->name[0] == '$') {
+ for (auto &conn : cell->connections()) {
+ string suffix = stringf("_%s_%s", log_id(cell->type), log_id(conn.first));
+ for (auto bit : conn.second)
+ if (bit.wire != nullptr && bit.wire->name[0] != '$') {
+ IdString new_name(bit.wire->name.str() + suffix);
+ int score = wire_score.at(bit.wire);
+ if (cell->output(conn.first)) score = 0;
+ score = 10000*score + new_name.size();
+ if (!proposed_cell_names.count(cell) || score < proposed_cell_names.at(cell).first) {
+ if (best_score < 0 || score < best_score)
+ best_score = score;
+ proposed_cell_names[cell] = make_pair(score, new_name);
+ }
+ }
+ }
+ } else {
+ for (auto &conn : cell->connections()) {
+ string suffix = stringf("_%s", log_id(conn.first));
+ for (auto bit : conn.second)
+ if (bit.wire != nullptr && bit.wire->name[0] == '$') {
+ IdString new_name(cell->name.str() + suffix);
+ int score = wire_score.at(bit.wire);
+ if (cell->output(conn.first)) score = 0;
+ score = 10000*score + new_name.size();
+ if (!proposed_wire_names.count(bit.wire) || score < proposed_wire_names.at(bit.wire).first) {
+ if (best_score < 0 || score < best_score)
+ best_score = score;
+ proposed_wire_names[bit.wire] = make_pair(score, new_name);
+ }
+ }
+ }
+ }
+ }
+
+ for (auto &it : proposed_cell_names) {
+ if (best_score*2 < it.second.first)
+ continue;
+ IdString n = module->uniquify(it.second.second);
+ log_debug("Rename cell %s in %s to %s.\n", log_id(it.first), log_id(module), log_id(n));
+ module->rename(it.first, n);
+ }
+
+ for (auto &it : proposed_wire_names) {
+ if (best_score*2 < it.second.first)
+ continue;
+ IdString n = module->uniquify(it.second.second);
+ log_debug("Rename wire %s in %s to %s.\n", log_id(it.first), log_id(module), log_id(n));
+ module->rename(it.first, n);
+ }
+
+ return proposed_cell_names.size() + proposed_wire_names.size();
+}
+
+struct AutonamePass : public Pass {
+ AutonamePass() : Pass("autoname", "automatically assign names to objects") { }
+ void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" autoname [selection]\n");
+ log("\n");
+ log("Assign auto-generated public names to objects with private names (the ones\n");
+ log("with $-prefix).\n");
+ log("\n");
+ }
+ void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-foo") {
+ // foo = true;
+ // continue;
+ // }
+ break;
+ }
+
+ log_header(design, "Executing AUTONAME pass.\n");
+
+ for (auto module : design->selected_modules())
+ {
+ int count = 0, iter = 0;
+ while (1) {
+ iter++;
+ int n = autoname_worker(module);
+ if (!n) break;
+ count += n;
+ }
+ if (count > 0)
+ log("Renamed %d objects in module %s (%d iterations).\n", count, log_id(module), iter);
+ }
+ }
+} AutonamePass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc
index 5ae991b28..fb3896669 100644
--- a/passes/fsm/fsm_detect.cc
+++ b/passes/fsm/fsm_detect.cc
@@ -158,22 +158,25 @@ static void detect_fsm(RTLIL::Wire *wire)
std::set<sig2driver_entry_t> cellport_list;
sig2user.find(sig_q, cellport_list);
+ auto sig_q_bits = sig_q.to_sigbit_pool();
+
for (auto &cellport : cellport_list)
{
RTLIL::Cell *cell = cellport.first;
bool set_output = false, clr_output = false;
- if (cell->type == "$ne")
+ if (cell->type.in("$ne", "$reduce_or", "$reduce_bool"))
set_output = true;
- if (cell->type == "$eq")
+ if (cell->type.in("$eq", "$logic_not", "$reduce_and"))
clr_output = true;
- if (!set_output && !clr_output) {
- clr_output = true;
+ if (set_output || clr_output) {
for (auto &port_it : cell->connections())
- if (port_it.first != "\\A" || port_it.first != "\\Y")
- clr_output = false;
+ if (cell->input(port_it.first))
+ for (auto bit : assign_map(port_it.second))
+ if (bit.wire != nullptr && !sig_q_bits.count(bit))
+ goto next_cellport;
}
if (set_output || clr_output) {
@@ -184,6 +187,7 @@ static void detect_fsm(RTLIL::Wire *wire)
ce.set(sig, val);
}
}
+ next_cellport:;
}
SigSpec sig_y = sig_d, sig_undef;
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index c02c355cb..04b882db9 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -143,13 +143,18 @@ struct WreduceWorker
SigSpec sig_d = mi.sigmap(cell->getPort(ID(D)));
SigSpec sig_q = mi.sigmap(cell->getPort(ID(Q)));
- Const initval;
+ bool is_adff = (cell->type == ID($adff));
+ Const initval, arst_value;
int width_before = GetSize(sig_q);
if (width_before == 0)
return;
+ if (cell->parameters.count(ID(ARST_VALUE))) {
+ arst_value = cell->parameters[ID(ARST_VALUE)];
+ }
+
bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0;
bool sign_ext = !zero_ext;
@@ -163,7 +168,8 @@ struct WreduceWorker
for (int i = GetSize(sig_q)-1; i >= 0; i--)
{
- if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx)) {
+ if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx) &&
+ (!is_adff || i >= GetSize(arst_value) || arst_value[i] == State::S0 || arst_value[i] == State::Sx)) {
module->connect(sig_q[i], State::S0);
remove_init_bits.insert(sig_q[i]);
sig_d.remove(i);
@@ -171,7 +177,8 @@ struct WreduceWorker
continue;
}
- if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1]) {
+ if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1] &&
+ (!is_adff || i >= GetSize(arst_value) || arst_value[i] == arst_value[i-1])) {
module->connect(sig_q[i], sig_q[i-1]);
remove_init_bits.insert(sig_q[i]);
sig_d.remove(i);
@@ -214,7 +221,6 @@ struct WreduceWorker
// Narrow ARST_VALUE parameter to new size.
if (cell->parameters.count(ID(ARST_VALUE))) {
- Const arst_value = cell->getParam(ID(ARST_VALUE));
arst_value.bits.resize(GetSize(sig_q));
cell->setParam(ID(ARST_VALUE), arst_value);
}
diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc
index 366c37943..145d2ebf9 100644
--- a/passes/pmgen/Makefile.inc
+++ b/passes/pmgen/Makefile.inc
@@ -1,5 +1,5 @@
%_pm.h: passes/pmgen/pmgen.py %.pmg
- $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p $(subst _pm.h,,$(notdir $@)) $(filter-out $<,$^)
+ $(P) mkdir -p passes/pmgen && $(PYTHON_EXECUTABLE) $< -o $@ -p $(subst _pm.h,,$(notdir $@)) $(filter-out $<,$^)
# --------------------------------------
@@ -38,7 +38,7 @@ PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg
PEEPOPT_PATTERN += passes/pmgen/peepopt_dffmux.pmg
passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN)
- $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^)
+ $(P) mkdir -p passes/pmgen && $(PYTHON_EXECUTABLE) $< -o $@ -p peepopt $(filter-out $<,$^)
# --------------------------------------
diff --git a/passes/pmgen/generate.h b/passes/pmgen/generate.h
new file mode 100644
index 000000000..354583de5
--- /dev/null
+++ b/passes/pmgen/generate.h
@@ -0,0 +1,140 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * 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.
+ *
+ */
+
+#ifndef PMGEN_GENERATE
+#define PMGEN_GENERATE
+
+#define GENERATE_PATTERN(pmclass, pattern) \
+ generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design)
+
+void pmtest_addports(Module *module)
+{
+ pool<SigBit> driven_bits, used_bits;
+ SigMap sigmap(module);
+ int icnt = 0, ocnt = 0;
+
+ for (auto cell : module->cells())
+ for (auto conn : cell->connections())
+ {
+ if (cell->input(conn.first))
+ for (auto bit : sigmap(conn.second))
+ used_bits.insert(bit);
+ if (cell->output(conn.first))
+ for (auto bit : sigmap(conn.second))
+ driven_bits.insert(bit);
+ }
+
+ for (auto wire : vector<Wire*>(module->wires()))
+ {
+ SigSpec ibits, obits;
+ for (auto bit : sigmap(wire)) {
+ if (!used_bits.count(bit))
+ obits.append(bit);
+ if (!driven_bits.count(bit))
+ ibits.append(bit);
+ }
+ if (!ibits.empty()) {
+ Wire *w = module->addWire(stringf("\\i%d", icnt++), GetSize(ibits));
+ w->port_input = true;
+ module->connect(ibits, w);
+ }
+ if (!obits.empty()) {
+ Wire *w = module->addWire(stringf("\\o%d", ocnt++), GetSize(obits));
+ w->port_output = true;
+ module->connect(w, obits);
+ }
+ }
+
+ module->fixup_ports();
+}
+
+template <class pm>
+void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const char *pmclass, const char *pattern, Design *design)
+{
+ log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass);
+
+ int modcnt = 0;
+ int maxmodcnt = 100;
+ int maxsubcnt = 4;
+ int timeout = 0;
+ vector<Module*> mods;
+
+ while (modcnt < maxmodcnt)
+ {
+ int submodcnt = 0, itercnt = 0, cellcnt = 0;
+ Module *mod = design->addModule(NEW_ID);
+
+ while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000)
+ {
+ if (timeout++ > 10000)
+ log_error("pmgen generator is stuck: 10000 iterations with no matching module generated.\n");
+
+ pm matcher(mod, mod->cells());
+
+ matcher.rng(1);
+ matcher.rngseed += modcnt;
+ matcher.rng(1);
+ matcher.rngseed += submodcnt;
+ matcher.rng(1);
+ matcher.rngseed += itercnt;
+ matcher.rng(1);
+ matcher.rngseed += cellcnt;
+ matcher.rng(1);
+
+ if (GetSize(mod->cells()) != cellcnt)
+ {
+ bool found_match = false;
+ run(matcher, [&](){ found_match = true; });
+ cellcnt = GetSize(mod->cells());
+
+ if (found_match) {
+ Module *m = design->addModule(stringf("\\pmtest_%s_%s_%05d",
+ pmclass, pattern, modcnt++));
+ log("Creating module %s with %d cells.\n", log_id(m), cellcnt);
+ mod->cloneInto(m);
+ pmtest_addports(m);
+ mods.push_back(m);
+ submodcnt++;
+ timeout = 0;
+ }
+ }
+
+ matcher.generate_mode = true;
+ run(matcher, [](){});
+ }
+
+ if (submodcnt && maxsubcnt < (1 << 16))
+ maxsubcnt *= 2;
+
+ design->remove(mod);
+ }
+
+ Module *m = design->addModule(stringf("\\pmtest_%s_%s", pmclass, pattern));
+ log("Creating module %s with %d cells.\n", log_id(m), GetSize(mods));
+ for (auto mod : mods) {
+ Cell *c = m->addCell(mod->name, mod->name);
+ for (auto port : mod->ports) {
+ Wire *w = m->addWire(NEW_ID, GetSize(mod->wire(port)));
+ c->setPort(port, w);
+ }
+ }
+ pmtest_addports(m);
+}
+
+#endif
diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc
index 72b02127a..2230145df 100644
--- a/passes/pmgen/peepopt.cc
+++ b/passes/pmgen/peepopt.cc
@@ -24,8 +24,11 @@ USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
bool did_something;
+dict<SigBit, State> initbits;
+pool<SigBit> rminitbits;
#include "passes/pmgen/peepopt_pm.h"
+#include "generate.h"
struct PeepoptPass : public Pass {
PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { }
@@ -40,27 +43,86 @@ struct PeepoptPass : public Pass {
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
+ std::string genmode;
+
log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
- // if (args[argidx] == "-singleton") {
- // singleton_mode = true;
- // continue;
- // }
+ if (args[argidx] == "-generate" && argidx+1 < args.size()) {
+ genmode = args[++argidx];
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
- for (auto module : design->selected_modules()) {
+ if (!genmode.empty())
+ {
+ initbits.clear();
+ rminitbits.clear();
+
+ if (genmode == "shiftmul")
+ GENERATE_PATTERN(peepopt_pm, shiftmul);
+ else if (genmode == "muldiv")
+ GENERATE_PATTERN(peepopt_pm, muldiv);
+ else if (genmode == "dffmux")
+ GENERATE_PATTERN(peepopt_pm, dffmux);
+ else
+ log_abort();
+ return;
+ }
+
+ for (auto module : design->selected_modules())
+ {
did_something = true;
- while (did_something) {
+
+ while (did_something)
+ {
did_something = false;
- peepopt_pm pm(module, module->selected_cells());
+ initbits.clear();
+ rminitbits.clear();
+
+ peepopt_pm pm(module);
+
+ for (auto w : module->wires()) {
+ auto it = w->attributes.find(ID(init));
+ if (it != w->attributes.end()) {
+ SigSpec sig = pm.sigmap(w);
+ Const val = it->second;
+ int len = std::min(GetSize(sig), GetSize(val));
+ for (int i = 0; i < len; i++) {
+ if (sig[i].wire == nullptr)
+ continue;
+ if (val[i] != State::S0 && val[i] != State::S1)
+ continue;
+ initbits[sig[i]] = val[i];
+ }
+ }
+ }
+
+ pm.setup(module->selected_cells());
+
pm.run_shiftmul();
pm.run_muldiv();
pm.run_dffmux();
+
+ for (auto w : module->wires()) {
+ auto it = w->attributes.find(ID(init));
+ if (it != w->attributes.end()) {
+ SigSpec sig = pm.sigmap(w);
+ Const &val = it->second;
+ int len = std::min(GetSize(sig), GetSize(val));
+ for (int i = 0; i < len; i++) {
+ if (rminitbits.count(sig[i]))
+ val[i] = State::Sx;
+ }
+ }
+ }
+
+ initbits.clear();
+ rminitbits.clear();
}
}
}
diff --git a/passes/pmgen/peepopt_dffmux.pmg b/passes/pmgen/peepopt_dffmux.pmg
index bfd155c58..0069b0570 100644
--- a/passes/pmgen/peepopt_dffmux.pmg
+++ b/passes/pmgen/peepopt_dffmux.pmg
@@ -60,12 +60,13 @@ code
SigSpec Q = port(dff, \Q);
int width = GetSize(D);
- SigSpec &dffD = dff->connections_.at(\D);
- SigSpec &dffQ = dff->connections_.at(\Q);
- Const init;
- for (const auto &b : Q) {
- auto it = b.wire->attributes.find(\init);
- init.bits.push_back(it == b.wire->attributes.end() ? State::Sx : it->second[b.offset]);
+ SigSpec dffD = dff->getPort(\D);
+ SigSpec dffQ = dff->getPort(\Q);
+
+ Const initval;
+ for (auto b : Q) {
+ auto it = initbits.find(b);
+ initval.bits.push_back(it == initbits.end() ? State::Sx : it->second);
}
auto cmpx = [=](State lhs, State rhs) {
@@ -76,56 +77,68 @@ code
int i = width-1;
while (i > 1) {
- log_dump(i, D[i], D[i-1], rst[i], rst[i-1], init[i], init[i-1]);
if (D[i] != D[i-1])
break;
if (!cmpx(rst[i], rst[i-1]))
break;
- if (!cmpx(init[i], init[i-1]))
+ if (!cmpx(initval[i], initval[i-1]))
break;
- if (!cmpx(rst[i], init[i]))
+ if (!cmpx(rst[i], initval[i]))
break;
+ rminitbits.insert(Q[i]);
module->connect(Q[i], Q[i-1]);
i--;
}
if (i < width-1) {
did_something = true;
if (cemux) {
- SigSpec &ceA = cemux->connections_.at(\A);
- SigSpec &ceB = cemux->connections_.at(\B);
- SigSpec &ceY = cemux->connections_.at(\Y);
+ SigSpec ceA = cemux->getPort(\A);
+ SigSpec ceB = cemux->getPort(\B);
+ SigSpec ceY = cemux->getPort(\Y);
ceA.remove(i, width-1-i);
ceB.remove(i, width-1-i);
ceY.remove(i, width-1-i);
+ cemux->setPort(\A, ceA);
+ cemux->setPort(\B, ceB);
+ cemux->setPort(\Y, ceY);
cemux->fixup_parameters();
+ blacklist(cemux);
}
if (rstmux) {
- SigSpec &rstA = rstmux->connections_.at(\A);
- SigSpec &rstB = rstmux->connections_.at(\B);
- SigSpec &rstY = rstmux->connections_.at(\Y);
+ SigSpec rstA = rstmux->getPort(\A);
+ SigSpec rstB = rstmux->getPort(\B);
+ SigSpec rstY = rstmux->getPort(\Y);
rstA.remove(i, width-1-i);
rstB.remove(i, width-1-i);
rstY.remove(i, width-1-i);
+ rstmux->setPort(\A, rstA);
+ rstmux->setPort(\B, rstB);
+ rstmux->setPort(\Y, rstY);
rstmux->fixup_parameters();
+ blacklist(rstmux);
}
dffD.remove(i, width-1-i);
dffQ.remove(i, width-1-i);
+ dff->setPort(\D, dffD);
+ dff->setPort(\Q, dffQ);
dff->fixup_parameters();
+ blacklist(dff);
log("dffcemux pattern in %s: dff=%s, cemux=%s, rstmux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(cemux, "n/a"), log_id(rstmux, "n/a"), width-1-i);
width = i+1;
}
if (cemux) {
- SigSpec &ceA = cemux->connections_.at(\A);
- SigSpec &ceB = cemux->connections_.at(\B);
- SigSpec &ceY = cemux->connections_.at(\Y);
+ SigSpec ceA = cemux->getPort(\A);
+ SigSpec ceB = cemux->getPort(\B);
+ SigSpec ceY = cemux->getPort(\Y);
int count = 0;
for (int i = width-1; i >= 0; i--) {
if (D[i].wire)
continue;
- if (cmpx(rst[i], D[i].data) && cmpx(init[i], D[i].data)) {
+ if (cmpx(rst[i], D[i].data) && cmpx(initval[i], D[i].data)) {
count++;
+ rminitbits.insert(Q[i]);
module->connect(Q[i], D[i]);
ceA.remove(i);
ceB.remove(i);
@@ -134,10 +147,21 @@ code
dffQ.remove(i);
}
}
- if (count > 0) {
+ if (count > 0)
+ {
did_something = true;
+
+ cemux->setPort(\A, ceA);
+ cemux->setPort(\B, ceB);
+ cemux->setPort(\Y, ceY);
cemux->fixup_parameters();
+ blacklist(cemux);
+
+ dff->setPort(\D, dffD);
+ dff->setPort(\Q, dffQ);
dff->fixup_parameters();
+ blacklist(dff);
+
log("dffcemux pattern in %s: dff=%s, cemux=%s, rstmux=%s; removed %d constant bits.\n", log_id(module), log_id(dff), log_id(cemux), log_id(rstmux, "n/a"), count);
}
}
diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py
index 39a09991d..df0ffaff2 100644
--- a/passes/pmgen/pmgen.py
+++ b/passes/pmgen/pmgen.py
@@ -362,6 +362,7 @@ with open(outfile, "w") as f:
print(" Module *module;", file=f)
print(" SigMap sigmap;", file=f)
print(" std::function<void()> on_accept;", file=f)
+ print(" bool setup_done;", file=f)
print(" bool generate_mode;", file=f)
print(" int accept_cnt;", file=f)
print("", file=f)
@@ -477,7 +478,17 @@ with open(outfile, "w") as f:
print("", file=f)
print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f)
- print(" module(module), sigmap(module), generate_mode(false), rngseed(12345678) {", file=f)
+ print(" module(module), sigmap(module), setup_done(false), generate_mode(false), rngseed(12345678) {", file=f)
+ print(" setup(cells);", file=f)
+ print(" }", file=f)
+ print("", file=f)
+
+ print(" {}_pm(Module *module) :".format(prefix), file=f)
+ print(" module(module), sigmap(module), setup_done(false), generate_mode(false), rngseed(12345678) {", file=f)
+ print(" }", file=f)
+ print("", file=f)
+
+ print(" void setup(const vector<Cell*> &cells) {", file=f)
for current_pattern in sorted(patterns.keys()):
for s, t in sorted(udata_types[current_pattern].items()):
if t.endswith("*"):
@@ -485,6 +496,8 @@ with open(outfile, "w") as f:
else:
print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f)
current_pattern = None
+ print(" log_assert(!setup_done);", file=f)
+ print(" setup_done = true;", file=f)
print(" for (auto port : module->ports)", file=f)
print(" add_siguser(module->wire(port), nullptr);", file=f)
print(" for (auto cell : module->cells())", file=f)
@@ -539,6 +552,7 @@ with open(outfile, "w") as f:
for current_pattern in sorted(patterns.keys()):
print(" int run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f)
+ print(" log_assert(setup_done);", file=f)
print(" accept_cnt = 0;", file=f)
print(" on_accept = on_accept_f;", file=f)
print(" rollback = 0;", file=f)
diff --git a/passes/pmgen/test_pmgen.cc b/passes/pmgen/test_pmgen.cc
index 4f3eec935..72dc18dcc 100644
--- a/passes/pmgen/test_pmgen.cc
+++ b/passes/pmgen/test_pmgen.cc
@@ -23,13 +23,11 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-// for peepopt_pm
-bool did_something;
-
#include "passes/pmgen/test_pmgen_pm.h"
#include "passes/pmgen/ice40_dsp_pm.h"
#include "passes/pmgen/xilinx_srl_pm.h"
-#include "passes/pmgen/peepopt_pm.h"
+
+#include "generate.h"
void reduce_chain(test_pmgen_pm &pm)
{
@@ -118,123 +116,6 @@ void opt_eqpmux(test_pmgen_pm &pm)
log(" -> %s (%s)\n", log_id(c), log_id(c->type));
}
-#define GENERATE_PATTERN(pmclass, pattern) \
- generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design)
-
-void pmtest_addports(Module *module)
-{
- pool<SigBit> driven_bits, used_bits;
- SigMap sigmap(module);
- int icnt = 0, ocnt = 0;
-
- for (auto cell : module->cells())
- for (auto conn : cell->connections())
- {
- if (cell->input(conn.first))
- for (auto bit : sigmap(conn.second))
- used_bits.insert(bit);
- if (cell->output(conn.first))
- for (auto bit : sigmap(conn.second))
- driven_bits.insert(bit);
- }
-
- for (auto wire : vector<Wire*>(module->wires()))
- {
- SigSpec ibits, obits;
- for (auto bit : sigmap(wire)) {
- if (!used_bits.count(bit))
- obits.append(bit);
- if (!driven_bits.count(bit))
- ibits.append(bit);
- }
- if (!ibits.empty()) {
- Wire *w = module->addWire(stringf("\\i%d", icnt++), GetSize(ibits));
- w->port_input = true;
- module->connect(ibits, w);
- }
- if (!obits.empty()) {
- Wire *w = module->addWire(stringf("\\o%d", ocnt++), GetSize(obits));
- w->port_output = true;
- module->connect(w, obits);
- }
- }
-
- module->fixup_ports();
-}
-
-template <class pm>
-void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const char *pmclass, const char *pattern, Design *design)
-{
- log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass);
-
- int modcnt = 0;
- int maxmodcnt = 100;
- int maxsubcnt = 4;
- int timeout = 0;
- vector<Module*> mods;
-
- while (modcnt < maxmodcnt)
- {
- int submodcnt = 0, itercnt = 0, cellcnt = 0;
- Module *mod = design->addModule(NEW_ID);
-
- while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000)
- {
- if (timeout++ > 10000)
- log_error("pmgen generator is stuck: 10000 iterations with no matching module generated.\n");
-
- pm matcher(mod, mod->cells());
-
- matcher.rng(1);
- matcher.rngseed += modcnt;
- matcher.rng(1);
- matcher.rngseed += submodcnt;
- matcher.rng(1);
- matcher.rngseed += itercnt;
- matcher.rng(1);
- matcher.rngseed += cellcnt;
- matcher.rng(1);
-
- if (GetSize(mod->cells()) != cellcnt)
- {
- bool found_match = false;
- run(matcher, [&](){ found_match = true; });
- cellcnt = GetSize(mod->cells());
-
- if (found_match) {
- Module *m = design->addModule(stringf("\\pmtest_%s_%s_%05d",
- pmclass, pattern, modcnt++));
- log("Creating module %s with %d cells.\n", log_id(m), cellcnt);
- mod->cloneInto(m);
- pmtest_addports(m);
- mods.push_back(m);
- submodcnt++;
- timeout = 0;
- }
- }
-
- matcher.generate_mode = true;
- run(matcher, [](){});
- }
-
- if (submodcnt && maxsubcnt < (1 << 16))
- maxsubcnt *= 2;
-
- design->remove(mod);
- }
-
- Module *m = design->addModule(stringf("\\pmtest_%s_%s", pmclass, pattern));
- log("Creating module %s with %d cells.\n", log_id(m), GetSize(mods));
- for (auto mod : mods) {
- Cell *c = m->addCell(mod->name, mod->name);
- for (auto port : mod->ports) {
- Wire *w = m->addWire(NEW_ID, GetSize(mod->wire(port)));
- c->setPort(port, w);
- }
- }
- pmtest_addports(m);
-}
-
struct TestPmgenPass : public Pass {
TestPmgenPass() : Pass("test_pmgen", "test pass for pmgen") { }
void help() YS_OVERRIDE
@@ -355,12 +236,6 @@ struct TestPmgenPass : public Pass {
if (pattern == "xilinx_srl.variable")
return GENERATE_PATTERN(xilinx_srl_pm, variable);
- if (pattern == "peepopt-muldiv")
- return GENERATE_PATTERN(peepopt_pm, muldiv);
-
- if (pattern == "peepopt-shiftmul")
- return GENERATE_PATTERN(peepopt_pm, shiftmul);
-
log_cmd_error("Unknown pattern: %s\n", pattern.c_str());
}
diff --git a/passes/pmgen/xilinx_dsp.pmg b/passes/pmgen/xilinx_dsp.pmg
index 604aa222b..0ba529011 100644
--- a/passes/pmgen/xilinx_dsp.pmg
+++ b/passes/pmgen/xilinx_dsp.pmg
@@ -98,16 +98,16 @@ code sigA sigB sigC sigD sigM clock
if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") {
// Only care about those bits that are used
int i;
- for (i = 0; i < GetSize(P); i++) {
- if (nusers(P[i]) <= 1)
+ for (i = GetSize(P)-1; i >= 0; i--)
+ if (nusers(P[i]) > 1)
break;
- sigM.append(P[i]);
- }
+ i++;
log_assert(nusers(P.extract_end(i)) <= 1);
// This sigM could have no users if downstream sinks (e.g. $add) is
// narrower than $mul result, for example
- if (sigM.empty())
+ if (i == 0)
reject;
+ sigM = P.extract(0, i);
}
else
sigM = P;
@@ -460,6 +460,8 @@ arg argD argQ clock
code
dff = nullptr;
+ if (GetSize(argQ) == 0)
+ reject;
for (const auto &c : argQ.chunks()) {
// Abandon matches when 'Q' is a constant
if (!c.wire)
diff --git a/passes/pmgen/xilinx_dsp_CREG.pmg b/passes/pmgen/xilinx_dsp_CREG.pmg
index a57043009..5cd34162e 100644
--- a/passes/pmgen/xilinx_dsp_CREG.pmg
+++ b/passes/pmgen/xilinx_dsp_CREG.pmg
@@ -63,12 +63,12 @@ code sigC sigP clock
if (param(dsp, \USE_MULT, Const("MULTIPLY")).decode_string() == "MULTIPLY") {
// Only care about those bits that are used
int i;
- for (i = 0; i < GetSize(P); i++) {
- if (nusers(P[i]) <= 1)
+ for (i = GetSize(P)-1; i >= 0; i--)
+ if (nusers(P[i]) > 1)
break;
- sigP.append(P[i]);
- }
+ i++;
log_assert(nusers(P.extract_end(i)) <= 1);
+ sigP = P.extract(0, i);
}
else
sigP = P;
diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc
index 29700c37b..9f3bb525b 100644
--- a/passes/techmap/extract_fa.cc
+++ b/passes/techmap/extract_fa.cc
@@ -262,10 +262,14 @@ struct ExtractFaWorker
pool<SigBit> new_leaves = leaves;
new_leaves.erase(bit);
- if (cell->hasPort(ID::A)) new_leaves.insert(sigmap(SigBit(cell->getPort(ID::A))));
- if (cell->hasPort(ID::B)) new_leaves.insert(sigmap(SigBit(cell->getPort(ID::B))));
- if (cell->hasPort(ID(C))) new_leaves.insert(sigmap(SigBit(cell->getPort(ID(C)))));
- if (cell->hasPort(ID(D))) new_leaves.insert(sigmap(SigBit(cell->getPort(ID(D)))));
+ for (auto port : {ID::A, ID::B, ID(C), ID(D)}) {
+ if (!cell->hasPort(port))
+ continue;
+ auto bit = sigmap(SigBit(cell->getPort(port)));
+ if (!bit.wire)
+ continue;
+ new_leaves.insert(bit);
+ }
if (GetSize(new_leaves) > maxbreadth)
continue;
diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc
index 5807178dd..a2ad87f7d 100644
--- a/passes/techmap/flowmap.cc
+++ b/passes/techmap/flowmap.cc
@@ -394,7 +394,7 @@ struct FlowGraph
pair<pool<RTLIL::SigBit>, pool<RTLIL::SigBit>> edge_cut()
{
- pool<RTLIL::SigBit> x, xi;
+ pool<RTLIL::SigBit> x = {source}, xi; // X and X̅ in the paper
NodePrime source_prime = {source, true};
pool<NodePrime> visited;
@@ -437,6 +437,7 @@ struct FlowGraph
for (auto collapsed_node : collapsed[sink])
xi.insert(collapsed_node);
+ log_assert(x[source] && !xi[source]);
log_assert(!x[sink] && xi[sink]);
return {x, xi};
}
@@ -1050,7 +1051,7 @@ struct FlowmapWorker
auto cut_inputs = cut_lut_at_gate(lut, lut_gate);
pool<RTLIL::SigBit> gate_inputs = cut_inputs.first, other_inputs = cut_inputs.second;
- if (gate_inputs.empty() && (int)other_inputs.size() == order)
+ if (gate_inputs.empty() && (int)other_inputs.size() >= order)
{
if (debug_relax)
log(" Breaking would result in a (k+1)-LUT.\n");