Merge remote-tracking branch 'origin/eddie/shregmap_improve' into xc7mux
authorEddie Hung <eddie@fpgeh.com>
Mon, 10 Jun 2019 23:21:43 +0000 (16:21 -0700)
committerEddie Hung <eddie@fpgeh.com>
Mon, 10 Jun 2019 23:21:43 +0000 (16:21 -0700)
40 files changed:
CHANGELOG
Makefile
backends/aiger/Makefile.inc
backends/aiger/aiger.cc
backends/aiger/xaiger.cc [new file with mode: 0644]
frontends/aiger/aigerparse.cc
frontends/aiger/aigerparse.h
kernel/rtlil.h
passes/cmds/stat.cc
passes/opt/Makefile.inc
passes/opt/muxpack.cc [new file with mode: 0644]
passes/techmap/Makefile.inc
passes/techmap/abc9.cc [new file with mode: 0644]
techlibs/common/synth.cc
techlibs/ice40/Makefile.inc
techlibs/ice40/abc_hx.box [new file with mode: 0644]
techlibs/ice40/abc_hx.lut [new file with mode: 0644]
techlibs/ice40/abc_lp.box [new file with mode: 0644]
techlibs/ice40/abc_lp.lut [new file with mode: 0644]
techlibs/ice40/abc_u.box [new file with mode: 0644]
techlibs/ice40/abc_u.lut [new file with mode: 0644]
techlibs/ice40/cells_map.v
techlibs/ice40/cells_sim.v
techlibs/ice40/synth_ice40.cc
techlibs/xilinx/Makefile.inc
techlibs/xilinx/abc.box [new file with mode: 0644]
techlibs/xilinx/abc.lut [new file with mode: 0644]
techlibs/xilinx/arith_map.v
techlibs/xilinx/brams_bb.v
techlibs/xilinx/cells_map.v
techlibs/xilinx/cells_sim.v
techlibs/xilinx/cells_xtra.sh
techlibs/xilinx/cells_xtra.v
techlibs/xilinx/mux_map.v [new file with mode: 0644]
techlibs/xilinx/synth_xilinx.cc
tests/simple_abc9/abc.box [new file with mode: 0644]
tests/simple_abc9/abc9.v [new file with mode: 0644]
tests/simple_abc9/run-test.sh [new file with mode: 0755]
tests/various/muxpack.v [new file with mode: 0644]
tests/various/muxpack.ys [new file with mode: 0644]

index 839fefcf1d0b57888408eb5dc20bc8dae561733f..c1b548aebbcb4c416733b71fc922987876acfe55 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -17,7 +17,9 @@ Yosys 0.8 .. Yosys 0.8-dev
     - Added "rename -src"
     - Added "equiv_opt" pass
     - Added "read_aiger" frontend
+    - Added "muxpack" pass
     - "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx"
+    - "synth_xilinx" to now infer wide multiplexers
 
 
 Yosys 0.7 .. Yosys 0.8
index 76dac48a586c2ae9dd8c8b9b73f5a5c14cc5e3d6..fb0eaf14dc7d3290801996d036eaa374d8ceabc5 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -122,7 +122,7 @@ OBJS = kernel/version_$(GIT_REV).o
 # is just a symlink to your actual ABC working directory, as 'make mrproper'
 # will remove the 'abc' directory and you do not want to accidentally
 # delete your work on ABC..
-ABCREV = 3709744
+ABCREV = 62487de
 ABCPULL = 1
 ABCURL ?= https://github.com/berkeley-abc/abc
 ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
index 0fc37e95ca8a01278ee79de81ba71769c9073fbb..4a4cf30bd47defde4ef5739005c39b4f61ccd8e4 100644 (file)
@@ -1,3 +1,4 @@
 
 OBJS += backends/aiger/aiger.o
+OBJS += backends/aiger/xaiger.o
 
index dfe506c662278be9aec459ada19da09ce8cc0f3f..516e538a5b3da0537f6ef010775808c39202736a 100644 (file)
@@ -685,7 +685,7 @@ struct AigerBackend : public Backend {
                log("invariant constraints.\n");
                log("\n");
                log("    -ascii\n");
-               log("        write ASCII version of AGIER format\n");
+               log("        write ASCII version of AIGER format\n");
                log("\n");
                log("    -zinit\n");
                log("        convert FFs to zero-initialized FFs, adding additional inputs for\n");
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
new file mode 100644 (file)
index 0000000..bf2f9f1
--- /dev/null
@@ -0,0 +1,1145 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2019  Eddie Hung <eddie@fpgeh.com>
+ *
+ *  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"
+#include "kernel/celltypes.h"
+#include "kernel/utils.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 XAigerWriter
+{
+       Module *module;
+       bool zinit_mode;
+       SigMap sigmap;
+
+       dict<SigBit, bool> init_map;
+       pool<SigBit> input_bits, output_bits;
+       dict<SigBit, SigBit> not_map, ff_map, alias_map;
+       dict<SigBit, pair<SigBit, SigBit>> and_map;
+       //pool<SigBit> initstate_bits;
+       vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int>> ci_bits;
+       vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int,int>> co_bits;
+       vector<std::pair<SigBit,SigBit>> ff_bits;
+
+       vector<pair<int, int>> aig_gates;
+       vector<int> aig_latchin, aig_latchinit, aig_outputs;
+       int aig_m = 0, aig_i = 0, aig_l = 0, aig_o = 0, aig_a = 0;
+
+       dict<SigBit, int> aig_map;
+       dict<SigBit, int> ordered_outputs;
+       dict<SigBit, int> ordered_latches;
+
+       vector<Cell*> box_list;
+
+       //dict<SigBit, int> 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);
+       }
+
+       XAigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode, bool holes_mode=false) : module(module), zinit_mode(zinit_mode), sigmap(module)
+       {
+               pool<SigBit> undriven_bits;
+               pool<SigBit> 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;
+                       }
+
+                       bool keep = wire->attributes.count("\\keep");
+
+                       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 || keep) {
+                                       if (bit != wirebit)
+                                               alias_map[bit] = wirebit;
+                                       input_bits.insert(wirebit);
+                               }
+
+                               if (wire->port_output || keep) {
+                                       if (bit != wirebit)
+                                               alias_map[wirebit] = bit;
+                                       output_bits.insert(wirebit);
+                               }
+                       }
+               }
+
+               for (auto bit : input_bits)
+                       undriven_bits.erase(sigmap(bit));
+
+               for (auto bit : output_bits)
+                       if (!bit.wire->port_input)
+                               unused_bits.erase(bit);
+
+               dict<SigBit, pool<IdString>> bit_drivers, bit_users;
+               TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
+               bool abc_box_seen = false;
+
+               for (auto cell : module->cells())
+               {
+                       RTLIL::Module* inst_module = module->design->module(cell->type);
+                       bool builtin_type = yosys_celltypes.cell_known(cell->type);
+                       bool abc_type = inst_module && inst_module->attributes.count("\\abc_box_id");
+
+                       if (!holes_mode) {
+                               toposort.node(cell->name);
+                               for (const auto &conn : cell->connections()) {
+                                       if (!builtin_type && !abc_type)
+                                               continue;
+
+                                       if (!cell->type.in("$_NOT_", "$_AND_")) {
+                                               if (builtin_type) {
+                                                       if (conn.first.in("\\Q", "\\CTRL_OUT", "\\RD_DATA"))
+                                                               continue;
+                                                       if (cell->type == "$memrd" && conn.first == "\\DATA")
+                                                               continue;
+                                               }
+
+                                               if (inst_module) {
+                                                       RTLIL::Wire* inst_module_port = inst_module->wire(conn.first);
+                                                       log_assert(inst_module_port);
+
+                                                       if (inst_module_port->port_output && inst_module_port->attributes.count("\\abc_flop_q"))
+                                                                       continue;
+                                               }
+                                       }
+
+                                       if (cell->input(conn.first)) {
+                                               // Ignore inout for the sake of topographical ordering
+                                               if (cell->output(conn.first)) continue;
+                                               for (auto bit : sigmap(conn.second))
+                                                       bit_users[bit].insert(cell->name);
+                                       }
+
+                                       if (cell->output(conn.first))
+                                               for (auto bit : sigmap(conn.second))
+                                                       bit_drivers[bit].insert(cell->name);
+                               }
+                       }
+
+                       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;
+                       //}
+
+                       bool inst_flop = inst_module ? inst_module->attributes.count("\\abc_flop") : false;
+                       if (inst_flop) {
+                               SigBit d, q;
+                               for (const auto &c : cell->connections()) {
+                                       auto is_input = cell->input(c.first);
+                                       auto is_output = cell->output(c.first);
+                                       log_assert(is_input || is_output);
+                                       RTLIL::Wire* port = inst_module->wire(c.first);
+                                       for (auto b : c.second.bits()) {
+                                               if (is_input && port->attributes.count("\\abc_flop_d")) {
+                                                       d = b;
+                                                       SigBit I = sigmap(d);
+                                                       if (I != d)
+                                                               alias_map[I] = d;
+                                                       unused_bits.erase(d);
+                                               }
+                                               if (is_output && port->attributes.count("\\abc_flop_q")) {
+                                                       q = b;
+                                                       SigBit O = sigmap(q);
+                                                       if (O != q)
+                                                               alias_map[O] = q;
+                                                       undriven_bits.erase(O);
+                                               }
+                                       }
+                               }
+                               if (!abc_box_seen)
+                                       abc_box_seen = inst_module->attributes.count("\\abc_box_id");
+
+                               ff_bits.emplace_back(d, q);
+                       }
+                       else if (inst_module && inst_module->attributes.count("\\abc_box_id")) {
+                               abc_box_seen = true;
+                       }
+                       else {
+                               for (const auto &c : cell->connections()) {
+                                       if (c.second.is_fully_const()) continue;
+                                       for (auto b : c.second.bits()) {
+                                               Wire *w = b.wire;
+                                               if (!w) continue;
+                                               auto is_input = cell->input(c.first);
+                                               auto is_output = cell->output(c.first);
+                                               log_assert(is_input || is_output);
+                                               if (is_input) {
+                                                       if (!w->port_input) {
+                                                               SigBit I = sigmap(b);
+                                                               if (I != b)
+                                                                       alias_map[b] = I;
+                                                               output_bits.insert(b);
+                                                               unused_bits.erase(b);
+                                                       }
+                                               }
+                                               if (is_output) {
+                                                       input_bits.insert(b);
+                                                       SigBit O = sigmap(b);
+                                                       if (O != b)
+                                                               alias_map[O] = b;
+                                                       undriven_bits.erase(O);
+                                               }
+                                       }
+                               }
+                       }
+
+                       //log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell));
+               }
+
+               if (abc_box_seen) {
+                       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);
+
+                       pool<RTLIL::Module*> abc_carry_modules;
+
+#if 0
+                       toposort.analyze_loops = true;
+#endif
+                       bool no_loops = toposort.sort();
+#if 0
+                       unsigned i = 0;
+                       for (auto &it : toposort.loops) {
+                               log("  loop %d", i++);
+                               for (auto cell : it)
+                                       log(" %s", log_id(cell));
+                               log("\n");
+                       }
+#endif
+                       log_assert(no_loops);
+
+                       for (auto cell_name : toposort.sorted) {
+                               RTLIL::Cell *cell = module->cell(cell_name);
+                               RTLIL::Module* box_module = module->design->module(cell->type);
+                               if (!box_module || !box_module->attributes.count("\\abc_box_id"))
+                                       continue;
+
+                               if (box_module->attributes.count("\\abc_carry") && !abc_carry_modules.count(box_module)) {
+                                       RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr;
+                                       RTLIL::Wire* last_in = nullptr, *last_out = nullptr;
+                                       for (const auto &port_name : box_module->ports) {
+                                               RTLIL::Wire* w = box_module->wire(port_name);
+                                               log_assert(w);
+                                               if (w->port_input) {
+                                                       if (w->attributes.count("\\abc_carry_in")) {
+                                                               log_assert(!carry_in);
+                                                               carry_in = w;
+                                                       }
+                                                       log_assert(!last_in || last_in->port_id < w->port_id);
+                                                       last_in = w;
+                                               }
+                                               if (w->port_output) {
+                                                       if (w->attributes.count("\\abc_carry_out")) {
+                                                               log_assert(!carry_out);
+                                                               carry_out = w;
+                                                       }
+                                                       log_assert(!last_out || last_out->port_id < w->port_id);
+                                                       last_out = w;
+                                               }
+                                       }
+
+                                       if (carry_in) {
+                                               log_assert(last_in);
+                                               std::swap(box_module->ports[carry_in->port_id-1], box_module->ports[last_in->port_id-1]);
+                                               std::swap(carry_in->port_id, last_in->port_id);
+                                       }
+                                       if (carry_out) {
+                                               log_assert(last_out);
+                                               std::swap(box_module->ports[carry_out->port_id-1], box_module->ports[last_out->port_id-1]);
+                                               std::swap(carry_out->port_id, last_out->port_id);
+                                       }
+                               }
+
+                               // 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(RTLIL::S0, GetSize(w)-GetSize(it->second)));
+                                                       rhs = it->second;
+                                               }
+                                               else {
+                                                       rhs = RTLIL::SigSpec(RTLIL::S0, GetSize(w));
+                                                       cell->setPort(port_name, rhs);
+                                               }
+
+                                               int offset = 0;
+                                               for (const auto &b : rhs.bits()) {
+                                                       SigBit I = sigmap(b);
+                                                       if (I != b)
+                                                               alias_map[b] = I;
+                                                       co_bits.emplace_back(b, cell, port_name, offset++, 0);
+                                                       unused_bits.erase(b);
+                                               }
+                                       }
+                                       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 {
+                                                       rhs = module->addWire(NEW_ID, GetSize(w));
+                                                       cell->setPort(port_name, rhs);
+                                               }
+
+                                               int offset = 0;
+                                               for (const auto &b : rhs.bits()) {
+                                                       ci_bits.emplace_back(b, cell, port_name, offset++);
+                                                       SigBit O = sigmap(b);
+                                                       if (O != b)
+                                                               alias_map[O] = b;
+                                                       undriven_bits.erase(O);
+
+                                                       auto jt = input_bits.find(b);
+                                                       if (jt != input_bits.end()) {
+                                                               log_assert(b.wire->attributes.count("\\keep"));
+                                                               input_bits.erase(b);
+                                                       }
+                                               }
+                                       }
+                               }
+                               box_list.emplace_back(cell);
+                       }
+
+                       // TODO: Free memory from toposort, bit_drivers, bit_users
+               }
+
+               for (auto bit : input_bits) {
+                       RTLIL::Wire *wire = bit.wire;
+                       // If encountering an inout port, or a keep-ed wire, then create a new wire
+                       // with $inout.out suffix, make it a PO driven by the existing inout, and
+                       // inherit existing inout's drivers
+                       if ((wire->port_input && wire->port_output && !undriven_bits.count(bit))
+                                       || wire->attributes.count("\\keep")) {
+                               log_assert(input_bits.count(bit) && output_bits.count(bit));
+                               RTLIL::IdString wire_name = wire->name.str() + "$inout.out";
+                               RTLIL::Wire *new_wire = module->wire(wire_name);
+                               if (!new_wire)
+                                       new_wire = module->addWire(wire_name, GetSize(wire));
+                               SigBit new_bit(new_wire, bit.offset);
+                               module->connect(new_bit, bit);
+                               if (not_map.count(bit))
+                                       not_map[new_bit] = not_map.at(bit);
+                               else if (and_map.count(bit))
+                                       and_map[new_bit] = and_map.at(bit);
+                               else if (alias_map.count(bit))
+                                       alias_map[new_bit] = alias_map.at(bit);
+                               else
+                                       //log_abort();
+                                       alias_map[new_bit] = bit;
+                               output_bits.erase(bit);
+                               output_bits.insert(new_bit);
+                       }
+               }
+
+               // Erase all POs that are undriven
+               if (!holes_mode)
+                       for (auto bit : undriven_bits)
+                               output_bits.erase(bit);
+               for (auto bit : unused_bits)
+                       undriven_bits.erase(bit);
+
+               if (!undriven_bits.empty() && !holes_mode) {
+                       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();
+               if (holes_mode) {
+                       struct sort_by_port_id {
+                               bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const {
+                                       return a.wire->port_id < b.wire->port_id;
+                               }
+                       };
+                       input_bits.sort(sort_by_port_id());
+                       output_bits.sort(sort_by_port_id());
+               }
+               else {
+                       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++;
+                       log_assert(!aig_map.count(bit));
+                       aig_map[bit] = 2*aig_m;
+               }
+
+               for (auto &f : ff_bits) {
+                       RTLIL::SigBit bit = f.second;
+                       aig_m++, aig_i++;
+                       log_assert(!aig_map.count(bit));
+                       aig_map[bit] = 2*aig_m;
+               }
+
+               dict<SigBit, int> ff_aig_map;
+               for (auto &c : ci_bits) {
+                       RTLIL::SigBit bit = std::get<0>(c);
+                       aig_m++, aig_i++;
+                       auto r = aig_map.insert(std::make_pair(bit, 2*aig_m));
+                       if (!r.second)
+                               ff_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;
+               //      }
+               //}
+
+               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);
+               //}
+
+               //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 &c : co_bits) {
+                       RTLIL::SigBit bit = std::get<0>(c);
+                       std::get<4>(c) = ordered_outputs[bit] = aig_o++;
+                       aig_outputs.push_back(bit2aig(bit));
+               }
+
+               for (auto bit : output_bits) {
+                       ordered_outputs[bit] = aig_o++;
+                       aig_outputs.push_back(bit2aig(bit));
+               }
+
+               for (auto &f : ff_bits) {
+                       aig_o++;
+                       RTLIL::SigBit bit = f.second;
+                       aig_outputs.push_back(ff_aig_map.at(bit));
+               }
+
+               if (omode && output_bits.empty()) {
+                       aig_o++;
+                       aig_outputs.push_back(0);
+               }
+
+               if (bmode) {
+                       //aig_b++;
+                       aig_outputs.push_back(0);
+               }
+       }
+
+       void write_aiger(std::ostream &f, bool ascii_mode, bool miter_mode, bool symbols_mode, bool omode)
+       {
+               int aig_obc = aig_o;
+               int aig_obcj = aig_obc;
+               int aig_obcjf = aig_obcj;
+
+               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));
+
+               f << stringf("%s %d %d %d %d %d", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_o, aig_a);
+               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<string, vector<string>> symbols;
+
+                       bool output_seen = false;
+                       for (auto wire : module->wires())
+                       {
+                               //if (wire->name[0] == '$')
+                               //      continue;
+
+                               SigSpec sig = sigmap(wire);
+
+                               for (int i = 0; i < GetSize(wire); i++)
+                               {
+                                       RTLIL::SigBit b(wire, i);
+                                       if (input_bits.count(b)) {
+                                               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 (output_bits.count(b)) {
+                                               int o = ordered_outputs.at(b);
+                                               output_seen = !miter_mode;
+                                               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)));
+                                       }
+                               }
+                       }
+
+                       if (omode && !output_seen)
+                               symbols["o0"].push_back("__dummy_o__");
+
+                       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 << "c";
+
+               if (!box_list.empty() || !ff_bits.empty()) {
+                       std::stringstream h_buffer;
+                       auto write_h_buffer = [&h_buffer](int i32) {
+                               // TODO: Don't assume we're on little endian
+#ifdef _WIN32
+                               int i32_be = _byteswap_ulong(i32);
+#else
+                               int i32_be = __builtin_bswap32(i32);
+#endif
+                               h_buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be));
+                       };
+                       int num_outputs = output_bits.size();
+                       if (omode && num_outputs == 0)
+                               num_outputs = 1;
+                       write_h_buffer(1);
+                       log_debug("ciNum = %zu\n", input_bits.size() + ff_bits.size() + ci_bits.size());
+                       write_h_buffer(input_bits.size() + ff_bits.size() + ci_bits.size());
+                       log_debug("coNum = %zu\n", num_outputs + ff_bits.size() + co_bits.size());
+                       write_h_buffer(num_outputs + ff_bits.size()+ co_bits.size());
+                       log_debug("piNum = %zu\n", input_bits.size() + ff_bits.size());
+                       write_h_buffer(input_bits.size()+ ff_bits.size());
+                       log_debug("poNum = %zu\n", num_outputs + ff_bits.size());
+                       write_h_buffer(num_outputs + ff_bits.size());
+                       log_debug("boxNum = %zu\n", box_list.size());
+                       write_h_buffer(box_list.size());
+
+                       RTLIL::Module *holes_module = nullptr;
+                       holes_module = module->design->addModule("\\__holes__");
+                       log_assert(holes_module);
+
+                       int port_id = 1;
+                       int box_count = 0;
+                       for (auto cell : box_list) {
+                               RTLIL::Module* box_module = module->design->module(cell->type);
+                               int box_inputs = 0, box_outputs = 0;
+                               Cell *holes_cell = nullptr;
+                               if (box_module->get_bool_attribute("\\whitebox")) {
+                                       holes_cell = holes_module->addCell(cell->name, cell->type);
+                                       holes_cell->parameters = cell->parameters;
+                               }
+
+                               // 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);
+                                       RTLIL::Wire *holes_wire;
+                                       RTLIL::SigSpec port_wire;
+                                       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_wire.append(holes_wire);
+                                               }
+                                               if (!port_wire.empty())
+                                                       holes_cell->setPort(w->name, port_wire);
+                                       }
+                                       if (w->port_output) {
+                                               box_outputs += GetSize(w);
+                                               for (int i = 0; i < GetSize(w); i++) {
+                                                       if (GetSize(w) == 1)
+                                                               holes_wire = holes_module->addWire(stringf("%s.%s", cell->name.c_str(), w->name.c_str()));
+                                                       else
+                                                               holes_wire = holes_module->addWire(stringf("%s.%s[%d]", cell->name.c_str(), w->name.c_str(), i));
+                                                       holes_wire->port_output = true;
+                                                       holes_wire->port_id = port_id++;
+                                                       holes_module->ports.push_back(holes_wire->name);
+                                                       if (holes_cell)
+                                                               port_wire.append(holes_wire);
+                                                       else
+                                                               holes_module->connect(holes_wire, RTLIL::S0);
+                                               }
+                                               if (!port_wire.empty())
+                                                       holes_cell->setPort(w->name, port_wire);
+                                       }
+                               }
+
+                               write_h_buffer(box_inputs);
+                               write_h_buffer(box_outputs);
+                               write_h_buffer(box_module->attributes.at("\\abc_box_id").as_int());
+                               write_h_buffer(box_count++);
+                       }
+
+                       f << "h";
+                       std::string buffer_str = h_buffer.str();
+                       // TODO: Don't assume we're on little endian
+#ifdef _WIN32
+                       int buffer_size_be = _byteswap_ulong(buffer_str.size());
+#else
+                       int buffer_size_be = __builtin_bswap32(buffer_str.size());
+#endif
+                       f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
+                       f.write(buffer_str.data(), buffer_str.size());
+
+                       /*if (!ff_bits.empty())*/ {
+                               std::stringstream r_buffer;
+                               auto write_r_buffer = [&r_buffer](int i32) {
+                                       // TODO: Don't assume we're on little endian
+#ifdef _WIN32
+                                       int i32_be = _byteswap_ulong(i32);
+#else
+                                       int i32_be = __builtin_bswap32(i32);
+#endif
+                                       r_buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be));
+                               };
+                               log_debug("flopNum = %zu\n", ff_bits.size());
+                               write_r_buffer(ff_bits.size());
+                               int mergeability_class = 1;
+                               for (auto cell : ff_bits)
+                                       write_r_buffer(mergeability_class++);
+
+                               f << "r";
+                               std::string buffer_str = r_buffer.str();
+                               // TODO: Don't assume we're on little endian
+#ifdef _WIN32
+                               int buffer_size_be = _byteswap_ulong(buffer_str.size());
+#else
+                               int buffer_size_be = __builtin_bswap32(buffer_str.size());
+#endif
+                               f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
+                               f.write(buffer_str.data(), buffer_str.size());
+                       }
+
+                       if (holes_module) {
+                               // NB: fixup_ports() will sort ports by name
+                               //holes_module->fixup_ports();
+                               holes_module->check();
+
+                               holes_module->design->selection_stack.emplace_back(false);
+                               RTLIL::Selection& sel = holes_module->design->selection_stack.back();
+                               sel.select(holes_module);
+
+                               // TODO: Should not need to opt_merge if we only instantiate
+                               //       each box type once...
+                               Pass::call(holes_module->design, "opt_merge -share_all");
+
+                               Pass::call(holes_module->design, "flatten -wb");
+
+                               // TODO: Should techmap all lib_whitebox-es once
+                               //Pass::call(holes_module->design, "techmap");
+
+                               Pass::call(holes_module->design, "aigmap");
+                               Pass::call(holes_module->design, "clean -purge");
+
+                               holes_module->design->selection_stack.pop_back();
+
+                               std::stringstream a_buffer;
+                               XAigerWriter writer(holes_module, false /*zinit_mode*/, false /*imode*/, false /*omode*/, false /*bmode*/, true /* holes_mode */);
+                               writer.write_aiger(a_buffer, false /*ascii_mode*/, false /*miter_mode*/, false /*symbols_mode*/, false /*omode*/);
+
+                               f << "a";
+                               std::string buffer_str = a_buffer.str();
+                               // TODO: Don't assume we're on little endian
+#ifdef _WIN32
+                               int buffer_size_be = _byteswap_ulong(buffer_str.size());
+#else
+                               int buffer_size_be = __builtin_bswap32(buffer_str.size());
+#endif
+                               f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
+                               f.write(buffer_str.data(), buffer_str.size());
+                               holes_module->design->remove(holes_module);
+                       }
+               }
+
+               f << stringf("Generated by %s\n", yosys_version_str);
+       }
+
+       void write_map(std::ostream &f, bool verbose_map, bool omode)
+       {
+               dict<int, string> input_lines;
+               dict<int, string> init_lines;
+               dict<int, string> output_lines;
+               dict<int, string> latch_lines;
+               dict<int, string> 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++)
+                       {
+                               RTLIL::SigBit b(wire, i);
+                               if (input_bits.count(b)) {
+                                       int a = aig_map.at(b);
+                                       log_assert((a & 1) == 0);
+                                       input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire));
+                               }
+
+                               if (output_bits.count(b)) {
+                                       int o = ordered_outputs.at(b);
+                                       output_lines[o] += stringf("output %lu %d %s\n", o - co_bits.size(), i, log_id(wire));
+                                       continue;
+                               }
+
+                               //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));
+                               //      continue;
+                               //}
+
+                               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));
+                                       continue;
+                               }
+
+                               if (verbose_map) {
+                                       if (aig_map.count(sig[i]) == 0)
+                                               continue;
+
+                                       int a = aig_map.at(sig[i]);
+                                       wire_lines[a] += stringf("wire %d %d %s\n", a, i, log_id(wire));
+                               }
+                       }
+               }
+
+               input_lines.sort();
+               for (auto &it : input_lines)
+                       f << it.second;
+               log_assert(input_lines.size() == input_bits.size());
+
+               init_lines.sort();
+               for (auto &it : init_lines)
+                       f << it.second;
+
+               int box_count = 0;
+               for (auto cell : box_list)
+                       f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name));
+
+               output_lines.sort();
+               for (auto &it : output_lines)
+                       f << it.second;
+               log_assert(output_lines.size() == output_bits.size());
+               if (omode && output_bits.empty())
+                       f << "output " << output_lines.size() << " 0 __dummy_o__\n";
+
+               latch_lines.sort();
+               for (auto &it : latch_lines)
+                       f << it.second;
+
+               wire_lines.sort();
+               for (auto &it : wire_lines)
+                       f << it.second;
+       }
+};
+
+struct XAigerBackend : public Backend {
+       XAigerBackend() : Backend("xaiger", "write design to XAIGER file") { }
+       void help() YS_OVERRIDE
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    write_xaiger [options] [filename]\n");
+               log("\n");
+               log("Write the current design to an XAIGER file. The design must be flattened and\n");
+               log("all unsupported cells will be converted into psuedo-inputs and pseudo-outputs.\n");
+               log("\n");
+               log("    -ascii\n");
+               log("        write ASCII version of AIGER 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("    -symbols\n");
+               log("        include a symbol table in the generated AIGER file\n");
+               log("\n");
+               log("    -map <filename>\n");
+               log("        write an extra file with port and latch symbols\n");
+               log("\n");
+               log("    -vmap <filename>\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<std::string> 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 XAIGER 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] == "-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");
+
+               XAigerWriter writer(top_module, zinit_mode, imode, omode, bmode);
+               writer.write_aiger(*f, ascii_mode, miter_mode, symbols_mode, omode);
+
+               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, omode);
+               }
+       }
+} XAigerBackend;
+
+PRIVATE_NAMESPACE_END
index 68552fd06618d25cc26ee3feac40b52e4e95ba81..4c19ec171f53274e04b1fcf125979121f6d310f9 100644 (file)
@@ -2,7 +2,7 @@
  *  yosys -- Yosys Open SYnthesis Suite
  *
  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
