From f348ffa44d4ec00537499ffe79ce627beeeefe85 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 28 Dec 2019 05:07:46 -0800 Subject: abc9_techmap -> _map; called from abc9 script pass along with abc9_ops --- passes/techmap/abc9_ops.cc | 139 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 passes/techmap/abc9_ops.cc (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc new file mode 100644 index 000000000..4c30efd06 --- /dev/null +++ b/passes/techmap/abc9_ops.cc @@ -0,0 +1,139 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * 2019 Eddie Hung + * + * 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/register.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +void break_scc(RTLIL::Module *module) +{ + // For every unique SCC found, (arbitrarily) find the first + // cell in the component, and convert all wires driven by + // its output ports into a new PO, and drive its previous + // sinks with a new PI + pool ids_seen; + for (auto cell : module->selected_cells()) { + auto it = cell->attributes.find(ID(abc9_scc_id)); + if (it == cell->attributes.end()) + continue; + auto r = ids_seen.insert(it->second); + cell->attributes.erase(it); + if (!r.second) + continue; + 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; + if (w->port_input) { + // In this case, hopefully the loop break has been already created + // Get the non-prefixed wire + Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str())); + log_assert(wo != nullptr); + log_assert(wo->port_output); + log_assert(b.offset < GetSize(wo)); + c.second = RTLIL::SigBit(wo, b.offset); + } + else { + // Create a new output/input loop break + w->port_input = true; + w = module->wire(stringf("%s.abco", w->name.c_str())); + if (!w) { + w = module->addWire(stringf("%s.abco", 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(ID(abc9_scc_break)); + c.second = RTLIL::SigBit(w, b.offset); + } + } + } + } + + module->fixup_ports(); +} + +void unbreak_scc(RTLIL::Module *module) { + // Now 'unexpose' those wires by undoing + // the expose operation -- remove them from PO/PI + // and re-connecting them back together + for (auto wire : module->wires()) { + auto it = wire->attributes.find(ID(abc9_scc_break)); + if (it != wire->attributes.end()) { + wire->attributes.erase(it); + log_assert(wire->port_output); + wire->port_output = false; + std::string name = wire->name.str(); + RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5)); + log_assert(i_wire); + log_assert(i_wire->port_input); + i_wire->port_input = false; + module->connect(i_wire, wire); + } + } + module->fixup_ports(); +} + +struct Abc9PrepPass : public Pass { + Abc9PrepPass() : Pass("abc9_ops", "helper functions for ABC9") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" abc9_ops [options] [selection]\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); + log_push(); + + bool break_scc_mode = false; + bool unbreak_scc_mode = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-break_scc") { + break_scc_mode = true; + continue; + } + if (arg == "-unbreak_scc") { + unbreak_scc_mode = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto mod : design->selected_modules()) { + if (break_scc_mode) + break_scc(mod); + if (unbreak_scc_mode) + unbreak_scc(mod); + } + } +} Abc9PrepPass; + +PRIVATE_NAMESPACE_END -- cgit v1.2.3 From 16c4ec7edaa3cb66ced2f856d3c48f30d7d2acf1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 16:36:33 -0800 Subject: Add abc9_ops -prep_dff --- passes/techmap/abc9_ops.cc | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 4c30efd06..3e7e5ec7f 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -19,6 +19,7 @@ */ #include "kernel/register.h" +#include "kernel/sigtools.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -95,6 +96,44 @@ void unbreak_scc(RTLIL::Module *module) { module->fixup_ports(); } +void prep_dff(RTLIL::Module *module) { + auto design = module->design; + log_assert(design); + + SigMap assign_map(module); + + typedef SigSpec clkdomain_t; + dict clk_to_mergeability; + + for (auto cell : module->selected_cells()) { + auto inst_module = design->module(cell->type); + if (!inst_module || !inst_module->attributes.count("\\abc9_flop") + || cell->get_bool_attribute("\\abc9_keep")) + continue; + + Wire *abc9_clock_wire = module->wire(stringf("%s.$abc9_clock", cell->name.c_str())); + if (abc9_clock_wire == NULL) + log_error("'%s$abc9_clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); + SigSpec abc9_clock = assign_map(abc9_clock_wire); + + clkdomain_t key(abc9_clock); + + auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1)); + auto r2 YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second)); + log_assert(r2.second); + + Wire *abc9_init_wire = module->wire(stringf("%s.$abc9_init", cell->name.c_str())); + if (abc9_init_wire == NULL) + log_error("'%s.$abc9_init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); + log_assert(GetSize(abc9_init_wire) == 1); + SigSpec abc9_init = assign_map(abc9_init_wire); + if (!abc9_init.is_fully_const()) + log_error("'%s.$abc9_init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); + r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const())); + log_assert(r2.second); + } +} + struct Abc9PrepPass : public Pass { Abc9PrepPass() : Pass("abc9_ops", "helper functions for ABC9") { } void help() YS_OVERRIDE @@ -111,6 +150,7 @@ struct Abc9PrepPass : public Pass { bool break_scc_mode = false; bool unbreak_scc_mode = false; + bool prep_dff_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -123,6 +163,10 @@ struct Abc9PrepPass : public Pass { unbreak_scc_mode = true; continue; } + if (arg == "-prep_dff") { + prep_dff_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -132,6 +176,8 @@ struct Abc9PrepPass : public Pass { break_scc(mod); if (unbreak_scc_mode) unbreak_scc(mod); + if (prep_dff_mode) + prep_dff(mod); } } } Abc9PrepPass; -- cgit v1.2.3 From b50de28c045e786f3140c95ab23cb2f426918093 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 18:00:49 -0800 Subject: Add abc9_ops -prep_holes --- passes/techmap/abc9_ops.cc | 314 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 312 insertions(+), 2 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 3e7e5ec7f..8eb935e1f 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -20,6 +20,7 @@ #include "kernel/register.h" #include "kernel/sigtools.h" +#include "kernel/utils.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -75,7 +76,8 @@ void break_scc(RTLIL::Module *module) module->fixup_ports(); } -void unbreak_scc(RTLIL::Module *module) { +void unbreak_scc(RTLIL::Module *module) +{ // Now 'unexpose' those wires by undoing // the expose operation -- remove them from PO/PI // and re-connecting them back together @@ -96,7 +98,8 @@ void unbreak_scc(RTLIL::Module *module) { module->fixup_ports(); } -void prep_dff(RTLIL::Module *module) { +void prep_dff(RTLIL::Module *module) +{ auto design = module->design; log_assert(design); @@ -134,6 +137,306 @@ void prep_dff(RTLIL::Module *module) { } } +void prep_holes(RTLIL::Module *module) +{ + auto design = module->design; + log_assert(design); + + SigMap sigmap(module); + + // TODO: Speed up toposort -- ultimately we care about + // box ordering, but not individual AIG cells + dict> bit_drivers, bit_users; + TopoSort toposort; + bool abc9_box_seen = false; + + for (auto cell : module->selected_cells()) { + if (cell->type == "$_NOT_") + { + SigBit A = sigmap(cell->getPort("\\A").as_bit()); + SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); + toposort.node(cell->name); + bit_users[A].insert(cell->name); + bit_drivers[Y].insert(cell->name); + continue; + } + + if (cell->type == "$_AND_") + { + SigBit A = sigmap(cell->getPort("\\A").as_bit()); + SigBit B = sigmap(cell->getPort("\\B").as_bit()); + SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); + toposort.node(cell->name); + bit_users[A].insert(cell->name); + bit_users[B].insert(cell->name); + bit_drivers[Y].insert(cell->name); + continue; + } + + if (cell->type == "$__ABC9_FF_") + continue; + + RTLIL::Module* inst_module = design->module(cell->type); + if (inst_module) { + if (!inst_module->attributes.count("\\abc9_box_id") || cell->get_bool_attribute("\\abc9_keep")) + continue; + + for (const auto &conn : cell->connections()) { + auto port_wire = inst_module->wire(conn.first); + // Ignore inout for the sake of topographical ordering + if (port_wire->port_input && !port_wire->port_output) + for (auto bit : sigmap(conn.second)) + bit_users[bit].insert(cell->name); + if (port_wire->port_output) + for (auto bit : sigmap(conn.second)) + bit_drivers[bit].insert(cell->name); + } + + abc9_box_seen = true; + + toposort.node(cell->name); + } + } + + if (!abc9_box_seen) + return; + + for (auto &it : bit_users) + if (bit_drivers.count(it.first)) + for (auto driver_cell : bit_drivers.at(it.first)) + for (auto user_cell : it.second) + toposort.edge(driver_cell, user_cell); + +#if 0 + toposort.analyze_loops = true; +#endif + bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); +#if 0 + unsigned i = 0; + for (auto &it : toposort.loops) { + log(" loop %d\n", i++); + for (auto cell_name : it) { + auto cell = module->cell(cell_name); + log_assert(cell); + log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str()); + } + } +#endif + log_assert(no_loops); + + vector box_list; + for (auto cell_name : toposort.sorted) { + RTLIL::Cell *cell = module->cell(cell_name); + log_assert(cell); + + RTLIL::Module* box_module = design->module(cell->type); + if (!box_module || !box_module->attributes.count("\\abc9_box_id") + || cell->get_bool_attribute("\\abc9_keep")) + continue; + + bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); + + // Fully pad all unused input connections of this box cell with S0 + // Fully pad all undriven output connections of this box cell with anonymous wires + // NB: Assume box_module->ports are sorted alphabetically + // (as RTLIL::Module::fixup_ports() would do) + for (const auto &port_name : box_module->ports) { + RTLIL::Wire* w = box_module->wire(port_name); + log_assert(w); + auto it = cell->connections_.find(port_name); + if (w->port_input) { + RTLIL::SigSpec rhs; + if (it != cell->connections_.end()) { + if (GetSize(it->second) < GetSize(w)) + it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second))); + rhs = it->second; + } + else { + rhs = RTLIL::SigSpec(State::S0, GetSize(w)); + cell->setPort(port_name, rhs); + } + } + if (w->port_output) { + RTLIL::SigSpec rhs; + auto it = cell->connections_.find(w->name); + if (it != cell->connections_.end()) { + if (GetSize(it->second) < GetSize(w)) + it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second))); + rhs = it->second; + } + else { + Wire *wire = module->addWire(NEW_ID, GetSize(w)); + if (blackbox) + wire->set_bool_attribute(ID(abc9_padding)); + rhs = wire; + cell->setPort(port_name, rhs); + } + } + } + + box_list.emplace_back(cell); + } + log_assert(!box_list.empty()); + + RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str())); + log_assert(holes_module); + + dict cell_cache; + + int port_id = 1; + for (auto cell : box_list) { + RTLIL::Module* orig_box_module = design->module(cell->type); + log_assert(orig_box_module); + IdString derived_name = orig_box_module->derive(design, cell->parameters); + RTLIL::Module* box_module = design->module(derived_name); + if (box_module->has_processes()) + Pass::call_on_module(design, box_module, "proc"); + + int box_inputs = 0; + auto r = cell_cache.insert(std::make_pair(derived_name, nullptr)); + Cell *holes_cell = r.first->second; + if (r.second && box_module->get_bool_attribute("\\whitebox")) { + holes_cell = holes_module->addCell(cell->name, cell->type); + holes_cell->parameters = cell->parameters; + r.first->second = holes_cell; + + // Since Module::derive() will create a new module, there + // is a chance that the ports will be alphabetically ordered + // again, which is a problem when carry-chains are involved. + // Inherit the port ordering from the original module here... + // (and set the port_id below, when iterating through those) + log_assert(GetSize(box_module->ports) == GetSize(orig_box_module->ports)); + box_module->ports = orig_box_module->ports; + } + + // NB: Assume box_module->ports are sorted alphabetically + // (as RTLIL::Module::fixup_ports() would do) + int box_port_id = 1; + for (const auto &port_name : box_module->ports) { + RTLIL::Wire *w = box_module->wire(port_name); + log_assert(w); + if (r.second) + w->port_id = box_port_id++; + RTLIL::Wire *holes_wire; + RTLIL::SigSpec port_sig; + if (w->port_input) + for (int i = 0; i < GetSize(w); i++) { + box_inputs++; + holes_wire = holes_module->wire(stringf("\\i%d", box_inputs)); + if (!holes_wire) { + holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs)); + holes_wire->port_input = true; + holes_wire->port_id = port_id++; + holes_module->ports.push_back(holes_wire->name); + } + if (holes_cell) + port_sig.append(holes_wire); + } + if (w->port_output) + for (int i = 0; i < GetSize(w); i++) { + if (GetSize(w) == 1) + holes_wire = holes_module->addWire(stringf("$abc%s.%s", cell->name.c_str(), log_id(w->name))); + else + holes_wire = holes_module->addWire(stringf("$abc%s.%s[%d]", cell->name.c_str(), log_id(w->name), i)); + holes_wire->port_output = true; + holes_wire->port_id = port_id++; + holes_module->ports.push_back(holes_wire->name); + if (holes_cell) + port_sig.append(holes_wire); + else + holes_module->connect(holes_wire, State::S0); + } + if (!port_sig.empty()) { + if (r.second) + holes_cell->setPort(w->name, port_sig); + else + holes_module->connect(holes_cell->getPort(w->name), port_sig); + } + } + + // For flops only, create an extra 1-bit input that drives a new wire + // called ".$abc9_currQ" that is used below + if (box_module->get_bool_attribute("\\abc9_flop")) { + log_assert(holes_cell); + + box_inputs++; + Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs)); + if (!holes_wire) { + holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs)); + holes_wire->port_input = true; + holes_wire->port_id = port_id++; + holes_module->ports.push_back(holes_wire->name); + } + Wire *w = holes_module->addWire(stringf("%s.$abc9_currQ", cell->name.c_str())); + holes_module->connect(w, holes_wire); + } + } + + log_push(); + + // NB: fixup_ports() will sort ports by name + //holes_module->fixup_ports(); + holes_module->check(); + + // Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger + // since boxes may contain parameters in which case `flatten` would have + // created a new $paramod ... + Pass::call_on_module(design, holes_module, "flatten -wb; techmap; aigmap"); + + dict replace; + for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { + auto cell = it->second; + if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", + "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { + SigBit D = cell->getPort("\\D"); + SigBit Q = cell->getPort("\\Q"); + // Remove the DFF cell from what needs to be a combinatorial box + it = holes_module->cells_.erase(it); + Wire *port; + if (GetSize(Q.wire) == 1) + port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); + else + port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset)); + log_assert(port); + // Prepare to replace "assign = DFF.Q;" with "assign = DFF.D;" + // in order to extract the combinatorial control logic that feeds the box + // (i.e. clock enable, synchronous reset, etc.) + replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,D))); + // Since `flatten` above would have created wires named ".Q", + // extract the pre-techmap cell name + auto pos = Q.wire->name.str().rfind("."); + log_assert(pos != std::string::npos); + IdString driver = Q.wire->name.substr(0, pos); + // And drive the signal that was previously driven by "DFF.Q" (typically + // used to implement clock-enable functionality) with the ".$abc9_currQ" + // wire (which itself is driven an input port) we inserted above + Wire *currQ = holes_module->wire(stringf("%s.$abc9_currQ", driver.c_str())); + log_assert(currQ); + holes_module->connect(Q, currQ); + continue; + } + else if (!cell->type.in("$_NOT_", "$_AND_")) + log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n"); + ++it; + } + + for (auto &conn : holes_module->connections_) { + auto it = replace.find(conn); + if (it != replace.end()) + conn = it->second; + } + + // Move into a new (temporary) design so that "clean" will only + // operate (and run checks on) this one module + RTLIL::Design *holes_design = new RTLIL::Design; + holes_design->add(holes_module); + Pass::call(holes_design, "opt -purge"); + holes_design->modules_.erase(holes_module->name); + holes_module->design = design; + + log_pop(); +} + struct Abc9PrepPass : public Pass { Abc9PrepPass() : Pass("abc9_ops", "helper functions for ABC9") { } void help() YS_OVERRIDE @@ -151,6 +454,7 @@ struct Abc9PrepPass : public Pass { bool break_scc_mode = false; bool unbreak_scc_mode = false; bool prep_dff_mode = false; + bool prep_holes_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -167,6 +471,10 @@ struct Abc9PrepPass : public Pass { prep_dff_mode = true; continue; } + if (arg == "-prep_holes") { + prep_holes_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -178,6 +486,8 @@ struct Abc9PrepPass : public Pass { unbreak_scc(mod); if (prep_dff_mode) prep_dff(mod); + if (prep_holes_mode) + prep_holes(mod); } } } Abc9PrepPass; -- cgit v1.2.3 From 0317a2b476f5ec78cab35b79a02d166c84c0f53e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 18:46:22 -0800 Subject: holes_module to be whitebox --- passes/techmap/abc9_ops.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 8eb935e1f..e65b16fc6 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -434,6 +434,8 @@ void prep_holes(RTLIL::Module *module) holes_design->modules_.erase(holes_module->name); holes_module->design = design; + holes_module->set_bool_attribute(ID::whitebox); + log_pop(); } @@ -480,6 +482,14 @@ struct Abc9PrepPass : public Pass { extra_args(args, argidx, design); for (auto mod : design->selected_modules()) { + if (mod->get_blackbox_attribute()) + continue; + + if (mod->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(mod)); + continue; + } + if (break_scc_mode) break_scc(mod); if (unbreak_scc_mode) -- cgit v1.2.3 From b42b64e8ed713b0e9810f18db7cafcf356e2b4f6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 19:23:54 -0800 Subject: Move Pass::call() out of abc9_ops into abc9 --- passes/techmap/abc9_ops.cc | 113 +++++++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 66 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index e65b16fc6..b52382972 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -135,6 +135,50 @@ void prep_dff(RTLIL::Module *module) r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const())); log_assert(r2.second); } + + RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str())); + log_assert(holes_module); + + dict replace; + for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { + auto cell = it->second; + if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", + "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { + SigBit D = cell->getPort("\\D"); + SigBit Q = cell->getPort("\\Q"); + // Remove the DFF cell from what needs to be a combinatorial box + it = holes_module->cells_.erase(it); + Wire *port; + if (GetSize(Q.wire) == 1) + port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); + else + port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset)); + log_assert(port); + // Prepare to replace "assign = DFF.Q;" with "assign = DFF.D;" + // in order to extract the combinatorial control logic that feeds the box + // (i.e. clock enable, synchronous reset, etc.) + replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,D))); + // Since `flatten` above would have created wires named ".Q", + // extract the pre-techmap cell name + auto pos = Q.wire->name.str().rfind("."); + log_assert(pos != std::string::npos); + IdString driver = Q.wire->name.substr(0, pos); + // And drive the signal that was previously driven by "DFF.Q" (typically + // used to implement clock-enable functionality) with the ".$abc9_currQ" + // wire (which itself is driven an input port) we inserted above + Wire *currQ = holes_module->wire(stringf("%s.$abc9_currQ", driver.c_str())); + log_assert(currQ); + holes_module->connect(Q, currQ); + } + else + ++it; + } + + for (auto &conn : holes_module->connections_) { + auto it = replace.find(conn); + if (it != replace.end()) + conn = it->second; + } } void prep_holes(RTLIL::Module *module) @@ -280,6 +324,7 @@ void prep_holes(RTLIL::Module *module) RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str())); log_assert(holes_module); + holes_module->set_bool_attribute("\\abc9_holes"); dict cell_cache; @@ -371,72 +416,6 @@ void prep_holes(RTLIL::Module *module) holes_module->connect(w, holes_wire); } } - - log_push(); - - // NB: fixup_ports() will sort ports by name - //holes_module->fixup_ports(); - holes_module->check(); - - // Cannot techmap/aigmap/check all lib_whitebox-es outside of write_xaiger - // since boxes may contain parameters in which case `flatten` would have - // created a new $paramod ... - Pass::call_on_module(design, holes_module, "flatten -wb; techmap; aigmap"); - - dict replace; - for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { - auto cell = it->second; - if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", - "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { - SigBit D = cell->getPort("\\D"); - SigBit Q = cell->getPort("\\Q"); - // Remove the DFF cell from what needs to be a combinatorial box - it = holes_module->cells_.erase(it); - Wire *port; - if (GetSize(Q.wire) == 1) - port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); - else - port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset)); - log_assert(port); - // Prepare to replace "assign = DFF.Q;" with "assign = DFF.D;" - // in order to extract the combinatorial control logic that feeds the box - // (i.e. clock enable, synchronous reset, etc.) - replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,D))); - // Since `flatten` above would have created wires named ".Q", - // extract the pre-techmap cell name - auto pos = Q.wire->name.str().rfind("."); - log_assert(pos != std::string::npos); - IdString driver = Q.wire->name.substr(0, pos); - // And drive the signal that was previously driven by "DFF.Q" (typically - // used to implement clock-enable functionality) with the ".$abc9_currQ" - // wire (which itself is driven an input port) we inserted above - Wire *currQ = holes_module->wire(stringf("%s.$abc9_currQ", driver.c_str())); - log_assert(currQ); - holes_module->connect(Q, currQ); - continue; - } - else if (!cell->type.in("$_NOT_", "$_AND_")) - log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n"); - ++it; - } - - for (auto &conn : holes_module->connections_) { - auto it = replace.find(conn); - if (it != replace.end()) - conn = it->second; - } - - // Move into a new (temporary) design so that "clean" will only - // operate (and run checks on) this one module - RTLIL::Design *holes_design = new RTLIL::Design; - holes_design->add(holes_module); - Pass::call(holes_design, "opt -purge"); - holes_design->modules_.erase(holes_module->name); - holes_module->design = design; - - holes_module->set_bool_attribute(ID::whitebox); - - log_pop(); } struct Abc9PrepPass : public Pass { @@ -484,6 +463,8 @@ struct Abc9PrepPass : public Pass { for (auto mod : design->selected_modules()) { if (mod->get_blackbox_attribute()) continue; + if (mod->get_bool_attribute("\\abc9_holes")) + continue; if (mod->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(mod)); -- cgit v1.2.3 From a367f703ea0633a4a6289415ae8a4545440ee705 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 22:56:19 -0800 Subject: Rename struct --- passes/techmap/abc9_ops.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index b52382972..271b76a39 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -418,8 +418,8 @@ void prep_holes(RTLIL::Module *module) } } -struct Abc9PrepPass : public Pass { - Abc9PrepPass() : Pass("abc9_ops", "helper functions for ABC9") { } +struct Abc9OpsPass : public Pass { + Abc9OpsPass() : Pass("abc9_ops", "helper functions for ABC9") { } void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -481,6 +481,6 @@ struct Abc9PrepPass : public Pass { prep_holes(mod); } } -} Abc9PrepPass; +} Abc9OpsPass; PRIVATE_NAMESPACE_END -- cgit v1.2.3 From f1bf44ae8f66e81b7de6a2ec47c4a9dffe7e6587 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 22:58:39 -0800 Subject: abc9_ops -prep_dff cope with lack of holes module --- passes/techmap/abc9_ops.cc | 76 +++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 38 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 271b76a39..019868adb 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -137,47 +137,47 @@ void prep_dff(RTLIL::Module *module) } RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str())); - log_assert(holes_module); - - dict replace; - for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { - auto cell = it->second; - if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", - "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { - SigBit D = cell->getPort("\\D"); - SigBit Q = cell->getPort("\\Q"); - // Remove the DFF cell from what needs to be a combinatorial box - it = holes_module->cells_.erase(it); - Wire *port; - if (GetSize(Q.wire) == 1) - port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); + if (holes_module) { + dict replace; + for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { + auto cell = it->second; + if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", + "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { + SigBit D = cell->getPort("\\D"); + SigBit Q = cell->getPort("\\Q"); + // Remove the DFF cell from what needs to be a combinatorial box + it = holes_module->cells_.erase(it); + Wire *port; + if (GetSize(Q.wire) == 1) + port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); + else + port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset)); + log_assert(port); + // Prepare to replace "assign = DFF.Q;" with "assign = DFF.D;" + // in order to extract the combinatorial control logic that feeds the box + // (i.e. clock enable, synchronous reset, etc.) + replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,D))); + // Since `flatten` above would have created wires named ".Q", + // extract the pre-techmap cell name + auto pos = Q.wire->name.str().rfind("."); + log_assert(pos != std::string::npos); + IdString driver = Q.wire->name.substr(0, pos); + // And drive the signal that was previously driven by "DFF.Q" (typically + // used to implement clock-enable functionality) with the ".$abc9_currQ" + // wire (which itself is driven an input port) we inserted above + Wire *currQ = holes_module->wire(stringf("%s.$abc9_currQ", driver.c_str())); + log_assert(currQ); + holes_module->connect(Q, currQ); + } else - port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset)); - log_assert(port); - // Prepare to replace "assign = DFF.Q;" with "assign = DFF.D;" - // in order to extract the combinatorial control logic that feeds the box - // (i.e. clock enable, synchronous reset, etc.) - replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,D))); - // Since `flatten` above would have created wires named ".Q", - // extract the pre-techmap cell name - auto pos = Q.wire->name.str().rfind("."); - log_assert(pos != std::string::npos); - IdString driver = Q.wire->name.substr(0, pos); - // And drive the signal that was previously driven by "DFF.Q" (typically - // used to implement clock-enable functionality) with the ".$abc9_currQ" - // wire (which itself is driven an input port) we inserted above - Wire *currQ = holes_module->wire(stringf("%s.$abc9_currQ", driver.c_str())); - log_assert(currQ); - holes_module->connect(Q, currQ); + ++it; } - else - ++it; - } - for (auto &conn : holes_module->connections_) { - auto it = replace.find(conn); - if (it != replace.end()) - conn = it->second; + for (auto &conn : holes_module->connections_) { + auto it = replace.find(conn); + if (it != replace.end()) + conn = it->second; + } } } -- cgit v1.2.3 From a050f9c80887f9962c326566c1f351c991e0c8b0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 2 Jan 2020 16:14:04 -0800 Subject: Remove a few log_{push,pop}() --- passes/techmap/abc9_ops.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index dcb8a8a78..a4059bd4d 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -436,7 +436,6 @@ struct Abc9OpsPass : public Pass { void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); - log_push(); bool break_scc_mode = false; bool unbreak_scc_mode = false; -- cgit v1.2.3 From bb70915fb8adcd7ede7719174dea3bc9c04e613e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 Jan 2020 13:21:56 -0800 Subject: WIP --- passes/techmap/abc9_ops.cc | 48 +++++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 13 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index a4059bd4d..c671553e2 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -288,8 +288,6 @@ void prep_holes(RTLIL::Module *module) // Fully pad all unused input connections of this box cell with S0 // Fully pad all undriven output connections of this box cell with anonymous wires - // NB: Assume box_module->ports are sorted alphabetically - // (as RTLIL::Module::fixup_ports() would do) for (const auto &port_name : box_module->ports) { RTLIL::Wire* w = box_module->wire(port_name); log_assert(w); @@ -333,6 +331,7 @@ void prep_holes(RTLIL::Module *module) holes_module->set_bool_attribute("\\abc9_holes"); dict cell_cache; + dict> box_ports; int port_id = 1; for (auto cell : box_list) { @@ -350,24 +349,47 @@ void prep_holes(RTLIL::Module *module) holes_cell = holes_module->addCell(cell->name, cell->type); holes_cell->parameters = cell->parameters; r.first->second = holes_cell; + } - // Since Module::derive() will create a new module, there - // is a chance that the ports will be alphabetically ordered - // again, which is a problem when carry-chains are involved. - // Inherit the port ordering from the original module here... - // (and set the port_id below, when iterating through those) - log_assert(GetSize(box_module->ports) == GetSize(orig_box_module->ports)); - box_module->ports = orig_box_module->ports; + auto r2 = box_ports.insert(cell->type); + if (r2.second) { + // Make carry in the last PI, and carry out the last PO + // since ABC requires it this way + IdString carry_in, carry_out; + for (const auto &port_name : box_module->ports) { + auto w = box_module->wire(port_name); + log_assert(w); + if (w->get_bool_attribute("\\abc9_carry")) { + if (w->port_input) { + if (carry_in != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(box_module)); + carry_in = port_name; + } + if (w->port_output) { + if (carry_out != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(box_module)); + carry_out = port_name; + } + } + else + r2.first->second.push_back(port_name); + } + + if (carry_in != IdString() && carry_out == IdString()) + log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(box_module)); + if (carry_in == IdString() && carry_out != IdString()) + log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(box_module)); + if (carry_in != IdString()) { + r2.first->second.push_back(carry_in); + r2.first->second.push_back(carry_out); + } } // NB: Assume box_module->ports are sorted alphabetically // (as RTLIL::Module::fixup_ports() would do) - int box_port_id = 1; - for (const auto &port_name : box_module->ports) { + for (const auto &port_name : box_ports.at(cell->type)) { RTLIL::Wire *w = box_module->wire(port_name); log_assert(w); - if (r.second) - w->port_id = box_port_id++; RTLIL::Wire *holes_wire; RTLIL::SigSpec port_sig; if (w->port_input) -- cgit v1.2.3 From 559f3379e852f304a0255afcc37714b9d0da59d9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 Jan 2020 14:37:58 -0800 Subject: Preserve topo ordering from -prep_holes to write_xaiger --- passes/techmap/abc9_ops.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index c671553e2..bcf622dba 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -322,6 +322,7 @@ void prep_holes(RTLIL::Module *module) } } + cell->attributes["\\abc9_box_order"] = box_list.size(); box_list.emplace_back(cell); } log_assert(!box_list.empty()); -- cgit v1.2.3 From a819656972dd44c479422fa688874926d6239a95 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 Jan 2020 14:59:55 -0800 Subject: WIP --- passes/techmap/abc9_ops.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index bcf622dba..632f2bc8a 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -386,8 +386,6 @@ void prep_holes(RTLIL::Module *module) } } - // NB: Assume box_module->ports are sorted alphabetically - // (as RTLIL::Module::fixup_ports() would do) for (const auto &port_name : box_ports.at(cell->type)) { RTLIL::Wire *w = box_module->wire(port_name); log_assert(w); -- cgit v1.2.3 From 930f03e8830ed8a8023ff88207b97e757ae8496c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 3 Jan 2020 15:38:18 -0800 Subject: Call -prep_holes before aigmap; fix topo ordering --- passes/techmap/abc9_ops.cc | 55 +++++++++++++--------------------------------- 1 file changed, 15 insertions(+), 40 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 632f2bc8a..2f07de8d4 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -21,6 +21,7 @@ #include "kernel/register.h" #include "kernel/sigtools.h" #include "kernel/utils.h" +#include "kernel/celltypes.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -194,58 +195,32 @@ void prep_holes(RTLIL::Module *module) SigMap sigmap(module); - // TODO: Speed up toposort -- ultimately we care about - // box ordering, but not individual AIG cells dict> bit_drivers, bit_users; TopoSort toposort; bool abc9_box_seen = false; for (auto cell : module->selected_cells()) { - if (cell->type == "$_NOT_") - { - SigBit A = sigmap(cell->getPort("\\A").as_bit()); - SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); - toposort.node(cell->name); - bit_users[A].insert(cell->name); - bit_drivers[Y].insert(cell->name); - continue; - } - - if (cell->type == "$_AND_") - { - SigBit A = sigmap(cell->getPort("\\A").as_bit()); - SigBit B = sigmap(cell->getPort("\\B").as_bit()); - SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); - toposort.node(cell->name); - bit_users[A].insert(cell->name); - bit_users[B].insert(cell->name); - bit_drivers[Y].insert(cell->name); - continue; - } - if (cell->type == "$__ABC9_FF_") continue; - RTLIL::Module* inst_module = design->module(cell->type); - if (inst_module) { - if (!inst_module->attributes.count("\\abc9_box_id") || cell->get_bool_attribute("\\abc9_keep")) - continue; + auto inst_module = module->design->module(cell->type); + bool abc9_box = inst_module && inst_module->attributes.count("\\abc9_box_id") && !cell->get_bool_attribute("\\abc9_keep"); + abc9_box_seen = abc9_box_seen || abc9_box; - for (const auto &conn : cell->connections()) { - auto port_wire = inst_module->wire(conn.first); - // Ignore inout for the sake of topographical ordering - if (port_wire->port_input && !port_wire->port_output) - for (auto bit : sigmap(conn.second)) - bit_users[bit].insert(cell->name); - if (port_wire->port_output) - for (auto bit : sigmap(conn.second)) - bit_drivers[bit].insert(cell->name); - } + if (!abc9_box && !yosys_celltypes.cell_known(cell->type)) + continue; - abc9_box_seen = true; + for (auto conn : cell->connections()) { + if (cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) + bit_users[bit].insert(cell->name); - toposort.node(cell->name); + if (cell->output(conn.first)) + for (auto bit : sigmap(conn.second)) + bit_drivers[bit].insert(cell->name); } + + toposort.node(cell->name); } if (!abc9_box_seen) -- cgit v1.2.3 From 6556a1347ab56b022a599835071c6b3059787462 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 4 Jan 2020 09:17:01 -0800 Subject: Fix when -dff not given --- passes/techmap/abc9_ops.cc | 85 +++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 42 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 2f07de8d4..ab5aa9f8d 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -109,39 +109,31 @@ void prep_dff(RTLIL::Module *module) typedef SigSpec clkdomain_t; dict clk_to_mergeability; - //if (dff_mode) - for (auto cell : module->selected_cells()) { - if (cell->type != "$__ABC9_FF_") - continue; + for (auto cell : module->selected_cells()) { + if (cell->type != "$__ABC9_FF_") + continue; - Wire *abc9_clock_wire = module->wire(stringf("%s.clock", cell->name.c_str())); - if (abc9_clock_wire == NULL) - log_error("'%s.clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); - SigSpec abc9_clock = assign_map(abc9_clock_wire); - - clkdomain_t key(abc9_clock); - - auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1)); - auto r2 YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second)); - log_assert(r2.second); - - Wire *abc9_init_wire = module->wire(stringf("%s.init", cell->name.c_str())); - if (abc9_init_wire == NULL) - log_error("'%s.init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); - log_assert(GetSize(abc9_init_wire) == 1); - SigSpec abc9_init = assign_map(abc9_init_wire); - if (!abc9_init.is_fully_const()) - log_error("'%s.init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); - r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const())); - log_assert(r2.second); - } - //else - // for (auto cell : module->selected_cells()) { - // auto inst_module = design->module(cell->type); - // if (!inst_module || !inst_module->get_bool_attribute("\\abc9_flop")) - // continue; - // cell->set_bool_attribute("\\abc9_keep"); - // } + Wire *abc9_clock_wire = module->wire(stringf("%s.clock", cell->name.c_str())); + if (abc9_clock_wire == NULL) + log_error("'%s.clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); + SigSpec abc9_clock = assign_map(abc9_clock_wire); + + clkdomain_t key(abc9_clock); + + auto r = clk_to_mergeability.insert(std::make_pair(abc9_clock, clk_to_mergeability.size() + 1)); + auto r2 YS_ATTRIBUTE(unused) = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), r.first->second)); + log_assert(r2.second); + + Wire *abc9_init_wire = module->wire(stringf("%s.init", cell->name.c_str())); + if (abc9_init_wire == NULL) + log_error("'%s.init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); + log_assert(GetSize(abc9_init_wire) == 1); + SigSpec abc9_init = assign_map(abc9_init_wire); + if (!abc9_init.is_fully_const()) + log_error("'%s.init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module)); + r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const())); + log_assert(r2.second); + } RTLIL::Module *holes_module = design->module(stringf("%s$holes", module->name.c_str())); if (holes_module) { @@ -188,7 +180,7 @@ void prep_dff(RTLIL::Module *module) } } -void prep_holes(RTLIL::Module *module) +void prep_holes(RTLIL::Module *module, bool dff) { auto design = module->design; log_assert(design); @@ -204,10 +196,15 @@ void prep_holes(RTLIL::Module *module) continue; auto inst_module = module->design->module(cell->type); - bool abc9_box = inst_module && inst_module->attributes.count("\\abc9_box_id") && !cell->get_bool_attribute("\\abc9_keep"); - abc9_box_seen = abc9_box_seen || abc9_box; - - if (!abc9_box && !yosys_celltypes.cell_known(cell->type)) + bool abc9_box = inst_module && inst_module->attributes.count("\\abc9_box_id"); + bool abc9_flop = false; + if (abc9_box) { + abc9_flop = inst_module->get_bool_attribute("\\abc9_flop"); + if (abc9_flop && !dff) + continue; + abc9_box_seen = abc9_box; + } + else if (!yosys_celltypes.cell_known(cell->type)) continue; for (auto conn : cell->connections()) { @@ -215,7 +212,7 @@ void prep_holes(RTLIL::Module *module) for (auto bit : sigmap(conn.second)) bit_users[bit].insert(cell->name); - if (cell->output(conn.first)) + if (cell->output(conn.first) && !abc9_flop) for (auto bit : sigmap(conn.second)) bit_drivers[bit].insert(cell->name); } @@ -255,8 +252,7 @@ void prep_holes(RTLIL::Module *module) log_assert(cell); RTLIL::Module* box_module = design->module(cell->type); - if (!box_module || !box_module->attributes.count("\\abc9_box_id") - || cell->get_bool_attribute("\\abc9_keep")) + if (!box_module || !box_module->attributes.count("\\abc9_box_id")) continue; bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); @@ -297,7 +293,7 @@ void prep_holes(RTLIL::Module *module) } } - cell->attributes["\\abc9_box_order"] = box_list.size(); + cell->attributes["\\abc9_box_seq"] = box_list.size(); box_list.emplace_back(cell); } log_assert(!box_list.empty()); @@ -437,6 +433,7 @@ struct Abc9OpsPass : public Pass { bool unbreak_scc_mode = false; bool prep_dff_mode = false; bool prep_holes_mode = false; + bool dff_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -457,6 +454,10 @@ struct Abc9OpsPass : public Pass { prep_holes_mode = true; continue; } + if (arg == "-dff") { + dff_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -479,7 +480,7 @@ struct Abc9OpsPass : public Pass { if (prep_dff_mode) prep_dff(mod); if (prep_holes_mode) - prep_holes(mod); + prep_holes(mod, dff_mode); } } } Abc9OpsPass; -- cgit v1.2.3 From b5f60e055d07579a2d4f23fc053ca030f103f377 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 5 Jan 2020 10:20:24 -0800 Subject: write_xaiger to pad, not abc9_ops -prep_holes --- passes/techmap/abc9_ops.cc | 39 --------------------------------------- 1 file changed, 39 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index ab5aa9f8d..730431ebf 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -254,45 +254,6 @@ void prep_holes(RTLIL::Module *module, bool dff) RTLIL::Module* box_module = design->module(cell->type); if (!box_module || !box_module->attributes.count("\\abc9_box_id")) continue; - - bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); - - // Fully pad all unused input connections of this box cell with S0 - // Fully pad all undriven output connections of this box cell with anonymous wires - for (const auto &port_name : box_module->ports) { - RTLIL::Wire* w = box_module->wire(port_name); - log_assert(w); - auto it = cell->connections_.find(port_name); - if (w->port_input) { - RTLIL::SigSpec rhs; - if (it != cell->connections_.end()) { - if (GetSize(it->second) < GetSize(w)) - it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second))); - rhs = it->second; - } - else { - rhs = RTLIL::SigSpec(State::S0, GetSize(w)); - cell->setPort(port_name, rhs); - } - } - if (w->port_output) { - RTLIL::SigSpec rhs; - auto it = cell->connections_.find(w->name); - if (it != cell->connections_.end()) { - if (GetSize(it->second) < GetSize(w)) - it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second))); - rhs = it->second; - } - else { - Wire *wire = module->addWire(NEW_ID, GetSize(w)); - if (blackbox) - wire->set_bool_attribute(ID(abc9_padding)); - rhs = wire; - cell->setPort(port_name, rhs); - } - } - } - cell->attributes["\\abc9_box_seq"] = box_list.size(); box_list.emplace_back(cell); } -- cgit v1.2.3 From aa58472a292c2cd3c0f2ba669c9dcfd608d8dc5f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 6 Jan 2020 13:34:45 -0800 Subject: Revert "write_xaiger to pad, not abc9_ops -prep_holes" This reverts commit b5f60e055d07579a2d4f23fc053ca030f103f377. --- passes/techmap/abc9_ops.cc | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 730431ebf..ab5aa9f8d 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -254,6 +254,45 @@ void prep_holes(RTLIL::Module *module, bool dff) RTLIL::Module* box_module = design->module(cell->type); if (!box_module || !box_module->attributes.count("\\abc9_box_id")) continue; + + bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); + + // Fully pad all unused input connections of this box cell with S0 + // Fully pad all undriven output connections of this box cell with anonymous wires + for (const auto &port_name : box_module->ports) { + RTLIL::Wire* w = box_module->wire(port_name); + log_assert(w); + auto it = cell->connections_.find(port_name); + if (w->port_input) { + RTLIL::SigSpec rhs; + if (it != cell->connections_.end()) { + if (GetSize(it->second) < GetSize(w)) + it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second))); + rhs = it->second; + } + else { + rhs = RTLIL::SigSpec(State::S0, GetSize(w)); + cell->setPort(port_name, rhs); + } + } + if (w->port_output) { + RTLIL::SigSpec rhs; + auto it = cell->connections_.find(w->name); + if (it != cell->connections_.end()) { + if (GetSize(it->second) < GetSize(w)) + it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second))); + rhs = it->second; + } + else { + Wire *wire = module->addWire(NEW_ID, GetSize(w)); + if (blackbox) + wire->set_bool_attribute(ID(abc9_padding)); + rhs = wire; + cell->setPort(port_name, rhs); + } + } + } + cell->attributes["\\abc9_box_seq"] = box_list.size(); box_list.emplace_back(cell); } -- cgit v1.2.3 From cf3a13746d27fee141700e2c6ea40d528267190f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 6 Jan 2020 15:52:59 -0800 Subject: Add abc9_ops -reintegrate; moved out from now abc9_exe --- passes/techmap/abc9_ops.cc | 286 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 284 insertions(+), 2 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index ab5aa9f8d..c8d91a6ac 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -26,6 +26,13 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +int map_autoidx; + +inline std::string remap_name(RTLIL::IdString abc9_name) +{ + return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); +} + void break_scc(RTLIL::Module *module) { // For every unique SCC found, (arbitrarily) find the first @@ -416,6 +423,276 @@ void prep_holes(RTLIL::Module *module, bool dff) } } +void reintegrate(RTLIL::Module *module) +{ + auto design = module->design; + log_assert(design); + + map_autoidx = autoidx++; + + RTLIL::Module *mapped_mod = design->module(stringf("%s$abc9", module->name.c_str())); + if (mapped_mod == NULL) + log_error("ABC output file does not contain a module `%s$abc'.\n", log_id(module)); + + for (auto w : mapped_mod->wires()) + module->addWire(remap_name(w->name), GetSize(w)); + + for (auto it = module->cells_.begin(); it != module->cells_.end(); ) + if (it->second->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) + it = module->cells_.erase(it); + else + ++it; + + dict> bit_drivers, bit_users; + TopoSort toposort; + dict not2drivers; + dict> bit2sinks; + + std::map cell_stats; + for (auto mapped_cell : mapped_mod->cells()) + { + toposort.node(mapped_cell->name); + + RTLIL::Cell *cell = nullptr; + if (mapped_cell->type == ID($_NOT_)) { + RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A); + RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y); + bit_users[a_bit].insert(mapped_cell->name); + bit_drivers[y_bit].insert(mapped_cell->name); + + if (!a_bit.wire) { + mapped_cell->setPort(ID::Y, module->addWire(NEW_ID)); + RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); + log_assert(wire); + module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); + } + else { + RTLIL::Cell* driver_lut = nullptr; + // ABC can return NOT gates that drive POs + if (!a_bit.wire->port_input) { + // If it's not a NOT gate that that comes from a PI directly, + // find the driver LUT and clone that to guarantee that we won't + // increase the max logic depth + // (TODO: Optimise by not cloning unless will increase depth) + RTLIL::IdString driver_name; + if (GetSize(a_bit.wire) == 1) + driver_name = stringf("%s$lut", a_bit.wire->name.c_str()); + else + driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset); + driver_lut = mapped_mod->cell(driver_name); + } + + if (!driver_lut) { + // If a driver couldn't be found (could be from PI or box CI) + // then implement using a LUT + cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())), + RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), + RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), + RTLIL::Const::from_string("01")); + bit2sinks[cell->getPort(ID::A)].push_back(cell); + cell_stats[ID($lut)]++; + } + else + not2drivers[mapped_cell] = driver_lut; + } + continue; + } + cell_stats[mapped_cell->type]++; + + RTLIL::Cell *existing_cell = nullptr; + if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) { + if (mapped_cell->type == ID($lut) && + GetSize(mapped_cell->getPort(ID::A)) == 1 && + mapped_cell->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { + SigSpec my_a = module->wires_.at(remap_name(mapped_cell->getPort(ID::A).as_wire()->name)); + SigSpec my_y = module->wires_.at(remap_name(mapped_cell->getPort(ID::Y).as_wire()->name)); + module->connect(my_y, my_a); + log_abort(); + continue; + } + cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); + } + else { + existing_cell = module->cell(mapped_cell->name); + log_assert(existing_cell); + cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); + } + + RTLIL::Module* box_module = design->module(mapped_cell->type); + auto abc9_flop = box_module && box_module->attributes.count("\\abc9_flop"); + for (auto &mapped_conn : mapped_cell->connections()) { + RTLIL::SigSpec newsig; + for (auto c : mapped_conn.second.chunks()) { + if (c.width == 0) + continue; + //log_assert(c.width == 1); + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + newsig.append(c); + } + if (existing_cell) { + auto it = existing_cell->connections_.find(mapped_conn.first); + if (it == existing_cell->connections_.end()) + continue; + log_assert(GetSize(newsig) >= GetSize(it->second)); + newsig = newsig.extract(0, GetSize(it->second)); + } + cell->setPort(mapped_conn.first, newsig); + + if (abc9_flop) + continue; + + if (cell->input(mapped_conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : mapped_conn.second) + bit_users[i].insert(mapped_cell->name); + } + if (cell->output(mapped_conn.first)) + for (auto i : mapped_conn.second) + bit_drivers[i].insert(mapped_cell->name); + } + + if (existing_cell) { + cell->parameters = existing_cell->parameters; + cell->attributes = existing_cell->attributes; + if (cell->attributes.erase("\\abc9_box_seq")) { + module->swap_names(cell, existing_cell); + module->remove(existing_cell); + } + } + else { + cell->parameters = mapped_cell->parameters; + cell->attributes = mapped_cell->attributes; + } + } + + // Copy connections (and rename) from mapped_mod to module + for (auto conn : mapped_mod->connections()) { + if (!conn.first.is_fully_const()) { + auto chunks = conn.first.chunks(); + for (auto &c : chunks) + c.wire = module->wires_.at(remap_name(c.wire->name)); + conn.first = std::move(chunks); + } + if (!conn.second.is_fully_const()) { + auto chunks = conn.second.chunks(); + for (auto &c : chunks) + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + conn.second = std::move(chunks); + } + module->connect(conn); + } + + for (auto &it : cell_stats) + log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); + int in_wires = 0, out_wires = 0; + + // Stitch in mapped_mod's inputs/outputs into module + for (auto port : mapped_mod->ports) { + RTLIL::Wire *w = mapped_mod->wire(port); + RTLIL::Wire *wire = module->wire(port); + log_assert(wire); + RTLIL::Wire *remap_wire = module->wire(remap_name(port)); + RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); + log_assert(GetSize(signal) >= GetSize(remap_wire)); + + RTLIL::SigSig conn; + if (w->port_output) { + conn.first = signal; + conn.second = remap_wire; + out_wires++; + module->connect(conn); + } + else if (w->port_input) { + conn.first = remap_wire; + conn.second = signal; + in_wires++; + module->connect(conn); + } + } + + for (auto &it : bit_users) + if (bit_drivers.count(it.first)) + for (auto driver_cell : bit_drivers.at(it.first)) + for (auto user_cell : it.second) + toposort.edge(driver_cell, user_cell); + bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); + log_assert(no_loops); + + for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { + RTLIL::Cell *not_cell = mapped_mod->cell(*ii); + log_assert(not_cell); + if (not_cell->type != ID($_NOT_)) + continue; + auto it = not2drivers.find(not_cell); + if (it == not2drivers.end()) + continue; + RTLIL::Cell *driver_lut = it->second; + RTLIL::SigBit a_bit = not_cell->getPort(ID::A); + RTLIL::SigBit y_bit = not_cell->getPort(ID::Y); + RTLIL::Const driver_mask; + + a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name)); + y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name)); + + auto jt = bit2sinks.find(a_bit); + if (jt == bit2sinks.end()) + goto clone_lut; + + for (auto sink_cell : jt->second) + if (sink_cell->type != ID($lut)) + goto clone_lut; + + // Push downstream LUTs past inverter + for (auto sink_cell : jt->second) { + SigSpec A = sink_cell->getPort(ID::A); + RTLIL::Const mask = sink_cell->getParam(ID(LUT)); + int index = 0; + for (; index < GetSize(A); index++) + if (A[index] == a_bit) + break; + log_assert(index < GetSize(A)); + int i = 0; + while (i < GetSize(mask)) { + for (int j = 0; j < (1 << index); j++) + std::swap(mask[i+j], mask[i+j+(1 << index)]); + i += 1 << (index+1); + } + A[index] = y_bit; + sink_cell->setPort(ID::A, A); + sink_cell->setParam(ID(LUT), mask); + } + + // Since we have rewritten all sinks (which we know + // to be only LUTs) to be after the inverter, we can + // go ahead and clone the LUT with the expectation + // that the original driving LUT will become dangling + // and get cleaned away +clone_lut: + driver_mask = driver_lut->getParam(ID(LUT)); + for (auto &b : driver_mask.bits) { + if (b == RTLIL::State::S0) b = RTLIL::State::S1; + else if (b == RTLIL::State::S1) b = RTLIL::State::S0; + } + auto cell = module->addLut(NEW_ID, + driver_lut->getPort(ID::A), + y_bit, + driver_mask); + for (auto &bit : cell->connections_.at(ID::A)) { + bit.wire = module->wires_.at(remap_name(bit.wire->name)); + bit2sinks[bit].push_back(cell); + } + } + + //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); + log("ABC RESULTS: input signals: %8d\n", in_wires); + log("ABC RESULTS: output signals: %8d\n", out_wires); + + design->remove(mapped_mod); +} + struct Abc9OpsPass : public Pass { Abc9OpsPass() : Pass("abc9_ops", "helper functions for ABC9") { } void help() YS_OVERRIDE @@ -433,6 +710,7 @@ struct Abc9OpsPass : public Pass { bool unbreak_scc_mode = false; bool prep_dff_mode = false; bool prep_holes_mode = false; + bool reintegrate_mode = false; bool dff_mode = false; size_t argidx; @@ -454,6 +732,10 @@ struct Abc9OpsPass : public Pass { prep_holes_mode = true; continue; } + if (arg == "-reintegrate") { + reintegrate_mode = true; + continue; + } if (arg == "-dff") { dff_mode = true; continue; @@ -463,8 +745,6 @@ struct Abc9OpsPass : public Pass { extra_args(args, argidx, design); for (auto mod : design->selected_modules()) { - if (mod->get_blackbox_attribute()) - continue; if (mod->get_bool_attribute("\\abc9_holes")) continue; @@ -481,6 +761,8 @@ struct Abc9OpsPass : public Pass { prep_dff(mod); if (prep_holes_mode) prep_holes(mod, dff_mode); + if (reintegrate_mode) + reintegrate(mod); } } } Abc9OpsPass; -- cgit v1.2.3 From 6e12ba218be1beaa6da712ebf96ff08593793967 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 7 Jan 2020 09:32:58 -0800 Subject: Fix tabs and cleanup --- passes/techmap/abc9_ops.cc | 76 +++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 38 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index c8d91a6ac..69239c93d 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -521,49 +521,49 @@ void reintegrate(RTLIL::Module *module) RTLIL::Module* box_module = design->module(mapped_cell->type); auto abc9_flop = box_module && box_module->attributes.count("\\abc9_flop"); for (auto &mapped_conn : mapped_cell->connections()) { - RTLIL::SigSpec newsig; - for (auto c : mapped_conn.second.chunks()) { - if (c.width == 0) - continue; - //log_assert(c.width == 1); - if (c.wire) - c.wire = module->wires_.at(remap_name(c.wire->name)); - newsig.append(c); - } - if (existing_cell) { - auto it = existing_cell->connections_.find(mapped_conn.first); - if (it == existing_cell->connections_.end()) - continue; - log_assert(GetSize(newsig) >= GetSize(it->second)); - newsig = newsig.extract(0, GetSize(it->second)); - } - cell->setPort(mapped_conn.first, newsig); - - if (abc9_flop) - continue; + RTLIL::SigSpec newsig; + for (auto c : mapped_conn.second.chunks()) { + if (c.width == 0) + continue; + //log_assert(c.width == 1); + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + newsig.append(c); + } + if (existing_cell) { + auto it = existing_cell->connections_.find(mapped_conn.first); + if (it == existing_cell->connections_.end()) + continue; + log_assert(GetSize(newsig) >= GetSize(it->second)); + newsig = newsig.extract(0, GetSize(it->second)); + } + cell->setPort(mapped_conn.first, newsig); - if (cell->input(mapped_conn.first)) { - for (auto i : newsig) - bit2sinks[i].push_back(cell); - for (auto i : mapped_conn.second) - bit_users[i].insert(mapped_cell->name); - } - if (cell->output(mapped_conn.first)) - for (auto i : mapped_conn.second) - bit_drivers[i].insert(mapped_cell->name); + if (abc9_flop) + continue; + + if (cell->input(mapped_conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : mapped_conn.second) + bit_users[i].insert(mapped_cell->name); + } + if (cell->output(mapped_conn.first)) + for (auto i : mapped_conn.second) + bit_drivers[i].insert(mapped_cell->name); } if (existing_cell) { - cell->parameters = existing_cell->parameters; - cell->attributes = existing_cell->attributes; - if (cell->attributes.erase("\\abc9_box_seq")) { - module->swap_names(cell, existing_cell); - module->remove(existing_cell); - } + cell->parameters = existing_cell->parameters; + cell->attributes = existing_cell->attributes; + if (cell->attributes.erase("\\abc9_box_seq")) { + module->swap_names(cell, existing_cell); + module->remove(existing_cell); + } } else { - cell->parameters = mapped_cell->parameters; - cell->attributes = mapped_cell->attributes; + cell->parameters = mapped_cell->parameters; + cell->attributes = mapped_cell->attributes; } } @@ -595,7 +595,7 @@ void reintegrate(RTLIL::Module *module) RTLIL::Wire *wire = module->wire(port); log_assert(wire); RTLIL::Wire *remap_wire = module->wire(remap_name(port)); - RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); + RTLIL::SigSpec signal(wire, 0, GetSize(remap_wire)); log_assert(GetSize(signal) >= GetSize(remap_wire)); RTLIL::SigSig conn; -- cgit v1.2.3 From dc3b21c1c050416aae443231729c8f4e4faf93ab Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 7 Jan 2020 09:48:57 -0800 Subject: abc9_ops -reintegrate: process box connections --- passes/techmap/abc9_ops.cc | 161 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 134 insertions(+), 27 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 69239c93d..721a33f09 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -437,6 +437,57 @@ void reintegrate(RTLIL::Module *module) for (auto w : mapped_mod->wires()) module->addWire(remap_name(w->name), GetSize(w)); + dict box_lookup; + dict> box_ports; + + for (auto m : design->modules()) { + auto it = m->attributes.find(ID(abc9_box_id)); + if (it == m->attributes.end()) + continue; + if (m->name.begins_with("$paramod")) + continue; + auto id = it->second.as_int(); + auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); + if (!r.second) + log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", + log_id(m), id, log_id(r.first->second)); + log_assert(r.second); + + auto r2 = box_ports.insert(m->name); + if (r2.second) { + // Make carry in the last PI, and carry out the last PO + // since ABC requires it this way + IdString carry_in, carry_out; + for (const auto &port_name : m->ports) { + auto w = m->wire(port_name); + log_assert(w); + if (w->get_bool_attribute("\\abc9_carry")) { + if (w->port_input) { + if (carry_in != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(m)); + carry_in = port_name; + } + if (w->port_output) { + if (carry_out != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(m)); + carry_out = port_name; + } + } + else + r2.first->second.push_back(port_name); + } + + if (carry_in != IdString() && carry_out == IdString()) + log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(m)); + if (carry_in == IdString() && carry_out != IdString()) + log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); + if (carry_in != IdString()) { + r2.first->second.push_back(carry_in); + r2.first->second.push_back(carry_out); + } + } + } + for (auto it = module->cells_.begin(); it != module->cells_.end(); ) if (it->second->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) it = module->cells_.erase(it); @@ -515,42 +566,98 @@ void reintegrate(RTLIL::Module *module) else { existing_cell = module->cell(mapped_cell->name); log_assert(existing_cell); + + if (mapped_cell->type.begins_with("$__boxid")) { + auto type = box_lookup.at(mapped_cell->type, IdString()); + if (type == IdString()) + log_error("No module with abc9_box_id = %s found.\n", mapped_cell->type.c_str() + strlen("$__boxid")); + mapped_cell->type = type; + } cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); } - RTLIL::Module* box_module = design->module(mapped_cell->type); - auto abc9_flop = box_module && box_module->attributes.count("\\abc9_flop"); - for (auto &mapped_conn : mapped_cell->connections()) { - RTLIL::SigSpec newsig; - for (auto c : mapped_conn.second.chunks()) { - if (c.width == 0) - continue; - //log_assert(c.width == 1); - if (c.wire) - c.wire = module->wires_.at(remap_name(c.wire->name)); - newsig.append(c); + if (existing_cell) { + auto it = mapped_cell->connections_.find("\\i"); + log_assert(it != mapped_cell->connections_.end()); + SigSpec inputs = std::move(it->second); + mapped_cell->connections_.erase(it); + it = mapped_cell->connections_.find("\\o"); + log_assert(it != mapped_cell->connections_.end()); + SigSpec outputs = std::move(it->second); + mapped_cell->connections_.erase(it); + + RTLIL::Module* box_module = design->module(mapped_cell->type); + auto abc9_flop = box_module->attributes.count("\\abc9_flop"); + if (!abc9_flop) { + for (const auto &i : inputs) + bit_users[i].insert(mapped_cell->name); + for (const auto &i : outputs) + bit_drivers[i].insert(mapped_cell->name); } - if (existing_cell) { - auto it = existing_cell->connections_.find(mapped_conn.first); + + int input_count = 0, output_count = 0; + for (const auto &port_name : box_ports.at(cell->type)) { + RTLIL::Wire *w = box_module->wire(port_name); + log_assert(w); + + SigSpec sig; + if (w->port_input) { + sig = inputs.extract(input_count, GetSize(w)); + input_count += GetSize(w); + } + if (w->port_output) { + sig = outputs.extract(output_count, GetSize(w)); + output_count += GetSize(w); + } + + SigSpec newsig; + for (auto c : sig.chunks()) { + if (c.width == 0) + continue; + //log_assert(c.width == 1); + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + newsig.append(c); + } + + auto it = existing_cell->connections_.find(port_name); if (it == existing_cell->connections_.end()) continue; - log_assert(GetSize(newsig) >= GetSize(it->second)); - newsig = newsig.extract(0, GetSize(it->second)); - } - cell->setPort(mapped_conn.first, newsig); + if (GetSize(newsig) > GetSize(it->second)) + newsig = newsig.extract(0, GetSize(it->second)); + else + log_assert(GetSize(newsig) == GetSize(it->second)); - if (abc9_flop) - continue; + cell->setPort(port_name, newsig); - if (cell->input(mapped_conn.first)) { - for (auto i : newsig) - bit2sinks[i].push_back(cell); - for (auto i : mapped_conn.second) - bit_users[i].insert(mapped_cell->name); + if (w->port_input && !abc9_flop) + for (const auto &i : newsig) + bit2sinks[i].push_back(cell); + } + } + else { + for (auto &mapped_conn : mapped_cell->connections()) { + RTLIL::SigSpec newsig; + for (auto c : mapped_conn.second.chunks()) { + if (c.width == 0) + continue; + //log_assert(c.width == 1); + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + newsig.append(c); + } + cell->setPort(mapped_conn.first, newsig); + + if (cell->input(mapped_conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : mapped_conn.second) + bit_users[i].insert(mapped_cell->name); + } + if (cell->output(mapped_conn.first)) + for (auto i : mapped_conn.second) + bit_drivers[i].insert(mapped_cell->name); } - if (cell->output(mapped_conn.first)) - for (auto i : mapped_conn.second) - bit_drivers[i].insert(mapped_cell->name); } if (existing_cell) { -- cgit v1.2.3 From 4e396ee7a39682cb859aa64a89b40a149cb4148b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 9 Jan 2020 11:21:03 -0800 Subject: abc9_ops: fix reintegration by removing optimised-away boxes --- passes/techmap/abc9_ops.cc | 106 +++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 56 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 721a33f09..7c7208711 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -488,11 +488,13 @@ void reintegrate(RTLIL::Module *module) } } - for (auto it = module->cells_.begin(); it != module->cells_.end(); ) - if (it->second->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) - it = module->cells_.erase(it); - else - ++it; + std::vector boxes; + for (auto cell : module->cells().to_vector()) { + if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) + module->remove(cell); + else if (cell->attributes.erase("\\abc9_box_seq")) + boxes.emplace_back(cell); + } dict> bit_drivers, bit_users; TopoSort toposort; @@ -504,7 +506,6 @@ void reintegrate(RTLIL::Module *module) { toposort.node(mapped_cell->name); - RTLIL::Cell *cell = nullptr; if (mapped_cell->type == ID($_NOT_)) { RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A); RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y); @@ -536,7 +537,7 @@ void reintegrate(RTLIL::Module *module) if (!driver_lut) { // If a driver couldn't be found (could be from PI or box CI) // then implement using a LUT - cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())), + RTLIL::Cell *cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())), RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), RTLIL::Const::from_string("01")); @@ -548,10 +549,9 @@ void reintegrate(RTLIL::Module *module) } continue; } - cell_stats[mapped_cell->type]++; - RTLIL::Cell *existing_cell = nullptr; if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) { + // Convert buffer into direct connection if (mapped_cell->type == ID($lut) && GetSize(mapped_cell->getPort(ID::A)) == 1 && mapped_cell->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { @@ -561,22 +561,48 @@ void reintegrate(RTLIL::Module *module) log_abort(); continue; } - cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); + RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); + cell->parameters = mapped_cell->parameters; + cell->attributes = mapped_cell->attributes; + + for (auto &mapped_conn : mapped_cell->connections()) { + RTLIL::SigSpec newsig; + for (auto c : mapped_conn.second.chunks()) { + if (c.width == 0) + continue; + //log_assert(c.width == 1); + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + newsig.append(c); + } + cell->setPort(mapped_conn.first, newsig); + + if (cell->input(mapped_conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : mapped_conn.second) + bit_users[i].insert(mapped_cell->name); + } + if (cell->output(mapped_conn.first)) + for (auto i : mapped_conn.second) + bit_drivers[i].insert(mapped_cell->name); + } } else { - existing_cell = module->cell(mapped_cell->name); + RTLIL::Cell *existing_cell = module->cell(mapped_cell->name); log_assert(existing_cell); + log_assert(mapped_cell->type.begins_with("$__boxid")); - if (mapped_cell->type.begins_with("$__boxid")) { - auto type = box_lookup.at(mapped_cell->type, IdString()); - if (type == IdString()) - log_error("No module with abc9_box_id = %s found.\n", mapped_cell->type.c_str() + strlen("$__boxid")); - mapped_cell->type = type; - } - cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); - } + auto type = box_lookup.at(mapped_cell->type, IdString()); + if (type == IdString()) + log_error("No module with abc9_box_id = %s found.\n", mapped_cell->type.c_str() + strlen("$__boxid")); + mapped_cell->type = type; + + RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); + cell->parameters = existing_cell->parameters; + cell->attributes = existing_cell->attributes; + module->swap_names(cell, existing_cell); - if (existing_cell) { auto it = mapped_cell->connections_.find("\\i"); log_assert(it != mapped_cell->connections_.end()); SigSpec inputs = std::move(it->second); @@ -635,45 +661,13 @@ void reintegrate(RTLIL::Module *module) bit2sinks[i].push_back(cell); } } - else { - for (auto &mapped_conn : mapped_cell->connections()) { - RTLIL::SigSpec newsig; - for (auto c : mapped_conn.second.chunks()) { - if (c.width == 0) - continue; - //log_assert(c.width == 1); - if (c.wire) - c.wire = module->wires_.at(remap_name(c.wire->name)); - newsig.append(c); - } - cell->setPort(mapped_conn.first, newsig); - - if (cell->input(mapped_conn.first)) { - for (auto i : newsig) - bit2sinks[i].push_back(cell); - for (auto i : mapped_conn.second) - bit_users[i].insert(mapped_cell->name); - } - if (cell->output(mapped_conn.first)) - for (auto i : mapped_conn.second) - bit_drivers[i].insert(mapped_cell->name); - } - } - if (existing_cell) { - cell->parameters = existing_cell->parameters; - cell->attributes = existing_cell->attributes; - if (cell->attributes.erase("\\abc9_box_seq")) { - module->swap_names(cell, existing_cell); - module->remove(existing_cell); - } - } - else { - cell->parameters = mapped_cell->parameters; - cell->attributes = mapped_cell->attributes; - } + cell_stats[mapped_cell->type]++; } + for (auto cell : boxes) + module->remove(cell); + // Copy connections (and rename) from mapped_mod to module for (auto conn : mapped_mod->connections()) { if (!conn.first.is_fully_const()) { -- cgit v1.2.3 From 784fec93c901caa6f9d980388356d120b0cdfea9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Jan 2020 08:42:58 -0800 Subject: abc9: cleanup --- passes/techmap/abc9_ops.cc | 48 +++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 20 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 7c7208711..6f089447e 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -40,7 +40,7 @@ void break_scc(RTLIL::Module *module) // its output ports into a new PO, and drive its previous // sinks with a new PI pool ids_seen; - for (auto cell : module->selected_cells()) { + for (auto cell : module->cells()) { auto it = cell->attributes.find(ID(abc9_scc_id)); if (it == cell->attributes.end()) continue; @@ -116,7 +116,7 @@ void prep_dff(RTLIL::Module *module) typedef SigSpec clkdomain_t; dict clk_to_mergeability; - for (auto cell : module->selected_cells()) { + for (auto cell : module->cells()) { if (cell->type != "$__ABC9_FF_") continue; @@ -179,11 +179,8 @@ void prep_dff(RTLIL::Module *module) ++it; } - for (auto &conn : holes_module->connections_) { - auto it = replace.find(conn); - if (it != replace.end()) - conn = it->second; - } + for (auto &conn : holes_module->connections_) + conn = replace.at(conn, conn); } } @@ -198,7 +195,7 @@ void prep_holes(RTLIL::Module *module, bool dff) TopoSort toposort; bool abc9_box_seen = false; - for (auto cell : module->selected_cells()) { + for (auto cell : module->cells()) { if (cell->type == "$__ABC9_FF_") continue; @@ -236,21 +233,23 @@ void prep_holes(RTLIL::Module *module, bool dff) for (auto user_cell : it.second) toposort.edge(driver_cell, user_cell); -#if 0 - toposort.analyze_loops = true; -#endif + if (ys_debug(1)) + toposort.analyze_loops = true; + bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); -#if 0 - unsigned i = 0; - for (auto &it : toposort.loops) { - log(" loop %d\n", i++); - for (auto cell_name : it) { - auto cell = module->cell(cell_name); - log_assert(cell); - log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str()); + + if (ys_debug(1)) { + unsigned i = 0; + for (auto &it : toposort.loops) { + log(" loop %d\n", i++); + for (auto cell_name : it) { + auto cell = module->cell(cell_name); + log_assert(cell); + log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str()); + } } } -#endif + log_assert(no_loops); vector box_list; @@ -845,6 +844,12 @@ struct Abc9OpsPass : public Pass { } extra_args(args, argidx, design); + if (!(break_scc_mode || unbreak_scc_mode || prep_dff_mode || reintegrate_mode)) + log_cmd_error("At least one of -{,un}break_scc, -prep_{dff,holes}, -reintegrate must be specified.\n"); + + if (dff_mode && !prep_holes_mode) + log_cmd_error("'-dff' option is only relevant for -prep_holes.\n"); + for (auto mod : design->selected_modules()) { if (mod->get_bool_attribute("\\abc9_holes")) continue; @@ -854,6 +859,9 @@ struct Abc9OpsPass : public Pass { continue; } + if (!design->selected_whole_module(mod)) + log_error("Can't handle partially selected module %s!\n", log_id(mod)); + if (break_scc_mode) break_scc(mod); if (unbreak_scc_mode) -- cgit v1.2.3 From a6d4ea74634826741f09793c36d596f2fa239f62 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Jan 2020 19:21:11 -0800 Subject: abc9: respect (* keep *) on cells --- passes/techmap/abc9_ops.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index cc22fd474..9cc58c99d 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -489,6 +489,8 @@ void reintegrate(RTLIL::Module *module) std::vector boxes; for (auto cell : module->cells().to_vector()) { + if (cell->has_keep_attr()) + continue; if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) module->remove(cell); else if (cell->attributes.erase("\\abc9_box_seq")) -- cgit v1.2.3 From 2c65e1abacc4401c4fd3e9b48f52c4de120bc511 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Jan 2020 21:45:27 -0800 Subject: abc9: break SCC by setting (* keep *) on output wires --- passes/techmap/abc9_ops.cc | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 9cc58c99d..4da10d94b 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -53,30 +53,7 @@ void break_scc(RTLIL::Module *module) if (cell->output(c.first)) { SigBit b = c.second.as_bit(); Wire *w = b.wire; - if (w->port_input) { - // In this case, hopefully the loop break has been already created - // Get the non-prefixed wire - Wire *wo = module->wire(stringf("%s.abco", b.wire->name.c_str())); - log_assert(wo != nullptr); - log_assert(wo->port_output); - log_assert(b.offset < GetSize(wo)); - c.second = RTLIL::SigBit(wo, b.offset); - } - else { - // Create a new output/input loop break - w->port_input = true; - w = module->wire(stringf("%s.abco", w->name.c_str())); - if (!w) { - w = module->addWire(stringf("%s.abco", 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(ID(abc9_scc_break)); - c.second = RTLIL::SigBit(w, b.offset); - } + w->set_bool_attribute(ID::keep); } } } @@ -586,7 +563,9 @@ void reintegrate(RTLIL::Module *module) } if (cell->output(mapped_conn.first)) for (auto i : mapped_conn.second) - bit_drivers[i].insert(mapped_cell->name); + // Ignore inouts for topo ordering + if (i.wire && !(i.wire->port_input && i.wire->port_output)) + bit_drivers[i].insert(mapped_cell->name); } } else { -- cgit v1.2.3 From b678b15c6d0d14580ca18e89f86926eabf8fead0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Jan 2020 23:33:37 -0800 Subject: abc9_ops: ignore inouts of all cell outputs for topo ordering --- passes/techmap/abc9_ops.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 4da10d94b..d7ebfdf3f 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -488,7 +488,9 @@ void reintegrate(RTLIL::Module *module) RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A); RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y); bit_users[a_bit].insert(mapped_cell->name); - bit_drivers[y_bit].insert(mapped_cell->name); + // Ignore inouts for topo ordering + if (y_bit.wire && !(y_bit.wire->port_input && y_bit.wire->port_output)) + bit_drivers[y_bit].insert(mapped_cell->name); if (!a_bit.wire) { mapped_cell->setPort(ID::Y, module->addWire(NEW_ID)); @@ -598,7 +600,9 @@ void reintegrate(RTLIL::Module *module) for (const auto &i : inputs) bit_users[i].insert(mapped_cell->name); for (const auto &i : outputs) - bit_drivers[i].insert(mapped_cell->name); + // Ignore inouts for topo ordering + if (i.wire && !(i.wire->port_input && i.wire->port_output)) + bit_drivers[i].insert(mapped_cell->name); } int input_count = 0, output_count = 0; -- cgit v1.2.3 From 531fddf797a79b46df3e462112ca68ff50e6a18e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 13 Jan 2020 23:42:27 -0800 Subject: abc9_ops: -break_scc -> -mark_scc using (* keep *), remove -unbreak_scc --- passes/techmap/abc9_ops.cc | 59 ++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 41 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index d7ebfdf3f..c7236486f 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -33,7 +33,7 @@ inline std::string remap_name(RTLIL::IdString abc9_name) return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); } -void break_scc(RTLIL::Module *module) +void mark_scc(RTLIL::Module *module) { // For every unique SCC found, (arbitrarily) find the first // cell in the component, and convert all wires driven by @@ -44,7 +44,8 @@ void break_scc(RTLIL::Module *module) auto it = cell->attributes.find(ID(abc9_scc_id)); if (it == cell->attributes.end()) continue; - auto r = ids_seen.insert(it->second); + auto id = it->second; + auto r = ids_seen.insert(id); cell->attributes.erase(it); if (!r.second) continue; @@ -54,6 +55,7 @@ void break_scc(RTLIL::Module *module) SigBit b = c.second.as_bit(); Wire *w = b.wire; w->set_bool_attribute(ID::keep); + w->attributes[ID(abc9_scc_id)] = id.as_int(); } } } @@ -61,28 +63,6 @@ void break_scc(RTLIL::Module *module) module->fixup_ports(); } -void unbreak_scc(RTLIL::Module *module) -{ - // Now 'unexpose' those wires by undoing - // the expose operation -- remove them from PO/PI - // and re-connecting them back together - for (auto wire : module->wires()) { - auto it = wire->attributes.find(ID(abc9_scc_break)); - if (it != wire->attributes.end()) { - wire->attributes.erase(it); - log_assert(wire->port_output); - wire->port_output = false; - std::string name = wire->name.str(); - RTLIL::Wire *i_wire = module->wire(name.substr(0, GetSize(name) - 5)); - log_assert(i_wire); - log_assert(i_wire->port_input); - i_wire->port_input = false; - module->connect(i_wire, wire); - } - } - module->fixup_ports(); -} - void prep_dff(RTLIL::Module *module) { auto design = module->design; @@ -676,21 +656,25 @@ void reintegrate(RTLIL::Module *module) // Stitch in mapped_mod's inputs/outputs into module for (auto port : mapped_mod->ports) { - RTLIL::Wire *w = mapped_mod->wire(port); + RTLIL::Wire *mapped_wire = mapped_mod->wire(port); RTLIL::Wire *wire = module->wire(port); log_assert(wire); + if (wire->attributes.erase(ID(abc9_scc_id))) { + auto r YS_ATTRIBUTE(unused) = wire->attributes.erase(ID::keep); + log_assert(r); + } RTLIL::Wire *remap_wire = module->wire(remap_name(port)); RTLIL::SigSpec signal(wire, 0, GetSize(remap_wire)); log_assert(GetSize(signal) >= GetSize(remap_wire)); RTLIL::SigSig conn; - if (w->port_output) { + if (mapped_wire->port_output) { conn.first = signal; conn.second = remap_wire; out_wires++; module->connect(conn); } - else if (w->port_input) { + else if (mapped_wire->port_input) { conn.first = remap_wire; conn.second = signal; in_wires++; @@ -791,8 +775,7 @@ struct Abc9OpsPass : public Pass { { log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); - bool break_scc_mode = false; - bool unbreak_scc_mode = false; + bool mark_scc_mode = false; bool prep_dff_mode = false; bool prep_holes_mode = false; bool reintegrate_mode = false; @@ -801,12 +784,8 @@ struct Abc9OpsPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; - if (arg == "-break_scc") { - break_scc_mode = true; - continue; - } - if (arg == "-unbreak_scc") { - unbreak_scc_mode = true; + if (arg == "-mark_scc") { + mark_scc_mode = true; continue; } if (arg == "-prep_dff") { @@ -829,8 +808,8 @@ struct Abc9OpsPass : public Pass { } extra_args(args, argidx, design); - if (!(break_scc_mode || unbreak_scc_mode || prep_dff_mode || reintegrate_mode)) - log_cmd_error("At least one of -{,un}break_scc, -prep_{dff,holes}, -reintegrate must be specified.\n"); + if (!(mark_scc_mode || prep_dff_mode || reintegrate_mode)) + log_cmd_error("At least one of -mark_scc, -prep_{dff,holes}, -reintegrate must be specified.\n"); if (dff_mode && !prep_holes_mode) log_cmd_error("'-dff' option is only relevant for -prep_holes.\n"); @@ -847,10 +826,8 @@ struct Abc9OpsPass : public Pass { if (!design->selected_whole_module(mod)) log_error("Can't handle partially selected module %s!\n", log_id(mod)); - if (break_scc_mode) - break_scc(mod); - if (unbreak_scc_mode) - unbreak_scc(mod); + if (mark_scc_mode) + mark_scc(mod); if (prep_dff_mode) prep_dff(mod); if (prep_holes_mode) -- cgit v1.2.3 From 468386d67d902722562e9a0412a76fca79ec4fa2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 12:25:45 -0800 Subject: abc9_ops: -prep_holes -> -prep_xaiger, move padding to write_xaiger --- passes/techmap/abc9_ops.cc | 173 +++++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 102 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index cc82a72cf..405f3e267 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -143,7 +143,7 @@ void prep_dff(RTLIL::Module *module) } } -void prep_holes(RTLIL::Module *module, bool dff) +void prep_xaiger(RTLIL::Module *module, bool dff) { auto design = module->design; log_assert(design); @@ -152,7 +152,7 @@ void prep_holes(RTLIL::Module *module, bool dff) dict> bit_drivers, bit_users; TopoSort toposort; - bool abc9_box_seen = false; + dict> box_ports; for (auto cell : module->cells()) { if (cell->type == "$__ABC9_FF_") @@ -165,7 +165,40 @@ void prep_holes(RTLIL::Module *module, bool dff) abc9_flop = inst_module->get_bool_attribute("\\abc9_flop"); if (abc9_flop && !dff) continue; - abc9_box_seen = abc9_box; + + auto r = box_ports.insert(cell->type); + if (r.second) { + // Make carry in the last PI, and carry out the last PO + // since ABC requires it this way + IdString carry_in, carry_out; + for (const auto &port_name : inst_module->ports) { + auto w = inst_module->wire(port_name); + log_assert(w); + if (w->get_bool_attribute("\\abc9_carry")) { + if (w->port_input) { + if (carry_in != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(inst_module)); + carry_in = port_name; + } + if (w->port_output) { + if (carry_out != IdString()) + log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(inst_module)); + carry_out = port_name; + } + } + else + r.first->second.push_back(port_name); + } + + if (carry_in != IdString() && carry_out == IdString()) + log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(inst_module)); + if (carry_in == IdString() && carry_out != IdString()) + log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(inst_module)); + if (carry_in != IdString()) { + r.first->second.push_back(carry_in); + r.first->second.push_back(carry_out); + } + } } else if (!yosys_celltypes.cell_known(cell->type)) continue; @@ -183,7 +216,7 @@ void prep_holes(RTLIL::Module *module, bool dff) toposort.node(cell->name); } - if (!abc9_box_seen) + if (box_ports.empty()) return; for (auto &it : bit_users) @@ -211,7 +244,13 @@ void prep_holes(RTLIL::Module *module, bool dff) log_assert(no_loops); - vector box_list; + RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str())); + log_assert(holes_module); + holes_module->set_bool_attribute("\\abc9_holes"); + + dict cell_cache; + + int port_id = 1, box_count = 0; for (auto cell_name : toposort.sorted) { RTLIL::Cell *cell = module->cell(cell_name); log_assert(cell); @@ -220,62 +259,10 @@ void prep_holes(RTLIL::Module *module, bool dff) if (!box_module || !box_module->attributes.count("\\abc9_box_id")) continue; - bool blackbox = box_module->get_blackbox_attribute(true /* ignore_wb */); - - // Fully pad all unused input connections of this box cell with S0 - // Fully pad all undriven output connections of this box cell with anonymous wires - for (const auto &port_name : box_module->ports) { - RTLIL::Wire* w = box_module->wire(port_name); - log_assert(w); - auto it = cell->connections_.find(port_name); - if (w->port_input) { - RTLIL::SigSpec rhs; - if (it != cell->connections_.end()) { - if (GetSize(it->second) < GetSize(w)) - it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second))); - rhs = it->second; - } - else { - rhs = RTLIL::SigSpec(State::S0, GetSize(w)); - cell->setPort(port_name, rhs); - } - } - if (w->port_output) { - RTLIL::SigSpec rhs; - auto it = cell->connections_.find(w->name); - if (it != cell->connections_.end()) { - if (GetSize(it->second) < GetSize(w)) - it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second))); - rhs = it->second; - } - else { - Wire *wire = module->addWire(NEW_ID, GetSize(w)); - if (blackbox) - wire->set_bool_attribute(ID(abc9_padding)); - rhs = wire; - cell->setPort(port_name, rhs); - } - } - } - - cell->attributes["\\abc9_box_seq"] = box_list.size(); - box_list.emplace_back(cell); - } - log_assert(!box_list.empty()); - - RTLIL::Module *holes_module = design->addModule(stringf("%s$holes", module->name.c_str())); - log_assert(holes_module); - holes_module->set_bool_attribute("\\abc9_holes"); + cell->attributes["\\abc9_box_seq"] = box_count++; - dict cell_cache; - dict> box_ports; - - int port_id = 1; - for (auto cell : box_list) { - RTLIL::Module* orig_box_module = design->module(cell->type); - log_assert(orig_box_module); - IdString derived_name = orig_box_module->derive(design, cell->parameters); - RTLIL::Module* box_module = design->module(derived_name); + IdString derived_name = box_module->derive(design, cell->parameters); + box_module = design->module(derived_name); auto r = cell_cache.insert(derived_name); auto &holes_cell = r.first->second; @@ -283,40 +270,6 @@ void prep_holes(RTLIL::Module *module, bool dff) if (box_module->has_processes()) Pass::call_on_module(design, box_module, "proc"); - auto r2 = box_ports.insert(cell->type); - if (r2.second) { - // Make carry in the last PI, and carry out the last PO - // since ABC requires it this way - IdString carry_in, carry_out; - for (const auto &port_name : box_module->ports) { - auto w = box_module->wire(port_name); - log_assert(w); - if (w->get_bool_attribute("\\abc9_carry")) { - if (w->port_input) { - if (carry_in != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' input port.\n", log_id(box_module)); - carry_in = port_name; - } - if (w->port_output) { - if (carry_out != IdString()) - log_error("Module '%s' contains more than one 'abc9_carry' output port.\n", log_id(box_module)); - carry_out = port_name; - } - } - else - r2.first->second.push_back(port_name); - } - - if (carry_in != IdString() && carry_out == IdString()) - log_error("Module '%s' contains an 'abc9_carry' input port but no output port.\n", log_id(box_module)); - if (carry_in == IdString() && carry_out != IdString()) - log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(box_module)); - if (carry_in != IdString()) { - r2.first->second.push_back(carry_in); - r2.first->second.push_back(carry_out); - } - } - if (box_module->get_bool_attribute("\\whitebox")) { holes_cell = holes_module->addCell(cell->name, derived_name); @@ -770,6 +723,22 @@ struct Abc9OpsPass : public Pass { log("\n"); log(" abc9_ops [options] [selection]\n"); log("\n"); + log("This pass contains a set of supporting operations for use during ABC technology\n"); + log("mapping, and is expected to be called in conjunction with other operations from\n"); + log("the `abc9' script pass. Only fully-selected modules are supported.\n"); + log("\n"); + log(" -mark_scc\n"); + log(" for an arbitrarily chosen cell in each unique SCC of each selected module\n"); + log(" (tagged with an (* abc9_scc_id = *) attribute), temporarily mark all\n"); + log(" wires driven by this cell's outputs with a (* keep *) attribute in order\n"); + log(" to break the SCC. this temporary attribute will be removed on -reintegrate.\n"); + log("\n"); + log(" -prep_xaiger\n"); + log(" prepare the design for XAIGER output. this includes computing the\n"); + log(" topological ordering of ABC9 boxes, as well as preparing the\n"); + log(" '$holes' module that contains the logic behaviour of ABC9\n"); + log(" whiteboxes.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { @@ -777,7 +746,7 @@ struct Abc9OpsPass : public Pass { bool mark_scc_mode = false; bool prep_dff_mode = false; - bool prep_holes_mode = false; + bool prep_xaiger_mode = false; bool reintegrate_mode = false; bool dff_mode = false; @@ -792,8 +761,8 @@ struct Abc9OpsPass : public Pass { prep_dff_mode = true; continue; } - if (arg == "-prep_holes") { - prep_holes_mode = true; + if (arg == "-prep_xaiger") { + prep_xaiger_mode = true; continue; } if (arg == "-reintegrate") { @@ -809,10 +778,10 @@ struct Abc9OpsPass : public Pass { extra_args(args, argidx, design); if (!(mark_scc_mode || prep_dff_mode || reintegrate_mode)) - log_cmd_error("At least one of -mark_scc, -prep_{dff,holes}, -reintegrate must be specified.\n"); + log_cmd_error("At least one of -mark_scc, -prep_{xaiger,dff}, -reintegrate must be specified.\n"); - if (dff_mode && !prep_holes_mode) - log_cmd_error("'-dff' option is only relevant for -prep_holes.\n"); + if (dff_mode && !prep_xaiger_mode) + log_cmd_error("'-dff' option is only relevant for -prep_xaiger.\n"); for (auto mod : design->selected_modules()) { if (mod->get_bool_attribute("\\abc9_holes")) @@ -830,8 +799,8 @@ struct Abc9OpsPass : public Pass { mark_scc(mod); if (prep_dff_mode) prep_dff(mod); - if (prep_holes_mode) - prep_holes(mod, dff_mode); + if (prep_xaiger_mode) + prep_xaiger(mod, dff_mode); if (reintegrate_mode) reintegrate(mod); } -- cgit v1.2.3 From 654247abe9078566f93960a135ce08b0cfc96442 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 12:40:36 -0800 Subject: abc9_ops/write_xaiger: update doc --- passes/techmap/abc9_ops.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 405f3e267..463941b0b 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -739,6 +739,19 @@ struct Abc9OpsPass : public Pass { log(" '$holes' module that contains the logic behaviour of ABC9\n"); log(" whiteboxes.\n"); log("\n"); + log(" -dff\n"); + log(" consider flop cells (those instantiating modules marked with (* abc9_flop *)\n"); + log(" during -prep_xaiger.\n"); + log("\n"); + log(" -prep_dff\n"); + log(" compute the clock domain and initial value of each flop in the design.\n"); + log(" process the '$holes' module to support clock-enable functionality.\n"); + log("\n"); + log(" -reintegrate\n"); + log(" for each selected module, re-intergrate the module '$abc9'\n"); + log(" by first recovering ABC9 boxes, and then stitching in the remaining primary\n"); + log(" inputs and outputs.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { -- cgit v1.2.3 From 4656f202c6f05d126c1acc79fca675e467c80840 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 14:27:29 -0800 Subject: abc9_ops: -reintegrate to not trim box padding anymore --- passes/techmap/abc9_ops.cc | 9 --------- 1 file changed, 9 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 463941b0b..aa21ff283 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -562,15 +562,6 @@ void reintegrate(RTLIL::Module *module) c.wire = module->wires_.at(remap_name(c.wire->name)); newsig.append(c); } - - auto it = existing_cell->connections_.find(port_name); - if (it == existing_cell->connections_.end()) - continue; - if (GetSize(newsig) > GetSize(it->second)) - newsig = newsig.extract(0, GetSize(it->second)); - else - log_assert(GetSize(newsig) == GetSize(it->second)); - cell->setPort(port_name, newsig); if (w->port_input && !abc9_flop) -- cgit v1.2.3 From 1d4314d88853feb1fa6af13fe56274d53d81d853 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 14:58:56 -0800 Subject: abc9_ops -prep_dff: insert async s/r mux in holes when replacing $_DFF_* --- passes/techmap/abc9_ops.cc | 68 +++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 31 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 5091ac0f2..750f36ceb 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -106,38 +106,44 @@ void prep_dff(RTLIL::Module *module) SigMap sigmap(holes_module); dict replace; - for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) { - auto cell = it->second; - if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", - "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) { - SigBit D = cell->getPort("\\D"); - SigBit Q = cell->getPort("\\Q"); - // Remove the $_DFF_* cell from what needs to be a combinatorial box - it = holes_module->cells_.erase(it); - Wire *port; - if (GetSize(Q.wire) == 1) - port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); - else - port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset)); - log_assert(port); - // Prepare to replace "assign = $_DFF_*.Q;" with "assign = $_DFF_*.D;" - // in order to extract just the combinatorial control logic that feeds the box - // (i.e. clock enable, synchronous reset, etc.) - replace.insert(std::make_pair(Q,D)); - // Since `flatten` above would have created wires named ".Q", - // extract the pre-techmap cell name - auto pos = Q.wire->name.str().rfind("."); - log_assert(pos != std::string::npos); - IdString driver = Q.wire->name.substr(0, pos); - // And drive the signal that was previously driven by "DFF.Q" (typically - // used to implement clock-enable functionality) with the ".$abc9_currQ" - // wire (which itself is driven an by input port) we inserted above - Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str())); - log_assert(currQ); - holes_module->connect(Q, currQ); - } + for (auto cell : holes_module->cells().to_vector()) { + if (!cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", + "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) + continue; + SigBit D = cell->getPort("\\D"); + SigBit Q = cell->getPort("\\Q"); + // Emulate async control embedded inside $_DFF_* cell with mux in front of D + if (cell->type.in("$_DFF_NN0_", "$_DFF_PN0_")) + D = holes_module->MuxGate(NEW_ID, State::S0, D, cell->getPort("\\R")); + else if (cell->type.in("$_DFF_NN1_", "$_DFF_PN1_")) + D = holes_module->MuxGate(NEW_ID, State::S1, D, cell->getPort("\\R")); + else if (cell->type.in("$_DFF_NP0_", "$_DFF_PP0_")) + D = holes_module->MuxGate(NEW_ID, D, State::S0, cell->getPort("\\R")); + else if (cell->type.in("$_DFF_NP1_", "$_DFF_PP1_")) + D = holes_module->MuxGate(NEW_ID, D, State::S1, cell->getPort("\\R")); + // Remove the $_DFF_* cell from what needs to be a combinatorial box + holes_module->remove(cell); + Wire *port; + if (GetSize(Q.wire) == 1) + port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str())); else - ++it; + port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset)); + log_assert(port); + // Prepare to replace "assign = $_DFF_*.Q;" with "assign = $_DFF_*.D;" + // in order to extract just the combinatorial control logic that feeds the box + // (i.e. clock enable, synchronous reset, etc.) + replace.insert(std::make_pair(Q,D)); + // Since `flatten` above would have created wires named ".Q", + // extract the pre-techmap cell name + auto pos = Q.wire->name.str().rfind("."); + log_assert(pos != std::string::npos); + IdString driver = Q.wire->name.substr(0, pos); + // And drive the signal that was previously driven by "DFF.Q" (typically + // used to implement clock-enable functionality) with the ".$abc9_currQ" + // wire (which itself is driven an by input port) we inserted above + Wire *currQ = holes_module->wire(stringf("%s.abc9_ff.Q", driver.c_str())); + log_assert(currQ); + holes_module->connect(Q, currQ); } for (auto &conn : holes_module->connections_) -- cgit v1.2.3 From f180dba753c9f4bfb3b89575b0d224c73a1e8897 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 18:56:06 -0800 Subject: abc9_ops: -prep_xaiger to skip (* keep *) cells --- passes/techmap/abc9_ops.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 750f36ceb..40622ece7 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -165,6 +165,8 @@ void prep_xaiger(RTLIL::Module *module, bool dff) for (auto cell : module->cells()) { if (cell->type == "$__ABC9_FF_") continue; + if (cell->has_keep_attr()) + continue; auto inst_module = module->design->module(cell->type); bool abc9_box = inst_module && inst_module->attributes.count("\\abc9_box_id"); -- cgit v1.2.3 From dbf351390e68a9d7c453e893de8fa9d09eb24f62 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 23 Jan 2020 22:45:34 -0800 Subject: abc9: -reintegrate recover type from existing cell, check against boxid --- passes/techmap/abc9_ops.cc | 49 ++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 30 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 40622ece7..d238ce0ad 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -356,24 +356,14 @@ void reintegrate(RTLIL::Module *module) for (auto w : mapped_mod->wires()) module->addWire(remap_name(w->name), GetSize(w)); - dict box_lookup; dict> box_ports; for (auto m : design->modules()) { - auto it = m->attributes.find(ID(abc9_box_id)); - if (it == m->attributes.end()) + if (!m->attributes.count(ID(abc9_box_id))) continue; - if (m->name.begins_with("$paramod")) - continue; - auto id = it->second.as_int(); - auto r = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); - if (!r.second) - log_error("Module '%s' has the same abc9_box_id = %d value as '%s'.\n", - log_id(m), id, log_id(r.first->second)); - log_assert(r.second); - auto r2 = box_ports.insert(m->name); - if (r2.second) { + auto r = box_ports.insert(m->name); + if (r.second) { // Make carry in the last PI, and carry out the last PO // since ABC requires it this way IdString carry_in, carry_out; @@ -393,7 +383,7 @@ void reintegrate(RTLIL::Module *module) } } else - r2.first->second.push_back(port_name); + r.first->second.push_back(port_name); } if (carry_in != IdString() && carry_out == IdString()) @@ -401,8 +391,8 @@ void reintegrate(RTLIL::Module *module) if (carry_in == IdString() && carry_out != IdString()) log_error("Module '%s' contains an 'abc9_carry' output port but no input port.\n", log_id(m)); if (carry_in != IdString()) { - r2.first->second.push_back(carry_in); - r2.first->second.push_back(carry_out); + r.first->second.push_back(carry_in); + r.first->second.push_back(carry_out); } } } @@ -516,28 +506,27 @@ void reintegrate(RTLIL::Module *module) else { RTLIL::Cell *existing_cell = module->cell(mapped_cell->name); log_assert(existing_cell); - log_assert(mapped_cell->type.begins_with("$__boxid")); - auto type = box_lookup.at(mapped_cell->type, IdString()); - if (type == IdString()) - log_error("No module with abc9_box_id = %s found.\n", mapped_cell->type.c_str() + strlen("$__boxid")); - mapped_cell->type = type; + RTLIL::Module* box_module = design->module(existing_cell->type); + auto it = box_module->attributes.find(ID(abc9_box_id)); + log_assert(it != box_module->attributes.end()); + log_assert(mapped_cell->type == stringf("$__boxid%d", it->second.as_int())); + mapped_cell->type = existing_cell->type; RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); cell->parameters = existing_cell->parameters; cell->attributes = existing_cell->attributes; module->swap_names(cell, existing_cell); - auto it = mapped_cell->connections_.find("\\i"); - log_assert(it != mapped_cell->connections_.end()); - SigSpec inputs = std::move(it->second); - mapped_cell->connections_.erase(it); - it = mapped_cell->connections_.find("\\o"); - log_assert(it != mapped_cell->connections_.end()); - SigSpec outputs = std::move(it->second); - mapped_cell->connections_.erase(it); + auto jt = mapped_cell->connections_.find("\\i"); + log_assert(jt != mapped_cell->connections_.end()); + SigSpec inputs = std::move(jt->second); + mapped_cell->connections_.erase(jt); + jt = mapped_cell->connections_.find("\\o"); + log_assert(jt != mapped_cell->connections_.end()); + SigSpec outputs = std::move(jt->second); + mapped_cell->connections_.erase(jt); - RTLIL::Module* box_module = design->module(mapped_cell->type); auto abc9_flop = box_module->attributes.count("\\abc9_flop"); if (!abc9_flop) { for (const auto &i : inputs) -- cgit v1.2.3 From 9009b76a69b9e867f69295a8e555305925e83aeb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 27 Jan 2020 11:18:21 -0800 Subject: abc9_ops: add comments --- passes/techmap/abc9_ops.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index d238ce0ad..9ad29a8f6 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -213,6 +213,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) else if (!yosys_celltypes.cell_known(cell->type)) continue; + // TODO: Speed up toposort -- we care about box ordering only for (auto conn : cell->connections()) { if (cell->input(conn.first)) for (auto bit : sigmap(conn.second)) @@ -222,7 +223,6 @@ void prep_xaiger(RTLIL::Module *module, bool dff) for (auto bit : sigmap(conn.second)) bit_drivers[bit].insert(cell->name); } - toposort.node(cell->name); } @@ -415,6 +415,7 @@ void reintegrate(RTLIL::Module *module) std::map cell_stats; for (auto mapped_cell : mapped_mod->cells()) { + // TODO: Speed up toposort -- we care about NOT ordering only toposort.node(mapped_cell->name); if (mapped_cell->type == ID($_NOT_)) { @@ -625,6 +626,17 @@ void reintegrate(RTLIL::Module *module) } } + // ABC9 will return $_NOT_ gates in its mapping (since they are + // treated as being "free"), in particular driving primary + // outputs (real primary outputs, or cells treated as blackboxes) + // or driving box inputs. + // Instead of just mapping those $_NOT_ gates into 2-input $lut-s + // at an area and delay cost, see if it is possible to push + // this $_NOT_ into the driving LUT, or into all sink LUTs. + // When this is not possible, (i.e. this signal drives two primary + // outputs, only one of which is complemented) and when the driver + // is a LUT, then clone the LUT so that it can be inverted without + // increasing depth/delay. for (auto &it : bit_users) if (bit_drivers.count(it.first)) for (auto driver_cell : bit_drivers.at(it.first)) -- cgit v1.2.3