diff --git a/backends/aiger2/aiger.cc b/backends/aiger2/aiger.cc index d205f8508..5e58a9ebc 100644 --- a/backends/aiger2/aiger.cc +++ b/backends/aiger2/aiger.cc @@ -19,6 +19,7 @@ // TODOs: // - gracefully handling inout ports (an error message probably) +// - undriven wires #include "kernel/register.h" #include "kernel/celltypes.h" @@ -56,6 +57,7 @@ struct Index { int len; dict windices; dict suboffsets; + pool found_blackboxes; bool indexing = false; bool indexed = false; @@ -73,6 +75,10 @@ struct Index { return sum; } + bool flatten = false; + bool inline_whiteboxes = false; + bool allow_blackboxes = false; + int index_module(RTLIL::Module *m) { ModuleInfo &info = modules[m]; @@ -91,11 +97,21 @@ struct Index { continue; Module *submodule = m->design->module(cell->type); - if (!submodule || submodule->get_blackbox_attribute()) - log_error("Unsupported cell type: %s (%s in %s)\n", - log_id(cell->type), log_id(cell), log_id(m)); - info.suboffsets[cell] = pos; - pos += index_module(submodule); + + if (submodule && flatten && + !submodule->get_bool_attribute(ID::keep_hierarchy) && + !submodule->get_blackbox_attribute(inline_whiteboxes)) { + info.suboffsets[cell] = pos; + pos += index_module(submodule); + } else { + if (allow_blackboxes) { + info.found_blackboxes.insert(cell); + } else { + if (!submodule || submodule->get_blackbox_attribute()) + log_error("Unsupported cell type: %s (%s in %s)\n", + log_id(cell->type), log_id(cell), log_id(m)); + } + } } info.len = pos; @@ -429,30 +445,36 @@ struct Index { std::vector levels; int instance_offset = 0; - HierCursor(ModuleInfo &top) + HierCursor() { - levels.push_back(Level(top, nullptr)); } - ModuleInfo ¤t_minfo() + ModuleInfo &leaf_minfo(Index &index) { - log_assert(!levels.empty()); - return levels.back().first; + if (levels.empty()) + return *index.top_minfo; + else + return levels.back().first; } - int bitwire_index(SigBit bit) + Module *leaf_module(Index &index) + { + return leaf_minfo(index).module; + } + + int bitwire_index(Index &index, SigBit bit) { log_assert(bit.wire != nullptr); - return instance_offset + current_minfo().windices[bit.wire] + bit.offset; + return instance_offset + leaf_minfo(index).windices[bit.wire] + bit.offset; } - Cell *exit() + Cell *exit(Index &index) { - log_assert(levels.size() > 1); + log_assert(!levels.empty()); Cell *instance = levels.back().second; levels.pop_back(); - instance_offset -= current_minfo().suboffsets.at(instance); + instance_offset -= leaf_minfo(index).suboffsets.at(instance); // return the instance we just exited return instance; @@ -461,7 +483,7 @@ struct Index { Module *enter(Index &index, Cell *cell) { Design *design = index.design; - auto &minfo = current_minfo(); + auto &minfo = leaf_minfo(index); log_assert(minfo.suboffsets.count(cell)); Module *def = design->module(cell->type); log_assert(def); @@ -471,6 +493,47 @@ struct Index { // return the module definition we just entered return def; } + + bool is_top() + { + return levels.empty(); + } + + std::string path() + { + std::string ret; + bool first = true; + for (auto pair : levels) { + if (!first) + ret += "."; + if (!pair.second) + ret += RTLIL::unescape_id(pair.first.module->name); + else + ret += RTLIL::unescape_id(pair.second->name); + first = false; + } + return ret; + } + + int hash() const + { + int hash = 0; + for (auto pair : levels) + hash += (uintptr_t) pair.second; + return hash; + } + + bool operator==(const HierCursor &other) const + { + if (levels.size() != other.levels.size()) + return false; + + for (int i = 0; i < levels.size(); i++) + if (levels[i].second != other.levels[i].second) + return false; + + return true; + } }; Lit visit(HierCursor &cursor, SigBit bit) @@ -484,7 +547,7 @@ struct Index { log_error("Unhandled state %s\n", log_signal(bit)); } - int idx = cursor.bitwire_index(bit); + int idx = cursor.bitwire_index(*this, bit); if (lits[idx] != Writer::EMPTY_LIT) { // literal already assigned return lits[idx]; @@ -510,16 +573,15 @@ struct Index { bit.offset, log_id(portname), log_id(driver), log_id(def), w->width); ret = visit(cursor, SigBit(w, bit.offset)); } - cursor.exit(); + cursor.exit(*this); } - } else { // a module input: we cannot be the top module, otherwise // the branch for pre-existing literals would have been taken - log_assert(cursor.levels.size() > 1); + log_assert(!cursor.is_top()); // step into the upper module - Cell *instance = cursor.exit(); + Cell *instance = cursor.exit(*this); { IdString portname = bit.wire->name; if (!instance->hasPort(portname)) @@ -538,23 +600,54 @@ struct Index { return ret; } - void set_top_port(SigBit bit, Lit lit) + Lit &pi_literal(SigBit bit, HierCursor *cursor=nullptr) { log_assert(bit.wire); - log_assert(bit.wire->module == top); - log_assert(bit.wire->port_input); - lits[top_minfo->windices[bit.wire] + bit.offset] = lit; + if (!cursor) { + log_assert(bit.wire->module == top); + log_assert(bit.wire->port_input); + return lits[top_minfo->windices[bit.wire] + bit.offset]; + } else { + log_assert(bit.wire->module == cursor->leaf_module(*this)); + return lits[cursor->bitwire_index(*this, bit)]; + } } - Lit get_top_port(SigBit bit) + Lit eval_po(SigBit bit, HierCursor *cursor=nullptr) { - HierCursor cursor(*top_minfo); - Lit ret = visit(cursor, bit); - log_assert(cursor.levels.size() == 1); - log_assert(cursor.instance_offset == 0); + Lit ret; + if (!cursor) { + HierCursor cursor_; + ret = visit(cursor_, bit); + log_assert(cursor_.is_top()); + log_assert(cursor_.instance_offset == 0); + } else { + ret = visit(*cursor, bit); + } return ret; } + + void visit_hierarchy(std::function f, + HierCursor &cursor) + { + f(cursor); + + ModuleInfo &minfo = cursor.leaf_minfo(*this); + for (auto cell : minfo.module->cells()) { + if (minfo.suboffsets.count(cell)) { + cursor.enter(*this, cell); + visit_hierarchy(f, cursor); + cursor.exit(*this); + } + } + } + + void visit_hierarchy(std::function f) + { + HierCursor cursor; + visit_hierarchy(f, cursor); + } }; struct AigerWriter : Index { @@ -616,20 +709,25 @@ struct AigerWriter : Index { // populate inputs std::vector inputs; - for (auto w : top->wires()) + for (auto id : top->ports) { + Wire *w = top->wire(id); + log_assert(w); if (w->port_input) for (int i = 0; i < w->width; i++) { - set_top_port(SigBit(w, i), lit_counter); + pi_literal(SigBit(w, i)) = lit_counter; inputs.push_back(SigBit(w, i)); lit_counter += 2; ninputs++; } + } this->f = f; // start with the header write_header(); // insert padding where output literals will go (once known) - for (auto w : top->wires()) + for (auto id : top->ports) { + Wire *w = top->wire(id); + log_assert(w); if (w->port_output) { for (auto bit : SigSpec(w)) { (void) bit; @@ -639,6 +737,7 @@ struct AigerWriter : Index { noutputs++; } } + } auto data_start = f->tellp(); // now the guts @@ -646,7 +745,7 @@ struct AigerWriter : Index { for (auto w : top->wires()) if (w->port_output) { for (auto bit : SigSpec(w)) - outputs.push_back({bit, get_top_port(bit)}); + outputs.push_back({bit, eval_po(bit)}); } auto data_end = f->tellp(); @@ -749,6 +848,8 @@ struct Aiger2Backend : Backend { for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-strash") writer.strashing = true; + else if (args[argidx] == "-flatten") + writer.flatten = true; else break; } @@ -791,12 +892,12 @@ struct AIGCounter : Index { for (auto w : top->wires()) if (w->port_input) for (int i = 0; i < w->width; i++) - set_top_port(SigBit(w, i), ++nvars); + pi_literal(SigBit(w, i)) = ++nvars; for (auto w : top->wires()) if (w->port_output) { for (auto bit : SigSpec(w)) - (void) get_top_port(bit); + (void) eval_po(bit); } } }; @@ -808,10 +909,12 @@ struct AigsizePass : Pass { log_header(design, "Executing AIGSIZE pass. (size design AIG)\n"); size_t argidx; - AIGCounter counter; + AIGCounter writer; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-strash") - counter.strashing = true; + writer.strashing = true; + else if (args[argidx] == "-flatten") + writer.flatten = true; else break; } @@ -823,9 +926,9 @@ struct AigsizePass : Pass { log_cmd_error("No top module selected\n"); design->bufNormalize(true); - counter.setup(top); - counter.count(); - log("Counted %d gates\n", counter.ngates); + writer.setup(top); + writer.count(); + log("Counted %d gates\n", writer.ngates); // we are leaving the sacred land, un-bufnormalize // (if not, this will lead to bugs: the buf-normalized diff --git a/tests/various/aiger2.ys b/tests/various/aiger2.ys index 0efb5dd76..e008cdfaf 100644 --- a/tests/various/aiger2.ys +++ b/tests/various/aiger2.ys @@ -158,7 +158,7 @@ copy test gold flatten gold techmap submodule1 select test -write_aiger2 aiger2_ops.aig +write_aiger2 -flatten aiger2_ops.aig select -clear delete test read_aiger -module_name test aiger2_ops.aig