- *                      Eddie Hung <eddie@fpgeh.com>
+ *  Copyright (C) 2019  Eddie Hung <eddie@fpgeh.com>
  *
  *  Permission to use, copy, modify, and/or distribute this software for any
  *  purpose with or without fee is hereby granted, provided that the above
 // Armin Biere. The AIGER And-Inverter Graph (AIG) Format Version 20071012. Technical Report 07/1, October 2011, FMV Reports Series, Institute for Formal Models and Verification, Johannes Kepler University, Altenbergerstr. 69, 4040 Linz, Austria.
 // http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf
 
-#ifndef _WIN32
+#ifdef _WIN32
 #include <libgen.h>
+#include <stdlib.h>
 #endif
 #include <array>
 
 #include "kernel/yosys.h"
 #include "kernel/sigtools.h"
+#include "kernel/consteval.h"
 #include "aigerparse.h"
 
 YOSYS_NAMESPACE_BEGIN
 
-AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name)
-       : design(design), f(f), clk_name(clk_name)
+AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports)
+       : design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports)
 {
        module = new RTLIL::Module;
        module->name = module_name;
@@ -73,6 +75,8 @@ end_of_header:
        log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F);
 
        line_count = 1;
+       piNum = 0;
+       flopNum = 0;
 
        if (header == "aag")
                parse_aiger_ascii();
@@ -81,21 +85,10 @@ end_of_header:
        else
                log_abort();
 
-       RTLIL::Wire* n0 = module->wire("\\n0");
+       RTLIL::Wire* n0 = module->wire("\\__0__");
        if (n0)
                module->connect(n0, RTLIL::S0);
 
-       for (unsigned i = 0; i < outputs.size(); ++i) {
-               RTLIL::Wire *wire = outputs[i];
-               if (wire->port_input) {
-                       RTLIL::Wire *o_wire = module->addWire(wire->name.str() + "_o");
-                       o_wire->port_output = true;
-                       wire->port_output = false;
-                       module->connect(o_wire, wire);
-                       outputs[i] = o_wire;
-               }
-       }
-
        // Parse footer (symbol table, comments, etc.)
        unsigned l1;
        std::string s;
@@ -131,21 +124,35 @@ end_of_header:
                std::getline(f, line); // Ignore up to start of next line
        }
 
-       module->fixup_ports();
-       design->add(module);
+       post_process();
+}
+
+static uint32_t parse_xaiger_literal(std::istream &f)
+{
+       uint32_t l;
+       f.read(reinterpret_cast<char*>(&l), sizeof(l));
+       if (f.gcount() != sizeof(l))
+               log_error("Offset %ld: unable to read literal!\n", static_cast<int64_t>(f.tellg()));
+       // TODO: Don't assume we're on little endian
+#ifdef _WIN32
+       return _byteswap_ulong(l);
+#else
+       return __builtin_bswap32(l);
+#endif
 }
 
 static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal)
 {
        const unsigned variable = literal >> 1;
        const bool invert = literal & 1;
-       RTLIL::IdString wire_name(stringf("\\n%d%s", variable, invert ? "_inv" : "")); // FIXME: is "_inv" the right suffix?
+       RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix?
        RTLIL::Wire *wire = module->wire(wire_name);
        if (wire) return wire;
        log_debug("Creating %s\n", wire_name.c_str());
        wire = module->addWire(wire_name);
+       wire->port_input = wire->port_output = false;
        if (!invert) return wire;
-       RTLIL::IdString wire_inv_name(stringf("\\n%d", variable));
+       RTLIL::IdString wire_inv_name(stringf("\\__%d__", variable));
        RTLIL::Wire *wire_inv = module->wire(wire_inv_name);
        if (wire_inv) {
                if (module->cell(wire_inv_name)) return wire;
@@ -153,14 +160,159 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera
        else {
                log_debug("Creating %s\n", wire_inv_name.c_str());
                wire_inv = module->addWire(wire_inv_name);
+               wire_inv->port_input = wire_inv->port_output = false;
        }
 
        log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
-       module->addNotGate(stringf("\\n%d_not", variable), wire_inv, wire); // FIXME: is "_not" the right suffix?
+       module->addNotGate(stringf("\\__%d__$not", variable), wire_inv, wire); // FIXME: is "$not" the right suffix?
 
        return wire;
 }
 
+void AigerReader::parse_xaiger()
+{
+       std::string header;
+       f >> header;
+       if (header != "aag" && header != "aig")
+               log_error("Unsupported AIGER file!\n");
+
+       // Parse rest of header
+       if (!(f >> M >> I >> L >> O >> A))
+               log_error("Invalid AIGER header\n");
+
+       // Optional values
+       B = C = J = F = 0;
+
+       std::string line;
+       std::getline(f, line); // Ignore up to start of next line, as standard
+       // says anything that follows could be used for
+       // optional sections
+
+       log_debug("M=%u I=%u L=%u O=%u A=%u\n", M, I, L, O, A);
+
+       line_count = 1;
+       piNum = 0;
+       flopNum = 0;
+
+       if (header == "aag")
+               parse_aiger_ascii();
+       else if (header == "aig")
+               parse_aiger_binary();
+       else
+               log_abort();
+
+       RTLIL::Wire* n0 = module->wire("\\__0__");
+       if (n0)
+               module->connect(n0, RTLIL::S0);
+
+       dict<int,IdString> box_lookup;
+       for (auto m : design->modules()) {
+               auto it = m->attributes.find("\\abc_box_id");
+               if (it == m->attributes.end())
+                       continue;
+               if (m->name[0] == '$') continue;
+               auto r = box_lookup.insert(std::make_pair(it->second.as_int(), m->name));
+               log_assert(r.second);
+       }
+
+       // Parse footer (symbol table, comments, etc.)
+       std::string s;
+       bool comment_seen = false;
+       for (int c = f.peek(); c != EOF; c = f.peek()) {
+               if (comment_seen || c == 'c') {
+                       if (!comment_seen) {
+                               f.ignore(1);
+                               c = f.peek();
+                               comment_seen = true;
+                       }
+                       if (c == '\n')
+                               break;
+                       f.ignore(1);
+                       // XAIGER extensions
+                       if (c == 'm') {
+                               uint32_t dataSize = parse_xaiger_literal(f);
+                               uint32_t lutNum = parse_xaiger_literal(f);
+                               uint32_t lutSize = parse_xaiger_literal(f);
+                               log_debug("m: dataSize=%u lutNum=%u lutSize=%u\n", dataSize, lutNum, lutSize);
+                               ConstEval ce(module);
+                               for (unsigned i = 0; i < lutNum; ++i) {
+                                       uint32_t rootNodeID = parse_xaiger_literal(f);
+                                       uint32_t cutLeavesM = parse_xaiger_literal(f);
+                                       log_debug("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM);
+                                       RTLIL::Wire *output_sig = module->wire(stringf("\\__%d__", rootNodeID));
+                                       uint32_t nodeID;
+                                       RTLIL::SigSpec input_sig;
+                                       for (unsigned j = 0; j < cutLeavesM; ++j) {
+                                               nodeID = parse_xaiger_literal(f);
+                                               log_debug("\t%u\n", nodeID);
+                                               RTLIL::Wire *wire = module->wire(stringf("\\__%d__", nodeID));
+                                               log_assert(wire);
+                                               input_sig.append(wire);
+                                       }
+                                       RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << input_sig.size());
+                                       for (int j = 0; j < (1 << cutLeavesM); ++j) {
+                                               ce.push();
+                                               ce.set(input_sig, RTLIL::Const{j, static_cast<int>(cutLeavesM)});
+                                               RTLIL::SigSpec o(output_sig);
+                                               ce.eval(o);
+                                               lut_mask[j] = o.as_const()[0];
+                                               ce.pop();
+                                       }
+                                       RTLIL::Cell *output_cell = module->cell(stringf("\\__%d__$and", rootNodeID));
+                                       log_assert(output_cell);
+                                       module->remove(output_cell);
+                                       module->addLut(stringf("\\__%d__$lut", rootNodeID), input_sig, output_sig, std::move(lut_mask));
+                               }
+                       }
+                       else if (c == 'r') {
+                               uint32_t dataSize = parse_xaiger_literal(f);
+                               flopNum = parse_xaiger_literal(f);
+                               log_assert(dataSize == (flopNum+1) * sizeof(uint32_t));
+                               f.ignore(flopNum * sizeof(uint32_t));
+                       }
+                       else if (c == 'n') {
+                               parse_xaiger_literal(f);
+                               f >> s;
+                               log_debug("n: '%s'\n", s.c_str());
+                       }
+                       else if (c == 'h') {
+                               f.ignore(sizeof(uint32_t));
+                               uint32_t version = parse_xaiger_literal(f);
+                               log_assert(version == 1);
+                               uint32_t ciNum = parse_xaiger_literal(f);
+                               log_debug("ciNum = %u\n", ciNum);
+                               uint32_t coNum = parse_xaiger_literal(f);
+                               log_debug("coNum = %u\n", coNum);
+                               piNum = parse_xaiger_literal(f);
+                               log_debug("piNum = %u\n", piNum);
+                               uint32_t poNum = parse_xaiger_literal(f);
+                               log_debug("poNum = %u\n", poNum);
+                               uint32_t boxNum = parse_xaiger_literal(f);
+                               log_debug("boxNum = %u\n", poNum);
+                               for (unsigned i = 0; i < boxNum; i++) {
+                                       f.ignore(2*sizeof(uint32_t));
+                                       uint32_t boxUniqueId = parse_xaiger_literal(f);
+                                       log_assert(boxUniqueId > 0);
+                                       uint32_t oldBoxNum = parse_xaiger_literal(f);
+                                       RTLIL::Cell* cell = module->addCell(stringf("$__box%u__", oldBoxNum), box_lookup.at(boxUniqueId));
+                                       boxes.emplace_back(cell);
+                               }
+                       }
+                       else if (c == 'a' || c == 'i' || c == 'o') {
+                               uint32_t dataSize = parse_xaiger_literal(f);
+                               f.ignore(dataSize);
+                       }
+                       else {
+                               break;
+                       }
+               }
+               else
+                       log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
+       }
+
+       post_process();
+}
+
 void AigerReader::parse_aiger_ascii()
 {
        std::string line;
@@ -173,7 +325,7 @@ void AigerReader::parse_aiger_ascii()
                if (!(f >> l1))
                        log_error("Line %u cannot be interpreted as an input!\n", line_count);
                log_debug("%d is an input\n", l1);
-               log_assert(!(l1 & 1)); // TODO: Inputs can't be inverted?
+               log_assert(!(l1 & 1)); // Inputs can't be inverted
                RTLIL::Wire *wire = createWireIfNotExists(module, l1);
                wire->port_input = true;
                inputs.push_back(wire);
@@ -182,11 +334,13 @@ void AigerReader::parse_aiger_ascii()
        // Parse latches
        RTLIL::Wire *clk_wire = nullptr;
        if (L > 0) {
+               log_assert(clk_name != "");
                clk_wire = module->wire(clk_name);
                log_assert(!clk_wire);
                log_debug("Creating %s\n", clk_name.c_str());
                clk_wire = module->addWire(clk_name);
                clk_wire->port_input = true;
+               clk_wire->port_output = false;
        }
        for (unsigned i = 0; i < L; ++i, ++line_count) {
                if (!(f >> l1 >> l2))
@@ -208,7 +362,7 @@ void AigerReader::parse_aiger_ascii()
                        else if (l3 == 1)
                                q_wire->attributes["\\init"] = RTLIL::S1;
                        else if (l3 == l1) {
-                               //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
+                               //q_wire->attributes["\\init"] = RTLIL::Sx;
                        }
                        else
                                log_error("Line %u has invalid reset literal for latch!\n", line_count);
@@ -226,7 +380,17 @@ void AigerReader::parse_aiger_ascii()
                        log_error("Line %u cannot be interpreted as an output!\n", line_count);
 
                log_debug("%d is an output\n", l1);
-               RTLIL::Wire *wire = createWireIfNotExists(module, l1);
+               const unsigned variable = l1 >> 1;
+               const bool invert = l1 & 1;
+               RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix?
+               RTLIL::Wire *wire = module->wire(wire_name);
+               if (!wire)
+                       wire = createWireIfNotExists(module, l1);
+               else if (wire->port_input || wire->port_output) {
+                       RTLIL::Wire *new_wire = module->addWire(NEW_ID);
+                       module->connect(new_wire, wire);
+                       wire = new_wire;
+               }
                wire->port_output = true;
                outputs.push_back(wire);
        }
@@ -260,11 +424,11 @@ void AigerReader::parse_aiger_ascii()
                        log_error("Line %u cannot be interpreted as an AND!\n", line_count);
 
                log_debug("%d %d %d is an AND\n", l1, l2, l3);
-               log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
+               log_assert(!(l1 & 1));
                RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
                RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
                RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
-               module->addAndGate(NEW_ID, i1_wire, i2_wire, o_wire);
+               module->addAndGate(o_wire->name.str() + "$and", i1_wire, i2_wire, o_wire);
        }
        std::getline(f, line); // Ignore up to start of next line
 }
@@ -285,19 +449,23 @@ void AigerReader::parse_aiger_binary()
 
        // Parse inputs
        for (unsigned i = 1; i <= I; ++i) {
+               log_debug("%d is an input\n", i);
                RTLIL::Wire *wire = createWireIfNotExists(module, i << 1);
                wire->port_input = true;
+               log_assert(!wire->port_output);
                inputs.push_back(wire);
        }
 
        // Parse latches
        RTLIL::Wire *clk_wire = nullptr;
        if (L > 0) {
+               log_assert(clk_name != "");
                clk_wire = module->wire(clk_name);
                log_assert(!clk_wire);
                log_debug("Creating %s\n", clk_name.c_str());
                clk_wire = module->addWire(clk_name);
                clk_wire->port_input = true;
+               clk_wire->port_output = false;
        }
        l1 = (I+1) * 2;
        for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) {
@@ -319,7 +487,7 @@ void AigerReader::parse_aiger_binary()
                        else if (l3 == 1)
                                q_wire->attributes["\\init"] = RTLIL::S1;
                        else if (l3 == l1) {
-                               //q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
+                               //q_wire->attributes["\\init"] = RTLIL::Sx;
                        }
                        else
                                log_error("Line %u has invalid reset literal for latch!\n", line_count);
@@ -337,7 +505,17 @@ void AigerReader::parse_aiger_binary()
                        log_error("Line %u cannot be interpreted as an output!\n", line_count);
 
                log_debug("%d is an output\n", l1);
-               RTLIL::Wire *wire = createWireIfNotExists(module, l1);
+               const unsigned variable = l1 >> 1;
+               const bool invert = l1 & 1;
+               RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "_b" the right suffix?
+               RTLIL::Wire *wire = module->wire(wire_name);
+               if (!wire)
+                       wire = createWireIfNotExists(module, l1);
+               else if (wire->port_input || wire->port_output) {
+                       RTLIL::Wire *new_wire = module->addWire(NEW_ID);
+                       module->connect(new_wire, wire);
+                       wire = new_wire;
+               }
                wire->port_output = true;
                outputs.push_back(wire);
        }
@@ -375,15 +553,289 @@ void AigerReader::parse_aiger_binary()
                l3 = parse_next_delta_literal(f, l2);
 
                log_debug("%d %d %d is an AND\n", l1, l2, l3);
-               log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
+               log_assert(!(l1 & 1));
                RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
                RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
                RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
+               module->addAndGate(o_wire->name.str() + "$and", i1_wire, i2_wire, o_wire);
+       }
+}
 
