diff options
Diffstat (limited to 'passes')
-rw-r--r-- | passes/cmds/Makefile.inc | 1 | ||||
-rw-r--r-- | passes/cmds/autoname.cc | 134 | ||||
-rw-r--r-- | passes/fsm/fsm_detect.cc | 16 | ||||
-rw-r--r-- | passes/opt/wreduce.cc | 14 | ||||
-rw-r--r-- | passes/pmgen/Makefile.inc | 4 | ||||
-rw-r--r-- | passes/pmgen/generate.h | 140 | ||||
-rw-r--r-- | passes/pmgen/peepopt.cc | 76 | ||||
-rw-r--r-- | passes/pmgen/peepopt_dffmux.pmg | 64 | ||||
-rw-r--r-- | passes/pmgen/pmgen.py | 16 | ||||
-rw-r--r-- | passes/pmgen/test_pmgen.cc | 129 | ||||
-rw-r--r-- | passes/pmgen/xilinx_dsp.pmg | 12 | ||||
-rw-r--r-- | passes/pmgen/xilinx_dsp_CREG.pmg | 8 | ||||
-rw-r--r-- | passes/techmap/extract_fa.cc | 12 | ||||
-rw-r--r-- | passes/techmap/flowmap.cc | 5 |
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"); |