diff options
Diffstat (limited to 'passes/techmap')
-rw-r--r-- | passes/techmap/Makefile.inc | 13 | ||||
-rw-r--r-- | passes/techmap/alumacc.cc | 92 | ||||
-rw-r--r-- | passes/techmap/dff2dffe.cc | 337 | ||||
-rw-r--r-- | passes/techmap/dfflibmap.cc | 113 | ||||
-rw-r--r-- | passes/techmap/extract.cc | 534 | ||||
-rw-r--r-- | passes/techmap/hilomap.cc | 10 | ||||
-rw-r--r-- | passes/techmap/iopadmap.cc | 23 | ||||
-rw-r--r-- | passes/techmap/libparse.cc | 45 | ||||
-rw-r--r-- | passes/techmap/libparse.h | 2 | ||||
-rw-r--r-- | passes/techmap/maccmap.cc | 84 | ||||
-rw-r--r-- | passes/techmap/simplemap.cc | 121 | ||||
-rw-r--r-- | passes/techmap/simplemap.h | 48 | ||||
-rw-r--r-- | passes/techmap/techmap.cc | 140 |
13 files changed, 1062 insertions, 500 deletions
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 72998f87b..6b6846e20 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -2,14 +2,15 @@ OBJS += passes/techmap/techmap.o OBJS += passes/techmap/simplemap.o OBJS += passes/techmap/dfflibmap.o +OBJS += passes/techmap/maccmap.o OBJS += passes/techmap/libparse.o ifneq ($(SMALL),1) OBJS += passes/techmap/iopadmap.o OBJS += passes/techmap/hilomap.o OBJS += passes/techmap/extract.o -OBJS += passes/techmap/maccmap.o OBJS += passes/techmap/alumacc.o +OBJS += passes/techmap/dff2dffe.o endif GENFILES += passes/techmap/techmap.inc @@ -23,9 +24,11 @@ passes/techmap/techmap.inc: techlibs/common/techmap.v passes/techmap/techmap.o: passes/techmap/techmap.inc -TARGETS += yosys-filterlib -GENFILES += passes/techmap/filterlib.o +ifneq ($(CONFIG),emcc) +TARGETS += yosys-filterlib$(EXE) +EXTRA_OBJS += passes/techmap/filterlib.o -yosys-filterlib: passes/techmap/filterlib.o - $(P) $(CXX) -o yosys-filterlib $(LDFLAGS) $^ $(LDLIBS) +yosys-filterlib$(EXE): passes/techmap/filterlib.o + $(P) $(CXX) -o yosys-filterlib$(EXE) $(LDFLAGS) $^ $(LDLIBS) +endif diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index 1115eead5..dcffed94d 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -21,6 +21,9 @@ #include "kernel/sigtools.h" #include "kernel/macc.h" +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + struct AlumaccWorker { RTLIL::Module *module; @@ -45,51 +48,51 @@ struct AlumaccWorker RTLIL::SigSpec cached_cf, cached_of, cached_sf; RTLIL::SigSpec get_lt() { - if (SIZE(cached_lt) == 0) + if (GetSize(cached_lt) == 0) cached_lt = is_signed ? alu_cell->module->Xor(NEW_ID, get_of(), get_sf()) : get_cf(); return cached_lt; } RTLIL::SigSpec get_gt() { - if (SIZE(cached_gt) == 0) + if (GetSize(cached_gt) == 0) cached_gt = alu_cell->module->Not(NEW_ID, alu_cell->module->Or(NEW_ID, get_lt(), get_eq())); return cached_gt; } RTLIL::SigSpec get_eq() { - if (SIZE(cached_eq) == 0) + if (GetSize(cached_eq) == 0) cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort("\\X")); return cached_eq; } RTLIL::SigSpec get_ne() { - if (SIZE(cached_ne) == 0) + if (GetSize(cached_ne) == 0) cached_ne = alu_cell->module->Not(NEW_ID, get_eq()); return cached_ne; } RTLIL::SigSpec get_cf() { - if (SIZE(cached_cf) == 0) { + if (GetSize(cached_cf) == 0) { cached_cf = alu_cell->getPort("\\CO"); - log_assert(SIZE(cached_cf) >= 1); - cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[SIZE(cached_cf)-1]); + log_assert(GetSize(cached_cf) >= 1); + cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[GetSize(cached_cf)-1]); } return cached_cf; } RTLIL::SigSpec get_of() { - if (SIZE(cached_of) == 0) { + if (GetSize(cached_of) == 0) { cached_of = {alu_cell->getPort("\\CO"), alu_cell->getPort("\\CI")}; - log_assert(SIZE(cached_of) >= 2); - cached_of = alu_cell->module->Xor(NEW_ID, cached_of[SIZE(cached_of)-1], cached_of[SIZE(cached_of)-2]); + log_assert(GetSize(cached_of) >= 2); + cached_of = alu_cell->module->Xor(NEW_ID, cached_of[GetSize(cached_of)-1], cached_of[GetSize(cached_of)-2]); } return cached_of; } RTLIL::SigSpec get_sf() { - if (SIZE(cached_sf) == 0) { + if (GetSize(cached_sf) == 0) { cached_sf = alu_cell->getPort("\\Y"); - cached_sf = cached_sf[SIZE(cached_sf)-1]; + cached_sf = cached_sf[GetSize(cached_sf)-1]; } return cached_sf; } @@ -181,10 +184,10 @@ struct AlumaccWorker return true; if (!port.is_signed && port.do_subtract) return true; - if (SIZE(port.in_b)) - port_sizes.push_back(SIZE(port.in_a) + SIZE(port.in_b)); + if (GetSize(port.in_b)) + port_sizes.push_back(GetSize(port.in_a) + GetSize(port.in_b)); else - port_sizes.push_back(SIZE(port.in_a)); + port_sizes.push_back(GetSize(port.in_a)); } std::sort(port_sizes.begin(), port_sizes.end()); @@ -221,11 +224,11 @@ struct AlumaccWorker if (delete_nodes.count(n)) continue; - for (int i = 0; i < SIZE(n->macc.ports); i++) + for (int i = 0; i < GetSize(n->macc.ports); i++) { auto &port = n->macc.ports[i]; - if (SIZE(port.in_b) > 0 || sig_macc.count(port.in_a) == 0) + if (GetSize(port.in_b) > 0 || sig_macc.count(port.in_a) == 0) continue; auto other_n = sig_macc.at(port.in_a); @@ -233,13 +236,13 @@ struct AlumaccWorker if (other_n->users > 1) continue; - if (SIZE(other_n->y) != SIZE(n->y) && macc_may_overflow(other_n->macc, SIZE(other_n->y), port.is_signed)) + if (GetSize(other_n->y) != GetSize(n->y) && macc_may_overflow(other_n->macc, GetSize(other_n->y), port.is_signed)) continue; log(" merging $macc model for %s into %s.\n", log_id(other_n->cell), log_id(n->cell)); bool do_subtract = port.do_subtract; - for (int j = 0; j < SIZE(other_n->macc.ports); j++) { + for (int j = 0; j < GetSize(other_n->macc.ports); j++) { if (do_subtract) other_n->macc.ports[j].do_subtract = !other_n->macc.ports[j].do_subtract; if (j == 0) @@ -275,38 +278,38 @@ struct AlumaccWorker alunode_t *alunode; for (auto &port : n->macc.ports) - if (SIZE(port.in_b) > 0) { + if (GetSize(port.in_b) > 0) { goto next_macc; - } else if (SIZE(port.in_a) == 1 && !port.is_signed && !port.do_subtract) { + } else if (GetSize(port.in_a) == 1 && !port.is_signed && !port.do_subtract) { C.append(port.in_a); - } else if (SIZE(A) || port.do_subtract) { - if (SIZE(B)) + } else if (GetSize(A) || port.do_subtract) { + if (GetSize(B)) goto next_macc; B = port.in_a; b_signed = port.is_signed; subtract_b = port.do_subtract; } else { - if (SIZE(A)) + if (GetSize(A)) goto next_macc; A = port.in_a; a_signed = port.is_signed; } if (!a_signed || !b_signed) { - if (SIZE(A) == SIZE(n->y)) + if (GetSize(A) == GetSize(n->y)) a_signed = false; - if (SIZE(B) == SIZE(n->y)) + if (GetSize(B) == GetSize(n->y)) b_signed = false; if (a_signed != b_signed) goto next_macc; } - if (SIZE(A) == 0 && SIZE(C) > 0) { + if (GetSize(A) == 0 && GetSize(C) > 0) { A = C[0]; C.remove(0); } - if (SIZE(B) == 0 && SIZE(C) > 0) { + if (GetSize(B) == 0 && GetSize(C) > 0) { B = C[0]; C.remove(0); } @@ -314,10 +317,10 @@ struct AlumaccWorker if (subtract_b) C.append(RTLIL::S1); - if (SIZE(C) > 1) + if (GetSize(C) > 1) goto next_macc; - if (!subtract_b && B < A && SIZE(B)) + if (!subtract_b && B < A && GetSize(B)) std::swap(A, B); log(" creating $alu model for $macc %s.\n", log_id(n->cell)); @@ -353,7 +356,7 @@ struct AlumaccWorker log(" creating $macc cell for %s: %s\n", log_id(n->cell), log_id(cell)); - n->macc.optimize(SIZE(n->y)); + n->macc.optimize(GetSize(n->y)); n->macc.to_cell(cell); cell->setPort("\\Y", n->y); cell->fixup_parameters(); @@ -388,7 +391,7 @@ struct AlumaccWorker RTLIL::SigSpec B = sigmap(cell->getPort("\\B")); RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y")); - if (B < A && SIZE(B)) { + if (B < A && GetSize(B)) { cmp_less = !cmp_less; std::swap(A, B); } @@ -406,7 +409,7 @@ struct AlumaccWorker n->a = A; n->b = B; n->c = RTLIL::S1; - n->y = module->addWire(NEW_ID, std::max(SIZE(A), SIZE(B))); + n->y = module->addWire(NEW_ID, std::max(GetSize(A), GetSize(B))); n->is_signed = is_signed; n->invert_b = true; sig_alu[RTLIL::SigSig(A, B)].insert(n); @@ -428,7 +431,7 @@ struct AlumaccWorker RTLIL::SigSpec B = sigmap(cell->getPort("\\B")); RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y")); - if (B < A && SIZE(B)) + if (B < A && GetSize(B)) std::swap(A, B); alunode_t *n = nullptr; @@ -452,12 +455,12 @@ struct AlumaccWorker for (auto &it1 : sig_alu) for (auto n : it1.second) { - if (SIZE(n->b) == 0 && SIZE(n->c) == 0 && SIZE(n->cmp) == 0) + if (GetSize(n->b) == 0 && GetSize(n->c) == 0 && GetSize(n->cmp) == 0) { n->alu_cell = module->addPos(NEW_ID, n->a, n->y, n->is_signed); log(" creating $pos cell for "); - for (int i = 0; i < SIZE(n->cells); i++) + for (int i = 0; i < GetSize(n->cells); i++) log("%s%s", i ? ", ": "", log_id(n->cells[i])); log(": %s\n", log_id(n->alu_cell)); @@ -468,17 +471,17 @@ struct AlumaccWorker alu_counter++; log(" creating $alu cell for "); - for (int i = 0; i < SIZE(n->cells); i++) + for (int i = 0; i < GetSize(n->cells); i++) log("%s%s", i ? ", ": "", log_id(n->cells[i])); log(": %s\n", log_id(n->alu_cell)); n->alu_cell->setPort("\\A", n->a); n->alu_cell->setPort("\\B", n->b); - n->alu_cell->setPort("\\CI", SIZE(n->c) ? n->c : RTLIL::S0); + n->alu_cell->setPort("\\CI", GetSize(n->c) ? n->c : RTLIL::S0); n->alu_cell->setPort("\\BI", n->invert_b ? RTLIL::S1 : RTLIL::S0); n->alu_cell->setPort("\\Y", n->y); - n->alu_cell->setPort("\\X", module->addWire(NEW_ID, SIZE(n->y))); - n->alu_cell->setPort("\\CO", module->addWire(NEW_ID, SIZE(n->y))); + n->alu_cell->setPort("\\X", module->addWire(NEW_ID, GetSize(n->y))); + n->alu_cell->setPort("\\CO", module->addWire(NEW_ID, GetSize(n->y))); n->alu_cell->fixup_parameters(n->is_signed, n->is_signed); for (auto &it : n->cmp) @@ -495,10 +498,10 @@ struct AlumaccWorker if (cmp_eq) sig.append(n->get_eq()); if (cmp_ne) sig.append(n->get_ne()); - if (SIZE(sig) > 1) + if (GetSize(sig) > 1) sig = module->ReduceOr(NEW_ID, sig); - sig.extend(SIZE(cmp_y)); + sig.extend_u0(GetSize(cmp_y)); module->connect(cmp_y, sig); } @@ -535,8 +538,8 @@ struct AlumaccPass : public Pass { log("\n"); log(" alumacc [selection]\n"); log("\n"); - log("This pass translates arithmetic operations $add, $mul, $lt, etc. to $alu and\n"); - log("$macc cells.\n"); + log("This pass translates arithmetic operations like $add, $mul, $lt, etc. to $alu\n"); + log("and $macc cells.\n"); log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) @@ -561,3 +564,4 @@ struct AlumaccPass : public Pass { } } AlumaccPass; +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc new file mode 100644 index 000000000..17549bd06 --- /dev/null +++ b/passes/techmap/dff2dffe.cc @@ -0,0 +1,337 @@ +/* + * 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" +#include "kernel/sigtools.h" +#include "kernel/celltypes.h" +#include "passes/techmap/simplemap.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct Dff2dffeWorker +{ + RTLIL::Module *module; + SigMap sigmap; + CellTypes ct; + + RTLIL::IdString direct_to; + + typedef std::pair<RTLIL::Cell*, int> cell_int_t; + std::map<RTLIL::SigBit, cell_int_t> bit2mux; + std::vector<RTLIL::Cell*> dff_cells; + std::map<RTLIL::SigBit, int> bitusers; + + typedef std::map<RTLIL::SigBit, bool> pattern_t; + typedef std::set<pattern_t> patterns_t; + + + Dff2dffeWorker(RTLIL::Module *module, RTLIL::IdString direct_from, RTLIL::IdString direct_to) : + module(module), sigmap(module), ct(module->design), direct_to(direct_to) + { + for (auto wire : module->wires()) { + if (wire->port_output) + for (auto bit : sigmap(wire)) + bitusers[bit]++; + } + + for (auto cell : module->cells()) { + if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_") { + RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y")); + for (int i = 0; i < GetSize(sig_y); i++) + bit2mux[sig_y[i]] = cell_int_t(cell, i); + } + if (direct_to.empty()) { + if (cell->type == "$dff" || cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_") + dff_cells.push_back(cell); + } else { + if (cell->type == direct_from) + dff_cells.push_back(cell); + } + for (auto conn : cell->connections()) { + if (ct.cell_output(cell->type, conn.first)) + continue; + for (auto bit : sigmap(conn.second)) + bitusers[bit]++; + } + } + } + + patterns_t find_muxtree_feedback_patterns(RTLIL::SigBit d, RTLIL::SigBit q, pattern_t path) + { + patterns_t ret; + + if (d == q) { + ret.insert(path); + return ret; + } + + if (bit2mux.count(d) == 0 || bitusers[d] > 1) + return ret; + + cell_int_t mux_cell_int = bit2mux.at(d); + RTLIL::SigSpec sig_a = sigmap(mux_cell_int.first->getPort("\\A")); + RTLIL::SigSpec sig_b = sigmap(mux_cell_int.first->getPort("\\B")); + RTLIL::SigSpec sig_s = sigmap(mux_cell_int.first->getPort("\\S")); + int width = GetSize(sig_a), index = mux_cell_int.second; + + for (int i = 0; i < GetSize(sig_s); i++) + if (path.count(sig_s[i]) && path.at(sig_s[i])) + { + ret = find_muxtree_feedback_patterns(sig_b[i*width + index], q, path); + + if (sig_b[i*width + index] == q) { + RTLIL::SigSpec s = mux_cell_int.first->getPort("\\B"); + s[i*width + index] = RTLIL::Sx; + mux_cell_int.first->setPort("\\B", s); + } + + return ret; + } + + pattern_t path_else = path; + + for (int i = 0; i < GetSize(sig_s); i++) + { + if (path.count(sig_s[i])) + continue; + + pattern_t path_this = path; + path_else[sig_s[i]] = false; + path_this[sig_s[i]] = true; + + for (auto &pat : find_muxtree_feedback_patterns(sig_b[i*width + index], q, path_this)) + ret.insert(pat); + + if (sig_b[i*width + index] == q) { + RTLIL::SigSpec s = mux_cell_int.first->getPort("\\B"); + s[i*width + index] = RTLIL::Sx; + mux_cell_int.first->setPort("\\B", s); + } + } + + for (auto &pat : find_muxtree_feedback_patterns(sig_a[index], q, path_else)) + ret.insert(pat); + + if (sig_a[index] == q) { + RTLIL::SigSpec s = mux_cell_int.first->getPort("\\A"); + s[index] = RTLIL::Sx; + mux_cell_int.first->setPort("\\A", s); + } + + return ret; + } + + void simplify_patterns(patterns_t&) + { + // TBD + } + + RTLIL::SigSpec make_patterns_logic(patterns_t patterns, bool make_gates) + { + RTLIL::SigSpec or_input; + + for (auto pat : patterns) + { + RTLIL::SigSpec s1, s2; + for (auto it : pat) { + s1.append(it.first); + s2.append(it.second); + } + + RTLIL::SigSpec y = module->addWire(NEW_ID); + RTLIL::Cell *c = module->addNe(NEW_ID, s1, s2, y); + + if (make_gates) { + simplemap(module, c); + module->remove(c); + } + + or_input.append(y); + } + + if (GetSize(or_input) == 0) + return RTLIL::S1; + + if (GetSize(or_input) == 1) + return or_input; + + RTLIL::SigSpec y = module->addWire(NEW_ID); + RTLIL::Cell *c = module->addReduceAnd(NEW_ID, or_input, y); + + if (make_gates) { + simplemap(module, c); + module->remove(c); + } + + return y; + } + + void handle_dff_cell(RTLIL::Cell *dff_cell) + { + RTLIL::SigSpec sig_d = sigmap(dff_cell->getPort("\\D")); + RTLIL::SigSpec sig_q = sigmap(dff_cell->getPort("\\Q")); + + std::map<patterns_t, std::set<int>> grouped_patterns; + std::set<int> remaining_indices; + + for (int i = 0 ; i < GetSize(sig_d); i++) { + patterns_t patterns = find_muxtree_feedback_patterns(sig_d[i], sig_q[i], pattern_t()); + if (!patterns.empty()) { + simplify_patterns(patterns); + grouped_patterns[patterns].insert(i); + } else + remaining_indices.insert(i); + } + + for (auto &it : grouped_patterns) { + RTLIL::SigSpec new_sig_d, new_sig_q; + for (int i : it.second) { + new_sig_d.append(sig_d[i]); + new_sig_q.append(sig_q[i]); + } + if (!direct_to.empty()) { + log(" converting %s cell %s to %s for %s -> %s.\n", log_id(dff_cell->type), log_id(dff_cell), log_id(direct_to), log_signal(new_sig_d), log_signal(new_sig_q)); + dff_cell->setPort("\\E", make_patterns_logic(it.first, true)); + dff_cell->type = direct_to; + } else + if (dff_cell->type == "$dff") { + RTLIL::Cell *new_cell = module->addDffe(NEW_ID, dff_cell->getPort("\\CLK"), make_patterns_logic(it.first, false), + new_sig_d, new_sig_q, dff_cell->getParam("\\CLK_POLARITY").as_bool(), true); + log(" created $dffe cell %s for %s -> %s.\n", log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q)); + } else { + RTLIL::Cell *new_cell = module->addDffeGate(NEW_ID, dff_cell->getPort("\\C"), make_patterns_logic(it.first, true), + new_sig_d, new_sig_q, dff_cell->type == "$_DFF_P_", true); + log(" created %s cell %s for %s -> %s.\n", log_id(new_cell->type), log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q)); + } + } + + if (!direct_to.empty()) + return; + + if (remaining_indices.empty()) { + log(" removing now obsolete cell %s.\n", log_id(dff_cell)); + module->remove(dff_cell); + } else if (GetSize(remaining_indices) != GetSize(sig_d)) { + log(" removing %d now obsolete bits from cell %s.\n", GetSize(sig_d) - GetSize(remaining_indices), log_id(dff_cell)); + RTLIL::SigSpec new_sig_d, new_sig_q; + for (int i : remaining_indices) { + new_sig_d.append(sig_d[i]); + new_sig_q.append(sig_q[i]); + } + dff_cell->setPort("\\D", new_sig_d); + dff_cell->setPort("\\Q", new_sig_q); + dff_cell->setParam("\\WIDTH", GetSize(remaining_indices)); + } + } + + void run() + { + log("Transforming $dff to $dffe cells in module %s:\n", log_id(module)); + for (auto dff_cell : dff_cells) + handle_dff_cell(dff_cell); + } +}; + +struct Dff2dffePass : public Pass { + Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" dff2dffe [selection]\n"); + log("\n"); + log("This pass transforms $dff cells driven by a tree of multiplexers with one or\n"); + log("more feedback paths to $dffe cells. It also works on gate-level cells such as\n"); + log("$_DFF_P_, $_DFF_N_ and $_MUX_.\n"); + log("\n"); + log(" -unmap\n"); + log(" operate in the opposite direction: replace $dffe cells with combinations\n"); + log(" of $dff and $mux cells. the options below are ignore in unmap mode.\n"); + log("\n"); + log(" -direct <internal_gate_type> <external_gate_type>\n"); + log(" map directly to external gate type. <internal_gate_type> can\n"); + log(" be any internal gate-level FF cell (except $_DFFE_??_). the\n"); + log(" <external_gate_type> is the cell type name for a cell with an\n"); + log(" identical interface to the <internal_gate_type>, except it\n"); + log(" also has an high-active enable port 'E'.\n"); + log(" Usually <external_gate_type> is an intemediate cell type\n"); + log(" that is then translated to the final type using 'techmap'.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + log_header("Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n"); + + bool unmap_mode = false; + RTLIL::IdString direct_from, direct_to; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-unmap") { + unmap_mode = true; + continue; + } + if (args[argidx] == "-direct" && argidx + 2 < args.size()) { + direct_from = RTLIL::escape_id(args[++argidx]); + direct_to = RTLIL::escape_id(args[++argidx]); + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto mod : design->selected_modules()) + if (!mod->has_processes_warn()) + { + if (unmap_mode) { + for (auto cell : mod->selected_cells()) { + if (cell->type == "$dffe") { + RTLIL::SigSpec tmp = mod->addWire(NEW_ID, GetSize(cell->getPort("\\D"))); + mod->addDff(NEW_ID, cell->getPort("\\CLK"), tmp, cell->getPort("\\Q"), cell->getParam("\\CLK_POLARITY").as_bool()); + if (cell->getParam("\\EN_POLARITY").as_bool()) + mod->addMux(NEW_ID, cell->getPort("\\Q"), cell->getPort("\\D"), cell->getPort("\\EN"), tmp); + else + mod->addMux(NEW_ID, cell->getPort("\\D"), cell->getPort("\\Q"), cell->getPort("\\EN"), tmp); + mod->remove(cell); + continue; + } + if (cell->type.substr(0, 7) == "$_DFFE_") { + bool clk_pol = cell->type.substr(7, 1) == "P"; + bool en_pol = cell->type.substr(8, 1) == "P"; + RTLIL::SigSpec tmp = mod->addWire(NEW_ID); + mod->addDff(NEW_ID, cell->getPort("\\C"), tmp, cell->getPort("\\Q"), clk_pol); + if (en_pol) + mod->addMux(NEW_ID, cell->getPort("\\Q"), cell->getPort("\\D"), cell->getPort("\\E"), tmp); + else + mod->addMux(NEW_ID, cell->getPort("\\D"), cell->getPort("\\Q"), cell->getPort("\\E"), tmp); + mod->remove(cell); + continue; + } + } + continue; + } + + Dff2dffeWorker worker(mod, direct_from, direct_to); + worker.run(); + } + } +} Dff2dffePass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index 07993b868..b0318a0b3 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -23,7 +23,8 @@ #include <string.h> #include <errno.h> -using namespace PASS_DFFLIBMAP; +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN struct cell_mapping { std::string cell_name; @@ -102,12 +103,12 @@ static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name, return false; } -static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval) +static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode) { LibertyAst *best_cell = NULL; std::map<std::string, char> best_cell_ports; int best_cell_pins = 0; - float best_cell_area = 0; + double best_cell_area = 0; if (ast->id != "library") log_error("Format error in liberty file.\n"); @@ -143,7 +144,7 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool this_cell_ports[cell_rst_pin] = 'R'; this_cell_ports[cell_next_pin] = 'D'; - float area = 0; + double area = 0; LibertyAst *ar = cell->find("area"); if (ar != NULL && !ar->value.empty()) area = atof(ar->value.c_str()); @@ -192,18 +193,27 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool } if (best_cell != NULL) { - log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.substr(1).c_str()); - cell_mappings[cell_type].cell_name = best_cell->args[0]; - cell_mappings[cell_type].ports = best_cell_ports; + log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.c_str()); + if (prepare_mode) { + cell_mappings[cell_type].cell_name = cell_type; + cell_mappings[cell_type].ports["C"] = 'C'; + if (has_reset) + cell_mappings[cell_type].ports["R"] = 'R'; + cell_mappings[cell_type].ports["D"] = 'D'; + cell_mappings[cell_type].ports["Q"] = 'Q'; + } else { + cell_mappings[cell_type].cell_name = best_cell->args[0]; + cell_mappings[cell_type].ports = best_cell_ports; + } } } -static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bool setpol, bool clrpol) +static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode) { LibertyAst *best_cell = NULL; std::map<std::string, char> best_cell_ports; int best_cell_pins = 0; - float best_cell_area = 0; + double best_cell_area = 0; if (ast->id != "library") log_error("Format error in liberty file.\n"); @@ -235,7 +245,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo this_cell_ports[cell_clr_pin] = 'R'; this_cell_ports[cell_next_pin] = 'D'; - float area = 0; + double area = 0; LibertyAst *ar = cell->find("area"); if (ar != NULL && !ar->value.empty()) area = atof(ar->value.c_str()); @@ -284,9 +294,18 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo } if (best_cell != NULL) { - log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.substr(1).c_str()); - cell_mappings[cell_type].cell_name = best_cell->args[0]; - cell_mappings[cell_type].ports = best_cell_ports; + log(" cell %s (pins=%d, area=%.2f) is a direct match for cell type %s.\n", best_cell->args[0].c_str(), best_cell_pins, best_cell_area, cell_type.c_str()); + if (prepare_mode) { + cell_mappings[cell_type].cell_name = cell_type; + cell_mappings[cell_type].ports["C"] = 'C'; + cell_mappings[cell_type].ports["S"] = 'S'; + cell_mappings[cell_type].ports["R"] = 'R'; + cell_mappings[cell_type].ports["D"] = 'D'; + cell_mappings[cell_type].ports["Q"] = 'Q'; + } else { + cell_mappings[cell_type].cell_name = best_cell->args[0]; + cell_mappings[cell_type].ports = best_cell_ports; + } } } @@ -346,8 +365,12 @@ static void map_sr_to_arst(const char *from, const char *to) if (!cell_mappings.count(from) || cell_mappings.count(to) > 0) return; - char from_clk_pol = from[8], from_set_pol = from[9], from_clr_pol = from[10]; - char to_clk_pol = to[6], to_rst_pol = to[7], to_rst_val = to[8]; + char from_clk_pol YS_ATTRIBUTE(unused) = from[8]; + char from_set_pol = from[9]; + char from_clr_pol = from[10]; + char to_clk_pol YS_ATTRIBUTE(unused) = to[6]; + char to_rst_pol YS_ATTRIBUTE(unused) = to[7]; + char to_rst_val = to[8]; log_assert(from_clk_pol == to_clk_pol); log_assert(to_rst_pol == from_set_pol && to_rst_pol == from_clr_pol); @@ -383,7 +406,7 @@ static void map_sr_to_arst(const char *from, const char *to) } } -static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module) +static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare_mode) { log("Mapping DFF cells in module `%s':\n", module->name.c_str()); @@ -402,7 +425,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module) module->remove(cell); cell_mapping &cm = cell_mappings[cell_type]; - RTLIL::Cell *new_cell = module->addCell(cell_name, "\\" + cm.cell_name); + RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : "\\" + cm.cell_name); for (auto &port : cm.ports) { RTLIL::SigSpec sig; @@ -411,7 +434,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module) } else if (port.second == 'q') { RTLIL::SigSpec old_sig = cell_connections[std::string("\\") + char(port.second - ('a' - 'A'))]; - sig = module->addWire(NEW_ID, SIZE(old_sig)); + sig = module->addWire(NEW_ID, GetSize(old_sig)); module->addNotGate(NEW_ID, sig, old_sig); } else if ('a' <= port.second && port.second <= 'z') { @@ -438,7 +461,7 @@ struct DfflibmapPass : public Pass { virtual void help() { log("\n"); - log(" dfflibmap -liberty <file> [selection]\n"); + log(" dfflibmap [-prepare] -liberty <file> [selection]\n"); log("\n"); log("Map internal flip-flop cells to the flip-flop cells in the technology\n"); log("library specified in the given liberty file.\n"); @@ -446,12 +469,17 @@ struct DfflibmapPass : public Pass { log("This pass may add inverters as needed. Therefore it is recommended to\n"); log("first run this pass and then map the logic paths to the target technology.\n"); log("\n"); + log("When called with -prepare, this command will convert the internal FF cells\n"); + log("to the internal cell types that best match the cells found in the given\n"); + log("liberty file.\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { log_header("Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n"); std::string liberty_file; + bool prepare_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -461,6 +489,10 @@ struct DfflibmapPass : public Pass { liberty_file = args[++argidx]; continue; } + if (arg == "-prepare") { + prepare_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -475,26 +507,26 @@ struct DfflibmapPass : public Pass { LibertyParser libparser(f); f.close(); - find_cell(libparser.ast, "$_DFF_N_", false, false, false, false); - find_cell(libparser.ast, "$_DFF_P_", true, false, false, false); - - find_cell(libparser.ast, "$_DFF_NN0_", false, true, false, false); - find_cell(libparser.ast, "$_DFF_NN1_", false, true, false, true); - find_cell(libparser.ast, "$_DFF_NP0_", false, true, true, false); - find_cell(libparser.ast, "$_DFF_NP1_", false, true, true, true); - find_cell(libparser.ast, "$_DFF_PN0_", true, true, false, false); - find_cell(libparser.ast, "$_DFF_PN1_", true, true, false, true); - find_cell(libparser.ast, "$_DFF_PP0_", true, true, true, false); - find_cell(libparser.ast, "$_DFF_PP1_", true, true, true, true); - - find_cell_sr(libparser.ast, "$_DFFSR_NNN_", false, false, false); - find_cell_sr(libparser.ast, "$_DFFSR_NNP_", false, false, true); - find_cell_sr(libparser.ast, "$_DFFSR_NPN_", false, true, false); - find_cell_sr(libparser.ast, "$_DFFSR_NPP_", false, true, true); - find_cell_sr(libparser.ast, "$_DFFSR_PNN_", true, false, false); - find_cell_sr(libparser.ast, "$_DFFSR_PNP_", true, false, true); - find_cell_sr(libparser.ast, "$_DFFSR_PPN_", true, true, false); - find_cell_sr(libparser.ast, "$_DFFSR_PPP_", true, true, true); + find_cell(libparser.ast, "$_DFF_N_", false, false, false, false, prepare_mode); + find_cell(libparser.ast, "$_DFF_P_", true, false, false, false, prepare_mode); + + find_cell(libparser.ast, "$_DFF_NN0_", false, true, false, false, prepare_mode); + find_cell(libparser.ast, "$_DFF_NN1_", false, true, false, true, prepare_mode); + find_cell(libparser.ast, "$_DFF_NP0_", false, true, true, false, prepare_mode); + find_cell(libparser.ast, "$_DFF_NP1_", false, true, true, true, prepare_mode); + find_cell(libparser.ast, "$_DFF_PN0_", true, true, false, false, prepare_mode); + find_cell(libparser.ast, "$_DFF_PN1_", true, true, false, true, prepare_mode); + find_cell(libparser.ast, "$_DFF_PP0_", true, true, true, false, prepare_mode); + find_cell(libparser.ast, "$_DFF_PP1_", true, true, true, true, prepare_mode); + + find_cell_sr(libparser.ast, "$_DFFSR_NNN_", false, false, false, prepare_mode); + find_cell_sr(libparser.ast, "$_DFFSR_NNP_", false, false, true, prepare_mode); + find_cell_sr(libparser.ast, "$_DFFSR_NPN_", false, true, false, prepare_mode); + find_cell_sr(libparser.ast, "$_DFFSR_NPP_", false, true, true, prepare_mode); + find_cell_sr(libparser.ast, "$_DFFSR_PNN_", true, false, false, prepare_mode); + find_cell_sr(libparser.ast, "$_DFFSR_PNP_", true, false, true, prepare_mode); + find_cell_sr(libparser.ast, "$_DFFSR_PPN_", true, true, false, prepare_mode); + find_cell_sr(libparser.ast, "$_DFFSR_PPP_", true, true, true, prepare_mode); // try to implement as many cells as possible just by inverting // the SET and RESET pins. If necessary, implement cell types @@ -532,9 +564,10 @@ struct DfflibmapPass : public Pass { for (auto &it : design->modules_) if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox")) - dfflibmap(design, it.second); + dfflibmap(design, it.second, prepare_mode); cell_mappings.clear(); } } DfflibmapPass; +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc index 221e9e49d..ff99040e1 100644 --- a/passes/techmap/extract.cc +++ b/passes/techmap/extract.cc @@ -26,256 +26,240 @@ #include <stdio.h> #include <string.h> +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + using RTLIL::id2cstr; -namespace +class SubCircuitSolver : public SubCircuit::Solver { - class SubCircuitSolver : public SubCircuit::Solver - { - public: - bool ignore_parameters; - std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> ignored_parameters; - std::set<RTLIL::IdString> cell_attr, wire_attr; +public: + bool ignore_parameters; + std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> ignored_parameters; + std::set<RTLIL::IdString> cell_attr, wire_attr; - SubCircuitSolver() : ignore_parameters(false) - { - } + SubCircuitSolver() : ignore_parameters(false) + { + } - bool compareAttributes(const std::set<RTLIL::IdString> &attr, const std::map<RTLIL::IdString, RTLIL::Const> &needleAttr, const std::map<RTLIL::IdString, RTLIL::Const> &haystackAttr) - { - for (auto &it : attr) { - size_t nc = needleAttr.count(it), hc = haystackAttr.count(it); - if (nc != hc || (nc > 0 && needleAttr.at(it) != haystackAttr.at(it))) - return false; - } - return true; + bool compareAttributes(const std::set<RTLIL::IdString> &attr, const dict<RTLIL::IdString, RTLIL::Const> &needleAttr, const dict<RTLIL::IdString, RTLIL::Const> &haystackAttr) + { + for (auto &it : attr) { + size_t nc = needleAttr.count(it), hc = haystackAttr.count(it); + if (nc != hc || (nc > 0 && needleAttr.at(it) != haystackAttr.at(it))) + return false; } + return true; + } - RTLIL::Const unified_param(RTLIL::IdString cell_type, RTLIL::IdString param, RTLIL::Const value) - { - if (cell_type.substr(0, 1) != "$" || cell_type.substr(0, 2) == "$_") - return value; - - #define param_bool(_n) if (param == _n) return value.as_bool(); - param_bool("\\ARST_POLARITY"); - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - param_bool("\\CLK_ENABLE"); - param_bool("\\CLK_POLARITY"); - param_bool("\\CLR_POLARITY"); - param_bool("\\EN_POLARITY"); - param_bool("\\SET_POLARITY"); - param_bool("\\TRANSPARENT"); - #undef param_bool - - #define param_int(_n) if (param == _n) return value.as_int(); - param_int("\\ABITS") - param_int("\\A_WIDTH") - param_int("\\B_WIDTH") - param_int("\\CTRL_IN_WIDTH") - param_int("\\CTRL_OUT_WIDTH") - param_int("\\OFFSET") - param_int("\\PRIORITY") - param_int("\\RD_PORTS") - param_int("\\SIZE") - param_int("\\STATE_BITS") - param_int("\\STATE_NUM") - param_int("\\STATE_NUM_LOG2") - param_int("\\STATE_RST") - param_int("\\S_WIDTH") - param_int("\\TRANS_NUM") - param_int("\\WIDTH") - param_int("\\WR_PORTS") - param_int("\\Y_WIDTH") - #undef param_int - + RTLIL::Const unified_param(RTLIL::IdString cell_type, RTLIL::IdString param, RTLIL::Const value) + { + if (cell_type.substr(0, 1) != "$" || cell_type.substr(0, 2) == "$_") return value; - } - virtual bool userCompareNodes(const std::string &, const std::string &, void *needleUserData, - const std::string &, const std::string &, void *haystackUserData, const std::map<std::string, std::string> &portMapping) - { - RTLIL::Cell *needleCell = (RTLIL::Cell*) needleUserData; - RTLIL::Cell *haystackCell = (RTLIL::Cell*) haystackUserData; + #define param_bool(_n) if (param == _n) return value.as_bool(); + param_bool("\\ARST_POLARITY"); + param_bool("\\A_SIGNED"); + param_bool("\\B_SIGNED"); + param_bool("\\CLK_ENABLE"); + param_bool("\\CLK_POLARITY"); + param_bool("\\CLR_POLARITY"); + param_bool("\\EN_POLARITY"); + param_bool("\\SET_POLARITY"); + param_bool("\\TRANSPARENT"); + #undef param_bool + + #define param_int(_n) if (param == _n) return value.as_int(); + param_int("\\ABITS") + param_int("\\A_WIDTH") + param_int("\\B_WIDTH") + param_int("\\CTRL_IN_WIDTH") + param_int("\\CTRL_OUT_WIDTH") + param_int("\\OFFSET") + param_int("\\PRIORITY") + param_int("\\RD_PORTS") + param_int("\\SIZE") + param_int("\\STATE_BITS") + param_int("\\STATE_NUM") + param_int("\\STATE_NUM_LOG2") + param_int("\\STATE_RST") + param_int("\\S_WIDTH") + param_int("\\TRANS_NUM") + param_int("\\WIDTH") + param_int("\\WR_PORTS") + param_int("\\Y_WIDTH") + #undef param_int + + return value; + } - if (!needleCell || !haystackCell) { - log_assert(!needleCell && !haystackCell); - return true; - } + virtual bool userCompareNodes(const std::string &, const std::string &, void *needleUserData, + const std::string &, const std::string &, void *haystackUserData, const std::map<std::string, std::string> &portMapping) + { + RTLIL::Cell *needleCell = (RTLIL::Cell*) needleUserData; + RTLIL::Cell *haystackCell = (RTLIL::Cell*) haystackUserData; - if (!ignore_parameters) { - std::map<RTLIL::IdString, RTLIL::Const> needle_param, haystack_param; - for (auto &it : needleCell->parameters) - if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(needleCell->type, it.first))) - needle_param[it.first] = unified_param(needleCell->type, it.first, it.second); - for (auto &it : haystackCell->parameters) - if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(haystackCell->type, it.first))) - haystack_param[it.first] = unified_param(haystackCell->type, it.first, it.second); - if (needle_param != haystack_param) - return false; - } + if (!needleCell || !haystackCell) { + log_assert(!needleCell && !haystackCell); + return true; + } - if (cell_attr.size() > 0 && !compareAttributes(cell_attr, needleCell->attributes, haystackCell->attributes)) + if (!ignore_parameters) { + std::map<RTLIL::IdString, RTLIL::Const> needle_param, haystack_param; + for (auto &it : needleCell->parameters) + if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(needleCell->type, it.first))) + needle_param[it.first] = unified_param(needleCell->type, it.first, it.second); + for (auto &it : haystackCell->parameters) + if (!ignored_parameters.count(std::pair<RTLIL::IdString, RTLIL::IdString>(haystackCell->type, it.first))) + haystack_param[it.first] = unified_param(haystackCell->type, it.first, it.second); + if (needle_param != haystack_param) return false; + } - if (wire_attr.size() > 0) - { - RTLIL::Wire *lastNeedleWire = NULL; - RTLIL::Wire *lastHaystackWire = NULL; - std::map<RTLIL::IdString, RTLIL::Const> emptyAttr; + if (cell_attr.size() > 0 && !compareAttributes(cell_attr, needleCell->attributes, haystackCell->attributes)) + return false; - for (auto &conn : needleCell->connections()) - { - RTLIL::SigSpec needleSig = conn.second; - RTLIL::SigSpec haystackSig = haystackCell->getPort(portMapping.at(conn.first.str())); - - for (int i = 0; i < std::min(needleSig.size(), haystackSig.size()); i++) { - RTLIL::Wire *needleWire = needleSig[i].wire, *haystackWire = haystackSig[i].wire; - if (needleWire != lastNeedleWire || haystackWire != lastHaystackWire) - if (!compareAttributes(wire_attr, needleWire ? needleWire->attributes : emptyAttr, haystackWire ? haystackWire->attributes : emptyAttr)) - return false; - lastNeedleWire = needleWire, lastHaystackWire = haystackWire; - } + if (wire_attr.size() > 0) + { + RTLIL::Wire *lastNeedleWire = NULL; + RTLIL::Wire *lastHaystackWire = NULL; + dict<RTLIL::IdString, RTLIL::Const> emptyAttr; + + for (auto &conn : needleCell->connections()) + { + RTLIL::SigSpec needleSig = conn.second; + RTLIL::SigSpec haystackSig = haystackCell->getPort(portMapping.at(conn.first.str())); + + for (int i = 0; i < std::min(needleSig.size(), haystackSig.size()); i++) { + RTLIL::Wire *needleWire = needleSig[i].wire, *haystackWire = haystackSig[i].wire; + if (needleWire != lastNeedleWire || haystackWire != lastHaystackWire) + if (!compareAttributes(wire_attr, needleWire ? needleWire->attributes : emptyAttr, haystackWire ? haystackWire->attributes : emptyAttr)) + return false; + lastNeedleWire = needleWire, lastHaystackWire = haystackWire; } } - - return true; } - }; - struct bit_ref_t { - std::string cell, port; - int bit; - }; + return true; + } +}; - bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, RTLIL::Design *sel = NULL, - int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = NULL) - { - SigMap sigmap(mod); - std::map<RTLIL::SigBit, bit_ref_t> sig_bit_ref; +struct bit_ref_t { + std::string cell, port; + int bit; +}; - if (sel && !sel->selected(mod)) { - log(" Skipping module %s as it is not selected.\n", id2cstr(mod->name)); - return false; - } +bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, RTLIL::Design *sel = NULL, + int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = NULL) +{ + SigMap sigmap(mod); + std::map<RTLIL::SigBit, bit_ref_t> sig_bit_ref; - if (mod->processes.size() > 0) { - log(" Skipping module %s as it contains unprocessed processes.\n", id2cstr(mod->name)); - return false; - } + if (sel && !sel->selected(mod)) { + log(" Skipping module %s as it is not selected.\n", id2cstr(mod->name)); + return false; + } - if (constports) { - graph.createNode("$const$0", "$const$0", NULL, true); - graph.createNode("$const$1", "$const$1", NULL, true); - graph.createNode("$const$x", "$const$x", NULL, true); - graph.createNode("$const$z", "$const$z", NULL, true); - graph.createPort("$const$0", "\\Y", 1); - graph.createPort("$const$1", "\\Y", 1); - graph.createPort("$const$x", "\\Y", 1); - graph.createPort("$const$z", "\\Y", 1); - graph.markExtern("$const$0", "\\Y", 0); - graph.markExtern("$const$1", "\\Y", 0); - graph.markExtern("$const$x", "\\Y", 0); - graph.markExtern("$const$z", "\\Y", 0); - } + if (mod->processes.size() > 0) { + log(" Skipping module %s as it contains unprocessed processes.\n", id2cstr(mod->name)); + return false; + } - std::map<std::pair<RTLIL::Wire*, int>, int> sig_use_count; - if (max_fanout > 0) - for (auto &cell_it : mod->cells_) - { - RTLIL::Cell *cell = cell_it.second; - if (!sel || sel->selected(mod, cell)) - for (auto &conn : cell->connections()) { - RTLIL::SigSpec conn_sig = conn.second; - sigmap.apply(conn_sig); - for (auto &bit : conn_sig) - if (bit.wire != NULL) - sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)]++; - } - } + if (constports) { + graph.createNode("$const$0", "$const$0", NULL, true); + graph.createNode("$const$1", "$const$1", NULL, true); + graph.createNode("$const$x", "$const$x", NULL, true); + graph.createNode("$const$z", "$const$z", NULL, true); + graph.createPort("$const$0", "\\Y", 1); + graph.createPort("$const$1", "\\Y", 1); + graph.createPort("$const$x", "\\Y", 1); + graph.createPort("$const$z", "\\Y", 1); + graph.markExtern("$const$0", "\\Y", 0); + graph.markExtern("$const$1", "\\Y", 0); + graph.markExtern("$const$x", "\\Y", 0); + graph.markExtern("$const$z", "\\Y", 0); + } - // create graph nodes from cells + std::map<std::pair<RTLIL::Wire*, int>, int> sig_use_count; + if (max_fanout > 0) for (auto &cell_it : mod->cells_) { RTLIL::Cell *cell = cell_it.second; - if (sel && !sel->selected(mod, cell)) - continue; + if (!sel || sel->selected(mod, cell)) + for (auto &conn : cell->connections()) { + RTLIL::SigSpec conn_sig = conn.second; + sigmap.apply(conn_sig); + for (auto &bit : conn_sig) + if (bit.wire != NULL) + sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)]++; + } + } - std::string type = cell->type.str(); - if (sel == NULL && type.substr(0, 2) == "\\$") - type = type.substr(1); - graph.createNode(cell->name.str(), type, (void*)cell); + // create graph nodes from cells + for (auto &cell_it : mod->cells_) + { + RTLIL::Cell *cell = cell_it.second; + if (sel && !sel->selected(mod, cell)) + continue; - for (auto &conn : cell->connections()) - { - graph.createPort(cell->name.str(), conn.first.str(), conn.second.size()); + std::string type = cell->type.str(); + if (sel == NULL && type.substr(0, 2) == "\\$") + type = type.substr(1); + graph.createNode(cell->name.str(), type, (void*)cell); - if (split && split->count(std::pair<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0) - continue; + for (auto &conn : cell->connections()) + { + graph.createPort(cell->name.str(), conn.first.str(), conn.second.size()); - RTLIL::SigSpec conn_sig = conn.second; - sigmap.apply(conn_sig); + if (split && split->count(std::pair<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0) + continue; - for (int i = 0; i < conn_sig.size(); i++) - { - auto &bit = conn_sig[i]; - - if (bit.wire == NULL) { - if (constports) { - std::string node = "$const$x"; - if (bit == RTLIL::State::S0) node = "$const$0"; - if (bit == RTLIL::State::S1) node = "$const$1"; - if (bit == RTLIL::State::Sz) node = "$const$z"; - graph.createConnection(cell->name.str(), conn.first.str(), i, node, "\\Y", 0); - } else - graph.createConstant(cell->name.str(), conn.first.str(), i, int(bit.data)); - continue; - } + RTLIL::SigSpec conn_sig = conn.second; + sigmap.apply(conn_sig); - if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)] > max_fanout) - continue; + for (int i = 0; i < conn_sig.size(); i++) + { + auto &bit = conn_sig[i]; + + if (bit.wire == NULL) { + if (constports) { + std::string node = "$const$x"; + if (bit == RTLIL::State::S0) node = "$const$0"; + if (bit == RTLIL::State::S1) node = "$const$1"; + if (bit == RTLIL::State::Sz) node = "$const$z"; + graph.createConnection(cell->name.str(), conn.first.str(), i, node, "\\Y", 0); + } else + graph.createConstant(cell->name.str(), conn.first.str(), i, int(bit.data)); + continue; + } - if (sel && !sel->selected(mod, bit.wire)) - continue; + if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)] > max_fanout) + continue; - if (sig_bit_ref.count(bit) == 0) { - bit_ref_t &bit_ref = sig_bit_ref[bit]; - bit_ref.cell = cell->name.str(); - bit_ref.port = conn.first.str(); - bit_ref.bit = i; - } + if (sel && !sel->selected(mod, bit.wire)) + continue; + if (sig_bit_ref.count(bit) == 0) { bit_ref_t &bit_ref = sig_bit_ref[bit]; - graph.createConnection(bit_ref.cell, bit_ref.port, bit_ref.bit, cell->name.str(), conn.first.str(), i); + bit_ref.cell = cell->name.str(); + bit_ref.port = conn.first.str(); + bit_ref.bit = i; } - } - } - - // mark external signals (used in non-selected cells) - for (auto &cell_it : mod->cells_) - { - RTLIL::Cell *cell = cell_it.second; - if (sel && !sel->selected(mod, cell)) - for (auto &conn : cell->connections()) - { - RTLIL::SigSpec conn_sig = conn.second; - sigmap.apply(conn_sig); - for (auto &bit : conn_sig) - if (sig_bit_ref.count(bit) != 0) { - bit_ref_t &bit_ref = sig_bit_ref[bit]; - graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit); - } - } + bit_ref_t &bit_ref = sig_bit_ref[bit]; + graph.createConnection(bit_ref.cell, bit_ref.port, bit_ref.bit, cell->name.str(), conn.first.str(), i); + } } + } - // mark external signals (used in module ports) - for (auto &wire_it : mod->wires_) - { - RTLIL::Wire *wire = wire_it.second; - if (wire->port_id > 0) + // mark external signals (used in non-selected cells) + for (auto &cell_it : mod->cells_) + { + RTLIL::Cell *cell = cell_it.second; + if (sel && !sel->selected(mod, cell)) + for (auto &conn : cell->connections()) { - RTLIL::SigSpec conn_sig(wire); + RTLIL::SigSpec conn_sig = conn.second; sigmap.apply(conn_sig); for (auto &bit : conn_sig) @@ -284,70 +268,86 @@ namespace graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit); } } - } - - // graph.print(); - return true; } - RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match) + // mark external signals (used in module ports) + for (auto &wire_it : mod->wires_) { - SigMap sigmap(needle); - SigSet<std::pair<RTLIL::IdString, int>> sig2port; - - // create new cell - RTLIL::Cell *cell = haystack->addCell(stringf("$extract$%s$%d", needle->name.c_str(), autoidx++), needle->name); - - // create cell ports - for (auto &it : needle->wires_) { - RTLIL::Wire *wire = it.second; - if (wire->port_id > 0) { - for (int i = 0; i < wire->width; i++) - sig2port.insert(sigmap(RTLIL::SigSpec(wire, i)), std::pair<RTLIL::IdString, int>(wire->name, i)); - cell->setPort(wire->name, RTLIL::SigSpec(RTLIL::State::Sz, wire->width)); - } + RTLIL::Wire *wire = wire_it.second; + if (wire->port_id > 0) + { + RTLIL::SigSpec conn_sig(wire); + sigmap.apply(conn_sig); + + for (auto &bit : conn_sig) + if (sig_bit_ref.count(bit) != 0) { + bit_ref_t &bit_ref = sig_bit_ref[bit]; + graph.markExtern(bit_ref.cell, bit_ref.port, bit_ref.bit); + } } + } - // delete replaced cells and connect new ports - for (auto &it : match.mappings) - { - auto &mapping = it.second; - RTLIL::Cell *needle_cell = (RTLIL::Cell*)mapping.needleUserData; - RTLIL::Cell *haystack_cell = (RTLIL::Cell*)mapping.haystackUserData; + // graph.print(); + return true; +} - if (needle_cell == NULL) - continue; +RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match) +{ + SigMap sigmap(needle); + SigSet<std::pair<RTLIL::IdString, int>> sig2port; + + // create new cell + RTLIL::Cell *cell = haystack->addCell(stringf("$extract$%s$%d", needle->name.c_str(), autoidx++), needle->name); + + // create cell ports + for (auto &it : needle->wires_) { + RTLIL::Wire *wire = it.second; + if (wire->port_id > 0) { + for (int i = 0; i < wire->width; i++) + sig2port.insert(sigmap(RTLIL::SigSpec(wire, i)), std::pair<RTLIL::IdString, int>(wire->name, i)); + cell->setPort(wire->name, RTLIL::SigSpec(RTLIL::State::Sz, wire->width)); + } + } - for (auto &conn : needle_cell->connections()) { - RTLIL::SigSpec sig = sigmap(conn.second); - if (mapping.portMapping.count(conn.first.str()) > 0 && sig2port.has(sigmap(sig))) { - for (int i = 0; i < sig.size(); i++) - for (auto &port : sig2port.find(sig[i])) { - RTLIL::SigSpec bitsig = haystack_cell->getPort(mapping.portMapping[conn.first.str()]).extract(i, 1); - RTLIL::SigSpec new_sig = cell->getPort(port.first); - new_sig.replace(port.second, bitsig); - cell->setPort(port.first, new_sig); - } + // delete replaced cells and connect new ports + for (auto &it : match.mappings) + { + auto &mapping = it.second; + RTLIL::Cell *needle_cell = (RTLIL::Cell*)mapping.needleUserData; + RTLIL::Cell *haystack_cell = (RTLIL::Cell*)mapping.haystackUserData; + + if (needle_cell == NULL) + continue; + + for (auto &conn : needle_cell->connections()) { + RTLIL::SigSpec sig = sigmap(conn.second); + if (mapping.portMapping.count(conn.first.str()) > 0 && sig2port.has(sigmap(sig))) { + for (int i = 0; i < sig.size(); i++) + for (auto &port : sig2port.find(sig[i])) { + RTLIL::SigSpec bitsig = haystack_cell->getPort(mapping.portMapping[conn.first.str()]).extract(i, 1); + RTLIL::SigSpec new_sig = cell->getPort(port.first); + new_sig.replace(port.second, bitsig); + cell->setPort(port.first, new_sig); } } - - haystack->remove(haystack_cell); } - return cell; + haystack->remove(haystack_cell); } - bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right) - { - int left_idx = 0, right_idx = 0; - if (left->attributes.count("\\extract_order") > 0) - left_idx = left->attributes.at("\\extract_order").as_int(); - if (right->attributes.count("\\extract_order") > 0) - right_idx = right->attributes.at("\\extract_order").as_int(); - if (left_idx != right_idx) - return left_idx < right_idx; - return left->name < right->name; - } + return cell; +} + +bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right) +{ + int left_idx = 0, right_idx = 0; + if (left->attributes.count("\\extract_order") > 0) + left_idx = left->attributes.at("\\extract_order").as_int(); + if (right->attributes.count("\\extract_order") > 0) + right_idx = right->attributes.at("\\extract_order").as_int(); + if (left_idx != right_idx) + return left_idx < right_idx; + return left->name < right->name; } struct ExtractPass : public Pass { @@ -518,24 +518,21 @@ struct ExtractPass : public Pass { if (args[argidx] == "-swap" && argidx+2 < args.size()) { std::string type = RTLIL::escape_id(args[++argidx]); std::set<std::string> ports; - char *ports_str = strdup(args[++argidx].c_str()); - for (char *sptr, *p = strtok_r(ports_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr)) + std::string ports_str = args[++argidx], p; + while (!(p = next_token(ports_str, ",\t\r\n ")).empty()) ports.insert(RTLIL::escape_id(p)); - free(ports_str); solver.addSwappablePorts(type, ports); continue; } if (args[argidx] == "-perm" && argidx+3 < args.size()) { std::string type = RTLIL::escape_id(args[++argidx]); std::vector<std::string> map_left, map_right; - char *left_str = strdup(args[++argidx].c_str()); - char *right_str = strdup(args[++argidx].c_str()); - for (char *sptr, *p = strtok_r(left_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr)) + std::string left_str = args[++argidx]; + std::string right_str = args[++argidx], p; + while (!(p = next_token(left_str, ",\t\r\n ")).empty()) map_left.push_back(RTLIL::escape_id(p)); - for (char *sptr, *p = strtok_r(right_str, ",\t\r\n ", &sptr); p != NULL; p = strtok_r(NULL, ",\t\r\n ", &sptr)) + while (!(p = next_token(right_str, ",\t\r\n ")).empty()) map_right.push_back(RTLIL::escape_id(p)); - free(left_str); - free(right_str); if (map_left.size() != map_right.size()) log_cmd_error("Arguments to -perm are not a valid permutation!\n"); std::map<std::string, std::string> map; @@ -665,7 +662,7 @@ struct ExtractPass : public Pass { log("Solving for %s in %s.\n", ("needle_" + RTLIL::unescape_id(needle->name)).c_str(), haystack_it.first.c_str()); solver.solve(results, "needle_" + RTLIL::unescape_id(needle->name), haystack_it.first, false); } - log("Found %zd matches.\n", results.size()); + log("Found %d matches.\n", GetSize(results)); if (results.size() > 0) { @@ -761,3 +758,4 @@ struct ExtractPass : public Pass { } } ExtractPass; +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc index 784c4cf31..9a14ffa3c 100644 --- a/passes/techmap/hilomap.cc +++ b/passes/techmap/hilomap.cc @@ -21,6 +21,9 @@ #include "kernel/rtlil.h" #include "kernel/log.h" +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + static std::string hicell_celltype, hicell_portname; static std::string locell_celltype, locell_portname; static bool singleton_mode; @@ -57,9 +60,7 @@ struct HilomapPass : public Pass { log("\n"); log(" hilomap [options] [selection]\n"); log("\n"); - log("Map module inputs/outputs to PAD cells from a library. This pass\n"); - log("can only map to very simple PAD cells. Use 'techmap' to further map\n"); - log("the resulting cells to more sophisticated PAD cells.\n"); + log("Map constants to 'tielo' and 'tiehi' driver cells.\n"); log("\n"); log(" -hicell <celltype> <portname>\n"); log(" Replace constant hi bits with this cell.\n"); @@ -75,7 +76,7 @@ struct HilomapPass : public Pass { } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - log_header("Executing HILOPAD pass (mapping to constant drivers).\n"); + log_header("Executing HILOMAP pass (mapping to constant drivers).\n"); hicell_celltype = std::string(); hicell_portname = std::string(); @@ -119,3 +120,4 @@ struct HilomapPass : public Pass { } } HilomapPass; +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index 9cd23ce6f..3fba0e618 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -21,7 +21,10 @@ #include "kernel/rtlil.h" #include "kernel/log.h" -static void split_portname_pair(std::string &port1, std::string &port2) +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +void split_portname_pair(std::string &port1, std::string &port2) { size_t pos = port1.find_first_of(':'); if (pos != std::string::npos) { @@ -59,8 +62,8 @@ struct IopadmapPass : public Pass { log("\n"); log(" -bits\n"); log(" create individual bit-wide buffers even for ports that\n"); - log(" are wider. (the default behavio is to create word-wide\n"); - log(" buffers use -widthparam to set the word size on the cell.)\n"); + log(" are wider. (the default behavior is to create word-wide\n"); + log(" buffers using -widthparam to set the word size on the cell.)\n"); log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) @@ -111,18 +114,11 @@ struct IopadmapPass : public Pass { } extra_args(args, argidx, design); - for (auto &it : design->modules_) + for (auto module : design->selected_modules()) { - RTLIL::Module *module = it.second; - - if (!design->selected(module) || module->get_bool_attribute("\\blackbox")) - continue; - - for (auto &it2 : module->wires_) + for (auto wire : module->selected_wires()) { - RTLIL::Wire *wire = it2.second; - - if (!wire->port_id || !design->selected(module, wire)) + if (!wire->port_id) continue; std::string celltype, portname, portname2; @@ -207,3 +203,4 @@ struct IopadmapPass : public Pass { } } IopadmapPass; +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 612fa1117..def480394 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -29,7 +29,7 @@ #include "kernel/log.h" #endif -using namespace PASS_DFFLIBMAP; +using namespace Yosys; std::set<std::string> LibertyAst::blacklist; std::set<std::string> LibertyAst::whitelist; @@ -43,8 +43,6 @@ LibertyAst::~LibertyAst() LibertyAst *LibertyAst::find(std::string name) { - if (this == NULL) - return NULL; for (auto child : children) if (child->id == name) return child; @@ -107,14 +105,14 @@ int LibertyParser::lexer(std::string &str) } if (c == '"') { - str = c; + str = ""; while (1) { c = f.get(); if (c == '\n') line++; - str += c; if (c == '"') break; + str += c; } // fprintf(stderr, "LEX: string >>%s<<\n", str.c_str()); return 'v'; @@ -244,21 +242,6 @@ void LibertyParser::error() /**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/ -// This is to not confuse the VIM syntax highlighting -#define CHECK_VAL_OPEN ( -#define CHECK_VAL_CLOSE ) - -#define CHECK(result, check) \ - CHECK_VAL_OPEN{ \ - auto _R = (result); \ - if (!(_R check)) { \ - fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \ - #result, (long int)_R, #check, __FILE__, __LINE__); \ - abort(); \ - } \ - _R; \ - }CHECK_VAL_CLOSE - #define CHECK_NV(result, check) \ do { \ auto _R = (result); \ @@ -280,6 +263,14 @@ void LibertyParser::error() /**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/ +LibertyAst *find_non_null(LibertyAst *node, const char *name) +{ + LibertyAst *ret = node->find(name); + if (ret == NULL) + fprintf(stderr, "Error: expected to find `%s' node.\n", name); + return ret; +} + std::string func2vl(std::string str) { for (size_t pos = str.find_first_of("\" \t"); pos != std::string::npos; pos = str.find_first_of("\" \t")) { @@ -388,7 +379,7 @@ void gen_verilogsim_cell(LibertyAst *ast) if (child->id != "pin") continue; CHECK_NV(child->args.size(), == 1); - LibertyAst *dir = CHECK(child->find("direction"), != NULL); + LibertyAst *dir = find_non_null(child, "direction"); LibertyAst *func = child->find("function"); printf(" %s %s;\n", dir->value.c_str(), child->args[0].c_str()); if (func != NULL) @@ -428,8 +419,8 @@ void gen_verilogsim_cell(LibertyAst *ast) const char *else_prefix = ""; if (!clear_expr.empty() && !preset_expr.empty()) { printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str()); - clear_preset_var(iq_var, CHECK(child->find("clear_preset_var1"), != NULL)->value); - clear_preset_var(iqn_var, CHECK(child->find("clear_preset_var2"), != NULL)->value); + clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value); + clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value); printf(" end\n"); else_prefix = "else "; } @@ -449,7 +440,7 @@ void gen_verilogsim_cell(LibertyAst *ast) } if (*else_prefix) printf(" %sbegin\n", else_prefix); - std::string expr = CHECK(child->find("next_state"), != NULL)->value; + std::string expr = find_non_null(child, "next_state")->value; printf(" // %s\n", expr.c_str()); printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str()); printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str()); @@ -481,8 +472,8 @@ void gen_verilogsim_cell(LibertyAst *ast) const char *else_prefix = ""; if (!clear_expr.empty() && !preset_expr.empty()) { printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str()); - clear_preset_var(iq_var, CHECK(child->find("clear_preset_var1"), != NULL)->value); - clear_preset_var(iqn_var, CHECK(child->find("clear_preset_var2"), != NULL)->value); + clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value); + clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value); printf(" end\n"); else_prefix = "else "; } @@ -502,7 +493,7 @@ void gen_verilogsim_cell(LibertyAst *ast) } if (!enable_expr.empty()) { printf(" %sif (%s) begin\n", else_prefix, enable_expr.c_str()); - std::string expr = CHECK(child->find("data_in"), != NULL)->value; + std::string expr = find_non_null(child, "data_in")->value; printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str()); printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str()); printf(" end\n"); diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index 247487424..e947bd8cd 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -25,7 +25,7 @@ #include <vector> #include <set> -namespace PASS_DFFLIBMAP +namespace Yosys { struct LibertyAst { diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc index 2d625eefe..ffbd6289d 100644 --- a/passes/techmap/maccmap.cc +++ b/passes/techmap/maccmap.cc @@ -20,7 +20,8 @@ #include "kernel/yosys.h" #include "kernel/macc.h" -extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false); +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN struct MaccmapWorker { @@ -48,7 +49,7 @@ struct MaccmapWorker void add(RTLIL::SigSpec a, bool is_signed, bool do_subtract) { - a.extend(width, is_signed); + a.extend_u0(width, is_signed); if (do_subtract) { a = module->Not(NEW_ID, a); @@ -61,16 +62,16 @@ struct MaccmapWorker void add(RTLIL::SigSpec a, RTLIL::SigSpec b, bool is_signed, bool do_subtract) { - if (SIZE(a) < SIZE(b)) + if (GetSize(a) < GetSize(b)) std::swap(a, b); - a.extend(width, is_signed); + a.extend_u0(width, is_signed); - if (SIZE(b) > width) - b.extend(width, is_signed); + if (GetSize(b) > width) + b.extend_u0(width, is_signed); - for (int i = 0; i < SIZE(b); i++) - if (is_signed && i+1 == SIZE(b)) + for (int i = 0; i < GetSize(b); i++) + if (is_signed && i+1 == GetSize(b)) { a = {module->Not(NEW_ID, a.extract(i, width-i)), RTLIL::SigSpec(0, i)}; add(module->And(NEW_ID, a, RTLIL::SigSpec(b[i], width)), false, do_subtract); @@ -85,7 +86,7 @@ struct MaccmapWorker void fulladd(RTLIL::SigSpec &in1, RTLIL::SigSpec &in2, RTLIL::SigSpec &in3, RTLIL::SigSpec &out1, RTLIL::SigSpec &out2) { - int start_index = 0, stop_index = SIZE(in1); + int start_index = 0, stop_index = GetSize(in1); while (start_index < stop_index && in1[start_index] == RTLIL::S0 && in2[start_index] == RTLIL::S0 && in3[start_index] == RTLIL::S0) start_index++; @@ -95,18 +96,18 @@ struct MaccmapWorker if (start_index == stop_index) { - out1 = RTLIL::SigSpec(0, SIZE(in1)); - out2 = RTLIL::SigSpec(0, SIZE(in1)); + out1 = RTLIL::SigSpec(0, GetSize(in1)); + out2 = RTLIL::SigSpec(0, GetSize(in1)); } else { - RTLIL::SigSpec out_zeros_lsb(0, start_index), out_zeros_msb(0, SIZE(in1)-stop_index); + RTLIL::SigSpec out_zeros_lsb(0, start_index), out_zeros_msb(0, GetSize(in1)-stop_index); in1 = in1.extract(start_index, stop_index-start_index); in2 = in2.extract(start_index, stop_index-start_index); in3 = in3.extract(start_index, stop_index-start_index); - int width = SIZE(in1); + int width = GetSize(in1); RTLIL::Wire *w1 = module->addWire(NEW_ID, width); RTLIL::Wire *w2 = module->addWire(NEW_ID, width); @@ -164,12 +165,12 @@ struct MaccmapWorker while (1) { - int free_bit_slots = tree_bit_slots(SIZE(summands)) - SIZE(tree_sum_bits); + int free_bit_slots = tree_bit_slots(GetSize(summands)) - GetSize(tree_sum_bits); int max_depth = 0, max_position = 0; for (int i = 0; i < width; i++) - if (max_depth <= SIZE(bits.at(i))) { - max_depth = SIZE(bits.at(i)); + if (max_depth <= GetSize(bits.at(i))) { + max_depth = GetSize(bits.at(i)); max_position = i; } @@ -178,14 +179,14 @@ struct MaccmapWorker int required_bits = 0; for (int i = 0; i <= max_position; i++) - if (SIZE(bits.at(i)) == max_depth) + if (GetSize(bits.at(i)) == max_depth) required_bits += 1 << i; if (required_bits > free_bit_slots) break; for (int i = 0; i <= max_position; i++) - if (SIZE(bits.at(i)) == max_depth) { + if (GetSize(bits.at(i)) == max_depth) { auto it = bits.at(i).begin(); RTLIL::SigBit bit = *it; for (int k = 0; k < (1 << i); k++, free_bit_slots--) @@ -199,23 +200,23 @@ struct MaccmapWorker } if (!tree_sum_bits.empty()) - log(" packed %d (%d) bits / %d words into adder tree\n", SIZE(tree_sum_bits), unique_tree_bits, count_tree_words); + log(" packed %d (%d) bits / %d words into adder tree\n", GetSize(tree_sum_bits), unique_tree_bits, count_tree_words); - if (SIZE(summands) == 0) { + if (GetSize(summands) == 0) { log_assert(tree_sum_bits.empty()); return RTLIL::SigSpec(0, width); } - if (SIZE(summands) == 1) { + if (GetSize(summands) == 1) { log_assert(tree_sum_bits.empty()); return summands.front(); } - while (SIZE(summands) > 2) + while (GetSize(summands) > 2) { std::vector<RTLIL::SigSpec> new_summands; - for (int i = 0; i < SIZE(summands); i += 3) - if (i+2 < SIZE(summands)) { + for (int i = 0; i < GetSize(summands); i += 3) + if (i+2 < GetSize(summands)) { RTLIL::SigSpec in1 = summands[i]; RTLIL::SigSpec in2 = summands[i+1]; RTLIL::SigSpec in3 = summands[i+2]; @@ -256,9 +257,14 @@ struct MaccmapWorker } }; +PRIVATE_NAMESPACE_END +YOSYS_NAMESPACE_BEGIN + +extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false); + void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap) { - int width = SIZE(cell->getPort("\\Y")); + int width = GetSize(cell->getPort("\\Y")); Macc macc; macc.from_cell(cell); @@ -273,15 +279,15 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap) } for (auto &port : macc.ports) - if (SIZE(port.in_b) == 0) + if (GetSize(port.in_b) == 0) log(" %s %s (%d bits, %s)\n", port.do_subtract ? "sub" : "add", log_signal(port.in_a), - SIZE(port.in_a), port.is_signed ? "signed" : "unsigned"); + GetSize(port.in_a), port.is_signed ? "signed" : "unsigned"); else log(" %s %s * %s (%dx%d bits, %s)\n", port.do_subtract ? "sub" : "add", log_signal(port.in_a), log_signal(port.in_b), - SIZE(port.in_a), SIZE(port.in_b), port.is_signed ? "signed" : "unsigned"); + GetSize(port.in_a), GetSize(port.in_b), port.is_signed ? "signed" : "unsigned"); - if (SIZE(macc.bit_ports) != 0) - log(" add bits %s (%d bits)\n", log_signal(macc.bit_ports), SIZE(macc.bit_ports)); + if (GetSize(macc.bit_ports) != 0) + log(" add bits %s (%d bits)\n", log_signal(macc.bit_ports), GetSize(macc.bit_ports)); if (unmap) { @@ -290,10 +296,10 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap) for (auto &port : macc.ports) { summand_t this_summand; - if (SIZE(port.in_b)) { + if (GetSize(port.in_b)) { this_summand.first = module->addWire(NEW_ID, width); module->addMul(NEW_ID, port.in_a, port.in_b, this_summand.first, port.is_signed); - } else if (SIZE(port.in_a) != width) { + } else if (GetSize(port.in_a) != width) { this_summand.first = module->addWire(NEW_ID, width); module->addPos(NEW_ID, port.in_a, this_summand.first, port.is_signed); } else { @@ -306,14 +312,14 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap) for (auto &bit : macc.bit_ports) summands.push_back(summand_t(bit, false)); - if (SIZE(summands) == 0) + if (GetSize(summands) == 0) summands.push_back(summand_t(RTLIL::SigSpec(0, width), false)); - while (SIZE(summands) > 1) + while (GetSize(summands) > 1) { std::vector<summand_t> new_summands; - for (int i = 0; i < SIZE(summands); i += 2) { - if (i+1 < SIZE(summands)) { + for (int i = 0; i < GetSize(summands); i += 2) { + if (i+1 < GetSize(summands)) { summand_t this_summand; this_summand.first = module->addWire(NEW_ID, width); this_summand.second = summands[i].second && summands[i+1].second; @@ -342,7 +348,7 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap) MaccmapWorker worker(module, width); for (auto &port : macc.ports) - if (SIZE(port.in_b) == 0) + if (GetSize(port.in_b) == 0) worker.add(port.in_a, port.is_signed, port.do_subtract); else worker.add(port.in_a, port.in_b, port.is_signed, port.do_subtract); @@ -354,6 +360,9 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap) } } +YOSYS_NAMESPACE_END +PRIVATE_NAMESPACE_BEGIN + struct MaccmapPass : public Pass { MaccmapPass() : Pass("maccmap", "mapping macc cells") { } virtual void help() @@ -392,3 +401,4 @@ struct MaccmapPass : public Pass { } } MaccmapPass; +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index f8d5d4584..9cea5f45d 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -17,53 +17,53 @@ * */ -#include "kernel/register.h" +#include "simplemap.h" #include "kernel/sigtools.h" -#include "kernel/log.h" #include <stdlib.h> #include <stdio.h> #include <string.h> -extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers); +USING_YOSYS_NAMESPACE +YOSYS_NAMESPACE_BEGIN -static void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell) { RTLIL::SigSpec sig_a = cell->getPort("\\A"); RTLIL::SigSpec sig_y = cell->getPort("\\Y"); - sig_a.extend(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool()); + sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool()); - for (int i = 0; i < SIZE(sig_y); i++) { + for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_"); gate->setPort("\\A", sig_a[i]); gate->setPort("\\Y", sig_y[i]); } } -static void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell) { RTLIL::SigSpec sig_a = cell->getPort("\\A"); RTLIL::SigSpec sig_y = cell->getPort("\\Y"); - sig_a.extend_u0(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool()); + sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool()); module->connect(RTLIL::SigSig(sig_y, sig_a)); } -static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell) { RTLIL::SigSpec sig_a = cell->getPort("\\A"); RTLIL::SigSpec sig_b = cell->getPort("\\B"); RTLIL::SigSpec sig_y = cell->getPort("\\Y"); - sig_a.extend_u0(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool()); - sig_b.extend_u0(SIZE(sig_y), cell->parameters.at("\\B_SIGNED").as_bool()); + sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool()); + sig_b.extend_u0(GetSize(sig_y), cell->parameters.at("\\B_SIGNED").as_bool()); if (cell->type == "$xnor") { - RTLIL::SigSpec sig_t = module->addWire(NEW_ID, SIZE(sig_y)); + RTLIL::SigSpec sig_t = module->addWire(NEW_ID, GetSize(sig_y)); - for (int i = 0; i < SIZE(sig_y); i++) { + for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_"); gate->setPort("\\A", sig_t[i]); gate->setPort("\\Y", sig_y[i]); @@ -79,7 +79,7 @@ static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell) if (cell->type == "$xnor") gate_type = "$_XOR_"; log_assert(!gate_type.empty()); - for (int i = 0; i < SIZE(sig_y); i++) { + for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); gate->setPort("\\A", sig_a[i]); gate->setPort("\\B", sig_b[i]); @@ -87,7 +87,7 @@ static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell) } } -static void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) { RTLIL::SigSpec sig_a = cell->getPort("\\A"); RTLIL::SigSpec sig_y = cell->getPort("\\Y"); @@ -182,7 +182,7 @@ static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig) sig = RTLIL::SigSpec(0, 1); } -static void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell) { RTLIL::SigSpec sig_a = cell->getPort("\\A"); logic_reduce(module, sig_a); @@ -202,7 +202,7 @@ static void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell) gate->setPort("\\Y", sig_y); } -static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell) { RTLIL::SigSpec sig_a = cell->getPort("\\A"); logic_reduce(module, sig_a); @@ -231,13 +231,38 @@ static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell) gate->setPort("\\Y", sig_y); } -static void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell) { RTLIL::SigSpec sig_a = cell->getPort("\\A"); RTLIL::SigSpec sig_b = cell->getPort("\\B"); RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool(); + bool is_ne = cell->type == "$ne" || cell->type == "$nex"; + + RTLIL::SigSpec xor_out = module->addWire(NEW_ID, std::max(GetSize(sig_a), GetSize(sig_b))); + RTLIL::Cell *xor_cell = module->addXor(NEW_ID, sig_a, sig_b, xor_out, is_signed); + simplemap_bitop(module, xor_cell); + module->remove(xor_cell); + + RTLIL::SigSpec reduce_out = is_ne ? sig_y : module->addWire(NEW_ID); + RTLIL::Cell *reduce_cell = module->addReduceOr(NEW_ID, xor_out, reduce_out); + simplemap_reduce(module, reduce_cell); + module->remove(reduce_cell); + + if (!is_ne) { + RTLIL::Cell *not_cell = module->addLogicNot(NEW_ID, reduce_out, sig_y); + simplemap_lognot(module, not_cell); + module->remove(not_cell); + } +} - for (int i = 0; i < SIZE(sig_y); i++) { +void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell) +{ + RTLIL::SigSpec sig_a = cell->getPort("\\A"); + RTLIL::SigSpec sig_b = cell->getPort("\\B"); + RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + + for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, "$_MUX_"); gate->setPort("\\A", sig_a[i]); gate->setPort("\\B", sig_b[i]); @@ -246,7 +271,7 @@ static void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell) } } -static void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell) { int offset = cell->parameters.at("\\OFFSET").as_int(); RTLIL::SigSpec sig_a = cell->getPort("\\A"); @@ -254,7 +279,7 @@ static void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell) module->connect(RTLIL::SigSig(sig_y, sig_a.extract(offset, sig_y.size()))); } -static void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell) { RTLIL::SigSpec sig_ab = cell->getPort("\\A"); sig_ab.append(cell->getPort("\\B")); @@ -262,7 +287,7 @@ static void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell) module->connect(RTLIL::SigSig(sig_y, sig_ab)); } -static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell) { int width = cell->parameters.at("\\WIDTH").as_int(); char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N'; @@ -282,7 +307,7 @@ static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell) } } -static void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell) { int width = cell->parameters.at("\\WIDTH").as_int(); char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N'; @@ -301,7 +326,29 @@ static void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell) } } -static void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_dffe(RTLIL::Module *module, RTLIL::Cell *cell) +{ + int width = cell->parameters.at("\\WIDTH").as_int(); + char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N'; + char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N'; + + RTLIL::SigSpec sig_clk = cell->getPort("\\CLK"); + RTLIL::SigSpec sig_en = cell->getPort("\\EN"); + RTLIL::SigSpec sig_d = cell->getPort("\\D"); + RTLIL::SigSpec sig_q = cell->getPort("\\Q"); + + std::string gate_type = stringf("$_DFFE_%c%c_", clk_pol, en_pol); + + for (int i = 0; i < width; i++) { + RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); + gate->setPort("\\C", sig_clk); + gate->setPort("\\E", sig_en); + gate->setPort("\\D", sig_d[i]); + gate->setPort("\\Q", sig_q[i]); + } +} + +void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell) { int width = cell->parameters.at("\\WIDTH").as_int(); char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N'; @@ -326,7 +373,7 @@ static void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell) } } -static void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell) { int width = cell->parameters.at("\\WIDTH").as_int(); char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N'; @@ -353,7 +400,7 @@ static void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell) } } -static void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell) +void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell) { int width = cell->parameters.at("\\WIDTH").as_int(); char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N'; @@ -388,16 +435,37 @@ void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTL mappers["$logic_not"] = simplemap_lognot; mappers["$logic_and"] = simplemap_logbin; mappers["$logic_or"] = simplemap_logbin; + mappers["$eq"] = simplemap_eqne; + mappers["$eqx"] = simplemap_eqne; + mappers["$ne"] = simplemap_eqne; + mappers["$nex"] = simplemap_eqne; mappers["$mux"] = simplemap_mux; mappers["$slice"] = simplemap_slice; mappers["$concat"] = simplemap_concat; mappers["$sr"] = simplemap_sr; mappers["$dff"] = simplemap_dff; + mappers["$dffe"] = simplemap_dffe; mappers["$dffsr"] = simplemap_dffsr; mappers["$adff"] = simplemap_adff; mappers["$dlatch"] = simplemap_dlatch; } +void simplemap(RTLIL::Module *module, RTLIL::Cell *cell) +{ + static std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers; + static bool initialized_mappers = false; + + if (!initialized_mappers) { + simplemap_get_mappers(mappers); + initialized_mappers = true; + } + + mappers.at(cell->type)(module, cell); +} + +YOSYS_NAMESPACE_END +PRIVATE_NAMESPACE_BEGIN + struct SimplemapPass : public Pass { SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { } virtual void help() @@ -440,3 +508,4 @@ struct SimplemapPass : public Pass { } } SimplemapPass; +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/simplemap.h b/passes/techmap/simplemap.h new file mode 100644 index 000000000..dc2a395d3 --- /dev/null +++ b/passes/techmap/simplemap.h @@ -0,0 +1,48 @@ +/* + * 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 SIMPLEMAP_H +#define SIMPLEMAP_H + +#include "kernel/yosys.h" + +YOSYS_NAMESPACE_BEGIN + +extern void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_dffe(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell); +extern void simplemap(RTLIL::Module *module, RTLIL::Cell *cell); + +extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers); + +YOSYS_NAMESPACE_END + +#endif diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index ed466faa1..ab748ed74 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -26,15 +26,20 @@ #include <stdio.h> #include <string.h> +#include "simplemap.h" #include "passes/techmap/techmap.inc" -// see simplemap.cc -extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers); +YOSYS_NAMESPACE_BEGIN // see maccmap.cc extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false); -static void apply_prefix(std::string prefix, std::string &id) +YOSYS_NAMESPACE_END + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +void apply_prefix(std::string prefix, std::string &id) { if (id[0] == '\\') id = prefix + "." + id.substr(1); @@ -42,7 +47,7 @@ static void apply_prefix(std::string prefix, std::string &id) id = "$techmap" + prefix + "." + id; } -static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) +void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) { std::vector<RTLIL::SigChunk> chunks = sig; for (auto &chunk : chunks) @@ -61,6 +66,11 @@ struct TechmapWorker std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache; std::map<RTLIL::Module*, bool> techmap_do_cache; std::set<RTLIL::Module*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Module>> module_queue; + dict<Module*, SigMap> sigmaps; + + pool<IdString> flatten_do_list; + pool<IdString> flatten_done_list; + pool<Cell*> flatten_keep_list; struct TechmapWireData { RTLIL::Wire *wire; @@ -90,7 +100,7 @@ struct TechmapWorker std::map<RTLIL::SigBit, std::pair<RTLIL::IdString, int>> connbits_map; for (auto conn : cell->connections()) - for (int i = 0; i < SIZE(conn.second); i++) { + for (int i = 0; i < GetSize(conn.second); i++) { RTLIL::SigBit bit = sigmap(conn.second[i]); if (bit.wire == nullptr) { if (verbose) @@ -102,8 +112,10 @@ struct TechmapWorker connbits_map.at(bit).second, log_id(connbits_map.at(bit).first)); constmap_info += stringf("|%s %d %s %d", log_id(conn.first), i, log_id(connbits_map.at(bit).first), connbits_map.at(bit).second); - } else - connbits_map[bit] = std::pair<RTLIL::IdString, int>(conn.first, i);stringf("%s %d", log_id(conn.first), i, bit.data); + } else { + connbits_map[bit] = std::pair<RTLIL::IdString, int>(conn.first, i); + constmap_info += stringf("|%s %d", log_id(conn.first), i); + } } return stringf("$paramod$constmap:%s%s", sha1(constmap_info).c_str(), tpl->name.c_str()); @@ -122,7 +134,7 @@ struct TechmapWorker continue; const char *q = strrchr(p+1, '.'); - p = q ? q : p+1; + p = q ? q+1 : p+1; if (!strncmp(p, "_TECHMAP_", 9)) { TechmapWireData record; @@ -146,16 +158,13 @@ struct TechmapWorker void techmap_module_worker(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl) { - if (tpl->memories.size() != 0) - log_error("Technology map yielded memories -> this is not supported.\n"); - if (tpl->processes.size() != 0) { log("Technology map yielded processes:\n"); for (auto &it : tpl->processes) log(" %s",RTLIL::id2cstr(it.first)); if (autoproc_mode) { Pass::call_on_module(tpl->design, tpl, "proc"); - log_assert(SIZE(tpl->processes) == 0); + log_assert(GetSize(tpl->processes) == 0); } else log_error("Technology map yielded processes -> this is not supported (use -autoproc to run 'proc' automatically).\n"); } @@ -169,6 +178,22 @@ struct TechmapWorker break; } + dict<IdString, IdString> memory_renames; + + for (auto &it : tpl->memories) { + std::string m_name = it.first.str(); + apply_prefix(cell->name.str(), m_name); + RTLIL::Memory *m = new RTLIL::Memory; + m->name = m_name; + m->width = it.second->width; + m->start_offset = it.second->start_offset; + m->size = it.second->size; + m->attributes = it.second->attributes; + module->memories[m->name] = m; + memory_renames[it.first] = m->name; + design->select(module, m); + } + std::map<RTLIL::IdString, RTLIL::IdString> positional_ports; for (auto &it : tpl->wires_) { @@ -215,6 +240,11 @@ struct TechmapWorker if (flatten_mode) { // more conservative approach: // connect internal and external wires + if (sigmaps.count(module) == 0) + sigmaps[module].set(module); + if (sigmaps.at(module)(c.first).has_const()) + log_error("Mismatch in directionality for cell port %s.%s.%s: %s <= %s\n", + log_id(module), log_id(cell), log_id(it.first), log_signal(c.first), log_signal(c.second)); module->connect(c); } else { // approach that yields nicer outputs: @@ -245,6 +275,12 @@ struct TechmapWorker apply_prefix(cell->name.str(), it2.second, module); port_signal_map.apply(it2.second); } + + if (c->type == "$memrd" || c->type == "$memwr") { + IdString memid = c->getParam("\\MEMID").decode_string(); + log_assert(memory_renames.count(memid)); + c->setParam("\\MEMID", Const(memory_renames[memid].str())); + } } for (auto &it : tpl->connections()) { @@ -272,7 +308,7 @@ struct TechmapWorker SigMap sigmap(module); - TopoSort<RTLIL::Cell*> cells; + TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells; std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit; std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell; @@ -291,12 +327,28 @@ struct TechmapWorker continue; } + if (flatten_mode) { + bool keepit = cell->get_bool_attribute("\\keep_hierarchy"); + for (auto &tpl_name : celltypeMap.at(cell_type)) + if (map->modules_[tpl_name]->get_bool_attribute("\\keep_hierarchy")) + keepit = true; + if (keepit) { + if (!flatten_keep_list[cell]) { + log("Keeping %s.%s (found keep_hierarchy property).\n", log_id(module), log_id(cell)); + flatten_keep_list.insert(cell); + } + if (!flatten_done_list[cell->type]) + flatten_do_list.insert(cell->type); + continue; + } + } + for (auto &conn : cell->connections()) { RTLIL::SigSpec sig = sigmap(conn.second); sig.remove_const(); - if (SIZE(sig) == 0) + if (GetSize(sig) == 0) continue; for (auto &tpl_name : celltypeMap.at(cell_type)) { @@ -334,7 +386,7 @@ struct TechmapWorker { RTLIL::IdString derived_name = tpl_name; RTLIL::Module *tpl = map->modules_[tpl_name]; - std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters; + std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end()); if (tpl->get_bool_attribute("\\blackbox")) continue; @@ -376,7 +428,7 @@ struct TechmapWorker int port_counter = 1; for (auto &c : extmapper_cell->connections_) { - RTLIL::Wire *w = extmapper_module->addWire(c.first, SIZE(c.second)); + RTLIL::Wire *w = extmapper_module->addWire(c.first, GetSize(c.second)); if (w->name == "\\Y" || w->name == "\\Q") w->port_output = true; else @@ -522,7 +574,7 @@ struct TechmapWorker tpl = techmap_cache[key]; } else { if (cell->parameters.size() != 0) { - derived_name = tpl->derive(map, parameters); + derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end())); tpl = map->module(derived_name); log_continue = true; } @@ -623,7 +675,7 @@ struct TechmapWorker } for (auto conn : cell->connections()) - for (int i = 0; i < SIZE(conn.second); i++) + for (int i = 0; i < GetSize(conn.second); i++) { RTLIL::SigBit bit = sigmap(conn.second[i]); RTLIL::SigBit tplbit(tpl->wire(conn.first), i); @@ -968,7 +1020,7 @@ struct TechmapPass : public Pass { Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend); } - std::map<RTLIL::IdString, RTLIL::Module*> modules_new; + dict<RTLIL::IdString, RTLIL::Module*> modules_new; for (auto &it : map->modules_) { if (it.first.substr(0, 2) == "\\$") it.second->name = it.first.substr(1); @@ -1027,6 +1079,9 @@ struct FlattenPass : public Pass { log("pass is very simmilar to the 'techmap' pass. The only difference is that this\n"); log("pass is using the current design as mapping library.\n"); log("\n"); + log("Cells and/or modules with the 'keep_hiearchy' attribute set will not be\n"); + log("flattened by this command.\n"); + log("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { @@ -1039,8 +1094,8 @@ struct FlattenPass : public Pass { worker.flatten_mode = true; std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; - for (auto &it : design->modules_) - celltypeMap[it.first].insert(it.first); + for (auto module : design->modules()) + celltypeMap[module->name].insert(module->name); RTLIL::Module *top_mod = NULL; if (design->full_selection()) @@ -1048,26 +1103,40 @@ struct FlattenPass : public Pass { if (mod->get_bool_attribute("\\top")) top_mod = mod; - bool did_something = true; std::set<RTLIL::Cell*> handled_cells; - while (did_something) { - did_something = false; - if (top_mod != NULL) { - if (worker.techmap_module(design, top_mod, design, handled_cells, celltypeMap, false)) - did_something = true; - } else { - for (auto mod : design->modules()) - if (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) - did_something = true; + if (top_mod != NULL) { + worker.flatten_do_list.insert(top_mod->name); + while (!worker.flatten_do_list.empty()) { + auto mod = design->module(*worker.flatten_do_list.begin()); + while (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) { } + worker.flatten_done_list.insert(mod->name); + worker.flatten_do_list.erase(mod->name); } + } else { + for (auto mod : vector<Module*>(design->modules())) + while (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) { } } log("No more expansions possible.\n"); - if (top_mod != NULL) { - std::map<RTLIL::IdString, RTLIL::Module*> new_modules; - for (auto mod : design->modules()) - if (mod == top_mod || mod->get_bool_attribute("\\blackbox")) { + if (top_mod != NULL) + { + pool<RTLIL::IdString> used_modules, new_used_modules; + new_used_modules.insert(top_mod->name); + while (!new_used_modules.empty()) { + pool<RTLIL::IdString> queue; + queue.swap(new_used_modules); + for (auto modname : queue) + used_modules.insert(modname); + for (auto modname : queue) + for (auto cell : design->module(modname)->cells()) + if (design->module(cell->type) && !used_modules[cell->type]) + new_used_modules.insert(cell->type); + } + + dict<RTLIL::IdString, RTLIL::Module*> new_modules; + for (auto mod : vector<Module*>(design->modules())) + if (used_modules[mod->name] || mod->get_bool_attribute("\\blackbox")) { new_modules[mod->name] = mod; } else { log("Deleting now unused module %s.\n", log_id(mod)); @@ -1080,3 +1149,4 @@ struct FlattenPass : public Pass { } } FlattenPass; +PRIVATE_NAMESPACE_END |