-               RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$_AND_");
-               and_cell->setPort("\\A", i1_wire);
-               and_cell->setPort("\\B", i2_wire);
-               and_cell->setPort("\\Y", o_wire);
+void AigerReader::post_process()
+{
+       pool<RTLIL::Module*> abc_carry_modules;
+       unsigned ci_count = 0, co_count = 0, flop_count = 0;
+       for (auto cell : boxes) {
+               RTLIL::Module* box_module = design->module(cell->type);
+               log_assert(box_module);
+
+               if (box_module->attributes.count("\\abc_carry") && !abc_carry_modules.count(box_module)) {
+                       RTLIL::Wire* carry_in = nullptr, *carry_out = nullptr;
+                       RTLIL::Wire* last_in = nullptr, *last_out = nullptr;
+                       for (const auto &port_name : box_module->ports) {
+                               RTLIL::Wire* w = box_module->wire(port_name);
+                               log_assert(w);
+                               if (w->port_input) {
+                                       if (w->attributes.count("\\abc_carry_in")) {
+                                               log_assert(!carry_in);
+                                               carry_in = w;
+                                       }
+                                       log_assert(!last_in || last_in->port_id < w->port_id);
+                                       last_in = w;
+                               }
+                               if (w->port_output) {
+                                       if (w->attributes.count("\\abc_carry_out")) {
+                                               log_assert(!carry_out);
+                                               carry_out = w;
+                                       }
+                                       log_assert(!last_out || last_out->port_id < w->port_id);
+                                       last_out = w;
+                               }
+                       }
+
+                       if (carry_in != last_in) {
+                               std::swap(box_module->ports[carry_in->port_id], box_module->ports[last_in->port_id]);
+                               std::swap(carry_in->port_id, last_in->port_id);
+                       }
+                       if (carry_out != last_out) {
+                               log_assert(last_out);
+                               std::swap(box_module->ports[carry_out->port_id], box_module->ports[last_out->port_id]);
+                               std::swap(carry_out->port_id, last_out->port_id);
+                       }
+               }
+
+               bool flop = box_module->attributes.count("\\abc_flop");
+               log_assert(!flop || flop_count < flopNum);
+
+               // NB: Assume box_module->ports are sorted alphabetically
+               //     (as RTLIL::Module::fixup_ports() would do)
+               for (auto port_name : box_module->ports) {
+                       RTLIL::Wire* w = box_module->wire(port_name);
+                       log_assert(w);
+                       RTLIL::SigSpec rhs;
+                       RTLIL::Wire* wire = nullptr;
+                       for (int i = 0; i < GetSize(w); i++) {
+                               if (w->port_input) {
+                                       log_assert(co_count < outputs.size());
+                                       wire = outputs[co_count++];
+                                       log_assert(wire);
+                                       log_assert(wire->port_output);
+                                       wire->port_output = false;
+
+                                       if (flop && w->attributes.count("\\abc_flop_d")) {
+                                               RTLIL::Wire* d = outputs[outputs.size() - flopNum + flop_count];
+                                               log_assert(d);
+                                               log_assert(d->port_output);
+                                               d->port_output = false;
+                                       }
+                               }
+                               if (w->port_output) {
+                                       log_assert((piNum + ci_count) < inputs.size());
+                                       wire = inputs[piNum + ci_count++];
+                                       log_assert(wire);
+                                       log_assert(wire->port_input);
+                                       wire->port_input = false;
+
+                                       if (flop && w->attributes.count("\\abc_flop_q")) {
+                                               wire = inputs[piNum - flopNum + flop_count];
+                                               log_assert(wire);
+                                               log_assert(wire->port_input);
+                                               wire->port_input = false;
+                                       }
+                               }
+                               rhs.append(wire);
+                       }
+                       cell->setPort(port_name, rhs);
+               }
+
+               if (flop) flop_count++;
+       }
+
+       dict<RTLIL::IdString, int> wideports_cache;
+
+       if (!map_filename.empty()) {
+               std::ifstream mf(map_filename);
+               std::string type, symbol;
+               int variable, index;
+               while (mf >> type >> variable >> index >> symbol) {
+                       RTLIL::IdString escaped_s = RTLIL::escape_id(symbol);
+                       if (type == "input") {
+                               log_assert(static_cast<unsigned>(variable) < inputs.size());
+                               RTLIL::Wire* wire = inputs[variable];
+                               log_assert(wire);
+                               log_assert(wire->port_input);
+
+                               if (index == 0) {
+                                       // Cope with the fact that a CI might be identical
+                                       // to a PI (necessary due to ABC); in those cases
+                                       // simply connect the latter to the former
+                                       RTLIL::Wire* existing = module->wire(escaped_s);
+                                       if (!existing)
+                                               module->rename(wire, escaped_s);
+                                       else {
+                                               wire->port_input = false;
+                                               module->connect(wire, existing);
+                                       }
+                               }
+                               else if (index > 0) {
+                                       std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
+                                       RTLIL::Wire* existing = module->wire(indexed_name);
+                                       if (!existing) {
+                                               module->rename(wire, indexed_name);
+                                               if (wideports)
+                                                       wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
+                                       }
+                                       else {
+                                               module->connect(wire, existing);
+                                               wire->port_input = false;
+                                       }
+                               }
+                       }
+                       else if (type == "output") {
+                               log_assert(static_cast<unsigned>(variable + co_count) < outputs.size());
+                               RTLIL::Wire* wire = outputs[variable + co_count];
+                               log_assert(wire);
+                               log_assert(wire->port_output);
+                               if (escaped_s.in("\\__dummy_o__", "\\__const0__", "\\__const1__")) {
+                                       wire->port_output = false;
+                                       continue;
+                               }
+
+                               if (index == 0) {
+                                       // Cope with the fact that a CO might be identical
+                                       // to a PO (necessary due to ABC); in those cases
+                                       // simply connect the latter to the former
+                                       RTLIL::Wire* existing = module->wire(escaped_s);
+                                       if (!existing) {
+                                               if (escaped_s.ends_with("$inout.out")) {
+                                                       wire->port_output = false;
+                                                       RTLIL::Wire *in_wire = module->wire(escaped_s.substr(0, escaped_s.size()-10));
+                                                       log_assert(in_wire);
+                                                       log_assert(in_wire->port_input && !in_wire->port_output);
+                                                       in_wire->port_output = true;
+                                                       module->connect(in_wire, wire);
+                                               }
+                                               else
+                                                       module->rename(wire, escaped_s);
+                                       }
+                                       else {
+                                               wire->port_output = false;
+                                               module->connect(wire, existing);
+                                       }
+                               }
+                               else if (index > 0) {
+                                       std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index);
+                                       RTLIL::Wire* existing = module->wire(indexed_name);
+                                       if (!existing) {
+                                               if (escaped_s.ends_with("$inout.out")) {
+                                                       wire->port_output = false;
+                                                       RTLIL::Wire *in_wire = module->wire(stringf("%s[%d]", escaped_s.substr(0, escaped_s.size()-10).c_str(), index));
+                                                       log_assert(in_wire);
+                                                       log_assert(in_wire->port_input && !in_wire->port_output);
+                                                       in_wire->port_output = true;
+                                                       module->connect(in_wire, wire);
+                                               }
+                                               else {
+                                                       module->rename(wire, indexed_name);
+                                                       if (wideports)
+                                                               wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
+                                               }
+                                       }
+                                       else {
+                                               module->connect(wire, existing);
+                                               wire->port_output = false;
+                                       }
+                               }
+                       }
+                       else if (type == "box") {
+                               RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable));
+                               if (cell) { // ABC could have optimised this box away
+                                       module->rename(cell, escaped_s);
+                                       RTLIL::Module* box_module = design->module(cell->type);
+                                       log_assert(box_module);
+
+                                       for (const auto &i : cell->connections()) {
+                                               RTLIL::IdString port_name = i.first;
+                                               RTLIL::SigSpec rhs = i.second;
+                                               int index = 0;
+                                               for (auto bit : rhs.bits()) {
+                                                       RTLIL::Wire* wire = bit.wire;
+                                                       RTLIL::IdString escaped_s = RTLIL::escape_id(stringf("%s.%s", log_id(cell), log_id(port_name)));
+                                                       if (index == 0)
+                                                               module->rename(wire, escaped_s);
+                                                       else if (index > 0) {
+                                                               module->rename(wire, stringf("%s[%d]", escaped_s.c_str(), index));
+                                                               if (wideports)
+                                                                       wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
+                                                       }
+                                                       index++;
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                               log_error("Symbol type '%s' not recognised.\n", type.c_str());
+               }
+       }
+
+       for (auto &wp : wideports_cache) {
+               auto name = wp.first;
+               int width = wp.second + 1;
+
+               RTLIL::Wire *wire = module->wire(name);
+               if (wire)
+                       module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0)));
+
+               // Do not make ports with a mix of input/output into
+               // wide ports
+               bool port_input = false, port_output = false;
+               for (int i = 0; i < width; i++) {
+                       RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
+                       RTLIL::Wire *other_wire = module->wire(other_name);
+                       if (other_wire) {
+                               port_input = port_input || other_wire->port_input;
+                               port_output = port_output || other_wire->port_output;
+                       }
+               }
+               if ((port_input && port_output) || (!port_input && !port_output))
+                       continue;
+
+               wire = module->addWire(name, width);
+               wire->port_input = port_input;
+               wire->port_output = port_output;
+
+               for (int i = 0; i < width; i++) {
+                       RTLIL::IdString other_name = name.str() + stringf("[%d]", i);
+                       RTLIL::Wire *other_wire = module->wire(other_name);
+                       if (other_wire) {
+                               other_wire->port_input = false;
+                               other_wire->port_output = false;
+                               if (wire->port_input)
+                                       module->connect(other_wire, SigSpec(wire, i));
+                               else
+                                       module->connect(SigSpec(wire, i), other_wire);
+                       }
+               }
+       }
+
+       module->fixup_ports();
+       design->add(module);
+
+       design->selection_stack.emplace_back(false);
+       RTLIL::Selection& sel = design->selection_stack.back();
+       sel.select(module);
+
+       Pass::call(design, "clean");
+
+       design->selection_stack.pop_back();
+
+       for (auto cell : module->cells().to_vector()) {
+               if (cell->type != "$lut") continue;
+               auto y_port = cell->getPort("\\Y").as_bit();
+               if (y_port.wire->width == 1)
+                       module->rename(cell, stringf("%s$lut", y_port.wire->name.c_str()));
+               else
+                       module->rename(cell, stringf("%s[%d]$lut", y_port.wire->name.c_str(), y_port.offset));
        }
 }
 
@@ -398,18 +850,19 @@ struct AigerFrontend : public Frontend {
                log("Load module from an AIGER file into the current design.\n");
                log("\n");
                log("    -module_name <module_name>\n");
-               log("        Name of module to be created (default: "
-#ifdef _WIN32
-                               "top" // FIXME
-#else
-                               "<filename>"
-#endif
-                               ")\n");
+               log("        Name of module to be created (default: <filename>)\n");
                log("\n");
                log("    -clk_name <wire_name>\n");
                log("        AIGER latches to be transformed into posedge DFFs clocked by wire of");
                log("        this name (default: clk)\n");
                log("\n");
+               log("    -map <filename>\n");
+               log("        read file with port and latch symbols\n");
+               log("\n");
+               log("    -wideports\n");
+               log("        Merge ports that match the pattern 'name[int]' into a single\n");
+               log("        multi-bit port 'name'.\n");
+               log("\n");
        }
        void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
        {
@@ -417,6 +870,8 @@ struct AigerFrontend : public Frontend {
 
                RTLIL::IdString clk_name = "\\clk";
                RTLIL::IdString module_name;
+               std::string map_filename;
+               bool wideports = false;
 
                size_t argidx;
                for (argidx = 1; argidx < args.size(); argidx++) {
@@ -429,13 +884,23 @@ struct AigerFrontend : public Frontend {
                                clk_name = RTLIL::escape_id(args[++argidx]);
                                continue;
                        }
+                       if (map_filename.empty() && arg == "-map" && argidx+1 < args.size()) {
+                               map_filename = args[++argidx];
+                               continue;
+                       }
+                       if (arg == "-wideports") {
+                               wideports = true;
+                               continue;
+                       }
                        break;
                }
                extra_args(f, filename, args, argidx);
 
                if (module_name.empty()) {
 #ifdef _WIN32
-                       module_name = "top"; // FIXME: basename equivalent on Win32?
+                       char fname[_MAX_FNAME];
+                       _splitpath(filename.c_str(), NULL /* drive */, NULL /* dir */, fname, NULL /* ext */)
+                               module_name = fname;
 #else
                        char* bn = strdup(filename.c_str());
                        module_name = RTLIL::escape_id(bn);
@@ -443,7 +908,7 @@ struct AigerFrontend : public Frontend {
 #endif
                }
 
-               AigerReader reader(design, *f, module_name, clk_name);
+               AigerReader reader(design, *f, module_name, clk_name, map_filename, wideports);
                reader.parse_aiger();
        }
 } AigerFrontend;
index 0e3719cc463ec225f71eb46061cfd3dedfd6a23f..7d6d70b2ca7e5c295e71afa2da5dd3dd42e26d65 100644 (file)
@@ -31,20 +31,26 @@ struct AigerReader
     std::istream &f;
     RTLIL::IdString clk_name;
     RTLIL::Module *module;
+    std::string map_filename;
+    bool wideports;
 
     unsigned M, I, L, O, A;
     unsigned B, C, J, F; // Optional in AIGER 1.9
     unsigned line_count;
+    uint32_t piNum, flopNum;
 
     std::vector<RTLIL::Wire*> inputs;
     std::vector<RTLIL::Wire*> latches;
     std::vector<RTLIL::Wire*> outputs;
     std::vector<RTLIL::Wire*> bad_properties;
+    std::vector<RTLIL::Cell*> boxes;
 
-    AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name);
+    AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports);
     void parse_aiger();
+    void parse_xaiger();
     void parse_aiger_ascii();
     void parse_aiger_binary();
+    void post_process();
 };
 
 YOSYS_NAMESPACE_END
index 8509670ff4b2580361c8cb3a01555a718a01e441..d3ad57d727bd496e1d945371a5de51e70dfc4df7 100644 (file)
@@ -276,6 +276,12 @@ namespace RTLIL
                                return std::string(c_str() + pos, len);
                }
 
+               bool ends_with(const char* suffix) const {
+                       size_t len = strlen(suffix);
+                       if (size() < len) return false;
+                       return substr(size()-len) == suffix;
+               }
+
                size_t size() const {
                        return str().size();
                }
index d22685b62954bfd9b17888618a220e6038c4e634..c42f7fcdd787a50707e415e6580559cbc6329e53 100644 (file)
@@ -339,6 +339,9 @@ struct StatPass : public Pass {
                                if (mod->get_bool_attribute("\\top"))
                                        top_mod = mod;
 
+                       if (mod->attributes.count("\\abc_box_id"))
+                               continue;
+
                        statdata_t data(design, mod, width_mode, cell_area, techname);
                        mod_stat[mod->name] = data;
 
index 337fee9e43f02d3f0f65f41f93347f565ed516ce..ea36463303935a7431f94c4d8d07c84c4ac0e8e0 100644 (file)
@@ -14,5 +14,6 @@ OBJS += passes/opt/opt_demorgan.o
 OBJS += passes/opt/rmports.o
 OBJS += passes/opt/opt_lut.o
 OBJS += passes/opt/pmux2shiftx.o
+OBJS += passes/opt/muxpack.o
 endif
 
diff --git a/passes/opt/muxpack.cc b/passes/opt/muxpack.cc
new file mode 100644 (file)
index 0000000..8c4db4e
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *                2019  Eddie Hung    <eddie@fpgeh.com>
+ *
+ *  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
+
+struct MuxpackWorker
+{
+       Module *module;
+       SigMap sigmap;
+
+       int mux_count, pmux_count;
+
+       pool<Cell*> remove_cells;
+
+       dict<SigSpec, Cell*> sig_chain_next;
+       dict<SigSpec, Cell*> sig_chain_prev;
+       pool<SigBit> sigbit_with_non_chain_users;
+       pool<Cell*> chain_start_cells;
+       pool<Cell*> candidate_cells;
+
+       void make_sig_chain_next_prev()
+       {
+               for (auto wire : module->wires())
+               {
+                       if (wire->port_output || wire->get_bool_attribute("\\keep")) {
+                               for (auto bit : sigmap(wire))
+                                       sigbit_with_non_chain_users.insert(bit);
+                       }
+               }
+
+               for (auto cell : module->cells())
+               {
+                       if (cell->type.in("$mux", "$pmux") && !cell->get_bool_attribute("\\keep"))
+                       {
+                               SigSpec a_sig = sigmap(cell->getPort("\\A"));
+                               SigSpec b_sig;
+                               if (cell->type == "$mux")
+                                       b_sig = sigmap(cell->getPort("\\B"));
+                               SigSpec y_sig = sigmap(cell->getPort("\\Y"));
+   
+                               if (sig_chain_next.count(a_sig))
+                                       for (auto a_bit : a_sig.bits())
+                                               sigbit_with_non_chain_users.insert(a_bit);
+                               else {
+                                       sig_chain_next[a_sig] = cell;
+                                       candidate_cells.insert(cell);
+                               }
+
+                               if (!b_sig.empty()) {
+                                       if (sig_chain_next.count(b_sig))
+                                               for (auto b_bit : b_sig.bits())
+                                                       sigbit_with_non_chain_users.insert(b_bit);
+                                       else {
+                                               sig_chain_next[b_sig] = cell;
+                                               candidate_cells.insert(cell);
+                                       }
+                               }
+
+                               sig_chain_prev[y_sig] = cell;
+                               continue;
+                       }
+
+                       for (auto conn : cell->connections())
+                               if (cell->input(conn.first))
+                                       for (auto bit : sigmap(conn.second))
+                                               sigbit_with_non_chain_users.insert(bit);
+               }
+       }
+
+       void find_chain_start_cells()
+       {
+               for (auto cell : candidate_cells)
+               {
+                       log_debug("Considering %s (%s)\n", log_id(cell), log_id(cell->type));
+
+                       SigSpec a_sig = cell->getPort("\\A");
+                       if (cell->type == "$mux") {
+                               SigSpec b_sig = cell->getPort("\\B");
+                               if (sig_chain_prev.count(a_sig) + sig_chain_prev.count(b_sig) != 1)
+                                       goto start_cell;
+
+                               if (!sig_chain_prev.count(a_sig))
+                                       a_sig = b_sig;
+                       }
+                       else if (cell->type == "$pmux") {
+                               if (!sig_chain_prev.count(a_sig))
+                                       goto start_cell;
+                       }
+                       else log_abort();
+
+                       {
+                               for (auto bit : a_sig.bits())
+                                       if (sigbit_with_non_chain_users.count(bit))
+                                               goto start_cell;
+
+                               Cell *c1 = sig_chain_prev.at(a_sig);
+                               Cell *c2 = cell;
+
+                               if (c1->getParam("\\WIDTH") != c2->getParam("\\WIDTH"))
+                                       goto start_cell;
+                       }
+
+                       continue;
+
+               start_cell:
+                       chain_start_cells.insert(cell);
+               }
+       }
+
+       vector<Cell*> create_chain(Cell *start_cell)
+       {
+               vector<Cell*> chain;
+
+               Cell *c = start_cell;
+               while (c != nullptr)
+               {
+                       chain.push_back(c);
+
+                       SigSpec y_sig = sigmap(c->getPort("\\Y"));
+
+                       if (sig_chain_next.count(y_sig) == 0)
+                               break;
+
+                       c = sig_chain_next.at(y_sig);
+                       if (chain_start_cells.count(c) != 0)
+                               break;
+               }
+
+               return chain;
+       }
+
+       void process_chain(vector<Cell*> &chain)
+       {
+               if (GetSize(chain) < 2)
+                       return;
+
+               int cursor = 0;
+               while (cursor < GetSize(chain))
+               {
+                       int cases = GetSize(chain) - cursor;
+
+                       Cell *first_cell = chain[cursor];
+                       dict<int, SigBit> taps_dict;
+
+                       if (cases < 2) {
+                               cursor++;
+                               continue;
+                       }
+
+                       Cell *last_cell = chain[cursor+cases-1];
+
+                       log("Converting %s.%s ... %s.%s to a pmux with %d cases.\n",
+                               log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), cases);
+
+                       mux_count += cases;
+                       pmux_count += 1;
+
+                       first_cell->type = "$pmux";
+                       SigSpec b_sig = first_cell->getPort("\\B");
+                       SigSpec s_sig = first_cell->getPort("\\S");
+
+                       for (int i = 1; i < cases; i++) {
+                               Cell* prev_cell = chain[cursor+i-1];
+                               Cell* cursor_cell = chain[cursor+i];
+                               if (sigmap(prev_cell->getPort("\\Y")) == sigmap(cursor_cell->getPort("\\A"))) {
+                                       b_sig.append(cursor_cell->getPort("\\B"));
+                                       s_sig.append(cursor_cell->getPort("\\S"));
+                               }
+                               else {
+                                       b_sig.append(cursor_cell->getPort("\\A"));
+                                       s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort("\\S")));
+                               }
+                               remove_cells.insert(cursor_cell);
+                       }
+
+                       first_cell->setPort("\\B", b_sig);
+                       first_cell->setPort("\\S", s_sig);
+                       first_cell->setParam("\\S_WIDTH", GetSize(s_sig));
+                       first_cell->setPort("\\Y", last_cell->getPort("\\Y"));
+
+                       cursor += cases;
+               }
+       }
+
+       void cleanup()
+       {
+               for (auto cell : remove_cells)
+                       module->remove(cell);
+
+               remove_cells.clear();
+               sig_chain_next.clear();
+               sig_chain_prev.clear();
+               chain_start_cells.clear();
+               candidate_cells.clear();
+       }
+
+       MuxpackWorker(Module *module) :
+                       module(module), sigmap(module), mux_count(0), pmux_count(0)
+       {
+               make_sig_chain_next_prev();
+               find_chain_start_cells();
+
+               for (auto c : chain_start_cells) {
+                       vector<Cell*> chain = create_chain(c);
+                       process_chain(chain);
+               }
+
+               cleanup();
+       }
+};
+
+struct MuxpackPass : public Pass {
+       MuxpackPass() : Pass("muxpack", "$mux/$pmux cascades to $pmux") { }
+       void help() YS_OVERRIDE
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    muxpack [selection]\n");
+               log("\n");
+               log("This pass converts cascaded chains of $pmux cells (e.g. those create from case\n");
+               log("constructs) and $mux cells (e.g. those created by if-else constructs) into \n");
+               log("into $pmux cells.\n");
+               log("\n");
+       }
+       void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+       {
+               log_header(design, "Executing MUXPACK pass ($mux cell cascades to $pmux).\n");
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++)
+               {
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               int mux_count = 0;
+               int pmux_count = 0;
+
+               for (auto module : design->selected_modules()) {
+                       MuxpackWorker worker(module);
+                       mux_count += worker.mux_count;
+                       pmux_count += worker.pmux_count;
+               }
+
+               log("Converted %d (p)mux cells into %d pmux cells.\n", mux_count, pmux_count);
+       }
+} MuxpackPass;
+
+PRIVATE_NAMESPACE_END
index cf9e198adaa3004cf9977f21d27da22b1dcd7aef..c45571b01e30073262ee4b5596ffeabe5b105768 100644 (file)
@@ -7,6 +7,7 @@ OBJS += passes/techmap/libparse.o
 
 ifeq ($(ENABLE_ABC),1)
 OBJS += passes/techmap/abc.o
+OBJS += passes/techmap/abc9.o
 ifneq ($(ABCEXTERNAL),)
 passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"'
 endif
diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc
new file mode 100644 (file)
index 0000000..af9439e
--- /dev/null
@@ -0,0 +1,1422 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2019  Eddie Hung <eddie@fpgeh.com>
+ *
+ *  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.
+ *
+ */
+
+// [[CITE]] ABC
+// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification
+// http://www.eecs.berkeley.edu/~alanmi/abc/
+
+#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
+#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
+//#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2"
+#define ABC_COMMAND_LUT "&st; &sweep; &scorr; "/*"&dc2; */"&retime; &dch -f; &ps -l; &if -W 160 -v; &ps -l"
+#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}"
+#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
+
+#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}"
+#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
+#define ABC_FAST_COMMAND_LUT "&st; &retime; &if"
+#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}"
+#define ABC_FAST_COMMAND_DFL "strash; dretime; map"
+
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+#include "kernel/cost.h"
+#include "kernel/log.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <cerrno>
+#include <sstream>
+#include <climits>
+
+#ifndef _WIN32
+#  include <unistd.h>
+#  include <dirent.h>
+#endif
+
+#include "frontends/aiger/aigerparse.h"
+
+#ifdef YOSYS_LINK_ABC
+extern "C" int Abc_RealMain(int argc, char *argv[]);
+#endif
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+bool map_mux4;
+bool map_mux8;
+bool map_mux16;
+
+bool markgroups;
+int map_autoidx;
+SigMap assign_map;
+RTLIL::Module *module;
+std::map<RTLIL::SigBit, int> signal_map;
+std::map<RTLIL::SigBit, RTLIL::State> signal_init;
+pool<std::string> enabled_gates;
+bool recover_init;
+
+bool clk_polarity, en_polarity;
+RTLIL::SigSpec clk_sig, en_sig;
+dict<int, std::string> pi_map, po_map;
+
+std::string remap_name(RTLIL::IdString abc_name)
+{
+       std::stringstream sstr;
+       sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1);
+       return sstr.str();
+}
+
+void handle_loops(RTLIL::Design *design)
+{
+       Pass::call(design, "scc -set_attr abc_scc_id {}");
+
+       design->selection_stack.emplace_back(false);
+       RTLIL::Selection& sel = design->selection_stack.back();
+
+       // For every unique SCC found, (arbitrarily) find the first
+       // cell in the component, and select (and mark) all its output
+       // wires
+       pool<RTLIL::Const> ids_seen;
+       for (auto cell : module->cells()) {
+               auto it = cell->attributes.find("\\abc_scc_id");
+               if (it != cell->attributes.end()) {
+                       auto r = ids_seen.insert(it->second);
+                       if (r.second) {
+                               for (const 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;
+                                               w->set_bool_attribute("\\abc_scc_break");
+                                               sel.select(module, w);
+                                       }
+                               }
+                       }
+                       cell->attributes.erase(it);
+               }
+       }
+
+       // Then cut those selected wires to expose them as new PO/PI
+       Pass::call(design, "expose -cut -sep .abc");
+
+       design->selection_stack.pop_back();
+}
+
+std::string add_echos_to_abc_cmd(std::string str)
+{
+       std::string new_str, token;
+       for (size_t i = 0; i < str.size(); i++) {
+               token += str[i];
+               if (str[i] == ';') {
+                       while (i+1 < str.size() && str[i+1] == ' ')
+                               i++;
+                       new_str += "echo + " + token + " " + token + " ";
+                       token.clear();
+               }
+       }
+
+       if (!token.empty()) {
+               if (!new_str.empty())
+                       new_str += "echo + " + token + "; ";
+               new_str += token;
+       }
+
+       return new_str;
+}
+
+std::string fold_abc_cmd(std::string str)
+{
+       std::string token, new_str = "          ";
+       int char_counter = 10;
+
+       for (size_t i = 0; i <= str.size(); i++) {
+               if (i < str.size())
+                       token += str[i];
+               if (i == str.size() || str[i] == ';') {
+                       if (char_counter + token.size() > 75)
+                               new_str += "\n              ", char_counter = 14;
+                       new_str += token, char_counter += token.size();
+                       token.clear();
+               }
+       }
+
+       return new_str;
+}
+
+std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir)
+{
+       if (show_tempdir)
+               return text;
+
+       while (1) {
+               size_t pos = text.find(tempdir_name);
+               if (pos == std::string::npos)
+                       break;
+               text = text.substr(0, pos) + "<abc-temp-dir>" + text.substr(pos + GetSize(tempdir_name));
+       }
+
+       std::string  selfdir_name = proc_self_dirname();
+       if (selfdir_name != "/") {
+               while (1) {
+                       size_t pos = text.find(selfdir_name);
+                       if (pos == std::string::npos)
+                               break;
+                       text = text.substr(0, pos) + "<yosys-exe-dir>/" + text.substr(pos + GetSize(selfdir_name));
+               }
+       }
+
+       return text;
+}
+
+struct abc_output_filter
+{
+       bool got_cr;
+       int escape_seq_state;
+       std::string linebuf;
+       std::string tempdir_name;
+       bool show_tempdir;
+
+       abc_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir)
+       {
+               got_cr = false;
+               escape_seq_state = 0;
+       }
+
+       void next_char(char ch)
+       {
+               if (escape_seq_state == 0 && ch == '\033') {
+                       escape_seq_state = 1;
+                       return;
+               }
+               if (escape_seq_state == 1) {
+                       escape_seq_state = ch == '[' ? 2 : 0;
+                       return;
+               }
+               if (escape_seq_state == 2) {
+                       if ((ch < '0' || '9' < ch) && ch != ';')
+                               escape_seq_state = 0;
+                       return;
+               }
+               escape_seq_state = 0;
+               if (ch == '\r') {
+                       got_cr = true;
+                       return;
+               }
+               if (ch == '\n') {
+                       log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir).c_str());
+                       got_cr = false, linebuf.clear();
+                       return;
+               }
+               if (got_cr)
+                       got_cr = false, linebuf.clear();
+               linebuf += ch;
+       }
+
+       void next_line(const std::string &line)
+       {
+               int pi, po;
+               if (sscanf(line.c_str(), "Start-point = pi%d.  End-point = po%d.", &pi, &po) == 2) {
+                       log("ABC: Start-point = pi%d (%s).  End-point = po%d (%s).\n",
+                                       pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???",
+                                       po, po_map.count(po) ? po_map.at(po).c_str() : "???");
+                       return;
+               }
+
+               for (char ch : line)
+                       next_char(ch);
+       }
+};
+
+static std::pair<RTLIL::IdString, int> wideports_split(std::string name)
+{
+       int pos = -1;
+
+       if (name.empty() || name.back() != ']')
+               goto failed;
+
+       for (int i = 0; i+1 < GetSize(name); i++) {
+               if (name[i] == '[')
+                       pos = i;
+               else if (name[i] < '0' || name[i] > '9')
+                       pos = -1;
+               else if (i == pos+1 && name[i] == '0' && name[i+1] != ']')
+                       pos = -1;
+       }
+
+       if (pos >= 0)
+               return std::pair<RTLIL::IdString, int>(RTLIL::escape_id(name.substr(0, pos)), atoi(name.c_str() + pos+1));
+
+failed:
+       return std::pair<RTLIL::IdString, int>(name, 0);
+}
+
+void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
+               std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
+               bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode,
+               const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode, std::string box_file, std::string lut_file)
+{
+       module = current_module;
+       map_autoidx = autoidx++;
+
+       signal_map.clear();
+       pi_map.clear();
+       po_map.clear();
+       recover_init = false;
+
+       if (clk_str != "$")
+       {
+               clk_polarity = true;
+               clk_sig = RTLIL::SigSpec();
+
+               en_polarity = true;
+               en_sig = RTLIL::SigSpec();
+       }
+
+       if (!clk_str.empty() && clk_str != "$")
+       {
+               if (clk_str.find(',') != std::string::npos) {
+                       int pos = clk_str.find(',');
+                       std::string en_str = clk_str.substr(pos+1);
+                       clk_str = clk_str.substr(0, pos);
+                       if (en_str[0] == '!') {
+                               en_polarity = false;
+                               en_str = en_str.substr(1);
+                       }
+                       if (module->wires_.count(RTLIL::escape_id(en_str)) != 0)
+                               en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0));
+               }
+               if (clk_str[0] == '!') {
+                       clk_polarity = false;
+                       clk_str = clk_str.substr(1);
+               }
+               if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0)
+                       clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0));
+       }
+
+       if (dff_mode && clk_sig.empty())
+               log_cmd_error("Clock domain %s not found.\n", clk_str.c_str());
+
+       std::string tempdir_name = "/tmp/yosys-abc-XXXXXX";
+       if (!cleanup)
+               tempdir_name[0] = tempdir_name[4] = '_';
+       tempdir_name = make_temp_dir(tempdir_name);
+       log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n",
+                       module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
+
+       std::string abc_script;
+
+       if (!liberty_file.empty()) {
+               abc_script += stringf("read_lib -w %s; ", liberty_file.c_str());
+               if (!constr_file.empty())
+                       abc_script += stringf("read_constr -v %s; ", constr_file.c_str());
+       } else
+       if (!lut_costs.empty()) {
+               abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str());
+               if (!box_file.empty())
+                       abc_script += stringf("read_box -v %s; ", box_file.c_str());
+       }
+       else
+       if (!lut_file.empty()) {
+               abc_script += stringf("read_lut %s; ", lut_file.c_str());
+               if (!box_file.empty())
+                       abc_script += stringf("read_box -v %s; ", box_file.c_str());
+       }
+       else
+               abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str());
+
+       abc_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str());
+
+       if (!script_file.empty()) {
+               if (script_file[0] == '+') {
+                       for (size_t i = 1; i < script_file.size(); i++)
+                               if (script_file[i] == '\'')
+                                       abc_script += "'\\''";
+                               else if (script_file[i] == ',')
+                                       abc_script += " ";
+                               else
+                                       abc_script += script_file[i];
+               } else
+                       abc_script += stringf("source %s", script_file.c_str());
+       } else if (!lut_costs.empty() || !lut_file.empty()) {
+               //bool all_luts_cost_same = true;
+               //for (int this_cost : lut_costs)
+               //      if (this_cost != lut_costs.front())
+               //              all_luts_cost_same = false;
+               abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT;
+               //if (all_luts_cost_same && !fast_mode)
+               //      abc_script += "; lutpack {S}";
+       } else if (!liberty_file.empty())
+               abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR);
+       else if (sop_mode)
+               abc_script += fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP;
+       else
+               abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
+
+       if (script_file.empty() && !delay_target.empty())
+               for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1))
+                       abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8);
+
+       for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
+               abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
+
+       for (size_t pos = abc_script.find("{I}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
+               abc_script = abc_script.substr(0, pos) + sop_inputs + abc_script.substr(pos+3);
+
+       for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
+               abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3);
+
+       for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
+               abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3);
+
+       abc_script += stringf("; &write %s/output.aig", tempdir_name.c_str());
+       abc_script = add_echos_to_abc_cmd(abc_script);
+
+       for (size_t i = 0; i+1 < abc_script.size(); i++)
+               if (abc_script[i] == ';' && abc_script[i+1] == ' ')
+                       abc_script[i+1] = '\n';
+
+       FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt");
+       fprintf(f, "%s\n", abc_script.c_str());
+       fclose(f);
+
+       if (dff_mode || !clk_str.empty())
+       {
+               if (clk_sig.size() == 0)
+                       log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching");
+               else {
+                       log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig));
+                       if (en_sig.size() != 0)
+                               log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig));
+                       log("\n");
+               }
+       }
+
+       design->selection_stack.emplace_back(false);
+       RTLIL::Selection& sel = design->selection_stack.back();
+       sel.select(module);
+
+       // Behave as for "abc" where BLIF writer implicitly outputs all undef as zero
+       Pass::call(design, "setundef -zero");
+
+       Pass::call(design, "aigmap");
+
+       handle_loops(design);
+
+       Pass::call(design, stringf("write_xaiger -O -map %s/input.sym %s/input.xaig; ", tempdir_name.c_str(), tempdir_name.c_str()));
+
+#if 0
+       std::string buffer = stringf("%s/%s", tempdir_name.c_str(), "input.xaig");
+       std::ifstream ifs;
+       ifs.open(buffer);
+       if (ifs.fail())
+               log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
+       buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym");
+       log_assert(!design->module("$__abc9__"));
+       AigerReader reader(design, ifs, "$__abc9__", "" /* clk_name */, buffer.c_str() /* map_filename */, false /* wideports */);
+       reader.parse_xaiger();
+       ifs.close();
+       Pass::call(design, stringf("write_verilog -noexpr -norename %s/%s", tempdir_name.c_str(), "input.v"));
+       design->remove(design->module("$__abc9__"));
+#endif
+
+       design->selection_stack.pop_back();
+
+       // 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("\\abc_scc_break");
+               if (it != wire->attributes.end()) {
+                       wire->attributes.erase(it);
+                       log_assert(wire->port_output);
+                       wire->port_output = false;
+                       RTLIL::Wire *i_wire = module->wire(wire->name.str() + ".abci");
+                       log_assert(i_wire);
+                       log_assert(i_wire->port_input);
+                       i_wire->port_input = false;
+                       module->connect(i_wire, wire);
+               }
+       }
+       module->fixup_ports();
+
+       //log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
+       //              count_gates, GetSize(signal_list), count_input, count_output);
+
+       log_push();
+
+       //if (count_output > 0)
+       {
+               log_header(design, "Executing ABC9.\n");
+
+        std::string buffer;
+               if (!lut_costs.empty()) {
+                       buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str());
+                       f = fopen(buffer.c_str(), "wt");
+                       if (f == NULL)
+                               log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
+                       for (int i = 0; i < GetSize(lut_costs); i++)
+                               fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i));
+                       fclose(f);
+               }
+
+               buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
+               log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
+
+#ifndef YOSYS_LINK_ABC
+               abc_output_filter filt(tempdir_name, show_tempdir);
+               int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
+#else
+               // These needs to be mutable, supposedly due to getopt
+               char *abc_argv[5];
+               string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str());
+               abc_argv[0] = strdup(exe_file.c_str());
+               abc_argv[1] = strdup("-s");
+               abc_argv[2] = strdup("-f");
+               abc_argv[3] = strdup(tmp_script_name.c_str());
+               abc_argv[4] = 0;
+               int ret = Abc_RealMain(4, abc_argv);
+               free(abc_argv[0]);
+               free(abc_argv[1]);
+               free(abc_argv[2]);
+               free(abc_argv[3]);
+#endif
+               if (ret != 0)
+                       log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret);
+
+               buffer = stringf("%s/%s", tempdir_name.c_str(), "output.aig");
+               std::ifstream ifs;
+               ifs.open(buffer);
+               if (ifs.fail())
+                       log_error("Can't open ABC output file `%s'.\n", buffer.c_str());
+
+               bool builtin_lib = liberty_file.empty();
+               //parse_blif(mapped_design, ifs, builtin_lib ? "\\DFF" : "\\_dff_", false, sop_mode);
+               buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym");
+               log_assert(!design->module("$__abc9__"));
+               AigerReader reader(design, ifs, "$__abc9__", "" /* clk_name */, buffer.c_str() /* map_filename */, false /* wideports */);
+               reader.parse_xaiger();
+               ifs.close();
+
+#if 0
+               Pass::call(design, stringf("write_verilog -noexpr -norename %s/%s", tempdir_name.c_str(), "output.v"));
+#endif
+
+               log_header(design, "Re-integrating ABC9 results.\n");
+               RTLIL::Module *mapped_mod = design->module("$__abc9__");
+               if (mapped_mod == NULL)
+                       log_error("ABC output file does not contain a module `$__abc9__'.\n");
+
+               pool<RTLIL::SigBit> output_bits;
+               for (auto &it : mapped_mod->wires_) {
+                       RTLIL::Wire *w = it.second;
+                       RTLIL::Wire *remap_wire = module->addWire(remap_name(w->name), GetSize(w));
+                       if (markgroups) remap_wire->attributes["\\abcgroup"] = map_autoidx;
+                       if (w->port_output) {
+                               RTLIL::Wire *wire = module->wire(w->name);
+                               if (wire) {
+                                       for (int i = 0; i < GetSize(wire); i++)
+                                               output_bits.insert({wire, i});
+                               }
+                               else {
+                                       // Attempt another wideports_split here because there
+                                       // exists the possibility that different bits of a port
+                                       // could be an input and output, therefore parse_xaiger()
+                                       // could not combine it into a wideport
+                                       auto r = wideports_split(w->name.str());
+                                       wire = module->wire(r.first);
+                                       log_assert(wire);
+                                       int i = r.second;
+                                       output_bits.insert({wire, i});
+                               }
+                       }
+               }
+
+               // Remove all AND, NOT, and ABC box instances
+               // in preparation for stitching mapped_mod in
+               dict<IdString, decltype(RTLIL::Cell::parameters)> erased_boxes;
+               for (auto it = module->cells_.begin(); it != module->cells_.end(); ) {
+                       RTLIL::Cell* cell = it->second;
+                       if (cell->type.in("$_AND_", "$_NOT_")) {
+                               it = module->cells_.erase(it);
+                               continue;
+                       }
+                       RTLIL::Module* box_module = design->module(cell->type);
+                       if (box_module && box_module->attributes.count("\\abc_box_id")) {
+                               erased_boxes.insert(std::make_pair(it->first, std::move(cell->parameters)));
+                               it = module->cells_.erase(it);
+                               continue;
+                       }
+                       ++it;
+               }
+               // Do the same for module connections
+               for (auto &it : module->connections_) {
+                       auto &signal = it.first;
+                       auto bits = signal.bits();
+                       for (auto &b : bits)
+                               if (output_bits.count(b))
+                                       b = module->addWire(NEW_ID);
+                       signal = std::move(bits);
+               }
+
+               std::map<std::string, int> cell_stats;
+               for (auto c : mapped_mod->cells())
+               {
+                       if (builtin_lib)
+                       {
+                               if (c->type == "$_NOT_") {
+                                       RTLIL::Cell *cell;
+                                       RTLIL::SigBit a_bit = c->getPort("\\A").as_bit();
+                                       RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit();
+                                       if (!a_bit.wire) {
+                                               c->setPort("\\Y", module->addWire(NEW_ID));
+                                               module->connect(module->wires_[remap_name(y_bit.wire->name)], RTLIL::S1);
+                                       }
+                                       else if (!lut_costs.empty() || !lut_file.empty()) {
+                                               RTLIL::Cell* driving_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 driving 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);
+                                                       driving_lut = mapped_mod->cell(driver_name);
+                                               }
+
+                                               if (!driving_lut) {
+                                                       // If a driver couldn't be found (could be from PI,
+                                                       // or from a box) then implement using a LUT
+                                                       cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
+                                                                       RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset),
+                                                                       RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset),
+                                                                       1);
+                                               }
+                                               else {
+                                                       auto driver_a = driving_lut->getPort("\\A").chunks();
+                                                       for (auto &chunk : driver_a)
+                                                               chunk.wire = module->wires_[remap_name(chunk.wire->name)];
+                                                       RTLIL::Const driver_lut = driving_lut->getParam("\\LUT");
+                                                       for (auto &b : driver_lut.bits) {
+                                                               if (b == RTLIL::State::S0) b = RTLIL::State::S1;
+                                                               else if (b == RTLIL::State::S1) b = RTLIL::State::S0;
+                                                       }
+                                                       cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
+                                                                       driver_a,
+                                                                       RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset),
+                                                                       driver_lut);
+                                               }
+                                       }
+                                       else {
+                                               cell = module->addCell(remap_name(c->name), "$_NOT_");
+                                               cell->setPort("\\A", RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset));
+                                               cell->setPort("\\Y", RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset));
+                                               cell_stats[RTLIL::unescape_id(c->type)]++;
+                                       }
+                                       if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
+                                       continue;
+                               }
+                       }
+            cell_stats[RTLIL::unescape_id(c->type)]++;
+
+                       if (c->type == "$lut") {
+                               if (GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) {
+                                       SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)];
+                                       SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)];
+                                       module->connect(my_y, my_a);
+                                       continue;
+                               }
+                       }
+                       else {
+                auto it = erased_boxes.find(c->name);
+                log_assert(it != erased_boxes.end());
+                c->parameters = std::move(it->second);
+            }
+
+                       RTLIL::Cell* cell = module->addCell(remap_name(c->name), c->type);
+                       if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
+                       cell->parameters = c->parameters;
+                       for (auto &conn : c->connections()) {
+                               RTLIL::SigSpec newsig;
+                               for (auto c : conn.second.chunks()) {
+                                       if (c.width == 0)
+                                               continue;
+                                       //log_assert(c.width == 1);
+                                       if (c.wire)
+                                               c.wire = module->wires_[remap_name(c.wire->name)];
+                                       newsig.append(c);
+                               }
+                               cell->setPort(conn.first, newsig);
+                       }
+               }
+
+               // 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_[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_[remap_name(c.wire->name)];
+                               conn.second = std::move(chunks);
+                       }
+                       module->connect(conn);
+               }
+
+               if (recover_init)
+                       for (auto wire : mapped_mod->wires()) {
+                               if (wire->attributes.count("\\init")) {
+                                       Wire *w = module->wires_[remap_name(wire->name)];
+                                       log_assert(w->attributes.count("\\init") == 0);
+                                       w->attributes["\\init"] = wire->attributes.at("\\init");
+                               }
+                       }
+
+               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 &it : mapped_mod->wires_) {
+                       RTLIL::Wire *w = it.second;
+                       if (!w->port_input && !w->port_output)
+                               continue;
+                       RTLIL::Wire *wire = module->wire(w->name);
+                       RTLIL::Wire *remap_wire = module->wire(remap_name(w->name));
+                       RTLIL::SigSpec signal;
+                       if (wire) {
+                               signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire));
+                       }
+                       else {
+                               // Attempt another wideports_split here because there
+                               // exists the possibility that different bits of a port
+                               // could be an input and output, therefore parse_xaiger()
+                               // could not combine it into a wideport
+                               auto r = wideports_split(w->name.str());
+                               wire = module->wire(r.first);
+                               log_assert(wire);
+                               int i = r.second;
+                               signal = RTLIL::SigSpec(wire, i);
+                       }
+                       log_assert(GetSize(signal) >= GetSize(remap_wire));
+
+                       log_assert(w->port_input || w->port_output);
+                       RTLIL::SigSig conn;
+                       if (w->port_input) {
+                               conn.first = remap_wire;
+                               conn.second = signal;
+                               in_wires++;
+                               module->connect(conn);
+                       }
+                       if (w->port_output) {
+                               conn.first = signal;
+                               conn.second = remap_wire;
+                               out_wires++;
+                               module->connect(conn);
+                       }
+               }
+
+               //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);
+       }
+       //else
+       //{
+       //      log("Don't call ABC as there is nothing to map.\n");
+       //}
+
+       if (cleanup)
+       {
+               log("Removing temp directory.\n");
+               remove_directory(tempdir_name);
+       }
+
+       log_pop();
+}
+
+struct Abc9Pass : public Pass {
+       Abc9Pass() : Pass("abc9", "use ABC for technology mapping") { }
+       void help() YS_OVERRIDE
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    abc9 [options] [selection]\n");
+               log("\n");
+               log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n");
+               log("library to a target architecture.\n");
+               log("\n");
+               log("    -exe <command>\n");
+#ifdef ABCEXTERNAL
+               log("        use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n");
+#else
+               log("        use the specified command instead of \"<yosys-bindir>/yosys-abc\" to execute ABC.\n");
+#endif
+               log("        This can e.g. be used to call a specific version of ABC or a wrapper.\n");
+               log("\n");
+               log("    -script <file>\n");
+               log("        use the specified ABC script file instead of the default script.\n");
+               log("\n");
+               log("        if <file> starts with a plus sign (+), then the rest of the filename\n");
+               log("        string is interpreted as the command string to be passed to ABC. The\n");
+               log("        leading plus sign is removed and all commas (,) in the string are\n");
+               log("        replaced with blanks before the string is passed to ABC.\n");
+               log("\n");
+               log("        if no -script parameter is given, the following scripts are used:\n");
+               log("\n");
+               log("        for -liberty without -constr:\n");
+               log("%s\n", fold_abc_cmd(ABC_COMMAND_LIB).c_str());
+               log("\n");
+               log("        for -liberty with -constr:\n");
+               log("%s\n", fold_abc_cmd(ABC_COMMAND_CTR).c_str());
+               log("\n");
+               log("        for -lut/-luts (only one LUT size):\n");
+               log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT "; lutpack {S}").c_str());
+               log("\n");
+               log("        for -lut/-luts (different LUT sizes):\n");
+               log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str());
+               log("\n");
+               log("        for -sop:\n");
+               log("%s\n", fold_abc_cmd(ABC_COMMAND_SOP).c_str());
+               log("\n");
+               log("        otherwise:\n");
+               log("%s\n", fold_abc_cmd(ABC_COMMAND_DFL).c_str());
+               log("\n");
+               log("    -fast\n");
+               log("        use different default scripts that are slightly faster (at the cost\n");
+               log("        of output quality):\n");
+               log("\n");
+               log("        for -liberty without -constr:\n");
+               log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LIB).c_str());
+               log("\n");
+               log("        for -liberty with -constr:\n");
+               log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_CTR).c_str());
+               log("\n");
+               log("        for -lut/-luts:\n");
+               log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LUT).c_str());
+               log("\n");
+               log("        for -sop:\n");
+               log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_SOP).c_str());
+               log("\n");
+               log("        otherwise:\n");
+               log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_DFL).c_str());
+               log("\n");
+               log("    -liberty <file>\n");
+               log("        generate netlists for the specified cell library (using the liberty\n");
+               log("        file format).\n");
+               log("\n");
+               log("    -constr <file>\n");
+               log("        pass this file with timing constraints to ABC. Use with -liberty.\n");
+               log("\n");
+               log("        a constr file contains two lines:\n");
+               log("            set_driving_cell <cell_name>\n");
+               log("            set_load <floating_point_number>\n");
+               log("\n");
+               log("        the set_driving_cell statement defines which cell type is assumed to\n");
+               log("        drive the primary inputs and the set_load statement sets the load in\n");
+               log("        femtofarads for each primary output.\n");
+               log("\n");
+               log("    -D <picoseconds>\n");
+               log("        set delay target. the string {D} in the default scripts above is\n");
+               log("        replaced by this option when used, and an empty string otherwise.\n");
+               log("        this also replaces 'dretime' with 'dretime; retime -o {D}' in the\n");
+               log("        default scripts above.\n");
+               log("\n");
+               log("    -I <num>\n");
+               log("        maximum number of SOP inputs.\n");
+               log("        (replaces {I} in the default scripts above)\n");
+               log("\n");
+               log("    -P <num>\n");
+               log("        maximum number of SOP products.\n");
+               log("        (replaces {P} in the default scripts above)\n");
+               log("\n");
+               log("    -S <num>\n");
+               log("        maximum number of LUT inputs shared.\n");
+               log("        (replaces {S} in the default scripts above, default: -S 1)\n");
+               log("\n");
+               log("    -lut <width>\n");
+               log("        generate netlist using luts of (max) the specified width.\n");
+               log("\n");
+               log("    -lut <w1>:<w2>\n");
+               log("        generate netlist using luts of (max) the specified width <w2>. All\n");
+               log("        luts with width <= <w1> have constant cost. for luts larger than <w1>\n");
+               log("        the area cost doubles with each additional input bit. the delay cost\n");
+               log("        is still constant for all lut widths.\n");
+               log("\n");
+               log("    -lut <file>\n");
+               log("        pass this file with lut library to ABC.\n");
+               log("\n");
+               log("    -luts <cost1>,<cost2>,<cost3>,<sizeN>:<cost4-N>,..\n");
+               log("        generate netlist using luts. Use the specified costs for luts with 1,\n");
+               log("        2, 3, .. inputs.\n");
+               log("\n");
+               log("    -sop\n");
+               log("        map to sum-of-product cells and inverters\n");
+               log("\n");
+               // log("    -mux4, -mux8, -mux16\n");
+               // log("        try to extract 4-input, 8-input, and/or 16-input muxes\n");
+               // log("        (ignored when used with -liberty or -lut)\n");
+               // log("\n");
+               log("    -g type1,type2,...\n");
+               log("        Map to the specified list of gate types. Supported gates types are:\n");
+               log("        AND, NAND, OR, NOR, XOR, XNOR, ANDNOT, ORNOT, MUX, AOI3, OAI3, AOI4, OAI4.\n");
+               log("        (The NOT gate is always added to this list automatically.)\n");
+               log("\n");
+               log("        The following aliases can be used to reference common sets of gate types:\n");
+               log("          simple: AND OR XOR MUX\n");
+               log("          cmos2: NAND NOR\n");
+               log("          cmos3: NAND NOR AOI3 OAI3\n");
+               log("          cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4\n");
+               log("          gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n");
+               log("          aig: AND NAND OR NOR ANDNOT ORNOT\n");
+               log("\n");
+               log("        Prefix a gate type with a '-' to remove it from the list. For example\n");
+               log("        the arguments 'AND,OR,XOR' and 'simple,-MUX' are equivalent.\n");
+               log("\n");
+               log("    -dff\n");
+               log("        also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n");
+               log("        clock domains are automatically partitioned in clock domains and each\n");
+               log("        domain is passed through ABC independently.\n");
+               log("\n");
+               log("    -clk [!]<clock-signal-name>[,[!]<enable-signal-name>]\n");
+               log("        use only the specified clock domain. this is like -dff, but only FF\n");
+               log("        cells that belong to the specified clock domain are used.\n");
+               log("\n");
+               log("    -keepff\n");
+               log("        set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n");
+               log("        them, for example for equivalence checking.)\n");
+               log("\n");
+               log("    -nocleanup\n");
+               log("        when this option is used, the temporary files created by this pass\n");
+               log("        are not removed. this is useful for debugging.\n");
+               log("\n");
+               log("    -showtmp\n");
+               log("        print the temp dir name in log. usually this is suppressed so that the\n");
+               log("        command output is identical across runs.\n");
+               log("\n");
+               log("    -markgroups\n");
+               log("        set a 'abcgroup' attribute on all objects created by ABC. The value of\n");
+               log("        this attribute is a unique integer for each ABC process started. This\n");
+               log("        is useful for debugging the partitioning of clock domains.\n");
+               log("\n");
+               log("    -box <file>\n");
+               log("        pass this file with box library to ABC. Use with -lut.\n");
+               log("\n");
+               log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n");
+               log("loaded into ABC before the ABC script is executed.\n");
+               log("\n");
+               log("Note that this is a logic optimization pass within Yosys that is calling ABC\n");
+               log("internally. This is not going to \"run ABC on your design\". It will instead run\n");
+               log("ABC on logic snippets extracted from your design. You will not get any useful\n");
+               log("output when passing an ABC script that writes a file. Instead write your full\n");
+               log("design as BLIF file with write_blif and the load that into ABC externally if\n");
+               log("you want to use ABC to convert your design into another format.\n");
+               log("\n");
+               log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
+               log("\n");
+       }
+       void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+       {
+               log_header(design, "Executing ABC9 pass (technology mapping using ABC).\n");
+               log_push();
+
+               assign_map.clear();
+               signal_map.clear();
+               signal_init.clear();
+               pi_map.clear();
+               po_map.clear();
+
+#ifdef ABCEXTERNAL
+               std::string exe_file = ABCEXTERNAL;
+#else
+               std::string exe_file = proc_self_dirname() + "yosys-abc";
+#endif
+               std::string script_file, liberty_file, constr_file, clk_str, box_file, lut_file;
+               std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
+               bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
+               bool show_tempdir = false, sop_mode = false;
+               vector<int> lut_costs;
+               markgroups = false;
+
+#if 0
+               cleanup = false;
+               show_tempdir = true;
+#endif
+
+               map_mux4 = false;
+               map_mux8 = false;
+               map_mux16 = false;
+               enabled_gates.clear();
+
+#ifdef _WIN32
+#ifndef ABCEXTERNAL
+               if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe"))
+                       exe_file = proc_self_dirname() + "..\\yosys-abc";
+#endif
+#endif
+
+               size_t argidx;
+               char pwd [PATH_MAX];
+               if (!getcwd(pwd, sizeof(pwd))) {
+                       log_cmd_error("getcwd failed: %s\n", strerror(errno));
+                       log_abort();
+               }
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       std::string arg = args[argidx];
+                       if (arg == "-exe" && argidx+1 < args.size()) {
+                               exe_file = args[++argidx];
+                               continue;
+                       }
+                       if (arg == "-script" && argidx+1 < args.size()) {
+                               script_file = args[++argidx];
+                               rewrite_filename(script_file);
+                               if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+')
+                                       script_file = std::string(pwd) + "/" + script_file;
+                               continue;
+                       }
+                       if (arg == "-liberty" && argidx+1 < args.size()) {
+                               liberty_file = args[++argidx];
+                               rewrite_filename(liberty_file);
+                               if (!liberty_file.empty() && !is_absolute_path(liberty_file))
+                                       liberty_file = std::string(pwd) + "/" + liberty_file;
+                               continue;
+                       }
+                       if (arg == "-constr" && argidx+1 < args.size()) {
+                               constr_file = args[++argidx];
+                               rewrite_filename(constr_file);
+                               if (!constr_file.empty() && !is_absolute_path(constr_file))
+                                       constr_file = std::string(pwd) + "/" + constr_file;
+                               continue;
+                       }
+                       if (arg == "-D" && argidx+1 < args.size()) {
+                               delay_target = "-D " + args[++argidx];
+                               continue;
+                       }
+                       if (arg == "-I" && argidx+1 < args.size()) {
+                               sop_inputs = "-I " + args[++argidx];
+                               continue;
+                       }
+                       if (arg == "-P" && argidx+1 < args.size()) {
+                               sop_products = "-P " + args[++argidx];
+                               continue;
+                       }
+                       if (arg == "-S" && argidx+1 < args.size()) {
+                               lutin_shared = "-S " + args[++argidx];
+                               continue;
+                       }
+                       if (arg == "-lut" && argidx+1 < args.size()) {
+                               string arg = args[++argidx];
+                               size_t pos = arg.find_first_of(':');
+                               int lut_mode = 0, lut_mode2 = 0;
+                               if (pos != string::npos) {
+                                       lut_mode = atoi(arg.substr(0, pos).c_str());
+                                       lut_mode2 = atoi(arg.substr(pos+1).c_str());
+                               } else {
+                                       pos = arg.find_first_of('.');
+                                       if (pos != string::npos) {
+                                               lut_file = arg;
+                                               rewrite_filename(lut_file);
+                                               if (!lut_file.empty() && !is_absolute_path(lut_file))
+                                                       lut_file = std::string(pwd) + "/" + lut_file;
+                                       }
+                                       else {
+                                               lut_mode = atoi(arg.c_str());
+                                               lut_mode2 = lut_mode;
+                                       }
+                               }
+                               lut_costs.clear();
+                               for (int i = 0; i < lut_mode; i++)
+                                       lut_costs.push_back(1);
+                               for (int i = lut_mode; i < lut_mode2; i++)
+                                       lut_costs.push_back(2 << (i - lut_mode));
+                               continue;
+                       }
+                       if (arg == "-luts" && argidx+1 < args.size()) {
+                               lut_costs.clear();
+                               for (auto &tok : split_tokens(args[++argidx], ",")) {
+                                       auto parts = split_tokens(tok, ":");
+                                       if (GetSize(parts) == 0 && !lut_costs.empty())
+                                               lut_costs.push_back(lut_costs.back());
+                                       else if (GetSize(parts) == 1)
+                                               lut_costs.push_back(atoi(parts.at(0).c_str()));
+                                       else if (GetSize(parts) == 2)
+                                               while (GetSize(lut_costs) < atoi(parts.at(0).c_str()))
+                                                       lut_costs.push_back(atoi(parts.at(1).c_str()));
+                                       else
+                                               log_cmd_error("Invalid -luts syntax.\n");
+                               }
+                               continue;
+                       }
+                       if (arg == "-sop") {
+                               sop_mode = true;
+                               continue;
+                       }
+                       if (arg == "-mux4") {
+                               map_mux4 = true;
+                               continue;
+                       }
+                       if (arg == "-mux8") {
+                               map_mux8 = true;
+                               continue;
+                       }
+                       if (arg == "-mux16") {
+                               map_mux16 = true;
+                               continue;
+                       }
+                       if (arg == "-dress") {
+                               // TODO
+                               //abc_dress = true;
+                               continue;
+                       }
+                       if (arg == "-g" && argidx+1 < args.size()) {
+                               for (auto g : split_tokens(args[++argidx], ",")) {
+                                       vector<string> gate_list;
+                                       bool remove_gates = false;
+                                       if (GetSize(g) > 0 && g[0] == '-') {
+                                               remove_gates = true;
+                                               g = g.substr(1);
+                                       }
+                                       if (g == "AND") goto ok_gate;
+                                       if (g == "NAND") goto ok_gate;
+                                       if (g == "OR") goto ok_gate;
+                                       if (g == "NOR") goto ok_gate;
+                                       if (g == "XOR") goto ok_gate;
+                                       if (g == "XNOR") goto ok_gate;
+                                       if (g == "ANDNOT") goto ok_gate;
+                                       if (g == "ORNOT") goto ok_gate;
+                                       if (g == "MUX") goto ok_gate;
+                                       if (g == "AOI3") goto ok_gate;
+                                       if (g == "OAI3") goto ok_gate;
+                                       if (g == "AOI4") goto ok_gate;
+                                       if (g == "OAI4") goto ok_gate;
+                                       if (g == "simple") {
+                                               gate_list.push_back("AND");
+                                               gate_list.push_back("OR");
+                                               gate_list.push_back("XOR");
+                                               gate_list.push_back("MUX");
+                                               goto ok_alias;
+                                       }
+                                       if (g == "cmos2") {
+                                               gate_list.push_back("NAND");
+                                               gate_list.push_back("NOR");
+                                               goto ok_alias;
+                                       }
+                                       if (g == "cmos3") {
+                                               gate_list.push_back("NAND");
+                                               gate_list.push_back("NOR");
+                                               gate_list.push_back("AOI3");
+                                               gate_list.push_back("OAI3");
+                                               goto ok_alias;
+                                       }
+                                       if (g == "cmos4") {
+                                               gate_list.push_back("NAND");
+                                               gate_list.push_back("NOR");
+                                               gate_list.push_back("AOI3");
+                                               gate_list.push_back("OAI3");
+                                               gate_list.push_back("AOI4");
+                                               gate_list.push_back("OAI4");
+                                               goto ok_alias;
+                                       }
+                                       if (g == "gates") {
+                                               gate_list.push_back("AND");
+                                               gate_list.push_back("NAND");
+                                               gate_list.push_back("OR");
+                                               gate_list.push_back("NOR");
+                                               gate_list.push_back("XOR");
+                                               gate_list.push_back("XNOR");
+                                               gate_list.push_back("ANDNOT");
+                                               gate_list.push_back("ORNOT");
+                                               goto ok_alias;
+                                       }
+                                       if (g == "aig") {
+                                               gate_list.push_back("AND");
+                                               gate_list.push_back("NAND");
+                                               gate_list.push_back("OR");
+                                               gate_list.push_back("NOR");
+                                               gate_list.push_back("ANDNOT");
+                                               gate_list.push_back("ORNOT");
+                                               goto ok_alias;
+                                       }
+                                       cmd_error(args, argidx, stringf("Unsupported gate type: %s", g.c_str()));
+                               ok_gate:
+                                       gate_list.push_back(g);
+                               ok_alias:
+                                       for (auto gate : gate_list) {
+                                               if (remove_gates)
+                                                       enabled_gates.erase(gate);
+                                               else
+                                                       enabled_gates.insert(gate);
+                                       }
+                               }
+                               continue;
+                       }
+                       if (arg == "-fast") {
+                               fast_mode = true;
+                               continue;
+                       }
+                       if (arg == "-dff") {
+                               dff_mode = true;
+                               continue;
+                       }
+                       if (arg == "-clk" && argidx+1 < args.size()) {
+                               clk_str = args[++argidx];
+                               dff_mode = true;
+                               continue;
+                       }
+                       if (arg == "-keepff") {
+                               keepff = true;
+                               continue;
+                       }
+                       if (arg == "-nocleanup") {
+                               cleanup = false;
+                               continue;
+                       }
+                       if (arg == "-showtmp") {
+                               show_tempdir = true;
+                               continue;
+                       }
+                       if (arg == "-markgroups") {
+                               markgroups = true;
+                               continue;
+                       }
+                       if (arg == "-box" && argidx+1 < args.size()) {
+                               box_file = args[++argidx];
+                               rewrite_filename(box_file);
+                               if (!box_file.empty() && !is_absolute_path(box_file))
+                                       box_file = std::string(pwd) + "/" + box_file;
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               if ((!lut_costs.empty() || !lut_file.empty()) && !liberty_file.empty())
+                       log_cmd_error("Got -lut and -liberty! This two options are exclusive.\n");
+               if (!constr_file.empty() && liberty_file.empty())
+                       log_cmd_error("Got -constr but no -liberty!\n");
+
+               for (auto mod : design->selected_modules())
+               {
+                       if (mod->attributes.count("\\abc_box_id"))
+                               continue;
+
+                       if (mod->processes.size() > 0) {
+                               log("Skipping module %s as it contains processes.\n", log_id(mod));
+                               continue;
+                       }
+
+                       assign_map.set(mod);
+                       signal_init.clear();
+
+                       for (Wire *wire : mod->wires())
+                               if (wire->attributes.count("\\init")) {
+                                       SigSpec initsig = assign_map(wire);
+                                       Const initval = wire->attributes.at("\\init");
+                                       for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++)
+                                               switch (initval[i]) {
+                                                       case State::S0:
+                                                               signal_init[initsig[i]] = State::S0;
+                                                               break;
+                                                       case State::S1:
+                                                               signal_init[initsig[i]] = State::S0;
+                                                               break;
+                                                       default:
+                                                               break;
+                                               }
+                               }
+
+                       if (!dff_mode || !clk_str.empty()) {
+                               abc9_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
+                                               delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode,
+                                               box_file, lut_file);
+                               continue;
+                       }
+
+                       CellTypes ct(design);
+
+                       std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
+                       std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
+
+                       std::set<RTLIL::Cell*> expand_queue, next_expand_queue;
+                       std::set<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
+                       std::set<RTLIL::Cell*> expand_queue_down, next_expand_queue_down;
+
+                       typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t;
+                       std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells;
+                       std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse;
+
+                       std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down;
+                       std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cell, bit_to_cell_up, bit_to_cell_down;
+
+                       for (auto cell : all_cells)
+                       {
+                               clkdomain_t key;
+
+                               for (auto &conn : cell->connections())
+                               for (auto bit : conn.second) {
+                                       bit = assign_map(bit);
+                                       if (bit.wire != nullptr) {
+                                               cell_to_bit[cell].insert(bit);
+                                               bit_to_cell[bit].insert(cell);
+                                               if (ct.cell_input(cell->type, conn.first)) {
+                                                       cell_to_bit_up[cell].insert(bit);
+                                                       bit_to_cell_down[bit].insert(cell);
+                                               }
+                                               if (ct.cell_output(cell->type, conn.first)) {
+                                                       cell_to_bit_down[cell].insert(bit);
+                                                       bit_to_cell_up[bit].insert(cell);
+                                               }
+                                       }
+                               }
+
+                               if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_")
+                               {
+                                       key = clkdomain_t(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")), true, RTLIL::SigSpec());
+                               }
+                               else
+                               if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")
+                               {
+                                       bool this_clk_pol = cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_";
+                                       bool this_en_pol = cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_";
+                                       key = clkdomain_t(this_clk_pol, assign_map(cell->getPort("\\C")), this_en_pol, assign_map(cell->getPort("\\E")));
+                               }
+                               else
+                                       continue;
+
+                               unassigned_cells.erase(cell);
+                               expand_queue.insert(cell);
+                               expand_queue_up.insert(cell);
+                               expand_queue_down.insert(cell);
+
+                               assigned_cells[key].push_back(cell);
+                               assigned_cells_reverse[cell] = key;
+                       }
+
+                       while (!expand_queue_up.empty() || !expand_queue_down.empty())
+                       {
+                               if (!expand_queue_up.empty())
+                               {
+                                       RTLIL::Cell *cell = *expand_queue_up.begin();
+                                       clkdomain_t key = assigned_cells_reverse.at(cell);
+                                       expand_queue_up.erase(cell);
+
+                                       for (auto bit : cell_to_bit_up[cell])
+                                       for (auto c : bit_to_cell_up[bit])
+                                               if (unassigned_cells.count(c)) {
+                                                       unassigned_cells.erase(c);
+                                                       next_expand_queue_up.insert(c);
+                                                       assigned_cells[key].push_back(c);
+                                                       assigned_cells_reverse[c] = key;
+                                                       expand_queue.insert(c);
+                                               }
+                               }
+
+                               if (!expand_queue_down.empty())
+                               {
+                                       RTLIL::Cell *cell = *expand_queue_down.begin();
+                                       clkdomain_t key = assigned_cells_reverse.at(cell);
+                                       expand_queue_down.erase(cell);
+
+                                       for (auto bit : cell_to_bit_down[cell])
+                                       for (auto c : bit_to_cell_down[bit])
+                                               if (unassigned_cells.count(c)) {
+                                                       unassigned_cells.erase(c);
+                                                       next_expand_queue_up.insert(c);
+                                                       assigned_cells[key].push_back(c);
+                                                       assigned_cells_reverse[c] = key;
+                                                       expand_queue.insert(c);
+                                               }
+                               }
+
+                               if (expand_queue_up.empty() && expand_queue_down.empty()) {
+                                       expand_queue_up.swap(next_expand_queue_up);
+                                       expand_queue_down.swap(next_expand_queue_down);
+                               }
+                       }
+
+                       while (!expand_queue.empty())
+                       {
+                               RTLIL::Cell *cell = *expand_queue.begin();
+                               clkdomain_t key = assigned_cells_reverse.at(cell);
+                               expand_queue.erase(cell);
+
+                               for (auto bit : cell_to_bit.at(cell)) {
+                                       for (auto c : bit_to_cell[bit])
+                                               if (unassigned_cells.count(c)) {
+                                                       unassigned_cells.erase(c);
+                                                       next_expand_queue.insert(c);
+                                                       assigned_cells[key].push_back(c);
+                                                       assigned_cells_reverse[c] = key;
+                                               }
+                                       bit_to_cell[bit].clear();
+                               }
+
+                               if (expand_queue.empty())
+                                       expand_queue.swap(next_expand_queue);
+                       }
+
+                       clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
+                       for (auto cell : unassigned_cells) {
+                               assigned_cells[key].push_back(cell);
+                               assigned_cells_reverse[cell] = key;
+                       }
+
+                       log_header(design, "Summary of detected clock domains:\n");
+                       for (auto &it : assigned_cells)
+                               log("  %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second),
+                                               std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)),
+                                               std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first)));
+
+                       for (auto &it : assigned_cells) {
+                               clk_polarity = std::get<0>(it.first);
+                               clk_sig = assign_map(std::get<1>(it.first));
+                               en_polarity = std::get<2>(it.first);
+                               en_sig = assign_map(std::get<3>(it.first));
+                               abc9_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$",
+                                               keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode,
+                                               box_file, lut_file);
+                               assign_map.set(mod);
+                       }
+               }
+
+               Pass::call(design, "clean");
+
+               assign_map.clear();
+               signal_map.clear();
+               signal_init.clear();
+               pi_map.clear();
+               po_map.clear();
+
+               log_pop();
+       }
+} Abc9Pass;
+
+PRIVATE_NAMESPACE_END
index e41c0fe97b48688075a2f06c8015ff8962e20e28..ee2e86de9fca99d74623ef3d66a7652df3a6a30a 100644 (file)
@@ -75,13 +75,16 @@ struct SynthPass : public ScriptPass
                log("        from label is synonymous to 'begin', and empty to label is\n");
                log("        synonymous to the end of the command list.\n");
                log("\n");
