diff options
author | Eddie Hung <eddie@fpgeh.com> | 2019-08-28 12:18:32 -0700 |
---|---|---|
committer | Eddie Hung <eddie@fpgeh.com> | 2019-08-28 12:18:32 -0700 |
commit | 32eef26ee277b79736e135a8800625543dd6080a (patch) | |
tree | 28cd6d5af904ddd2ec2772e2bd1d2378215c1dc7 /passes/techmap | |
parent | fe58790f3789a79b867660031d7e3e28cb3fff20 (diff) | |
parent | c499dc3e73390c3bc9bf8045f2e4cad963c1fbad (diff) | |
download | yosys-32eef26ee277b79736e135a8800625543dd6080a.tar.gz yosys-32eef26ee277b79736e135a8800625543dd6080a.tar.bz2 yosys-32eef26ee277b79736e135a8800625543dd6080a.zip |
Merge remote-tracking branch 'origin/clifford/async2synclatch' into Sergey/tests_ice40
Diffstat (limited to 'passes/techmap')
-rw-r--r-- | passes/techmap/Makefile.inc | 1 | ||||
-rw-r--r-- | passes/techmap/abc9.cc | 123 | ||||
-rw-r--r-- | passes/techmap/clkbufmap.cc | 298 | ||||
-rw-r--r-- | passes/techmap/iopadmap.cc | 58 | ||||
-rw-r--r-- | passes/techmap/techmap.cc | 10 |
5 files changed, 423 insertions, 67 deletions
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 56f05eca4..631a80aa5 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -16,6 +16,7 @@ endif ifneq ($(SMALL),1) OBJS += passes/techmap/iopadmap.o +OBJS += passes/techmap/clkbufmap.o OBJS += passes/techmap/hilomap.o OBJS += passes/techmap/extract.o OBJS += passes/techmap/extract_fa.o diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index c1d4fff2d..84cb2c04f 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -76,12 +76,11 @@ inline std::string remap_name(RTLIL::IdString abc_name) return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1); } -void handle_loops(RTLIL::Design *design) +void handle_loops(RTLIL::Design *design, + const dict<IdString,pool<IdString>> &scc_break_inputs) { Pass::call(design, "scc -set_attr abc_scc_id {}"); - dict<IdString, vector<IdString>> abc_scc_break; - // For every unique SCC found, (arbitrarily) find the first // cell in the component, and select (and mark) all its output // wires @@ -116,44 +115,29 @@ void handle_loops(RTLIL::Design *design) cell->attributes.erase(it); } - auto jt = abc_scc_break.find(cell->type); - if (jt == abc_scc_break.end()) { - std::vector<IdString> ports; - RTLIL::Module* box_module = design->module(cell->type); - if (box_module) { - auto ports_csv = box_module->attributes.at(ID(abc_scc_break), RTLIL::Const::from_string("")).decode_string(); - for (const auto &port_name : split_tokens(ports_csv, ",")) { - auto port_id = RTLIL::escape_id(port_name); - auto kt = cell->connections_.find(port_id); - if (kt == cell->connections_.end()) - log_error("abc_scc_break attribute value '%s' does not exist as port on module '%s'\n", port_name.c_str(), log_id(box_module)); - ports.push_back(port_id); - } - } - jt = abc_scc_break.insert(std::make_pair(cell->type, std::move(ports))).first; - } - - for (auto port_name : jt->second) { - RTLIL::SigSpec sig; - auto &rhs = cell->connections_.at(port_name); - for (auto b : rhs) { - Wire *w = b.wire; - if (!w) continue; - w->port_output = true; - w->set_bool_attribute(ID(abc_scc_break)); - w = module->wire(stringf("%s.abci", w->name.c_str())); - if (!w) { - w = module->addWire(stringf("%s.abci", b.wire->name.c_str()), GetSize(b.wire)); - w->port_input = true; - } - else { - log_assert(b.offset < GetSize(w)); - log_assert(w->port_input); + auto jt = scc_break_inputs.find(cell->type); + if (jt != scc_break_inputs.end()) + for (auto port_name : jt->second) { + RTLIL::SigSpec sig; + auto &rhs = cell->connections_.at(port_name); + for (auto b : rhs) { + Wire *w = b.wire; + if (!w) continue; + w->port_output = true; + w->set_bool_attribute(ID(abc_scc_break)); + w = module->wire(stringf("%s.abci", w->name.c_str())); + if (!w) { + w = module->addWire(stringf("%s.abci", b.wire->name.c_str()), GetSize(b.wire)); + w->port_input = true; + } + else { + log_assert(b.offset < GetSize(w)); + log_assert(w->port_input); + } + sig.append(RTLIL::SigBit(w, b.offset)); } - sig.append(RTLIL::SigBit(w, b.offset)); + rhs = sig; } - rhs = sig; - } } module->fixup_ports(); @@ -288,7 +272,9 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, bool show_tempdir, std::string box_file, std::string lut_file, - std::string wire_delay, const dict<int,IdString> &box_lookup) + std::string wire_delay, const dict<int,IdString> &box_lookup, + const dict<IdString,pool<IdString>> &scc_break_inputs +) { module = current_module; map_autoidx = autoidx++; @@ -427,7 +413,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri RTLIL::Selection& sel = design->selection_stack.back(); sel.select(module); - handle_loops(design); + handle_loops(design, scc_break_inputs); Pass::call(design, "aigmap"); @@ -1081,6 +1067,7 @@ struct Abc9Pass : public Pass { extra_args(args, argidx, design); dict<int,IdString> box_lookup; + dict<IdString,pool<IdString>> scc_break_inputs; for (auto m : design->modules()) { auto it = m->attributes.find(ID(abc_box_id)); if (it == m->attributes.end()) @@ -1093,6 +1080,56 @@ struct Abc9Pass : public Pass { log_error("Module '%s' has the same abc_box_id = %d value as '%s'.\n", log_id(m), id, log_id(r.first->second)); log_assert(r.second); + + RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; + for (auto p : m->ports) { + auto w = m->wire(p); + log_assert(w); + if (w->port_input) { + if (w->attributes.count(ID(abc_scc_break))) + scc_break_inputs[m->name].insert(p); + if (w->attributes.count(ID(abc_carry))) { + if (carry_in) + log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m)); + carry_in = w; + } + } + if (w->port_output) { + if (w->attributes.count(ID(abc_carry))) { + if (carry_out) + log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m)); + carry_out = w; + } + } + } + if (carry_in || carry_out) { + if (carry_in && !carry_out) + log_error("Module '%s' contains an 'abc_carry' input port but no output port.\n", log_id(m)); + if (!carry_in && carry_out) + log_error("Module '%s' contains an 'abc_carry' output port but no input port.\n", log_id(m)); + // Make carry_in the last PI, and carry_out the last PO + // since ABC requires it this way + auto &ports = m->ports; + for (auto it = ports.begin(); it != ports.end(); ) { + RTLIL::Wire* w = m->wire(*it); + log_assert(w); + if (w == carry_in || w == carry_out) { + it = ports.erase(it); + continue; + } + if (w->port_id > carry_in->port_id) + --w->port_id; + if (w->port_id > carry_out->port_id) + --w->port_id; + log_assert(w->port_input || w->port_output); + log_assert(ports[w->port_id-1] == w->name); + ++it; + } + ports.push_back(carry_in->name); + carry_in->port_id = ports.size(); + ports.push_back(carry_out->name); + carry_out->port_id = ports.size(); + } } for (auto mod : design->selected_modules()) @@ -1110,7 +1147,7 @@ struct Abc9Pass : public Pass { if (!dff_mode || !clk_str.empty()) { abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff, delay_target, lutin_shared, fast_mode, show_tempdir, - box_file, lut_file, wire_delay, box_lookup); + box_file, lut_file, wire_delay, box_lookup, scc_break_inputs); continue; } @@ -1256,7 +1293,7 @@ struct Abc9Pass : public Pass { en_sig = assign_map(std::get<3>(it.first)); abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$", keepff, delay_target, lutin_shared, fast_mode, show_tempdir, - box_file, lut_file, wire_delay, box_lookup); + box_file, lut_file, wire_delay, box_lookup, scc_break_inputs); assign_map.set(mod); } } diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc new file mode 100644 index 000000000..246932d81 --- /dev/null +++ b/passes/techmap/clkbufmap.cc @@ -0,0 +1,298 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2019 Marcin KoĆcielnicki <mwk@0x04.net> + * + * 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" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +void split_portname_pair(std::string &port1, std::string &port2) +{ + size_t pos = port1.find_first_of(':'); + if (pos != std::string::npos) { + port2 = port1.substr(pos+1); + port1 = port1.substr(0, pos); + } +} + +struct ClkbufmapPass : public Pass { + ClkbufmapPass() : Pass("clkbufmap", "insert global buffers on clock networks") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" clkbufmap [options] [selection]\n"); + log("\n"); + log("Inserts global buffers between nets connected to clock inputs and their drivers.\n"); + log("\n"); + log("In the absence of any selection, all wires without the 'clkbuf_inhibit'\n"); + log("attribute will be considered for global buffer insertion.\n"); + log("Alternatively, to consider all wires without the 'buffer_type' attribute set to\n"); + log("'none' or 'bufr' one would specify:\n"); + log(" 'w:* a:buffer_type=none a:buffer_type=bufr %%u %%d'\n"); + log("as the selection.\n"); + log("\n"); + log(" -buf <celltype> <portname_out>:<portname_in>\n"); + log(" Specifies the cell type to use for the global buffers\n"); + log(" and its port names. The first port will be connected to\n"); + log(" the clock network sinks, and the second will be connected\n"); + log(" to the actual clock source. This option is required.\n"); + log("\n"); + log(" -inpad <celltype> <portname_out>:<portname_in>\n"); + log(" If specified, a PAD cell of the given type is inserted on\n"); + log(" clock nets that are also top module's inputs (in addition\n"); + log(" to the global buffer).\n"); + log("\n"); + } + + void module_queue(Design *design, Module *module, std::vector<Module *> &modules_sorted, pool<Module *> &modules_processed) { + if (modules_processed.count(module)) + return; + for (auto cell : module->cells()) { + Module *submodule = design->module(cell->type); + if (!submodule) + continue; + module_queue(design, submodule, modules_sorted, modules_processed); + } + modules_sorted.push_back(module); + modules_processed.insert(module); + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing CLKBUFMAP pass (inserting global clock buffers).\n"); + + std::string buf_celltype, buf_portname, buf_portname2; + std::string inpad_celltype, inpad_portname, inpad_portname2; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + std::string arg = args[argidx]; + if (arg == "-buf" && argidx+2 < args.size()) { + buf_celltype = args[++argidx]; + buf_portname = args[++argidx]; + split_portname_pair(buf_portname, buf_portname2); + continue; + } + if (arg == "-inpad" && argidx+2 < args.size()) { + inpad_celltype = args[++argidx]; + inpad_portname = args[++argidx]; + split_portname_pair(inpad_portname, inpad_portname2); + continue; + } + break; + } + + bool select = false; + if (argidx < args.size()) { + if (args[argidx].compare(0, 1, "-") != 0) + select = true; + extra_args(args, argidx, design); + } + + if (buf_celltype.empty()) + log_error("The -buf option is required.\n"); + + // Cell type, port name, bit index. + pool<pair<IdString, pair<IdString, int>>> sink_ports; + pool<pair<IdString, pair<IdString, int>>> buf_ports; + + // Process submodules before module using them. + std::vector<Module *> modules_sorted; + pool<Module *> modules_processed; + for (auto module : design->selected_modules()) + module_queue(design, module, modules_sorted, modules_processed); + + for (auto module : modules_sorted) + { + if (module->get_blackbox_attribute()) { + for (auto port : module->ports) { + auto wire = module->wire(port); + if (wire->get_bool_attribute("\\clkbuf_driver")) + for (int i = 0; i < GetSize(wire); i++) + buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + if (wire->get_bool_attribute("\\clkbuf_sink")) + for (int i = 0; i < GetSize(wire); i++) + sink_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + } + continue; + } + pool<SigBit> sink_wire_bits; + pool<SigBit> buf_wire_bits; + pool<SigBit> driven_wire_bits; + SigMap sigmap(module); + // bit -> (buffer, buffer's input) + dict<SigBit, pair<Cell *, Wire *>> buffered_bits; + + // First, collect nets that could use a clock buffer. + for (auto cell : module->cells()) + for (auto port : cell->connections()) + for (int i = 0; i < port.second.size(); i++) + if (sink_ports.count(make_pair(cell->type, make_pair(port.first, i)))) + sink_wire_bits.insert(sigmap(port.second[i])); + + // Second, collect ones that already have a clock buffer. + for (auto cell : module->cells()) + for (auto port : cell->connections()) + for (int i = 0; i < port.second.size(); i++) + if (buf_ports.count(make_pair(cell->type, make_pair(port.first, i)))) + buf_wire_bits.insert(sigmap(port.second[i])); + + // Collect all driven bits. + for (auto cell : module->cells()) + for (auto port : cell->connections()) + if (cell->output(port.first)) + for (int i = 0; i < port.second.size(); i++) + driven_wire_bits.insert(port.second[i]); + + // Insert buffers. + std::vector<pair<Wire *, Wire *>> input_queue; + // Copy current wire list, as we will be adding new ones during iteration. + std::vector<Wire *> wires(module->wires()); + for (auto wire : wires) + { + // Should not happen. + if (wire->port_input && wire->port_output) + continue; + bool process_wire = module->selected(wire); + if (!select && wire->get_bool_attribute("\\clkbuf_inhibit")) + process_wire = false; + if (!process_wire) { + // This wire is supposed to be bypassed, so make sure we don't buffer it in + // some buffer higher up in the hierarchy. + if (wire->port_output) + for (int i = 0; i < GetSize(wire); i++) + buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + continue; + } + + pool<int> input_bits; + + for (int i = 0; i < GetSize(wire); i++) + { + SigBit wire_bit(wire, i); + SigBit mapped_wire_bit = sigmap(wire_bit); + if (buf_wire_bits.count(mapped_wire_bit)) { + // Already buffered downstream. If this is an output, mark it. + if (wire->port_output) + buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + } else if (!sink_wire_bits.count(mapped_wire_bit)) { + // Nothing to do. + } else if (driven_wire_bits.count(wire_bit) || (wire->port_input && module->get_bool_attribute("\\top"))) { + // Clock network not yet buffered, driven by one of + // our cells or a top-level input -- buffer it. + + log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i); + RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype)); + Wire *iwire = module->addWire(NEW_ID); + cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit); + cell->setPort(RTLIL::escape_id(buf_portname2), iwire); + if (wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute("\\top")) { + log("Inserting %s on %s.%s[%d].\n", inpad_celltype.c_str(), log_id(module), log_id(wire), i); + RTLIL::Cell *cell2 = module->addCell(NEW_ID, RTLIL::escape_id(inpad_celltype)); + cell2->setPort(RTLIL::escape_id(inpad_portname), iwire); + iwire = module->addWire(NEW_ID); + cell2->setPort(RTLIL::escape_id(inpad_portname2), iwire); + } + buffered_bits[mapped_wire_bit] = make_pair(cell, iwire); + + if (wire->port_input) { + input_bits.insert(i); + } + } else if (wire->port_input) { + // A clock input in a submodule -- mark it, let higher level + // worry about it. + if (wire->port_input) + sink_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + } + } + if (!input_bits.empty()) { + // This is an input port and some buffers were inserted -- we need + // to create a new input wire and transfer attributes. + Wire *new_wire = module->addWire(NEW_ID, wire); + + for (int i = 0; i < wire->width; i++) { + SigBit wire_bit(wire, i); + SigBit mapped_wire_bit = sigmap(wire_bit); + auto it = buffered_bits.find(mapped_wire_bit); + if (it != buffered_bits.end()) { + + module->connect(it->second.second, SigSpec(new_wire, i)); + } else { + module->connect(SigSpec(wire, i), SigSpec(new_wire, i)); + } + } + input_queue.push_back(make_pair(wire, new_wire)); + } + } + + // Mark any newly-buffered output ports as such. + for (auto wire : module->selected_wires()) { + if (wire->port_input || !wire->port_output) + continue; + for (int i = 0; i < GetSize(wire); i++) + { + SigBit wire_bit(wire, i); + SigBit mapped_wire_bit = sigmap(wire_bit); + if (buffered_bits.count(mapped_wire_bit)) + buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + } + } + + // Reconnect the drivers to buffer inputs. + for (auto cell : module->cells()) + for (auto port : cell->connections()) { + if (!cell->output(port.first)) + continue; + SigSpec sig = port.second; + bool newsig = false; + for (auto &bit : sig) { + const auto it = buffered_bits.find(sigmap(bit)); + if (it == buffered_bits.end()) + continue; + // Avoid substituting buffer's own output pin. + if (cell == it->second.first) + continue; + bit = it->second.second; + newsig = true; + } + if (newsig) + cell->setPort(port.first, sig); + } + + // This has to be done last, to avoid upsetting sigmap before the port reconnections. + for (auto &it : input_queue) { + Wire *wire = it.first; + Wire *new_wire = it.second; + module->swap_names(new_wire, wire); + wire->attributes.clear(); + wire->port_id = 0; + wire->port_input = false; + wire->port_output = false; + } + + module->fixup_ports(); + } + } +} ClkbufmapPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index a2551316f..c868b9a87 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -64,6 +64,11 @@ struct IopadmapPass : public Pass { log(" of the tristate driver and the 2nd portname is the internal output\n"); log(" buffering the external signal.\n"); log("\n"); + log(" -ignore <celltype> <portname>[:<portname>]*\n"); + log(" Skips mapping inputs/outputs that are already connected to given\n"); + log(" ports of the given cell. Can be used multiple times. This is in\n"); + log(" addition to the cells specified as mapping targets.\n"); + log("\n"); log(" -widthparam <param_name>\n"); log(" Use the specified parameter name to set the port width.\n"); log("\n"); @@ -88,6 +93,7 @@ struct IopadmapPass : public Pass { std::string toutpad_celltype, toutpad_portname, toutpad_portname2, toutpad_portname3; std::string tinoutpad_celltype, tinoutpad_portname, tinoutpad_portname2, tinoutpad_portname3, tinoutpad_portname4; std::string widthparam, nameparam; + pool<pair<IdString, IdString>> ignore; bool flag_bits = false; size_t argidx; @@ -127,6 +133,18 @@ struct IopadmapPass : public Pass { split_portname_pair(tinoutpad_portname3, tinoutpad_portname4); continue; } + if (arg == "-ignore" && argidx+2 < args.size()) { + std::string ignore_celltype = args[++argidx]; + std::string ignore_portname = args[++argidx]; + std::string ignore_portname2; + while (!ignore_portname.empty()) { + split_portname_pair(ignore_portname, ignore_portname2); + ignore.insert(make_pair(RTLIL::escape_id(ignore_celltype), RTLIL::escape_id(ignore_portname))); + + ignore_portname = ignore_portname2; + } + continue; + } if (arg == "-widthparam" && argidx+1 < args.size()) { widthparam = args[++argidx]; continue; @@ -143,6 +161,23 @@ struct IopadmapPass : public Pass { } extra_args(args, argidx, design); + if (!inpad_portname2.empty()) + ignore.insert(make_pair(RTLIL::escape_id(inpad_celltype), RTLIL::escape_id(inpad_portname2))); + if (!outpad_portname2.empty()) + ignore.insert(make_pair(RTLIL::escape_id(outpad_celltype), RTLIL::escape_id(outpad_portname2))); + if (!inoutpad_portname2.empty()) + ignore.insert(make_pair(RTLIL::escape_id(inoutpad_celltype), RTLIL::escape_id(inoutpad_portname2))); + if (!toutpad_portname3.empty()) + ignore.insert(make_pair(RTLIL::escape_id(toutpad_celltype), RTLIL::escape_id(toutpad_portname3))); + if (!tinoutpad_portname4.empty()) + ignore.insert(make_pair(RTLIL::escape_id(tinoutpad_celltype), RTLIL::escape_id(tinoutpad_portname4))); + + for (auto module : design->modules()) + if (module->get_blackbox_attribute()) + for (auto wire : module->wires()) + if (wire->get_bool_attribute("\\iopad_external_pin")) + ignore.insert(make_pair(module->name, wire->name)); + for (auto module : design->selected_modules()) { dict<IdString, pool<int>> skip_wires; @@ -150,28 +185,11 @@ struct IopadmapPass : public Pass { SigMap sigmap(module); for (auto cell : module->cells()) - { - if (cell->type == RTLIL::escape_id(inpad_celltype) && cell->hasPort(RTLIL::escape_id(inpad_portname2))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inpad_portname2)))) - skip_wire_bits.insert(bit); - - if (cell->type == RTLIL::escape_id(outpad_celltype) && cell->hasPort(RTLIL::escape_id(outpad_portname2))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(outpad_portname2)))) + for (auto port : cell->connections()) + if (ignore.count(make_pair(cell->type, port.first))) + for (auto bit : sigmap(port.second)) skip_wire_bits.insert(bit); - if (cell->type == RTLIL::escape_id(inoutpad_celltype) && cell->hasPort(RTLIL::escape_id(inoutpad_portname2))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inoutpad_portname2)))) - skip_wire_bits.insert(bit); - - if (cell->type == RTLIL::escape_id(toutpad_celltype) && cell->hasPort(RTLIL::escape_id(toutpad_portname3))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(toutpad_portname3)))) - skip_wire_bits.insert(bit); - - if (cell->type == RTLIL::escape_id(tinoutpad_celltype) && cell->hasPort(RTLIL::escape_id(tinoutpad_portname4))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(tinoutpad_portname4)))) - skip_wire_bits.insert(bit); - } - if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty()) { dict<SigBit, pair<IdString, pool<IdString>>> tbuf_bits; diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index b271c8781..c4496f76f 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -943,7 +943,8 @@ struct TechmapPass : public Pass { log(" instead of inlining them.\n"); log("\n"); log(" -max_iter <number>\n"); - log(" only run the specified number of iterations.\n"); + log(" only run the specified number of iterations on each module.\n"); + log(" default: unlimited\n"); log("\n"); log(" -recursive\n"); log(" instead of the iterative breadth-first algorithm use a recursive\n"); @@ -1157,15 +1158,16 @@ struct TechmapPass : public Pass { RTLIL::Module *module = *worker.module_queue.begin(); worker.module_queue.erase(module); + int module_max_iter = max_iter; 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 (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) + if (module_max_iter > 0 && --module_max_iter == 0) break; } } |