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 b2259a920165930261050065d870d03fc7573346 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 10 Jan 2020 11:45:41 -0800 Subject: Add abc9_ops -check, -prep_times, -write_box for required times --- passes/techmap/abc9_ops.cc | 300 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 233 insertions(+), 67 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 7c7208711..4d49bb4d2 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -23,6 +23,8 @@ #include "kernel/utils.h" #include "kernel/celltypes.h" +#define ABC9_DELAY_BASE_ID 9000 + USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -33,6 +35,48 @@ inline std::string remap_name(RTLIL::IdString abc9_name) return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1); } +void check(RTLIL::Design *design) +{ + dict box_lookup; + 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)); + + // 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; + } + } + } + + 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)); + } +} + void break_scc(RTLIL::Module *module) { // For every unique SCC found, (arbitrarily) find the first @@ -301,6 +345,7 @@ void prep_holes(RTLIL::Module *module, bool dff) } cell->attributes["\\abc9_box_seq"] = box_list.size(); + //log_debug("%s.%s is box %d\n", log_id(module), log_id(cell), box_list.size()); box_list.emplace_back(cell); } log_assert(!box_list.empty()); @@ -318,8 +363,8 @@ void prep_holes(RTLIL::Module *module, bool dff) 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"); + cell->type = derived_name; + cell->parameters.clear(); int box_inputs = 0; auto r = cell_cache.insert(std::make_pair(derived_name, nullptr)); @@ -328,6 +373,9 @@ void prep_holes(RTLIL::Module *module, bool dff) holes_cell = holes_module->addCell(cell->name, cell->type); holes_cell->parameters = cell->parameters; r.first->second = holes_cell; + + if (box_module->has_processes()) + Pass::call_on_module(design, box_module, "proc"); } auto r2 = box_ports.insert(cell->type); @@ -339,25 +387,15 @@ void prep_holes(RTLIL::Module *module, bool dff) 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)); + if (w->port_input) 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)); + if (w->port_output) 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); @@ -423,6 +461,116 @@ void prep_holes(RTLIL::Module *module, bool dff) } } +void prep_times(RTLIL::Design *design) +{ + std::set delays; + std::vector boxes; + std::map> requireds; + for (auto module : design->selected_modules()) { + if (module->get_bool_attribute("\\abc9_holes")) + continue; + + if (module->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(module)); + continue; + } + + boxes.clear(); + for (auto cell : module->cells()) { + if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY))) + continue; + + RTLIL::Module* inst_module = module->design->module(cell->type); + if (!inst_module) + continue; + if (!inst_module->get_blackbox_attribute()) + continue; + // Flop inputs cannot have required times + // (required time should be captured by flop box) + // TODO: enforce this + if (cell->attributes.count(ID(abc9_box_id))) + continue; + boxes.emplace_back(cell); + } + + delays.clear(); + requireds.clear(); + for (auto cell : boxes) { + RTLIL::Module* inst_module = module->design->module(cell->type); + + for (auto &conn : cell->connections_) { + auto port_wire = inst_module->wire(conn.first); + if (!port_wire->port_input) + continue; + + auto it = port_wire->attributes.find("\\abc9_required"); + if (it == port_wire->attributes.end()) + continue; + + int count = 0; + requireds.clear(); + if (it->second.flags == 0) { + count = 1; + requireds[it->second.as_int()].push_back(0); + } + else + for (const auto &tok : split_tokens(it->second.decode_string())) + requireds[atoi(tok.c_str())].push_back(count++); + if (count > 1 && count != GetSize(port_wire)) + log_error("%s.%s is %d bits wide but abc9_required = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first), + GetSize(port_wire), log_signal(it->second), count); + + SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); + for (const auto &i : requireds) { + delays.insert(i.first); + for (auto offset : i.second) { + auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); + box->setPort(ID(I), conn.second[offset]); + box->setPort(ID(O), O[offset]); + box->setParam(ID(DELAY), i.first); + conn.second[offset] = O[offset]; + } + } + } + } + + std::stringstream ss; + bool first = true; + for (auto d : delays) + if (first) { + first = false; + ss << d; + } + else + ss << " " << d; + module->attributes[ID(abc9_delays)] = ss.str(); + } +} + +void write_box(RTLIL::Module *module, const std::string &src, const std::string &dst) { + std::ofstream ofs(dst); + log_assert(ofs.is_open()); + + // Since ABC can only accept one box file, we have to copy + // over the existing box file + if (src != "(null)") { + std::ifstream ifs(src); + ofs << ifs.rdbuf() << std::endl; + ifs.close(); + } + + auto it = module->attributes.find(ID(abc9_delays)); + if (it != module->attributes.end()) { + for (const auto &tok : split_tokens(it->second.decode_string())) { + int d = atoi(tok.c_str()); + ofs << "$__ABC9_DELAY@" << d << " " << ABC9_DELAY_BASE_ID + d << " 0 1 1" << std::endl; + ofs << d << std::endl; + } + } + + ofs.close(); +} + void reintegrate(RTLIL::Module *module) { auto design = module->design; @@ -438,8 +586,6 @@ void reintegrate(RTLIL::Module *module) 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()) @@ -447,51 +593,19 @@ void reintegrate(RTLIL::Module *module) 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)); + auto r YS_ATTRIBUTE(unused) = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); 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); - } - } } + pool delay_boxes; 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->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) { + delay_boxes.insert(cell->name); + module->remove(cell); + } else if (cell->attributes.erase("\\abc9_box_seq")) boxes.emplace_back(cell); } @@ -501,6 +615,7 @@ void reintegrate(RTLIL::Module *module) dict not2drivers; dict> bit2sinks; + dict> box_ports; std::map cell_stats; for (auto mapped_cell : mapped_mod->cells()) { @@ -551,16 +666,6 @@ void reintegrate(RTLIL::Module *module) } 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")) { - 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; - } RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); cell->parameters = mapped_cell->parameters; cell->attributes = mapped_cell->attributes; @@ -588,6 +693,16 @@ void reintegrate(RTLIL::Module *module) bit_drivers[i].insert(mapped_cell->name); } } + else if (delay_boxes.count(mapped_cell->name)) { + SigBit I = mapped_cell->getPort(ID(i)); + SigBit O = mapped_cell->getPort(ID(o)); + if (I.wire) + I.wire = module->wires_.at(remap_name(I.wire->name)); + log_assert(O.wire); + O.wire = module->wires_.at(remap_name(O.wire->name)); + module->connect(O, I); + continue; + } else { RTLIL::Cell *existing_cell = module->cell(mapped_cell->name); log_assert(existing_cell); @@ -621,6 +736,30 @@ void reintegrate(RTLIL::Module *module) bit_drivers[i].insert(mapped_cell->name); } + 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) + carry_in = port_name; + if (w->port_output) + carry_out = port_name; + } + else + r2.first->second.push_back(port_name); + } + + if (carry_in != IdString()) { + r2.first->second.push_back(carry_in); + r2.first->second.push_back(carry_out); + } + } + 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); @@ -807,16 +946,23 @@ struct Abc9OpsPass : public Pass { { log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); + bool check_mode = false; + bool prep_times_mode = false; bool break_scc_mode = false; bool unbreak_scc_mode = false; - bool prep_dff_mode = false; bool prep_holes_mode = false; + bool prep_dff_mode = false; + std::string write_box_src, write_box_dst; bool reintegrate_mode = false; bool dff_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; + if (arg == "-check") { + check_mode = true; + continue; + } if (arg == "-break_scc") { break_scc_mode = true; continue; @@ -833,6 +979,17 @@ struct Abc9OpsPass : public Pass { prep_holes_mode = true; continue; } + if (arg == "-prep_times") { + prep_times_mode = true; + continue; + } + if (arg == "-write_box" && argidx+2 < args.size()) { + write_box_src = args[++argidx]; + write_box_dst = args[++argidx]; + rewrite_filename(write_box_src); + rewrite_filename(write_box_dst); + continue; + } if (arg == "-reintegrate") { reintegrate_mode = true; continue; @@ -845,6 +1002,13 @@ struct Abc9OpsPass : public Pass { } extra_args(args, argidx, design); + // TODO: Check at least one mode given + + if (check_mode) + check(design); + if (prep_times_mode) + prep_times(design); + for (auto mod : design->selected_modules()) { if (mod->get_bool_attribute("\\abc9_holes")) continue; @@ -858,10 +1022,12 @@ struct Abc9OpsPass : public Pass { break_scc(mod); if (unbreak_scc_mode) unbreak_scc(mod); - if (prep_dff_mode) - prep_dff(mod); if (prep_holes_mode) prep_holes(mod, dff_mode); + if (prep_dff_mode) + prep_dff(mod); + if (!write_box_src.empty()) + write_box(mod, write_box_src, write_box_dst); if (reintegrate_mode) reintegrate(mod); } -- cgit v1.2.3 From e0af812180528c45e79291209e2e3726c98b80ae Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 10 Jan 2020 12:38:49 -0800 Subject: abc9_ops -prep_times: update comment --- passes/techmap/abc9_ops.cc | 7 ++++--- 1 file changed, 4 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 4d49bb4d2..14b3f6c43 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -485,9 +485,9 @@ void prep_times(RTLIL::Design *design) continue; if (!inst_module->get_blackbox_attribute()) continue; - // Flop inputs cannot have required times - // (required time should be captured by flop box) - // TODO: enforce this + // Only flop boxes are not combinatorial and may have required times, + // however those times are captured by this flop box, no need to + // add delay boxes if (cell->attributes.count(ID(abc9_box_id))) continue; boxes.emplace_back(cell); @@ -566,6 +566,7 @@ void write_box(RTLIL::Module *module, const std::string &src, const std::string ofs << "$__ABC9_DELAY@" << d << " " << ABC9_DELAY_BASE_ID + d << " 0 1 1" << std::endl; ofs << d << std::endl; } + module->attributes.erase(it); } ofs.close(); -- cgit v1.2.3 From 475d983676a42e57a104aaf5e72462d704c0c3aa Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 10 Jan 2020 14:49:52 -0800 Subject: abc9_ops -prep_times: generate flop boxes from abc9_required attr --- passes/techmap/abc9_ops.cc | 84 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 17 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 14b3f6c43..918afd284 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -39,9 +39,13 @@ void check(RTLIL::Design *design) { dict box_lookup; for (auto m : design->modules()) { + auto flop = m->get_bool_attribute(ID(abc9_flop)); auto it = m->attributes.find(ID(abc9_box_id)); - if (it == m->attributes.end()) + if (it == m->attributes.end()) { + if (flop) + log_error("Module '%s' contains (* abc9_flop *) but not (* abc9_box_id= *).\n", log_id(m)); continue; + } if (m->name.begins_with("$paramod")) continue; auto id = it->second.as_int(); @@ -59,21 +63,31 @@ void check(RTLIL::Design *design) 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)); + 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)); + log_error("Module '%s' contains more than one (* abc9_carry *) output port.\n", log_id(m)); carry_out = 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)); + 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)); + log_error("Module '%s' contains an (* abc9_carry *) output port but no input port.\n", log_id(m)); + + if (flop) { + int num_outputs = 0; + for (auto port_name : m->ports) { + auto wire = m->wire(port_name); + if (wire->port_output) num_outputs++; + } + if (num_outputs != 1) + log_error("Module '%s' with (* abc_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs); + } } } @@ -464,12 +478,10 @@ void prep_holes(RTLIL::Module *module, bool dff) void prep_times(RTLIL::Design *design) { std::set delays; + pool flops; std::vector boxes; std::map> requireds; for (auto module : design->selected_modules()) { - if (module->get_bool_attribute("\\abc9_holes")) - continue; - if (module->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(module)); continue; @@ -485,10 +497,13 @@ void prep_times(RTLIL::Design *design) continue; if (!inst_module->get_blackbox_attribute()) continue; - // Only flop boxes are not combinatorial and may have required times, - // however those times are captured by this flop box, no need to - // add delay boxes - if (cell->attributes.count(ID(abc9_box_id))) + if (inst_module->get_bool_attribute(ID(abc9_flop))) { + flops.insert(inst_module); + continue; + } + // All remaining boxes are combinatorial and cannot + // contain a required time + if (inst_module->attributes.count(ID(abc9_box_id))) continue; boxes.emplace_back(cell); } @@ -536,15 +551,48 @@ void prep_times(RTLIL::Design *design) std::stringstream ss; bool first = true; - for (auto d : delays) - if (first) { + for (auto d : delays) { + if (first) first = false; - ss << d; - } else - ss << " " << d; + ss << " "; + ss << d; + } module->attributes[ID(abc9_delays)] = ss.str(); } + + std::stringstream ss; + for (auto flop_module : flops) { + // Skip parameterised flop_modules for now (since we do not + // dynamically generate the abc9_box_id) + if (flop_module->name.begins_with("$paramod")) + continue; + + int num_inputs = 0, num_outputs = 0; + for (auto port_name : flop_module->ports) { + auto wire = flop_module->wire(port_name); + if (wire->port_input) num_inputs++; + if (wire->port_output) num_outputs++; + } + log_assert(num_outputs == 1); + + ss << log_id(flop_module) << " " << flop_module->attributes.at(ID(abc9_box_id)).as_int(); + ss << " 1 " << num_inputs+1 << " " << num_outputs << std::endl; + bool first = true; + for (auto port_name : flop_module->ports) { + auto wire = flop_module->wire(port_name); + if (!wire->port_input) + continue; + if (first) + first = false; + else + ss << " "; + ss << wire->attributes.at("\\abc9_required", 0).as_int(); + } + // Last input is 'abc9_ff.Q' + ss << " 0" << std::endl << std::endl; + } + design->scratchpad_set_string("abc9_ops.box.flops", ss.str()); } void write_box(RTLIL::Module *module, const std::string &src, const std::string &dst) { @@ -559,6 +607,8 @@ void write_box(RTLIL::Module *module, const std::string &src, const std::string ifs.close(); } + ofs << module->design->scratchpad_get_string("abc9_ops.box.flops"); + auto it = module->attributes.find(ID(abc9_delays)); if (it != module->attributes.end()) { for (const auto &tok : split_tokens(it->second.decode_string())) { -- cgit v1.2.3 From f24de88f385a3eeaadd9b9c8c200a7c338f37448 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 10 Jan 2020 17:13:27 -0800 Subject: log_debug() for abc9_{arrival,required} times --- passes/techmap/abc9_ops.cc | 8 +++++++- 1 file changed, 7 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 918afd284..eac1ff2b6 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -512,7 +512,7 @@ void prep_times(RTLIL::Design *design) requireds.clear(); for (auto cell : boxes) { RTLIL::Module* inst_module = module->design->module(cell->type); - + log_assert(inst_module); for (auto &conn : cell->connections_) { auto port_wire = inst_module->wire(conn.first); if (!port_wire->port_input) @@ -537,6 +537,12 @@ void prep_times(RTLIL::Design *design) SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); for (const auto &i : requireds) { +#ifndef NDEBUG + if (ys_debug(1)) { + static std::set> seen; + if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_required = %d\n", log_id(cell->type), log_id(conn.first), i.first); + } +#endif delays.insert(i.first); for (auto offset : i.second) { auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); -- 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 300003cb7854650cab9dd063a864f8f1df052d6d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 13:09:54 -0800 Subject: abc9_ops: discard $__ABC9_DELAY boxes --- passes/techmap/abc9_ops.cc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 04a54fd63..e1f6252f2 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -572,17 +572,12 @@ void reintegrate(RTLIL::Module *module) log_assert(r.second); } - pool delay_boxes; 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_))) + if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY))) module->remove(cell); - else if (cell->type.begins_with("$paramod$__ABC9_DELAY\\DELAY=")) { - delay_boxes.insert(cell->name); - module->remove(cell); - } else if (cell->attributes.erase("\\abc9_box_seq")) boxes.emplace_back(cell); } @@ -674,7 +669,7 @@ void reintegrate(RTLIL::Module *module) bit_drivers[i].insert(mapped_cell->name); } } - else if (delay_boxes.count(mapped_cell->name)) { + else if (mapped_cell->type == ID($__ABC9_DELAY)) { SigBit I = mapped_cell->getPort(ID(i)); SigBit O = mapped_cell->getPort(ID(o)); if (I.wire) -- cgit v1.2.3 From 593897ffc0b7bedfd65cdddf68dee6b89295b70b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 13:13:15 -0800 Subject: abc9_ops: cleanup --- passes/techmap/abc9_ops.cc | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index e1f6252f2..9b7901ffb 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -233,25 +233,15 @@ void prep_xaiger(RTLIL::Module *module, bool dff) 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)); + log_assert(w->port_input != w->port_output); + if (w->port_input) 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)); + else if (w->port_output) 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); @@ -723,9 +713,10 @@ void reintegrate(RTLIL::Module *module) auto w = box_module->wire(port_name); log_assert(w); if (w->get_bool_attribute("\\abc9_carry")) { + log_assert(w->port_input != w->port_output); if (w->port_input) carry_in = port_name; - if (w->port_output) + else if (w->port_output) carry_out = port_name; } else -- cgit v1.2.3 From ec95fbb273872ed41e2baadb644a311d31c3ee79 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 13:21:58 -0800 Subject: abc9_ops: -prep_times -> -prep_delays; add doc --- passes/techmap/abc9_ops.cc | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 9b7901ffb..af4073594 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -383,7 +383,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) } } -void prep_times(RTLIL::Design *design) +void prep_delays(RTLIL::Design *design) { std::set delays; pool flops; @@ -918,6 +918,14 @@ struct Abc9OpsPass : public Pass { 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(" -check\n"); + log(" check that the design is valid, e.g. (* abc9_box_id *) values are unique,\n"); + log(" (* abc9_carry *) is only given for one input/output port, etc.\n"); + log("\n"); + log(" -prep_delays\n"); + log(" insert `$__ABC9_DELAY' blackbox cells into the design to account for\n"); + log(" certain delays, e.g. (* abc9_required *) values.\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"); @@ -938,6 +946,10 @@ struct Abc9OpsPass : public Pass { 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(" -write_box (|(null)) \n"); + log(" copy the existing box file from (skip if '(null)') and append any\n"); + log(" new box definitions.\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"); @@ -949,7 +961,7 @@ struct Abc9OpsPass : public Pass { log_header(design, "Executing ABC9_OPS pass (helper functions for ABC9).\n"); bool check_mode = false; - bool prep_times_mode = false; + bool prep_delays_mode = false; bool mark_scc_mode = false; bool prep_dff_mode = false; bool prep_xaiger_mode = false; @@ -976,8 +988,8 @@ struct Abc9OpsPass : public Pass { prep_xaiger_mode = true; continue; } - if (arg == "-prep_times") { - prep_times_mode = true; + if (arg == "-prep_delays") { + prep_delays_mode = true; continue; } if (arg == "-write_box" && argidx+2 < args.size()) { @@ -999,16 +1011,16 @@ struct Abc9OpsPass : public Pass { } extra_args(args, argidx, design); - if (!(check_mode || mark_scc_mode || prep_times_mode || prep_xaiger_mode || prep_dff_mode || !write_box_src.empty() || reintegrate_mode)) - log_cmd_error("At least one of -check, -mark_scc, -prep_{times,xaiger,dff}, -write_box, -reintegrate must be specified.\n"); + if (!(check_mode || mark_scc_mode || prep_delays_mode || prep_xaiger_mode || prep_dff_mode || !write_box_src.empty() || reintegrate_mode)) + log_cmd_error("At least one of -check, -mark_scc, -prep_{delays,xaiger,dff}, -write_box, -reintegrate must be specified.\n"); if (dff_mode && !prep_xaiger_mode) log_cmd_error("'-dff' option is only relevant for -prep_xaiger.\n"); if (check_mode) check(design); - if (prep_times_mode) - prep_times(design); + if (prep_delays_mode) + prep_delays(design); for (auto mod : design->selected_modules()) { if (mod->get_bool_attribute("\\abc9_holes")) -- cgit v1.2.3 From b951ca9e1c25b0c9c021419c3e537c743dca6216 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 14:06:02 -0800 Subject: abc9_ops: fix -reintegrate handling of $__ABC9_DELAY --- passes/techmap/abc9_ops.cc | 5 +++-- 1 file changed, 3 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 af4073594..816c0276a 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -659,7 +659,7 @@ void reintegrate(RTLIL::Module *module) bit_drivers[i].insert(mapped_cell->name); } } - else if (mapped_cell->type == ID($__ABC9_DELAY)) { + else if (box_lookup.at(mapped_cell->type, IdString()) == ID($__ABC9_DELAY)) { SigBit I = mapped_cell->getPort(ID(i)); SigBit O = mapped_cell->getPort(ID(o)); if (I.wire) @@ -671,7 +671,8 @@ void reintegrate(RTLIL::Module *module) } else { RTLIL::Cell *existing_cell = module->cell(mapped_cell->name); - log_assert(existing_cell); + if (!existing_cell) + log_error("Cannot find existing box cell with name '%s' in original design.\n", log_id(mapped_cell)); log_assert(mapped_cell->type.begins_with("$__boxid")); auto type = box_lookup.at(mapped_cell->type, IdString()); -- 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 0e4285ca0d92397490768e649626cfdb5a0c9d95 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 15:05:49 -0800 Subject: abc9_ops: generate flop box ids, add abc9_required to FD* cells --- passes/techmap/abc9_ops.cc | 121 +++++++++++++++++++++------------------------ 1 file changed, 56 insertions(+), 65 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index a686bbd32..0c95f7ff6 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -23,6 +23,7 @@ #include "kernel/utils.h" #include "kernel/celltypes.h" +#define ABC9_FLOPS_BASE_ID 8000 #define ABC9_DELAY_BASE_ID 9000 USING_YOSYS_NAMESPACE @@ -39,20 +40,20 @@ void check(RTLIL::Design *design) { dict box_lookup; for (auto m : design->modules()) { + if (m->name.begins_with("$paramod")) + continue; + auto flop = m->get_bool_attribute(ID(abc9_flop)); auto it = m->attributes.find(ID(abc9_box_id)); - if (it == m->attributes.end()) { - if (flop) - log_error("Module '%s' contains (* abc9_flop *) but not (* abc9_box_id= *).\n", log_id(m)); - continue; + if (!flop) { + if (it == m->attributes.end()) + 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)); } - 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)); // Make carry in the last PI, and carry out the last PO // since ABC requires it this way @@ -217,13 +218,11 @@ void prep_xaiger(RTLIL::Module *module, bool dff) continue; auto inst_module = module->design->module(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; + bool abc9_flop = inst_module && inst_module->get_bool_attribute("\\abc9_flop"); + if (abc9_flop && !dff) + continue; + if ((inst_module && inst_module->attributes.count("\\abc9_box_id")) || abc9_flop) { auto r = box_ports.insert(cell->type); if (r.second) { // Make carry in the last PI, and carry out the last PO @@ -309,17 +308,17 @@ void prep_xaiger(RTLIL::Module *module, bool dff) cell->attributes["\\abc9_box_seq"] = box_count++; - IdString derived_name = box_module->derive(design, cell->parameters); - box_module = design->module(derived_name); + IdString derived_type = box_module->derive(design, cell->parameters); + box_module = design->module(derived_type); - auto r = cell_cache.insert(derived_name); + auto r = cell_cache.insert(derived_type); auto &holes_cell = r.first->second; if (r.second) { if (box_module->has_processes()) Pass::call_on_module(design, box_module, "proc"); if (box_module->get_bool_attribute("\\whitebox")) { - holes_cell = holes_module->addCell(cell->name, derived_name); + holes_cell = holes_module->addCell(cell->name, derived_type); if (box_module->has_processes()) Pass::call_on_module(design, box_module, "proc"); @@ -344,7 +343,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) } } else if (w->port_output) - conn = holes_module->addWire(stringf("%s.%s", derived_name.c_str(), log_id(port_name)), GetSize(w)); + conn = holes_module->addWire(stringf("%s.%s", derived_type.c_str(), log_id(port_name)), GetSize(w)); } // For flops only, create an extra 1-bit input that drives a new wire @@ -387,7 +386,7 @@ void prep_delays(RTLIL::Design *design) { std::set delays; pool flops; - std::vector boxes; + std::vector cells; std::map> requireds; for (auto module : design->selected_modules()) { if (module->processes.size() > 0) { @@ -395,7 +394,7 @@ void prep_delays(RTLIL::Design *design) continue; } - boxes.clear(); + cells.clear(); for (auto cell : module->cells()) { if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_), ID($__ABC9_DELAY))) continue; @@ -406,19 +405,21 @@ void prep_delays(RTLIL::Design *design) if (!inst_module->get_blackbox_attribute()) continue; if (inst_module->get_bool_attribute(ID(abc9_flop))) { + IdString derived_type = inst_module->derive(design, cell->parameters); + inst_module = design->module(derived_type); + log_assert(inst_module); flops.insert(inst_module); - continue; + continue; // because all flop required times + // will be captured in the flop box } - // All remaining boxes are combinatorial and cannot - // contain a required time if (inst_module->attributes.count(ID(abc9_box_id))) continue; - boxes.emplace_back(cell); + cells.emplace_back(cell); } delays.clear(); requireds.clear(); - for (auto cell : boxes) { + for (auto cell : cells) { RTLIL::Module* inst_module = module->design->module(cell->type); log_assert(inst_module); for (auto &conn : cell->connections_) { @@ -475,13 +476,9 @@ void prep_delays(RTLIL::Design *design) module->attributes[ID(abc9_delays)] = ss.str(); } + int flops_id = ABC9_FLOPS_BASE_ID; std::stringstream ss; for (auto flop_module : flops) { - // Skip parameterised flop_modules for now (since we do not - // dynamically generate the abc9_box_id) - if (flop_module->name.begins_with("$paramod")) - continue; - int num_inputs = 0, num_outputs = 0; for (auto port_name : flop_module->ports) { auto wire = flop_module->wire(port_name); @@ -490,7 +487,11 @@ void prep_delays(RTLIL::Design *design) } log_assert(num_outputs == 1); - ss << log_id(flop_module) << " " << flop_module->attributes.at(ID(abc9_box_id)).as_int(); + auto r = flop_module->attributes.insert(ID(abc9_box_id)); + if (r.second) + r.first->second = flops_id++; + + ss << log_id(flop_module) << " " << r.first->second.as_int(); ss << " 1 " << num_inputs+1 << " " << num_outputs << std::endl; bool first = true; for (auto port_name : flop_module->ports) { @@ -550,23 +551,11 @@ void reintegrate(RTLIL::Module *module) for (auto w : mapped_mod->wires()) module->addWire(remap_name(w->name), GetSize(w)); - dict box_lookup; - 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 YS_ATTRIBUTE(unused) = box_lookup.insert(std::make_pair(stringf("$__boxid%d", id), m->name)); - log_assert(r.second); - } - 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_), ID($__ABC9_DELAY))) + 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); @@ -659,26 +648,29 @@ void reintegrate(RTLIL::Module *module) bit_drivers[i].insert(mapped_cell->name); } } - else if (box_lookup.at(mapped_cell->type, IdString()) == ID($__ABC9_DELAY)) { - SigBit I = mapped_cell->getPort(ID(i)); - SigBit O = mapped_cell->getPort(ID(o)); - if (I.wire) - I.wire = module->wires_.at(remap_name(I.wire->name)); - log_assert(O.wire); - O.wire = module->wires_.at(remap_name(O.wire->name)); - module->connect(O, I); - continue; - } else { RTLIL::Cell *existing_cell = module->cell(mapped_cell->name); if (!existing_cell) log_error("Cannot find existing box cell with name '%s' in original design.\n", log_id(mapped_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; +#ifndef NDEBUG + RTLIL::Module* box_module = design->module(existing_cell->type); + IdString derived_type = box_module->derive(design, existing_cell->parameters); + RTLIL::Module* derived_module = design->module(derived_type); + log_assert(derived_module); + log_assert(mapped_cell->type == stringf("$__boxid%d", derived_module->attributes.at("\\abc9_box_id").as_int())); +#endif + mapped_cell->type = existing_cell->type; + + if (mapped_cell->type == ID($__ABC9_DELAY)) { + SigBit I = mapped_cell->getPort(ID(i)); + SigBit O = mapped_cell->getPort(ID(o)); + if (I.wire) + I.wire = module->wires_.at(remap_name(I.wire->name)); + log_assert(O.wire); + O.wire = module->wires_.at(remap_name(O.wire->name)); + module->connect(O, I); + continue; + } RTLIL::Cell *cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type); cell->parameters = existing_cell->parameters; @@ -694,7 +686,6 @@ void reintegrate(RTLIL::Module *module) 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) -- cgit v1.2.3 From 1c88a6c24084743c95db9fb21c2b429a3736fb77 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 15:20:04 -0800 Subject: abc9_ops: implement a requireds_cache --- passes/techmap/abc9_ops.cc | 60 ++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 26 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 0c95f7ff6..1de95128f 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -387,7 +387,7 @@ void prep_delays(RTLIL::Design *design) std::set delays; pool flops; std::vector cells; - std::map> requireds; + dict>> requireds_cache; for (auto module : design->selected_modules()) { if (module->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(module)); @@ -418,48 +418,56 @@ void prep_delays(RTLIL::Design *design) } delays.clear(); - requireds.clear(); for (auto cell : cells) { RTLIL::Module* inst_module = module->design->module(cell->type); log_assert(inst_module); + auto &cell_requireds = requireds_cache[cell->type]; for (auto &conn : cell->connections_) { auto port_wire = inst_module->wire(conn.first); if (!port_wire->port_input) continue; - auto it = port_wire->attributes.find("\\abc9_required"); - if (it == port_wire->attributes.end()) - continue; - - int count = 0; - requireds.clear(); - if (it->second.flags == 0) { - count = 1; - requireds[it->second.as_int()].push_back(0); + auto r = cell_requireds.insert(conn.first); + auto &requireds = r.first->second; + if (r.second) { + auto it = port_wire->attributes.find("\\abc9_required"); + if (it == port_wire->attributes.end()) + continue; + if (it->second.flags == 0) { + int delay = it->second.as_int(); + delays.insert(delay); + requireds.emplace_back(delay); + } + else + for (const auto &tok : split_tokens(it->second.decode_string())) { + int delay = atoi(tok.c_str()); + delays.insert(delay); + requireds.push_back(delay); + } } - else - for (const auto &tok : split_tokens(it->second.decode_string())) - requireds[atoi(tok.c_str())].push_back(count++); - if (count > 1 && count != GetSize(port_wire)) + + if (requireds.empty()) + continue; + if (GetSize(requireds) > 1 && GetSize(requireds) != GetSize(port_wire)) log_error("%s.%s is %d bits wide but abc9_required = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first), - GetSize(port_wire), log_signal(it->second), count); + GetSize(port_wire), log_signal(port_wire->attributes.at("\\abc9_required")), GetSize(requireds)); SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); - for (const auto &i : requireds) { + auto it = requireds.begin(); + for (int i = 0; i < GetSize(conn.second); ++i) { #ifndef NDEBUG if (ys_debug(1)) { static std::set> seen; - if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_required = %d\n", log_id(cell->type), log_id(conn.first), i.first); + if (seen.emplace(cell->type, conn.first).second) log("%s.%s abc9_required = %d\n", log_id(cell->type), log_id(conn.first), requireds[i]); } #endif - delays.insert(i.first); - for (auto offset : i.second) { - auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); - box->setPort(ID(I), conn.second[offset]); - box->setPort(ID(O), O[offset]); - box->setParam(ID(DELAY), i.first); - conn.second[offset] = O[offset]; - } + auto box = module->addCell(NEW_ID, ID($__ABC9_DELAY)); + box->setPort(ID(I), conn.second[i]); + box->setPort(ID(O), O[i]); + box->setParam(ID(DELAY), *it); + if (requireds.size() > 1) + it++; + conn.second[i] = O[i]; } } } -- cgit v1.2.3 From f60e071e1c3ab64d1a45c4aea3580027b4242908 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 15:24:44 -0800 Subject: abc9_ops: -check to check abc9_{arrival,required} --- passes/techmap/abc9_ops.cc | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 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 1de95128f..4d05b5afb 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -73,6 +73,36 @@ void check(RTLIL::Design *design) carry_out = port_name; } } + + auto it = w->attributes.find("\\abc9_arrival"); + if (it != w->attributes.end()) { + int count = 0; + if (it->second.flags == 0) + count++; + else + for (const auto &tok : split_tokens(it->second.decode_string())) { + (void) tok; + count++; + } + if (count > 1 && count != GetSize(w)) + log_error("%s.%s is %d bits wide but abc9_arrival = %s has %d value(s)!\n", log_id(m), log_id(port_name), + GetSize(w), log_signal(it->second), count); + } + + it = w->attributes.find("\\abc9_required"); + if (it != w->attributes.end()) { + int count = 0; + if (it->second.flags == 0) + count++; + else + for (const auto &tok : split_tokens(it->second.decode_string())) { + (void) tok; + count++; + } + if (count > 1 && count != GetSize(w)) + log_error("%s.%s is %d bits wide but abc9_required = %s has %d value(s)!\n", log_id(m), log_id(port_name), + GetSize(w), log_signal(it->second), count); + } } if (carry_in != IdString() && carry_out == IdString()) @@ -448,9 +478,6 @@ void prep_delays(RTLIL::Design *design) if (requireds.empty()) continue; - if (GetSize(requireds) > 1 && GetSize(requireds) != GetSize(port_wire)) - log_error("%s.%s is %d bits wide but abc9_required = %s has %d value(s)!\n", log_id(cell->type), log_id(conn.first), - GetSize(port_wire), log_signal(port_wire->attributes.at("\\abc9_required")), GetSize(requireds)); SigSpec O = module->addWire(NEW_ID, GetSize(conn.second)); auto it = requireds.begin(); -- cgit v1.2.3 From 485e08e4363f2aa93204f8bcc6c1ff5243936ea6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Jan 2020 16:33:41 -0800 Subject: abc9_ops: cope with (* abc9_flop *) in place of (* abc9_box_id *) --- passes/techmap/abc9_ops.cc | 4 ++-- 1 file changed, 2 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 4d05b5afb..fd2759ae5 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -117,7 +117,7 @@ void check(RTLIL::Design *design) if (wire->port_output) num_outputs++; } if (num_outputs != 1) - log_error("Module '%s' with (* abc_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs); + log_error("Module '%s' with (* abc9_flop *) has %d outputs (expect 1).\n", log_id(m), num_outputs); } } } @@ -333,7 +333,7 @@ void prep_xaiger(RTLIL::Module *module, bool dff) log_assert(cell); RTLIL::Module* box_module = design->module(cell->type); - if (!box_module || !box_module->attributes.count("\\abc9_box_id")) + if (!box_module || (!box_module->attributes.count("\\abc9_box_id") && !box_module->get_bool_attribute("\\abc9_flop"))) continue; cell->attributes["\\abc9_box_seq"] = box_count++; -- cgit v1.2.3 From 5a63c197477d59567424faab3b56329c426394b9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 15 Jan 2020 13:14:48 -0800 Subject: abc9_ops: -write_box is empty, output a dummy box to prevent ABC error --- passes/techmap/abc9_ops.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index fd2759ae5..13340f311 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -569,6 +569,9 @@ void write_box(RTLIL::Module *module, const std::string &src, const std::string module->attributes.erase(it); } + if (ofs.tellp() == 0) + ofs << "(dummy) 1 0 0 0"; + ofs.close(); } -- 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 From 21ce1b37fbc93562942c10f631c7f415f8fdba2e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 27 Jan 2020 14:22:46 -0800 Subject: abc9_ops: -check for negative arrival/required times --- passes/techmap/abc9_ops.cc | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'passes/techmap/abc9_ops.cc') diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 0fc4de3bb..2b4a5c802 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -77,11 +77,20 @@ void check(RTLIL::Design *design) auto it = w->attributes.find("\\abc9_arrival"); if (it != w->attributes.end()) { int count = 0; - if (it->second.flags == 0) + if (it->second.flags == 0) { + if (it->second.as_int() < 0) + log_error("%s.%s has negative arrival value %d!\n", log_id(m), log_id(port_name), + it->second.as_int()); count++; + } else for (const auto &tok : split_tokens(it->second.decode_string())) { - (void) tok; + if (tok.find_first_not_of("0123456789") != std::string::npos) + log_error("%s.%s has non-integer arrival value '%s'!\n", log_id(m), log_id(port_name), + tok.c_str()); + if (atoi(tok.c_str()) < 0) + log_error("%s.%s has negative arrival value %s!\n", log_id(m), log_id(port_name), + tok.c_str()); count++; } if (count > 1 && count != GetSize(w)) @@ -92,11 +101,20 @@ void check(RTLIL::Design *design) it = w->attributes.find("\\abc9_required"); if (it != w->attributes.end()) { int count = 0; - if (it->second.flags == 0) + if (it->second.flags == 0) { + if (it->second.as_int() < 0) + log_error("%s.%s has negative required value %d!\n", log_id(m), log_id(port_name), + it->second.as_int()); count++; + } else for (const auto &tok : split_tokens(it->second.decode_string())) { - (void) tok; + if (tok.find_first_not_of("0123456789") != std::string::npos) + log_error("%s.%s has non-integer required value '%s'!\n", log_id(m), log_id(port_name), + tok.c_str()); + if (atoi(tok.c_str()) < 0) + log_error("%s.%s has negative required value %s!\n", log_id(m), log_id(port_name), + tok.c_str()); count++; } if (count > 1 && count != GetSize(w)) -- cgit v1.2.3