diff options
author | Eddie Hung <eddie@fpgeh.com> | 2019-07-01 10:44:42 -0700 |
---|---|---|
committer | Eddie Hung <eddie@fpgeh.com> | 2019-07-01 10:44:42 -0700 |
commit | 699d8e393953a3e5f0c35afec54464e6810f8f1d (patch) | |
tree | 4edf4b25dd3c9f8eaf1dad737baa49a04f78ec3f /passes/techmap | |
parent | 75d92fb590b190e0da43e99853f839b7afb10f83 (diff) | |
parent | 0067dc44f3928833eede2b9bb40260be78e11a93 (diff) | |
download | yosys-699d8e393953a3e5f0c35afec54464e6810f8f1d.tar.gz yosys-699d8e393953a3e5f0c35afec54464e6810f8f1d.tar.bz2 yosys-699d8e393953a3e5f0c35afec54464e6810f8f1d.zip |
Merge remote-tracking branch 'origin/master' into xaig_dff
Diffstat (limited to 'passes/techmap')
-rw-r--r-- | passes/techmap/Makefile.inc | 1 | ||||
-rw-r--r-- | passes/techmap/abc9.cc | 121 | ||||
-rw-r--r-- | passes/techmap/muxcover.cc | 181 | ||||
-rw-r--r-- | passes/techmap/shregmap.cc | 20 |
4 files changed, 232 insertions, 91 deletions
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index c45571b01..56f05eca4 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -10,6 +10,7 @@ OBJS += passes/techmap/abc.o OBJS += passes/techmap/abc9.o ifneq ($(ABCEXTERNAL),) passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' +passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' endif endif diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index f56350b1d..2eee43739 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -33,7 +33,7 @@ #endif -#define ABC_FAST_COMMAND_LUT "&st; &retime; &if {W}" +#define ABC_FAST_COMMAND_LUT "&st; &if {W} {D}" #include "kernel/register.h" #include "kernel/sigtools.h" @@ -80,8 +80,7 @@ void handle_loops(RTLIL::Design *design) { Pass::call(design, "scc -set_attr abc_scc_id {}"); - design->selection_stack.emplace_back(false); - RTLIL::Selection& sel = design->selection_stack.back(); + 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 @@ -92,24 +91,72 @@ void handle_loops(RTLIL::Design *design) if (it != cell->attributes.end()) { auto r = ids_seen.insert(it->second); if (r.second) { - for (const auto &c : cell->connections()) { + for (auto &c : cell->connections_) { if (c.second.is_fully_const()) continue; if (cell->output(c.first)) { SigBit b = c.second.as_bit(); Wire *w = b.wire; + log_assert(!w->port_input); + w->port_input = true; + 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_output = true; + } + else { + log_assert(w->port_input); + log_assert(b.offset < GetSize(w)); + } w->set_bool_attribute("\\abc_scc_break"); - sel.select(module, w); + module->swap_names(b.wire, w); + c.second = RTLIL::SigBit(w, b.offset); } } } cell->attributes.erase(it); } - } - // Then cut those selected wires to expose them as new PO/PI - Pass::call(design, "expose -cut -sep .abc"); + 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("\\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("\\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)); + } + rhs = sig; + } + } - design->selection_stack.pop_back(); + module->fixup_ports(); } std::string add_echos_to_abc_cmd(std::string str) @@ -380,9 +427,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri RTLIL::Selection& sel = design->selection_stack.back(); sel.select(module); - // Behave as for "abc" where BLIF writer implicitly outputs all undef as zero - Pass::call(design, "setundef -zero"); - Pass::call(design, "aigmap"); handle_loops(design); @@ -409,7 +453,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri reader.parse_xaiger(); } ifs.close(); - Pass::call(design, stringf("write_verilog -noexpr -norename %s/%s", tempdir_name.c_str(), "input.v")); + Pass::call(design, stringf("write_verilog -noexpr -norename")); design->remove(design->module("$__abc9__")); #endif @@ -482,7 +526,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri ifs.close(); #if 0 - Pass::call(design, stringf("write_verilog -noexpr -norename %s/%s", tempdir_name.c_str(), "output.v")); + Pass::call(design, stringf("write_verilog -noexpr -norename")); #endif log_header(design, "Re-integrating ABC9 results.\n"); @@ -498,7 +542,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri if (w->port_output) { RTLIL::Wire *wire = module->wire(w->name); log_assert(wire); - for (int i = 0; i < GetSize(wire); i++) + for (int i = 0; i < GetSize(w); i++) output_bits.insert({wire, i}); } @@ -518,24 +562,28 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri signal = std::move(bits); } + dict<IdString, bool> abc_box; vector<RTLIL::Cell*> boxes; - for (auto it = module->cells_.begin(); it != module->cells_.end(); ) { - RTLIL::Cell* cell = it->second; - if (cell->type.in("$_AND_", "$_NOT_", "$__ABC_FF_")) { - it = module->remove(it); + for (const auto &it : module->cells_) { + auto cell = it.second; + if (cell->type.in("$_AND_", "$_NOT_")) { + module->remove(cell); continue; } - RTLIL::Module* box_module = design->module(cell->type); - if (box_module && box_module->attributes.count("\\abc_box_id")) + auto jt = abc_box.find(cell->type); + if (jt == abc_box.end()) { + RTLIL::Module* box_module = design->module(cell->type); + jt = abc_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count("\\abc_box_id"))).first; + } + if (jt->second) boxes.emplace_back(cell); - ++it; } std::map<std::string, int> cell_stats; for (auto c : mapped_mod->cells()) { + RTLIL::Cell *cell = nullptr; if (c->type == "$_NOT_") { - RTLIL::Cell *cell; RTLIL::SigBit a_bit = c->getPort("\\A").as_bit(); RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit(); if (!a_bit.wire) { @@ -589,11 +637,12 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri cell->setPort("\\Y", RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset)); cell_stats[RTLIL::unescape_id(c->type)]++; } - if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; + if (cell && markgroups) cell->attributes["\\abcgroup"] = map_autoidx; continue; } cell_stats[RTLIL::unescape_id(c->type)]++; + RTLIL::Cell *existing_cell = nullptr; if (c->type == "$lut") { if (GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) { SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]; @@ -602,19 +651,23 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri if (markgroups) c->attributes["\\abcgroup"] = map_autoidx; continue; } + cell = module->addCell(remap_name(c->name), c->type); + } + else { + existing_cell = module->cell(c->name); + cell = module->addCell(remap_name(c->name), c->type); + module->swap_names(cell, existing_cell); } - RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type); if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; - RTLIL::Cell *existing_cell = module->cell(c->name); - if (existing_cell) { - cell->parameters = existing_cell->parameters; - cell->attributes = existing_cell->attributes; - } - else { - cell->parameters = c->parameters; - cell->attributes = c->attributes; - } + if (existing_cell) { + cell->parameters = existing_cell->parameters; + cell->attributes = existing_cell->attributes; + } + else { + cell->parameters = c->parameters; + cell->attributes = c->attributes; + } for (auto &conn : c->connections()) { RTLIL::SigSpec newsig; for (auto c : conn.second.chunks()) { diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index 32102436d..c84cfc39a 100644 --- a/passes/techmap/muxcover.cc +++ b/passes/techmap/muxcover.cc @@ -23,6 +23,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +#define COST_DMUX 90 #define COST_MUX2 100 #define COST_MUX4 220 #define COST_MUX8 460 @@ -57,7 +58,9 @@ struct MuxcoverWorker bool use_mux8; bool use_mux16; bool nodecode; + bool nopartial; + int cost_dmux; int cost_mux2; int cost_mux4; int cost_mux8; @@ -69,6 +72,8 @@ struct MuxcoverWorker use_mux8 = false; use_mux16 = false; nodecode = false; + nopartial = false; + cost_dmux = COST_DMUX; cost_mux2 = COST_MUX2; cost_mux4 = COST_MUX4; cost_mux8 = COST_MUX8; @@ -76,6 +81,23 @@ struct MuxcoverWorker decode_mux_counter = 0; } + bool xcmp(std::initializer_list<SigBit> list) + { + auto cursor = list.begin(), end = list.end(); + log_assert(cursor != end); + SigBit tmp = *(cursor++); + while (cursor != end) { + SigBit bit = *(cursor++); + if (bit == State::Sx) + continue; + if (tmp == State::Sx) + tmp = bit; + if (bit != tmp) + return false; + } + return true; + } + void treeify() { pool<SigBit> roots; @@ -133,13 +155,22 @@ struct MuxcoverWorker log(" Finished treeification: Found %d trees.\n", GetSize(tree_list)); } - bool follow_muxtree(SigBit &ret_bit, tree_t &tree, SigBit bit, const char *path) + bool follow_muxtree(SigBit &ret_bit, tree_t &tree, SigBit bit, const char *path, bool first_layer = true) { if (*path) { - if (tree.muxes.count(bit) == 0) - return false; + if (tree.muxes.count(bit) == 0) { + if (first_layer || nopartial) + return false; + while (path[0] && path[1]) + path++; + if (path[0] == 'S') + ret_bit = State::Sx; + else + ret_bit = bit; + return true; + } char port_name[3] = {'\\', *path, 0}; - return follow_muxtree(ret_bit, tree, sigmap(tree.muxes.at(bit)->getPort(port_name)), path+1); + return follow_muxtree(ret_bit, tree, sigmap(tree.muxes.at(bit)->getPort(port_name)), path+1, false); } else { ret_bit = bit; return true; @@ -148,7 +179,7 @@ struct MuxcoverWorker int prepare_decode_mux(SigBit &A, SigBit B, SigBit sel, SigBit bit) { - if (A == B) + if (A == B || sel == State::Sx) return 0; tuple<SigBit, SigBit, SigBit> key(A, B, sel); @@ -166,7 +197,10 @@ struct MuxcoverWorker if (std::get<2>(entry)) return 0; - return cost_mux2 / GetSize(std::get<1>(entry)); + if (A == State::Sx || B == State::Sx) + return 0; + + return cost_dmux / GetSize(std::get<1>(entry)); } void implement_decode_mux(SigBit ctrl_bit) @@ -183,9 +217,32 @@ struct MuxcoverWorker implement_decode_mux(std::get<0>(key)); implement_decode_mux(std::get<1>(key)); - module->addMuxGate(NEW_ID, std::get<0>(key), std::get<1>(key), std::get<2>(key), ctrl_bit); + if (std::get<0>(key) == State::Sx) { + module->addBufGate(NEW_ID, std::get<1>(key), ctrl_bit); + } else if (std::get<1>(key) == State::Sx) { + module->addBufGate(NEW_ID, std::get<0>(key), ctrl_bit); + } else { + module->addMuxGate(NEW_ID, std::get<0>(key), std::get<1>(key), std::get<2>(key), ctrl_bit); + decode_mux_counter++; + } std::get<2>(entry) = true; - decode_mux_counter++; + } + + void find_best_covers(tree_t &tree, const vector<SigBit> &bits) + { + for (auto bit : bits) + find_best_cover(tree, bit); + } + + int sum_best_covers(tree_t &tree, const vector<SigBit> &bits) + { + int sum = 0; + for (auto bit : pool<SigBit>(bits.begin(), bits.end())) { + int cost = tree.newmuxes.at(bit).cost; + log_debug(" Best cost for %s: %d\n", log_signal(bit), cost); + sum += cost; + } + return sum; } int find_best_cover(tree_t &tree, SigBit bit) @@ -218,9 +275,13 @@ struct MuxcoverWorker mux.inputs.push_back(B); mux.selects.push_back(S1); + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux2 at %s: %d\n", log_signal(bit), mux.cost); + mux.cost += cost_mux2; - mux.cost += find_best_cover(tree, A); - mux.cost += find_best_cover(tree, B); + mux.cost += sum_best_covers(tree, mux.inputs); + + log_debug(" Cost of mux2 at %s: %d\n", log_signal(bit), mux.cost); best_mux = mux; } @@ -238,7 +299,7 @@ struct MuxcoverWorker ok = ok && follow_muxtree(S2, tree, bit, "BS"); if (nodecode) - ok = ok && S1 == S2; + ok = ok && xcmp({S1, S2}); ok = ok && follow_muxtree(T1, tree, bit, "S"); @@ -256,13 +317,15 @@ struct MuxcoverWorker mux.selects.push_back(S1); mux.selects.push_back(T1); + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux4 at %s: %d\n", log_signal(bit), mux.cost); + mux.cost += cost_mux4; - mux.cost += find_best_cover(tree, A); - mux.cost += find_best_cover(tree, B); - mux.cost += find_best_cover(tree, C); - mux.cost += find_best_cover(tree, D); + mux.cost += sum_best_covers(tree, mux.inputs); - if (best_mux.cost > mux.cost) + log_debug(" Cost of mux4 at %s: %d\n", log_signal(bit), mux.cost); + + if (best_mux.cost >= mux.cost) best_mux = mux; } } @@ -286,13 +349,13 @@ struct MuxcoverWorker ok = ok && follow_muxtree(S4, tree, bit, "BBS"); if (nodecode) - ok = ok && S1 == S2 && S2 == S3 && S3 == S4; + ok = ok && xcmp({S1, S2, S3, S4}); ok = ok && follow_muxtree(T1, tree, bit, "AS"); ok = ok && follow_muxtree(T2, tree, bit, "BS"); if (nodecode) - ok = ok && T1 == T2; + ok = ok && xcmp({T1, T2}); ok = ok && follow_muxtree(U1, tree, bit, "S"); @@ -319,17 +382,15 @@ struct MuxcoverWorker mux.selects.push_back(T1); mux.selects.push_back(U1); + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux8 at %s: %d\n", log_signal(bit), mux.cost); + mux.cost += cost_mux8; - mux.cost += find_best_cover(tree, A); - mux.cost += find_best_cover(tree, B); - mux.cost += find_best_cover(tree, C); - mux.cost += find_best_cover(tree, D); - mux.cost += find_best_cover(tree, E); - mux.cost += find_best_cover(tree, F); - mux.cost += find_best_cover(tree, G); - mux.cost += find_best_cover(tree, H); - - if (best_mux.cost > mux.cost) + mux.cost += sum_best_covers(tree, mux.inputs); + + log_debug(" Cost of mux8 at %s: %d\n", log_signal(bit), mux.cost); + + if (best_mux.cost >= mux.cost) best_mux = mux; } } @@ -365,7 +426,7 @@ struct MuxcoverWorker ok = ok && follow_muxtree(S8, tree, bit, "BBBS"); if (nodecode) - ok = ok && S1 == S2 && S2 == S3 && S3 == S4 && S4 == S5 && S5 == S6 && S6 == S7 && S7 == S8; + ok = ok && xcmp({S1, S2, S3, S4, S5, S6, S7, S8}); ok = ok && follow_muxtree(T1, tree, bit, "AAS"); ok = ok && follow_muxtree(T2, tree, bit, "ABS"); @@ -373,13 +434,13 @@ struct MuxcoverWorker ok = ok && follow_muxtree(T4, tree, bit, "BBS"); if (nodecode) - ok = ok && T1 == T2 && T2 == T3 && T3 == T4; + ok = ok && xcmp({T1, T2, T3, T4}); ok = ok && follow_muxtree(U1, tree, bit, "AS"); ok = ok && follow_muxtree(U2, tree, bit, "BS"); if (nodecode) - ok = ok && U1 == U2; + ok = ok && xcmp({U1, U2}); ok = ok && follow_muxtree(V1, tree, bit, "S"); @@ -423,25 +484,15 @@ struct MuxcoverWorker mux.selects.push_back(U1); mux.selects.push_back(V1); + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux16 at %s: %d\n", log_signal(bit), mux.cost); + mux.cost += cost_mux16; - mux.cost += find_best_cover(tree, A); - mux.cost += find_best_cover(tree, B); - mux.cost += find_best_cover(tree, C); - mux.cost += find_best_cover(tree, D); - mux.cost += find_best_cover(tree, E); - mux.cost += find_best_cover(tree, F); - mux.cost += find_best_cover(tree, G); - mux.cost += find_best_cover(tree, H); - mux.cost += find_best_cover(tree, I); - mux.cost += find_best_cover(tree, J); - mux.cost += find_best_cover(tree, K); - mux.cost += find_best_cover(tree, L); - mux.cost += find_best_cover(tree, M); - mux.cost += find_best_cover(tree, N); - mux.cost += find_best_cover(tree, O); - mux.cost += find_best_cover(tree, P); - - if (best_mux.cost > mux.cost) + mux.cost += sum_best_covers(tree, mux.inputs); + + log_debug(" Cost of mux16 at %s: %d\n", log_signal(bit), mux.cost); + + if (best_mux.cost >= mux.cost) best_mux = mux; } } @@ -537,6 +588,7 @@ struct MuxcoverWorker void treecover(tree_t &tree) { int count_muxes_by_type[4] = {0, 0, 0, 0}; + log_debug(" Searching for best cover for tree at %s.\n", log_signal(tree.root)); find_best_cover(tree, tree.root); implement_best_cover(tree, tree.root, count_muxes_by_type); log(" Replaced tree at %s: %d MUX2, %d MUX4, %d MUX8, %d MUX16\n", log_signal(tree.root), @@ -553,12 +605,13 @@ struct MuxcoverWorker log(" Covering trees:\n"); - // pre-fill cache of decoder muxes - if (!nodecode) + if (!nodecode) { + log_debug(" Populating cache of decoder muxes.\n"); for (auto &tree : tree_list) { find_best_cover(tree, tree.root); tree.newmuxes.clear(); } + } for (auto &tree : tree_list) treecover(tree); @@ -584,11 +637,19 @@ struct MuxcoverPass : public Pass { log(" Default costs: $_MUX_ = %d, $_MUX4_ = %d,\n", COST_MUX2, COST_MUX4); log(" $_MUX8_ = %d, $_MUX16_ = %d\n", COST_MUX8, COST_MUX16); log("\n"); + log(" -dmux=cost\n"); + log(" Use the specified cost for $_MUX_ cells used in decoders.\n"); + log(" Default cost: %d\n", COST_DMUX); + log("\n"); log(" -nodecode\n"); log(" Do not insert decoder logic. This reduces the number of possible\n"); log(" substitutions, but guarantees that the resulting circuit is not\n"); log(" less efficient than the original circuit.\n"); log("\n"); + log(" -nopartial\n"); + log(" Do not consider mappings that use $_MUX<N>_ to select from less\n"); + log(" than <N> different signals.\n"); + log("\n"); } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { @@ -598,6 +659,8 @@ struct MuxcoverPass : public Pass { bool use_mux8 = false; bool use_mux16 = false; bool nodecode = false; + bool nopartial = false; + int cost_dmux = COST_DMUX; int cost_mux4 = COST_MUX4; int cost_mux8 = COST_MUX8; int cost_mux16 = COST_MUX16; @@ -610,7 +673,7 @@ struct MuxcoverPass : public Pass { use_mux4 = true; if (arg.size() > 5) { if (arg[5] != '=') break; - cost_mux4 = atoi(arg.substr(5).c_str()); + cost_mux4 = atoi(arg.substr(6).c_str()); } continue; } @@ -618,7 +681,7 @@ struct MuxcoverPass : public Pass { use_mux8 = true; if (arg.size() > 5) { if (arg[5] != '=') break; - cost_mux8 = atoi(arg.substr(5).c_str()); + cost_mux8 = atoi(arg.substr(6).c_str()); } continue; } @@ -626,14 +689,22 @@ struct MuxcoverPass : public Pass { use_mux16 = true; if (arg.size() > 6) { if (arg[6] != '=') break; - cost_mux16 = atoi(arg.substr(6).c_str()); + cost_mux16 = atoi(arg.substr(7).c_str()); } continue; } + if (arg.size() >= 6 && arg.substr(0,6) == "-dmux=") { + cost_dmux = atoi(arg.substr(6).c_str()); + continue; + } if (arg == "-nodecode") { nodecode = true; continue; } + if (arg == "-nopartial") { + nopartial = true; + continue; + } break; } extra_args(args, argidx, design); @@ -650,10 +721,12 @@ struct MuxcoverPass : public Pass { worker.use_mux4 = use_mux4; worker.use_mux8 = use_mux8; worker.use_mux16 = use_mux16; + worker.cost_dmux = cost_dmux; worker.cost_mux4 = cost_mux4; worker.cost_mux8 = cost_mux8; worker.cost_mux16 = cost_mux16; worker.nodecode = nodecode; + worker.nopartial = nopartial; worker.run(); } } diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 21dfe9619..004ab1eb9 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -293,10 +293,22 @@ struct ShregmapWorker if (opts.init || sigbit_init.count(q_bit) == 0) { - if (sigbit_chain_next.count(d_bit)) { + auto r = sigbit_chain_next.insert(std::make_pair(d_bit, cell)); + if (!r.second) { + // Insertion not successful means that d_bit is already + // connected to another register, thus mark it as a + // non chain user ... sigbit_with_non_chain_users.insert(d_bit); - } else - sigbit_chain_next[d_bit] = cell; + // ... and clone d_bit into another wire, and use that + // wire as a different key in the d_bit-to-cell dictionary + // so that it can be identified as another chain + // (omitting this common flop) + // Link: https://github.com/YosysHQ/yosys/pull/1085 + Wire *wire = module->addWire(NEW_ID); + module->connect(wire, d_bit); + sigmap.add(wire, d_bit); + sigbit_chain_next.insert(std::make_pair(wire, cell)); + } sigbit_chain_prev[q_bit] = cell; continue; @@ -605,9 +617,11 @@ struct ShregmapPass : public Pass { log("\n"); log(" -tech greenpak4\n"); log(" map to greenpak4 shift registers.\n"); + log(" this option also implies -clkpol pos -zinit\n"); log("\n"); log(" -tech xilinx\n"); log(" map to xilinx dynamic-length shift registers.\n"); + log(" this option also implies -params -init\n"); log("\n"); } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE |