Merge remote-tracking branch 'origin/master' into xaig_dff
authorEddie Hung <eddie@fpgeh.com>
Fri, 20 Dec 2019 21:56:13 +0000 (13:56 -0800)
committerEddie Hung <eddie@fpgeh.com>
Fri, 20 Dec 2019 21:56:13 +0000 (13:56 -0800)
17 files changed:
Makefile
backends/aiger/xaiger.cc
frontends/aiger/aigerparse.cc
passes/hierarchy/submod.cc
passes/techmap/abc9.cc
techlibs/xilinx/abc9_map.v
techlibs/xilinx/abc9_model.v
techlibs/xilinx/abc9_unmap.v
techlibs/xilinx/abc9_xc7.box
techlibs/xilinx/cells_sim.v
techlibs/xilinx/synth_xilinx.cc
tests/arch/xilinx/abc9_map.ys [new file with mode: 0644]
tests/simple_abc9/abc9.v
tests/simple_abc9/run-test.sh
tests/various/abc9.v
tests/various/abc9.ys
tests/various/submod.ys [new file with mode: 0644]

index a85f6350c556836c6728f9ffe6a2ee913316a40e..2a3332af9e9415262b022888f21e7b9711e76758 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -128,7 +128,7 @@ bumpversion:
 # 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 = 623b5e8
+ABCREV = c4b12fa
 ABCPULL = 1
 ABCURL ?= https://github.com/berkeley-abc/abc
 ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
index 627133314e47af23a7751ca7859dcf83d3cc6d33..af52daa0cd64a615a2d44588e9f7eb71463797c0 100644 (file)
@@ -78,11 +78,12 @@ struct XAigerWriter
        Module *module;
        SigMap sigmap;
 
-       pool<SigBit> input_bits, output_bits;
+       pool<SigBit> input_bits, output_bits, external_bits;
        dict<SigBit, SigBit> not_map, alias_map;
        dict<SigBit, pair<SigBit, SigBit>> and_map;
        vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int>> ci_bits;
        vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int,int>> co_bits;
+       dict<SigBit, std::pair<int,int>> ff_bits;
        dict<SigBit, float> arrival_times;
 
        vector<pair<int, int>> aig_gates;
@@ -141,7 +142,7 @@ struct XAigerWriter
        {
                pool<SigBit> undriven_bits;
                pool<SigBit> unused_bits;
-               pool<SigBit> keep_bits;
+               pool<SigBit> inout_bits;
 
                // promote public wires
                for (auto wire : module->wires())
@@ -153,52 +154,52 @@ struct XAigerWriter
                        if (wire->port_input)
                                sigmap.add(wire);
 
+               // promote keep wires
                for (auto wire : module->wires())
-               {
-                       bool keep = wire->attributes.count("\\keep");
+                       if (wire->get_bool_attribute(ID::keep))
+                               sigmap.add(wire);
 
+               for (auto wire : module->wires())
                        for (int i = 0; i < GetSize(wire); i++)
                        {
                                SigBit wirebit(wire, i);
                                SigBit bit = sigmap(wirebit);
 
-                               if (bit.wire) {
-                                       undriven_bits.insert(bit);
-                                       unused_bits.insert(bit);
+                               if (bit.wire == nullptr) {
+                                       if (wire->port_output) {
+                                               aig_map[wirebit] = (bit == State::S1) ? 1 : 0;
+                                               if (holes_mode)
+                                                       output_bits.insert(wirebit);
+                                               //external_bits.insert(wirebit);
+                                       }
+                                       continue;
                                }
 
-                               if (keep)
-                                       keep_bits.insert(wirebit);
+                               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_input)
+                                       input_bits.insert(bit);
 
-                               if (wire->port_output || keep) {
-                                       if (bit != RTLIL::Sx) {
-                                               if (bit != wirebit)
-                                                       alias_map[wirebit] = bit;
+                               if (wire->port_output) {
+                                       if (bit != wirebit)
+                                               alias_map[wirebit] = bit;
+                                       if (holes_mode)
                                                output_bits.insert(wirebit);
-                                       }
                                        else
-                                               log_debug("Skipping PO '%s' driven by 1'bx\n", log_signal(wirebit));
+                                               external_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);
+                               if (wire->port_input && wire->port_output)
+                                       inout_bits.insert(wirebit);
+                       }
 
                // TODO: Speed up toposort -- ultimately we care about
                //       box ordering, but not individual AIG cells
                dict<SigBit, pool<IdString>> bit_drivers, bit_users;
                TopoSort<IdString, RTLIL::sort_by_id_str> toposort;
                bool abc9_box_seen = false;
+               std::vector<Cell*> flop_boxes;
 
                for (auto cell : module->selected_cells()) {
                        if (cell->type == "$_NOT_")
@@ -236,75 +237,77 @@ struct XAigerWriter
 
                        log_assert(!holes_mode);
 
+                       if (cell->type == "$__ABC9_FF_")
+                       {
+                               SigBit D = sigmap(cell->getPort("\\D").as_bit());
+                               SigBit Q = sigmap(cell->getPort("\\Q").as_bit());
+                               unused_bits.erase(D);
+                               undriven_bits.erase(Q);
+                               alias_map[Q] = D;
+                               auto r = ff_bits.insert(std::make_pair(D, std::make_pair(0, 2)));
+                               log_assert(r.second);
+                               continue;
+                       }
+
                        RTLIL::Module* inst_module = module->design->module(cell->type);
                        if (inst_module && inst_module->attributes.count("\\abc9_box_id")) {
                                abc9_box_seen = true;
 
-                               if (!holes_mode) {
-                                       toposort.node(cell->name);
-                                       for (const auto &conn : cell->connections()) {
-                                               auto port_wire = inst_module->wire(conn.first);
-                                               if (port_wire->port_input) {
-                                                       // Ignore inout for the sake of topographical ordering
-                                                       if (port_wire->port_output) continue;
-                                                       for (auto bit : sigmap(conn.second))
-                                                               bit_users[bit].insert(cell->name);
-                                               }
+                               toposort.node(cell->name);
 
-                                               if (port_wire->port_output)
-                                                       for (auto bit : sigmap(conn.second))
-                                                               bit_drivers[bit].insert(cell->name);
+                               for (const auto &conn : cell->connections()) {
+                                       auto port_wire = inst_module->wire(conn.first);
+                                       if (port_wire->port_input) {
+                                               // Ignore inout for the sake of topographical ordering
+                                               if (port_wire->port_output) continue;
+                                               for (auto bit : sigmap(conn.second))
+                                                       bit_users[bit].insert(cell->name);
                                        }
-                               }
-                       }
-                       else {
-                               bool cell_known = inst_module || cell->known();
-                               for (const auto &c : cell->connections()) {
-                                       if (c.second.is_fully_const()) continue;
-                                       auto port_wire = inst_module ? inst_module->wire(c.first) : nullptr;
-                                       auto is_input = (port_wire && port_wire->port_input) || !cell_known || cell->input(c.first);
-                                       auto is_output = (port_wire && port_wire->port_output) || !cell_known || cell->output(c.first);
-                                       if (!is_input && !is_output)
-                                               log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type));
-
-                                       if (is_input) {
-                                               for (auto b : c.second) {
-                                                       Wire *w = b.wire;
-                                                       if (!w) continue;
-                                                       if (!w->port_output || !cell_known) {
-                                                               SigBit I = sigmap(b);
-                                                               if (I != b)
-                                                                       alias_map[b] = I;
-                                                               output_bits.insert(b);
-                                                               unused_bits.erase(b);
 
-                                                               if (!cell_known)
-                                                                       keep_bits.insert(b);
-                                                       }
-                                               }
-                                       }
-                                       if (is_output) {
+                                       if (port_wire->port_output) {
                                                int arrival = 0;
-                                               if (port_wire) {
-                                                       auto it = port_wire->attributes.find("\\abc9_arrival");
-                                                       if (it != port_wire->attributes.end()) {
-                                                               if (it->second.flags != 0)
-                                                                       log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type));
-                                                               arrival = it->second.as_int();
-                                                       }
+                                               auto it = port_wire->attributes.find("\\abc9_arrival");
+                                               if (it != port_wire->attributes.end()) {
+                                                       if (it->second.flags != 0)
+                                                               log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type));
+                                                       arrival = it->second.as_int();
                                                }
 
-                                               for (auto b : c.second) {
-                                                       Wire *w = b.wire;
-                                                       if (!w) continue;
-                                                       input_bits.insert(b);
-                                                       SigBit O = sigmap(b);
-                                                       if (O != b)
-                                                               alias_map[O] = b;
-                                                       undriven_bits.erase(O);
-
+                                               for (auto bit : sigmap(conn.second)) {
+                                                       bit_drivers[bit].insert(cell->name);
                                                        if (arrival)
-                                                               arrival_times[b] = arrival;
+                                                               arrival_times[bit] = arrival;
+                                               }
+                                       }
+
+                               }
+
+                               if (inst_module->attributes.count("\\abc9_flop"))
+                                       flop_boxes.push_back(cell);
+                               continue;
+                       }
+
+                       bool cell_known = inst_module || cell->known();
+                       for (const auto &c : cell->connections()) {
+                               if (c.second.is_fully_const()) continue;
+                               auto port_wire = inst_module ? inst_module->wire(c.first) : nullptr;
+                               auto is_input = (port_wire && port_wire->port_input) || !cell_known || cell->input(c.first);
+                               auto is_output = (port_wire && port_wire->port_output) || !cell_known || cell->output(c.first);
+                               if (!is_input && !is_output)
+                                       log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type));
+
+                               if (is_input) {
+                                       for (auto b : c.second) {
+                                               Wire *w = b.wire;
+                                               if (!w) continue;
+                                               if (!w->port_output || !cell_known) {
+                                                       SigBit I = sigmap(b);
+                                                       if (I != b)
+                                                               alias_map[b] = I;
+                                                       if (holes_mode)
+                                                               output_bits.insert(b);
+                                                       else
+                                                               external_bits.insert(b);
                                                }
                                        }
                                }
@@ -314,6 +317,60 @@ struct XAigerWriter
                }
 
                if (abc9_box_seen) {
+                       dict<IdString, std::pair<IdString,int>> flop_q;
+                       for (auto cell : flop_boxes) {
+                               auto r = flop_q.insert(std::make_pair(cell->type, std::make_pair(IdString(), 0)));
+                               SigBit d;
+                               if (r.second) {
+                                       for (const auto &conn : cell->connections()) {
+                                               const SigSpec &rhs = conn.second;
+                                               if (!rhs.is_bit())
+                                                       continue;
+                                               if (!ff_bits.count(rhs))
+                                                       continue;
+                                               r.first->second.first = conn.first;
+                                               Module *inst_module = module->design->module(cell->type);
+                                               Wire *wire = inst_module->wire(conn.first);
+                                               log_assert(wire);
+                                               auto jt = wire->attributes.find("\\abc9_arrival");
+                                               if (jt != wire->attributes.end()) {
+                                                       if (jt->second.flags != 0)
+                                                               log_error("Attribute 'abc9_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(wire), log_id(cell->type));
+                                                       r.first->second.second = jt->second.as_int();
+                                               }
+                                               d = rhs;
+                                               log_assert(d == sigmap(d));
+                                               break;
+                                       }
+                               }
+                               else
+                                       d = cell->getPort(r.first->second.first);
+
+                               auto &rhs = ff_bits.at(d);
+
+                               auto it = cell->attributes.find(ID(abc9_mergeability));
+                               log_assert(it != cell->attributes.end());
+                               rhs.first = it->second.as_int();
+                               cell->attributes.erase(it);
+
+                               it = cell->attributes.find(ID(abc9_init));
+                               log_assert(it != cell->attributes.end());
+                               log_assert(GetSize(it->second) == 1);
+                               if (it->second[0] == State::S1)
+                                       rhs.second = 1;
+                               else if (it->second[0] == State::S0)
+                                       rhs.second = 0;
+                               else {
+                                       log_assert(it->second[0] == State::Sx);
+                                       rhs.second = 0;
+                               }
+                               cell->attributes.erase(it);
+
+                               auto arrival = r.first->second.second;
+                               if (arrival)
+                                       arrival_times[d] = arrival;
+                       }
+
                        for (auto &it : bit_users)
                                if (bit_drivers.count(it.first))
                                        for (auto driver_cell : bit_drivers.at(it.first))
@@ -379,7 +436,7 @@ struct XAigerWriter
                                                                        alias_map[b] = I;
                                                        }
                                                        co_bits.emplace_back(b, cell, port_name, offset++, 0);
-                                                       unused_bits.erase(b);
+                                                       unused_bits.erase(I);
                                                }
                                        }
                                        if (w->port_output) {
@@ -404,62 +461,76 @@ struct XAigerWriter
                                                        SigBit O = sigmap(b);
                                                        if (O != b)
                                                                alias_map[O] = b;
+                                                       input_bits.erase(O);
                                                        undriven_bits.erase(O);
-                                                       input_bits.erase(b);
                                                }
                                        }
                                }
+
+                               // Connect <cell>.$abc9_currQ (inserted by abc9_map.v) as an input to the flop box
+                               if (box_module->get_bool_attribute("\\abc9_flop")) {
+                                       SigSpec rhs = module->wire(stringf("%s.$abc9_currQ", cell->name.c_str()));
+                                       if (rhs.empty())
+                                               log_error("'%s.$abc9_currQ' is not a wire present in module '%s'.\n", log_id(cell), log_id(module));
+
+                                       int offset = 0;
+                                       for (auto b : rhs) {
+                                               SigBit I = sigmap(b);
+                                               if (b == RTLIL::Sx)
+                                                       b = State::S0;
+                                               else if (I != b) {
+                                                       if (I == RTLIL::Sx)
+                                                               alias_map[b] = State::S0;
+                                                       else
+                                                               alias_map[b] = I;
+                                               }
+                                               co_bits.emplace_back(b, cell, "\\$abc9_currQ", offset++, 0);
+                                               unused_bits.erase(I);
+                                       }
+                               }
+
                                box_list.emplace_back(cell);
                        }
 
                        // TODO: Free memory from toposort, bit_drivers, bit_users
                }
 
