abc9_ops: still emit delay table even box has no timing
[yosys.git] / passes / techmap / extract_fa.cc
index 162a90306eb1e14116ee95f906ade5bb66d8afa6..9f3bb525bdd17885330fdc74dc0dc2a741b54617 100644 (file)
@@ -28,6 +28,9 @@ struct ExtractFaConfig
 {
        bool enable_fa = false;
        bool enable_ha = false;
+       bool verbose = false;
+       int maxdepth = 20;
+       int maxbreadth = 6;
 };
 
 // http://svn.clifford.at/handicraft/2016/bindec/bindec.c
@@ -63,6 +66,9 @@ struct ExtractFaWorker
        dict<tuple<SigBit, SigBit>, dict<int, pool<SigBit>>> func2;
        dict<tuple<SigBit, SigBit, SigBit>, dict<int, pool<SigBit>>> func3;
 
+       int count_func2;
+       int count_func3;
+
        struct func2_and_info_t {
                bool inv_a, inv_b, inv_y;
        };
@@ -79,11 +85,11 @@ struct ExtractFaWorker
        {
                for (auto cell : module->selected_cells())
                {
-                       if (cell->type.in( "$_BUF_", "$_NOT_", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_",
-                                       "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", "$_MUX_",
-                                       "$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_"))
+                       if (cell->type.in( ID($_BUF_), ID($_NOT_), ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_),
+                                       ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), ID($_MUX_), ID($_NMUX_),
+                                       ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_)))
                        {
-                               SigBit y = sigmap(SigBit(cell->getPort("\\Y")));
+                               SigBit y = sigmap(SigBit(cell->getPort(ID::Y)));
                                log_assert(driver.count(y) == 0);
                                driver[y] = cell;
                        }
@@ -168,8 +174,10 @@ struct ExtractFaWorker
 
                                SigSpec sig = root;
 
-                               if (!ce.eval(sig))
-                                       log_abort();
+                               if (!ce.eval(sig)) {
+                                       ce.pop();
+                                       return;
+                               }
 
                                if (sig == State::S1)
                                        func |= 1 << i;
@@ -182,6 +190,7 @@ struct ExtractFaWorker
                        if (func == xor2_func || func == xnor2_func)
                                xorxnor2.insert(tuple<SigBit, SigBit>(A, B));
 
+                       count_func2++;
                        func2[tuple<SigBit, SigBit>(A, B)][func].insert(root);
                }
 
@@ -207,8 +216,10 @@ struct ExtractFaWorker
 
                                SigSpec sig = root;
 
-                               if (!ce.eval(sig))
-                                       log_abort();
+                               if (!ce.eval(sig)) {
+                                       ce.pop();
+                                       return;
+                               }
 
                                if (sig == State::S1)
                                        func |= 1 << i;
@@ -221,6 +232,7 @@ struct ExtractFaWorker
                        if (func == xor3_func || func == xnor3_func)
                                xorxnor3.insert(tuple<SigBit, SigBit, SigBit>(A, B, C));
 
+                       count_func3++;
                        func3[tuple<SigBit, SigBit, SigBit>(A, B, C)][func].insert(root);
                }
        }
@@ -250,10 +262,14 @@ struct ExtractFaWorker
                        pool<SigBit> new_leaves = leaves;
 
                        new_leaves.erase(bit);
