Merge remote-tracking branch 'origin/master' into xaig
[yosys.git] / passes / techmap / abc9.cc
index 5c10278a947bb69e67432171888b21f555222cdd..da3d36354157110c644c2905a2d10adf123437b6 100644 (file)
@@ -2,6 +2,7 @@
  *  yosys -- Yosys Open SYnthesis Suite
  *
  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
+ *  Copyright (C) 2019  Eddie Hung <eddie@fpgeh.com>
  *
  *  Permission to use, copy, modify, and/or distribute this software for any
  *  purpose with or without fee is hereby granted, provided that the above
 // Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification
 // http://www.eecs.berkeley.edu/~alanmi/abc/
 
-// [[CITE]] Berkeley Logic Interchange Format (BLIF)
-// University of California. Berkeley. July 28, 1992
-// http://www.ece.cmu.edu/~ee760/760docs/blif.pdf
-
-// [[CITE]] Kahn's Topological sorting algorithm
-// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025
-// http://en.wikipedia.org/wiki/Topological_sorting
-
 #define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
 #define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
-#define ABC_COMMAND_LUT "&st; &fraig; &scorr; &dc2; &retime; &dch -f; &if;"/*" &mfs"*/
+//#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2"
+#define ABC_COMMAND_LUT "&st; &fraig; &scorr; &dc2; &retime; &dch -f; &if; &mfs"
 #define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}"
 #define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
 
 #define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}"
 #define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
-#define ABC_FAST_COMMAND_LUT "strash; dretime; if"
+#define ABC_FAST_COMMAND_LUT "&st; &retime; &if"
 #define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}"
 #define ABC_FAST_COMMAND_DFL "strash; dretime; map"
 
@@ -91,14 +85,12 @@ std::string remap_name(RTLIL::IdString abc_name)
        return sstr.str();
 }
 
-void handle_loops(RTLIL::Design *design, RTLIL::Module *module)
+void handle_loops(RTLIL::Design *design)
 {
-       design->selection_stack.emplace_back(false);
-       RTLIL::Selection& sel = design->selection_stack.back();
-       sel.select(module);
        Pass::call(design, "scc -set_attr abc_scc_id {}");
 
-       sel = RTLIL::Selection(false);
+       design->selection_stack.emplace_back(false);
+       RTLIL::Selection& sel = design->selection_stack.back();
 
        // For every unique SCC found, (arbitrarily) find the first
        // cell in the component, and select (and mark) all its output
@@ -327,10 +319,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
        if (!cleanup)
                tempdir_name[0] = tempdir_name[4] = '_';
        tempdir_name = make_temp_dir(tempdir_name);
-       log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n",
+       log_header(design, "Extracting gate netlist of module `%s' to `%s/input.aig'..\n",
                        module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str());
 
-       std::string abc_script = stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str());
+       std::string abc_script = stringf("read %s/input.aig; &get -n; ", tempdir_name.c_str());
 
        if (!liberty_file.empty()) {
                abc_script += stringf("read_lib -w %s; ", liberty_file.c_str());
@@ -384,7 +376,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
        for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos))
                abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3);
 
-       abc_script += stringf("; &ps; &write %s/output.xaig", tempdir_name.c_str());
+       abc_script += stringf("; &write %s/output.aig", tempdir_name.c_str());
        abc_script = add_echos_to_abc_cmd(abc_script);
 
        for (size_t i = 0; i+1 < abc_script.size(); i++)
@@ -407,11 +399,17 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                }
        }
 
-       Pass::call(design, "aigmap; clean;");
+       design->selection_stack.emplace_back(false);
+       RTLIL::Selection& sel = design->selection_stack.back();
+       sel.select(module);
+
+       Pass::call(design, "aigmap");
 
-       handle_loops(design, module);
+       handle_loops(design);
 