-               for (auto bit : input_bits) {
-                       if (!output_bits.count(bit))
+               if (!holes_mode)
+                       for (auto cell : module->cells())
+                               if (!module->selected(cell))
+                                       for (auto &conn : cell->connections())
+                                               if (cell->input(conn.first))
+                                                       for (auto wirebit : conn.second)
+                                                               if (sigmap(wirebit).wire)
+                                                                       external_bits.insert(wirebit);
+
+               // For all bits consumed outside of the selected cells,
+               //   but driven from a selected cell, then add it as
+               //   a primary output
+               for (auto wirebit : external_bits) {
+                       SigBit bit = sigmap(wirebit);
+                       if (!bit.wire)
                                continue;
-                       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))
-                                       || keep_bits.count(bit)) {
-                               RTLIL::IdString wire_name = stringf("$%s$inout.out", wire->name.c_str());
-                               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)) {
-                                       auto a = not_map.at(bit);
-                                       not_map[new_bit] = a;
-                               }
-                               else if (and_map.count(bit)) {
-                                       auto a = and_map.at(bit);
-                                       and_map[new_bit] = a;
-                               }
-                               else if (alias_map.count(bit)) {
-                                       auto a = alias_map.at(bit);
-                                       alias_map[new_bit] = a;
-                               }
-                               else
-                                       alias_map[new_bit] = bit;
-                               output_bits.erase(bit);
-                               output_bits.insert(new_bit);
+                       if (!undriven_bits.count(bit)) {
+                               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)
+                       unused_bits.erase(sigmap(bit));
                for (auto bit : unused_bits)
                        undriven_bits.erase(bit);
 
-               if (!undriven_bits.empty() && !holes_mode) {
-                       undriven_bits.sort();
+               // Make all undriven bits a primary input
+               if (!holes_mode)
                        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);
+                               undriven_bits.erase(bit);
                        }
-                       log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module));
-               }
 
                if (holes_mode) {
                        struct sort_by_port_id {
@@ -487,10 +558,20 @@ struct XAigerWriter
                        aig_map[bit] = 2*aig_m;
                }
 
+               for (const auto &i : ff_bits) {
+                       const SigBit &bit = i.first;
+                       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++;
-                       aig_map[bit] = 2*aig_m;
+                       auto r = aig_map.insert(std::make_pair(bit, 2*aig_m));
+                       if (!r.second)
+                               ff_aig_map[bit] = 2*aig_m;
                }
 
                for (auto &c : co_bits) {
@@ -509,6 +590,17 @@ struct XAigerWriter
                        aig_outputs.push_back(bit2aig(bit));
                }
 
+               for (auto &i : ff_bits) {
+                       const SigBit &bit = i.first;
+                       aig_o++;
+                       aig_outputs.push_back(ff_aig_map.at(bit));
+               }
+
+               if (output_bits.empty()) {
+                       aig_o++;
+                       aig_outputs.push_back(0);
+                       omode = true;
+               }
        }
 
        void write_aiger(std::ostream &f, bool ascii_mode)
@@ -578,14 +670,14 @@ struct XAigerWriter
                std::stringstream h_buffer;
                auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1);
                write_h_buffer(1);
-               log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ci_bits));
-               write_h_buffer(input_bits.size() + ci_bits.size());
-               log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(co_bits));
-               write_h_buffer(output_bits.size() + GetSize(co_bits));
-               log_debug("piNum = %d\n", GetSize(input_bits));
-               write_h_buffer(input_bits.size());
-               log_debug("poNum = %d\n", GetSize(output_bits));
-               write_h_buffer(output_bits.size());
+               log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ff_bits) + GetSize(ci_bits));
+               write_h_buffer(input_bits.size() + ff_bits.size() + ci_bits.size());
+               log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(ff_bits) + GetSize(co_bits));
+               write_h_buffer(output_bits.size() + GetSize(ff_bits) + GetSize(co_bits));
+               log_debug("piNum = %d\n", GetSize(input_bits) + GetSize(ff_bits));
+               write_h_buffer(input_bits.size() + ff_bits.size());
+               log_debug("poNum = %d\n", GetSize(output_bits) + GetSize(ff_bits));
+               write_h_buffer(output_bits.size() + ff_bits.size());
                log_debug("boxNum = %d\n", GetSize(box_list));
                write_h_buffer(box_list.size());
 
@@ -601,19 +693,29 @@ struct XAigerWriter
                //for (auto bit : output_bits)
                //      write_o_buffer(0);
 
-               if (!box_list.empty()) {
+               if (!box_list.empty() || !ff_bits.empty()) {
                        RTLIL::Module *holes_module = module->design->addModule("$__holes__");
                        log_assert(holes_module);
 
+                       dict<IdString, Cell*> cell_cache;
+
                        int port_id = 1;
                        int box_count = 0;
                        for (auto cell : box_list) {
                                RTLIL::Module* box_module = module->design->module(cell->type);
+                               log_assert(box_module);
+                               IdString derived_name = box_module->derive(module->design, cell->parameters);
+                               box_module = module->design->module(derived_name);
+                               if (box_module->has_processes())
+                                       Pass::call_on_module(module->design, box_module, "proc");
+
                                int box_inputs = 0, box_outputs = 0;
-                               Cell *holes_cell = nullptr;
-                               if (box_module->get_bool_attribute("\\whitebox")) {
+                               auto r = cell_cache.insert(std::make_pair(derived_name, nullptr));
+                               Cell *holes_cell = r.first->second;
+                               if (r.second && !holes_cell && box_module->get_bool_attribute("\\whitebox")) {
                                        holes_cell = holes_module->addCell(cell->name, cell->type);
                                        holes_cell->parameters = cell->parameters;
+                                       r.first->second = holes_cell;
                                }
 
                                // NB: Assume box_module->ports are sorted alphabetically
@@ -622,8 +724,8 @@ struct XAigerWriter
                                        RTLIL::Wire *w = box_module->wire(port_name);
                                        log_assert(w);
                                        RTLIL::Wire *holes_wire;
-                                       RTLIL::SigSpec port_wire;
-                                       if (w->port_input) {
+                                       RTLIL::SigSpec port_sig;
+                                       if (w->port_input)
                                                for (int i = 0; i < GetSize(w); i++) {
                                                        box_inputs++;
                                                        holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
@@ -634,29 +736,47 @@ struct XAigerWriter
                                                                holes_module->ports.push_back(holes_wire->name);
                                                        }
                                                        if (holes_cell)
-                                                               port_wire.append(holes_wire);
+                                                               port_sig.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()));
+                                                               holes_wire = holes_module->addWire(stringf("$abc%s.%s", cell->name.c_str(), log_id(w->name)));
                                                        else
-                                                               holes_wire = holes_module->addWire(stringf("%s.%s[%d]", cell->name.c_str(), w->name.c_str(), i));
+                                                               holes_wire = holes_module->addWire(stringf("$abc%s.%s[%d]", cell->name.c_str(), log_id(w->name), i));
                                                        holes_wire->port_output = true;
                                                        holes_wire->port_id = port_id++;
                                                        holes_module->ports.push_back(holes_wire->name);
                                                        if (holes_cell)
-                                                               port_wire.append(holes_wire);
+                                                               port_sig.append(holes_wire);
                                                        else
                                                                holes_module->connect(holes_wire, State::S0);
                                                }
-                                               if (!port_wire.empty())
-                                                       holes_cell->setPort(w->name, port_wire);
                                        }
+                                       if (!port_sig.empty()) {
+                                               if (r.second)
+                                                       holes_cell->setPort(w->name, port_sig);
+                                               else
+                                                       holes_module->connect(holes_cell->getPort(w->name), port_sig);
+                                       }
+                               }
+
+                               // For flops only, create an extra 1-bit input that drives a new wire
+                               //   called "<cell>.$abc9_currQ" that is used below
+                               if (box_module->get_bool_attribute("\\abc9_flop")) {
+                                       log_assert(holes_cell);
+
+                                       box_inputs++;
+                                       Wire *holes_wire = holes_module->wire(stringf("\\i%d", box_inputs));
+                                       if (!holes_wire) {
+                                               holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs));
+                                               holes_wire->port_input = true;
+                                               holes_wire->port_id = port_id++;
+                                               holes_module->ports.push_back(holes_wire->name);
+                                       }
+                                       Wire *w = holes_module->addWire(stringf("%s.$abc9_currQ", cell->name.c_str()));
+                                       holes_module->connect(w, holes_wire);
                                }
 
                                write_h_buffer(box_inputs);
@@ -667,13 +787,36 @@ struct XAigerWriter
 
                        std::stringstream r_buffer;
                        auto write_r_buffer = std::bind(write_buffer, std::ref(r_buffer), std::placeholders::_1);
-                       write_r_buffer(0);
+                       log_debug("flopNum = %d\n", GetSize(ff_bits));
+                       write_r_buffer(ff_bits.size());
+
+                       std::stringstream s_buffer;
+                       auto write_s_buffer = std::bind(write_buffer, std::ref(s_buffer), std::placeholders::_1);
+                       write_s_buffer(ff_bits.size());
+
+                       for (const auto &i : ff_bits) {
+                               const SigBit &bit = i.first;
+                               int mergeability = i.second.first;
+                               log_assert(mergeability > 0);
+                               write_r_buffer(mergeability);
+                               int init = i.second.second;
+                               write_s_buffer(init);
+                               write_i_buffer(arrival_times.at(bit, 0));
+                               //write_o_buffer(0);
+                       }
+
                        f << "r";
                        std::string buffer_str = r_buffer.str();
                        int32_t buffer_size_be = to_big_endian(buffer_str.size());
                        f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
                        f.write(buffer_str.data(), buffer_str.size());
 
+                       f << "s";
+                       buffer_str = s_buffer.str();
+                       buffer_size_be = to_big_endian(buffer_str.size());
+                       f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be));
+                       f.write(buffer_str.data(), buffer_str.size());
+
                        if (holes_module) {
                                log_push();
 
@@ -681,37 +824,63 @@ struct XAigerWriter
                                //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/aigmap/check all lib_whitebox-es just once,
                                //       instead of per write_xaiger call
-                               Pass::call(holes_module->design, "techmap");
-                               Pass::call(holes_module->design, "aigmap");
-                               for (auto cell : holes_module->cells())
-                                       if (!cell->type.in("$_NOT_", "$_AND_"))
+                               Pass::call_on_module(holes_module->design, holes_module, "flatten -wb; techmap; aigmap");
+
+                               dict<SigSig, SigSig> replace;
+                               for (auto it = holes_module->cells_.begin(); it != holes_module->cells_.end(); ) {
+                                       auto cell = it->second;
+                                       if (cell->type.in("$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_",
+                                                               "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1", "$_DFF_PP0_", "$_DFF_PP1_")) {
+                                               SigBit D = cell->getPort("\\D");
+                                               SigBit Q = cell->getPort("\\Q");
+                                               // Remove the DFF cell from what needs to be a combinatorial box
+                                               it = holes_module->cells_.erase(it);
+                                               Wire *port;
+                                               if (GetSize(Q.wire) == 1)
+                                                       port = holes_module->wire(stringf("$abc%s", Q.wire->name.c_str()));
+                                               else
+                                                       port = holes_module->wire(stringf("$abc%s[%d]", Q.wire->name.c_str(), Q.offset));
+                                               log_assert(port);
+                                               // Prepare to replace "assign <port> = DFF.Q;" with "assign <port> = DFF.D;"
+                                               //   in order to extract the combinatorial control logic that feeds the box
+                                               //   (i.e. clock enable, synchronous reset, etc.)
+                                               replace.insert(std::make_pair(SigSig(port,Q), SigSig(port,D)));
+                                               // Since `flatten` above would have created wires named "<cell>.Q",
+                                               //   extract the pre-techmap cell name
+                                               auto pos = Q.wire->name.str().rfind(".");
+                                               log_assert(pos != std::string::npos);
+                                               IdString driver = Q.wire->name.substr(0, pos);
+                                               // And drive the signal that was previously driven by "DFF.Q" (typically
+                                               //   used to implement clock-enable functionality) with the "<cell>.$abc9_currQ"
+                                               //   wire (which itself is driven an input port) we inserted above
+                                               Wire *currQ = holes_module->wire(stringf("%s.$abc9_currQ", driver.c_str()));
+                                               log_assert(currQ);
+                                               holes_module->connect(Q, currQ);
+                                               continue;
+                                       }
+                                       else if (!cell->type.in("$_NOT_", "$_AND_"))
                                                log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n");
+                                       ++it;
+                               }
 
-                               holes_module->design->selection_stack.pop_back();
+                               for (auto &conn : holes_module->connections_) {
+                                       auto it = replace.find(conn);
+                                       if (it != replace.end())
+                                               conn = it->second;
+                               }
 
                                // Move into a new (temporary) design so that "clean" will only
                                // operate (and run checks on) this one module
                                RTLIL::Design *holes_design = new RTLIL::Design;
-                               holes_module->design->modules_.erase(holes_module->name);
+                               module->design->modules_.erase(holes_module->name);
                                holes_design->add(holes_module);
                                Pass::call(holes_design, "clean -purge");
 
                                std::stringstream a_buffer;
                                XAigerWriter writer(holes_module, true /* holes_mode */);
                                writer.write_aiger(a_buffer, false /*ascii_mode*/);
-
                                delete holes_design;
 
                                f << "a";
@@ -747,6 +916,7 @@ struct XAigerWriter
        void write_map(std::ostream &f, bool verbose_map)
        {
                dict<int, string> input_lines;
+               dict<int, string> init_lines;
                dict<int, string> output_lines;
                dict<int, string> wire_lines;
 
@@ -768,7 +938,8 @@ struct XAigerWriter
 
                                if (output_bits.count(b)) {
                                        int o = ordered_outputs.at(b);
-                                       output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), i, log_id(wire));
+                                       int init = 2;
+                                       output_lines[o] += stringf("output %d %d %s %d\n", o - GetSize(co_bits), i, log_id(wire), init);
                                        continue;
                                }
 
@@ -787,6 +958,10 @@ struct XAigerWriter
                        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));
@@ -797,6 +972,8 @@ struct XAigerWriter
                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__\n";
 
                wire_lines.sort();
                for (auto &it : wire_lines)
index cf060193d031236be9f17c3444152993dc89b1a6..9cb05dfb381caea4ada7b67b7ec3bb95bbcfb740 100644 (file)
@@ -255,7 +255,7 @@ end_of_header:
        else
                log_abort();
 
-       RTLIL::Wire* n0 = module->wire("\\__0__");
+       RTLIL::Wire* n0 = module->wire("$0");
        if (n0)
                module->connect(n0, State::S0);
 
@@ -316,14 +316,14 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera
 {
        const unsigned variable = literal >> 1;
        const bool invert = literal & 1;
-       RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : ""));
+       RTLIL::IdString wire_name(stringf("$%d%s", variable, invert ? "b" : ""));
        RTLIL::Wire *wire = module->wire(wire_name);
        if (wire) return wire;
        log_debug2("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("\\__%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;
@@ -335,7 +335,7 @@ static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned litera
        }
 
        log_debug2("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
-       module->addNotGate(stringf("\\__%d__$not", variable), wire_inv, wire);
+       module->addNotGate(stringf("$%d$not", variable), wire_inv, wire);
 
        return wire;
 }
@@ -372,108 +372,102 @@ void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup)
        else
                log_abort();
 
-       RTLIL::Wire* n0 = module->wire("\\__0__");
+       RTLIL::Wire* n0 = module->wire("$0");
        if (n0)
                module->connect(n0, State::S0);
 
+       int c = f.get();
+       if (c != 'c')
+               log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
+       if (f.peek() == '\n')
+               f.get();
+
        // 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 YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
-                               uint32_t lutNum = parse_xaiger_literal(f);
-                               uint32_t lutSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
-                               log_debug("m: dataSize=%u lutNum=%u lutSize=%u\n", dataSize, lutNum, lutSize);
-                               ConstEvalAig ce(module);
-                               for (unsigned i = 0; i < lutNum; ++i) {
-                                       uint32_t rootNodeID = parse_xaiger_literal(f);
-                                       uint32_t cutLeavesM = parse_xaiger_literal(f);
-                                       log_debug2("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_debug2("\t%u\n", nodeID);
-                                               RTLIL::Wire *wire = module->wire(stringf("\\__%d__", nodeID));
-                                               log_assert(wire);
-                                               input_sig.append(wire);
-                                       }
-                                       // TODO: Compute LUT mask from AIG in less than O(2 ** input_sig.size())
-                                       ce.clear();
-                                       ce.compute_deps(output_sig, input_sig.to_sigbit_pool());
-                                       RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << input_sig.size());
-                                       for (int j = 0; j < (1 << cutLeavesM); ++j) {
-                                               int gray = j ^ (j >> 1);
-                                               ce.set_incremental(input_sig, RTLIL::Const{gray, static_cast<int>(cutLeavesM)});
-                                               RTLIL::SigBit o(output_sig);
-                                               bool success YS_ATTRIBUTE(unused) = ce.eval(o);
-                                               log_assert(success);
-                                               log_assert(o.wire == nullptr);
-                                               lut_mask[gray] = o.data;
-                                       }
-                                       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));
+       for (int c = f.get(); c != EOF; c = f.get()) {
+               // XAIGER extensions
+               if (c == 'm') {
+                       uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+                       uint32_t lutNum = parse_xaiger_literal(f);
+                       uint32_t lutSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+                       log_debug("m: dataSize=%u lutNum=%u lutSize=%u\n", dataSize, lutNum, lutSize);
+                       ConstEvalAig ce(module);
+                       for (unsigned i = 0; i < lutNum; ++i) {
+                               uint32_t rootNodeID = parse_xaiger_literal(f);
+                               uint32_t cutLeavesM = parse_xaiger_literal(f);
+                               log_debug2("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_debug2("\t%u\n", nodeID);
+                                       RTLIL::Wire *wire = module->wire(stringf("$%d", nodeID));
+                                       log_assert(wire);
+                                       input_sig.append(wire);
                                }
-                       }
-                       else if (c == 'r') {
-                               uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
-                               flopNum = parse_xaiger_literal(f);
-                               log_debug("flopNum: %u\n", flopNum);
-                               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 YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
-                               log_assert(version == 1);
-                               uint32_t ciNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
-                               log_debug("ciNum = %u\n", ciNum);
-                               uint32_t coNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
-                               log_debug("coNum = %u\n", coNum);
-                               piNum = parse_xaiger_literal(f);
-                               log_debug("piNum = %u\n", piNum);
-                               uint32_t poNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
-                               log_debug("poNum = %u\n", poNum);
-                               uint32_t boxNum = parse_xaiger_literal(f);
-                               log_debug("boxNum = %u\n", boxNum);
-                               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);
+                               // TODO: Compute LUT mask from AIG in less than O(2 ** input_sig.size())
+                               ce.clear();
+                               ce.compute_deps(output_sig, input_sig.to_sigbit_pool());
+                               RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << input_sig.size());
+                               for (int j = 0; j < (1 << cutLeavesM); ++j) {
+                                       int gray = j ^ (j >> 1);
+                                       ce.set_incremental(input_sig, RTLIL::Const{gray, static_cast<int>(cutLeavesM)});
+                                       RTLIL::SigBit o(output_sig);
+                                       bool success YS_ATTRIBUTE(unused) = ce.eval(o);
+                                       log_assert(success);
+                                       log_assert(o.wire == nullptr);
+                                       lut_mask[gray] = o.data;
                                }
+                               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 == 'a' || c == 'i' || c == 'o') {
-                               uint32_t dataSize = parse_xaiger_literal(f);
-                               f.ignore(dataSize);
-                       }
-                       else {
-                               break;
+               }
+               else if (c == 'r') {
+                       uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+                       flopNum = parse_xaiger_literal(f);
+                       log_debug("flopNum = %u\n", flopNum);
+                       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 YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+                       log_assert(version == 1);
+                       uint32_t ciNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+                       log_debug("ciNum = %u\n", ciNum);
+                       uint32_t coNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+                       log_debug("coNum = %u\n", coNum);
+                       piNum = parse_xaiger_literal(f);
+                       log_debug("piNum = %u\n", piNum);
+                       uint32_t poNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f);
+                       log_debug("poNum = %u\n", poNum);
+                       uint32_t boxNum = parse_xaiger_literal(f);
+                       log_debug("boxNum = %u\n", boxNum);
+                       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
-                       log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
+               else if (c == 'a' || c == 'i' || c == 'o' || c == 's') {
+                       uint32_t dataSize = parse_xaiger_literal(f);
+                       f.ignore(dataSize);
+                       log_debug("ignoring '%c'\n", c);
+               }
+               else {
+                       break;
+               }
        }
 
        post_process();
@@ -550,7 +544,7 @@ void AigerReader::parse_aiger_ascii()
                log_debug2("%d is an output\n", 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::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);
@@ -616,11 +610,12 @@ void AigerReader::parse_aiger_binary()
        std::string line;
 
        // Parse inputs
+       int digits = ceil(log10(I));
        for (unsigned i = 1; i <= I; ++i) {
                log_debug2("%d is an input\n", i);
-               RTLIL::Wire *wire = createWireIfNotExists(module, i << 1);
+               RTLIL::Wire *wire = module->addWire(stringf("$i%0*d", digits, i));
                wire->port_input = true;
-               log_assert(!wire->port_output);
+               module->connect(createWireIfNotExists(module, i << 1), wire);
                inputs.push_back(wire);
        }
 
@@ -670,23 +665,15 @@ void AigerReader::parse_aiger_binary()
        }
 
        // Parse outputs
+       digits = ceil(log10(O));
        for (unsigned i = 0; i < O; ++i, ++line_count) {
                if (!(f >> l1))
                        log_error("Line %u cannot be interpreted as an output!\n", line_count);
 
                log_debug2("%d is an output\n", 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;
-               }
+               RTLIL::Wire *wire = module->addWire(stringf("$o%0*d", digits, i));
                wire->port_output = true;
+               module->connect(wire, createWireIfNotExists(module, l1));
                outputs.push_back(wire);
        }
        std::getline(f, line); // Ignore up to start of next line
@@ -734,12 +721,19 @@ void AigerReader::parse_aiger_binary()
 void AigerReader::post_process()
 {
        pool<IdString> seen_boxes;
-       unsigned ci_count = 0, co_count = 0;
+       pool<IdString> flops;
+       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);
 
+               bool is_flop = false;
                if (seen_boxes.insert(cell->type).second) {
+                       if (box_module->attributes.count("\\abc9_flop")) {
+                               log_assert(flop_count < flopNum);
+                               flops.insert(cell->type);
+                               is_flop = true;
+                       }
                        auto it = box_module->attributes.find("\\abc9_carry");
                        if (it != box_module->attributes.end()) {
                                RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr;
@@ -779,6 +773,8 @@ void AigerReader::post_process()
                                carry_out->port_id = ports.size();
                        }
                }
+               else
+                       is_flop = flops.count(cell->type);
 
                // NB: Assume box_module->ports are sorted alphabetically
                //     (as RTLIL::Module::fixup_ports() would do)
@@ -804,9 +800,32 @@ void AigerReader::post_process()
                                }
                                rhs.append(wire);
                        }
-
                        cell->setPort(port_name, rhs);
                }
+
+               if (is_flop) {
+                       log_assert(co_count < outputs.size());
+                       Wire *wire = outputs[co_count++];
+                       log_assert(wire);
+                       log_assert(wire->port_output);
+                       wire->port_output = false;
+
+                       RTLIL::Wire *d = outputs[outputs.size() - flopNum + flop_count];
+                       log_assert(d);
+                       log_assert(d->port_output);
+                       d->port_output = false;
+
+                       RTLIL::Wire *q = inputs[piNum - flopNum + flop_count];
+                       log_assert(q);
+                       log_assert(q->port_input);
+                       q->port_input = false;
+
+                       auto ff = module->addCell(NEW_ID, "$__ABC9_FF_");
+                       ff->setPort("\\D", d);
+                       ff->setPort("\\Q", q);
+                       flop_count++;
+                       continue;
+               }
        }
 
        dict<RTLIL::IdString, int> wideports_cache;
@@ -868,16 +887,7 @@ void AigerReader::post_process()
                                        // 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(1, escaped_s.size()-11));
-                                                       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);
+                                               module->rename(wire, escaped_s);
                                        }
                                        else {
                                                wire->port_output = false;
@@ -889,19 +899,9 @@ void AigerReader::post_process()
                                        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(1, escaped_s.size()-11).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);
-                                               }
+                                               module->rename(wire, indexed_name);
+                                               if (wideports)
+                                                       wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index);
                                        }
                                        else {
                                                module->connect(wire, existing);
@@ -909,9 +909,13 @@ void AigerReader::post_process()
                                        }
                                }
                                log_debug(" -> %s\n", log_id(wire));
+                               int init;
+                               mf >> init;
+                               if (init < 2)
+                                       wire->attributes["\\init"] = init;
                        }
                        else if (type == "box") {
-                               RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable));
+                               RTLIL::Cell* cell = module->cell(stringf("$__box%d", variable));
                                if (cell) { // ABC could have optimised this box away
                                        module->rename(cell, escaped_s);
                                        for (const auto &i : cell->connections()) {
@@ -968,15 +972,10 @@ void AigerReader::post_process()
                        if (other_wire) {
                                other_wire->port_input = false;
                                other_wire->port_output = false;
-                       }
-                       if (wire->port_input) {
-                               if (other_wire)
+                               if (wire->port_input)
                                        module->connect(other_wire, SigSpec(wire, i));
-                       }
-                       else {
-                                                                 // Since we skip POs that are connected to Sx,
-                                                                 // re-connect them here
-                               module->connect(SigSpec(wire, i), other_wire ? other_wire : SigSpec(RTLIL::Sx));
+                               else
+                                       module->connect(SigSpec(wire, i), other_wire);
                        }
                }
        }
index ec242aa1fa689a5bd2f3109037953c235a8c32f8..3b4f33a60fbb86ca41e214e686beb9daeb4e079c 100644 (file)
@@ -20,6 +20,7 @@
 #include "kernel/register.h"
 #include "kernel/celltypes.h"
 #include "kernel/log.h"
+#include "kernel/sigtools.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <set>
@@ -32,49 +33,56 @@ struct SubmodWorker
        CellTypes ct;
        RTLIL::Design *design;
        RTLIL::Module *module;
+       SigMap sigmap;
 
        bool copy_mode;
+       bool hidden_mode;
        std::string opt_name;
 
        struct SubModule
        {
                std::string name, full_name;
-               std::set<RTLIL::Cell*> cells;
+               pool<RTLIL::Cell*> cells;
        };
 
        std::map<std::string, SubModule> submodules;
 
        struct wire_flags_t {
                RTLIL::Wire *new_wire;
-               bool is_int_driven, is_int_used, is_ext_driven, is_ext_used;
-               wire_flags_t() : new_wire(NULL), is_int_driven(false), is_int_used(false), is_ext_driven(false), is_ext_used(false) { }
+               RTLIL::Const is_int_driven;
+               bool is_int_used, is_ext_driven, is_ext_used;
+               wire_flags_t(RTLIL::Wire* wire) : new_wire(NULL), is_int_driven(State::S0, GetSize(wire)), is_int_used(false), is_ext_driven(false), is_ext_used(false) { }
        };
        std::map<RTLIL::Wire*, wire_flags_t> wire_flags;
        bool flag_found_something;
 