+               log("    -abc9\n");
+               log("        use abc9 instead of abc\n");
+               log("\n");
                log("\n");
                log("The following commands are executed by this synthesis command:\n");
                help_script();
                log("\n");
        }
 
-       string top_module, fsm_opts, memory_opts;
+       string top_module, fsm_opts, memory_opts, abc;
        bool autotop, flatten, noalumacc, nofsm, noabc, noshare;
        int lut;
 
@@ -98,6 +101,7 @@ struct SynthPass : public ScriptPass
                nofsm = false;
                noabc = false;
                noshare = false;
+               abc = "abc";
        }
 
        void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -159,6 +163,10 @@ struct SynthPass : public ScriptPass
                                noshare = true;
                                continue;
                        }
+                       if (args[argidx] == "-abc9") {
+                               abc = "abc9";
+                               continue;
+                       }
                        break;
                }
                extra_args(args, argidx, design);
@@ -241,15 +249,15 @@ struct SynthPass : public ScriptPass
                #ifdef YOSYS_ENABLE_ABC
                                if (help_mode)
                                {
-                                       run("abc -fast", "       (unless -noabc, unless -lut)");
-                                       run("abc -fast -lut k", "(unless -noabc, if -lut)");
+                                       run(abc + " -fast", "       (unless -noabc, unless -lut)");
+                                       run(abc + " -fast -lut k", "(unless -noabc, if -lut)");
                                }
                                else
                                {
                                        if (lut)
-                                               run(stringf("abc -fast -lut %d", lut));
+                                               run(stringf("%s -fast -lut %d", abc.c_str(), lut));
                                        else
-                                               run("abc -fast");
+                                               run(abc + " -fast");
                                }
                                run("opt -fast", "       (unless -noabc)");
                #endif
index 723b59d6f661b8e7e16477031b68373a43e35524..d258d5a5d901c3753da7c3fb1618bf479bfc5fea 100644 (file)
@@ -28,6 +28,12 @@ $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v))
 $(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v))
 $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt))
 $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams_map.v))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_hx.box))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_hx.lut))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_lp.box))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_lp.lut))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_u.box))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_u.lut))
 
 $(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init1.vh))
 $(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init2.vh))