-    Pass::call(design, stringf("write_xaiger -O -map %s/input.symbols %s/input.xaig; ", tempdir_name.c_str(), tempdir_name.c_str()));
+       Pass::call(design, stringf("write_xaiger -O -symbols %s/input.aig; ", tempdir_name.c_str()));
+
+       design->selection_stack.pop_back();
 
        // Now 'unexpose' those wires by undoing
        // the expose operation -- remove them from PO/PI
@@ -431,11 +429,14 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
        }
        module->fixup_ports();
 
+       //log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n",
+       //              count_gates, GetSize(signal_list), count_input, count_output);
+
        log_push();
 
        //if (count_output > 0)
        {
-               log_header(design, "Executing ABC.\n");
+               log_header(design, "Executing ABC9.\n");
 
                std::string buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str());
                f = fopen(buffer.c_str(), "wt");
@@ -513,7 +514,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                if (ret != 0)
                        log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret);
 
-               buffer = stringf("%s/%s", tempdir_name.c_str(), "output.xaig");
+               buffer = stringf("%s/%s", tempdir_name.c_str(), "output.aig");
                std::ifstream ifs;
                ifs.open(buffer);
                if (ifs.fail())
@@ -522,22 +523,21 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                bool builtin_lib = liberty_file.empty();
                RTLIL::Design *mapped_design = new RTLIL::Design;
                //parse_blif(mapped_design, ifs, builtin_lib ? "\\DFF" : "\\_dff_", false, sop_mode);
-               buffer = stringf("%s/%s", tempdir_name.c_str(), "input.symbols");
-               AigerReader reader(mapped_design, ifs, "\\netlist", "\\clk", buffer, true /* wideports */);
+               AigerReader reader(mapped_design, ifs, "\\netlist", "" /* clk_name */, "" /* map_filename */, true /* wideports */);
                reader.parse_xaiger();
 
                ifs.close();
 
-               log_header(design, "Re-integrating ABC results.\n");
+               log_header(design, "Re-integrating ABC9 results.\n");
                RTLIL::Module *mapped_mod = mapped_design->modules_["\\netlist"];
                if (mapped_mod == NULL)
                        log_error("ABC output file does not contain a module `netlist'.\n");