-       void flag_wire(RTLIL::Wire *wire, bool create, bool set_int_driven, bool set_int_used, bool set_ext_driven, bool set_ext_used)
+       void flag_wire(RTLIL::Wire *wire, bool create, bool set_int_used, bool set_ext_driven, bool set_ext_used)
        {
                if (wire_flags.count(wire) == 0) {
                        if (!create)
                                return;
-                       wire_flags[wire] = wire_flags_t();
+                       wire_flags.emplace(wire, wire);
                }
-               if (set_int_driven)
-                       wire_flags[wire].is_int_driven = true;
                if (set_int_used)
-                       wire_flags[wire].is_int_used = true;
+                       wire_flags.at(wire).is_int_used = true;
                if (set_ext_driven)
-                       wire_flags[wire].is_ext_driven = true;
+                       wire_flags.at(wire).is_ext_driven = true;
                if (set_ext_used)
-                       wire_flags[wire].is_ext_used = true;
+                       wire_flags.at(wire).is_ext_used = true;
                flag_found_something = true;
        }
 
        void flag_signal(const RTLIL::SigSpec &sig, bool create, bool set_int_driven, bool set_int_used, bool set_ext_driven, bool set_ext_used)
        {
                for (auto &c : sig.chunks())
-                       if (c.wire != NULL)
-                               flag_wire(c.wire, create, set_int_driven, set_int_used, set_ext_driven, set_ext_used);
+                       if (c.wire != NULL) {
+                               flag_wire(c.wire, create, set_int_used, set_ext_driven, set_ext_used);
+                               if (set_int_driven)
+                                       for (int i = c.offset; i < c.offset+c.width; i++) {
+                                               wire_flags.at(c.wire).is_int_driven[i] = State::S1;
+                                               flag_found_something = true;
+                                       }
+                       }
        }
 
        void handle_submodule(SubModule &submod)
@@ -127,27 +135,39 @@ struct SubmodWorker
                                flags.is_ext_driven = true;
                        if (wire->port_output)
                                flags.is_ext_used = true;
+                       else {
+                               auto sig = sigmap(wire);
+                               for (auto c : sig.chunks())
+                                       if (c.wire && c.wire->port_output) {
+                                               flags.is_ext_used = true;
+                                               break;
+                                       }
+                       }
 
                        bool new_wire_port_input = false;
                        bool new_wire_port_output = false;
 
-                       if (flags.is_int_driven && flags.is_ext_used)
+                       if (!flags.is_int_driven.is_fully_zero() && flags.is_ext_used)
                                new_wire_port_output = true;
                        if (flags.is_ext_driven && flags.is_int_used)
                                new_wire_port_input = true;
 
-                       if (flags.is_int_driven && flags.is_ext_driven)
+                       if (!flags.is_int_driven.is_fully_zero() && flags.is_ext_driven)
                                new_wire_port_input = true, new_wire_port_output = true;
 
                        std::string new_wire_name = wire->name.str();
                        if (new_wire_port_input || new_wire_port_output) {
-                               while (new_wire_name[0] == '$') {
-                                       std::string next_wire_name = stringf("\\n%d", auto_name_counter++);
-                                       if (all_wire_names.count(next_wire_name) == 0) {
-                                               all_wire_names.insert(next_wire_name);
-                                               new_wire_name = next_wire_name;
+                               if (new_wire_name[0] == '$')
+                                       while (1) {
+                                               std::string next_wire_name = stringf("%s\\n%d", hidden_mode ? "$submod" : "", auto_name_counter++);
+                                               if (all_wire_names.count(next_wire_name) == 0) {
+                                                       all_wire_names.insert(next_wire_name);
+                                                       new_wire_name = next_wire_name;
+                                                       break;
+                                               }
                                        }
-                               }
+                               else if (hidden_mode)
+                                       new_wire_name = stringf("$submod%s", new_wire_name.c_str());
                        }
 
                        RTLIL::Wire *new_wire = new_mod->addWire(new_wire_name, wire->width);
@@ -155,6 +175,22 @@ struct SubmodWorker
                        new_wire->port_output = new_wire_port_output;
                        new_wire->start_offset = wire->start_offset;
                        new_wire->attributes = wire->attributes;
+                       if (!flags.is_int_driven.is_fully_zero()) {
+                               new_wire->attributes.erase(ID(init));
+                               auto sig = sigmap(wire);
+                               for (int i = 0; i < GetSize(sig); i++) {
+                                       if (flags.is_int_driven[i] == State::S0)
+                                               continue;
+                                       if (!sig[i].wire)
+                                               continue;
+                                       auto it = sig[i].wire->attributes.find(ID(init));
+                                       if (it != sig[i].wire->attributes.end()) {
+                                               auto jt = new_wire->attributes.insert(std::make_pair(ID(init), Const(State::Sx, GetSize(sig)))).first;
+                                               jt->second[i] = it->second[sig[i].offset];
+                                               it->second[sig[i].offset] = State::Sx;
+                                       }
+                               }
+                       }
 
                        if (new_wire->port_input && new_wire->port_output)
                                log("  signal %s: inout %s\n", wire->name.c_str(), new_wire->name.c_str());
@@ -177,7 +213,7 @@ struct SubmodWorker
                                for (auto &bit : conn.second)
                                        if (bit.wire != NULL) {
                                                log_assert(wire_flags.count(bit.wire) > 0);
-                                               bit.wire = wire_flags[bit.wire].new_wire;
+                                               bit.wire = wire_flags.at(bit.wire).new_wire;
                                        }
                        log("  cell %s (%s)\n", new_cell->name.c_str(), new_cell->type.c_str());
                        if (!copy_mode)
@@ -189,16 +225,27 @@ struct SubmodWorker
                        RTLIL::Cell *new_cell = module->addCell(submod.full_name, submod.full_name);
                        for (auto &it : wire_flags)
                        {
-                               RTLIL::Wire *old_wire = it.first;
+                               RTLIL::SigSpec old_sig = sigmap(it.first);
                                RTLIL::Wire *new_wire = it.second.new_wire;
-                               if (new_wire->port_id > 0)
-                                       new_cell->setPort(new_wire->name, RTLIL::SigSpec(old_wire));
+                               if (new_wire->port_id > 0) {
+                                       if (new_wire->port_output)
+                                               for (int i = 0; i < GetSize(old_sig); i++) {
+                                                       auto &b = old_sig[i];
+                                                       // Prevents "ERROR: Mismatch in directionality ..." when flattening
+                                                       if (!b.wire)
+                                                               b = module->addWire(NEW_ID);
+                                                       // Prevents "Warning: multiple conflicting drivers ..."
+                                                       else if (!it.second.is_int_driven[i])
+                                                               b = module->addWire(NEW_ID);
+                                               }
+                                       new_cell->setPort(new_wire->name, old_sig);
+                               }
                        }
                }
        }
 
-       SubmodWorker(RTLIL::Design *design, RTLIL::Module *module, bool copy_mode = false, std::string opt_name = std::string()) :
-                       design(design), module(module), copy_mode(copy_mode), opt_name(opt_name)
+       SubmodWorker(RTLIL::Design *design, RTLIL::Module *module, bool copy_mode = false, bool hidden_mode = false, std::string opt_name = std::string()) :
+                       design(design), module(module), sigmap(module), copy_mode(copy_mode), hidden_mode(hidden_mode), opt_name(opt_name)
        {
                if (!design->selected_whole_module(module->name) && opt_name.empty())
                        return;
@@ -219,6 +266,12 @@ struct SubmodWorker
                ct.setup_stdcells_mem();
                ct.setup_design(design);
 
+               for (auto port : module->ports) {
+                       auto wire = module->wire(port);
+                       if (wire->port_output)
+                               sigmap.add(wire);
+               }
+
                if (opt_name.empty())
                {
                        for (auto &it : module->wires_)
@@ -273,7 +326,7 @@ struct SubmodPass : public Pass {
        {
                //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
                log("\n");
-               log("    submod [-copy] [selection]\n");
+               log("    submod [options] [selection]\n");
                log("\n");
                log("This pass identifies all cells with the 'submod' attribute and moves them to\n");
                log("a newly created module. The value of the attribute is used as name for the\n");
@@ -285,16 +338,20 @@ struct SubmodPass : public Pass {
                log("This pass only operates on completely selected modules with no processes\n");
                log("or memories.\n");
                log("\n");
+               log("    -copy\n");
+               log("        by default the cells are 'moved' from the source module and the source\n");
+               log("        module will use an instance of the new module after this command is\n");
+               log("        finished. call with -copy to not modify the source module.\n");
                log("\n");
-               log("    submod -name <name> [-copy] [selection]\n");
-               log("\n");
-               log("As above, but don't use the 'submod' attribute but instead use the selection.\n");
-               log("Only objects from one module might be selected. The value of the -name option\n");
-               log("is used as the value of the 'submod' attribute above.\n");
+               log("    -name <name>\n");
+               log("        don't use the 'submod' attribute but instead use the selection. only\n");
+               log("        objects from one module might be selected. the value of the -name option\n");
+               log("        is used as the value of the 'submod' attribute instead.\n");
                log("\n");
-               log("By default the cells are 'moved' from the source module and the source module\n");
-               log("will use an instance of the new module after this command is finished. Call\n");
-               log("with -copy to not modify the source module.\n");
+               log("    -hidden\n");
+               log("        instead of creating submodule ports with public names, create ports with\n");
+               log("        private names so that a subsequent 'flatten; clean' call will restore the\n");
+               log("        original module with original public names.\n");
                log("\n");
        }
        void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -304,6 +361,7 @@ struct SubmodPass : public Pass {
 
                std::string opt_name;
                bool copy_mode = false;
+               bool hidden_mode = false;
 
                size_t argidx;
                for (argidx = 1; argidx < args.size(); argidx++) {
@@ -315,6 +373,10 @@ struct SubmodPass : public Pass {
                                copy_mode = true;
                                continue;
                        }
+                       if (args[argidx] == "-hidden") {
+                               hidden_mode = true;
+                               continue;
+                       }
                        break;
                }
                extra_args(args, argidx, design);
@@ -335,7 +397,7 @@ struct SubmodPass : public Pass {
                                                queued_modules.push_back(mod_it.first);
                                for (auto &modname : queued_modules)
                                        if (design->modules_.count(modname) != 0) {
-                                               SubmodWorker worker(design, design->modules_[modname], copy_mode);
+                                               SubmodWorker worker(design, design->modules_[modname], copy_mode, hidden_mode);
                                                handled_modules.insert(modname);
                                                did_something = true;
                                        }
@@ -358,7 +420,7 @@ struct SubmodPass : public Pass {
                        else {
                                Pass::call_on_module(design, module, "opt_clean");
                                log_header(design, "Continuing SUBMOD pass.\n");
-                               SubmodWorker worker(design, module, copy_mode, opt_name);
+                               SubmodWorker worker(design, module, copy_mode, hidden_mode, opt_name);
                        }
                }
 
index d03e5da8e8da151cbd7309e64fd7f8209258134a..def347c210d3b676763dbe66e4eae9b5b66a0262 100644 (file)
@@ -65,20 +65,15 @@ PRIVATE_NAMESPACE_BEGIN
 
 bool markgroups;
 int map_autoidx;
-SigMap assign_map;
-RTLIL::Module *module;
-
-bool clk_polarity, en_polarity;
-RTLIL::SigSpec clk_sig, en_sig;
 
 inline std::string remap_name(RTLIL::IdString abc9_name)
 {
        return stringf("$abc$%d$%s", map_autoidx, abc9_name.c_str()+1);
 }
 
-void handle_loops(RTLIL::Design *design)
+void handle_loops(RTLIL::Design *design, RTLIL::Module *module)
 {
-       Pass::call(design, "scc -set_attr abc9_scc_id {}");
+       Pass::call(design, "scc -set_attr abc9_scc_id {} % w:*");
 
        // For every unique SCC found, (arbitrarily) find the first
        // cell in the component, and select (and mark) all its output
@@ -253,49 +248,15 @@ struct abc9_output_filter
        }
 };
 
-void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file,
-               bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str,
+void abc9_module(RTLIL::Design *design, RTLIL::Module *module, std::string script_file, std::string exe_file,
+               bool cleanup, vector<int> lut_costs, bool /*dff_mode*/, std::string /*clk_str*/,
                bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode,
                bool show_tempdir, std::string box_file, std::string lut_file,
                std::string wire_delay, const dict<int,IdString> &box_lookup, bool nomfs
 )
 {
-       module = current_module;
        map_autoidx = autoidx++;
 
-       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] = '_';
@@ -360,7 +321,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                for (size_t pos = abc9_script.find("&mfs"); pos != std::string::npos; pos = abc9_script.find("&mfs", pos))
                        abc9_script = abc9_script.erase(pos, strlen("&mfs"));
 
-       abc9_script += stringf("; &write %s/output.aig", tempdir_name.c_str());
+       abc9_script += stringf("; &write -n %s/output.aig", tempdir_name.c_str());
        abc9_script = add_echos_to_abc9_cmd(abc9_script);
 
        for (size_t i = 0; i+1 < abc9_script.size(); i++)
@@ -371,39 +332,14 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
        fprintf(f, "%s\n", abc9_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");
-               }
-       }
-
-       bool count_output = false;
-       for (auto port_name : module->ports) {
-               RTLIL::Wire *port_wire = module->wire(port_name);
-               log_assert(port_wire);
-               if (port_wire->port_output) {
-                       count_output = true;
-                       break;
-               }
-       }
-
+       //bool count_output = false;
        log_push();
 
-       if (count_output)
+       //if (count_output)
        {
-               design->selection_stack.emplace_back(false);
-               RTLIL::Selection& sel = design->selection_stack.back();
-               sel.select(module);
+               handle_loops(design, module);
 
-               handle_loops(design);
-
-               Pass::call(design, "aigmap");
+               Pass::call(design, "aigmap -select");
 
                //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);
@@ -421,15 +357,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                log_assert(!design->module(ID($__abc9__)));
                {
                        AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */);
-                       reader.parse_xaiger();
+                       reader.parse_xaiger(box_lookup);
                }
                ifs.close();
-               Pass::call(design, stringf("write_verilog -noexpr -norename"));
+               Pass::call_on_module(design, design->module(ID($__abc9__)), stringf("write_verilog -noexpr -norename -selected"));
                design->remove(design->module(ID($__abc9__)));
 #endif
 
-               design->selection_stack.pop_back();
-
                log_header(design, "Executing ABC9.\n");
 
                if (!lut_costs.empty()) {
@@ -479,7 +413,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                ifs.close();
 
 #if 0
-               Pass::call(design, stringf("write_verilog -noexpr -norename"));
+               Pass::call_on_module(design, design->module(ID($__abc9__)), stringf("write_verilog -noexpr -norename -selected"));
 #endif
 
                log_header(design, "Re-integrating ABC9 results.\n");
@@ -487,33 +421,16 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                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[ID(abcgroup)] = map_autoidx;
-                       if (w->port_output) {
-                               RTLIL::Wire *wire = module->wire(w->name);
-                               log_assert(wire);
-                               for (int i = 0; i < GetSize(w); i++)
-                                       output_bits.insert({wire, i});
-                       }
-               }
-
-               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);
                }
 
                dict<IdString, bool> abc9_box;
                vector<RTLIL::Cell*> boxes;
-               for (const auto &it : module->cells_) {
-                       auto cell = it.second;
-                       if (cell->type.in(ID($_AND_), ID($_NOT_))) {
+               for (auto cell : module->selected_cells()) {
+                       if (cell->type.in(ID($_AND_), ID($_NOT_), ID($__ABC9_FF_))) {
                                module->remove(cell);
                                continue;
                        }
@@ -532,19 +449,19 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks;
 
                std::map<IdString, int> cell_stats;
-               for (auto c : mapped_mod->cells())
+               for (auto mapped_cell : mapped_mod->cells())
                {
-                       toposort.node(c->name);
+                       toposort.node(mapped_cell->name);
 
                        RTLIL::Cell *cell = nullptr;
-                       if (c->type == ID($_NOT_)) {
-                               RTLIL::SigBit a_bit = c->getPort(ID::A);
-                               RTLIL::SigBit y_bit = c->getPort(ID::Y);
-                               bit_users[a_bit].insert(c->name);
-                               bit_drivers[y_bit].insert(c->name);
+                       if (mapped_cell->type == ID($_NOT_)) {
+                               RTLIL::SigBit a_bit = mapped_cell->getPort(ID::A);
+                               RTLIL::SigBit y_bit = mapped_cell->getPort(ID::Y);
+                               bit_users[a_bit].insert(mapped_cell->name);
+                               bit_drivers[y_bit].insert(mapped_cell->name);
 
                                if (!a_bit.wire) {
-                                       c->setPort(ID::Y, module->addWire(NEW_ID));
+                                       mapped_cell->setPort(ID::Y, module->addWire(NEW_ID));
                                        RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name));
                                        log_assert(wire);
                                        module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1);
@@ -568,7 +485,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                        if (!driver_lut) {
                                                // If a driver couldn't be found (could be from PI or box CI)
                                                // then implement using a LUT
-                                               cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
+                                               cell = module->addLut(remap_name(stringf("%s$lut", mapped_cell->name.c_str())),
                                                                RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset),
                                                                RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset),
                                                                RTLIL::Const::from_string("01"));
@@ -576,7 +493,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                                cell_stats[ID($lut)]++;
                                        }
                                        else
-                                               not2drivers[c] = driver_lut;
+                                               not2drivers[mapped_cell] = driver_lut;
                                        continue;
                                }
                                else
@@ -584,24 +501,26 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
                                continue;
                        }
-                       cell_stats[c->type]++;
+                       cell_stats[mapped_cell->type]++;
 
                        RTLIL::Cell *existing_cell = nullptr;
-                       if (c->type == ID($lut)) {
-                               if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) {
-                                       SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name));
-                                       SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name));
+                       if (mapped_cell->type.in(ID($lut), ID($__ABC9_FF_))) {
+                               if (mapped_cell->type == ID($lut) &&
+                                               GetSize(mapped_cell->getPort(ID::A)) == 1 &&
+                                               mapped_cell->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) {
+                                       SigSpec my_a = module->wires_.at(remap_name(mapped_cell->getPort(ID::A).as_wire()->name));
+                                       SigSpec my_y = module->wires_.at(remap_name(mapped_cell->getPort(ID::Y).as_wire()->name));
                                        module->connect(my_y, my_a);
-                                       if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx;
+                                       if (markgroups) mapped_cell->attributes[ID(abcgroup)] = map_autoidx;
                                        log_abort();
                                        continue;
                                }
-                               cell = module->addCell(remap_name(c->name), c->type);
+                               cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
                        }
                        else {
-                               existing_cell = module->cell(c->name);
+                               existing_cell = module->cell(mapped_cell->name);
                                log_assert(existing_cell);
-                               cell = module->addCell(remap_name(c->name), c->type);
+                               cell = module->addCell(remap_name(mapped_cell->name), mapped_cell->type);
                        }
 
                        if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx;
