diff options
author | Ahmed Irfan <ahmedirfan1983@gmail.com> | 2014-09-22 11:35:04 +0200 |
---|---|---|
committer | Ahmed Irfan <ahmedirfan1983@gmail.com> | 2014-09-22 11:35:04 +0200 |
commit | d3c67ad9b61f602de1100cd264efd227dcacb417 (patch) | |
tree | 88c462c53bdab128cd1edbded42483772f82612a /passes/techmap | |
parent | b783dbe148e6d246ebd107c0913de2989ab5af48 (diff) | |
parent | 13117bb346dd02d2345f716b4403239aebe3d0e2 (diff) | |
download | yosys-d3c67ad9b61f602de1100cd264efd227dcacb417.tar.gz yosys-d3c67ad9b61f602de1100cd264efd227dcacb417.tar.bz2 yosys-d3c67ad9b61f602de1100cd264efd227dcacb417.zip |
Merge branch 'master' of https://github.com/cliffordwolf/yosys into btor
added case for memwr cell that is used in muxes (same cell is used more than one time)
corrected bug for xnor and logic_not
added pmux cell translation
Conflicts:
backends/btor/btor.cc
Diffstat (limited to 'passes/techmap')
-rw-r--r-- | passes/techmap/.gitignore | 2 | ||||
-rw-r--r-- | passes/techmap/Makefile.inc | 24 | ||||
-rw-r--r-- | passes/techmap/alumacc.cc | 563 | ||||
-rw-r--r-- | passes/techmap/dfflibmap.cc | 60 | ||||
-rw-r--r-- | passes/techmap/extract.cc | 285 | ||||
-rw-r--r-- | passes/techmap/hilomap.cc | 42 | ||||
-rw-r--r-- | passes/techmap/iopadmap.cc | 67 | ||||
-rw-r--r-- | passes/techmap/libparse.cc | 45 | ||||
-rw-r--r-- | passes/techmap/libparse.h | 4 | ||||
-rw-r--r-- | passes/techmap/maccmap.cc | 394 | ||||
-rw-r--r-- | passes/techmap/simplemap.cc | 423 | ||||
-rw-r--r-- | passes/techmap/techmap.cc | 1104 |
12 files changed, 2234 insertions, 779 deletions
diff --git a/passes/techmap/.gitignore b/passes/techmap/.gitignore index ca9d3942c..e6dcc6bc0 100644 --- a/passes/techmap/.gitignore +++ b/passes/techmap/.gitignore @@ -1 +1 @@ -stdcells.inc +techmap.inc diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index ae1ebbb56..72998f87b 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -2,24 +2,30 @@ OBJS += passes/techmap/techmap.o OBJS += passes/techmap/simplemap.o OBJS += passes/techmap/dfflibmap.o +OBJS += passes/techmap/libparse.o + +ifneq ($(SMALL),1) OBJS += passes/techmap/iopadmap.o OBJS += passes/techmap/hilomap.o -OBJS += passes/techmap/libparse.o OBJS += passes/techmap/extract.o +OBJS += passes/techmap/maccmap.o +OBJS += passes/techmap/alumacc.o +endif -GENFILES += passes/techmap/stdcells.inc +GENFILES += passes/techmap/techmap.inc -passes/techmap/stdcells.inc: techlibs/common/stdcells.v - echo "// autogenerated from $<" > $@.new - od -v -td1 -w1 $< | awk 'BEGIN { print "static char stdcells_code[] = {"; } $$2 != "" { print $$2 ","; } \ - END { print 0 "};"; }' | fmt >> $@.new - mv $@.new $@ +passes/techmap/techmap.inc: techlibs/common/techmap.v + $(P) echo "// autogenerated from $<" > $@.new + $(Q) echo "static char stdcells_code[] = {" >> $@.new + $(Q) od -v -td1 -An $< | $(SED) -e 's/[0-9][0-9]*/&,/g' >> $@.new + $(Q) echo "0};" >> $@.new + $(Q) mv $@.new $@ -passes/techmap/techmap.o: passes/techmap/stdcells.inc +passes/techmap/techmap.o: passes/techmap/techmap.inc TARGETS += yosys-filterlib GENFILES += passes/techmap/filterlib.o yosys-filterlib: passes/techmap/filterlib.o - $(CXX) -o yosys-filterlib $(LDFLAGS) $^ $(LDLIBS) + $(P) $(CXX) -o yosys-filterlib $(LDFLAGS) $^ $(LDLIBS) diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc new file mode 100644 index 000000000..1115eead5 --- /dev/null +++ b/passes/techmap/alumacc.cc @@ -0,0 +1,563 @@ +/* + * 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/macc.h" + +struct AlumaccWorker +{ + RTLIL::Module *module; + SigMap sigmap; + + struct maccnode_t { + Macc macc; + RTLIL::Cell *cell; + RTLIL::SigSpec y; + int users; + }; + + struct alunode_t + { + std::vector<RTLIL::Cell*> cells; + RTLIL::SigSpec a, b, c, y; + std::vector<std::tuple<bool, bool, bool, bool, RTLIL::SigSpec>> cmp; + bool is_signed, invert_b; + + RTLIL::Cell *alu_cell; + RTLIL::SigSpec cached_lt, cached_gt, cached_eq, cached_ne; + RTLIL::SigSpec cached_cf, cached_of, cached_sf; + + RTLIL::SigSpec get_lt() { + if (SIZE(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) + 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) + cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort("\\X")); + return cached_eq; + } + + RTLIL::SigSpec get_ne() { + if (SIZE(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) { + 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]); + } + return cached_cf; + } + + RTLIL::SigSpec get_of() { + if (SIZE(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]); + } + return cached_of; + } + + RTLIL::SigSpec get_sf() { + if (SIZE(cached_sf) == 0) { + cached_sf = alu_cell->getPort("\\Y"); + cached_sf = cached_sf[SIZE(cached_sf)-1]; + } + return cached_sf; + } + }; + + std::map<RTLIL::SigBit, int> bit_users; + std::map<RTLIL::SigSpec, maccnode_t*> sig_macc; + std::map<RTLIL::SigSig, std::set<alunode_t*>> sig_alu; + int macc_counter, alu_counter; + + AlumaccWorker(RTLIL::Module *module) : module(module), sigmap(module) + { + macc_counter = 0; + alu_counter = 0; + } + + void count_bit_users() + { + for (auto port : module->ports) + for (auto bit : sigmap(module->wire(port))) + bit_users[bit]++; + + for (auto cell : module->cells()) + for (auto &conn : cell->connections()) + for (auto bit : sigmap(conn.second)) + bit_users[bit]++; + } + + void extract_macc() + { + for (auto cell : module->selected_cells()) + { + if (!cell->type.in("$pos", "$neg", "$add", "$sub", "$mul")) + continue; + + log(" creating $macc model for %s (%s).\n", log_id(cell), log_id(cell->type)); + + maccnode_t *n = new maccnode_t; + Macc::port_t new_port; + + n->cell = cell; + n->y = sigmap(cell->getPort("\\Y")); + n->users = 0; + + for (auto bit : n->y) + n->users = std::max(n->users, bit_users.at(bit) - 1); + + if (cell->type.in("$pos", "$neg")) + { + new_port.in_a = sigmap(cell->getPort("\\A")); + new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool(); + new_port.do_subtract = cell->type == "$neg"; + n->macc.ports.push_back(new_port); + } + + if (cell->type.in("$add", "$sub")) + { + new_port.in_a = sigmap(cell->getPort("\\A")); + new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool(); + new_port.do_subtract = false; + n->macc.ports.push_back(new_port); + + new_port.in_a = sigmap(cell->getPort("\\B")); + new_port.is_signed = cell->getParam("\\B_SIGNED").as_bool(); + new_port.do_subtract = cell->type == "$sub"; + n->macc.ports.push_back(new_port); + } + + if (cell->type.in("$mul")) + { + new_port.in_a = sigmap(cell->getPort("\\A")); + new_port.in_b = sigmap(cell->getPort("\\B")); + new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool(); + new_port.do_subtract = false; + n->macc.ports.push_back(new_port); + } + + log_assert(sig_macc.count(n->y) == 0); + sig_macc[n->y] = n; + } + } + + static bool macc_may_overflow(Macc &macc, int width, bool is_signed) + { + std::vector<int> port_sizes; + + for (auto &port : macc.ports) { + if (port.is_signed != is_signed) + 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)); + else + port_sizes.push_back(SIZE(port.in_a)); + } + + std::sort(port_sizes.begin(), port_sizes.end()); + + int acc_sum = 0, acc_shift = 0; + for (int sz : port_sizes) { + while ((sz - acc_shift) > 20) { + if (acc_sum & 1) + acc_sum++; + acc_sum = acc_sum >> 1; + acc_shift++; + } + acc_sum += (1 << (sz - acc_shift)) - 1; + } + + while (acc_sum) { + acc_sum = acc_sum >> 1; + acc_shift++; + } + + return acc_shift > width; + } + + void merge_macc() + { + while (1) + { + std::set<maccnode_t*> delete_nodes; + + for (auto &it : sig_macc) + { + auto n = it.second; + + if (delete_nodes.count(n)) + continue; + + for (int i = 0; i < SIZE(n->macc.ports); i++) + { + auto &port = n->macc.ports[i]; + + if (SIZE(port.in_b) > 0 || sig_macc.count(port.in_a) == 0) + continue; + + auto other_n = sig_macc.at(port.in_a); + + 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)) + 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++) { + if (do_subtract) + other_n->macc.ports[j].do_subtract = !other_n->macc.ports[j].do_subtract; + if (j == 0) + n->macc.ports[i--] = other_n->macc.ports[j]; + else + n->macc.ports.push_back(other_n->macc.ports[j]); + } + + delete_nodes.insert(other_n); + } + } + + if (delete_nodes.empty()) + break; + + for (auto n : delete_nodes) { + sig_macc.erase(n->y); + delete n; + } + } + } + + void macc_to_alu() + { + std::set<maccnode_t*> delete_nodes; + + for (auto &it : sig_macc) + { + auto n = it.second; + RTLIL::SigSpec A, B, C = n->macc.bit_ports; + bool a_signed = false, b_signed = false; + bool subtract_b = false; + alunode_t *alunode; + + for (auto &port : n->macc.ports) + if (SIZE(port.in_b) > 0) { + goto next_macc; + } else if (SIZE(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)) + goto next_macc; + B = port.in_a; + b_signed = port.is_signed; + subtract_b = port.do_subtract; + } else { + if (SIZE(A)) + goto next_macc; + A = port.in_a; + a_signed = port.is_signed; + } + + if (!a_signed || !b_signed) { + if (SIZE(A) == SIZE(n->y)) + a_signed = false; + if (SIZE(B) == SIZE(n->y)) + b_signed = false; + if (a_signed != b_signed) + goto next_macc; + } + + if (SIZE(A) == 0 && SIZE(C) > 0) { + A = C[0]; + C.remove(0); + } + + if (SIZE(B) == 0 && SIZE(C) > 0) { + B = C[0]; + C.remove(0); + } + + if (subtract_b) + C.append(RTLIL::S1); + + if (SIZE(C) > 1) + goto next_macc; + + if (!subtract_b && B < A && SIZE(B)) + std::swap(A, B); + + log(" creating $alu model for $macc %s.\n", log_id(n->cell)); + + alunode = new alunode_t; + alunode->cells.push_back(n->cell); + alunode->is_signed = a_signed; + alunode->invert_b = subtract_b; + + alunode->a = A; + alunode->b = B; + alunode->c = C; + alunode->y = n->y; + + sig_alu[RTLIL::SigSig(A, B)].insert(alunode); + delete_nodes.insert(n); + next_macc:; + } + + for (auto n : delete_nodes) { + sig_macc.erase(n->y); + delete n; + } + } + + void replace_macc() + { + for (auto &it : sig_macc) + { + auto n = it.second; + auto cell = module->addCell(NEW_ID, "$macc"); + macc_counter++; + + log(" creating $macc cell for %s: %s\n", log_id(n->cell), log_id(cell)); + + n->macc.optimize(SIZE(n->y)); + n->macc.to_cell(cell); + cell->setPort("\\Y", n->y); + cell->fixup_parameters(); + module->remove(n->cell); + delete n; + } + + sig_macc.clear(); + } + + void extract_cmp_alu() + { + std::vector<RTLIL::Cell*> lge_cells, eq_cells; + + for (auto cell : module->selected_cells()) + { + if (cell->type.in("$lt", "$le", "$ge", "$gt")) + lge_cells.push_back(cell); + if (cell->type.in("$eq", "$eqx", "$ne", "$nex")) + eq_cells.push_back(cell); + } + + for (auto cell : lge_cells) + { + log(" creating $alu model for %s (%s):", log_id(cell), log_id(cell->type)); + + bool cmp_less = cell->type.in("$lt", "$le"); + bool cmp_equal = cell->type.in("$le", "$ge"); + bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + + RTLIL::SigSpec A = sigmap(cell->getPort("\\A")); + RTLIL::SigSpec B = sigmap(cell->getPort("\\B")); + RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y")); + + if (B < A && SIZE(B)) { + cmp_less = !cmp_less; + std::swap(A, B); + } + + alunode_t *n = nullptr; + + for (auto node : sig_alu[RTLIL::SigSig(A, B)]) + if (node->is_signed == is_signed && node->invert_b && node->c == RTLIL::S1) { + n = node; + break; + } + + if (n == nullptr) { + n = new alunode_t; + n->a = A; + n->b = B; + n->c = RTLIL::S1; + n->y = module->addWire(NEW_ID, std::max(SIZE(A), SIZE(B))); + n->is_signed = is_signed; + n->invert_b = true; + sig_alu[RTLIL::SigSig(A, B)].insert(n); + log(" new $alu\n"); + } else { + log(" merged with %s.\n", log_id(n->cells.front())); + } + + n->cells.push_back(cell); + n->cmp.push_back(std::make_tuple(cmp_less, !cmp_less, cmp_equal, false, Y)); + } + + for (auto cell : eq_cells) + { + bool cmp_equal = cell->type.in("$eq", "$eqx"); + bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + + RTLIL::SigSpec A = sigmap(cell->getPort("\\A")); + RTLIL::SigSpec B = sigmap(cell->getPort("\\B")); + RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y")); + + if (B < A && SIZE(B)) + std::swap(A, B); + + alunode_t *n = nullptr; + + for (auto node : sig_alu[RTLIL::SigSig(A, B)]) + if (node->is_signed == is_signed && node->invert_b && node->c == RTLIL::S1) { + n = node; + break; + } + + if (n != nullptr) { + log(" creating $alu model for %s (%s): merged with %s.\n", log_id(cell), log_id(cell->type), log_id(n->cells.front())); + n->cells.push_back(cell); + n->cmp.push_back(std::make_tuple(false, false, cmp_equal, !cmp_equal, Y)); + } + } + } + + void replace_alu() + { + for (auto &it1 : sig_alu) + for (auto n : it1.second) + { + if (SIZE(n->b) == 0 && SIZE(n->c) == 0 && SIZE(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++) + log("%s%s", i ? ", ": "", log_id(n->cells[i])); + log(": %s\n", log_id(n->alu_cell)); + + goto delete_node; + } + + n->alu_cell = module->addCell(NEW_ID, "$alu"); + alu_counter++; + + log(" creating $alu cell for "); + for (int i = 0; i < SIZE(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("\\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->fixup_parameters(n->is_signed, n->is_signed); + + for (auto &it : n->cmp) + { + bool cmp_lt = std::get<0>(it); + bool cmp_gt = std::get<1>(it); + bool cmp_eq = std::get<2>(it); + bool cmp_ne = std::get<3>(it); + RTLIL::SigSpec cmp_y = std::get<4>(it); + + RTLIL::SigSpec sig; + if (cmp_lt) sig.append(n->get_lt()); + if (cmp_gt) sig.append(n->get_gt()); + if (cmp_eq) sig.append(n->get_eq()); + if (cmp_ne) sig.append(n->get_ne()); + + if (SIZE(sig) > 1) + sig = module->ReduceOr(NEW_ID, sig); + + sig.extend(SIZE(cmp_y)); + module->connect(cmp_y, sig); + } + + delete_node: + for (auto c : n->cells) + module->remove(c); + delete n; + } + + sig_alu.clear(); + } + + void run() + { + log("Extracting $alu and $macc cells in module %s:\n", log_id(module)); + + count_bit_users(); + extract_macc(); + merge_macc(); + macc_to_alu(); + replace_macc(); + extract_cmp_alu(); + replace_alu(); + + log(" created %d $alu and %d $macc cells.\n", alu_counter, macc_counter); + } +}; + +struct AlumaccPass : public Pass { + AlumaccPass() : Pass("alumacc", "extract ALU and MACC cells") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + 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("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + log_header("Executing ALUMACC pass (create $alu and $macc cells).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + // if (args[argidx] == "-foobar") { + // foobar_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto mod : design->selected_modules()) + if (!mod->has_processes_warn()) { + AlumaccWorker worker(mod); + worker.run(); + } + } +} AlumaccPass; + diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index 23d93353f..07993b868 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -21,6 +21,7 @@ #include "kernel/log.h" #include "libparse.h" #include <string.h> +#include <errno.h> using namespace PASS_DFFLIBMAP; @@ -28,7 +29,7 @@ struct cell_mapping { std::string cell_name; std::map<std::string, char> ports; }; -static std::map<std::string, cell_mapping> cell_mappings; +static std::map<RTLIL::IdString, cell_mapping> cell_mappings; static void logmap(std::string dff) { @@ -318,7 +319,7 @@ static bool expand_cellmap(std::string pattern, std::string inv) bool return_status = false; for (auto &it : cell_mappings) { - std::string from = it.first, to = it.first; + std::string from = it.first.str(), to = it.first.str(); if (from.size() != pattern.size()) continue; for (size_t i = 0; i < from.size(); i++) { @@ -342,7 +343,7 @@ static bool expand_cellmap(std::string pattern, std::string inv) static void map_sr_to_arst(const char *from, const char *to) { - if (cell_mappings.count(to) > 0) + 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]; @@ -387,45 +388,45 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module) log("Mapping DFF cells in module `%s':\n", module->name.c_str()); std::vector<RTLIL::Cell*> cell_list; - for (auto &it : module->cells) { + for (auto &it : module->cells_) { if (design->selected(module, it.second) && cell_mappings.count(it.second->type) > 0) cell_list.push_back(it.second); } std::map<std::string, int> stats; - for (auto cell : cell_list) { - cell_mapping &cm = cell_mappings[cell->type]; - RTLIL::Cell *new_cell = new RTLIL::Cell; - new_cell->name = cell->name; - new_cell->type = "\\" + cm.cell_name; + for (auto cell : cell_list) + { + auto cell_type = cell->type; + auto cell_name = cell->name; + auto cell_connections = cell->connections(); + module->remove(cell); + + cell_mapping &cm = cell_mappings[cell_type]; + RTLIL::Cell *new_cell = module->addCell(cell_name, "\\" + cm.cell_name); + for (auto &port : cm.ports) { RTLIL::SigSpec sig; if ('A' <= port.second && port.second <= 'Z') { - sig = cell->connections[std::string("\\") + port.second]; + sig = cell_connections[std::string("\\") + port.second]; + } 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)); + module->addNotGate(NEW_ID, sig, old_sig); } else if ('a' <= port.second && port.second <= 'z') { - sig = cell->connections[std::string("\\") + char(port.second - ('a' - 'A'))]; - RTLIL::Cell *inv_cell = new RTLIL::Cell; - RTLIL::Wire *inv_wire = new RTLIL::Wire; - inv_cell->name = stringf("$dfflibmap$inv$%d", RTLIL::autoidx); - inv_wire->name = stringf("$dfflibmap$sig$%d", RTLIL::autoidx++); - inv_cell->type = "$_INV_"; - inv_cell->connections[port.second == 'q' ? "\\Y" : "\\A"] = sig; - sig = RTLIL::SigSpec(inv_wire); - inv_cell->connections[port.second == 'q' ? "\\A" : "\\Y"] = sig; - module->cells[inv_cell->name] = inv_cell; - module->wires[inv_wire->name] = inv_wire; + sig = cell_connections[std::string("\\") + char(port.second - ('a' - 'A'))]; + sig = module->NotGate(NEW_ID, sig); } else if (port.second == '0' || port.second == '1') { sig = RTLIL::SigSpec(port.second == '0' ? 0 : 1, 1); } else if (port.second != 0) log_abort(); - new_cell->connections["\\" + port.first] = sig; + new_cell->setPort("\\" + port.first, sig); } - stats[stringf(" mapped %%d %s cells to %s cells.\n", cell->type.c_str(), new_cell->type.c_str())]++; - module->cells[cell->name] = new_cell; - delete cell; + + stats[stringf(" mapped %%d %s cells to %s cells.\n", cell_type.c_str(), new_cell->type.c_str())]++; } for (auto &stat: stats) @@ -467,11 +468,12 @@ struct DfflibmapPass : public Pass { if (liberty_file.empty()) log_cmd_error("Missing `-liberty liberty_file' option!\n"); - FILE *f = fopen(liberty_file.c_str(), "r"); - if (f == NULL) + std::ifstream f; + f.open(liberty_file.c_str()); + if (f.fail()) log_cmd_error("Can't open liberty file `%s': %s\n", liberty_file.c_str(), strerror(errno)); LibertyParser libparser(f); - fclose(f); + f.close(); find_cell(libparser.ast, "$_DFF_N_", false, false, false, false); find_cell(libparser.ast, "$_DFF_P_", true, false, false, false); @@ -528,7 +530,7 @@ struct DfflibmapPass : public Pass { log(" final dff cell mappings:\n"); logmap_all(); - for (auto &it : design->modules) + for (auto &it : design->modules_) if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox")) dfflibmap(design, it.second); diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc index eff14ff01..221e9e49d 100644 --- a/passes/techmap/extract.cc +++ b/passes/techmap/extract.cc @@ -23,7 +23,6 @@ #include "libs/subcircuit/subcircuit.h" #include <algorithm> #include <stdlib.h> -#include <assert.h> #include <stdio.h> #include <string.h> @@ -34,8 +33,14 @@ namespace 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; + 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) { @@ -46,12 +51,70 @@ namespace 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 + + 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; + if (!needleCell || !haystackCell) { + log_assert(!needleCell && !haystackCell); + return true; + } + + 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 (cell_attr.size() > 0 && !compareAttributes(cell_attr, needleCell->attributes, haystackCell->attributes)) return false; @@ -61,16 +124,13 @@ namespace RTLIL::Wire *lastHaystackWire = NULL; std::map<RTLIL::IdString, RTLIL::Const> emptyAttr; - for (auto &conn : needleCell->connections) + for (auto &conn : needleCell->connections()) { RTLIL::SigSpec needleSig = conn.second; - RTLIL::SigSpec haystackSig = haystackCell->connections.at(portMapping.at(conn.first)); - - needleSig.expand(); - haystackSig.expand(); + RTLIL::SigSpec haystackSig = haystackCell->getPort(portMapping.at(conn.first.str())); - for (int i = 0; i < std::min(needleSig.width, haystackSig.width); i++) { - RTLIL::Wire *needleWire = needleSig.chunks.at(i).wire, *haystackWire = haystackSig.chunks.at(i).wire; + 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; @@ -92,7 +152,7 @@ namespace int max_fanout = -1, std::set<std::pair<RTLIL::IdString, RTLIL::IdString>> *split = NULL) { SigMap sigmap(mod); - std::map<RTLIL::SigChunk, bit_ref_t> sig_bit_ref; + std::map<RTLIL::SigBit, bit_ref_t> sig_bit_ref; if (sel && !sel->selected(mod)) { log(" Skipping module %s as it is not selected.\n", id2cstr(mod->name)); @@ -121,111 +181,106 @@ namespace std::map<std::pair<RTLIL::Wire*, int>, int> sig_use_count; if (max_fanout > 0) - for (auto &cell_it : mod->cells) + for (auto &cell_it : mod->cells_) { RTLIL::Cell *cell = cell_it.second; if (!sel || sel->selected(mod, cell)) - for (auto &conn : cell->connections) { + for (auto &conn : cell->connections()) { RTLIL::SigSpec conn_sig = conn.second; sigmap.apply(conn_sig); - conn_sig.expand(); - for (auto &chunk : conn_sig.chunks) - if (chunk.wire != NULL) - sig_use_count[std::pair<RTLIL::Wire*, int>(chunk.wire, chunk.offset)]++; + for (auto &bit : conn_sig) + if (bit.wire != NULL) + sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)]++; } } // create graph nodes from cells - for (auto &cell_it : mod->cells) + for (auto &cell_it : mod->cells_) { RTLIL::Cell *cell = cell_it.second; if (sel && !sel->selected(mod, cell)) continue; - std::string type = cell->type; + std::string type = cell->type.str(); if (sel == NULL && type.substr(0, 2) == "\\$") type = type.substr(1); - graph.createNode(cell->name, type, (void*)cell); + graph.createNode(cell->name.str(), type, (void*)cell); - for (auto &conn : cell->connections) + for (auto &conn : cell->connections()) { - graph.createPort(cell->name, conn.first, conn.second.width); + graph.createPort(cell->name.str(), conn.first.str(), conn.second.size()); if (split && split->count(std::pair<RTLIL::IdString, RTLIL::IdString>(cell->type, conn.first)) > 0) continue; RTLIL::SigSpec conn_sig = conn.second; sigmap.apply(conn_sig); - conn_sig.expand(); - for (size_t i = 0; i < conn_sig.chunks.size(); i++) + for (int i = 0; i < conn_sig.size(); i++) { - auto &chunk = conn_sig.chunks[i]; - assert(chunk.width == 1); + auto &bit = conn_sig[i]; - if (chunk.wire == NULL) { + if (bit.wire == NULL) { if (constports) { std::string node = "$const$x"; - if (chunk.data.bits[0] == RTLIL::State::S0) node = "$const$0"; - if (chunk.data.bits[0] == RTLIL::State::S1) node = "$const$1"; - if (chunk.data.bits[0] == RTLIL::State::Sz) node = "$const$z"; - graph.createConnection(cell->name, conn.first, i, node, "\\Y", 0); + 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, conn.first, i, int(chunk.data.bits[0])); + graph.createConstant(cell->name.str(), conn.first.str(), i, int(bit.data)); continue; } - if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(chunk.wire, chunk.offset)] > max_fanout) + if (max_fanout > 0 && sig_use_count[std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset)] > max_fanout) continue; - if (sel && !sel->selected(mod, chunk.wire)) + if (sel && !sel->selected(mod, bit.wire)) continue; - if (sig_bit_ref.count(chunk) == 0) { - bit_ref_t &bit_ref = sig_bit_ref[chunk]; - bit_ref.cell = cell->name; - bit_ref.port = conn.first; + 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; } - bit_ref_t &bit_ref = sig_bit_ref[chunk]; - graph.createConnection(bit_ref.cell, bit_ref.port, bit_ref.bit, cell->name, conn.first, i); + 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 non-selected cells) - for (auto &cell_it : mod->cells) + for (auto &cell_it : mod->cells_) { RTLIL::Cell *cell = cell_it.second; if (sel && !sel->selected(mod, cell)) - for (auto &conn : cell->connections) + for (auto &conn : cell->connections()) { RTLIL::SigSpec conn_sig = conn.second; sigmap.apply(conn_sig); - conn_sig.expand(); - for (auto &chunk : conn_sig.chunks) - if (sig_bit_ref.count(chunk) != 0) { - bit_ref_t &bit_ref = sig_bit_ref[chunk]; + 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); } } } // mark external signals (used in module ports) - for (auto &wire_it : mod->wires) + for (auto &wire_it : mod->wires_) { RTLIL::Wire *wire = wire_it.second; if (wire->port_id > 0) { RTLIL::SigSpec conn_sig(wire); sigmap.apply(conn_sig); - conn_sig.expand(); - for (auto &chunk : conn_sig.chunks) - if (sig_bit_ref.count(chunk) != 0) { - bit_ref_t &bit_ref = sig_bit_ref[chunk]; + 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); } } @@ -238,21 +293,18 @@ namespace RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit::Solver::Result &match) { SigMap sigmap(needle); - SigSet<std::pair<std::string, int>> sig2port; + SigSet<std::pair<RTLIL::IdString, int>> sig2port; // create new cell - RTLIL::Cell *cell = new RTLIL::Cell; - cell->name = stringf("$extract$%s$%d", needle->name.c_str(), RTLIL::autoidx++); - cell->type = needle->name; - haystack->add(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) { + 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, 1, i)), std::pair<std::string, int>(wire->name, i)); - cell->connections[wire->name] = RTLIL::SigSpec(RTLIL::State::Sz, wire->width); + 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)); } } @@ -266,20 +318,20 @@ namespace if (needle_cell == NULL) continue; - for (auto &conn : needle_cell->connections) { + for (auto &conn : needle_cell->connections()) { RTLIL::SigSpec sig = sigmap(conn.second); - if (mapping.portMapping.count(conn.first) > 0 && sig2port.has(sigmap(sig))) { - sig.expand(); - for (int i = 0; i < sig.width; i++) - for (auto &port : sig2port.find(sig.chunks[i])) { - RTLIL::SigSpec bitsig = haystack_cell->connections.at(mapping.portMapping[conn.first]).extract(i, 1); - cell->connections.at(port.first).replace(port.second, bitsig); + 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->cells.erase(haystack_cell->name); - delete haystack_cell; + haystack->remove(haystack_cell); } return cell; @@ -315,6 +367,10 @@ struct ExtractPass : public Pass { log(" use the modules in this file as reference. This option can be used\n"); log(" multiple times.\n"); log("\n"); + log(" -map %%<design-name>\n"); + log(" use the modules in this in-memory design as reference. This option can\n"); + log(" be used multiple times.\n"); + log("\n"); log(" -verbose\n"); log(" print debug output while analyzing\n"); log("\n"); @@ -347,6 +403,12 @@ struct ExtractPass : public Pass { log(" -wire_attr <attribute_name>\n"); log(" Attributes on wires with the given name must match.\n"); log("\n"); + log(" -ignore_parameters\n"); + log(" Do not use parameters when matching cells.\n"); + log("\n"); + log(" -ignore_param <cell_type> <parameter_name>\n"); + log(" Do not use this parameter when matching cells.\n"); + log("\n"); log("This pass does not operate on modules with uprocessed processes in it.\n"); log("(I.e. the 'proc' pass should be used first to convert processes to netlists.)\n"); log("\n"); @@ -494,6 +556,15 @@ struct ExtractPass : public Pass { solver.wire_attr.insert(RTLIL::escape_id(args[++argidx])); continue; } + if (args[argidx] == "-ignore_parameters") { + solver.ignore_parameters = true; + continue; + } + if (args[argidx] == "-ignore_param" && argidx+2 < args.size()) { + solver.ignored_parameters.insert(std::pair<RTLIL::IdString, RTLIL::IdString>(RTLIL::escape_id(args[argidx+1]), RTLIL::escape_id(args[argidx+2]))); + argidx += 2; + continue; + } break; } extra_args(args, argidx, design); @@ -524,16 +595,33 @@ struct ExtractPass : public Pass { if (!mine_mode) { map = new RTLIL::Design; - for (auto &filename : map_filenames) { - FILE *f = fopen(filename.c_str(), "rt"); - if (f == NULL) - log_cmd_error("Can't open map file `%s'.\n", filename.c_str()); - Frontend::frontend_call(map, f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog"); - fclose(f); - - if (filename.size() <= 3 || filename.substr(filename.size()-3) != ".il") { - Pass::call(map, "proc"); - Pass::call(map, "opt_clean"); + for (auto &filename : map_filenames) + { + if (filename.substr(0, 1) == "%") + { + if (!saved_designs.count(filename.substr(1))) { + delete map; + log_cmd_error("Can't saved design `%s'.\n", filename.c_str()+1); + } + for (auto mod : saved_designs.at(filename.substr(1))->modules()) + if (!map->has(mod->name)) + map->add(mod->clone()); + } + else + { + std::ifstream f; + f.open(filename.c_str()); + if (f.fail()) { + delete map; + log_cmd_error("Can't open map file `%s'.\n", filename.c_str()); + } + Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog"); + f.close(); + + if (filename.size() <= 3 || filename.substr(filename.size()-3) != ".il") { + Pass::call(map, "proc"); + Pass::call(map, "opt_clean"); + } } } } @@ -544,7 +632,7 @@ struct ExtractPass : public Pass { log_header("Creating graphs for SubCircuit library.\n"); if (!mine_mode) - for (auto &mod_it : map->modules) { + for (auto &mod_it : map->modules_) { SubCircuit::Graph mod_graph; std::string graph_name = "needle_" + RTLIL::unescape_id(mod_it.first); log("Creating needle graph %s.\n", graph_name.c_str()); @@ -555,7 +643,7 @@ struct ExtractPass : public Pass { } } - for (auto &mod_it : design->modules) { + for (auto &mod_it : design->modules_) { SubCircuit::Graph mod_graph; std::string graph_name = "haystack_" + RTLIL::unescape_id(mod_it.first); log("Creating haystack graph %s.\n", graph_name.c_str()); @@ -613,7 +701,7 @@ struct ExtractPass : public Pass { log("\nFrequent SubCircuit with %d nodes and %d matches:\n", int(result.nodes.size()), result.totalMatchesAfterLimits); log(" primary match in %s:", id2cstr(haystack_map.at(result.graphId)->name)); for (auto &node : result.nodes) - log(" %s", id2cstr(node.nodeId)); + log(" %s", RTLIL::unescape_id(node.nodeId).c_str()); log("\n"); for (auto &it : result.matchesPerGraph) log(" matches in %s: %d\n", id2cstr(haystack_map.at(it.first)->name), it.second); @@ -628,49 +716,44 @@ struct ExtractPass : public Pass { cells.insert((RTLIL::Cell*)node.userData); for (auto cell : cells) - for (auto &conn : cell->connections) { + for (auto &conn : cell->connections()) { RTLIL::SigSpec sig = sigmap(conn.second); - for (auto &chunk : sig.chunks) + for (auto &chunk : sig.chunks()) if (chunk.wire != NULL) wires.insert(chunk.wire); } RTLIL::Module *newMod = new RTLIL::Module; newMod->name = stringf("\\needle%05d_%s_%dx", needleCounter++, id2cstr(haystack_map.at(result.graphId)->name), result.totalMatchesAfterLimits); - map->modules[newMod->name] = newMod; + map->add(newMod); - int portCounter = 1; for (auto wire : wires) { - RTLIL::Wire *newWire = new RTLIL::Wire; - newWire->name = wire->name; - newWire->width = wire->width; - newWire->port_id = portCounter++; + RTLIL::Wire *newWire = newMod->addWire(wire->name, wire->width); newWire->port_input = true; newWire->port_output = true; - newMod->add(newWire); } + newMod->fixup_ports(); + for (auto cell : cells) { - RTLIL::Cell *newCell = new RTLIL::Cell; - newCell->name = cell->name; - newCell->type = cell->type; + RTLIL::Cell *newCell = newMod->addCell(cell->name, cell->type); newCell->parameters = cell->parameters; - for (auto &conn : cell->connections) { - RTLIL::SigSpec sig = sigmap(conn.second); - for (auto &chunk : sig.chunks) + for (auto &conn : cell->connections()) { + std::vector<RTLIL::SigChunk> chunks = sigmap(conn.second); + for (auto &chunk : chunks) if (chunk.wire != NULL) - chunk.wire = newMod->wires.at(chunk.wire->name); - newCell->connections[conn.first] = sig; + chunk.wire = newMod->wires_.at(chunk.wire->name); + newCell->setPort(conn.first, chunks); } - newMod->add(newCell); } } - FILE *f = fopen(mine_outfile.c_str(), "wt"); - if (f == NULL) + std::ofstream f; + f.open(mine_outfile.c_str(), std::ofstream::trunc); + if (f.fail()) log_error("Can't open output file `%s'.\n", mine_outfile.c_str()); - Backend::backend_call(map, f, mine_outfile, "ilang"); - fclose(f); + Backend::backend_call(map, &f, mine_outfile, "ilang"); + f.close(); } delete map; diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc index bc5caa38c..784c4cf31 100644 --- a/passes/techmap/hilomap.cc +++ b/passes/techmap/hilomap.cc @@ -26,36 +26,28 @@ static std::string locell_celltype, locell_portname; static bool singleton_mode; static RTLIL::Module *module; -static RTLIL::SigChunk last_hi, last_lo; +static RTLIL::SigBit last_hi, last_lo; void hilomap_worker(RTLIL::SigSpec &sig) { - sig.expand(); - for (auto &c : sig.chunks) { - if (c.wire == NULL && (c.data.bits.at(0) == RTLIL::State::S1) && !hicell_celltype.empty()) { - if (!singleton_mode || last_hi.width == 0) { - last_hi = RTLIL::SigChunk(NEW_WIRE(module, 1)); - RTLIL::Cell *cell = new RTLIL::Cell; - cell->name = NEW_ID; - cell->type = RTLIL::escape_id(hicell_celltype); - cell->connections[RTLIL::escape_id(hicell_portname)] = last_hi; - module->add(cell); + for (auto &bit : sig) { + if (bit == RTLIL::State::S1 && !hicell_celltype.empty()) { + if (!singleton_mode || last_hi == RTLIL::State::Sm) { + last_hi = module->addWire(NEW_ID); + RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(hicell_celltype)); + cell->setPort(RTLIL::escape_id(hicell_portname), last_hi); } - c = last_hi; + bit = last_hi; } - if (c.wire == NULL && (c.data.bits.at(0) == RTLIL::State::S0) && !locell_celltype.empty()) { - if (!singleton_mode || last_lo.width == 0) { - last_lo = RTLIL::SigChunk(NEW_WIRE(module, 1)); - RTLIL::Cell *cell = new RTLIL::Cell; - cell->name = NEW_ID; - cell->type = RTLIL::escape_id(locell_celltype); - cell->connections[RTLIL::escape_id(locell_portname)] = last_lo; - module->add(cell); + if (bit == RTLIL::State::S0 && !locell_celltype.empty()) { + if (!singleton_mode || last_lo == RTLIL::State::Sm) { + last_lo = module->addWire(NEW_ID); + RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(locell_celltype)); + cell->setPort(RTLIL::escape_id(locell_portname), last_lo); } - c = last_lo; + bit = last_lo; } } - sig.optimize(); } struct HilomapPass : public Pass { @@ -112,15 +104,15 @@ struct HilomapPass : public Pass { } extra_args(args, argidx, design); - for (auto &it : design->modules) + for (auto &it : design->modules_) { module = it.second; if (!design->selected(module)) continue; - last_hi = RTLIL::SigChunk(); - last_lo = RTLIL::SigChunk(); + last_hi = RTLIL::State::Sm; + last_lo = RTLIL::State::Sm; module->rewrite_sigspecs(hilomap_worker); } diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index b98214977..9cd23ce6f 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -57,6 +57,11 @@ struct IopadmapPass : public Pass { log(" -nameparam <param_name>\n"); log(" Use the specified parameter to set the port name.\n"); 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("\n"); } virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { @@ -66,6 +71,7 @@ struct IopadmapPass : public Pass { std::string outpad_celltype, outpad_portname, outpad_portname2; std::string inoutpad_celltype, inoutpad_portname, inoutpad_portname2; std::string widthparam, nameparam; + bool flag_bits = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -97,18 +103,22 @@ struct IopadmapPass : public Pass { nameparam = args[++argidx]; continue; } + if (arg == "-bits") { + flag_bits = true; + continue; + } break; } extra_args(args, argidx, design); - for (auto &it : design->modules) + for (auto &it : design->modules_) { RTLIL::Module *module = it.second; - if (!design->selected(module)) + if (!design->selected(module) || module->get_bool_attribute("\\blackbox")) continue; - for (auto &it2 : module->wires) + for (auto &it2 : module->wires_) { RTLIL::Wire *wire = it2.second; @@ -146,31 +156,46 @@ struct IopadmapPass : public Pass { } else log_abort(); - if (wire->width != 1 && widthparam.empty()) { - log("Don't map multi-bit port %s.%s: Missing option -widthparam.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name)); + if (!flag_bits && wire->width != 1 && widthparam.empty()) { + log("Don't map multi-bit port %s.%s: Missing option -widthparam or -bits.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name)); continue; } log("Mapping port %s.%s using %s.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name), celltype.c_str()); - RTLIL::Cell *cell = new RTLIL::Cell; - cell->name = NEW_ID; - cell->type = RTLIL::escape_id(celltype); - cell->connections[RTLIL::escape_id(portname)] = RTLIL::SigSpec(wire); + RTLIL::Wire *new_wire = NULL; if (!portname2.empty()) { - RTLIL::Wire *new_wire = new RTLIL::Wire; - *new_wire = *wire; - wire->name = NEW_ID; - module->wires[wire->name] = wire; - module->wires[new_wire->name] = new_wire; - cell->connections[RTLIL::escape_id(portname2)] = RTLIL::SigSpec(new_wire); + new_wire = module->addWire(NEW_ID, wire); + module->swap_names(new_wire, wire); + } + + if (flag_bits) + { + for (int i = 0; i < wire->width; i++) + { + RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype)); + cell->setPort(RTLIL::escape_id(portname), RTLIL::SigSpec(wire, i)); + if (!portname2.empty()) + cell->setPort(RTLIL::escape_id(portname2), RTLIL::SigSpec(new_wire, i)); + if (!widthparam.empty()) + cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(1); + if (!nameparam.empty()) + cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(stringf("%s[%d]", RTLIL::id2cstr(wire->name), i)); + cell->attributes["\\keep"] = RTLIL::Const(1); + } + } + else + { + RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(celltype)); + cell->setPort(RTLIL::escape_id(portname), RTLIL::SigSpec(wire)); + if (!portname2.empty()) + cell->setPort(RTLIL::escape_id(portname2), RTLIL::SigSpec(new_wire)); + if (!widthparam.empty()) + cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(wire->width); + if (!nameparam.empty()) + cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(RTLIL::id2cstr(wire->name)); + cell->attributes["\\keep"] = RTLIL::Const(1); } - if (!widthparam.empty()) - cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(wire->width); - if (!nameparam.empty()) - cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(RTLIL::id2cstr(wire->name)); - cell->attributes["\\keep"] = RTLIL::Const(1); - module->add(cell); wire->port_id = 0; wire->port_input = false; diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 8cbb8e2be..612fa1117 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -21,6 +21,10 @@ #include <stdlib.h> #include <string.h> +#include <istream> +#include <fstream> +#include <iostream> + #ifndef FILTERLIB #include "kernel/log.h" #endif @@ -63,9 +67,10 @@ void LibertyAst::dump(FILE *f, std::string indent, std::string path, bool path_o } fprintf(f, "%s%s", indent.c_str(), id.c_str()); - if (!args.empty()) { + if (!args.empty() || !children.empty()) { + fprintf(f, "("); for (size_t i = 0; i < args.size(); i++) - fprintf(f, "%s%s", i > 0 ? ", " : "(", args[i].c_str()); + fprintf(f, "%s%s", i > 0 ? ", " : "", args[i].c_str()); fprintf(f, ")"); } if (!value.empty()) @@ -84,19 +89,19 @@ int LibertyParser::lexer(std::string &str) int c; do { - c = fgetc(f); + c = f.get(); } while (c == ' ' || c == '\t' || c == '\r'); if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') { str = c; while (1) { - c = fgetc(f); + c = f.get(); if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') str += c; else break; } - ungetc(c, f); + f.unget(); // fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str()); return 'v'; } @@ -104,7 +109,7 @@ int LibertyParser::lexer(std::string &str) if (c == '"') { str = c; while (1) { - c = fgetc(f); + c = f.get(); if (c == '\n') line++; str += c; @@ -116,34 +121,34 @@ int LibertyParser::lexer(std::string &str) } if (c == '/') { - c = fgetc(f); + c = f.get(); if (c == '*') { int last_c = 0; while (c > 0 && (last_c != '*' || c != '/')) { last_c = c; - c = fgetc(f); + c = f.get(); if (c == '\n') line++; } return lexer(str); } else if (c == '/') { while (c > 0 && c != '\n') - c = fgetc(f); + c = f.get(); line++; return lexer(str); } - ungetc(c, f); + f.unget(); // fprintf(stderr, "LEX: char >>/<<\n"); return '/'; } if (c == '\\') { - c = fgetc(f); + c = f.get(); if (c == '\r') - c = fgetc(f); + c = f.get(); if (c == '\n') return lexer(str); - ungetc(c, f); + f.unget(); return '\\'; } @@ -607,16 +612,20 @@ int main(int argc, char **argv) } } - FILE *f = stdin; + std::istream *f = &std::cin; + if (argc == 3) { - f = fopen(argv[2], "r"); - if (f == NULL) { + std::ifstream *ff = new std::ifstream; + ff->open(argv[2]); + if (ff->fail()) { + delete ff; fprintf(stderr, "Can't open liberty file `%s'.\n", argv[2]); usage(); } + f = ff; } - LibertyParser parser(f); + LibertyParser parser(*f); if (parser.ast) { if (flag_verilogsim) gen_verilogsim(parser.ast); @@ -625,7 +634,7 @@ int main(int argc, char **argv) } if (argc == 3) - fclose(f); + delete f; return 0; } diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index eff268bbb..247487424 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -41,10 +41,10 @@ namespace PASS_DFFLIBMAP struct LibertyParser { - FILE *f; + std::istream &f; int line; LibertyAst *ast; - LibertyParser(FILE *f) : f(f), line(1), ast(parse()) {} + LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {} ~LibertyParser() { if (ast) delete ast; } int lexer(std::string &str); LibertyAst *parse(); diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc new file mode 100644 index 000000000..2d625eefe --- /dev/null +++ b/passes/techmap/maccmap.cc @@ -0,0 +1,394 @@ +/* + * 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/macc.h" + +extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false); + +struct MaccmapWorker +{ + std::vector<std::set<RTLIL::SigBit>> bits; + RTLIL::Module *module; + int width; + + MaccmapWorker(RTLIL::Module *module, int width) : module(module), width(width) + { + bits.resize(width); + } + + void add(RTLIL::SigBit bit, int position) + { + if (position >= width || bit == RTLIL::S0) + return; + + if (bits.at(position).count(bit)) { + bits.at(position).erase(bit); + add(bit, position+1); + } else { + bits.at(position).insert(bit); + } + } + + void add(RTLIL::SigSpec a, bool is_signed, bool do_subtract) + { + a.extend(width, is_signed); + + if (do_subtract) { + a = module->Not(NEW_ID, a); + add(RTLIL::S1, 0); + } + + for (int i = 0; i < width; i++) + add(a[i], i); + } + + void add(RTLIL::SigSpec a, RTLIL::SigSpec b, bool is_signed, bool do_subtract) + { + if (SIZE(a) < SIZE(b)) + std::swap(a, b); + + a.extend(width, is_signed); + + if (SIZE(b) > width) + b.extend(width, is_signed); + + for (int i = 0; i < SIZE(b); i++) + if (is_signed && i+1 == SIZE(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); + add({b[i], RTLIL::SigSpec(0, i)}, false, do_subtract); + } + else + { + add(module->And(NEW_ID, a, RTLIL::SigSpec(b[i], width)), false, do_subtract); + a = {a.extract(0, width-1), RTLIL::S0}; + } + } + + 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); + + while (start_index < stop_index && in1[start_index] == RTLIL::S0 && in2[start_index] == RTLIL::S0 && in3[start_index] == RTLIL::S0) + start_index++; + + while (start_index < stop_index && in1[stop_index-1] == RTLIL::S0 && in2[stop_index-1] == RTLIL::S0 && in3[stop_index-1] == RTLIL::S0) + stop_index--; + + if (start_index == stop_index) + { + out1 = RTLIL::SigSpec(0, SIZE(in1)); + out2 = RTLIL::SigSpec(0, SIZE(in1)); + } + else + { + RTLIL::SigSpec out_zeros_lsb(0, start_index), out_zeros_msb(0, SIZE(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); + RTLIL::Wire *w1 = module->addWire(NEW_ID, width); + RTLIL::Wire *w2 = module->addWire(NEW_ID, width); + + RTLIL::Cell *cell = module->addCell(NEW_ID, "$fa"); + cell->setParam("\\WIDTH", width); + cell->setPort("\\A", in1); + cell->setPort("\\B", in2); + cell->setPort("\\C", in3); + cell->setPort("\\Y", w1); + cell->setPort("\\X", w2); + + out1 = {out_zeros_msb, w1, out_zeros_lsb}; + out2 = {out_zeros_msb, w2, out_zeros_lsb}; + } + } + + int tree_bit_slots(int n) + { + #if 0 + int retval = 1; + while (n > 2) { + retval += n / 3; + n = 2*(n / 3) + (n % 3); + } + return retval; + #else + return std::max(n - 1, 0); + #endif + } + + RTLIL::SigSpec synth() + { + std::vector<RTLIL::SigSpec> summands; + std::vector<RTLIL::SigBit> tree_sum_bits; + int unique_tree_bits = 0; + int count_tree_words = 0; + + while (1) + { + RTLIL::SigSpec summand(0, width); + bool got_data_bits = false; + + for (int i = 0; i < width; i++) + if (!bits.at(i).empty()) { + auto it = bits.at(i).begin(); + summand[i] = *it; + bits.at(i).erase(it); + got_data_bits = true; + } + + if (!got_data_bits) + break; + + summands.push_back(summand); + + while (1) + { + int free_bit_slots = tree_bit_slots(SIZE(summands)) - SIZE(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)); + max_position = i; + } + + if (max_depth == 0 || max_position > 4) + break; + + int required_bits = 0; + for (int i = 0; i <= max_position; i++) + if (SIZE(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) { + auto it = bits.at(i).begin(); + RTLIL::SigBit bit = *it; + for (int k = 0; k < (1 << i); k++, free_bit_slots--) + tree_sum_bits.push_back(bit); + bits.at(i).erase(it); + unique_tree_bits++; + } + + count_tree_words++; + } + } + + 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); + + if (SIZE(summands) == 0) { + log_assert(tree_sum_bits.empty()); + return RTLIL::SigSpec(0, width); + } + + if (SIZE(summands) == 1) { + log_assert(tree_sum_bits.empty()); + return summands.front(); + } + + while (SIZE(summands) > 2) + { + std::vector<RTLIL::SigSpec> new_summands; + for (int i = 0; i < SIZE(summands); i += 3) + if (i+2 < SIZE(summands)) { + RTLIL::SigSpec in1 = summands[i]; + RTLIL::SigSpec in2 = summands[i+1]; + RTLIL::SigSpec in3 = summands[i+2]; + RTLIL::SigSpec out1, out2; + fulladd(in1, in2, in3, out1, out2); + RTLIL::SigBit extra_bit = RTLIL::S0; + if (!tree_sum_bits.empty()) { + extra_bit = tree_sum_bits.back(); + tree_sum_bits.pop_back(); + } + new_summands.push_back(out1); + new_summands.push_back({out2.extract(0, width-1), extra_bit}); + } else { + new_summands.push_back(summands[i]); + i -= 2; + } + summands.swap(new_summands); + } + + + RTLIL::Cell *c = module->addCell(NEW_ID, "$alu"); + c->setPort("\\A", summands.front()); + c->setPort("\\B", summands.back()); + c->setPort("\\CI", RTLIL::S0); + c->setPort("\\BI", RTLIL::S0); + c->setPort("\\Y", module->addWire(NEW_ID, width)); + c->setPort("\\X", module->addWire(NEW_ID, width)); + c->setPort("\\CO", module->addWire(NEW_ID, width)); + c->fixup_parameters(); + + if (!tree_sum_bits.empty()) { + c->setPort("\\CI", tree_sum_bits.back()); + tree_sum_bits.pop_back(); + } + log_assert(tree_sum_bits.empty()); + + return c->getPort("\\Y"); + } +}; + +void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap) +{ + int width = SIZE(cell->getPort("\\Y")); + + Macc macc; + macc.from_cell(cell); + + RTLIL::SigSpec all_input_bits; + all_input_bits.append(cell->getPort("\\A")); + all_input_bits.append(cell->getPort("\\B")); + + if (all_input_bits.to_sigbit_set().count(RTLIL::Sx)) { + module->connect(cell->getPort("\\Y"), RTLIL::SigSpec(RTLIL::Sx, width)); + return; + } + + for (auto &port : macc.ports) + if (SIZE(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"); + 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"); + + if (SIZE(macc.bit_ports) != 0) + log(" add bits %s (%d bits)\n", log_signal(macc.bit_ports), SIZE(macc.bit_ports)); + + if (unmap) + { + typedef std::pair<RTLIL::SigSpec, bool> summand_t; + std::vector<summand_t> summands; + + for (auto &port : macc.ports) { + summand_t this_summand; + if (SIZE(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) { + this_summand.first = module->addWire(NEW_ID, width); + module->addPos(NEW_ID, port.in_a, this_summand.first, port.is_signed); + } else { + this_summand.first = port.in_a; + } + this_summand.second = port.do_subtract; + summands.push_back(this_summand); + } + + for (auto &bit : macc.bit_ports) + summands.push_back(summand_t(bit, false)); + + if (SIZE(summands) == 0) + summands.push_back(summand_t(RTLIL::SigSpec(0, width), false)); + + while (SIZE(summands) > 1) + { + std::vector<summand_t> new_summands; + for (int i = 0; i < SIZE(summands); i += 2) { + if (i+1 < SIZE(summands)) { + summand_t this_summand; + this_summand.first = module->addWire(NEW_ID, width); + this_summand.second = summands[i].second && summands[i+1].second; + if (summands[i].second == summands[i+1].second) + module->addAdd(NEW_ID, summands[i].first, summands[i+1].first, this_summand.first); + else if (summands[i].second) + module->addSub(NEW_ID, summands[i+1].first, summands[i].first, this_summand.first); + else if (summands[i+1].second) + module->addSub(NEW_ID, summands[i].first, summands[i+1].first, this_summand.first); + else + log_abort(); + new_summands.push_back(this_summand); + } else + new_summands.push_back(summands[i]); + } + summands.swap(new_summands); + } + + if (summands.front().second) + module->addNeg(NEW_ID, summands.front().first, cell->getPort("\\Y")); + else + module->connect(cell->getPort("\\Y"), summands.front().first); + } + else + { + MaccmapWorker worker(module, width); + + for (auto &port : macc.ports) + if (SIZE(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); + + for (auto &bit : macc.bit_ports) + worker.add(bit, 0); + + module->connect(cell->getPort("\\Y"), worker.synth()); + } +} + +struct MaccmapPass : public Pass { + MaccmapPass() : Pass("maccmap", "mapping macc cells") { } + virtual void help() + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" maccmap [-unmap] [selection]\n"); + log("\n"); + log("This pass maps $macc cells to yosys gate primitives. When the -unmap option is\n"); + log("used then the $macc cell is mapped to $and, $sub, etc. cells instead.\n"); + log("\n"); + } + virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + { + bool unmap_mode = false; + + log_header("Executing MACCMAP pass (map $macc cells).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-unmap") { + unmap_mode = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto mod : design->selected_modules()) + for (auto cell : mod->selected_cells()) + if (cell->type == "$macc") { + log("Mapping %s.%s (%s).\n", log_id(mod), log_id(cell), log_id(cell->type)); + maccmap(mod, cell, unmap_mode); + mod->remove(cell); + } + } +} MaccmapPass; + diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index e67b1e055..f8d5d4584 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -21,84 +21,52 @@ #include "kernel/sigtools.h" #include "kernel/log.h" #include <stdlib.h> -#include <assert.h> #include <stdio.h> #include <string.h> -extern void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers); +extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers); static void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell) { - int width = cell->parameters.at("\\Y_WIDTH").as_int(); + RTLIL::SigSpec sig_a = cell->getPort("\\A"); + RTLIL::SigSpec sig_y = cell->getPort("\\Y"); - RTLIL::SigSpec sig_a = cell->connections.at("\\A"); - sig_a.extend(width, cell->parameters.at("\\A_SIGNED").as_bool()); - sig_a.expand(); + sig_a.extend(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool()); - RTLIL::SigSpec sig_y = cell->connections.at("\\Y"); - sig_y.expand(); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = "$_INV_"; - gate->connections["\\A"] = sig_a.chunks.at(i); - gate->connections["\\Y"] = sig_y.chunks.at(i); - module->add(gate); + for (int i = 0; i < SIZE(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) { - int width = cell->parameters.at("\\Y_WIDTH").as_int(); - - RTLIL::SigSpec sig_a = cell->connections.at("\\A"); - sig_a.extend(width, cell->parameters.at("\\A_SIGNED").as_bool()); - - RTLIL::SigSpec sig_y = cell->connections.at("\\Y"); - - module->connections.push_back(RTLIL::SigSig(sig_y, sig_a)); -} - -static void simplemap_bu0(RTLIL::Module *module, RTLIL::Cell *cell) -{ - int width = cell->parameters.at("\\Y_WIDTH").as_int(); - - RTLIL::SigSpec sig_a = cell->connections.at("\\A"); - sig_a.extend_u0(width, cell->parameters.at("\\A_SIGNED").as_bool()); + RTLIL::SigSpec sig_a = cell->getPort("\\A"); + RTLIL::SigSpec sig_y = cell->getPort("\\Y"); - RTLIL::SigSpec sig_y = cell->connections.at("\\Y"); + sig_a.extend_u0(SIZE(sig_y), cell->parameters.at("\\A_SIGNED").as_bool()); - module->connections.push_back(RTLIL::SigSig(sig_y, sig_a)); + module->connect(RTLIL::SigSig(sig_y, sig_a)); } static void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell) { - int width = cell->parameters.at("\\Y_WIDTH").as_int(); + RTLIL::SigSpec sig_a = cell->getPort("\\A"); + RTLIL::SigSpec sig_b = cell->getPort("\\B"); + RTLIL::SigSpec sig_y = cell->getPort("\\Y"); - RTLIL::SigSpec sig_a = cell->connections.at("\\A"); - sig_a.extend_u0(width, cell->parameters.at("\\A_SIGNED").as_bool()); - sig_a.expand(); - - RTLIL::SigSpec sig_b = cell->connections.at("\\B"); - sig_b.extend_u0(width, cell->parameters.at("\\B_SIGNED").as_bool()); - sig_b.expand(); - - RTLIL::SigSpec sig_y = cell->connections.at("\\Y"); - sig_y.expand(); + 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()); if (cell->type == "$xnor") { - RTLIL::SigSpec sig_t = module->new_wire(width, NEW_ID); - sig_t.expand(); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = "$_INV_"; - gate->connections["\\A"] = sig_t.chunks.at(i); - gate->connections["\\Y"] = sig_y.chunks.at(i); - module->add(gate); + RTLIL::SigSpec sig_t = module->addWire(NEW_ID, SIZE(sig_y)); + + for (int i = 0; i < SIZE(sig_y); i++) { + RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_"); + gate->setPort("\\A", sig_t[i]); + gate->setPort("\\Y", sig_y[i]); } sig_y = sig_t; @@ -111,38 +79,33 @@ 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 < width; i++) { - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = gate_type; - gate->connections["\\A"] = sig_a.chunks.at(i); - gate->connections["\\B"] = sig_b.chunks.at(i); - gate->connections["\\Y"] = sig_y.chunks.at(i); - module->add(gate); + for (int i = 0; i < SIZE(sig_y); i++) { + RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); + gate->setPort("\\A", sig_a[i]); + gate->setPort("\\B", sig_b[i]); + gate->setPort("\\Y", sig_y[i]); } } static void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_a = cell->connections.at("\\A"); - sig_a.expand(); + RTLIL::SigSpec sig_a = cell->getPort("\\A"); + RTLIL::SigSpec sig_y = cell->getPort("\\Y"); - RTLIL::SigSpec sig_y = cell->connections.at("\\Y"); - - if (sig_y.width == 0) + if (sig_y.size() == 0) return; - if (sig_a.width == 0) { - if (cell->type == "$reduce_and") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.width))); - if (cell->type == "$reduce_or") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.width))); - if (cell->type == "$reduce_xor") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.width))); - if (cell->type == "$reduce_xnor") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.width))); - if (cell->type == "$reduce_bool") module->connections.push_back(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.width))); + if (sig_a.size() == 0) { + if (cell->type == "$reduce_and") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == "$reduce_or") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == "$reduce_xor") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == "$reduce_xnor") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == "$reduce_bool") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); return; } - if (sig_y.width > 1) { - module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.width-1), RTLIL::SigSpec(0, sig_y.width-1))); + if (sig_y.size() > 1) { + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); sig_y = sig_y.extract(0, 1); } @@ -154,122 +117,106 @@ static void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) if (cell->type == "$reduce_bool") gate_type = "$_OR_"; log_assert(!gate_type.empty()); - RTLIL::SigSpec *last_output = NULL; + RTLIL::Cell *last_output_cell = NULL; - while (sig_a.width > 1) + while (sig_a.size() > 1) { - RTLIL::SigSpec sig_t = module->new_wire(sig_a.width / 2, NEW_ID); - sig_t.expand(); + RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig_a.size() / 2); - for (int i = 0; i < sig_a.width; i += 2) + for (int i = 0; i < sig_a.size(); i += 2) { - if (i+1 == sig_a.width) { - sig_t.append(sig_a.chunks.at(i)); + if (i+1 == sig_a.size()) { + sig_t.append(sig_a[i]); continue; } - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = gate_type; - gate->connections["\\A"] = sig_a.chunks.at(i); - gate->connections["\\B"] = sig_a.chunks.at(i+1); - gate->connections["\\Y"] = sig_t.chunks.at(i/2); - last_output = &gate->connections["\\Y"]; - module->add(gate); + RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); + gate->setPort("\\A", sig_a[i]); + gate->setPort("\\B", sig_a[i+1]); + gate->setPort("\\Y", sig_t[i/2]); + last_output_cell = gate; } sig_a = sig_t; } if (cell->type == "$reduce_xnor") { - RTLIL::SigSpec sig_t = module->new_wire(1, NEW_ID); - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = "$_INV_"; - gate->connections["\\A"] = sig_a; - gate->connections["\\Y"] = sig_t; - last_output = &gate->connections["\\Y"]; - module->add(gate); + RTLIL::SigSpec sig_t = module->addWire(NEW_ID); + RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_"); + gate->setPort("\\A", sig_a); + gate->setPort("\\Y", sig_t); + last_output_cell = gate; sig_a = sig_t; } - if (last_output == NULL) { - module->connections.push_back(RTLIL::SigSig(sig_y, sig_a)); + if (last_output_cell == NULL) { + module->connect(RTLIL::SigSig(sig_y, sig_a)); } else { - *last_output = sig_y; + last_output_cell->setPort("\\Y", sig_y); } } static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig) { - sig.expand(); - - while (sig.width > 1) + while (sig.size() > 1) { - RTLIL::SigSpec sig_t = module->new_wire(sig.width / 2, NEW_ID); - sig_t.expand(); + RTLIL::SigSpec sig_t = module->addWire(NEW_ID, sig.size() / 2); - for (int i = 0; i < sig.width; i += 2) + for (int i = 0; i < sig.size(); i += 2) { - if (i+1 == sig.width) { - sig_t.append(sig.chunks.at(i)); + if (i+1 == sig.size()) { + sig_t.append(sig[i]); continue; } - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = "$_OR_"; - gate->connections["\\A"] = sig.chunks.at(i); - gate->connections["\\B"] = sig.chunks.at(i+1); - gate->connections["\\Y"] = sig_t.chunks.at(i/2); - module->add(gate); + RTLIL::Cell *gate = module->addCell(NEW_ID, "$_OR_"); + gate->setPort("\\A", sig[i]); + gate->setPort("\\B", sig[i+1]); + gate->setPort("\\Y", sig_t[i/2]); } sig = sig_t; } - if (sig.width == 0) + if (sig.size() == 0) sig = RTLIL::SigSpec(0, 1); } static void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_a = cell->connections.at("\\A"); + RTLIL::SigSpec sig_a = cell->getPort("\\A"); logic_reduce(module, sig_a); - RTLIL::SigSpec sig_y = cell->connections.at("\\Y"); + RTLIL::SigSpec sig_y = cell->getPort("\\Y"); - if (sig_y.width == 0) + if (sig_y.size() == 0) return; - if (sig_y.width > 1) { - module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.width-1), RTLIL::SigSpec(0, sig_y.width-1))); + if (sig_y.size() > 1) { + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); sig_y = sig_y.extract(0, 1); } - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = "$_INV_"; - gate->connections["\\A"] = sig_a; - gate->connections["\\Y"] = sig_y; - module->add(gate); + RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_"); + gate->setPort("\\A", sig_a); + gate->setPort("\\Y", sig_y); } static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_a = cell->connections.at("\\A"); + RTLIL::SigSpec sig_a = cell->getPort("\\A"); logic_reduce(module, sig_a); - RTLIL::SigSpec sig_b = cell->connections.at("\\B"); + RTLIL::SigSpec sig_b = cell->getPort("\\B"); logic_reduce(module, sig_b); - RTLIL::SigSpec sig_y = cell->connections.at("\\Y"); + RTLIL::SigSpec sig_y = cell->getPort("\\Y"); - if (sig_y.width == 0) + if (sig_y.size() == 0) return; - if (sig_y.width > 1) { - module->connections.push_back(RTLIL::SigSig(sig_y.extract(1, sig_y.width-1), RTLIL::SigSpec(0, sig_y.width-1))); + if (sig_y.size() > 1) { + module->connect(RTLIL::SigSig(sig_y.extract(1, sig_y.size()-1), RTLIL::SigSpec(0, sig_y.size()-1))); sig_y = sig_y.extract(0, 1); } @@ -278,54 +225,41 @@ static void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell) if (cell->type == "$logic_or") gate_type = "$_OR_"; log_assert(!gate_type.empty()); - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = gate_type; - gate->connections["\\A"] = sig_a; - gate->connections["\\B"] = sig_b; - gate->connections["\\Y"] = sig_y; - module->add(gate); + RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); + gate->setPort("\\A", sig_a); + gate->setPort("\\B", sig_b); + gate->setPort("\\Y", sig_y); } static void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell) { - int width = cell->parameters.at("\\WIDTH").as_int(); - - RTLIL::SigSpec sig_a = cell->connections.at("\\A"); - sig_a.expand(); - - RTLIL::SigSpec sig_b = cell->connections.at("\\B"); - sig_b.expand(); - - RTLIL::SigSpec sig_y = cell->connections.at("\\Y"); - sig_y.expand(); - - for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = "$_MUX_"; - gate->connections["\\A"] = sig_a.chunks.at(i); - gate->connections["\\B"] = sig_b.chunks.at(i); - gate->connections["\\S"] = cell->connections.at("\\S"); - gate->connections["\\Y"] = sig_y.chunks.at(i); - module->add(gate); + 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 < SIZE(sig_y); i++) { + RTLIL::Cell *gate = module->addCell(NEW_ID, "$_MUX_"); + gate->setPort("\\A", sig_a[i]); + gate->setPort("\\B", sig_b[i]); + gate->setPort("\\S", cell->getPort("\\S")); + gate->setPort("\\Y", sig_y[i]); } } static void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell) { int offset = cell->parameters.at("\\OFFSET").as_int(); - RTLIL::SigSpec sig_a = cell->connections.at("\\A"); - RTLIL::SigSpec sig_y = cell->connections.at("\\Y"); - module->connections.push_back(RTLIL::SigSig(sig_y, sig_a.extract(offset, sig_y.width))); + RTLIL::SigSpec sig_a = cell->getPort("\\A"); + RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + module->connect(RTLIL::SigSig(sig_y, sig_a.extract(offset, sig_y.size()))); } static void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_ab = cell->connections.at("\\A"); - sig_ab.append(cell->connections.at("\\B")); - RTLIL::SigSpec sig_y = cell->connections.at("\\Y"); - module->connections.push_back(RTLIL::SigSig(sig_y, sig_ab)); + RTLIL::SigSpec sig_ab = cell->getPort("\\A"); + sig_ab.append(cell->getPort("\\B")); + RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + module->connect(RTLIL::SigSig(sig_y, sig_ab)); } static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell) @@ -334,25 +268,17 @@ static void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell) char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N'; char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N'; - RTLIL::SigSpec sig_s = cell->connections.at("\\SET"); - sig_s.expand(); - - RTLIL::SigSpec sig_r = cell->connections.at("\\CLR"); - sig_r.expand(); - - RTLIL::SigSpec sig_q = cell->connections.at("\\Q"); - sig_q.expand(); + RTLIL::SigSpec sig_s = cell->getPort("\\SET"); + RTLIL::SigSpec sig_r = cell->getPort("\\CLR"); + RTLIL::SigSpec sig_q = cell->getPort("\\Q"); std::string gate_type = stringf("$_SR_%c%c_", set_pol, clr_pol); for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = gate_type; - gate->connections["\\S"] = sig_s.chunks.at(i); - gate->connections["\\R"] = sig_r.chunks.at(i); - gate->connections["\\Q"] = sig_q.chunks.at(i); - module->add(gate); + RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); + gate->setPort("\\S", sig_s[i]); + gate->setPort("\\R", sig_r[i]); + gate->setPort("\\Q", sig_q[i]); } } @@ -361,24 +287,17 @@ static 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'; - RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK"); - - RTLIL::SigSpec sig_d = cell->connections.at("\\D"); - sig_d.expand(); - - RTLIL::SigSpec sig_q = cell->connections.at("\\Q"); - sig_q.expand(); + RTLIL::SigSpec sig_clk = cell->getPort("\\CLK"); + RTLIL::SigSpec sig_d = cell->getPort("\\D"); + RTLIL::SigSpec sig_q = cell->getPort("\\Q"); std::string gate_type = stringf("$_DFF_%c_", clk_pol); for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = gate_type; - gate->connections["\\C"] = sig_clk; - gate->connections["\\D"] = sig_d.chunks.at(i); - gate->connections["\\Q"] = sig_q.chunks.at(i); - module->add(gate); + RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); + gate->setPort("\\C", sig_clk); + gate->setPort("\\D", sig_d[i]); + gate->setPort("\\Q", sig_q[i]); } } @@ -389,32 +308,21 @@ static void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell) char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N'; char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N'; - RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK"); - - RTLIL::SigSpec sig_s = cell->connections.at("\\SET"); - sig_s.expand(); - - RTLIL::SigSpec sig_r = cell->connections.at("\\CLR"); - sig_r.expand(); - - RTLIL::SigSpec sig_d = cell->connections.at("\\D"); - sig_d.expand(); - - RTLIL::SigSpec sig_q = cell->connections.at("\\Q"); - sig_q.expand(); + RTLIL::SigSpec sig_clk = cell->getPort("\\CLK"); + RTLIL::SigSpec sig_s = cell->getPort("\\SET"); + RTLIL::SigSpec sig_r = cell->getPort("\\CLR"); + RTLIL::SigSpec sig_d = cell->getPort("\\D"); + RTLIL::SigSpec sig_q = cell->getPort("\\Q"); std::string gate_type = stringf("$_DFFSR_%c%c%c_", clk_pol, set_pol, clr_pol); for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = gate_type; - gate->connections["\\C"] = sig_clk; - gate->connections["\\S"] = sig_s.chunks.at(i); - gate->connections["\\R"] = sig_r.chunks.at(i); - gate->connections["\\D"] = sig_d.chunks.at(i); - gate->connections["\\Q"] = sig_q.chunks.at(i); - module->add(gate); + RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); + gate->setPort("\\C", sig_clk); + gate->setPort("\\S", sig_s[i]); + gate->setPort("\\R", sig_r[i]); + gate->setPort("\\D", sig_d[i]); + gate->setPort("\\Q", sig_q[i]); } } @@ -428,27 +336,20 @@ static void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell) while (int(rst_val.size()) < width) rst_val.push_back(RTLIL::State::S0); - RTLIL::SigSpec sig_clk = cell->connections.at("\\CLK"); - RTLIL::SigSpec sig_rst = cell->connections.at("\\ARST"); - - RTLIL::SigSpec sig_d = cell->connections.at("\\D"); - sig_d.expand(); - - RTLIL::SigSpec sig_q = cell->connections.at("\\Q"); - sig_q.expand(); + RTLIL::SigSpec sig_clk = cell->getPort("\\CLK"); + RTLIL::SigSpec sig_rst = cell->getPort("\\ARST"); + RTLIL::SigSpec sig_d = cell->getPort("\\D"); + RTLIL::SigSpec sig_q = cell->getPort("\\Q"); std::string gate_type_0 = stringf("$_DFF_%c%c0_", clk_pol, rst_pol); std::string gate_type_1 = stringf("$_DFF_%c%c1_", clk_pol, rst_pol); for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0; - gate->connections["\\C"] = sig_clk; - gate->connections["\\R"] = sig_rst; - gate->connections["\\D"] = sig_d.chunks.at(i); - gate->connections["\\Q"] = sig_q.chunks.at(i); - module->add(gate); + RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0); + gate->setPort("\\C", sig_clk); + gate->setPort("\\R", sig_rst); + gate->setPort("\\D", sig_d[i]); + gate->setPort("\\Q", sig_q[i]); } } @@ -457,32 +358,24 @@ static 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'; - RTLIL::SigSpec sig_en = cell->connections.at("\\EN"); - - RTLIL::SigSpec sig_d = cell->connections.at("\\D"); - sig_d.expand(); - - RTLIL::SigSpec sig_q = cell->connections.at("\\Q"); - sig_q.expand(); + 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("$_DLATCH_%c_", en_pol); for (int i = 0; i < width; i++) { - RTLIL::Cell *gate = new RTLIL::Cell; - gate->name = NEW_ID; - gate->type = gate_type; - gate->connections["\\E"] = sig_en; - gate->connections["\\D"] = sig_d.chunks.at(i); - gate->connections["\\Q"] = sig_q.chunks.at(i); - module->add(gate); + RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); + gate->setPort("\\E", sig_en); + gate->setPort("\\D", sig_d[i]); + gate->setPort("\\Q", sig_q[i]); } } -void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers) +void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers) { mappers["$not"] = simplemap_not; mappers["$pos"] = simplemap_pos; - mappers["$bu0"] = simplemap_bu0; mappers["$and"] = simplemap_bitop; mappers["$or"] = simplemap_bitop; mappers["$xor"] = simplemap_bitop; @@ -516,7 +409,7 @@ struct SimplemapPass : public Pass { log("This pass maps a small selection of simple coarse-grain cells to yosys gate\n"); log("primitives. The following internal cell types are mapped by this pass:\n"); log("\n"); - log(" $not, $pos, $bu0, $and, $or, $xor, $xnor\n"); + log(" $not, $pos, $and, $or, $xor, $xnor\n"); log(" $reduce_and, $reduce_or, $reduce_xor, $reduce_xnor, $reduce_bool\n"); log(" $logic_not, $logic_and, $logic_or, $mux\n"); log(" $sr, $dff, $dffsr, $adff, $dlatch\n"); @@ -527,25 +420,21 @@ struct SimplemapPass : public Pass { log_header("Executing SIMPLEMAP pass (map simple cells to gate primitives).\n"); extra_args(args, 1, design); - std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers; + std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> mappers; simplemap_get_mappers(mappers); - for (auto &mod_it : design->modules) { - if (!design->selected(mod_it.second)) + for (auto mod : design->modules()) { + if (!design->selected(mod)) continue; - std::vector<RTLIL::Cell*> delete_cells; - for (auto &cell_it : mod_it.second->cells) { - if (mappers.count(cell_it.second->type) == 0) + std::vector<RTLIL::Cell*> cells = mod->cells(); + for (auto cell : cells) { + if (mappers.count(cell->type) == 0) continue; - if (!design->selected(mod_it.second, cell_it.second)) + if (!design->selected(mod, cell)) continue; - log("Mapping %s.%s (%s).\n", RTLIL::id2cstr(mod_it.first), RTLIL::id2cstr(cell_it.first), RTLIL::id2cstr(cell_it.second->type)); - mappers.at(cell_it.second->type)(mod_it.second, cell_it.second); - delete_cells.push_back(cell_it.second); - } - for (auto &it : delete_cells) { - mod_it.second->cells.erase(it->name); - delete it; + log("Mapping %s.%s (%s).\n", log_id(mod), log_id(cell), log_id(cell->type)); + mappers.at(cell->type)(mod, cell); + mod->remove(cell); } } } diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index eeeebd111..ed466faa1 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -17,18 +17,22 @@ * */ -#include "kernel/register.h" +#include "kernel/yosys.h" +#include "kernel/utils.h" #include "kernel/sigtools.h" -#include "kernel/log.h" +#include "libs/sha1/sha1.h" + #include <stdlib.h> -#include <assert.h> #include <stdio.h> #include <string.h> -#include "passes/techmap/stdcells.inc" +#include "passes/techmap/techmap.inc" // see simplemap.cc -extern void simplemap_get_mappers(std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers); +extern void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers); + +// 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) { @@ -40,327 +44,712 @@ static void apply_prefix(std::string prefix, std::string &id) static void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) { - for (size_t i = 0; i < sig.chunks.size(); i++) { - if (sig.chunks[i].wire == NULL) - continue; - std::string wire_name = sig.chunks[i].wire->name; - apply_prefix(prefix, wire_name); - assert(module->wires.count(wire_name) > 0); - sig.chunks[i].wire = module->wires[wire_name]; - } + std::vector<RTLIL::SigChunk> chunks = sig; + for (auto &chunk : chunks) + if (chunk.wire != NULL) { + std::string wire_name = chunk.wire->name.str(); + apply_prefix(prefix, wire_name); + log_assert(module->wires_.count(wire_name) > 0); + chunk.wire = module->wires_[wire_name]; + } + sig = chunks; } -std::map<std::string, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers; -std::map<std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>>, RTLIL::Module*> techmap_cache; -std::map<RTLIL::Module*, bool> techmap_do_cache; - -struct TechmapWireData { - RTLIL::Wire *wire; - RTLIL::SigSpec value; -}; +struct TechmapWorker +{ + std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> simplemap_mappers; + 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; -typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires; + struct TechmapWireData { + RTLIL::Wire *wire; + RTLIL::SigSpec value; + }; -static TechmapWires techmap_find_special_wires(RTLIL::Module *module) -{ - TechmapWires result; + typedef std::map<std::string, std::vector<TechmapWireData>> TechmapWires; - if (module == NULL) - return result; + bool extern_mode; + bool assert_mode; + bool flatten_mode; + bool recursive_mode; + bool autoproc_mode; - for (auto &it : module->wires) { - const char *p = it.first.c_str(); - if (*p == '$') - continue; - - const char *q = strrchr(p+1, '.'); - p = q ? q : p+1; - - if (!strncmp(p, "_TECHMAP_", 9)) { - TechmapWireData record; - record.wire = it.second; - record.value = it.second; - result[p].push_back(record); - it.second->attributes["\\keep"] = RTLIL::Const(1); - it.second->attributes["\\_techmap_special_"] = RTLIL::Const(1); - } + TechmapWorker() + { + extern_mode = false; + assert_mode = false; + flatten_mode = false; + recursive_mode = false; + autoproc_mode = false; } - if (!result.empty()) { - SigMap sigmap(module); - for (auto &it1 : result) - for (auto &it2 : it1.second) - sigmap.apply(it2.value); + std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose) + { + std::string constmap_info; + 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++) { + RTLIL::SigBit bit = sigmap(conn.second[i]); + if (bit.wire == nullptr) { + if (verbose) + log(" Constant input on bit %d of port %s: %s\n", i, log_id(conn.first), log_signal(bit)); + constmap_info += stringf("|%s %d %d", log_id(conn.first), i, bit.data); + } else if (connbits_map.count(bit)) { + if (verbose) + log(" Bit %d of port %s and bit %d of port %s are connected.\n", i, log_id(conn.first), + 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); + } + + return stringf("$paramod$constmap:%s%s", sha1(constmap_info).c_str(), tpl->name.c_str()); } - return result; -} + TechmapWires techmap_find_special_wires(RTLIL::Module *module) + { + TechmapWires result; -static void techmap_module_worker(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::Module *tpl, bool flatten_mode) -{ - log("Mapping `%s.%s' using `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(tpl->name)); - - if (tpl->memories.size() != 0) - log_error("Technology map yielded memories -> this is not supported.\n"); - - if (tpl->processes.size() != 0) - log_error("Technology map yielded processes -> this is not supported.\n"); - - std::map<RTLIL::IdString, RTLIL::IdString> positional_ports; - - for (auto &it : tpl->wires) { - if (it.second->port_id > 0) - positional_ports[stringf("$%d", it.second->port_id)] = it.first; - RTLIL::Wire *w = new RTLIL::Wire(*it.second); - apply_prefix(cell->name, w->name); - w->port_input = false; - w->port_output = false; - w->port_id = 0; - if (it.second->get_bool_attribute("\\_techmap_special_")) - w->attributes.clear(); - module->wires[w->name] = w; - design->select(module, w); - } + if (module == NULL) + return result; + + for (auto &it : module->wires_) { + const char *p = it.first.c_str(); + if (*p == '$') + continue; - SigMap port_signal_map; + const char *q = strrchr(p+1, '.'); + p = q ? q : p+1; - for (auto &it : cell->connections) { - RTLIL::IdString portname = it.first; - if (positional_ports.count(portname) > 0) - portname = positional_ports.at(portname); - if (tpl->wires.count(portname) == 0 || tpl->wires.at(portname)->port_id == 0) { - if (portname.substr(0, 1) == "$") - log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str()); - continue; + if (!strncmp(p, "_TECHMAP_", 9)) { + TechmapWireData record; + record.wire = it.second; + record.value = it.second; + result[p].push_back(record); + it.second->attributes["\\keep"] = RTLIL::Const(1); + it.second->attributes["\\_techmap_special_"] = RTLIL::Const(1); + } } - RTLIL::Wire *w = tpl->wires.at(portname); - RTLIL::SigSig c; - if (w->port_output) { - c.first = it.second; - c.second = RTLIL::SigSpec(w); - apply_prefix(cell->name, c.second, module); - } else { - c.first = RTLIL::SigSpec(w); - c.second = it.second; - apply_prefix(cell->name, c.first, module); + + if (!result.empty()) { + SigMap sigmap(module); + for (auto &it1 : result) + for (auto &it2 : it1.second) + sigmap.apply(it2.value); } - if (c.second.width > c.first.width) - c.second.remove(c.first.width, c.second.width - c.first.width); - if (c.second.width < c.first.width) - c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.width - c.second.width)); - assert(c.first.width == c.second.width); -#if 0 - // more conservative approach: - // connect internal and external wires - module->connections.push_back(c); -#else - // approach that yields nicer outputs: - // replace internal wires that are connected to external wires - if (w->port_output) - port_signal_map.add(c.second, c.first); - else - port_signal_map.add(c.first, c.second); -#endif + + return result; } - for (auto &it : tpl->cells) { - RTLIL::Cell *c = new RTLIL::Cell(*it.second); - if (!flatten_mode && c->type.substr(0, 2) == "\\$") - c->type = c->type.substr(1); - apply_prefix(cell->name, c->name); - for (auto &it2 : c->connections) { - apply_prefix(cell->name, it2.second, module); - port_signal_map.apply(it2.second); + 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); + } else + log_error("Technology map yielded processes -> this is not supported (use -autoproc to run 'proc' automatically).\n"); } - module->cells[c->name] = c; - design->select(module, c); - } - for (auto &it : tpl->connections) { - RTLIL::SigSig c = it; - apply_prefix(cell->name, c.first, module); - apply_prefix(cell->name, c.second, module); - port_signal_map.apply(c.first); - port_signal_map.apply(c.second); - module->connections.push_back(c); - } + std::string orig_cell_name; + if (!flatten_mode) + for (auto &it : tpl->cells_) + if (it.first == "\\_TECHMAP_REPLACE_") { + orig_cell_name = cell->name.str(); + module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str()); + break; + } - module->cells.erase(cell->name); - delete cell; -} + std::map<RTLIL::IdString, RTLIL::IdString> positional_ports; + + for (auto &it : tpl->wires_) { + if (it.second->port_id > 0) + positional_ports[stringf("$%d", it.second->port_id)] = it.first; + std::string w_name = it.second->name.str(); + apply_prefix(cell->name.str(), w_name); + RTLIL::Wire *w = module->addWire(w_name, it.second); + w->port_input = false; + w->port_output = false; + w->port_id = 0; + if (it.second->get_bool_attribute("\\_techmap_special_")) + w->attributes.clear(); + design->select(module, w); + } -static bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells, - const std::map<RTLIL::IdString, std::set<RTLIL::IdString>> &celltypeMap, bool flatten_mode) -{ - if (!design->selected(module)) - return false; + SigMap port_signal_map; + + for (auto &it : cell->connections()) { + RTLIL::IdString portname = it.first; + if (positional_ports.count(portname) > 0) + portname = positional_ports.at(portname); + if (tpl->wires_.count(portname) == 0 || tpl->wires_.at(portname)->port_id == 0) { + if (portname.substr(0, 1) == "$") + log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str()); + continue; + } + RTLIL::Wire *w = tpl->wires_.at(portname); + RTLIL::SigSig c; + if (w->port_output) { + c.first = it.second; + c.second = RTLIL::SigSpec(w); + apply_prefix(cell->name.str(), c.second, module); + } else { + c.first = RTLIL::SigSpec(w); + c.second = it.second; + apply_prefix(cell->name.str(), c.first, module); + } + if (c.second.size() > c.first.size()) + c.second.remove(c.first.size(), c.second.size() - c.first.size()); + if (c.second.size() < c.first.size()) + c.second.append(RTLIL::SigSpec(RTLIL::State::S0, c.first.size() - c.second.size())); + log_assert(c.first.size() == c.second.size()); + if (flatten_mode) { + // more conservative approach: + // connect internal and external wires + module->connect(c); + } else { + // approach that yields nicer outputs: + // replace internal wires that are connected to external wires + if (w->port_output) + port_signal_map.add(c.second, c.first); + else + port_signal_map.add(c.first, c.second); + } + } + + for (auto &it : tpl->cells_) + { + std::string c_name = it.second->name.str(); + + if (!flatten_mode && c_name == "\\_TECHMAP_REPLACE_") + c_name = orig_cell_name; + else + apply_prefix(cell->name.str(), c_name); + + RTLIL::Cell *c = module->addCell(c_name, it.second); + design->select(module, c); + + if (!flatten_mode && c->type.substr(0, 2) == "\\$") + c->type = c->type.substr(1); - bool log_continue = false; - bool did_something = false; - std::vector<std::string> cell_names; + for (auto &it2 : c->connections_) { + apply_prefix(cell->name.str(), it2.second, module); + port_signal_map.apply(it2.second); + } + } + + for (auto &it : tpl->connections()) { + RTLIL::SigSig c = it; + apply_prefix(cell->name.str(), c.first, module); + apply_prefix(cell->name.str(), c.second, module); + port_signal_map.apply(c.first); + port_signal_map.apply(c.second); + module->connect(c); + } - for (auto &cell_it : module->cells) - cell_names.push_back(cell_it.first); + module->remove(cell); + } - for (auto &cell_name : cell_names) + bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells, + const std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> &celltypeMap, bool in_recursion) { - if (module->cells.count(cell_name) == 0) - continue; + std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; + + if (!design->selected(module)) + return false; - RTLIL::Cell *cell = module->cells[cell_name]; + bool log_continue = false; + bool did_something = false; - if (!design->selected(module, cell) || handled_cells.count(cell) > 0) - continue; + SigMap sigmap(module); - if (celltypeMap.count(cell->type) == 0) - continue; + TopoSort<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; - for (auto &tpl_name : celltypeMap.at(cell->type)) + for (auto cell : module->cells()) { - std::string derived_name = tpl_name; - RTLIL::Module *tpl = map->modules[tpl_name]; - std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters; + if (!design->selected(module, cell) || handled_cells.count(cell) > 0) + continue; - if (!flatten_mode) - { - if (tpl->get_bool_attribute("\\techmap_simplemap")) { - log("Mapping %s.%s (%s) with simplemap.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); - if (simplemap_mappers.count(cell->type) == 0) - log_error("No simplemap mapper for cell type %s found!\n", RTLIL::id2cstr(cell->type)); - simplemap_mappers.at(cell->type)(module, cell); - module->cells.erase(cell->name); - delete cell; - cell = NULL; - did_something = true; - break; - } + std::string cell_type = cell->type.str(); + if (in_recursion && cell_type.substr(0, 2) == "\\$") + cell_type = cell_type.substr(1); - for (auto conn : cell->connections) { - if (conn.first.substr(0, 1) == "$") - continue; - if (tpl->wires.count(conn.first) > 0 && tpl->wires.at(conn.first)->port_id > 0) - continue; - if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0) - goto next_tpl; - parameters[conn.first] = conn.second.as_const(); - } + if (celltypeMap.count(cell_type) == 0) { + if (assert_mode && cell_type.back() != '_') + log_error("(ASSERT MODE) No matching template cell for type %s found.\n", log_id(cell_type)); + continue; + } - if (0) { - next_tpl: - continue; - } + for (auto &conn : cell->connections()) + { + RTLIL::SigSpec sig = sigmap(conn.second); + sig.remove_const(); - if (tpl->avail_parameters.count("\\_TECHMAP_CELLTYPE_") != 0) - parameters["\\_TECHMAP_CELLTYPE_"] = RTLIL::unescape_id(cell->type); - } + if (SIZE(sig) == 0) + continue; - std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters); - if (techmap_cache.count(key) > 0) { - tpl = techmap_cache[key]; - } else { - if (cell->parameters.size() != 0) { - derived_name = tpl->derive(map, parameters); - tpl = map->modules[derived_name]; - log_continue = true; + for (auto &tpl_name : celltypeMap.at(cell_type)) { + RTLIL::Module *tpl = map->modules_[tpl_name]; + RTLIL::Wire *port = tpl->wire(conn.first); + if (port && port->port_input) + cell_to_inbit[cell].insert(sig.begin(), sig.end()); + if (port && port->port_output) + for (auto &bit : sig) + outbit_to_cell[bit].insert(cell); } - techmap_cache[key] = tpl; } - if (flatten_mode) - techmap_do_cache[tpl] = true; + cells.node(cell); + } + + for (auto &it_right : cell_to_inbit) + for (auto &it_sigbit : it_right.second) + for (auto &it_left : outbit_to_cell[it_sigbit]) + cells.edge(it_left, it_right.first); + + cells.sort(); + + for (auto cell : cells.sorted) + { + log_assert(handled_cells.count(cell) == 0); + log_assert(cell == module->cell(cell->name)); + bool mapped_cell = false; + + std::string cell_type = cell->type.str(); + if (in_recursion && cell_type.substr(0, 2) == "\\$") + cell_type = cell_type.substr(1); - if (techmap_do_cache.count(tpl) == 0) + for (auto &tpl_name : celltypeMap.at(cell_type)) { - bool keep_running = true; - techmap_do_cache[tpl] = true; + RTLIL::IdString derived_name = tpl_name; + RTLIL::Module *tpl = map->modules_[tpl_name]; + std::map<RTLIL::IdString, RTLIL::Const> parameters = cell->parameters; + + if (tpl->get_bool_attribute("\\blackbox")) + continue; - while (keep_running) + if (!flatten_mode) { - TechmapWires twd = techmap_find_special_wires(tpl); - keep_running = false; - - for (auto &it : twd["_TECHMAP_FAIL_"]) { - RTLIL::SigSpec value = it.value; - if (value.is_fully_const() && value.as_bool()) { - log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n", - derived_name.c_str(), RTLIL::id2cstr(it.wire->name), log_signal(value)); - techmap_do_cache[tpl] = false; + std::string extmapper_name; + + if (tpl->get_bool_attribute("\\techmap_simplemap")) + extmapper_name = "simplemap"; + + if (tpl->get_bool_attribute("\\techmap_maccmap")) + extmapper_name = "maccmap"; + + if (tpl->attributes.count("\\techmap_wrap")) + extmapper_name = "wrap"; + + if (!extmapper_name.empty()) + { + cell->type = cell_type; + + if ((extern_mode && !in_recursion) || extmapper_name == "wrap") + { + std::string m_name = stringf("$extern:%s:%s", extmapper_name.c_str(), log_id(cell->type)); + + for (auto &c : cell->parameters) + m_name += stringf(":%s=%s", log_id(c.first), log_signal(c.second)); + + if (extmapper_name == "wrap") + m_name += ":" + sha1(tpl->attributes.at("\\techmap_wrap").decode_string()); + + RTLIL::Design *extmapper_design = extern_mode && !in_recursion ? design : tpl->design; + RTLIL::Module *extmapper_module = extmapper_design->module(m_name); + + if (extmapper_module == nullptr) + { + extmapper_module = extmapper_design->addModule(m_name); + RTLIL::Cell *extmapper_cell = extmapper_module->addCell(cell->type, cell); + + int port_counter = 1; + for (auto &c : extmapper_cell->connections_) { + RTLIL::Wire *w = extmapper_module->addWire(c.first, SIZE(c.second)); + if (w->name == "\\Y" || w->name == "\\Q") + w->port_output = true; + else + w->port_input = true; + w->port_id = port_counter++; + c.second = w; + } + + extmapper_module->fixup_ports(); + extmapper_module->check(); + + if (extmapper_name == "simplemap") { + log("Creating %s with simplemap.\n", log_id(extmapper_module)); + if (simplemap_mappers.count(extmapper_cell->type) == 0) + log_error("No simplemap mapper for cell type %s found!\n", log_id(extmapper_cell->type)); + simplemap_mappers.at(extmapper_cell->type)(extmapper_module, extmapper_cell); + extmapper_module->remove(extmapper_cell); + } + + if (extmapper_name == "maccmap") { + log("Creating %s with maccmap.\n", log_id(extmapper_module)); + if (extmapper_cell->type != "$macc") + log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(extmapper_cell->type)); + maccmap(extmapper_module, extmapper_cell); + extmapper_module->remove(extmapper_cell); + } + + if (extmapper_name == "wrap") { + std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string(); + log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module)); + Pass::call_on_module(extmapper_design, extmapper_module, cmd_string); + log_continue = true; + } + } + + cell->type = extmapper_module->name; + cell->parameters.clear(); + + if (!extern_mode || in_recursion) { + tpl = extmapper_module; + goto use_wrapper_tpl; + } + + log("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); + } + else + { + log("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); + + if (extmapper_name == "simplemap") { + if (simplemap_mappers.count(cell->type) == 0) + log_error("No simplemap mapper for cell type %s found!\n", RTLIL::id2cstr(cell->type)); + simplemap_mappers.at(cell->type)(module, cell); + } + + if (extmapper_name == "maccmap") { + if (cell->type != "$macc") + log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(cell->type)); + maccmap(module, cell); + } + + module->remove(cell); + cell = NULL; } - } - if (!techmap_do_cache[tpl]) + did_something = true; + mapped_cell = true; break; + } - for (auto &it : twd) - { - if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty()) + for (auto conn : cell->connections()) { + if (conn.first.substr(0, 1) == "$") + continue; + if (tpl->wires_.count(conn.first) > 0 && tpl->wires_.at(conn.first)->port_id > 0) continue; + if (!conn.second.is_fully_const() || parameters.count(conn.first) > 0 || tpl->avail_parameters.count(conn.first) == 0) + goto next_tpl; + parameters[conn.first] = conn.second.as_const(); + } + + if (0) { + next_tpl: + continue; + } + + if (tpl->avail_parameters.count("\\_TECHMAP_CELLTYPE_") != 0) + parameters["\\_TECHMAP_CELLTYPE_"] = RTLIL::unescape_id(cell->type); + + for (auto conn : cell->connections()) { + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))) != 0) { + std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector(); + for (auto &bit : v) + bit = RTLIL::SigBit(bit.wire == NULL ? RTLIL::State::S1 : RTLIL::State::S0); + parameters[stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const(); + } + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))) != 0) { + std::vector<RTLIL::SigBit> v = sigmap(conn.second).to_sigbit_vector(); + for (auto &bit : v) + if (bit.wire != NULL) + bit = RTLIL::SigBit(RTLIL::State::Sx); + parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const(); + } + } + + int unique_bit_id_counter = 0; + std::map<RTLIL::SigBit, int> unique_bit_id; + unique_bit_id[RTLIL::State::S0] = unique_bit_id_counter++; + unique_bit_id[RTLIL::State::S1] = unique_bit_id_counter++; + unique_bit_id[RTLIL::State::Sx] = unique_bit_id_counter++; + unique_bit_id[RTLIL::State::Sz] = unique_bit_id_counter++; + + for (auto conn : cell->connections()) + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) { + for (auto &bit : sigmap(conn.second).to_sigbit_vector()) + if (unique_bit_id.count(bit) == 0) + unique_bit_id[bit] = unique_bit_id_counter++; + } - auto &data = it.second.front(); + int bits = 0; + for (int i = 0; i < 32; i++) + if (((unique_bit_id_counter-1) & (1 << i)) != 0) + bits = i; + if (tpl->avail_parameters.count("\\_TECHMAP_BITS_CONNMAP_")) + parameters["\\_TECHMAP_BITS_CONNMAP_"] = bits; + + for (auto conn : cell->connections()) + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) { + RTLIL::Const value; + for (auto &bit : sigmap(conn.second).to_sigbit_vector()) { + RTLIL::Const chunk(unique_bit_id.at(bit), bits); + value.bits.insert(value.bits.end(), chunk.bits.begin(), chunk.bits.end()); + } + parameters[stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))] = value; + } + } - if (!data.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(data.wire->name), log_signal(data.value)); + if (0) { + use_wrapper_tpl:; + // do not register techmap_wrap modules with techmap_cache + } else { + std::pair<RTLIL::IdString, std::map<RTLIL::IdString, RTLIL::Const>> key(tpl_name, parameters); + if (techmap_cache.count(key) > 0) { + tpl = techmap_cache[key]; + } else { + if (cell->parameters.size() != 0) { + derived_name = tpl->derive(map, parameters); + tpl = map->module(derived_name); + log_continue = true; + } + techmap_cache[key] = tpl; + } + } - tpl->wires.erase(data.wire->name); - const char *p = data.wire->name.c_str(); - const char *q = strrchr(p+1, '.'); - q = q ? q : p+1; + if (flatten_mode) { + techmap_do_cache[tpl] = true; + } else { + RTLIL::Module *constmapped_tpl = map->module(constmap_tpl_name(sigmap, tpl, cell, false)); + if (constmapped_tpl != nullptr) + tpl = constmapped_tpl; + } - assert(!strncmp(q, "_TECHMAP_DO_", 12)); - std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12); - while (tpl->wires.count(new_name)) - new_name += "_"; - data.wire->name = new_name; - tpl->add(data.wire); + if (techmap_do_cache.count(tpl) == 0) + { + bool keep_running = true; + techmap_do_cache[tpl] = true; - std::string cmd_string = data.value.as_const().decode_string(); + std::set<std::string> techmap_wire_names; - RTLIL::Selection tpl_mod_sel(false); - tpl_mod_sel.select(tpl); - map->selection_stack.push_back(tpl_mod_sel); - Pass::call(map, cmd_string); - map->selection_stack.pop_back(); + while (keep_running) + { + TechmapWires twd = techmap_find_special_wires(tpl); + keep_running = false; + + for (auto &it : twd) + techmap_wire_names.insert(it.first); + + for (auto &it : twd["_TECHMAP_FAIL_"]) { + RTLIL::SigSpec value = it.value; + if (value.is_fully_const() && value.as_bool()) { + log("Not using module `%s' from techmap as it contains a %s marker wire with non-zero value %s.\n", + derived_name.c_str(), RTLIL::id2cstr(it.wire->name), log_signal(value)); + techmap_do_cache[tpl] = false; + } + } - keep_running = true; - break; + if (!techmap_do_cache[tpl]) + break; + + for (auto &it : twd) + { + if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty()) + continue; + + auto &data = it.second.front(); + + if (!data.value.is_fully_const()) + log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(data.wire->name), log_signal(data.value)); + + techmap_wire_names.erase(it.first); + + const char *p = data.wire->name.c_str(); + const char *q = strrchr(p+1, '.'); + q = q ? q : p+1; + + std::string cmd_string = data.value.as_const().decode_string(); + + restart_eval_cmd_string: + if (cmd_string.rfind("CONSTMAP; ", 0) == 0) + { + cmd_string = cmd_string.substr(strlen("CONSTMAP; ")); + + log("Analyzing pattern of constant bits for this cell:\n"); + RTLIL::IdString new_tpl_name = constmap_tpl_name(sigmap, tpl, cell, true); + log("Creating constmapped module `%s'.\n", log_id(new_tpl_name)); + log_assert(map->module(new_tpl_name) == nullptr); + + RTLIL::Module *new_tpl = map->addModule(new_tpl_name); + tpl->cloneInto(new_tpl); + + techmap_do_cache.erase(tpl); + techmap_do_cache[new_tpl] = true; + tpl = new_tpl; + + std::map<RTLIL::SigBit, RTLIL::SigBit> port_new2old_map; + std::map<RTLIL::SigBit, RTLIL::SigBit> port_connmap; + std::map<RTLIL::SigBit, RTLIL::SigBit> cellbits_to_tplbits; + + for (auto wire : tpl->wires().to_vector()) + { + if (!wire->port_input || wire->port_output) + continue; + + RTLIL::IdString port_name = wire->name; + tpl->rename(wire, NEW_ID); + + RTLIL::Wire *new_wire = tpl->addWire(port_name, wire); + wire->port_input = false; + wire->port_id = 0; + + for (int i = 0; i < wire->width; i++) { + port_new2old_map[RTLIL::SigBit(new_wire, i)] = RTLIL::SigBit(wire, i); + port_connmap[RTLIL::SigBit(wire, i)] = RTLIL::SigBit(new_wire, i); + } + } + + for (auto conn : cell->connections()) + for (int i = 0; i < SIZE(conn.second); i++) + { + RTLIL::SigBit bit = sigmap(conn.second[i]); + RTLIL::SigBit tplbit(tpl->wire(conn.first), i); + + if (bit.wire == nullptr) + { + RTLIL::SigBit oldbit = port_new2old_map.at(tplbit); + port_connmap.at(oldbit) = bit; + } + else if (cellbits_to_tplbits.count(bit)) + { + RTLIL::SigBit oldbit = port_new2old_map.at(tplbit); + port_connmap.at(oldbit) = cellbits_to_tplbits[bit]; + } + else + cellbits_to_tplbits[bit] = tplbit; + } + + RTLIL::SigSig port_conn; + for (auto &it : port_connmap) { + port_conn.first.append_bit(it.first); + port_conn.second.append_bit(it.second); + } + tpl->connect(port_conn); + + tpl->check(); + goto restart_eval_cmd_string; + } + + if (cmd_string.rfind("RECURSION; ", 0) == 0) + { + cmd_string = cmd_string.substr(strlen("RECURSION; ")); + while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } + goto restart_eval_cmd_string; + } + + Pass::call_on_module(map, tpl, cmd_string); + + log_assert(!strncmp(q, "_TECHMAP_DO_", 12)); + std::string new_name = data.wire->name.substr(0, q-p) + "_TECHMAP_DONE_" + data.wire->name.substr(q-p+12); + while (tpl->wires_.count(new_name)) + new_name += "_"; + tpl->rename(data.wire->name, new_name); + + keep_running = true; + break; + } + } + + TechmapWires twd = techmap_find_special_wires(tpl); + for (auto &it : twd) { + if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_") + log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str()); + if (techmap_do_cache[tpl]) + for (auto &it2 : it.second) + if (!it2.value.is_fully_const()) + log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value)); + techmap_wire_names.erase(it.first); + } + + for (auto &it : techmap_wire_names) + log_error("Techmap special wire %s disappeared. This is considered a fatal error.\n", RTLIL::id2cstr(it)); + + if (recursive_mode) { + if (log_continue) { + log_header("Continuing TECHMAP pass.\n"); + log_continue = false; + } + while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } } } - TechmapWires twd = techmap_find_special_wires(tpl); - for (auto &it : twd) { - if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_") - log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str()); - if (techmap_do_cache[tpl]) - for (auto &it2 : it.second) - if (!it2.value.is_fully_const()) - log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value)); + if (techmap_do_cache.at(tpl) == false) + continue; + + if (log_continue) { + log_header("Continuing TECHMAP pass.\n"); + log_continue = false; } - } - if (techmap_do_cache.at(tpl) == false) - continue; + if (extern_mode && !in_recursion) + { + std::string m_name = stringf("$extern:%s", log_id(tpl)); - if (log_continue) { - log_header("Continuing TECHMAP pass.\n"); - log_continue = false; + if (!design->module(m_name)) + { + RTLIL::Module *m = design->addModule(m_name); + tpl->cloneInto(m); + + for (auto cell : m->cells()) { + if (cell->type.substr(0, 2) == "\\$") + cell->type = cell->type.substr(1); + } + + module_queue.insert(m); + } + + log("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); + cell->type = m_name; + cell->parameters.clear(); + } + else + { + log("%s %s.%s using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(tpl)); + techmap_module_worker(design, module, cell, tpl); + cell = NULL; + } + did_something = true; + mapped_cell = true; + break; } - techmap_module_worker(design, module, cell, tpl, flatten_mode); - did_something = true; - cell = NULL; - break; + if (assert_mode && !mapped_cell) + log_error("(ASSERT MODE) Failed to map cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type)); + + handled_cells.insert(cell); } - handled_cells.insert(cell); - } + if (log_continue) { + log_header("Continuing TECHMAP pass.\n"); + log_continue = false; + } - if (log_continue) { - log_header("Continuing TECHMAP pass.\n"); - log_continue = false; + return did_something; } - - return did_something; -} +}; struct TechmapPass : public Pass { TechmapPass() : Pass("techmap", "generic technology mapper") { } @@ -380,11 +769,34 @@ struct TechmapPass : public Pass { log(" transforms the internal RTL cells to the internal gate\n"); log(" library.\n"); log("\n"); + log(" -map %%<design-name>\n"); + log(" like -map above, but with an in-memory design instead of a file.\n"); + log("\n"); log(" -share_map filename\n"); log(" like -map, but look for the file in the share directory (where the\n"); log(" yosys data files are). this is mainly used internally when techmap\n"); log(" is called from other commands.\n"); log("\n"); + log(" -extern\n"); + log(" load the cell implementations as separate modules into the design\n"); + log(" instead of inlining them.\n"); + log("\n"); + log(" -max_iter <number>\n"); + log(" only run the specified number of iterations.\n"); + log("\n"); + log(" -recursive\n"); + log(" instead of the iterative breadth-first algorithm use a recursive\n"); + log(" depth-first algorithm. both methods should yield equivialent results,\n"); + log(" but may differ in performance.\n"); + log("\n"); + log(" -autoproc\n"); + log(" Automatically call \"proc\" on implementations that contain processes.\n"); + log("\n"); + log(" -assert\n"); + log(" this option will cause techmap to exit with an error if it can't map\n"); + log(" a selected cell. only cell types that end on an underscore are accepted\n"); + log(" as final cell types by this mode.\n"); + log("\n"); log(" -D <define>, -I <incdir>\n"); log(" this options are passed as-is to the verilog frontend for loading the\n"); log(" map file. Note that the verilog frontend is also called with the\n"); @@ -397,6 +809,13 @@ struct TechmapPass : public Pass { log("When a module in the map file has the 'techmap_simplemap' attribute set, techmap\n"); log("will use 'simplemap' (see 'help simplemap') to map cells matching the module.\n"); log("\n"); + log("When a module in the map file has the 'techmap_maccmap' attribute set, techmap\n"); + log("will use 'maccmap' (see 'help maccmap') to map cells matching the module.\n"); + log("\n"); + log("When a module in the map file has the 'techmap_wrap' attribute set, techmap\n"); + log("will create a wrapper for the cell and then run the command string that the\n"); + log("attribute is set to on the wrapper module.\n"); + log("\n"); log("All wires in the modules from the map file matching the pattern _TECHMAP_*\n"); log("or *._TECHMAP_* are special wires that are used to pass instructions from\n"); log("the mapping module to the techmap command. At the moment the following special\n"); @@ -421,6 +840,20 @@ struct TechmapPass : public Pass { log(" wire to start out as non-constant and evaluate to a constant value\n"); log(" during processing of other _TECHMAP_DO_* commands.\n"); log("\n"); + log(" A _TECHMAP_DO_* command may start with the special token 'CONSTMAP; '.\n"); + log(" in this case techmap will create a copy for each distinct configuration\n"); + log(" of constant inputs and shorted inputs at this point and import the\n"); + log(" constant and connected bits into the map module. All further commands\n"); + log(" are executed in this copy. This is a very convenient way of creating\n"); + log(" optimizied specializations of techmap modules without using the special\n"); + log(" parameters described below.\n"); + log("\n"); + log(" A _TECHMAP_DO_* command may start with the special token 'RECURSION; '.\n"); + log(" then techmap will recursively replace the cells in the module with their\n"); + log(" implementation. This is not affected by the -max_iter option.\n"); + log("\n"); + log(" It is possible to combine both prefixes to 'RECURSION; CONSTMAP; '.\n"); + log("\n"); log("In addition to this special wires, techmap also supports special parameters in\n"); log("modules in the map file:\n"); log("\n"); @@ -428,11 +861,28 @@ struct TechmapPass : public Pass { log(" When a parameter with this name exists, it will be set to the type name\n"); log(" of the cell that matches the module.\n"); log("\n"); + log(" _TECHMAP_CONSTMSK_<port-name>_\n"); + log(" _TECHMAP_CONSTVAL_<port-name>_\n"); + log(" When this pair of parameters is available in a module for a port, then\n"); + log(" former has a 1-bit for each constant input bit and the latter has the\n"); + log(" value for this bit. The unused bits of the latter are set to undef (x).\n"); + log("\n"); + log(" _TECHMAP_BITS_CONNMAP_\n"); + log(" _TECHMAP_CONNMAP_<port-name>_\n"); + log(" For an N-bit port, the _TECHMAP_CONNMAP_<port-name>_ parameter, if it\n"); + log(" exists, will be set to an N*_TECHMAP_BITS_CONNMAP_ bit vector containing\n"); + log(" N words (of _TECHMAP_BITS_CONNMAP_ bits each) that assign each single\n"); + log(" bit driver a unique id. The values 0-3 are reserved for 0, 1, x, and z.\n"); + log(" This can be used to detect shorted inputs.\n"); + log("\n"); log("When a module in the map file has a parameter where the according cell in the\n"); log("design has a port, the module from the map file is only used if the port in\n"); log("the design is connected to a constant value. The parameter is then set to the\n"); log("constant value.\n"); log("\n"); + log("A cell with the name _TECHMAP_REPLACE_ in the map file will inherit the name\n"); + log("of the cell that is beeing replaced.\n"); + log("\n"); log("See 'help extract' for a pass that does the opposite thing.\n"); log("\n"); log("See 'help flatten' for a pass that does flatten the design (which is\n"); @@ -444,17 +894,28 @@ struct TechmapPass : public Pass { log_header("Executing TECHMAP pass (map to technology primitives).\n"); log_push(); + TechmapWorker worker; + simplemap_get_mappers(worker.simplemap_mappers); + std::vector<std::string> map_files; std::string verilog_frontend = "verilog -ignore_redef"; + int max_iter = -1; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-map" && argidx+1 < args.size()) { - map_files.push_back(args[++argidx]); + if (args[argidx+1].substr(0, 2) == "+/") + map_files.push_back(proc_share_dirname() + args[++argidx].substr(2)); + else + map_files.push_back(args[++argidx]); continue; } if (args[argidx] == "-share_map" && argidx+1 < args.size()) { - map_files.push_back(get_share_file_name(args[++argidx])); + map_files.push_back(proc_share_dirname() + args[++argidx]); + continue; + } + if (args[argidx] == "-max_iter" && argidx+1 < args.size()) { + max_iter = atoi(args[++argidx].c_str()); continue; } if (args[argidx] == "-D" && argidx+1 < args.size()) { @@ -465,36 +926,58 @@ struct TechmapPass : public Pass { verilog_frontend += " -I " + args[++argidx]; continue; } + if (args[argidx] == "-assert") { + worker.assert_mode = true; + continue; + } + if (args[argidx] == "-extern") { + worker.extern_mode = true; + continue; + } + if (args[argidx] == "-recursive") { + worker.recursive_mode = true; + continue; + } + if (args[argidx] == "-autoproc") { + worker.autoproc_mode = true; + continue; + } break; } extra_args(args, argidx, design); - simplemap_get_mappers(simplemap_mappers); - RTLIL::Design *map = new RTLIL::Design; if (map_files.empty()) { - FILE *f = fmemopen(stdcells_code, strlen(stdcells_code), "rt"); - Frontend::frontend_call(map, f, "<stdcells.v>", verilog_frontend); - fclose(f); + std::istringstream f(stdcells_code); + Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend); } else - for (auto &fn : map_files) { - FILE *f = fopen(fn.c_str(), "rt"); - if (f == NULL) - log_cmd_error("Can't open map file `%s'\n", fn.c_str()); - Frontend::frontend_call(map, f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend); - fclose(f); - } + for (auto &fn : map_files) + if (fn.substr(0, 1) == "%") { + if (!saved_designs.count(fn.substr(1))) { + delete map; + log_cmd_error("Can't saved design `%s'.\n", fn.c_str()+1); + } + for (auto mod : saved_designs.at(fn.substr(1))->modules()) + if (!map->has(mod->name)) + map->add(mod->clone()); + } else { + std::ifstream f; + f.open(fn.c_str()); + if (f.fail()) + log_cmd_error("Can't open map file `%s'\n", fn.c_str()); + 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; - for (auto &it : map->modules) { + for (auto &it : map->modules_) { if (it.first.substr(0, 2) == "\\$") it.second->name = it.first.substr(1); modules_new[it.second->name] = it.second; } - map->modules.swap(modules_new); + map->modules_.swap(modules_new); - std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap; - for (auto &it : map->modules) { + std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; + for (auto &it : map->modules_) { if (it.second->attributes.count("\\techmap_celltype") && !it.second->attributes.at("\\techmap_celltype").bits.empty()) { char *p = strdup(it.second->attributes.at("\\techmap_celltype").decode_string().c_str()); for (char *q = strtok(p, " \t\r\n"); q; q = strtok(NULL, " \t\r\n")) @@ -504,22 +987,30 @@ struct TechmapPass : public Pass { celltypeMap[it.first].insert(it.first); } - bool did_something = true; - std::set<RTLIL::Cell*> handled_cells; - while (did_something) { - did_something = false; - for (auto &mod_it : design->modules) - if (techmap_module(design, mod_it.second, map, handled_cells, celltypeMap, false)) - did_something = true; - if (did_something) - design->check(); + for (auto module : design->modules()) + worker.module_queue.insert(module); + + while (!worker.module_queue.empty()) + { + RTLIL::Module *module = *worker.module_queue.begin(); + worker.module_queue.erase(module); + + bool did_something = true; + std::set<RTLIL::Cell*> handled_cells; + while (did_something) { + did_something = false; + if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) + did_something = true; + if (did_something) + module->check(); + if (max_iter > 0 && --max_iter == 0) + break; + } } log("No more expansions possible.\n"); - techmap_cache.clear(); - techmap_do_cache.clear(); - simplemap_mappers.clear(); delete map; + log_pop(); } } TechmapPass; @@ -544,26 +1035,29 @@ struct FlattenPass : public Pass { extra_args(args, 1, design); - std::map<RTLIL::IdString, std::set<RTLIL::IdString>> celltypeMap; - for (auto &it : design->modules) + TechmapWorker worker; + 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); RTLIL::Module *top_mod = NULL; if (design->full_selection()) - for (auto &mod_it : design->modules) - if (mod_it.second->get_bool_attribute("\\top")) - top_mod = mod_it.second; + for (auto mod : design->modules()) + 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 (techmap_module(design, top_mod, design, handled_cells, celltypeMap, true)) + if (worker.techmap_module(design, top_mod, design, handled_cells, celltypeMap, false)) did_something = true; } else { - for (auto &mod_it : design->modules) - if (techmap_module(design, mod_it.second, design, handled_cells, celltypeMap, true)) + for (auto mod : design->modules()) + if (worker.techmap_module(design, mod, design, handled_cells, celltypeMap, false)) did_something = true; } } @@ -572,18 +1066,16 @@ struct FlattenPass : public Pass { if (top_mod != NULL) { std::map<RTLIL::IdString, RTLIL::Module*> new_modules; - for (auto &mod_it : design->modules) - if (mod_it.second == top_mod) { - new_modules[mod_it.first] = mod_it.second; + for (auto mod : design->modules()) + if (mod == top_mod || mod->get_bool_attribute("\\blackbox")) { + new_modules[mod->name] = mod; } else { - log("Deleting now unused module %s.\n", RTLIL::id2cstr(mod_it.first)); - delete mod_it.second; + log("Deleting now unused module %s.\n", log_id(mod)); + delete mod; } - design->modules.swap(new_modules); + design->modules_.swap(new_modules); } - techmap_cache.clear(); - techmap_do_cache.clear(); log_pop(); } } FlattenPass; |