+
                pool<RTLIL::SigBit> output_bits;
                for (auto &it : mapped_mod->wires_) {
                        RTLIL::Wire *w = it.second;
                        RTLIL::Wire *remap_wire = module->addWire(remap_name(w->name), GetSize(w));
                        if (markgroups) remap_wire->attributes["\\abcgroup"] = map_autoidx;
-                       design->select(module, remap_wire);
                        if (w->port_output) {
                                RTLIL::Wire *wire = module->wire(w->name);
                                if (wire) {
@@ -550,6 +550,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                                goto cleanup;
                                        }
 
+                                       // Attempt another wideports_split here because there
+                                       // exists the possibility that different bits of a port
+                                       // could be an input and output, therefore parse_xiager()
+                                       // could not combine it into a wideport
                                        auto r = wideports_split(w->name.str());
                                        wire = module->wire(r.first);
                                        log_assert(wire);
@@ -564,6 +568,56 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                {
                        if (builtin_lib)
                        {
+                               if (c->type == "$_NOT_") {
+                                       RTLIL::Cell *cell;
+                                       RTLIL::SigBit a_bit = c->getPort("\\A").as_bit();
+                                       RTLIL::SigBit y_bit = c->getPort("\\Y").as_bit();
+                                       if (!lut_costs.empty()) {
+                                               // ABC can return NOT gates that drive POs
+                                               if (a_bit.wire->port_input) {
+                                                       // If it's a NOT gate that comes from a primary input directly
+                                                       // then implement it using a LUT
+                                                       cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
+                                                                       RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset),
+                                                                       RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset),
+                                                                       1);
+                                               }
+                                               else {
+                                                       // Otherwise, clone the driving LUT to guarantee that we
+                                                       // won't increase the max logic depth
+                                                       // (TODO: Optimise by not cloning unless will increase depth)
+                                                       RTLIL::IdString driver_name;
+                                                       if (GetSize(a_bit.wire) == 1)
+                                                               driver_name = stringf("%s$lut", a_bit.wire->name.c_str());
+                                                       else
+                                                               driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset);
+                                                       RTLIL::Cell* driver = mapped_mod->cell(driver_name);
+                                                       log_assert(driver);
+                                                       auto driver_a = driver->getPort("\\A").chunks();
+                                                       for (auto &chunk : driver_a)
+                                                               chunk.wire = module->wires_[remap_name(chunk.wire->name)];
+                                                       RTLIL::Const driver_lut = driver->getParam("\\LUT");
+                                                       for (auto &b : driver_lut.bits) {
+                                                               if (b == RTLIL::State::S0) b = RTLIL::State::S1;
+                                                               else if (b == RTLIL::State::S1) b = RTLIL::State::S0;
+                                                       }
+                                                       cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())),
+                                                                       driver_a,
+                                                                       RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset),
+                                                                       driver_lut);
+                                               }
+                                               cell_stats["$lut"]++;
+                                       }
+                                       else {
+                                               cell = module->addCell(remap_name(c->name), "$_NOT_");
+                                               cell->setPort("\\A", RTLIL::SigBit(module->wires_[remap_name(a_bit.wire->name)], a_bit.offset));
+                                               cell->setPort("\\Y", RTLIL::SigBit(module->wires_[remap_name(y_bit.wire->name)], y_bit.offset));
+                                               cell_stats[RTLIL::unescape_id(c->type)]++;
+                                       }
+                                       if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
+                                       continue;
+                               }
+
                                cell_stats[RTLIL::unescape_id(c->type)]++;
                                if (c->type == "\\ZERO" || c->type == "\\ONE") {
                                        RTLIL::SigSig conn;
@@ -579,14 +633,7 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                        module->connect(conn);
                                        continue;
                                }
-                               if (c->type == "\\NOT") {
-                                       RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_NOT_");
-                                       if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
-                                       cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
-                                       cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
-                                       design->select(module, cell);
-                                       continue;
-                               }
+
                                if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR" || c->type == "\\NAND" || c->type == "\\NOR" ||
                                                c->type == "\\XNOR" || c->type == "\\ANDNOT" || c->type == "\\ORNOT") {
                                        RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
@@ -594,7 +641,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                        cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
                                        cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
                                        cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
-                                       design->select(module, cell);
                                        continue;
                                }
                                if (c->type == "\\MUX") {
@@ -604,7 +650,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                        cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
                                        cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)]));
                                        cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
-                                       design->select(module, cell);
                                        continue;
                                }
                                if (c->type == "\\MUX4") {
@@ -617,7 +662,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                        cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)]));
                                        cell->setPort("\\T", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\T").as_wire()->name)]));
                                        cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
-                                       design->select(module, cell);
                                        continue;
                                }
                                if (c->type == "\\MUX8") {
@@ -635,7 +679,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                        cell->setPort("\\T", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\T").as_wire()->name)]));
                                        cell->setPort("\\U", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\U").as_wire()->name)]));
                                        cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
-                                       design->select(module, cell);
                                        continue;
                                }
                                if (c->type == "\\MUX16") {
@@ -662,7 +705,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                        cell->setPort("\\U", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\U").as_wire()->name)]));
                                        cell->setPort("\\V", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\V").as_wire()->name)]));
                                        cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
-                                       design->select(module, cell);
                                        continue;
                                }
                                if (c->type == "\\AOI3" || c->type == "\\OAI3") {
@@ -672,7 +714,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                        cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)]));
                                        cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
                                        cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
-                                       design->select(module, cell);
                                        continue;
                                }
                                if (c->type == "\\AOI4" || c->type == "\\OAI4") {
@@ -683,7 +724,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                        cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)]));
                                        cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
                                        cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]));