@@ -610,10 +529,13 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                cell->attributes = existing_cell->attributes;
                        }
                        else {
-                               cell->parameters = c->parameters;
-                               cell->attributes = c->attributes;
+                               cell->parameters = mapped_cell->parameters;
+                               cell->attributes = mapped_cell->attributes;
                        }
-                       for (auto &conn : c->connections()) {
+
+                       RTLIL::Module* box_module = design->module(mapped_cell->type);
+                       auto abc9_flop = box_module && box_module->attributes.count("\\abc9_flop");
+                       for (auto &conn : mapped_cell->connections()) {
                                RTLIL::SigSpec newsig;
                                for (auto c : conn.second.chunks()) {
                                        if (c.width == 0)
@@ -625,15 +547,17 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                }
                                cell->setPort(conn.first, newsig);
 
-                               if (cell->input(conn.first)) {
-                                       for (auto i : newsig)
-                                               bit2sinks[i].push_back(cell);
-                                       for (auto i : conn.second)
-                                               bit_users[i].insert(c->name);
+                               if (!abc9_flop) {
+                                       if (cell->input(conn.first)) {
+                                               for (auto i : newsig)
+                                                       bit2sinks[i].push_back(cell);
+                                               for (auto i : conn.second)
+                                                       bit_users[i].insert(mapped_cell->name);
+                                       }
+                                       if (cell->output(conn.first))
+                                               for (auto i : conn.second)
+                                                       bit_drivers[i].insert(mapped_cell->name);
                                }
-                               if (cell->output(conn.first))
-                                       for (auto i : conn.second)
-                                               bit_drivers[i].insert(c->name);
                        }
                }
 
@@ -798,10 +722,10 @@ clone_lut:
 
                design->remove(mapped_mod);
        }
