From b42b64e8ed713b0e9810f18db7cafcf356e2b4f6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 30 Dec 2019 19:23:54 -0800 Subject: [PATCH] Move Pass::call() out of abc9_ops into abc9 --- backends/aiger/xaiger.cc | 4 ++ passes/techmap/abc9.cc | 14 ++++- passes/techmap/abc9_ops.cc | 113 +++++++++++++++---------------------- 3 files changed, 63 insertions(+), 68 deletions(-) diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc index 9e0a56963..830c86787 100644 --- a/backends/aiger/xaiger.cc +++ b/backends/aiger/xaiger.cc @@ -710,6 +710,10 @@ struct XAigerWriter RTLIL::Module *holes_module = module->design->module(stringf("%s$holes", module->name.c_str())); log_assert(holes_module); + for (auto cell : holes_module->cells()) + if (!cell->type.in("$_NOT_", "$_AND_")) + log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n"); + module->design->selection_stack.emplace_back(false); module->design->selection().select(holes_module); diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index e11b15065..7d922df56 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -185,11 +185,21 @@ struct Abc9Pass : public ScriptPass void script() YS_OVERRIDE { + run("abc9_ops -prep_holes"); + run("select -set abc9_holes A:abc9_holes"); + run("flatten -wb @abc9_holes"); + run("techmap @abc9_holes"); + run("aigmap @abc9_holes"); + run("select -list @abc9_holes"); + run("abc9_ops -prep_dff"); + run("opt -purge @abc9_holes"); + run("setattr -mod -set whitebox 1 @abc9_holes"); + auto selected_modules = active_design->selected_modules(); active_design->selection_stack.emplace_back(false); for (auto mod : selected_modules) { - if (mod->attributes.count(ID(abc9_box_id))) + if (mod->get_blackbox_attribute()) continue; if (mod->processes.size() > 0) { @@ -207,7 +217,7 @@ struct Abc9Pass : public ScriptPass tempdir_name = make_temp_dir(tempdir_name); run("scc -set_attr abc9_scc_id {}"); - run("abc9_ops -break_scc -prep_dff -prep_holes"); + run("abc9_ops -break_scc"); run("aigmap"); run(stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str()), "write_xaiger -map /input.sym /input.xaig"); 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)); -- 2.30.2