-                                       design->select(module, cell);
                                        continue;
                                }
                                if (c->type == "\\DFF") {
@@ -700,7 +740,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                        cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
                                        cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
                                        cell->setPort("\\C", clk_sig);
-                                       design->select(module, cell);
                                        continue;
                                }
                        }
@@ -729,7 +768,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)]));
                                cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)]));
                                cell->setPort("\\C", clk_sig);
-                               design->select(module, cell);
                                continue;
                        }
 
@@ -754,7 +792,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                }
                                cell->setPort(conn.first, newsig);
                        }
-                       design->select(module, cell);
                }
 
                // Copy connections (and rename) from mapped_mod to module
@@ -804,25 +841,31 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                //              module->connect(conn);
                //      }
 
-               // Go through all cell output connections,
+               // Go through all AND and NOT output connections,
                // and for those output ports driving wires
                // also driven by mapped_mod, disconnect them
                for (auto cell : module->cells()) {
+                       if (!cell->type.in("$_AND_", "$_NOT_"))
+                               continue;
                        for (auto &it : cell->connections_) {
                                auto port_name = it.first;
                                if (!cell->output(port_name)) continue;
                                auto &signal = it.second;
-                               if (!signal.is_bit()) continue;
-                               if (output_bits.count(signal.as_bit()))
-                                       signal = module->addWire(NEW_ID);
+                               auto bits = signal.bits();
+                               for (auto &b : bits)
+                                       if (output_bits.count(b))
+                                               b = module->addWire(NEW_ID);
+                               signal = std::move(bits);
                        }
                }
                // Do the same for module connections
                for (auto &it : module->connections_) {
                        auto &signal = it.first;
-                       if (!signal.is_bit()) continue;
-                       if (output_bits.count(signal.as_bit()))
-                               signal = module->addWire(NEW_ID);
+                       auto bits = signal.bits();
+                       for (auto &b : bits)
+                               if (output_bits.count(b))
+                                       b = module->addWire(NEW_ID);
+                       signal = std::move(bits);
                }
 
                // Stitch in mapped_mod's inputs/outputs into module
@@ -837,6 +880,10 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                                signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire));
                        }
                        else {
+                               // Attempt another wideports_split here because there
+                               // exists the possibility that different bits of a port
+                               // could be an input and output, therefore parse_xiager()
+                               // could not combine it into a wideport
                                auto r = wideports_split(w->name.str());
                                wire = module->wire(r.first);
                                log_assert(wire);
@@ -845,21 +892,20 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
                        }
                        log_assert(GetSize(signal) >= GetSize(remap_wire));
 
+                       log_assert(w->port_input || w->port_output);
+                       RTLIL::SigSig conn;
                        if (w->port_input) {
-                               RTLIL::SigSig conn;
                                conn.first = remap_wire;
                                conn.second = signal;
                                in_wires++;
                                module->connect(conn);
                        }
-                       else if (w->port_output) {
-                               RTLIL::SigSig conn;
+                       if (w->port_output) {
                                conn.first = signal;
                                conn.second = remap_wire;
                                out_wires++;
                                module->connect(conn);
                        }
-                       else log_abort();
                }
 
                //log("ABC RESULTS:        internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires);
@@ -873,8 +919,6 @@ void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::stri
        //      log("Don't call ABC as there is nothing to map.\n");
        //}
 
-       Pass::call(design, "clean");
-
 cleanup:
        if (cleanup)
        {
@@ -1079,7 +1123,6 @@ struct Abc9Pass : public Pass {
                std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1";
                bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true;
                bool show_tempdir = false, sop_mode = false;
-               show_tempdir = true; cleanup = true;
                vector<int> lut_costs;
                markgroups = false;
 
@@ -1493,6 +1536,8 @@ struct Abc9Pass : public Pass {
                        }
                }
 
+               Pass::call(design, "clean");
+
                assign_map.clear();
                signal_map.clear();
                signal_init.clear();