-       else
-       {
-               log("Don't call ABC as there is nothing to map.\n");
-       }
+       //else
+       //{
+       //      log("Don't call ABC as there is nothing to map.\n");
+       //}
 
        if (cleanup)
        {
@@ -914,8 +838,17 @@ struct Abc9Pass : public Pass {
                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 then load that into ABC externally if\n");
-               log("you want to use ABC to convert your design into another format.\n");
+               log("design as an XAIGER file with write_xaiger and then load that into ABC externally\n");
+               log("if you want to use ABC to convert your design into another format.\n");
+               log("\n");
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("Delay targets can also be specified on a per clock basis by attaching a\n");
+               log("'(* abc9_period = <int> *)' attribute onto clock wires (specifically, onto wires\n");
+               log("that appear inside any special '$abc9_clock' wires inserted by abc9_map.v). This\n");
+               log("can be achieved by modifying the source directly, or through a `setattr`\n");
+               log("invocation. Since such attributes cannot yet be propagated through a\n");
+               log("hierarchical design (whether or not it has been uniquified) it is recommended\n");
+               log("that the design be flattened when using this feature.\n");
                log("\n");
                log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
                log("\n");
@@ -925,8 +858,6 @@ struct Abc9Pass : public Pass {
                log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n");
                log_push();
 
-               assign_map.clear();
-
 #ifdef ABCEXTERNAL
                std::string exe_file = ABCEXTERNAL;
 #else
@@ -934,7 +865,7 @@ struct Abc9Pass : public Pass {
 #endif
                std::string script_file, clk_str, box_file, lut_file;
                std::string delay_target, lutin_shared = "-S 1", wire_delay;
-               bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
+               bool fast_mode = false, /*dff_mode = false,*/ keepff = false, cleanup = true;
                bool show_tempdir = false;
                bool nomfs = false;
                vector<int> lut_costs;
@@ -1135,48 +1066,37 @@ struct Abc9Pass : public Pass {
                        }
                }
 
-               for (auto mod : design->selected_modules())
+               SigMap assign_map;
+               CellTypes ct(design);
+               for (auto module : design->selected_modules())
                {
-                       if (mod->attributes.count(ID(abc9_box_id)))
-                               continue;
-
-                       if (mod->processes.size() > 0) {
-                               log("Skipping module %s as it contains processes.\n", log_id(mod));
+                       if (module->attributes.count(ID(abc9_box_id)))
                                continue;
-                       }
-
-                       assign_map.set(mod);
 
-                       if (!dff_mode || !clk_str.empty()) {
-                               abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff,
-                                               delay_target, lutin_shared, fast_mode, show_tempdir,
-                                               box_file, lut_file, wire_delay, box_lookup, nomfs);
+                       if (module->processes.size() > 0) {
+                               log("Skipping module %s as it contains processes.\n", log_id(module));
                                continue;
                        }
 
-                       CellTypes ct(design);
+                       assign_map.set(module);
 
-                       std::vector<RTLIL::Cell*> all_cells = mod->selected_cells();
-                       std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end());
+                       std::vector<RTLIL::Cell*> all_cells = module->selected_cells();
+                       pool<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;
+                       pool<RTLIL::Cell*> expand_queue, next_expand_queue;
+                       pool<RTLIL::Cell*> expand_queue_up, next_expand_queue_up;
+                       pool<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;
+                       typedef SigSpec clkdomain_t;
+                       std::map<clkdomain_t, pool<RTLIL::IdString>> 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;
+                       std::map<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down;
+                       std::map<RTLIL::SigBit, pool<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);
+                               for (auto bit : assign_map(conn.second))
                                        if (bit.wire != nullptr) {
                                                cell_to_bit[cell].insert(bit);
                                                bit_to_cell[bit].insert(cell);
@@ -1189,29 +1109,59 @@ struct Abc9Pass : public Pass {
                                                        bit_to_cell_up[bit].insert(cell);
                                                }
                                        }
-                               }
 
-                               if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
-                               {
-                                       key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec());
-                               }
-                               else
-                               if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
-                               {
-                                       bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_));
-                                       bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_));
-                                       key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID(C))), this_en_pol, assign_map(cell->getPort(ID(E))));
-                               }
-                               else
+                       for (auto cell : all_cells) {
+                               auto inst_module = design->module(cell->type);
+                               if (!inst_module || !inst_module->attributes.count("\\abc9_flop"))
                                        continue;
 
+                               Wire *abc9_clock_wire = module->wire(stringf("%s.$abc9_clock", cell->name.c_str()));
+                               if (abc9_clock_wire == NULL)
+                                       log_error("'%s$abc9_clock' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
+                               SigSpec abc9_clock = assign_map(abc9_clock_wire);
+
                                unassigned_cells.erase(cell);
-                               expand_queue.insert(cell);
                                expand_queue_up.insert(cell);
-                               expand_queue_down.insert(cell);
-
-                               assigned_cells[key].push_back(cell);
+                               clkdomain_t key(abc9_clock);
+                               assigned_cells[key].insert(cell->name);
                                assigned_cells_reverse[cell] = key;
+
+                               auto YS_ATTRIBUTE(unused) r2 = cell->attributes.insert(std::make_pair(ID(abc9_mergeability), 1));
+                               log_assert(r2.second);
+
+                               Wire *abc9_init_wire = module->wire(stringf("%s.$abc9_init", cell->name.c_str()));
+                               if (abc9_init_wire == NULL)
+                                   log_error("'%s.$abc9_init' is not a wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
+                               log_assert(GetSize(abc9_init_wire) == 1);
+                               SigSpec abc9_init = assign_map(abc9_init_wire);
+                               if (!abc9_init.is_fully_const())
+                                   log_error("'%s.$abc9_init' is not a constant wire present in module '%s'.\n", cell->name.c_str(), log_id(module));
+                               r2 = cell->attributes.insert(std::make_pair(ID(abc9_init), abc9_init.as_const()));
+                               log_assert(r2.second);
+
+                               // Also assign these special ABC9 cells to the
+                               //   same clock domain
+                               for (auto b : cell_to_bit_down[cell])
+                               for (auto c : bit_to_cell_down[b])
+                                       if (c->type == "$__ABC9_FF_") {
+                                               cell = c;
+                                               unassigned_cells.erase(cell);
+                                               assigned_cells[key].insert(cell->name);
+                                               assigned_cells_reverse[cell] = key;
+                                               break;
+                                       }
+                               for (auto b : cell_to_bit_down[cell])
+                               for (auto c : bit_to_cell_down[b])
+                                       if (c->type == "$__ABC9_ASYNC") {
+                                               cell = c;
+                                               unassigned_cells.erase(cell);
+                                               assigned_cells[key].insert(cell->name);
+                                               assigned_cells_reverse[cell] = key;
+                                               break;
+                                       }
+
+                               expand_queue.insert(cell);
+                               expand_queue_down.insert(cell);
                        }
 
                        while (!expand_queue_up.empty() || !expand_queue_down.empty())
@@ -1219,7 +1169,7 @@ struct Abc9Pass : public Pass {
                                if (!expand_queue_up.empty())
                                {
                                        RTLIL::Cell *cell = *expand_queue_up.begin();
-                                       clkdomain_t key = assigned_cells_reverse.at(cell);
+                                       auto key = assigned_cells_reverse.at(cell);
                                        expand_queue_up.erase(cell);
 
                                        for (auto bit : cell_to_bit_up[cell])
@@ -1227,7 +1177,7 @@ struct Abc9Pass : public Pass {
                                                if (unassigned_cells.count(c)) {
                                                        unassigned_cells.erase(c);
                                                        next_expand_queue_up.insert(c);
-                                                       assigned_cells[key].push_back(c);
+                                                       assigned_cells[key].insert(c->name);
                                                        assigned_cells_reverse[c] = key;
                                                        expand_queue.insert(c);
                                                }
@@ -1236,7 +1186,7 @@ struct Abc9Pass : public Pass {
                                if (!expand_queue_down.empty())
                                {
                                        RTLIL::Cell *cell = *expand_queue_down.begin();
-                                       clkdomain_t key = assigned_cells_reverse.at(cell);
+                                       auto key = assigned_cells_reverse.at(cell);
                                        expand_queue_down.erase(cell);
 
                                        for (auto bit : cell_to_bit_down[cell])
@@ -1244,7 +1194,7 @@ struct Abc9Pass : public Pass {
                                                if (unassigned_cells.count(c)) {
                                                        unassigned_cells.erase(c);
                                                        next_expand_queue_up.insert(c);
-                                                       assigned_cells[key].push_back(c);
+                                                       assigned_cells[key].insert(c->name);
                                                        assigned_cells_reverse[c] = key;
                                                        expand_queue.insert(c);
                                                }
@@ -1259,7 +1209,7 @@ struct Abc9Pass : public Pass {
                        while (!expand_queue.empty())
                        {
                                RTLIL::Cell *cell = *expand_queue.begin();
-                               clkdomain_t key = assigned_cells_reverse.at(cell);
+                               auto key = assigned_cells_reverse.at(cell);
                                expand_queue.erase(cell);
 
                                for (auto bit : cell_to_bit.at(cell)) {
@@ -1267,7 +1217,7 @@ struct Abc9Pass : public Pass {
                                                if (unassigned_cells.count(c)) {
                                                        unassigned_cells.erase(c);
                                                        next_expand_queue.insert(c);
-                                                       assigned_cells[key].push_back(c);
+                                                       assigned_cells[key].insert(c->name);
                                                        assigned_cells_reverse[c] = key;
                                                }
                                        bit_to_cell[bit].clear();
@@ -1277,32 +1227,42 @@ struct Abc9Pass : public Pass {
                                        expand_queue.swap(next_expand_queue);
                        }
 
-                       clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec());
+                       clkdomain_t key;
                        for (auto cell : unassigned_cells) {
-                               assigned_cells[key].push_back(cell);
+                               assigned_cells[key].insert(cell->name);
                                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)));
+                               log("  %d cells in clk=%s\n", GetSize(it.second), log_signal(it.first));
 
+                       design->selection_stack.emplace_back(false);
+                       design->selected_active_module = module->name.str();
                        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, cleanup, lut_costs, !clk_sig.empty(), "$",
-                                               keepff, delay_target, lutin_shared, fast_mode, show_tempdir,
+                               std::string target = delay_target;
+                               if (target.empty()) {
+                                       for (auto b : assign_map(it.first))
+                                               if (b.wire) {
+                                                       auto jt = b.wire->attributes.find("\\abc9_period");
+                                                       if (jt != b.wire->attributes.end()) {
+                                                               target = stringf("-D %d", jt->second.as_int());
+                                                               log("Target period = %s ps for clock domain %s\n", target.c_str(), log_signal(it.first));
+                                                               break;
+                                                       }
+                                               }
+                               }
+                               RTLIL::Selection& sel = design->selection_stack.back();
+                               sel.selected_members[module->name] = std::move(it.second);
+                               abc9_module(design, module, script_file, exe_file, cleanup, lut_costs, false, "$",
+                                               keepff, target, lutin_shared, fast_mode, show_tempdir,
                                                box_file, lut_file, wire_delay, box_lookup, nomfs);
-                               assign_map.set(mod);
+                               assign_map.set(module);
                        }
+                       design->selection_stack.pop_back();
+                       design->selected_active_module.clear();
                }
 
-               assign_map.clear();
-
                log_pop();
        }
 } Abc9Pass;
index 7b9427b2fcc1cae9b1fe377d770d75efee371df5..d2d7d9114a75111a511751971170ed2cb9e67076 100644 (file)
  *
  */
 
-// ============================================================================
+// The following techmapping rules are intended to be run (with -max_iter 1)
+//   before invoking the `abc9` pass in order to transform the design into
+//   a format that it understands.
+//
+// For example, (complex) flip-flops are expected to be described as an
+//   combinatorial box (containing all control logic such as clock enable
+//   or synchronous resets) followed by a basic D-Q flop.
+// Yosys will automatically analyse the simulation model (described in
+//   cells_sim.v) and detach any $_DFF_P_ or $_DFF_N_ cells present in
+//   order to extract the combinatorial control logic left behind.
+//   Specifically, a simulation model similar to the one below:
+//
+//                ++===================================++
+//                ||                        Sim model  ||
+//                ||      /\/\/\/\                     ||
+//            D -->>-----<        >     +------+       ||
+//            R -->>-----<  Comb. >     |$_DFF_|       ||
+//           CE -->>-----<  logic >-----| [NP]_|---+---->>-- Q
+//                ||  +--<        >     +------+   |   ||
+//                ||  |   \/\/\/\/                 |   ||
+//                ||  |                            |   ||
+//                ||  +----------------------------+   ||
+//                ||                                   ||
+//                ++===================================++
+//
+//   is transformed into:
+//
+//                ++==================++
+//                ||         Comb box ||
+//                ||                  ||
+//                ||      /\/\/\/\    ||
+//           D  -->>-----<        >   ||            +------+
+//           R  -->>-----<  Comb. >   ||            |$__ABC|
+//          CE  -->>-----<  logic >--->>-- $nextQ --| _FF_ |--+-->> Q
+// $abc9_currQ +-->>-----<        >   ||            +------+  |
+//             |  ||      \/\/\/\/    ||                      |
+//             |  ||                  ||                      |
+//             |  ++==================++                      |
+//             |                                              |
+//             +----------------------------------------------+
+//
+// The purpose of the following FD* rules are to wrap the flop with:
+// (a) a special $__ABC9_FF_ in front of the FD*'s output, indicating to abc9
+//     the connectivity of its basic D-Q flop
+// (b) an optional $__ABC9_ASYNC_ cell in front of $__ABC_FF_'s output to
+//     capture asynchronous behaviour
+// (c) a special _TECHMAP_REPLACE_.$abc9_clock wire to capture its clock
+//     domain and polarity (used when partitioning the module so that `abc9' only
+//     performs sequential synthesis (with reachability analysis) correctly on
+//     one domain at a time) and also used to infer the optional delay target
+//     from the (* abc9_clock_period = %d *) attribute attached to any wire
+//     within
+// (d) a special _TECHMAP_REPLACE_.$abc9_init wire to encode the flop's initial
+//     state
+// (e) a special _TECHMAP_REPLACE_.$abc9_currQ wire that will be used for feedback
+//     into the (combinatorial) FD* cell to facilitate clock-enable behaviour
+//
+// In order to perform sequential synthesis, `abc9' also requires that
+// the initial value of all flops be zero.
+
+module FDRE (output 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;
+  parameter [0:0] IS_R_INVERTED = 1'b0;
+  wire QQ, $nextQ;
+  generate if (INIT == 1'b1) begin
+    assign Q = ~QQ;
+    FDSE #(
+      .INIT(1'b0),
+      .IS_C_INVERTED(IS_C_INVERTED),
+      .IS_D_INVERTED(IS_D_INVERTED),
+      .IS_S_INVERTED(IS_R_INVERTED)
+    ) _TECHMAP_REPLACE_ (
+      .D(~D), .Q($nextQ), .C(C), .CE(CE), .S(R)
+    );
+  end
+  else begin
+    assign Q = QQ;
+    FDRE #(
+      .INIT(1'b0),
+      .IS_C_INVERTED(IS_C_INVERTED),
+      .IS_D_INVERTED(IS_D_INVERTED),
+      .IS_R_INVERTED(IS_R_INVERTED)
+    ) _TECHMAP_REPLACE_ (
+      .D(D), .Q($nextQ), .C(C), .CE(CE), .R(R)
+    );
+  end
+  endgenerate
+  \$__ABC9_FF_ abc_dff (.D($nextQ), .Q(QQ));
+
+  // Special signals
+  wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, IS_C_INVERTED};
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = QQ;
+endmodule
+module FDRE_1 (output Q, input C, CE, D, R);
+  parameter [0:0] INIT = 1'b0;
+  wire QQ, $nextQ;
+  generate if (INIT == 1'b1) begin
+    assign Q = ~QQ;
+    FDSE_1 #(
+      .INIT(1'b0)
+    ) _TECHMAP_REPLACE_ (
+      .D(~D), .Q($nextQ), .C(C), .CE(CE), .S(R)
+    );
+  end
+  else begin
+    assign Q = QQ;
+    FDRE_1 #(
+      .INIT(1'b0)
+    ) _TECHMAP_REPLACE_ (
+      .D(D), .Q($nextQ), .C(C), .CE(CE), .R(R)
+    );
+  end
+  endgenerate
+  \$__ABC9_FF_ abc_dff (.D($nextQ), .Q(QQ));
+
+  // Special signals
+  wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, 1'b1 /* IS_C_INVERTED */};
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = QQ;
+endmodule
+
+module FDCE (output 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;
+  parameter [0:0] IS_CLR_INVERTED = 1'b0;
+  wire QQ, $nextQ, $abc9_currQ;
+  generate if (INIT == 1'b1) begin
+    assign Q = ~QQ;
+    FDPE #(
+      .INIT(1'b0),
+      .IS_C_INVERTED(IS_C_INVERTED),
+      .IS_D_INVERTED(IS_D_INVERTED),
+      .IS_PRE_INVERTED(IS_CLR_INVERTED)
+    ) _TECHMAP_REPLACE_ (
+      .D(~D), .Q($nextQ), .C(C), .CE(CE), .PRE(CLR)
+                                            // ^^^ Note that async
+                                            //     control is not directly
+                                            //     supported by abc9 but its
+                                            //     behaviour is captured by
+                                            //     $__ABC9_ASYNC1 below
+    );
+    // Since this is an async flop, async behaviour is dealt with here
+    \$__ABC9_ASYNC0 abc_async (.A($abc9_currQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ));
+  end
+  else begin
+    assign Q = QQ;
+    FDCE #(
+      .INIT(1'b0),
+      .IS_C_INVERTED(IS_C_INVERTED),
+      .IS_D_INVERTED(IS_D_INVERTED),
+      .IS_CLR_INVERTED(IS_CLR_INVERTED)
+    ) _TECHMAP_REPLACE_ (
+      .D(D), .Q($nextQ), .C(C), .CE(CE), .CLR(CLR)
+                                           // ^^^ Note that async
+                                           //     control is not directly
+                                           //     supported by abc9 but its
+                                           //     behaviour is captured by
+                                           //     $__ABC9_ASYNC0 below
+    );
+    // Since this is an async flop, async behaviour is dealt with here
+    \$__ABC9_ASYNC1 abc_async (.A($abc9_currQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ));
+  end endgenerate
+  \$__ABC9_FF_ abc_dff (.D($nextQ), .Q($abc9_currQ));
+
+  // Special signals
+  wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, IS_C_INVERTED};
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = $abc9_currQ;
+endmodule
+module FDCE_1 (output Q, input C, CE, D, CLR);
+  parameter [0:0] INIT = 1'b0;
+  wire QQ, $nextQ, $abc9_currQ;
+  generate if (INIT == 1'b1) begin
+    assign Q = ~QQ;
+    FDPE_1 #(
+      .INIT(1'b0)
+    ) _TECHMAP_REPLACE_ (
+      .D(~D), .Q($nextQ), .C(C), .CE(CE), .PRE(CLR)
+                                            // ^^^ Note that async
+                                            //     control is not directly
+                                            //     supported by abc9 but its
+                                            //     behaviour is captured by
+                                            //     $__ABC9_ASYNC1 below
+    );
+    \$__ABC9_ASYNC1 abc_async (.A($abc9_currQ), .S(CLR), .Y(QQ));
+  end
+  else begin
+    assign Q = QQ;
+    FDCE_1 #(
+      .INIT(1'b0)
+    ) _TECHMAP_REPLACE_ (
+      .D(D), .Q($nextQ), .C(C), .CE(CE), .CLR(CLR)
+                                           // ^^^ Note that async
+                                           //     control is not directly
+                                           //     supported by abc9 but its
+                                           //     behaviour is captured by
+                                           //     $__ABC9_ASYNC0 below
+    );
+    \$__ABC9_ASYNC0 abc_async (.A($abc9_currQ), .S(CLR), .Y(QQ));
+  end endgenerate
+  \$__ABC9_FF_ abc_dff (.D($nextQ), .Q($abc9_currQ));
+
+  // Special signals
+  wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, 1'b1 /* IS_C_INVERTED */};
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = $abc9_currQ;
+endmodule
+
+module FDPE (output Q, input C, CE, D, PRE);
+  parameter [0:0] INIT = 1'b1;
+  parameter [0:0] IS_C_INVERTED = 1'b0;
+  parameter [0:0] IS_D_INVERTED = 1'b0;
+  parameter [0:0] IS_PRE_INVERTED = 1'b0;
+  wire QQ, $nextQ, $abc9_currQ;
+  generate if (INIT == 1'b1) begin
+    assign Q = ~QQ;
+    FDCE #(
+      .INIT(1'b0),
+      .IS_C_INVERTED(IS_C_INVERTED),
+      .IS_D_INVERTED(IS_D_INVERTED),
+      .IS_CLR_INVERTED(IS_PRE_INVERTED),
+    ) _TECHMAP_REPLACE_ (
+      .D(~D), .Q($nextQ), .C(C), .CE(CE), .CLR(PRE)
+                                            // ^^^ Note that async
+                                            //     control is not directly
+                                            //     supported by abc9 but its
+                                            //     behaviour is captured by
+                                            //     $__ABC9_ASYNC0 below
+    );
+    \$__ABC9_ASYNC0 abc_async (.A($abc9_currQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ));
+  end
+  else begin
+    assign Q = QQ;
+    FDPE #(
+      .INIT(1'b0),
+      .IS_C_INVERTED(IS_C_INVERTED),
+      .IS_D_INVERTED(IS_D_INVERTED),
+      .IS_PRE_INVERTED(IS_PRE_INVERTED),
+    ) _TECHMAP_REPLACE_ (
+      .D(D), .Q($nextQ), .C(C), .CE(CE), .PRE(PRE)
+                                           // ^^^ Note that async
+                                           //     control is not directly
+                                           //     supported by abc9 but its
+                                           //     behaviour is captured by
+                                           //     $__ABC9_ASYNC1 below
+    );
+    \$__ABC9_ASYNC1 abc_async (.A($abc9_currQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ));
+  end endgenerate
+  \$__ABC9_FF_ abc_dff (.D($nextQ), .Q($abc9_currQ));
+
+  // Special signals
+  wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, IS_C_INVERTED};
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = $abc9_currQ;
+endmodule
+module FDPE_1 (output Q, input C, CE, D, PRE);
+  parameter [0:0] INIT = 1'b1;
+  wire QQ, $nextQ, $abc9_currQ;
+  generate if (INIT == 1'b1) begin
+    assign Q = ~QQ;
+    FDCE_1 #(
+      .INIT(1'b0)
+    ) _TECHMAP_REPLACE_ (
+      .D(~D), .Q($nextQ), .C(C), .CE(CE), .CLR(PRE)
+                                            // ^^^ Note that async
+                                            //     control is not directly
+                                            //     supported by abc9 but its
+                                            //     behaviour is captured by
+                                            //     $__ABC9_ASYNC0 below
+    );
+    \$__ABC9_ASYNC0 abc_async (.A($abc9_currQ), .S(PRE), .Y(QQ));
+  end
+  else begin
+    assign Q = QQ;
+    FDPE_1 #(
+      .INIT(1'b0)
+    ) _TECHMAP_REPLACE_ (
+      .D(D), .Q($nextQ), .C(C), .CE(CE), .PRE(PRE)
+                                           // ^^^ Note that async
+                                           //     control is not directly
+                                           //     supported by abc9 but its
+                                           //     behaviour is captured by
+                                           //     $__ABC9_ASYNC1 below
+    );
+    \$__ABC9_ASYNC1 abc_async (.A($abc9_currQ), .S(PRE), .Y(QQ));
+  end endgenerate
+  \$__ABC9_FF_ abc_dff (.D($nextQ), .Q($abc9_currQ));
+
+  // Special signals
+  wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, 1'b1 /* IS_C_INVERTED */};
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = $abc9_currQ;
+endmodule
+
+module FDSE (output Q, input C, CE, D, S);
+  parameter [0:0] INIT = 1'b1;
+  parameter [0:0] IS_C_INVERTED = 1'b0;
+  parameter [0:0] IS_D_INVERTED = 1'b0;
+  parameter [0:0] IS_S_INVERTED = 1'b0;
+  wire QQ, $nextQ;
+  generate if (INIT == 1'b1) begin
+    assign Q = ~QQ;
+    FDRE #(
+      .INIT(1'b0),
+      .IS_C_INVERTED(IS_C_INVERTED),
+      .IS_D_INVERTED(IS_D_INVERTED),
+      .IS_R_INVERTED(IS_S_INVERTED)
+    ) _TECHMAP_REPLACE_ (
+      .D(~D), .Q($nextQ), .C(C), .CE(CE), .R(S)
+    );
+  end
+  else begin
+    assign Q = QQ;
+    FDSE #(
+      .INIT(1'b0),
+      .IS_C_INVERTED(IS_C_INVERTED),
+      .IS_D_INVERTED(IS_D_INVERTED),
+      .IS_S_INVERTED(IS_S_INVERTED)
+    ) _TECHMAP_REPLACE_ (
+      .D(D), .Q($nextQ), .C(C), .CE(CE), .S(S)
+    );
+  end endgenerate
+  \$__ABC9_FF_ abc_dff (.D($nextQ), .Q(QQ));
+
+  // Special signals
+  wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, IS_C_INVERTED};
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = QQ;
+endmodule
+module FDSE_1 (output Q, input C, CE, D, S);
+  parameter [0:0] INIT = 1'b1;
+  wire QQ, $nextQ;
+  generate if (INIT == 1'b1) begin
+    assign Q = ~QQ;
+    FDRE_1 #(
+      .INIT(1'b0)
+    ) _TECHMAP_REPLACE_ (
+      .D(~D), .Q($nextQ), .C(C), .CE(CE), .R(S)
+    );
+  end
+  else begin
+    assign Q = QQ;
+    FDSE_1 #(
+      .INIT(1'b0)
+    ) _TECHMAP_REPLACE_ (
+      .D(D), .Q($nextQ), .C(C), .CE(CE), .S(S)
+    );
+  end endgenerate
+  \$__ABC9_FF_ abc_dff (.D($nextQ), .Q(QQ));
+
+  // Special signals
+  wire [1:0] _TECHMAP_REPLACE_.$abc9_clock = {C, 1'b1 /* IS_C_INVERTED */};
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_init = 1'b0;
+  wire [0:0] _TECHMAP_REPLACE_.$abc9_currQ = QQ;
+endmodule
 
 module RAM32X1D (
   output DPO, SPO,
index 8c8e1556c5590a256e64ab9692cc77385293f671..c793396a4bc9be5f9c921a9fcaee566cee844f02 100644 (file)
@@ -30,7 +30,22 @@ module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1);
                 : (S0 ? I1 : I0);
 endmodule
 
-// Box to emulate comb/seq behaviour of RAMD{32,64} and SRL{16,32}
+module \$__ABC9_FF_ (input D, output Q);
+endmodule
+
+// Box to emulate async behaviour of FDC*
+(* abc_box_id = 1000 *)
+module \$__ABC9_ASYNC0 (input A, S, output Y);
+  assign Y = S ? 1'b0 : A;
+endmodule
+
+// Box to emulate async behaviour of FDP*
+(* abc_box_id = 1001 *)
+module \$__ABC9_ASYNC1 (input A, S, output Y);
+  assign Y = S ? 1'b0 : A;
+endmodule
+
+// Box to emulate comb/seq behaviour of RAM{32,64} and SRL{16,32}
 //   Necessary since RAMD* and SRL* have both combinatorial (i.e.
 //   same-cycle read operation) and sequential (write operation
 //   is only committed on the next clock edge).
@@ -39,7 +54,7 @@ endmodule
 (* abc9_box_id=2000 *)
 module \$__ABC9_LUT6 (input A, input [5:0] S, output Y);
 endmodule
-// Box to emulate comb/seq behaviour of RAMD128
+// Box to emulate comb/seq behaviour of RAM128
 (* abc9_box_id=2001 *)
 module \$__ABC9_LUT7 (input A, input [6:0] S, output Y);
 endmodule
index ad6469702efe683070850cc4b4130c0fee1e2a44..46526007d61a822dd47f1ec33e018050226468bd 100644 (file)
 
 // ============================================================================
 
+(* techmap_celltype = "$__ABC9_ASYNC0 $__ABC9_ASYNC1" *)
+module \$__ABC9_ASYNC01 (input A, S, output Y);
+  assign Y = A;
+endmodule
+
+module \$__ABC9_FF_ (input D, output Q);
+  assign Q = D;
+endmodule
+
 module \$__ABC9_LUT6 (input A, input [5:0] S, output Y);
   assign Y = A;
 endmodule
index 774388d495cd94d9d2e5a9571b2b71c9f2bd1a58..a2d119284368035cf635d9a5df32f321f48d0958 100644 (file)
@@ -41,6 +41,63 @@ CARRY4 4 1 10 8
 592 540 520 356 -   512 548 292 -   228
 580 526 507 398 385 508 528 378 380 114
 
+# Box to emulate async behaviour of FDC*
+# Inputs: A S
+# Outputs: Y
+$__ABC9_ASYNC0 1000 1 2 1
+0 764
+
+# Box to emulate async behaviour of FDP*
+# Inputs: A S
+# Outputs: Y
+$__ABC9_ASYNC1 1001 1 2 1
+0 764
+
+# The following FD*.{CE,R,CLR,PRE) are offset by 46ps to
+# reflect the -46ps Tsu
+# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L237-L251
+# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L265-L277
+
+# Inputs: C CE D R \$currQ
+# Outputs: Q
+FDRE 1100 1 5 1
+0 151 0 446 0
+
+# Inputs: C CE D R \$currQ
+# Outputs: Q
+FDRE_1 1101 1 5 1
+0 151 0 446 0
+
+# Inputs: C CE CLR D \$currQ
+# Outputs: Q
+FDCE 1102 1 5 1
+0 151 806 0 0
+
+# Inputs: C CE CLR D \$currQ
+# Outputs: Q
+FDCE_1 1103 1 5 1
+0 151 806 0 0
+
+# Inputs: C CE D PRE \$currQ
+# Outputs: Q
+FDPE 1104 1 5 1
+0 151 0 806 0
+
+# Inputs: C CE D PRE \$currQ
+# Outputs: Q
+FDPE_1 1105 1 5 1
+0 151 0 806 0
+
+# Inputs: C CE D S \$currQ
+# Outputs: Q
+FDSE 1106 1 5 1
+0 151 0 446 0
+
+# Inputs: C CE D S \$currQ
+# Outputs: Q
+FDSE_1 1107 1 5 1
+0 151 0 446 0
+
 # SLICEM/A6LUT
 # Box to emulate comb/seq behaviour of RAMD{32,64} and SRL{16,32}
 #   Necessary since RAMD* and SRL* have both combinatorial (i.e.
@@ -56,7 +113,7 @@ $__ABC9_LUT6 2000 0 7 1
 # SLICEM/A6LUT + F7BMUX
 # Box to emulate comb/seq behaviour of RAMD128
 # Inputs: A S0 S1 S2 S3 S4 S5 S6
-# Outputs: DPO SPO
+# Outputs: Y
 $__ABC9_LUT7 2001 0 8 1
 0 1047 1036 877 812 643 532 478
 
index 47ba794bf60da847c9d94d18da991e13e26330a9..5d589bd2fda89c5159a84b0c160b989776349d77 100644 (file)
@@ -325,6 +325,7 @@ endmodule
 
 // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250
 
+(* abc9_box_id=1100, lib_whitebox, abc9_flop *)
 module FDRE (
   (* abc9_arrival=303 *)
   output reg Q,
@@ -348,27 +349,17 @@ module FDRE (
   endcase endgenerate
 endmodule
 
-module FDSE (
+(* abc9_box_id=1101, lib_whitebox, abc9_flop *)
+module FDRE_1 (
   (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
-  (* invertible_pin = "IS_C_INVERTED" *)
   input C,
-  input CE,
-  (* invertible_pin = "IS_D_INVERTED" *)
-  input D,
-  (* invertible_pin = "IS_S_INVERTED" *)
-  input S
+  input CE, D, R
 );
-  parameter [0:0] INIT = 1'b1;
-  parameter [0:0] IS_C_INVERTED = 1'b0;
-  parameter [0:0] IS_D_INVERTED = 1'b0;
-  parameter [0:0] IS_S_INVERTED = 1'b0;
+  parameter [0:0] INIT = 1'b0;
   initial Q <= INIT;
-  generate case (|IS_C_INVERTED)
-    1'b0: always @(posedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
-    1'b1: always @(negedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
-  endcase endgenerate
+  always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D;
 endmodule
 
 module FDRSE (
@@ -406,6 +397,7 @@ module FDRSE (
       Q <= d;
 endmodule
 
+(* abc9_box_id=1102, lib_whitebox, abc9_flop *)
 module FDCE (
   (* abc9_arrival=303 *)
   output reg Q,
@@ -431,29 +423,17 @@ module FDCE (
   endcase endgenerate
 endmodule
 
-module FDPE (
+(* abc9_box_id=1103, lib_whitebox, abc9_flop *)
+module FDCE_1 (
   (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
-  (* invertible_pin = "IS_C_INVERTED" *)
   input C,
-  input CE,
-  (* invertible_pin = "IS_D_INVERTED" *)
-  input D,
-  (* invertible_pin = "IS_PRE_INVERTED" *)
-  input PRE
+  input CE, D, CLR
 );
-  parameter [0:0] INIT = 1'b1;
-  parameter [0:0] IS_C_INVERTED = 1'b0;
-  parameter [0:0] IS_D_INVERTED = 1'b0;
-  parameter [0:0] IS_PRE_INVERTED = 1'b0;
+  parameter [0:0] INIT = 1'b0;
   initial Q <= INIT;
-  generate case ({|IS_C_INVERTED, |IS_PRE_INVERTED})
-    2'b00: always @(posedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
-    2'b01: always @(posedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
-    2'b10: always @(negedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
-    2'b11: always @(negedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
-  endcase endgenerate
+  always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
 endmodule
 
 module FDCPE (
@@ -501,52 +481,80 @@ module FDCPE (
   assign Q = qs ? qp : qc;
 endmodule
 
-module FDRE_1 (
+(* abc9_box_id=1104, lib_whitebox, abc9_flop *)
+module FDPE (
   (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
+  (* invertible_pin = "IS_C_INVERTED" *)
   input C,
-  input CE, D, R
+  input CE,
+  (* invertible_pin = "IS_D_INVERTED" *)
+  input D,
+  (* invertible_pin = "IS_PRE_INVERTED" *)
+  input PRE
 );
-  parameter [0:0] INIT = 1'b0;
+  parameter [0:0] INIT = 1'b1;
+  parameter [0:0] IS_C_INVERTED = 1'b0;
+  parameter [0:0] IS_D_INVERTED = 1'b0;
+  parameter [0:0] IS_PRE_INVERTED = 1'b0;
   initial Q <= INIT;
-  always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D;
+  generate case ({|IS_C_INVERTED, |IS_PRE_INVERTED})
+    2'b00: always @(posedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
+    2'b01: always @(posedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
+    2'b10: always @(negedge C, posedge PRE) if ( PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
+    2'b11: always @(negedge C, negedge PRE) if (!PRE) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
+  endcase endgenerate
 endmodule
 
-module FDSE_1 (
+(* abc9_box_id=1105, lib_whitebox, abc9_flop *)
+module FDPE_1 (
   (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
   input C,
-  input CE, D, S
+  input CE, D, PRE
 );
   parameter [0:0] INIT = 1'b1;
   initial Q <= INIT;
-  always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D;
+  always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
 endmodule
 
-module FDCE_1 (
+(* abc9_box_id=1106, lib_whitebox, abc9_flop *)
+module FDSE (
   (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
+  (* invertible_pin = "IS_C_INVERTED" *)
   input C,
-  input CE, D, CLR
+  input CE,
+  (* invertible_pin = "IS_D_INVERTED" *)
+  input D,
+  (* invertible_pin = "IS_S_INVERTED" *)
+  input S
 );
-  parameter [0:0] INIT = 1'b0;
+  parameter [0:0] INIT = 1'b1;
+  parameter [0:0] IS_C_INVERTED = 1'b0;
+  parameter [0:0] IS_D_INVERTED = 1'b0;
+  parameter [0:0] IS_S_INVERTED = 1'b0;
   initial Q <= INIT;
-  always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
+  generate case (|IS_C_INVERTED)
+    1'b0: always @(posedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
+    1'b1: always @(negedge C) if (S == !IS_S_INVERTED) Q <= 1'b1; else if (CE) Q <= D ^ IS_D_INVERTED;
+  endcase endgenerate
 endmodule
 
-module FDPE_1 (
+(* abc9_box_id=1107, lib_whitebox, abc9_flop *)
+module FDSE_1 (
   (* abc9_arrival=303 *)
   output reg Q,
   (* clkbuf_sink *)
   input C,
-  input CE, D, PRE
+  input CE, D, S
 );
   parameter [0:0] INIT = 1'b1;
   initial Q <= INIT;
-  always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D;
+  always @(negedge C) if (S) Q <= 1'b1; else if (CE) Q <= D;
 endmodule
 
 module LDCE (
index 971089b289a385230718a3ff02de4d14560a78a0..ac6fedc58596c2338bcbb4214062ca5360e7b18b 100644 (file)
@@ -292,10 +292,11 @@ struct SynthXilinxPass : public ScriptPass
                        ff_map_file = "+/xilinx/xc7_ff_map.v";
 
                if (check_label("begin")) {
+                       std::string read_args;
                        if (vpr)
-                               run("read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
-                       else
-                               run("read_verilog -lib +/xilinx/cells_sim.v");
+                               read_args += " -D_EXPLICIT_CARRY";
+                       read_args += " -lib +/xilinx/cells_sim.v";
+                       run("read_verilog" + read_args);
 
                        run("read_verilog -lib +/xilinx/cells_xtra.v");
 
@@ -549,6 +550,7 @@ struct SynthXilinxPass : public ScriptPass
                                else
                                        abc9_opts += " -lut +/xilinx/abc9_xc7.lut";
                                run("abc9" + abc9_opts);
+                               run("techmap -map +/xilinx/abc9_unmap.v");
                        }
                        else {
                                if (nowidelut)
@@ -564,14 +566,11 @@ struct SynthXilinxPass : public ScriptPass
                                run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')");
                        std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v";
                        if (help_mode)
-                               techmap_args += " [-map " + ff_map_file + "]";
-                       else if (abc9)
-                               techmap_args += " -map +/xilinx/abc9_unmap.v";
-                       else
-                               techmap_args += " -map " + ff_map_file;
-                       run("techmap " + techmap_args);
+                               techmap_args += stringf("[-map %s]", ff_map_file.c_str());
+                       else if (!abc9)
+                               techmap_args += stringf(" -map %s", ff_map_file.c_str());
+                       run("techmap " + techmap_args, "(option without '-abc9')");
                        run("xilinx_dffopt");
-                       run("clean");
                }
 
                if (check_label("finalize")) {
@@ -579,6 +578,7 @@ struct SynthXilinxPass : public ScriptPass
                                run("clkbufmap -buf BUFG O:I ", "(skip if '-noclkbuf')");
                        if (help_mode || ise)
                                run("extractinv -inv INV O:I", "(only if '-ise')");
+                       run("clean");
                }
 
                if (check_label("check")) {
diff --git a/tests/arch/xilinx/abc9_map.ys b/tests/arch/xilinx/abc9_map.ys
new file mode 100644 (file)
index 0000000..6823589
--- /dev/null
@@ -0,0 +1,91 @@
+read_verilog <<EOT
+module top(input C, CE, D, R, output [1:0] Q);
+FDRE   #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .R(R), .Q(Q[0]));
+FDRE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .R(R), .Q(Q[1]));
+endmodule
+EOT
+design -save gold
+
+techmap -map +/xilinx/abc9_map.v -max_iter 1
+techmap -map +/xilinx/abc9_unmap.v
+select -assert-count 1 t:FDSE
+select -assert-count 1 t:FDSE_1
+techmap -autoproc -map +/xilinx/cells_sim.v
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+techmap -autoproc -map +/xilinx/cells_sim.v
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -seq 2 -verify -prove-asserts -show-ports miter
+
+design -reset
+read_verilog <<EOT
+module top(input C, CE, D, S, output [1:0] Q);
+FDSE   #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .S(S), .Q(Q[0]));
+FDSE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .S(S), .Q(Q[1]));
+endmodule
+EOT
+design -save gold
+
+techmap -map +/xilinx/abc9_map.v -max_iter 1
+techmap -map +/xilinx/abc9_unmap.v
+select -assert-count 1 t:FDRE
+select -assert-count 1 t:FDRE_1
+techmap -autoproc -map +/xilinx/cells_sim.v
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+techmap -autoproc -map +/xilinx/cells_sim.v
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter
+
+design -reset
+read_verilog <<EOT
+module top(input C, CE, D, PRE, output [1:0] Q);
+FDPE   #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .PRE(PRE), .Q(Q[0]));
+FDPE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .PRE(PRE), .Q(Q[1]));
+endmodule
+EOT
+design -save gold
+
+techmap -map +/xilinx/abc9_map.v -max_iter 1
+techmap -map +/xilinx/abc9_unmap.v
+select -assert-count 1 t:FDCE
+select -assert-count 1 t:FDCE_1
+techmap -autoproc -map +/xilinx/cells_sim.v
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+techmap -autoproc -map +/xilinx/cells_sim.v
+clk2fflogic
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter
+
+design -reset
+read_verilog <<EOT
+module top(input C, CE, D, CLR, output [1:0] Q);
+FDCE   #(.INIT(1'b1)) ff1 (.C(C), .CE(CE), .D(D), .CLR(CLR), .Q(Q[0]));
+FDCE_1 #(.INIT(1'b1)) ff2 (.C(C), .CE(CE), .D(D), .CLR(CLR), .Q(Q[1]));
+endmodule
+EOT
+design -save gold
+
+techmap -map +/xilinx/abc9_map.v -max_iter 1
+techmap -map +/xilinx/abc9_unmap.v
+select -assert-count 1 t:FDPE
+techmap -autoproc -map +/xilinx/cells_sim.v
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+techmap -autoproc -map +/xilinx/cells_sim.v
+clk2fflogic
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -seq 2 -set-init-zero -verify -prove-asserts -show-ports miter
index de60619d1b71ebf54929995e3c79add0942d96df..8afd0ce963afb325db7622bbf9d449fb7fcec8a4 100644 (file)
@@ -264,3 +264,30 @@ always @*
   if (en)
     q <= d;
 endmodule
+
+module abc9_test031(input clk1, clk2, d, output reg q1, q2);
+always @(posedge clk1) q1 <= d;
+always @(negedge clk2) q2 <= q1;
+endmodule
+
+module abc9_test032(input clk, d, r, output reg q);
+always @(posedge clk or posedge r)
+    if (r) q <= 1'b0;
+    else q <= d;
+endmodule
+
+module abc9_test033(input clk, d, r, output reg q);
+always @(negedge clk or posedge r)
+    if (r) q <= 1'b1;
+    else q <= d;
+endmodule
+
+module abc9_test034(input clk, d, output reg q1, q2);
+always @(posedge clk) q1 <= d;
+always @(posedge clk) q2 <= q1;
+endmodule
+
+module abc9_test035(input clk, d, output reg [1:0] q);
+always @(posedge clk) q[0] <= d;
+always @(negedge clk) q[1] <= q[0];
+endmodule
index 0d4262005fd3b207cc725ae689f0b3023b25a92a..bc921daa9dc3715eb74d8d54102f6282666e39d9 100755 (executable)
@@ -20,10 +20,12 @@ fi
 cp ../simple/*.v .
 cp ../simple/*.sv .
 DOLLAR='?'
-exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-n 300 -p '\
+exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v *.sv EXTRA_FLAGS="-n 300 -p '\
     hierarchy; \
     synth -run coarse; \
     opt -full; \
-    techmap; abc9 -lut 4 -box ../abc.box; \
+    techmap; \
+    abc9 -lut 4 -box ../abc.box; \
+    clean; \
     check -assert; \
     select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'"
index 30ebd4e26c9fb410c5f6bcd9c235fab64efa17dd..f0b3f68373fe3ce2bb1ec11b548407d94a5d3b55 100644 (file)
@@ -9,3 +9,10 @@ wire w;
 unknown u(~i, w);
 unknown2 u2(w, o);
 endmodule
+
+module abc9_test032(input clk, d, r, output reg q);
+initial q = 1'b0;
+always @(negedge clk or negedge r)
+    if (!r) q <= 1'b0;
+    else q <= d;
+endmodule
index 5c9a4075d0d79d40491282a1a23d964127c25a8e..81d0afd1ba0461917576799686e5df4150242d21 100644 (file)
@@ -22,3 +22,19 @@ abc9 -lut 4
 select -assert-count 1 t:$lut r:LUT=2'b01 r:WIDTH=1 %i %i
 select -assert-count 1 t:unknown
 select -assert-none t:$lut t:unknown %% t: %D
+
+design -load read
+hierarchy -top abc9_test032
+proc
+clk2fflogic
+design -save gold
+
+abc9 -lut 4
+check
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -seq 10 -verify -prove-asserts -show-ports miter
diff --git a/tests/various/submod.ys b/tests/various/submod.ys
new file mode 100644 (file)
index 0000000..9d7dabd
--- /dev/null
@@ -0,0 +1,102 @@
+read_verilog <<EOT
+module top(input a, output b);
+wire c;
+(* submod="bar" *) sub s1(a, c);
+assign b = c;
+endmodule
+
+module sub(input a, output c);
+assign c = a;
+endmodule
+EOT
+
+hierarchy -top top
+proc
+design -save gold
+
+submod
+check -assert
+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 -reset
+read_verilog <<EOT
+module top(input a, output [1:0] b);
+(* submod="bar" *) sub s1(a, b[1]);
+assign b[0] = 1'b0;
+endmodule
+
+module sub(input a, output c);
+assign c = a;
+endmodule
+EOT
+
+hierarchy -top top
+proc
+design -save gold
+
+submod
+check -assert top
+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 -reset
+read_verilog <<EOT
+module top(input a, output [1:0] b, c);
+(* submod="bar" *) sub s1(a, b[0]);
+(* submod="bar" *) sub s2(a, c[1]);
+assign c = b;
+endmodule
+
+module sub(input a, output c);
+assign c = a;
+endmodule
+EOT
+
+hierarchy -top top
+proc
+design -save gold
+
+submod
+check -assert top
+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 -reset
+read_verilog -icells <<EOT
+module top(input d, c, (* init = 3'b011 *) output reg [2:0] q);
+(* submod="bar" *) DFF s1(.D(d), .C(c), .Q(q[1]));
+DFF s2(.D(d), .C(c), .Q(q[0]));
+DFF s3(.D(d), .C(c), .Q(q[2]));
+endmodule
+
+module DFF(input D, C, output Q);
+parameter INIT = 1'b0;
+endmodule
+EOT
+
+hierarchy -top top
+proc
+
+submod
+dffinit -ff DFF Q INIT
+check -noinit -assert