From db08afe146b885777bb1bfa2260c090d9554afe3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 8 Feb 2019 14:53:12 -0800 Subject: [PATCH] Copy backends/aiger/aiger.cc to xaiger.cc --- backends/aiger/xaiger.cc | 788 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 788 insertions(+) create mode 100644 backends/aiger/xaiger.cc diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc new file mode 100644 index 000000000..dfe506c66 --- /dev/null +++ b/backends/aiger/xaiger.cc @@ -0,0 +1,788 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * 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/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +void aiger_encode(std::ostream &f, int x) +{ + log_assert(x >= 0); + + while (x & ~0x7f) { + f.put((x & 0x7f) | 0x80); + x = x >> 7; + } + + f.put(x); +} + +struct AigerWriter +{ + Module *module; + bool zinit_mode; + SigMap sigmap; + + dict init_map; + pool input_bits, output_bits; + dict not_map, ff_map, alias_map; + dict> and_map; + vector> asserts, assumes; + vector> liveness, fairness; + pool initstate_bits; + + vector> aig_gates; + vector aig_latchin, aig_latchinit, aig_outputs; + int aig_m = 0, aig_i = 0, aig_l = 0, aig_o = 0, aig_a = 0; + int aig_b = 0, aig_c = 0, aig_j = 0, aig_f = 0; + + dict aig_map; + dict ordered_outputs; + dict ordered_latches; + + dict init_inputs; + int initstate_ff = 0; + + int mkgate(int a0, int a1) + { + aig_m++, aig_a++; + aig_gates.push_back(a0 > a1 ? make_pair(a0, a1) : make_pair(a1, a0)); + return 2*aig_m; + } + + int bit2aig(SigBit bit) + { + if (aig_map.count(bit) == 0) + { + aig_map[bit] = -1; + + if (initstate_bits.count(bit)) { + log_assert(initstate_ff > 0); + aig_map[bit] = initstate_ff; + } else + if (not_map.count(bit)) { + int a = bit2aig(not_map.at(bit)) ^ 1; + aig_map[bit] = a; + } else + if (and_map.count(bit)) { + auto args = and_map.at(bit); + int a0 = bit2aig(args.first); + int a1 = bit2aig(args.second); + aig_map[bit] = mkgate(a0, a1); + } else + if (alias_map.count(bit)) { + aig_map[bit] = bit2aig(alias_map.at(bit)); + } + + if (bit == State::Sx || bit == State::Sz) + log_error("Design contains 'x' or 'z' bits. Use 'setundef' to replace those constants.\n"); + } + + log_assert(aig_map.at(bit) >= 0); + return aig_map.at(bit); + } + + AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode) : module(module), zinit_mode(zinit_mode), sigmap(module) + { + pool undriven_bits; + pool unused_bits; + + // promote public wires + for (auto wire : module->wires()) + if (wire->name[0] == '\\') + sigmap.add(wire); + + // promote input wires + for (auto wire : module->wires()) + if (wire->port_input) + sigmap.add(wire); + + // promote output wires + for (auto wire : module->wires()) + if (wire->port_output) + sigmap.add(wire); + + for (auto wire : module->wires()) + { + if (wire->attributes.count("\\init")) { + SigSpec initsig = sigmap(wire); + Const initval = wire->attributes.at("\\init"); + for (int i = 0; i < GetSize(wire) && i < GetSize(initval); i++) + if (initval[i] == State::S0 || initval[i] == State::S1) + init_map[initsig[i]] = initval[i] == State::S1; + } + + for (int i = 0; i < GetSize(wire); i++) + { + SigBit wirebit(wire, i); + SigBit bit = sigmap(wirebit); + + if (bit.wire == nullptr) { + if (wire->port_output) { + aig_map[wirebit] = (bit == State::S1) ? 1 : 0; + output_bits.insert(wirebit); + } + continue; + } + + undriven_bits.insert(bit); + unused_bits.insert(bit); + + if (wire->port_input) + input_bits.insert(bit); + + if (wire->port_output) { + if (bit != wirebit) + alias_map[wirebit] = bit; + output_bits.insert(wirebit); + } + } + } + + for (auto bit : input_bits) + undriven_bits.erase(bit); + + for (auto bit : output_bits) + unused_bits.erase(bit); + + for (auto cell : module->cells()) + { + if (cell->type == "$_NOT_") + { + SigBit A = sigmap(cell->getPort("\\A").as_bit()); + SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); + unused_bits.erase(A); + undriven_bits.erase(Y); + not_map[Y] = A; + continue; + } + + if (cell->type.in("$_FF_", "$_DFF_N_", "$_DFF_P_")) + { + SigBit D = sigmap(cell->getPort("\\D").as_bit()); + SigBit Q = sigmap(cell->getPort("\\Q").as_bit()); + unused_bits.erase(D); + undriven_bits.erase(Q); + ff_map[Q] = D; + 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()); + unused_bits.erase(A); + unused_bits.erase(B); + undriven_bits.erase(Y); + and_map[Y] = make_pair(A, B); + continue; + } + + if (cell->type == "$initstate") + { + SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); + undriven_bits.erase(Y); + initstate_bits.insert(Y); + continue; + } + + if (cell->type == "$assert") + { + SigBit A = sigmap(cell->getPort("\\A").as_bit()); + SigBit EN = sigmap(cell->getPort("\\EN").as_bit()); + unused_bits.erase(A); + unused_bits.erase(EN); + asserts.push_back(make_pair(A, EN)); + continue; + } + + if (cell->type == "$assume") + { + SigBit A = sigmap(cell->getPort("\\A").as_bit()); + SigBit EN = sigmap(cell->getPort("\\EN").as_bit()); + unused_bits.erase(A); + unused_bits.erase(EN); + assumes.push_back(make_pair(A, EN)); + continue; + } + + if (cell->type == "$live") + { + SigBit A = sigmap(cell->getPort("\\A").as_bit()); + SigBit EN = sigmap(cell->getPort("\\EN").as_bit()); + unused_bits.erase(A); + unused_bits.erase(EN); + liveness.push_back(make_pair(A, EN)); + continue; + } + + if (cell->type == "$fair") + { + SigBit A = sigmap(cell->getPort("\\A").as_bit()); + SigBit EN = sigmap(cell->getPort("\\EN").as_bit()); + unused_bits.erase(A); + unused_bits.erase(EN); + fairness.push_back(make_pair(A, EN)); + continue; + } + + if (cell->type == "$anyconst") + { + for (auto bit : sigmap(cell->getPort("\\Y"))) { + undriven_bits.erase(bit); + ff_map[bit] = bit; + } + continue; + } + + if (cell->type == "$anyseq") + { + for (auto bit : sigmap(cell->getPort("\\Y"))) { + undriven_bits.erase(bit); + input_bits.insert(bit); + } + continue; + } + + log_error("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell)); + } + + for (auto bit : unused_bits) + undriven_bits.erase(bit); + + if (!undriven_bits.empty()) { + undriven_bits.sort(); + for (auto bit : undriven_bits) { + log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit)); + input_bits.insert(bit); + } + log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module)); + } + + init_map.sort(); + input_bits.sort(); + output_bits.sort(); + not_map.sort(); + ff_map.sort(); + and_map.sort(); + + aig_map[State::S0] = 0; + aig_map[State::S1] = 1; + + for (auto bit : input_bits) { + aig_m++, aig_i++; + aig_map[bit] = 2*aig_m; + } + + if (imode && input_bits.empty()) { + aig_m++, aig_i++; + } + + if (zinit_mode) + { + for (auto it : ff_map) { + if (init_map.count(it.first)) + continue; + aig_m++, aig_i++; + init_inputs[it.first] = 2*aig_m; + } + } + + int fair_live_inputs_cnt = GetSize(liveness); + int fair_live_inputs_m = aig_m; + + aig_m += fair_live_inputs_cnt; + aig_i += fair_live_inputs_cnt; + + for (auto it : ff_map) { + aig_m++, aig_l++; + aig_map[it.first] = 2*aig_m; + ordered_latches[it.first] = aig_l-1; + if (init_map.count(it.first) == 0) + aig_latchinit.push_back(2); + else + aig_latchinit.push_back(init_map.at(it.first) ? 1 : 0); + } + + if (!initstate_bits.empty() || !init_inputs.empty()) { + aig_m++, aig_l++; + initstate_ff = 2*aig_m+1; + aig_latchinit.push_back(0); + } + + int fair_live_latches_cnt = GetSize(fairness) + 2*GetSize(liveness); + int fair_live_latches_m = aig_m; + int fair_live_latches_l = aig_l; + + aig_m += fair_live_latches_cnt; + aig_l += fair_live_latches_cnt; + + for (int i = 0; i < fair_live_latches_cnt; i++) + aig_latchinit.push_back(0); + + if (zinit_mode) + { + for (auto it : ff_map) + { + int l = ordered_latches[it.first]; + + if (aig_latchinit.at(l) == 1) + aig_map[it.first] ^= 1; + + if (aig_latchinit.at(l) == 2) + { + int gated_ffout = mkgate(aig_map[it.first], initstate_ff^1); + int gated_initin = mkgate(init_inputs[it.first], initstate_ff); + aig_map[it.first] = mkgate(gated_ffout^1, gated_initin^1)^1; + } + } + } + + for (auto it : ff_map) { + int a = bit2aig(it.second); + int l = ordered_latches[it.first]; + if (zinit_mode && aig_latchinit.at(l) == 1) + aig_latchin.push_back(a ^ 1); + else + aig_latchin.push_back(a); + } + + if (!initstate_bits.empty() || !init_inputs.empty()) + aig_latchin.push_back(1); + + for (auto bit : output_bits) { + aig_o++; + ordered_outputs[bit] = aig_o-1; + aig_outputs.push_back(bit2aig(bit)); + } + + if (omode && output_bits.empty()) { + aig_o++; + aig_outputs.push_back(0); + } + + for (auto it : asserts) { + aig_b++; + int bit_a = bit2aig(it.first); + int bit_en = bit2aig(it.second); + aig_outputs.push_back(mkgate(bit_a^1, bit_en)); + } + + if (bmode && asserts.empty()) { + aig_b++; + aig_outputs.push_back(0); + } + + for (auto it : assumes) { + aig_c++; + int bit_a = bit2aig(it.first); + int bit_en = bit2aig(it.second); + aig_outputs.push_back(mkgate(bit_a^1, bit_en)^1); + } + + for (auto it : liveness) + { + int input_m = ++fair_live_inputs_m; + int latch_m1 = ++fair_live_latches_m; + int latch_m2 = ++fair_live_latches_m; + + log_assert(GetSize(aig_latchin) == fair_live_latches_l); + fair_live_latches_l += 2; + + int bit_a = bit2aig(it.first); + int bit_en = bit2aig(it.second); + int bit_s = 2*input_m; + int bit_q1 = 2*latch_m1; + int bit_q2 = 2*latch_m2; + + int bit_d1 = mkgate(mkgate(bit_s, bit_en)^1, bit_q1^1)^1; + int bit_d2 = mkgate(mkgate(bit_d1, bit_a)^1, bit_q2^1)^1; + + aig_j++; + aig_latchin.push_back(bit_d1); + aig_latchin.push_back(bit_d2); + aig_outputs.push_back(mkgate(bit_q1, bit_q2^1)); + } + + for (auto it : fairness) + { + int latch_m = ++fair_live_latches_m; + + log_assert(GetSize(aig_latchin) == fair_live_latches_l); + fair_live_latches_l += 1; + + int bit_a = bit2aig(it.first); + int bit_en = bit2aig(it.second); + int bit_q = 2*latch_m; + + aig_f++; + aig_latchin.push_back(mkgate(mkgate(bit_q^1, bit_en^1)^1, bit_a^1)); + aig_outputs.push_back(bit_q^1); + } + } + + void write_aiger(std::ostream &f, bool ascii_mode, bool miter_mode, bool symbols_mode) + { + int aig_obc = aig_o + aig_b + aig_c; + int aig_obcj = aig_obc + aig_j; + int aig_obcjf = aig_obcj + aig_f; + + log_assert(aig_m == aig_i + aig_l + aig_a); + log_assert(aig_l == GetSize(aig_latchin)); + log_assert(aig_l == GetSize(aig_latchinit)); + log_assert(aig_obcjf == GetSize(aig_outputs)); + + if (miter_mode) { + if (aig_b || aig_c || aig_j || aig_f) + log_error("Running AIGER back-end in -miter mode, but design contains $assert, $assume, $live and/or $fair cells!\n"); + f << stringf("%s %d %d %d 0 %d %d\n", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_a, aig_o); + } else { + f << stringf("%s %d %d %d %d %d", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_o, aig_a); + if (aig_b || aig_c || aig_j || aig_f) + f << stringf(" %d %d %d %d", aig_b, aig_c, aig_j, aig_f); + f << stringf("\n"); + } + + if (ascii_mode) + { + for (int i = 0; i < aig_i; i++) + f << stringf("%d\n", 2*i+2); + + for (int i = 0; i < aig_l; i++) { + if (zinit_mode || aig_latchinit.at(i) == 0) + f << stringf("%d %d\n", 2*(aig_i+i)+2, aig_latchin.at(i)); + else if (aig_latchinit.at(i) == 1) + f << stringf("%d %d 1\n", 2*(aig_i+i)+2, aig_latchin.at(i)); + else if (aig_latchinit.at(i) == 2) + f << stringf("%d %d %d\n", 2*(aig_i+i)+2, aig_latchin.at(i), 2*(aig_i+i)+2); + } + + for (int i = 0; i < aig_obc; i++) + f << stringf("%d\n", aig_outputs.at(i)); + + for (int i = aig_obc; i < aig_obcj; i++) + f << stringf("1\n"); + + for (int i = aig_obc; i < aig_obcj; i++) + f << stringf("%d\n", aig_outputs.at(i)); + + for (int i = aig_obcj; i < aig_obcjf; i++) + f << stringf("%d\n", aig_outputs.at(i)); + + for (int i = 0; i < aig_a; i++) + f << stringf("%d %d %d\n", 2*(aig_i+aig_l+i)+2, aig_gates.at(i).first, aig_gates.at(i).second); + } + else + { + for (int i = 0; i < aig_l; i++) { + if (zinit_mode || aig_latchinit.at(i) == 0) + f << stringf("%d\n", aig_latchin.at(i)); + else if (aig_latchinit.at(i) == 1) + f << stringf("%d 1\n", aig_latchin.at(i)); + else if (aig_latchinit.at(i) == 2) + f << stringf("%d %d\n", aig_latchin.at(i), 2*(aig_i+i)+2); + } + + for (int i = 0; i < aig_obc; i++) + f << stringf("%d\n", aig_outputs.at(i)); + + for (int i = aig_obc; i < aig_obcj; i++) + f << stringf("1\n"); + + for (int i = aig_obc; i < aig_obcj; i++) + f << stringf("%d\n", aig_outputs.at(i)); + + for (int i = aig_obcj; i < aig_obcjf; i++) + f << stringf("%d\n", aig_outputs.at(i)); + + for (int i = 0; i < aig_a; i++) { + int lhs = 2*(aig_i+aig_l+i)+2; + int rhs0 = aig_gates.at(i).first; + int rhs1 = aig_gates.at(i).second; + int delta0 = lhs - rhs0; + int delta1 = rhs0 - rhs1; + aiger_encode(f, delta0); + aiger_encode(f, delta1); + } + } + + if (symbols_mode) + { + dict> symbols; + + for (auto wire : module->wires()) + { + if (wire->name[0] == '$') + continue; + + SigSpec sig = sigmap(wire); + + for (int i = 0; i < GetSize(wire); i++) + { + if (sig[i].wire == nullptr) { + if (wire->port_output) + sig[i] = SigBit(wire, i); + else + continue; + } + + if (wire->port_input) { + int a = aig_map.at(sig[i]); + log_assert((a & 1) == 0); + if (GetSize(wire) != 1) + symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s[%d]", log_id(wire), i)); + else + symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("%s", log_id(wire))); + } + + if (wire->port_output) { + int o = ordered_outputs.at(SigSpec(wire, i)); + if (GetSize(wire) != 1) + symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s[%d]", log_id(wire), i)); + else + symbols[stringf("%c%d", miter_mode ? 'b' : 'o', o)].push_back(stringf("%s", log_id(wire))); + } + + if (init_inputs.count(sig[i])) { + int a = init_inputs.at(sig[i]); + log_assert((a & 1) == 0); + if (GetSize(wire) != 1) + symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s[%d]", log_id(wire), i)); + else + symbols[stringf("i%d", (a >> 1)-1)].push_back(stringf("init:%s", log_id(wire))); + } + + if (ordered_latches.count(sig[i])) { + int l = ordered_latches.at(sig[i]); + const char *p = (zinit_mode && (aig_latchinit.at(l) == 1)) ? "!" : ""; + if (GetSize(wire) != 1) + symbols[stringf("l%d", l)].push_back(stringf("%s%s[%d]", p, log_id(wire), i)); + else + symbols[stringf("l%d", l)].push_back(stringf("%s%s", p, log_id(wire))); + } + } + } + + symbols.sort(); + + for (auto &sym : symbols) { + f << sym.first; + std::sort(sym.second.begin(), sym.second.end()); + for (auto &s : sym.second) + f << " " << s; + f << std::endl; + } + } + + f << stringf("c\nGenerated by %s\n", yosys_version_str); + } + + void write_map(std::ostream &f, bool verbose_map) + { + dict input_lines; + dict init_lines; + dict output_lines; + dict latch_lines; + dict wire_lines; + + for (auto wire : module->wires()) + { + if (!verbose_map && wire->name[0] == '$') + continue; + + SigSpec sig = sigmap(wire); + + for (int i = 0; i < GetSize(wire); i++) + { + if (aig_map.count(sig[i]) == 0 || sig[i].wire == nullptr) + continue; + + int a = aig_map.at(sig[i]); + + if (verbose_map) + wire_lines[a] += stringf("wire %d %d %s\n", a, i, log_id(wire)); + + if (wire->port_input) { + log_assert((a & 1) == 0); + input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire)); + } + + if (wire->port_output) { + int o = ordered_outputs.at(sig[i]); + output_lines[o] += stringf("output %d %d %s\n", o, i, log_id(wire)); + } + + if (init_inputs.count(sig[i])) { + int a = init_inputs.at(sig[i]); + log_assert((a & 1) == 0); + init_lines[a] += stringf("init %d %d %s\n", (a >> 1)-1, i, log_id(wire)); + } + + if (ordered_latches.count(sig[i])) { + int l = ordered_latches.at(sig[i]); + if (zinit_mode && (aig_latchinit.at(l) == 1)) + latch_lines[l] += stringf("invlatch %d %d %s\n", l, i, log_id(wire)); + else + latch_lines[l] += stringf("latch %d %d %s\n", l, i, log_id(wire)); + } + } + } + + input_lines.sort(); + for (auto &it : input_lines) + f << it.second; + + init_lines.sort(); + for (auto &it : init_lines) + f << it.second; + + output_lines.sort(); + for (auto &it : output_lines) + f << it.second; + + latch_lines.sort(); + for (auto &it : latch_lines) + f << it.second; + + wire_lines.sort(); + for (auto &it : wire_lines) + f << it.second; + } +}; + +struct AigerBackend : public Backend { + AigerBackend() : Backend("aiger", "write design to AIGER file") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" write_aiger [options] [filename]\n"); + log("\n"); + log("Write the current design to an AIGER file. The design must be flattened and\n"); + log("must not contain any cell types except $_AND_, $_NOT_, simple FF types,\n"); + log("$assert and $assume cells, and $initstate cells.\n"); + log("\n"); + log("$assert and $assume cells are converted to AIGER bad state properties and\n"); + log("invariant constraints.\n"); + log("\n"); + log(" -ascii\n"); + log(" write ASCII version of AGIER format\n"); + log("\n"); + log(" -zinit\n"); + log(" convert FFs to zero-initialized FFs, adding additional inputs for\n"); + log(" uninitialized FFs.\n"); + log("\n"); + log(" -miter\n"); + log(" design outputs are AIGER bad state properties\n"); + log("\n"); + log(" -symbols\n"); + log(" include a symbol table in the generated AIGER file\n"); + log("\n"); + log(" -map \n"); + log(" write an extra file with port and latch symbols\n"); + log("\n"); + log(" -vmap \n"); + log(" like -map, but more verbose\n"); + log("\n"); + log(" -I, -O, -B\n"); + log(" If the design contains no input/output/assert then create one\n"); + log(" dummy input/output/bad_state pin to make the tools reading the\n"); + log(" AIGER file happy.\n"); + log("\n"); + } + void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + bool ascii_mode = false; + bool zinit_mode = false; + bool miter_mode = false; + bool symbols_mode = false; + bool verbose_map = false; + bool imode = false; + bool omode = false; + bool bmode = false; + std::string map_filename; + + log_header(design, "Executing AIGER backend.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-ascii") { + ascii_mode = true; + continue; + } + if (args[argidx] == "-zinit") { + zinit_mode = true; + continue; + } + if (args[argidx] == "-miter") { + miter_mode = true; + continue; + } + if (args[argidx] == "-symbols") { + symbols_mode = true; + continue; + } + if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) { + map_filename = args[++argidx]; + continue; + } + if (map_filename.empty() && args[argidx] == "-vmap" && argidx+1 < args.size()) { + map_filename = args[++argidx]; + verbose_map = true; + continue; + } + if (args[argidx] == "-I") { + imode = true; + continue; + } + if (args[argidx] == "-O") { + omode = true; + continue; + } + if (args[argidx] == "-B") { + bmode = true; + continue; + } + break; + } + extra_args(f, filename, args, argidx); + + Module *top_module = design->top_module(); + + if (top_module == nullptr) + log_error("Can't find top module in current design!\n"); + + AigerWriter writer(top_module, zinit_mode, imode, omode, bmode); + writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode); + + if (!map_filename.empty()) { + std::ofstream mapf; + mapf.open(map_filename.c_str(), std::ofstream::trunc); + if (mapf.fail()) + log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno)); + writer.write_map(mapf, verbose_map); + } + } +} AigerBackend; + +PRIVATE_NAMESPACE_END -- 2.30.2