diff --git a/techlibs/ice40/abc_hx.box b/techlibs/ice40/abc_hx.box
new file mode 100644 (file)
index 0000000..a065564
--- /dev/null
@@ -0,0 +1,113 @@
+# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_hx8k.txt
+
+# NB: Inputs/Outputs must be ordered alphabetically
+
+# Inputs: C D
+# Outputs: Q
+SB_DFF 1 0 2 1
+- -
+
+# Inputs: C D E
+# Outputs: Q
+SB_DFFE 2 0 3 1
+- - -
+
+# Inputs: C D R
+# Outputs: Q
+SB_DFFSR 3 0 3 1
+- - -
+
+# Inputs: C D R
+# Outputs: Q
+SB_DFFR 4 0 3 1
+- - -
+
+# Inputs: C D S
+# Outputs: Q
+SB_DFFSS 5 0 3 1
+- - -
+
+# Inputs: C D S
+# Outputs: Q
+SB_DFFS 6 0 3 1
+- - -
+
+# Inputs: C D E R
+# Outputs: Q
+SB_DFFESR 7 0 4 1
+- - - -
+
+# Inputs: C D E R
+# Outputs: Q
+SB_DFFER 8 0 4 1
+- - - -
+
+# Inputs: C D E S
+# Outputs: Q
+SB_DFFESS 9 0 4 1
+- - - -
+
+# Inputs: C D E S
+# Outputs: Q
+SB_DFFES 10 0 4 1
+- - - -
+
+# Inputs: C D
+# Outputs: Q
+SB_DFFN 11 0 2 1
+- -
+
+# Inputs: C D E
+# Outputs: Q
+SB_DFFNE 12 0 3 1
+- - -
+
+# Inputs: C D R
+# Outputs: Q
+SB_DFFNSR 13 0 3 1
+- - -
+
+# Inputs: C D R
+# Outputs: Q
+SB_DFFNR 14 0 3 1
+- - -
+
+# Inputs: C D S
+# Outputs: Q
+SB_DFFNSS 15 0 3 1
+- - -
+
+# Inputs: C D S
+# Outputs: Q
+SB_DFFNS 16 0 3 1
+- - -
+
+# Inputs: C D E R
+# Outputs: Q
+SB_DFFNESR 17 0 4 1
+- - - -
+
+# Inputs: C D E R
+# Outputs: Q
+SB_DFFNER 18 0 4 1
+- - - -
+
+# Inputs: C D E S
+# Outputs: Q
+SB_DFFNESS 19 0 4 1
+- - - -
+
+# Inputs: C D E S
+# Outputs: Q
+SB_DFFNES 20 0 4 1
+- - - -
+
+# Inputs: CI I0 I1
+# Outputs: CO
+SB_CARRY 21 1 3 1
+126 259 231
+
+# Inputs: I0 I1 I2 I3
+# Outputs: O
+SB_LUT4 22 1 4 1
+449 400 379 316
diff --git a/techlibs/ice40/abc_hx.lut b/techlibs/ice40/abc_hx.lut
new file mode 100644 (file)
index 0000000..3b3bb11
--- /dev/null
@@ -0,0 +1,6 @@
+# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_hx8k.txt
+#       I3  I2  I1  I0
+1   1   316
+2   1   316 379
+3   1   316 379 400
+4   1   316 379 400 449
diff --git a/techlibs/ice40/abc_lp.box b/techlibs/ice40/abc_lp.box
new file mode 100644 (file)
index 0000000..dbc98d0
--- /dev/null
@@ -0,0 +1,113 @@
+# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_lp8k.txt
+
+# NB: Inputs/Outputs must be ordered alphabetically
+
+# Inputs: C D
+# Outputs: Q
+SB_DFF 1 0 2 1
+- -
+
+# Inputs: C D E
+# Outputs: Q
+SB_DFFE 2 0 3 1
+- - -
+
+# Inputs: C D R
+# Outputs: Q
+SB_DFFSR 3 0 3 1
+- - -
+
+# Inputs: C D R
+# Outputs: Q
+SB_DFFR 4 0 3 1
+- - -
+
+# Inputs: C D S
+# Outputs: Q
+SB_DFFSS 5 0 3 1
+- - -
+
+# Inputs: C D S
+# Outputs: Q
+SB_DFFS 6 0 3 1
+- - -
+
+# Inputs: C D E R
+# Outputs: Q
+SB_DFFESR 7 0 4 1
+- - - -
+
+# Inputs: C D E R
+# Outputs: Q
+SB_DFFER 8 0 4 1
+- - - -
+
+# Inputs: C D E S
+# Outputs: Q
+SB_DFFESS 9 0 4 1
+- - - -
+
+# Inputs: C D E S
+# Outputs: Q
+SB_DFFES 10 0 4 1
+- - - -
+
+# Inputs: C D
+# Outputs: Q
+SB_DFFN 11 0 2 1
+- -
+
+# Inputs: C D E
+# Outputs: Q
+SB_DFFNE 12 0 3 1
+- - -
+
+# Inputs: C D R
+# Outputs: Q
+SB_DFFNSR 13 0 3 1
+- - -
+
+# Inputs: C D R
+# Outputs: Q
+SB_DFFNR 14 0 3 1
+- - -
+
+# Inputs: C D S
+# Outputs: Q
+SB_DFFNSS 15 0 3 1
+- - -
+
+# Inputs: C D S
+# Outputs: Q
+SB_DFFNS 16 0 3 1
+- - -
+
+# Inputs: C D E R
+# Outputs: Q
+SB_DFFNESR 17 0 4 1
+- - - -
+
+# Inputs: C D E R
+# Outputs: Q
+SB_DFFNER 18 0 4 1
+- - - -
+
+# Inputs: C D E S
+# Outputs: Q
+SB_DFFNESS 19 0 4 1
+- - - -
+
+# Inputs: C D E S
+# Outputs: Q
+SB_DFFNES 20 0 4 1
+- - - -
+
+# Inputs: CI I0 I1
+# Outputs: CO
+SB_CARRY 21 1 3 1
+186 675 609
+
+# Inputs: I0 I1 I2 I3
+# Outputs: O
+SB_LUT4 22 1 4 1
+465 558 589 661
diff --git a/techlibs/ice40/abc_lp.lut b/techlibs/ice40/abc_lp.lut
new file mode 100644 (file)
index 0000000..e72f760
--- /dev/null
@@ -0,0 +1,6 @@
+# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_lp8k.txt
+#       I3  I2  I1  I0
+1   1   465
+2   1   465 558
+3   1   465 558 589
+4   1   465 558 589 661
diff --git a/techlibs/ice40/abc_u.box b/techlibs/ice40/abc_u.box
new file mode 100644 (file)
index 0000000..3b5834e
--- /dev/null
@@ -0,0 +1,113 @@
+# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_up5k.txt
+
+# NB: Inputs/Outputs must be ordered alphabetically
+
+# Inputs: C D
+# Outputs: Q
+SB_DFF 1 0 2 1
+- -
+
+# Inputs: C D E
+# Outputs: Q
+SB_DFFE 2 0 3 1
+- - -
+
+# Inputs: C D R
+# Outputs: Q
+SB_DFFSR 3 0 3 1
+- - -
+
+# Inputs: C D R
+# Outputs: Q
+SB_DFFR 4 0 3 1
+- - -
+
+# Inputs: C D S
+# Outputs: Q
+SB_DFFSS 5 0 3 1
+- - -
+
+# Inputs: C D S
+# Outputs: Q
+SB_DFFS 6 0 3 1
+- - -
+
+# Inputs: C D E R
+# Outputs: Q
+SB_DFFESR 7 0 4 1
+- - - -
+
+# Inputs: C D E R
+# Outputs: Q
+SB_DFFER 8 0 4 1
+- - - -
+
+# Inputs: C D E S
+# Outputs: Q
+SB_DFFESS 9 0 4 1
+- - - -
+
+# Inputs: C D E S
+# Outputs: Q
+SB_DFFES 10 0 4 1
+- - - -
+
+# Inputs: C D
+# Outputs: Q
+SB_DFFN 11 0 2 1
+- -
+
+# Inputs: C D E
+# Outputs: Q
+SB_DFFNE 12 0 3 1
+- - -
+
+# Inputs: C D R
+# Outputs: Q
+SB_DFFNSR 13 0 3 1
+- - -
+
+# Inputs: C D R
+# Outputs: Q
+SB_DFFNR 14 0 3 1
+- - -
+
+# Inputs: C D S
+# Outputs: Q
+SB_DFFNSS 15 0 3 1
+- - -
+
+# Inputs: C D S
+# Outputs: Q
+SB_DFFNS 16 0 3 1
+- - -
+
+# Inputs: C D E R
+# Outputs: Q
+SB_DFFNESR 17 0 4 1
+- - - -
+
+# Inputs: C D E R
+# Outputs: Q
+SB_DFFNER 18 0 4 1
+- - - -
+
+# Inputs: C D E S
+# Outputs: Q
+SB_DFFNESS 19 0 4 1
+- - - -
+
+# Inputs: C D E S
+# Outputs: Q
+SB_DFFNES 20 0 4 1
+- - - -
+
+# Inputs: CI I0 I1
+# Outputs: CO
+SB_CARRY 21 1 3 1
+278 675 609
+
+# Inputs: I0 I1 I2 I3
+# Outputs: O
+SB_LUT4 22 1 4 1
+1285 1231 1205 874
diff --git a/techlibs/ice40/abc_u.lut b/techlibs/ice40/abc_u.lut
new file mode 100644 (file)
index 0000000..1e4fcad
--- /dev/null
@@ -0,0 +1,6 @@
+# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_up5k.txt
+#       I3  I2  I1  I0
+1   1   874
+2   1   874 1205
+3   1   874 1205 1231
+4   1   874 1205 1231 1285
index d0ddfd02e0b1c223312f1ee015ea62430f8cb71a..759549e30cc183bb662c805fa86863f3e6fce1c3 100644 (file)
@@ -37,20 +37,24 @@ module \$lut (A, Y);
 
   generate
     if (WIDTH == 1) begin
-      SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
-        .I0(A[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0));
+      localparam [15:0] INIT = {{8{LUT[1]}}, {8{LUT[0]}}};
+      SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
+        .I0(1'b0), .I1(1'b0), .I2(1'b0), .I3(A[0]));
     end else
     if (WIDTH == 2) begin
-      SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
-        .I0(A[0]), .I1(A[1]), .I2(1'b0), .I3(1'b0));
+      localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[1]}}, {4{LUT[2]}}, {4{LUT[0]}}};
+      SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
+        .I0(1'b0), .I1(1'b0), .I2(A[1]), .I3(A[0]));
     end else
     if (WIDTH == 3) begin
-      SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
-        .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(1'b0));
+      localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[3]}}, {2{LUT[5]}}, {2{LUT[1]}}, {2{LUT[6]}}, {2{LUT[2]}}, {2{LUT[4]}}, {2{LUT[0]}}};
+      SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
+        .I0(1'b0), .I1(A[2]), .I2(A[1]), .I3(A[0]));
     end else
     if (WIDTH == 4) begin
-      SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
-        .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3]));
+      localparam [15:0] INIT = {LUT[15], LUT[7], LUT[11], LUT[3], LUT[13], LUT[5], LUT[9], LUT[1], LUT[14], LUT[6], LUT[10], LUT[2], LUT[12], LUT[4], LUT[8], LUT[0]};
+      SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y),
+        .I0(A[3]), .I1(A[2]), .I2(A[1]), .I3(A[0]));
     end else begin
       wire _TECHMAP_FAIL_ = 1;
     end
index f9945b2b52dd33b1082ee99ea7b9f0c036c9b23b..523dd8cbeab4f7fee703a24609629a7f81854821 100644 (file)
@@ -127,6 +127,7 @@ endmodule
 
 // SiliconBlue Logic Cells
 
+(* abc_box_id = 22, lib_whitebox *)
 module SB_LUT4 (output O, input I0, I1, I2, I3);
        parameter [15:0] LUT_INIT = 0;
        wire [7:0] s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0];
@@ -135,24 +136,32 @@ module SB_LUT4 (output O, input I0, I1, I2, I3);
        assign O = I0 ? s1[1] : s1[0];
 endmodule
 
-module SB_CARRY (output CO, input I0, I1, CI);
+(* abc_box_id = 21, abc_carry, lib_whitebox *)
+module SB_CARRY ((* abc_carry_out *) output CO, input I0, I1, (* abc_carry_in *) input CI);
        assign CO = (I0 && I1) || ((I0 || I1) && CI);
 endmodule
 
 // Positive Edge SiliconBlue FF Cells
 
-module SB_DFF (output `SB_DFF_REG, input C, D);
+(* abc_box_id = 1, abc_flop, lib_whitebox *)
+module SB_DFF ((* abc_flop_q *) output `SB_DFF_REG, input C, (* abc_flop_d *) input D);
+`ifndef _ABC
        always @(posedge C)
                Q <= D;
+`else
+    always @* Q <= D;
+`endif
 endmodule
 
-module SB_DFFE (output `SB_DFF_REG, input C, E, D);
+//(* abc_box_id = 2, abc_flop *)
+module SB_DFFE ((* abc_flop_q *) output `SB_DFF_REG, input C, E, (* abc_flop_d *) input D);
        always @(posedge C)
                if (E)
                        Q <= D;
 endmodule
 
-module SB_DFFSR (output `SB_DFF_REG, input C, R, D);
+//(* abc_box_id = 3, abc_flop *)
+module SB_DFFSR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d *) input D);
        always @(posedge C)
                if (R)
                        Q <= 0;
@@ -160,7 +169,8 @@ module SB_DFFSR (output `SB_DFF_REG, input C, R, D);
                        Q <= D;
 endmodule
 
-module SB_DFFR (output `SB_DFF_REG, input C, R, D);
+//(* abc_box_id = 4, abc_flop *)
+module SB_DFFR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d *) input D);
        always @(posedge C, posedge R)
                if (R)
                        Q <= 0;
@@ -168,7 +178,8 @@ module SB_DFFR (output `SB_DFF_REG, input C, R, D);
                        Q <= D;
 endmodule
 
-module SB_DFFSS (output `SB_DFF_REG, input C, S, D);
+//(* abc_box_id = 5, abc_flop *)
+module SB_DFFSS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d *) input D);
        always @(posedge C)
                if (S)
                        Q <= 1;
@@ -176,7 +187,8 @@ module SB_DFFSS (output `SB_DFF_REG, input C, S, D);
                        Q <= D;
 endmodule
 
-module SB_DFFS (output `SB_DFF_REG, input C, S, D);
+//(* abc_box_id = 6, abc_flop *)
+module SB_DFFS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d *) input D);
        always @(posedge C, posedge S)
                if (S)
                        Q <= 1;
@@ -184,7 +196,8 @@ module SB_DFFS (output `SB_DFF_REG, input C, S, D);
                        Q <= D;
 endmodule
 
-module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D);
+//(* abc_box_id = 7, abc_flop *)
+module SB_DFFESR ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flop_d *) input D);
        always @(posedge C)
                if (E) begin
                        if (R)
@@ -194,7 +207,8 @@ module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D);
                end
 endmodule
 
-module SB_DFFER (output `SB_DFF_REG, input C, E, R, D);
+//(* abc_box_id = 8, abc_flop *)
+module SB_DFFER ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flop_d *) input D);
        always @(posedge C, posedge R)
                if (R)
                        Q <= 0;
@@ -202,7 +216,8 @@ module SB_DFFER (output `SB_DFF_REG, input C, E, R, D);
                        Q <= D;
 endmodule
 
-module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D);
+//(* abc_box_id = 9, abc_flop *)
+module SB_DFFESS ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_flop_d *) input D);
        always @(posedge C)
                if (E) begin
                        if (S)
@@ -212,7 +227,8 @@ module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D);
                end
 endmodule
 
-module SB_DFFES (output `SB_DFF_REG, input C, E, S, D);
+//(* abc_box_id = 10, abc_flop *)
+module SB_DFFES ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_flop_d *) input D);
        always @(posedge C, posedge S)
                if (S)
                        Q <= 1;
@@ -222,18 +238,21 @@ endmodule
 
 // Negative Edge SiliconBlue FF Cells
 
-module SB_DFFN (output `SB_DFF_REG, input C, D);
+//(* abc_box_id = 11, abc_flop *)
+module SB_DFFN ((* abc_flop_q *) output `SB_DFF_REG, input C, (* abc_flop_d *) input D);
        always @(negedge C)
                Q <= D;
 endmodule
 
-module SB_DFFNE (output `SB_DFF_REG, input C, E, D);
+//(* abc_box_id = 12, abc_flop *)
+module SB_DFFNE ((* abc_flop_q *) output `SB_DFF_REG, input C, E, (* abc_flop_d *) input D);
        always @(negedge C)
                if (E)
                        Q <= D;
 endmodule
 
-module SB_DFFNSR (output `SB_DFF_REG, input C, R, D);
+//(* abc_box_id = 13, abc_flop *)
+module SB_DFFNSR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d *) input D);
        always @(negedge C)
                if (R)
                        Q <= 0;
@@ -241,7 +260,8 @@ module SB_DFFNSR (output `SB_DFF_REG, input C, R, D);
                        Q <= D;
 endmodule
 
-module SB_DFFNR (output `SB_DFF_REG, input C, R, D);
+//(* abc_box_id = 14, abc_flop *)
+module SB_DFFNR ((* abc_flop_q *) output `SB_DFF_REG, input C, R, (* abc_flop_d *) input D);
        always @(negedge C, posedge R)
                if (R)
                        Q <= 0;
@@ -249,7 +269,8 @@ module SB_DFFNR (output `SB_DFF_REG, input C, R, D);
                        Q <= D;
 endmodule
 
-module SB_DFFNSS (output `SB_DFF_REG, input C, S, D);
+//(* abc_box_id = 15, abc_flop *)
+module SB_DFFNSS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d *) input D);
        always @(negedge C)
                if (S)
                        Q <= 1;
@@ -257,7 +278,8 @@ module SB_DFFNSS (output `SB_DFF_REG, input C, S, D);
                        Q <= D;
 endmodule
 
-module SB_DFFNS (output `SB_DFF_REG, input C, S, D);
+//(* abc_box_id = 16, abc_flop *)
+module SB_DFFNS ((* abc_flop_q *) output `SB_DFF_REG, input C, S, (* abc_flop_d *) input D);
        always @(negedge C, posedge S)
                if (S)
                        Q <= 1;
@@ -265,7 +287,8 @@ module SB_DFFNS (output `SB_DFF_REG, input C, S, D);
                        Q <= D;
 endmodule
 
-module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D);
+//(* abc_box_id = 17, abc_flop *)
+module SB_DFFNESR ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flop_d *) input D);
        always @(negedge C)
                if (E) begin
                        if (R)
@@ -275,7 +298,8 @@ module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D);
                end
 endmodule
 