-                       if (cell->hasPort("\\A")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\A"))));
-                       if (cell->hasPort("\\B")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\B"))));
-                       if (cell->hasPort("\\C")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\C"))));
-                       if (cell->hasPort("\\D")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\D"))));
+                       for (auto port : {ID::A, ID::B, ID(C), ID(D)}) {
+                               if (!cell->hasPort(port))
+                                       continue;
+                               auto bit = sigmap(SigBit(cell->getPort(port)));
+                               if (!bit.wire)
+                                       continue;
+                               new_leaves.insert(bit);
+                       }
 
                        if (GetSize(new_leaves) > maxbreadth)
                                continue;
@@ -265,8 +281,8 @@ struct ExtractFaWorker
        void assign_new_driver(SigBit bit, SigBit new_driver)
        {
                Cell *cell = driver.at(bit);
-               if (sigmap(cell->getPort("\\Y")) == bit) {
-                       cell->setPort("\\Y", module->addWire(NEW_ID));
+               if (sigmap(cell->getPort(ID::Y)) == bit) {
+                       cell->setPort(ID::Y, module->addWire(NEW_ID));
                        module->connect(bit, new_driver);
                }
        }
@@ -277,14 +293,26 @@ struct ExtractFaWorker
 
                for (auto it : driver)
                {
-                       if (it.second->type.in("$_BUF_", "$_NOT_"))
+                       if (it.second->type.in(ID($_BUF_), ID($_NOT_)))
                                continue;
 
                        SigBit root = it.first;
                        pool<SigBit> leaves = { root };
                        pool<pool<SigBit>> cache;
 
-                       find_partitions(root, leaves, cache, 20, 10);
+                       if (config.verbose)
+                               log("  checking %s\n", log_signal(it.first));
+
+                       count_func2 = 0;
+                       count_func3 = 0;
+
+                       find_partitions(root, leaves, cache, config.maxdepth, config.maxbreadth);
+
+                       if (config.verbose && count_func2 > 0)
+                               log("    extracted %d two-input functions\n", count_func2);
+
+                       if (config.verbose && count_func3 > 0)
+                               log("    extracted %d three-input functions\n", count_func3);
                }
 
                for (auto &key : xorxnor3)
@@ -306,6 +334,8 @@ struct ExtractFaWorker
                                log("\n");
                        }
 
+                       dict<int, tuple<SigBit, SigBit, Cell*>> facache;
+
                        for (auto &it : func3_maj_info)
                        {
                                int func = it.first;
@@ -337,33 +367,64 @@ struct ExtractFaWorker
                                        log(" %s", log_signal(bit));
                                log("\n");
 
-                               Cell *cell = module->addCell(NEW_ID, "$fa");
-                               cell->setParam("\\WIDTH", 1);
+                               int fakey = 0;
+                               if (f3i.inv_a) fakey |= 1;
+                               if (f3i.inv_b) fakey |= 2;
+                               if (f3i.inv_c) fakey |= 4;
+
+                               int fakey_inv = fakey ^ 7;
+                               bool invert_xy = false;
+                               SigBit X, Y;
+
+                               if (facache.count(fakey))
+                               {
+                                       auto &fa = facache.at(fakey);
+                                       X = get<0>(fa);
+                                       Y = get<1>(fa);
+                                       log("      Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+                               }
+                               else
+                               if (facache.count(fakey_inv))
+                               {
+                                       auto &fa = facache.at(fakey_inv);
+                                       invert_xy = true;
+                                       X = get<0>(fa);
+                                       Y = get<1>(fa);
+                                       log("      Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+                               }
+                               else
+                               {
+                                       Cell *cell = module->addCell(NEW_ID, ID($fa));
+                                       cell->setParam(ID(WIDTH), 1);
+
+                                       log("      Created $fa cell %s.\n", log_id(cell));
 
-                               log("      Created $fa cell %s.\n", log_id(cell));
+                                       cell->setPort(ID::A, f3i.inv_a ? module->NotGate(NEW_ID, A) : A);
+                                       cell->setPort(ID::B, f3i.inv_b ? module->NotGate(NEW_ID, B) : B);
+                                       cell->setPort(ID(C), f3i.inv_c ? module->NotGate(NEW_ID, C) : C);
 
-                               cell->setPort("\\A", f3i.inv_a ? module->NotGate(NEW_ID, A) : A);
-                               cell->setPort("\\B", f3i.inv_b ? module->NotGate(NEW_ID, B) : B);
-                               cell->setPort("\\C", f3i.inv_c ? module->NotGate(NEW_ID, C) : C);
+                                       X = module->addWire(NEW_ID);
+                                       Y = module->addWire(NEW_ID);
 
-                               SigBit X = module->addWire(NEW_ID);
-                               SigBit Y = module->addWire(NEW_ID);
+                                       cell->setPort(ID(X), X);
+                                       cell->setPort(ID::Y, Y);
 
-                               cell->setPort("\\X", X);
-                               cell->setPort("\\Y", Y);
+                                       facache[fakey] = make_tuple(X, Y, cell);
+                               }
 
                                if (func3.at(key).count(xor3_func)) {
+                                       SigBit YY = invert_xy ? module->NotGate(NEW_ID, Y) : Y;
                                        for (auto bit : func3.at(key).at(xor3_func))
-                                               assign_new_driver(bit, Y);
+                                               assign_new_driver(bit, YY);
                                }
 
                                if (func3.at(key).count(xnor3_func)) {
-                                       SigBit YN = module->NotGate(NEW_ID, Y);
+                                       SigBit YY = invert_xy ? Y : module->NotGate(NEW_ID, Y);
                                        for (auto bit : func3.at(key).at(xnor3_func))
-                                               assign_new_driver(bit, YN);
+                                               assign_new_driver(bit, YY);
                                }
 
-                               SigBit XX = f3i.inv_y ? module->NotGate(NEW_ID, X) : X;
+                               SigBit XX = invert_xy != f3i.inv_y ? module->NotGate(NEW_ID, X) : X;
 
                                for (auto bit : func3.at(key).at(func))
                                        assign_new_driver(bit, XX);
@@ -388,6 +449,8 @@ struct ExtractFaWorker
                                log("\n");
                        }
 
+                       dict<int, tuple<SigBit, SigBit, Cell*>> facache;
+
                        for (auto &it : func2_and_info)
                        {
                                int func = it.first;
@@ -411,33 +474,61 @@ struct ExtractFaWorker
                                        log(" %s", log_signal(bit));
                                log("\n");
 
-                               Cell *cell = module->addCell(NEW_ID, "$fa");
-                               cell->setParam("\\WIDTH", 1);
+                               int fakey = 0;
+                               if (f2i.inv_a) fakey |= 1;
+                               if (f2i.inv_b) fakey |= 2;
+
+                               int fakey_inv = fakey ^ 3;
+                               bool invert_xy = false;
+                               SigBit X, Y;
+
+                               if (facache.count(fakey))
+                               {
+                                       auto &fa = facache.at(fakey);
+                                       X = get<0>(fa);
+                                       Y = get<1>(fa);
+                                       log("      Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+                               }
+                               else
+                               if (facache.count(fakey_inv))
+                               {
+                                       auto &fa = facache.at(fakey_inv);
+                                       invert_xy = true;
+                                       X = get<0>(fa);
+                                       Y = get<1>(fa);
+                                       log("      Reusing $fa cell %s.\n", log_id(get<2>(fa)));
+                               }
+                               else
+                               {
+                                       Cell *cell = module->addCell(NEW_ID, ID($fa));
+                                       cell->setParam(ID(WIDTH), 1);
 
-                               log("      Created $fa cell %s.\n", log_id(cell));
+                                       log("      Created $fa cell %s.\n", log_id(cell));
 
-                               cell->setPort("\\A", f2i.inv_a ? module->NotGate(NEW_ID, A) : A);
-                               cell->setPort("\\B", f2i.inv_b ? module->NotGate(NEW_ID, B) : B);
-                               cell->setPort("\\C", State::S0);
+                                       cell->setPort(ID::A, f2i.inv_a ? module->NotGate(NEW_ID, A) : A);
+                                       cell->setPort(ID::B, f2i.inv_b ? module->NotGate(NEW_ID, B) : B);
+                                       cell->setPort(ID(C), State::S0);
 
-                               SigBit X = module->addWire(NEW_ID);
-                               SigBit Y = module->addWire(NEW_ID);
+                                       X = module->addWire(NEW_ID);
+                                       Y = module->addWire(NEW_ID);
 
-                               cell->setPort("\\X", X);
-                               cell->setPort("\\Y", Y);
+                                       cell->setPort(ID(X), X);
+                                       cell->setPort(ID::Y, Y);
+                               }
 
                                if (func2.at(key).count(xor2_func)) {
+                                       SigBit YY = invert_xy || (f2i.inv_a && !f2i.inv_b) || (!f2i.inv_a && f2i.inv_b) ? module->NotGate(NEW_ID, Y) : Y;
                                        for (auto bit : func2.at(key).at(xor2_func))
-                                               assign_new_driver(bit, Y);
+                                               assign_new_driver(bit, YY);
                                }
 
                                if (func2.at(key).count(xnor2_func)) {
-                                       SigBit YN = module->NotGate(NEW_ID, Y);
+                                       SigBit YY = invert_xy || (f2i.inv_a && !f2i.inv_b) || (!f2i.inv_a && f2i.inv_b) ? Y : module->NotGate(NEW_ID, Y);
                                        for (auto bit : func2.at(key).at(xnor2_func))
-                                               assign_new_driver(bit, YN);
+                                               assign_new_driver(bit, YY);
                                }
 
-                               SigBit XX = f2i.inv_y ? module->NotGate(NEW_ID, X) : X;
+                               SigBit XX = invert_xy != f2i.inv_y ? module->NotGate(NEW_ID, X) : X;
 
                                for (auto bit : func2.at(key).at(func))
                                        assign_new_driver(bit, XX);
@@ -448,7 +539,7 @@ struct ExtractFaWorker
 
 struct ExtractFaPass : public Pass {
        ExtractFaPass() : Pass("extract_fa", "find and extract full/half adders") { }
-       virtual void help()
+       void help() YS_OVERRIDE
        {
                //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
                log("\n");
@@ -460,8 +551,17 @@ struct ExtractFaPass : public Pass {
                log("        Enable cell types (fa=full adder, ha=half adder)\n");
                log("        All types are enabled if none of this options is used\n");
                log("\n");
+               log("    -d <int>\n");
+               log("        Set maximum depth for extracted logic cones (default=20)\n");
+               log("\n");
+               log("    -b <int>\n");
+               log("        Set maximum breadth for extracted logic cones (default=6)\n");
+               log("\n");
+               log("    -v\n");
+               log("        Verbose output\n");
+               log("\n");
        }
-       virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+       void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
        {
                ExtractFaConfig config;
 
@@ -479,6 +579,18 @@ struct ExtractFaPass : public Pass {
                                config.enable_ha = true;
                                continue;
                        }
+                       if (args[argidx] == "-v") {
+                               config.verbose = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-d" && argidx+2 < args.size()) {
+                               config.maxdepth = atoi(args[++argidx].c_str());
+                               continue;
+                       }
+                       if (args[argidx] == "-b" && argidx+2 < args.size()) {
+                               config.maxbreadth = atoi(args[++argidx].c_str());
+                               continue;
+                       }
                        break;
                }
                extra_args(args, argidx, design);