-module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D);
+//(* abc_box_id = 18, abc_flop *)
+module SB_DFFNER ((* abc_flop_q *) output `SB_DFF_REG, input C, E, R, (* abc_flop_d *) input D);
        always @(negedge C, posedge R)
                if (R)
                        Q <= 0;
@@ -283,7 +307,8 @@ module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D);
                        Q <= D;
 endmodule
 
-module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D);
+//(* abc_box_id = 19, abc_flop *)
+module SB_DFFNESS ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_flop_d *) input D);
        always @(negedge C)
                if (E) begin
                        if (S)
@@ -293,7 +318,8 @@ module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D);
                end
 endmodule
 
-module SB_DFFNES (output `SB_DFF_REG, input C, E, S, D);
+//(* abc_box_id = 20, abc_flop *)
+module SB_DFFNES ((* abc_flop_q *) output `SB_DFF_REG, input C, E, S, (* abc_flop_d *) input D);
        always @(negedge C, posedge S)
                if (S)
                        Q <= 1;
@@ -304,7 +330,7 @@ endmodule
 // SiliconBlue RAM Cells
 
 module SB_RAM40_4K (
-       output [15:0] RDATA,
+       (* abc_flop_q *) output [15:0] RDATA,
        input         RCLK, RCLKE, RE,
        input  [10:0] RADDR,
        input         WCLK, WCLKE, WE,
@@ -472,7 +498,7 @@ module SB_RAM40_4K (
 endmodule
 
 module SB_RAM40_4KNR (
-       output [15:0] RDATA,
+       (* abc_flop_q *) output [15:0] RDATA,
        input         RCLKN, RCLKE, RE,
        input  [10:0] RADDR,
        input         WCLK, WCLKE, WE,
@@ -537,7 +563,7 @@ module SB_RAM40_4KNR (
 endmodule
 
 module SB_RAM40_4KNW (
-       output [15:0] RDATA,
+       (* abc_flop_q *) output [15:0] RDATA,
        input         RCLK, RCLKE, RE,
        input  [10:0] RADDR,
        input         WCLKN, WCLKE, WE,
@@ -602,7 +628,7 @@ module SB_RAM40_4KNW (
 endmodule
 
 module SB_RAM40_4KNRNW (
-       output [15:0] RDATA,
+       (* abc_flop_q *) output [15:0] RDATA,
        input         RCLKN, RCLKE, RE,
        input  [10:0] RADDR,
        input         WCLKN, WCLKE, WE,
@@ -890,12 +916,13 @@ module SB_WARMBOOT (
 );
 endmodule
 
+(* nomem2reg *)
 module SB_SPRAM256KA (
        input [13:0] ADDRESS,
        input [15:0] DATAIN,
        input [3:0] MASKWREN,
        input WREN, CHIPSELECT, CLOCK, STANDBY, SLEEP, POWEROFF,
-       output reg [15:0] DATAOUT
+       (* abc_flop_q *) output reg [15:0] DATAOUT
 );
 `ifndef BLACKBOX
 `ifndef EQUIV
index bb96d66d1b2a6407f0721fa72784d7ad1f993f54..5afa042b01d322720ae1c67fc75c98e83a988f18 100644 (file)
@@ -37,6 +37,10 @@ struct SynthIce40Pass : public ScriptPass
                log("\n");
                log("This command runs synthesis for iCE40 FPGAs.\n");
                log("\n");
+               log("    -device < hx | lp | u >\n");
+               log("        optimise the synthesis netlist for the specified device.\n");
+               log("        HX is the default target if no device argument specified.\n");
+               log("\n");
                log("    -top <module>\n");
                log("        use the specified module as top module\n");
                log("\n");
@@ -92,13 +96,17 @@ struct SynthIce40Pass : public ScriptPass
                log("        generate an output netlist (and BLIF file) suitable for VPR\n");
                log("        (this feature is experimental and incomplete)\n");
                log("\n");
+               log("    -abc9\n");
+               log("        use abc9 instead of abc\n");
+               log("\n");
                log("\n");
                log("The following commands are executed by this synthesis command:\n");
                help_script();
                log("\n");
        }
 
-       string top_opt, blif_file, edif_file, json_file;
+
+       string top_opt, blif_file, edif_file, json_file, abc, device_opt;
        bool nocarry, nodffe, nobram, dsp, flatten, retime, relut, noabc, abc2, vpr;
        int min_ce_use;
 
@@ -119,6 +127,8 @@ struct SynthIce40Pass : public ScriptPass
                noabc = false;
                abc2 = false;
                vpr = false;
+               abc = "abc";
+               device_opt = "hx";
        }
 
        void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -201,12 +211,22 @@ struct SynthIce40Pass : public ScriptPass
                                vpr = true;
                                continue;
                        }
+                       if (args[argidx] == "-abc9") {
+                               abc = "abc9";
+                               continue;
+                       }
+                       if (args[argidx] == "-device" && argidx+1 < args.size()) {
+                               device_opt = args[++argidx];
+                               continue;
+                       }
                        break;
                }
                extra_args(args, argidx, design);
 
                if (!design->full_selection())
                        log_cmd_error("This command only operates on fully selected designs!\n");
+               if (device_opt != "hx" && device_opt != "lp" && device_opt !="u")
+                       log_cmd_error("Invalid or no device specified: '%s'\n", device_opt.c_str());
 
                log_header(design, "Executing SYNTH_ICE40 pass.\n");
                log_push();
@@ -220,7 +240,7 @@ struct SynthIce40Pass : public ScriptPass
        {
                if (check_label("begin"))
                {
-                       run("read_verilog -lib +/ice40/cells_sim.v");
+                       run("read_verilog -lib -D_ABC +/ice40/cells_sim.v");
                        run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
                        run("proc");
                }
@@ -277,8 +297,8 @@ struct SynthIce40Pass : public ScriptPass
                                run("techmap");
                        else
                                run("techmap -map +/techmap.v -map +/ice40/arith_map.v");
-                       if (retime || help_mode)
-                               run("abc -dff", "(only if -retime)");
+                       if ((retime || help_mode) && abc != "abc9")
+                               run(abc + " -dff", "(only if -retime)");
                        run("ice40_opt");
                }
 
@@ -302,7 +322,7 @@ struct SynthIce40Pass : public ScriptPass
                if (check_label("map_luts"))
                {
                        if (abc2 || help_mode) {
-                               run("abc", "      (only if -abc2)");
+                               run(abc, "      (only if -abc2)");
                                run("ice40_opt", "(only if -abc2)");
                        }
                        run("techmap -map +/ice40/latches_map.v");
@@ -311,7 +331,10 @@ struct SynthIce40Pass : public ScriptPass
                                run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)");
                        }
                        if (!noabc) {
-                               run("abc -dress -lut 4", "(skip if -noabc)");
+                               if (abc == "abc9")
+                                       run(abc + stringf(" -dress -lut +/ice40/abc_%s.lut -box +/ice40/abc_%s.box", device_opt.c_str(), device_opt.c_str()), "(skip if -noabc)");
+                               else
+                                       run(abc + " -dress -lut 4", "(skip if -noabc)");
                        }
                        run("clean");
                        if (relut || help_mode) {
index d68f03bb44f3635209e3224be27e87562b2fd8aa..2f39451677eb2d80cbb9843b63e117b978b473f0 100644 (file)
@@ -30,6 +30,9 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v))
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc.box))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc.lut))
 
 $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
 $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))
diff --git a/techlibs/xilinx/abc.box b/techlibs/xilinx/abc.box
new file mode 100644 (file)
index 0000000..a4182ed
--- /dev/null
@@ -0,0 +1,62 @@
+# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf
+
+# F7BMUX slower than F7AMUX
+# Inputs: I0 I1 S0
+# Outputs: O
+F7BMUX 1 1 3 1
+217 223 296
+
+# Inputs: I0 I1 S0
+# Outputs: O
+MUXF8 2 1 3 1
+104 94 273
+
+# CARRY4 + CARRY4_[ABCD]X
+# Inputs: S0 S1 S2 S3 CYINIT DI0 DI1 DI2 DI3 CI
+# Outputs:  O0 O1 O2 O3 CO0 CO1 CO2 CO3
+#   (NB: carry chain input/output must be last input/output,
+#        swapped with what normally would have been the last
+#        output, here: CI <-> S, CO <-> O
+CARRY4 3 1 10 8
+223 -   -   -   482 -   -   -   -   222
+400 205 -   -   598 407 -   -   -   334
+523 558 226 -   584 556 537 -   -   239
+582 618 330 227 642 615 596 438 -   313
+340 -   -   -   536 379 -   -   -   271
+433 469 -   -   494 465 445 -   -   157
+512 548 292 -   592 540 520 356 -   228
+508 528 378 380 580 526 507 398 385 114
+
+# SLICEM/A6LUT
+# Inputs: A0 A1 A2 A3 A4 A5 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 WCLK WE
+# Outputs: DPO SPO
+RAM64X1D 4 0 15 2
+-   -   -   -   -   -   - 124 124 124 124 124 124 - -
+124 124 124 124 124 124 - -   -   -   -   -   124 - -
+
+# SLICEM/A6LUT + F7[AB]MUX
+# Inputs: A0 A1 A2 A3 A4 A5 A6 D DPRA0 DPRA1 DPRA2 DPRA3 DPRA4 DPRA5 DPRA6 WCLK WE
+# Outputs: DPO SPO
+RAM128X1D 5 0 17 2
+-   -   -   -   -   -   -   - 314 314 314 314 314 314 292 - -
+347 347 347 347 347 347 296 - -   -   -   -   -   -   -   - -
+
+# Inputs: C CE D R
+# Outputs: Q
+FDRE 6 0 4 1
+- - - -
+
+# Inputs: C CE D S
+# Outputs: Q
+FDSE 7 0 4 1
+- - - -
+
+# Inputs: C CE CLR D
+# Outputs: Q
+FDCE 8 0 4 1
+- - 404 -
+
+# Inputs: C CE D PRE
+# Outputs: Q
+FDPE 9 0 4 1
+- - - 404
diff --git a/techlibs/xilinx/abc.lut b/techlibs/xilinx/abc.lut
new file mode 100644 (file)
index 0000000..3a7dc26
--- /dev/null
@@ -0,0 +1,14 @@
+# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf
+
+# K    area    delay
+1      1       124
+2      2       124 235
+3      3       124 235 399
+4      3       124 235 399 490
+5      3       124 235 399 490 620
+6      5       124 235 399 490 620 632
+                # F7BMUX
+7      10      296 420 531 695 756 916 928
+                # F8MUX
+                    # F8MUX+F7BMUX
+8      20      273 569 693 804 968 1029 1189 1201
index 09a5f07e83d76b2d1b6bdfa3b450ddea750bc833..5c848d4e69913167cbad26b00baf7585ccca8bff 100644 (file)
@@ -180,7 +180,7 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
 
                        // First one
                        if (i == 0) begin
-                               CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_part
+                               CARRY4 carry4_1st_part
                                (
                                .CYINIT(CI),
                                .CI    (1'd0),
@@ -207,7 +207,7 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
 
                        // First one
                        if (i == 0) begin
-                               CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_full
+                               CARRY4 carry4_1st_full
                                (
                                .CYINIT(CI),
                                .CI    (1'd0),
index a682ba4a72926b7ae506673edcdd5874fa4a4bb6..f540d299d5e861e0eb47079d0587d2b70849b677 100644 (file)
@@ -19,10 +19,10 @@ module RAMB18E1 (
        input [1:0] WEA,
        input [3:0] WEBWE,
 
-       output [15:0] DOADO,
-       output [15:0] DOBDO,
-       output [1:0] DOPADOP,
-       output [1:0] DOPBDOP
+       (* abc_flop_q *) output [15:0] DOADO,
+       (* abc_flop_q *) output [15:0] DOBDO,
+       (* abc_flop_q *) output [1:0] DOPADOP,
+       (* abc_flop_q *) output [1:0] DOPBDOP
 );
        parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
        parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
@@ -143,10 +143,10 @@ module RAMB36E1 (
        input [3:0] WEA,
        input [7:0] WEBWE,
 
-       output [31:0] DOADO,
-       output [31:0] DOBDO,
-       output [3:0] DOPADOP,
-       output [3:0] DOPBDOP
+       (* abc_flop_q *) output [31:0] DOADO,
+       (* abc_flop_q *) output [31:0] DOBDO,
+       (* abc_flop_q *) output [3:0] DOPADOP,
+       (* abc_flop_q *) output [3:0] DOPBDOP
 );
        parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
        parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
index 40789ddbe1548c9e5041f55f24c0021cacd2ed92..f8f9356bc6c2db816dc68b56fe5a8954a0db30f8 100644 (file)
@@ -2,6 +2,7 @@
  *  yosys -- Yosys Open SYnthesis Suite
  *
  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *                2019  Eddie Hung    <eddie@fpgeh.com>
  *
  *  Permission to use, copy, modify, and/or distribute this software for any
  *  purpose with or without fee is hereby granted, provided that the above
  *
  */
 
-// Convert negative-polarity reset to positive-polarity
-(* techmap_celltype = "$_DFF_NN0_" *)
-module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
-(* techmap_celltype = "$_DFF_PN0_" *)
-module _90_dff_pn0_to_pp0 (input D, C, R, output Q); \$_DFF_PP0_  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
-(* techmap_celltype = "$_DFF_NN1_" *)
-module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1   _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
-(* techmap_celltype = "$_DFF_PN1_" *)
-module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1   _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
-
 module \$__SHREG_ (input C, input D, input E, output Q);
   parameter DEPTH = 0;
   parameter [DEPTH-1:0] INIT = 0;
@@ -88,7 +79,7 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o
     end else
     if (DEPTH > 65 && DEPTH <= 96) begin
       wire T0, T1, T2, T3, T4, T5, T6;
-      SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
+      SRLC32E #(.INIT(INIT_R[32-1: 0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D( D), .Q(T0), .Q31(T1));
       SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
       \$__XILINX_SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .L(L[4:0]), .E(E), .Q(T4));
       if (&_TECHMAP_CONSTMSK_L_)
@@ -101,7 +92,7 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o
     end else
     if (DEPTH > 97 && DEPTH < 128) begin
       wire T0, T1, T2, T3, T4, T5, T6, T7, T8;
-      SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
+      SRLC32E #(.INIT(INIT_R[32-1: 0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D( D), .Q(T0), .Q31(T1));
       SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
       SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
       \$__XILINX_SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .L(L[4:0]), .E(E), .Q(T6));
@@ -115,9 +106,9 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o
     end
     else if (DEPTH == 128) begin
       wire T0, T1, T2, T3, T4, T5, T6;
-      SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
-      SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
-      SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
+      SRLC32E #(.INIT(INIT_R[ 32-1: 0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D( D), .Q(T0), .Q31(T1));
+      SRLC32E #(.INIT(INIT_R[ 64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
+      SRLC32E #(.INIT(INIT_R[ 96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
       SRLC32E #(.INIT(INIT_R[128-1:96]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_3 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T5), .Q(T6), .Q31(SO));
       if (&_TECHMAP_CONSTMSK_L_)
         assign Q = T6;
@@ -152,5 +143,122 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o
   endgenerate
 endmodule
 
-`ifndef SRL_ONLY
-`endif
+module \$__XILINX_SHIFTX (A, B, Y);
+  parameter A_SIGNED = 0;
+  parameter B_SIGNED = 0;
+  parameter A_WIDTH = 1;
+  parameter B_WIDTH = 1;
+  parameter Y_WIDTH = 1;
+
+  input [A_WIDTH-1:0] A;
+  input [B_WIDTH-1:0] B;
+  output [Y_WIDTH-1:0] Y;
+
+  parameter [A_WIDTH-1:0] _TECHMAP_CONSTMSK_A_ = 0;
+  parameter [A_WIDTH-1:0] _TECHMAP_CONSTVAL_A_ = 0;
+  parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0;
+  parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0;
+
+  function integer compute_num_leading_X_in_A;
+    integer i, c;
+  begin
+    compute_num_leading_X_in_A = 0;
+    c = 1;
+    for (i = A_WIDTH-1; i >= 0; i=i-1) begin
+      if (!_TECHMAP_CONSTMSK_A_[i] || _TECHMAP_CONSTVAL_A_[i] !== 1'bx)
+        c = 0;
+      compute_num_leading_X_in_A = compute_num_leading_X_in_A + c;
+    end
+  end
+  endfunction
+  localparam num_leading_X_in_A = compute_num_leading_X_in_A();
+
+  generate
+    genvar i, j;
+    // Bit-blast
+    if (Y_WIDTH > 1) begin
+      for (i = 0; i < Y_WIDTH; i++)
+        \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH-Y_WIDTH+1), .B_WIDTH(B_WIDTH), .Y_WIDTH(1'd1)) bitblast (.A(A[A_WIDTH-Y_WIDTH+i:i]), .B(B), .Y(Y[i]));
+    end
+    // If the LSB of B is constant zero (and Y_WIDTH is 1) then
+    //   we can optimise by removing every other entry from A
+    //   and popping the constant zero from B
+    else if (_TECHMAP_CONSTMSK_B_[0] && !_TECHMAP_CONSTVAL_B_[0]) begin
+      wire [(A_WIDTH+1)/2-1:0] A_i;
+      for (i = 0; i < (A_WIDTH+1)/2; i++)
+        assign A_i[i] = A[i*2];
+      \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH((A_WIDTH+1'd1)/2'd2), .B_WIDTH(B_WIDTH-1'd1), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A_i), .B(B[B_WIDTH-1:1]), .Y(Y));
+    end
+    // Trim off any leading 1'bx -es in A, and resize B accordingly
+    else if (num_leading_X_in_A > 0) begin
+      localparam A_WIDTH_new = A_WIDTH - num_leading_X_in_A;
+      localparam B_WIDTH_new = $clog2(A_WIDTH_new);
+      \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH_new), .B_WIDTH(B_WIDTH_new), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A[A_WIDTH_new-1:0]), .B(B[B_WIDTH_new-1:0]), .Y(Y));
+    end
+    else if (B_WIDTH < 3 || A_WIDTH <= 4) begin
+      \$shiftx  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y));
+    end
+    else if (B_WIDTH == 3) begin
+      localparam a_width0 = 2 ** 2;
+      localparam a_widthN = A_WIDTH - a_width0;
+      wire T0, T1;
+      \$shiftx  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(2),                .Y_WIDTH(Y_WIDTH)) fpga_soft_mux      (.A(A[a_width0-1:0]),       .B(B[2-1:0]),                .Y(T0));
+      if (a_widthN > 1)
+        \$shiftx  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1:a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T1));
+      else
+        assign T1 = A[A_WIDTH-1];
+      MUXF7 fpga_hard_mux (.I0(T0), .I1(T1), .S(B[B_WIDTH-1]), .O(Y));
+    end
+    else if (B_WIDTH == 4) begin
+      localparam a_width0 = 2 ** 2;
+      localparam num_mux8 = A_WIDTH / a_width0;
+      localparam a_widthN = A_WIDTH - num_mux8*a_width0;
+      wire [4-1:0] T;
+      wire T0, T1;
+      for (i = 0; i < 4; i++)
+        if (i < num_mux8)
+          \$shiftx  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(2),                .Y_WIDTH(Y_WIDTH)) fpga_soft_mux      (.A(A[i*a_width0+:a_width0]), .B(B[2-1:0]),                .Y(T[i]));
+        else if (i == num_mux8 && a_widthN > 0) begin
+          if (a_widthN > 1)
+            \$shiftx  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1:i*a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[i]));
+          else
+            assign T[i] = A[A_WIDTH-1];
+        end
+        else
+          assign T[i] = 1'bx;
+      MUXF7 fpga_hard_mux_0 (.I0(T[0]), .I1(T[1]), .S(B[2]), .O(T0));
+      MUXF7 fpga_hard_mux_1 (.I0(T[2]), .I1(T[3]), .S(B[2]), .O(T1));
+      MUXF8 fpga_hard_mux_2 (.I0(T0),   .I1(T1),   .S(B[3]), .O(Y));
+    end
+    else begin
+      localparam a_width0 = 2 ** 4;
+      localparam num_mux16 = A_WIDTH / a_width0;
+      localparam a_widthN = A_WIDTH - num_mux16*a_width0;
+      wire [(2**(B_WIDTH-4))-1:0] T;
+      for (i = 0; i < 2 ** (B_WIDTH-4); i++)
+        if (i < num_mux16)
+          \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(4),                .Y_WIDTH(Y_WIDTH)) fpga_soft_mux      (.A(A[i*a_width0+:a_width0]), .B(B[4-1:0]),                .Y(T[i]));
+        else if (i == num_mux16 && a_widthN > 0) begin
+          if (a_widthN > 1)
+            \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1:i*a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[i]));
+          else
+            assign T[i] = A[A_WIDTH-1];
+        end
+        else
+          assign T[i] = 1'bx;
+      \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(2**(B_WIDTH-4)), .B_WIDTH(B_WIDTH-4), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(T), .B(B[B_WIDTH-1:4]), .Y(Y));
+    end
+  endgenerate
+endmodule
+
+module \$_MUX8_ (A, B, C, D, E, F, G, H, S, T, U, Y);
+input A, B, C, D, E, F, G, H, S, T, U;
+output Y;
+  \$__XILINX_SHIFTX  #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(8), .B_WIDTH(3), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({H,G,F,E,D,C,B,A}), .B({U,T,S}), .Y(Y));
+endmodule
+
+module \$_MUX16_ (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V, Y);
+input A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V;
+output Y;
+  \$__XILINX_SHIFTX  #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(16), .B_WIDTH(4), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A}), .B({V,U,T,S}), .Y(Y));
+endmodule
index 3a4540b83689be6a2c7d33692f62924cd7846711..88967b0685834551dc0888168fcfb22e5ecd12ec 100644 (file)
@@ -159,10 +159,12 @@ module MUXCY(output O, input CI, DI, S);
   assign O = S ? CI : DI;
 endmodule
 
+(* abc_box_id = 1, lib_whitebox *)
 module MUXF7(output O, input I0, I1, S);
   assign O = S ? I1 : I0;
 endmodule
 
+(* abc_box_id = 2, lib_whitebox *)
 module MUXF8(output O, input I0, I1, S);
   assign O = S ? I1 : I0;
 endmodule
@@ -171,7 +173,8 @@ module XORCY(output O, input CI, LI);
   assign O = CI ^ LI;
 endmodule
 
-module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S);
+(* abc_box_id = 3, abc_carry, lib_whitebox *)
+module CARRY4((* abc_carry_out *) output [3:0] CO, output [3:0] O, (* abc_carry_in *) input CI, input CYINIT, input [3:0] DI, S);
   assign O = S ^ {CO[2:0], CI | CYINIT};
   assign CO[0] = S[0] ? CI | CYINIT : DI[0];
   assign CO[1] = S[1] ? CO[0] : DI[1];
@@ -202,7 +205,7 @@ endmodule
 
 `endif
 
-module FDRE (output reg Q, input C, CE, D, R);
+module FDRE ((* abc_flop_q *) output reg Q, input C, CE, D, R);
   parameter [0:0] INIT = 1'b0;
   parameter [0:0] IS_C_INVERTED = 1'b0;
   parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -214,7 +217,7 @@ module FDRE (output reg Q, input C, CE, D, R);
   endcase endgenerate
 endmodule
 
-module FDSE (output reg Q, input C, CE, D, S);
+module FDSE ((* abc_flop_q *) output reg Q, input C, CE, D, S);
   parameter [0:0] INIT = 1'b0;
   parameter [0:0] IS_C_INVERTED = 1'b0;
   parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -226,7 +229,7 @@ module FDSE (output reg Q, input C, CE, D, S);
   endcase endgenerate
 endmodule
 
-module FDCE (output reg Q, input C, CE, D, CLR);
+module FDCE ((* abc_flop_q *) output reg Q, input C, CE, D, CLR);
   parameter [0:0] INIT = 1'b0;
   parameter [0:0] IS_C_INVERTED = 1'b0;
   parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -240,7 +243,7 @@ module FDCE (output reg Q, input C, CE, D, CLR);
   endcase endgenerate
 endmodule
 
-module FDPE (output reg Q, input C, CE, D, PRE);
+module FDPE ((* abc_flop_q *) output reg Q, input C, CE, D, PRE);
   parameter [0:0] INIT = 1'b0;
   parameter [0:0] IS_C_INVERTED = 1'b0;
   parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -254,30 +257,31 @@ module FDPE (output reg Q, input C, CE, D, PRE);
   endcase endgenerate
 endmodule
 
-module FDRE_1 (output reg Q, input C, CE, D, R);
+module FDRE_1 ((* abc_flop_q *) output reg Q, input C, CE, D, R);
   parameter [0:0] INIT = 1'b0;
   initial Q <= INIT;
   always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D;
 endmodule
 
-module FDSE_1 (output reg Q, input C, CE, D, S);
+module FDSE_1 ((* abc_flop_q *) output reg Q, input C, CE, D, S);
   parameter [0:0] INIT = 1'b1;
   initial Q <= INIT;
   always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D;
 endmodule
 
-module FDCE_1 (output reg Q, input C, CE, D, CLR);
+module FDCE_1 ((* abc_flop_q *) output reg Q, input C, CE, D, CLR);
   parameter [0:0] INIT = 1'b0;
   initial Q <= INIT;
   always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
 endmodule
 
-module FDPE_1 (output reg Q, input C, CE, D, PRE);
+module FDPE_1 ((* abc_flop_q *) output reg Q, input C, CE, D, PRE);
   parameter [0:0] INIT = 1'b1;
   initial Q <= INIT;
   always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
 endmodule
 
+(* abc_box_id = 4 /*, lib_whitebox*/ *)
 module RAM64X1D (
   output DPO, SPO,
   input  D, WCLK, WE,
@@ -291,10 +295,13 @@ module RAM64X1D (
   reg [63:0] mem = INIT;
   assign SPO = mem[a];
   assign DPO = mem[dpra];
+`ifndef _ABC
   wire clk = WCLK ^ IS_WCLK_INVERTED;
   always @(posedge clk) if (WE) mem[a] <= D;
+`endif
 endmodule
 
+(* abc_box_id = 5 /*, lib_whitebox*/ *)
 module RAM128X1D (
   output       DPO, SPO,
   input        D, WCLK, WE,
@@ -305,12 +312,14 @@ module RAM128X1D (
   reg [127:0] mem = INIT;
   assign SPO = mem[A];
   assign DPO = mem[DPRA];
+`ifndef _ABC
   wire clk = WCLK ^ IS_WCLK_INVERTED;
   always @(posedge clk) if (WE) mem[A] <= D;
+`endif
 endmodule
 
 module SRL16E (
-  output Q,
+  (* abc_flop_q *) output Q,
   input A0, A1, A2, A3, CE, CLK, D
 );
   parameter [15:0] INIT = 16'h0000;
@@ -328,7 +337,7 @@ module SRL16E (
 endmodule
 
 module SRLC32E (
-  output Q,
+  (* abc_flop_q *) output Q,
   output Q31,
   input [4:0] A,
   input CE, CLK, D
index 8e39b440dfbd9a3e1def30b29c9bdd896e19627e..2b384f40589e096a2dc0176c1a18b34031bb0db7 100644 (file)
@@ -116,7 +116,7 @@ function xtract_cell_decl()
        xtract_cell_decl PS7 "(* keep *)"
        xtract_cell_decl PULLDOWN
        xtract_cell_decl PULLUP
-       xtract_cell_decl RAM128X1D
+       #xtract_cell_decl RAM128X1D
        xtract_cell_decl RAM128X1S
        xtract_cell_decl RAM256X1S
        xtract_cell_decl RAM32M
@@ -125,7 +125,7 @@ function xtract_cell_decl()
        xtract_cell_decl RAM32X1S_1
        xtract_cell_decl RAM32X2S
        xtract_cell_decl RAM64M
-       xtract_cell_decl RAM64X1D
+       #xtract_cell_decl RAM64X1D
        xtract_cell_decl RAM64X1S
        xtract_cell_decl RAM64X1S_1
        xtract_cell_decl RAM64X2S
index fbcc74682c49e20ecd2b35cf924b3684fd1bba69..0ec3d0df0302b5b8d261f501c089ad862c3f0f07 100644 (file)
@@ -3655,17 +3655,6 @@ module PULLUP (...);
     output O;
 endmodule
 
-module RAM128X1D (...);
-    parameter [127:0] INIT = 128'h00000000000000000000000000000000;
-    parameter [0:0] IS_WCLK_INVERTED = 1'b0;
-    output DPO, SPO;
-    input [6:0] A;
-    input [6:0] DPRA;
-    input D;
-    input WCLK;
-    input WE;
-endmodule
-
 module RAM128X1S (...);
     parameter [127:0] INIT = 128'h00000000000000000000000000000000;
     parameter [0:0] IS_WCLK_INVERTED = 1'b0;
@@ -3756,13 +3745,6 @@ module RAM64M (...);
     input WE;
 endmodule
 
-module RAM64X1D (...);
-    parameter [63:0] INIT = 64'h0000000000000000;
-    parameter [0:0] IS_WCLK_INVERTED = 1'b0;
-    output DPO, SPO;
-    input A0, A1, A2, A3, A4, A5, D, DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5, WCLK, WE;
-endmodule
-
 module RAM64X1S (...);
     parameter [63:0] INIT = 64'h0000000000000000;
     parameter [0:0] IS_WCLK_INVERTED = 1'b0;
diff --git a/techlibs/xilinx/mux_map.v b/techlibs/xilinx/mux_map.v
new file mode 100644 (file)
index 0000000..0fa8db7
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *                2019  Eddie Hung    <eddie@fpgeh.com>
+ *
+ *  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.
+ *
+ */
+
+module \$shiftx (A, B, Y);
+  parameter A_SIGNED = 0;
+  parameter B_SIGNED = 0;
+  parameter A_WIDTH = 1;
+  parameter B_WIDTH = 1;
+  parameter Y_WIDTH = 1;
+
+  input [A_WIDTH-1:0] A;
+  input [B_WIDTH-1:0] B;
+  output [Y_WIDTH-1:0] Y;
+
+  parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0;
+  parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0;
+
+  generate
+    genvar i, j;
+    // TODO: Check if this opt still necessary
+    if (B_SIGNED) begin
+      if (_TECHMAP_CONSTMSK_B_[B_WIDTH-1] && _TECHMAP_CONSTVAL_B_[B_WIDTH-1] == 1'b0)
+        // Optimisation to remove B_SIGNED if sign bit of B is constant-0
+        \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(0), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH-1'd1), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B[B_WIDTH-2:0]), .Y(Y));
+      else
+        wire _TECHMAP_FAIL_ = 1;
+    end
+    else if (B_WIDTH < 3 || A_WIDTH <= 4) begin
+      wire _TECHMAP_FAIL_ = 1;
+    end
+    else begin
+        \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y));
+    end
+  endgenerate
+endmodule
index a293081f1825966dc164d26cb7fa7709d4f6efb0..f5f8c43e0d0ab0961c90161477efc1fba222d528 100644 (file)
@@ -58,6 +58,9 @@ struct SynthXilinxPass : public ScriptPass
                log("        generate an output netlist (and BLIF file) suitable for VPR\n");
                log("        (this feature is experimental and incomplete)\n");
                log("\n");
+               log("    -nocarry\n");
+               log("        disable inference of carry chains\n");
+               log("\n");
                log("    -nobram\n");
                log("        disable inference of block rams\n");
                log("\n");
@@ -67,6 +70,9 @@ struct SynthXilinxPass : public ScriptPass
                log("    -nosrl\n");
                log("        disable inference of shift registers\n");
                log("\n");
+               log("    -nomux\n");
+               log("        disable inference of wide multiplexers\n");
+               log("\n");
                log("    -run <from_label>:<to_label>\n");
                log("        only run the commands between the labels (see below). an empty\n");
                log("        from label is synonymous to 'begin', and empty to label is\n");
@@ -78,26 +84,32 @@ struct SynthXilinxPass : public ScriptPass
                log("    -retime\n");
                log("        run 'abc' with -dff option\n");
                log("\n");
+               log("    -abc9\n");
+               log("        use abc9 instead of abc\n");
+               log("\n");
                log("\n");
                log("The following commands are executed by this synthesis command:\n");
                help_script();
                log("\n");
        }
 
-       std::string top_opt, edif_file, blif_file, arch;
-       bool flatten, retime, vpr, nobram, nodram, nosrl;
+       std::string top_opt, edif_file, blif_file, abc, arch;
+       bool flatten, retime, vpr, nocarry, nobram, nodram, nosrl, nomux;
 
        void clear_flags() YS_OVERRIDE
        {
                top_opt = "-auto-top";
                edif_file.clear();
                blif_file.clear();
+               abc = "abc";
                flatten = false;
                retime = false;
                vpr = false;
+               nocarry = false;
                nobram = false;
                nodram = false;
                nosrl = false;
+               nomux = false;
                arch = "xc7";
        }
 
@@ -145,6 +157,10 @@ struct SynthXilinxPass : public ScriptPass
                                vpr = true;
                                continue;
                        }
+                       if (args[argidx] == "-nocarry") {
+                               nocarry = true;
+                               continue;
+                       }
                        if (args[argidx] == "-nobram") {
                                nobram = true;
                                continue;
@@ -157,6 +173,14 @@ struct SynthXilinxPass : public ScriptPass
                                nosrl = true;
                                continue;
                        }
+                       if (args[argidx] == "-nomux") {
+                               nomux = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-abc9") {
+                               abc = "abc9";
+                               continue;
+                       }
                        break;
                }
                extra_args(args, argidx, design);
@@ -179,9 +203,9 @@ struct SynthXilinxPass : public ScriptPass
        {
                if (check_label("begin")) {
                        if (vpr)
-                               run("read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
+                               run("read_verilog -lib -D _ABC -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
                        else
-                               run("read_verilog -lib +/xilinx/cells_sim.v");
+                               run("read_verilog -lib -D _ABC +/xilinx/cells_sim.v");
 
                        run("read_verilog -lib +/xilinx/cells_xtra.v");
 
@@ -200,6 +224,21 @@ struct SynthXilinxPass : public ScriptPass
 
                if (check_label("coarse")) {
                        run("synth -run coarse");
+
+                       //if (!nomux || help_mode)
+                       //      run("muxpack", "(skip if '-nomux')");
+
+                       // shregmap -tech xilinx can cope with $shiftx and $mux
+                       //   cells for identifying variable-length shift registers,
+                       //   so attempt to convert $pmux-es to the former
+                       // Also: wide multiplexer inference benefits from this too
+                       if (!(nosrl && nomux) || help_mode)
+                               run("pmux2shiftx", "(skip if '-nosrl' and '-nomux')");
+
+                       // Run a number of peephole optimisations, including one
+                       //   that optimises $mul cells driving $shiftx's B input
+                       //   and that aids wide mux analysis
+                       run("peepopt");
                }
 
                if (check_label("bram", "(skip if '-nobram')")) {
@@ -217,12 +256,6 @@ struct SynthXilinxPass : public ScriptPass
                }
 
                if (check_label("fine")) {
-                       // shregmap -tech xilinx can cope with $shiftx and $mux
-                       //   cells for identifiying variable-length shift registers,
-                       //   so attempt to convert $pmux-es to the former
-                       if (!nosrl || help_mode)
-                               run("pmux2shiftx", "(skip if '-nosrl')");
-
                        run("opt -fast -full");
                        run("memory_map");
                        run("dffsr2dff");
@@ -237,30 +270,45 @@ struct SynthXilinxPass : public ScriptPass
                                run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
                        }
 
-                       if (!vpr || help_mode)
-                               run("techmap -map +/techmap.v -map +/xilinx/arith_map.v");
-                       else
-                               run("techmap -map +/techmap.v +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
-
+                       std::string techmap_files = " -map +/techmap.v";
+                       if (help_mode)
+                                       techmap_files += " [-map +/xilinx/mux_map.v]";
+                       else if (!nomux)
+                                       techmap_files += " -map +/xilinx/mux_map.v";
+                       if (help_mode)
+                                       techmap_files += " [-map +/xilinx/arith_map.v]";
+                       else if (!nocarry) {
+                                       techmap_files += " -map +/xilinx/arith_map.v";
+                                       if (vpr)
+                                                       techmap_files += " -D _EXPLICIT_CARRY";
+                                       else if (abc == "abc9")
+                                                       techmap_files += " -D _CLB_CARRY";
+                       }
+                       run("techmap " + techmap_files);
                        run("opt -fast");
                }
 
                if (check_label("map_cells")) {
+                       if (!nomux || help_mode)
+                               run("muxcover -mux8 -mux16", "(skip if '-nomux')");
                        run("techmap -map +/techmap.v -map +/xilinx/cells_map.v");
                        run("clean");
                }
 
                if (check_label("map_luts")) {
-                       if (help_mode)
-                               run("abc -luts 2:2,3,6:5,10,20 [-dff]");
+                       if (abc == "abc9")
+                               run(abc + " -lut +/xilinx/abc.lut -box +/xilinx/abc.box" + string(retime ? " -dff" : ""));
+                       else if (help_mode)
+                               run(abc + " -luts 2:2,3,6:5,10,20 [-dff]");
                        else
-                               run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
+                               run(abc + " -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
                        run("clean");
+
                        // This shregmap call infers fixed length shift registers after abc
                        //   has performed any necessary retiming
                        if (!nosrl || help_mode)
                                run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
-                       run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
+                       run("techmap -map +/xilinx/lut_map.v -map +/xilinx/cells_map.v -map +/xilinx/ff_map.v");
                        run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
                                        "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
                        run("clean");
diff --git a/tests/simple_abc9/abc.box b/tests/simple_abc9/abc.box
new file mode 100644 (file)
index 0000000..a8801d8
--- /dev/null
@@ -0,0 +1,2 @@
+MUXF8 1 0 3 1
+1 1 1
diff --git a/tests/simple_abc9/abc9.v b/tests/simple_abc9/abc9.v
new file mode 100644 (file)
index 0000000..2752ff8
--- /dev/null
@@ -0,0 +1,252 @@
+module abc9_test001(input a, output o);
+assign o = a;
+endmodule
+
+module abc9_test002(input [1:0] a, output o);
+assign o = a[1];
+endmodule
+
+module abc9_test003(input [1:0] a, output [1:0] o);
+assign o = a;
+endmodule
+
+module abc9_test004(input [1:0] a, output o);
+assign o = ^a;
+endmodule
+
+module abc9_test005(input [1:0] a, output o, output p);
+assign o = ^a;
+assign p = ~o;
+endmodule
+
+module abc9_test006(input [1:0] a, output [2:0] o);
+assign o[0] = ^a;
+assign o[1] = ~o[0];
+assign o[2] = o[1];
+endmodule
+
+module abc9_test007(input a, output o);
+wire b, c;
+assign c = ~a;
+assign b = c;
+abc9_test007_sub s(b, o);
+endmodule
+
+module abc9_test007_sub(input a, output b);
+assign b = a;
+endmodule
+
+module abc9_test008(input a, output o);
+wire b, c;
+assign b = ~a;
+assign c = b;
+abc9_test008_sub s(b, o);
+endmodule
+
+module abc9_test008_sub(input a, output b);
+assign b = ~a;
+endmodule
+
+module abc9_test009(inout io, input oe);
+reg latch;
+always @(io or oe)
+    if (!oe)
+        latch <= io;
+assign io = oe ? ~latch : 1'bz;
+endmodule
+
+module abc9_test010(inout [7:0] io, input oe);
+reg [7:0] latch;
+always @(io or oe)
+    if (!oe)
+        latch <= io;
+assign io = oe ? ~latch : 8'bz;
+endmodule
+
+module abc9_test011(inout io, input oe);
+reg latch;
+always @(io or oe)
+    if (!oe)
+        latch <= io;
+//assign io = oe ? ~latch : 8'bz;
+endmodule
+
+module abc9_test012(inout io, input oe);
+reg latch;
+//always @(io or oe)
+//    if (!oe)
+//        latch <= io;
+assign io = oe ? ~latch : 8'bz;
+endmodule
+
+module abc9_test013(inout [3:0] io, input oe);
+reg [3:0] latch;
+always @(io or oe)
+    if (!oe)
+        latch[3:0] <= io[3:0];
+    else
+        latch[7:4] <= io;
+assign io[3:0] = oe ? ~latch[3:0] : 4'bz;
+assign io[7:4] = !oe ? {latch[4], latch[7:3]} : 4'bz;
+endmodule
+
+module abc9_test014(inout [7:0] io, input oe);
+abc9_test012_sub sub(io, oe);
+endmodule
+
+module abc9_test012_sub(inout [7:0] io, input oe);
+reg [7:0] latch;
+always @(io or oe)
+    if (!oe)
+        latch[3:0] <= io;
+    else
+        latch[7:4] <= io;
+assign io[3:0] = oe ? ~latch[3:0] : 4'bz;
+assign io[7:4] = !oe ? {latch[4], latch[7:3]} : 4'bz;
+endmodule
+
+module abc9_test015(input a, output b, input c);
+assign b = ~a;
+(* keep *) wire d;
+assign d = ~c;
+endmodule
+
+module abc9_test016(input a, output b);
+assign b = ~a;
+(* keep *) reg c;
+always @* c <= ~a;
+endmodule
+
+module abc9_test017(input a, output b);
+assign b = ~a;
+(* keep *) reg c;
+always @* c = b;
+endmodule
+
+module abc9_test018(input a, output b, output c);
+assign b = ~a;
+(* keep *) wire [1:0] d;
+assign c = &d;
+endmodule
+
+module abc9_test019(input a, output b);
+assign b = ~a;
+(* keep *) reg [1:0] c;
+reg d;
+always @* d <= &c;
+endmodule
+
+module abc9_test020(input a, output b);
+assign b = ~a;
+(* keep *) reg [1:0] c;
+(* keep *) reg d;
+always @* d <= &c;
+endmodule
+
+// Citation: https://github.com/alexforencich/verilog-ethernet
+module abc9_test021(clk, rst, s_eth_hdr_valid, s_eth_hdr_ready, s_eth_dest_mac, s_eth_src_mac, s_eth_type, s_eth_payload_axis_tdata, s_eth_payload_axis_tkeep, s_eth_payload_axis_tvalid, s_eth_payload_axis_tready, s_eth_payload_axis_tlast, s_eth_payload_axis_tid, s_eth_payload_axis_tdest, s_eth_payload_axis_tuser, m_eth_hdr_valid, m_eth_hdr_ready, m_eth_dest_mac, m_eth_src_mac, m_eth_type, m_eth_payload_axis_tdata, m_eth_payload_axis_tkeep, m_eth_payload_axis_tvalid, m_eth_payload_axis_tready, m_eth_payload_axis_tlast, m_eth_payload_axis_tid, m_eth_payload_axis_tdest, m_eth_payload_axis_tuser);
+  input clk;
+  output [47:0] m_eth_dest_mac;
+  input m_eth_hdr_ready;
+  output m_eth_hdr_valid;
+  output [7:0] m_eth_payload_axis_tdata;
+  output [7:0] m_eth_payload_axis_tdest;
+  output [7:0] m_eth_payload_axis_tid;
+  output m_eth_payload_axis_tkeep;
+  output m_eth_payload_axis_tlast;
+  input m_eth_payload_axis_tready;
+  output m_eth_payload_axis_tuser;
+  output m_eth_payload_axis_tvalid;
+  output [47:0] m_eth_src_mac;
+  output [15:0] m_eth_type;
+  input rst;
+  input [191:0] s_eth_dest_mac;
+  output [3:0] s_eth_hdr_ready;
+  input [3:0] s_eth_hdr_valid;
+  input [31:0] s_eth_payload_axis_tdata;
+  input [31:0] s_eth_payload_axis_tdest;
+  input [31:0] s_eth_payload_axis_tid;
+  input [3:0] s_eth_payload_axis_tkeep;
+  input [3:0] s_eth_payload_axis_tlast;
+  output [3:0] s_eth_payload_axis_tready;
+  input [3:0] s_eth_payload_axis_tuser;
+  input [3:0] s_eth_payload_axis_tvalid;
+  input [191:0] s_eth_src_mac;
+  input [63:0] s_eth_type;
+  (* keep *)
+  wire [0:0] grant, request;
+  wire a;
+  not u0 (
+    a,
+    grant[0]
+  );
+  and u1  (
+    request[0],
+    s_eth_hdr_valid[0],
+    a
+  );
+  (* keep *)
+  MUXF8 u2  (
+    .I0(1'bx),
+    .I1(1'bx),
+    .O(o),
+    .S(1'bx)
+  );
+  arbiter  arb_inst (
+    .acknowledge(acknowledge),
+    .clk(clk),
+    .grant(grant),
+    .grant_encoded(grant_encoded),
+    .grant_valid(grant_valid),
+    .request(request),
+    .rst(rst)
+  );
+endmodule
+
+module arbiter (clk, rst, request, acknowledge, grant, grant_valid, grant_encoded);
+  input [3:0] acknowledge;
+  input clk;
+  output [3:0] grant;
+  output [1:0] grant_encoded;
+  output grant_valid;
+  input [3:0] request;
+  input rst;
+endmodule
+
+(* abc_box_id=1 *)
+module MUXF8(input I0, I1, S, output O);
+endmodule
+
+// Citation: https://github.com/alexforencich/verilog-ethernet
+// TODO: yosys -p "synth_xilinx -abc9 -top abc9_test022" abc9.v -q
+// returns before b4321a31
+//   Warning: Wire abc9_test022.\m_eth_payload_axis_tkeep [7] is used but has no
+//   driver.
+//   Warning: Wire abc9_test022.\m_eth_payload_axis_tkeep [3] is used but has no
+//   driver.
+module abc9_test022
+(
+    input  wire        clk,
+    input  wire        i,
+    output wire [7:0]  m_eth_payload_axis_tkeep
+);
+    reg [7:0]  m_eth_payload_axis_tkeep_reg = 8'd0;
+    assign m_eth_payload_axis_tkeep = m_eth_payload_axis_tkeep_reg;
+    always @(posedge clk)
+        m_eth_payload_axis_tkeep_reg <= i ? 8'hff : 8'h0f;
+endmodule
+
+// Citation: https://github.com/riscv/riscv-bitmanip
+// TODO: yosys -p "synth_xilinx -abc9 -top abc9_test023" abc9.v -q
+// returns before 14233843
+//   Warning: Wire abc9_test023.\dout [1] is used but has no driver.
+module abc9_test023 #(
+       parameter integer N = 2,
+       parameter integer M = 2
+) (
+       input [7:0] din,
+       output [M-1:0] dout
+);
+       wire [2*M-1:0] mask = {M{1'b1}};
+       assign dout = (mask << din[N-1:0]) >> M;
+endmodule
diff --git a/tests/simple_abc9/run-test.sh b/tests/simple_abc9/run-test.sh
new file mode 100755 (executable)
index 0000000..4935d41
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+OPTIND=1
+seed=""    # default to no seed specified
+while getopts "S:" opt
+do
+    case "$opt" in
+       S) arg="${OPTARG#"${OPTARG%%[![:space:]]*}"}" # remove leading space
+          seed="SEED=$arg" ;;
+    esac
+done
+shift "$((OPTIND-1))"
+
+# check for Icarus Verilog
+if ! which iverilog > /dev/null ; then
+  echo "$0: Error: Icarus Verilog 'iverilog' not found."
+  exit 1
+fi
+
+cp ../simple/*.v .
+DOLLAR='?'
+exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-p 'hierarchy; synth -run coarse; opt -full; techmap; abc9 -lut 4 -box ../abc.box; stat; check -assert; select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'"
diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v
new file mode 100644 (file)
index 0000000..f1bd5ea
--- /dev/null
@@ -0,0 +1,138 @@
+module mux_if_unbal_4_1 #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @*
+    if (s == 0) o <= i[0*W+:W];
+    else if (s == 1) o <= i[1*W+:W];
+    else if (s == 2) o <= i[2*W+:W];
+    else if (s == 3) o <= i[3*W+:W];
+    else o <= {W{1'bx}};
+endmodule
+
+module mux_if_unbal_5_3 #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+    o <= {W{1'bx}};
+    if (s == 0) o <= i[0*W+:W];
+    if (s == 1) o <= i[1*W+:W];
+    if (s == 2) o <= i[2*W+:W];
+    if (s == 3) o <= i[3*W+:W];
+    if (s == 4) o <= i[4*W+:W];
+end
+endmodule
+
+module mux_if_unbal_5_3_invert #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @*
+    if (s != 0) 
+               if (s != 1) 
+                       if (s != 2)
+                               if (s != 3)
+                                       if (s != 4) o <= i[4*W+:W];
+                                       else o <= i[0*W+:W];
+                               else o <= i[3*W+:W];
+                       else o <= i[2*W+:W];
+               else o <= i[1*W+:W];
+    else o <= {W{1'bx}};
+endmodule
+
+module mux_if_unbal_5_3_width_mismatch #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+    o <= {W{1'bx}};
+    if (s == 0) o <= i[0*W+:W];
+    if (s == 1) o <= i[1*W+:W];
+    if (s == 2) o[W-2:0] <= i[2*W+:W-1];
+    if (s == 3) o <= i[3*W+:W];
+    if (s == 4) o <= i[4*W+:W];
+end
+endmodule
+
+module mux_if_unbal_4_1_missing #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+    if (s == 0) o <= i[0*W+:W];
+//    else if (s == 1) o <= i[1*W+:W];
+//    else if (s == 2) o <= i[2*W+:W];
+    else if (s == 3) o <= i[3*W+:W];
+    else o <= {W{1'bx}};
+end
+endmodule
+
+module mux_if_unbal_5_3_order #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+    o <= {W{1'bx}};
+    if (s == 3) o <= i[3*W+:W];
+    if (s == 2) o <= i[2*W+:W];
+    if (s == 1) o <= i[1*W+:W];
+    if (s == 4) o <= i[4*W+:W];
+    if (s == 0) o <= i[0*W+:W];
+end
+endmodule
+
+module mux_if_unbal_4_1_nonexcl #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @*
+    if (s == 0) o <= i[0*W+:W];
+    else if (s == 1) o <= i[1*W+:W];
+    else if (s == 2) o <= i[2*W+:W];
+    else if (s == 3) o <= i[3*W+:W];
+       else if (s == 0) o <= {W{1'b0}};
+    else o <= {W{1'bx}};
+endmodule
+
+module mux_if_unbal_5_3_nonexcl #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+    o <= {W{1'bx}};
+    if (s == 0) o <= i[0*W+:W];
+    if (s == 1) o <= i[1*W+:W];
+    if (s == 2) o <= i[2*W+:W];
+    if (s == 3) o <= i[3*W+:W];
+    if (s == 4) o <= i[4*W+:W];
+       if (s == 0) o <= i[2*W+:W];
+end
+endmodule
+
+module mux_case_unbal_8_7#(parameter N=8, parameter W=7) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @* begin
+    o <= {W{1'bx}};
+    case (s)
+    0: o <= i[0*W+:W];
+    default:
+        case (s)
+        1: o <= i[1*W+:W];
+        2: o <= i[2*W+:W];
+        default:
+            case (s)
+            3: o <= i[3*W+:W];
+            4: o <= i[4*W+:W];
+            5: o <= i[5*W+:W];
+            default:
+                case (s)
+                    6: o <= i[6*W+:W];
+                    default: o <= i[7*W+:W];
+                endcase
+            endcase
+        endcase
+    endcase
+end
+endmodule
+
+module mux_if_bal_8_2 #(parameter N=8, parameter W=2) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o);
+always @*
+    if (s[0] == 1'b0)
+     if (s[1] == 1'b0)
+      if (s[2] == 1'b0)
+       o <= i[0*W+:W];
+      else
+       o <= i[1*W+:W];
+     else
+      if (s[2] == 1'b0)
+       o <= i[2*W+:W];
+      else
+       o <= i[3*W+:W];
+    else
+     if (s[1] == 1'b0)
+      if (s[2] == 1'b0)
+       o <= i[4*W+:W];
+      else
+       o <= i[5*W+:W];
+     else
+      if (s[2] == 1'b0)
+       o <= i[6*W+:W];
+      else
+       o <= i[7*W+:W];
+endmodule
diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys
new file mode 100644 (file)
index 0000000..9ea743b
--- /dev/null
@@ -0,0 +1,150 @@
+read_verilog muxpack.v
+design -save read
+hierarchy -top mux_if_unbal_4_1
+prep
+design -save gold
+muxpack
+opt
+stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_unbal_5_3
+prep
+design -save gold
+muxpack
+opt
+stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_unbal_5_3_invert
+prep
+design -save gold
+muxpack
+opt
+stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_unbal_5_3_width_mismatch
+prep
+design -save gold
+muxpack
+opt
+stat
+select -assert-count 0 t:$mux
+select -assert-count 2 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_unbal_4_1_missing
+prep
+design -save gold
+muxpack
+opt
+stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_unbal_5_3_order
+prep
+design -save gold
+muxpack
+opt
+stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_unbal_4_1_nonexcl
+prep
+design -save gold
+muxpack
+opt
+stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_unbal_5_3_nonexcl
+prep
+design -save gold
+muxpack
+opt
+stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_case_unbal_8_7
+prep
+design -save gold
+muxpack
+opt
+stat
+select -assert-count 0 t:$mux
+select -assert-count 1 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+design -load read
+hierarchy -top mux_if_bal_8_2
+prep
+design -save gold
+muxpack
+opt
+stat
+select -assert-count 7 t:$mux
+select -assert-count 0 t:$pmux
+design -stash gate
+design -import gold -as gold
+design -import gate -as gate
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter