Add $_NMUX_, add "abc -g cmos", add proper cmos cell costs
authorClifford Wolf <clifford@clifford.at>
Tue, 6 Aug 2019 02:47:55 +0000 (04:47 +0200)
committerClifford Wolf <clifford@clifford.at>
Tue, 6 Aug 2019 02:47:55 +0000 (04:47 +0200)
Signed-off-by: Clifford Wolf <clifford@clifford.at>
19 files changed:
CHANGELOG
backends/blif/blif.cc
backends/btor/btor.cc
backends/simplec/simplec.cc
backends/smt2/smt2.cc
backends/smv/smv.cc
backends/verilog/verilog_backend.cc
kernel/cellaigs.cc
kernel/celltypes.h
kernel/consteval.h
kernel/cost.h
kernel/rtlil.cc
kernel/rtlil.h
kernel/satgen.h
manual/CHAPTER_CellLib.tex
passes/cmds/stat.cc
passes/techmap/abc.cc
passes/techmap/extract_fa.cc
techlibs/common/simcells.v

index 00b10c591db67d9c89fb914720a1196997c92025..9e9bda6e9759b8f73be86cf659456164553d2112 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -15,6 +15,7 @@ Yosys 0.9 .. Yosys 0.9-dev
     - Added "script -scriptwire
     - "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable)
     - Added automatic gzip decompression for frontends
+    - Added $_NMUX_ cell type
 
 Yosys 0.8 .. Yosys 0.8-dev
 --------------------------
index a1761b66236da654268da1106e273c525e8c6a10..f32b0f53309c94a0b2cddf63115fd64ede307746 100644 (file)
@@ -327,6 +327,13 @@ struct BlifDumper
                                goto internal_cell;
                        }
 
+                       if (!config->icells_mode && cell->type == "$_NMUX_") {
+                               f << stringf(".names %s %s %s %s\n0-0 1\n-01 1\n",
+                                               cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")),
+                                               cstr(cell->getPort("\\S")), cstr(cell->getPort("\\Y")));
+                               goto internal_cell;
+                       }
+
                        if (!config->icells_mode && cell->type == "$_FF_") {
                                f << stringf(".latch %s %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
                                                cstr_init(cell->getPort("\\Q")));
index a507b120b88e7a00012dc17aa582b33898dedc5b..7bacce2afb66bac219a42005bf2f386646e29542 100644 (file)
@@ -496,7 +496,7 @@ struct BtorWorker
                        goto okay;
                }
 
-               if (cell->type.in("$mux", "$_MUX_"))
+               if (cell->type.in("$mux", "$_MUX_", "$_NMUX_"))
                {
                        SigSpec sig_a = sigmap(cell->getPort("\\A"));
                        SigSpec sig_b = sigmap(cell->getPort("\\B"));
@@ -511,6 +511,12 @@ struct BtorWorker
                        int nid = next_nid++;
                        btorf("%d ite %d %d %d %d\n", nid, sid, nid_s, nid_b, nid_a);
 
+                       if (cell->type == "$_NMUX_") {
+                               int tmp = nid;
+                               nid = next_nid++;
+                               btorf("%d not %d %d\n", nid, sid, tmp);
+                       }
+
                        add_nid_sig(nid, sig_y);
                        goto okay;
                }
index 6f2ccbe20bc78a79b744dc76454b4129a3ecf752..54dbb84afcfe67c78873df0872b95e044bc21702 100644 (file)
@@ -472,7 +472,7 @@ struct SimplecWorker
                        return;
                }
 
-               if (cell->type == "$_MUX_")
+               if (cell->type.in("$_MUX_", "$_NMUX_"))
                {
                        SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
                        SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
@@ -484,7 +484,9 @@ struct SimplecWorker
                        string s_expr = s.wire ? util_get_bit(work->prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0";
 
                        // casts to bool are a workaround for CBMC bug (https://github.com/diffblue/cbmc/issues/933)
-                       string expr = stringf("%s ? (bool)%s : (bool)%s", s_expr.c_str(), b_expr.c_str(), a_expr.c_str());
+                       string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr.c_str(),
+                                       cell->type == "$_NMUX_" ? "!" : "", b_expr.c_str(),
+                                       cell->type == "$_NMUX_" ? "!" : "", a_expr.c_str());
 
                        log_assert(y.wire);
                        funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) +
index e318a40517eefcf4d2cd288cd89b96269fd7cc82..ddd680782a1ca7de4f7fbc9264d5a709fb304e57 100644 (file)
@@ -510,6 +510,7 @@ struct Smt2Worker
                if (cell->type == "$_ANDNOT_") return export_gate(cell, "(and A (not B))");
                if (cell->type == "$_ORNOT_") return export_gate(cell, "(or A (not B))");
                if (cell->type == "$_MUX_") return export_gate(cell, "(ite S B A)");
+               if (cell->type == "$_NMUX_") return export_gate(cell, "(not (ite S B A))");
                if (cell->type == "$_AOI3_") return export_gate(cell, "(not (or (and A B) C))");
                if (cell->type == "$_OAI3_") return export_gate(cell, "(not (and (or A B) C))");
                if (cell->type == "$_AOI4_") return export_gate(cell, "(not (or (and A B) (and C D)))");
index d75456c1b43098c0307c3a3b5846bddc8f1aed91..e9586fae0f5b03a75dc76d8d8b1fbdd5b2ae6d5e 100644 (file)
@@ -537,6 +537,13 @@ struct SmvWorker
                                continue;
                        }
 
+                       if (cell->type == "$_NMUX_")
+                       {
+                               definitions.push_back(stringf("%s := !(bool(%s) ? %s : %s);", lvalue(cell->getPort("\\Y")),
+                                               rvalue(cell->getPort("\\S")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\A"))));
+                               continue;
+                       }
+
                        if (cell->type == "$_AOI3_")
                        {
                                definitions.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")),
index e0b3a6f80ae5efff8214258da32ae97e196353b5..776f4eacbbe1c4d360fd1e44f0fd49bf6627cec0 100644 (file)
@@ -558,6 +558,20 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
                return true;
        }
 
+       if (cell->type == "$_NMUX_") {
+               f << stringf("%s" "assign ", indent.c_str());
+               dump_sigspec(f, cell->getPort("\\Y"));
+               f << stringf(" = !(");
+               dump_cell_expr_port(f, cell, "S", false);
+               f << stringf(" ? ");
+               dump_attributes(f, "", cell->attributes, ' ');
+               dump_cell_expr_port(f, cell, "B", false);
+               f << stringf(" : ");
+               dump_cell_expr_port(f, cell, "A", false);
+               f << stringf(");\n");
+               return true;
+       }
+
        if (cell->type.in("$_AOI3_", "$_OAI3_")) {
                f << stringf("%s" "assign ", indent.c_str());
                dump_sigspec(f, cell->getPort("\\Y"));
index 26c625f89a62d2f3ab1f18e3fce70eba82664333..fbc6d045e7634511200f96b77e6b5b8da20baab0 100644 (file)
@@ -325,6 +325,8 @@ Aig::Aig(Cell *cell)
                        int A = mk.inport("\\A", i);
                        int B = mk.inport("\\B", i);
                        int Y = mk.mux_gate(A, B, S);
+                       if (cell->type == "$_NMUX_")
+                               Y = mk.not_gate(Y);
                        mk.outport(Y, "\\Y", i);
                }
                goto optimize;
index 758661c0236a0a80a996165393bbe3b887f0b501..d2594bc46c1f79021be564f92d696c1a660ea3ab 100644 (file)
@@ -193,6 +193,7 @@ struct CellTypes
                setup_type("$_ANDNOT_", {A, B}, {Y}, true);
                setup_type("$_ORNOT_", {A, B}, {Y}, true);
                setup_type("$_MUX_", {A, B, S}, {Y}, true);
+               setup_type("$_NMUX_", {A, B, S}, {Y}, true);
                setup_type("$_MUX4_", {A, B, C, D, S, T}, {Y}, true);
                setup_type("$_MUX8_", {A, B, C, D, E, F, G, H, S, T, U}, {Y}, true);
                setup_type("$_MUX16_", {A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V}, {Y}, true);
index 154373a8deeef29bb2223ae6029d4ffeb167a31c..f70dfa0fbda03261b24d31518a7dbfaa04ac2ecf 100644 (file)
@@ -145,7 +145,7 @@ struct ConstEval
                if (cell->hasPort("\\B"))
                        sig_b = cell->getPort("\\B");
 
-               if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_")
+               if (cell->type.in("$mux", "$pmux", "$_MUX_", "$_NMUX_"))
                {
                        std::vector<RTLIL::SigSpec> y_candidates;
                        int count_maybe_set_s_bits = 0;
@@ -175,7 +175,10 @@ struct ConstEval
                        for (auto &yc : y_candidates) {
                                if (!eval(yc, undef, cell))
                                        return false;
-                               y_values.push_back(yc.as_const());
+                               if (cell->type == "$_NMUX_")
+                                       y_values.push_back(RTLIL::const_not(yc.as_const(), Const(), false, false, GetSize(yc)));
+                               else
+                                       y_values.push_back(yc.as_const());
                        }
 
                        if (y_values.size() > 1)
index 41a09eb6334bdcd63a363adb5f7566a4e551c7f3..e8e077ff5491a1ddd72b163d042f17b68eae6c88 100644 (file)
 
 YOSYS_NAMESPACE_BEGIN
 
-int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr);
+int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr, bool cmos_cost = false);
 
 inline int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> &parameters = dict<RTLIL::IdString, RTLIL::Const>(),
-               RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr)
+               RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr, bool cmos_cost = false)
 {
        static dict<RTLIL::IdString, int> gate_cost = {
                { "$_BUF_",    1 },
@@ -44,9 +44,33 @@ inline int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL
                { "$_OAI3_",   6 },
                { "$_AOI4_",   8 },
                { "$_OAI4_",   8 },
-               { "$_MUX_",    4 }
+               { "$_MUX_",    4 },
+               { "$_NMUX_",   4 }
        };
 
+       // match costs in "stat -tech cmos"
+       static dict<RTLIL::IdString, int> cmos_gate_cost = {
+               { "$_BUF_",     1 },
+               { "$_NOT_",     2 },
+               { "$_AND_",     6 },
+               { "$_NAND_",    4 },
+               { "$_OR_",      6 },
+               { "$_NOR_",     4 },
+               { "$_ANDNOT_",  6 },
+               { "$_ORNOT_",   6 },
+               { "$_XOR_",    12 },
+               { "$_XNOR_",   12 },
+               { "$_AOI3_",    6 },
+               { "$_OAI3_",    6 },
+               { "$_AOI4_",    8 },
+               { "$_OAI4_",    8 },
+               { "$_MUX_",    12 },
+               { "$_NMUX_",   10 }
+       };
+
+       if (cmos_cost && cmos_gate_cost.count(type))
+               return cmos_gate_cost.at(type);
+
        if (gate_cost.count(type))
                return gate_cost.at(type);
 
@@ -76,9 +100,9 @@ inline int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL
        return 1;
 }
 
-inline int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache)
+inline int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache, bool cmos_cost)
 {
-       return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache);
+       return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache, cmos_cost);
 }
 
 YOSYS_NAMESPACE_END
index a09f4a0d1cbfa81cb2edbf69a06f605684b95a63..ba8472ec11350912d5401d8d4643cbb8bada3b03 100644 (file)
@@ -1249,6 +1249,7 @@ namespace {
                        if (cell->type == "$_ANDNOT_") { check_gate("ABY"); return; }
                        if (cell->type == "$_ORNOT_")  { check_gate("ABY"); return; }
                        if (cell->type == "$_MUX_")    { check_gate("ABSY"); return; }
+                       if (cell->type == "$_NMUX_")   { check_gate("ABSY"); return; }
                        if (cell->type == "$_AOI3_")   { check_gate("ABCY"); return; }
                        if (cell->type == "$_OAI3_")   { check_gate("ABCY"); return; }
                        if (cell->type == "$_AOI4_")   { check_gate("ABCDY"); return; }
@@ -1976,6 +1977,7 @@ DEF_METHOD_3(XnorGate,   "$_XNOR_",   A, B, Y)
 DEF_METHOD_3(AndnotGate, "$_ANDNOT_", A, B, Y)
 DEF_METHOD_3(OrnotGate,  "$_ORNOT_",  A, B, Y)
 DEF_METHOD_4(MuxGate,    "$_MUX_",    A, B, S, Y)
+DEF_METHOD_4(NmuxGate,   "$_NMUX_",   A, B, S, Y)
 DEF_METHOD_4(Aoi3Gate,   "$_AOI3_",   A, B, C, Y)
 DEF_METHOD_4(Oai3Gate,   "$_OAI3_",   A, B, C, Y)
 DEF_METHOD_5(Aoi4Gate,   "$_AOI4_",   A, B, C, D, Y)
index 712250b3e7f6ba0630bbece46cc1ce625c2fcfb0..1cfe71473f241aca9a77a98879b751f8c67237f7 100644 (file)
@@ -1154,6 +1154,7 @@ public:
        RTLIL::Cell* addAndnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = "");
        RTLIL::Cell* addOrnotGate  (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = "");
        RTLIL::Cell* addMuxGate    (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y, const std::string &src = "");
+       RTLIL::Cell* addNmuxGate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y, const std::string &src = "");
        RTLIL::Cell* addAoi3Gate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y, const std::string &src = "");
        RTLIL::Cell* addOai3Gate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y, const std::string &src = "");
        RTLIL::Cell* addAoi4Gate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y, const std::string &src = "");
@@ -1229,6 +1230,7 @@ public:
        RTLIL::SigBit AndnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = "");
        RTLIL::SigBit OrnotGate  (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = "");
        RTLIL::SigBit MuxGate    (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, const std::string &src = "");
+       RTLIL::SigBit NmuxGate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, const std::string &src = "");
        RTLIL::SigBit Aoi3Gate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, const std::string &src = "");
        RTLIL::SigBit Oai3Gate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, const std::string &src = "");
        RTLIL::SigBit Aoi4Gate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, const std::string &src = "");
index 210cca3f3c89d82b0aca25dbd8da94c7a6f058be..e9f3ecd440553cbd6c43c0861520dc80ee40e814 100644 (file)
@@ -475,7 +475,7 @@ struct SatGen
                        return true;
                }
 
-               if (cell->type == "$_MUX_" || cell->type == "$mux")
+               if (cell->type == "$_MUX_" || cell->type == "$mux" || cell->type == "$_NMUX_")
                {
                        std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
                        std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
@@ -483,7 +483,10 @@ struct SatGen
                        std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
 
                        std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
-                       ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy));
+                       if (cell->type == "$_NMUX_")
+                               ez->assume(ez->vec_eq(ez->vec_not(ez->vec_ite(s.at(0), b, a)), yy));
+                       else
+                               ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy));
 
                        if (model_undef)
                        {
index cb1bcf1be25885ad5e50f6017e1f8ca9f282aea0..0106059b6a37443d9237350cb0009d021c08e6c7 100644 (file)
@@ -494,6 +494,6 @@ Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLA
 \end{fixme}
 
 \begin{fixme}
-Add information about {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
+Add information about {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, {\tt \$\_OAI4\_}, and {\tt \$\_NMUX\_} cells.
 \end{fixme}
 
index 80b400e0c7529a74ecafc4da704339e47a126869..89920ed555d1ce0a0d1709caacc4bb337cb6f0ab 100644 (file)
@@ -241,6 +241,10 @@ struct statdata_t
                                        tran_cnt += 6*cnum;
                                else if (ctype.in("$_AOI4_", "$_OAI4_"))
                                        tran_cnt += 8*cnum;
+                               else if (ctype.in("$_NMUX_"))
+                                       tran_cnt += 10*cnum;
+                               else if (ctype.in("$_MUX_", "$_XOR_", "$_XNOR_"))
+                                       tran_cnt += 12*cnum;
                                else if (ctype.in("$_DFF_P_", "$_DFF_N_"))
                                        tran_cnt += 16*cnum;
                                else
index 19afb58cbcf83c1a011832d37e0e54914d662853..41a05c619aa3d616348d6f40ea80470837867c91 100644 (file)
@@ -82,6 +82,7 @@ enum class gate_type_t {
        G_ANDNOT,
        G_ORNOT,
        G_MUX,
+       G_NMUX,
        G_AOI3,
        G_OAI3,
        G_AOI4,
@@ -112,7 +113,7 @@ std::vector<gate_t> signal_list;
 std::map<RTLIL::SigBit, int> signal_map;
 std::map<RTLIL::SigBit, RTLIL::State> signal_init;
 pool<std::string> enabled_gates;
-bool recover_init;
+bool recover_init, cmos_cost;
 
 bool clk_polarity, en_polarity;
 RTLIL::SigSpec clk_sig, en_sig;
@@ -258,7 +259,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
                return;
        }
 
-       if (cell->type == "$_MUX_")
+       if (cell->type.in("$_MUX_", "$_NMUX_"))
        {
                RTLIL::SigSpec sig_a = cell->getPort("\\A");
                RTLIL::SigSpec sig_b = cell->getPort("\\B");
@@ -274,7 +275,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
                int mapped_b = map_signal(sig_b);
                int mapped_s = map_signal(sig_s);
 
-               map_signal(sig_y, G(MUX), mapped_a, mapped_b, mapped_s);
+               map_signal(sig_y, cell->type == "$_MUX_" ? G(MUX) : G(NMUX), mapped_a, mapped_b, mapped_s);
 
                module->remove(cell);
                return;
@@ -886,6 +887,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
                        fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id);
                        fprintf(f, "1-0 1\n");
                        fprintf(f, "-11 1\n");
+               } else if (si.type == G(NMUX)) {
+                       fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id);
+                       fprintf(f, "0-0 1\n");
+                       fprintf(f, "-01 1\n");
                } else if (si.type == G(AOI3)) {
                        fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id);
                        fprintf(f, "-00 1\n");
@@ -926,46 +931,52 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
        {
                log_header(design, "Executing ABC.\n");
 
+               auto cell_cost = [](IdString cell_type) {
+                       return get_cell_cost(cell_type, dict<RTLIL::IdString, RTLIL::Const>(), nullptr, nullptr, cmos_cost);
+               };
+
                buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str());
                f = fopen(buffer.c_str(), "wt");
                if (f == NULL)
                        log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno));
                fprintf(f, "GATE ZERO    1 Y=CONST0;\n");
                fprintf(f, "GATE ONE     1 Y=CONST1;\n");
-               fprintf(f, "GATE BUF    %d Y=A;                  PIN * NONINV  1 999 1 0 1 0\n", get_cell_cost("$_BUF_"));
-               fprintf(f, "GATE NOT    %d Y=!A;                 PIN * INV     1 999 1 0 1 0\n", get_cell_cost("$_NOT_"));
+               fprintf(f, "GATE BUF    %d Y=A;                  PIN * NONINV  1 999 1 0 1 0\n", cell_cost("$_BUF_"));
+               fprintf(f, "GATE NOT    %d Y=!A;                 PIN * INV     1 999 1 0 1 0\n", cell_cost("$_NOT_"));
                if (enabled_gates.empty() || enabled_gates.count("AND"))
-                       fprintf(f, "GATE AND    %d Y=A*B;                PIN * NONINV  1 999 1 0 1 0\n", get_cell_cost("$_AND_"));
+                       fprintf(f, "GATE AND    %d Y=A*B;                PIN * NONINV  1 999 1 0 1 0\n", cell_cost("$_AND_"));
                if (enabled_gates.empty() || enabled_gates.count("NAND"))
-                       fprintf(f, "GATE NAND   %d Y=!(A*B);             PIN * INV     1 999 1 0 1 0\n", get_cell_cost("$_NAND_"));
+                       fprintf(f, "GATE NAND   %d Y=!(A*B);             PIN * INV     1 999 1 0 1 0\n", cell_cost("$_NAND_"));
                if (enabled_gates.empty() || enabled_gates.count("OR"))
-                       fprintf(f, "GATE OR     %d Y=A+B;                PIN * NONINV  1 999 1 0 1 0\n", get_cell_cost("$_OR_"));
+                       fprintf(f, "GATE OR     %d Y=A+B;                PIN * NONINV  1 999 1 0 1 0\n", cell_cost("$_OR_"));
                if (enabled_gates.empty() || enabled_gates.count("NOR"))
-                       fprintf(f, "GATE NOR    %d Y=!(A+B);             PIN * INV     1 999 1 0 1 0\n", get_cell_cost("$_NOR_"));
+                       fprintf(f, "GATE NOR    %d Y=!(A+B);             PIN * INV     1 999 1 0 1 0\n", cell_cost("$_NOR_"));
                if (enabled_gates.empty() || enabled_gates.count("XOR"))
-                       fprintf(f, "GATE XOR    %d Y=(A*!B)+(!A*B);      PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XOR_"));
+                       fprintf(f, "GATE XOR    %d Y=(A*!B)+(!A*B);      PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_XOR_"));
                if (enabled_gates.empty() || enabled_gates.count("XNOR"))
-                       fprintf(f, "GATE XNOR   %d Y=(A*B)+(!A*!B);      PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XNOR_"));
+                       fprintf(f, "GATE XNOR   %d Y=(A*B)+(!A*!B);      PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_XNOR_"));
                if (enabled_gates.empty() || enabled_gates.count("ANDNOT"))
-                       fprintf(f, "GATE ANDNOT %d Y=A*!B;               PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ANDNOT_"));
+                       fprintf(f, "GATE ANDNOT %d Y=A*!B;               PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_ANDNOT_"));
                if (enabled_gates.empty() || enabled_gates.count("ORNOT"))
-                       fprintf(f, "GATE ORNOT  %d Y=A+!B;               PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ORNOT_"));
+                       fprintf(f, "GATE ORNOT  %d Y=A+!B;               PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_ORNOT_"));
                if (enabled_gates.empty() || enabled_gates.count("AOI3"))
-                       fprintf(f, "GATE AOI3   %d Y=!((A*B)+C);         PIN * INV     1 999 1 0 1 0\n", get_cell_cost("$_AOI3_"));
+                       fprintf(f, "GATE AOI3   %d Y=!((A*B)+C);         PIN * INV     1 999 1 0 1 0\n", cell_cost("$_AOI3_"));
                if (enabled_gates.empty() || enabled_gates.count("OAI3"))
-                       fprintf(f, "GATE OAI3   %d Y=!((A+B)*C);         PIN * INV     1 999 1 0 1 0\n", get_cell_cost("$_OAI3_"));
+                       fprintf(f, "GATE OAI3   %d Y=!((A+B)*C);         PIN * INV     1 999 1 0 1 0\n", cell_cost("$_OAI3_"));
                if (enabled_gates.empty() || enabled_gates.count("AOI4"))
-                       fprintf(f, "GATE AOI4   %d Y=!((A*B)+(C*D));     PIN * INV     1 999 1 0 1 0\n", get_cell_cost("$_AOI4_"));
+                       fprintf(f, "GATE AOI4   %d Y=!((A*B)+(C*D));     PIN * INV     1 999 1 0 1 0\n", cell_cost("$_AOI4_"));
                if (enabled_gates.empty() || enabled_gates.count("OAI4"))
-                       fprintf(f, "GATE OAI4   %d Y=!((A+B)*(C+D));     PIN * INV     1 999 1 0 1 0\n", get_cell_cost("$_OAI4_"));
+                       fprintf(f, "GATE OAI4   %d Y=!((A+B)*(C+D));     PIN * INV     1 999 1 0 1 0\n", cell_cost("$_OAI4_"));
                if (enabled_gates.empty() || enabled_gates.count("MUX"))
-                       fprintf(f, "GATE MUX    %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_MUX_"));
+                       fprintf(f, "GATE MUX    %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_MUX_"));
+               if (enabled_gates.empty() || enabled_gates.count("NMUX"))
+                       fprintf(f, "GATE NMUX   %d Y=!((A*B)+(S*B)+(!S*A)); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost("$_NMUX_"));
                if (map_mux4)
-                       fprintf(f, "GATE MUX4   %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*get_cell_cost("$_MUX_"));
+                       fprintf(f, "GATE MUX4   %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*cell_cost("$_MUX_"));
                if (map_mux8)
-                       fprintf(f, "GATE MUX8   %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*get_cell_cost("$_MUX_"));
+                       fprintf(f, "GATE MUX8   %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*cell_cost("$_MUX_"));
                if (map_mux16)
-                       fprintf(f, "GATE MUX16  %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*get_cell_cost("$_MUX_"));
+                       fprintf(f, "GATE MUX16  %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*cell_cost("$_MUX_"));
                fclose(f);
 
                if (!lut_costs.empty()) {
@@ -1066,8 +1077,8 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
                                        design->select(module, cell);
                                        continue;
                                }
-                               if (c->type == "\\MUX") {
-                                       RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX_");
+                               if (c->type == "\\MUX" || c->type == "\\NMUX") {
+                                       RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_");
                                        if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
                                        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)]));
@@ -1407,11 +1418,12 @@ struct AbcPass : public Pass {
                log("\n");
                log("        The following aliases can be used to reference common sets of gate types:\n");
                log("          simple: AND OR XOR MUX\n");
-               log("          cmos2: NAND NOR\n");
-               log("          cmos3: NAND NOR AOI3 OAI3\n");
-               log("          cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4\n");
-               log("          gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n");
-               log("          aig: AND NAND OR NOR ANDNOT ORNOT\n");
+               log("          cmos2:  NAND NOR\n");
+               log("          cmos3:  NAND NOR AOI3 OAI3\n");
+               log("          cmos4:  NAND NOR AOI3 OAI3 AOI4 OAI4\n");
+               log("          cmos:   NAND NOR AOI3 OAI3 AOI4 OAI4 NMUX MUX XOR XNOR\n");
+               log("          gates:  AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n");
+               log("          aig:    AND NAND OR NOR ANDNOT ORNOT\n");
                log("\n");
                log("        Prefix a gate type with a '-' to remove it from the list. For example\n");
                log("        the arguments 'AND,OR,XOR' and 'simple,-MUX' are equivalent.\n");
@@ -1489,6 +1501,7 @@ struct AbcPass : public Pass {
                map_mux8 = false;
                map_mux16 = false;
                enabled_gates.clear();
+               cmos_cost = false;
 
 #ifdef _WIN32
 #ifndef ABCEXTERNAL
@@ -1629,11 +1642,15 @@ struct AbcPass : public Pass {
                                                goto ok_alias;
                                        }
                                        if (g == "cmos2") {
+                                               if (!remove_gates)
+                                                       cmos_cost = true;
                                                gate_list.push_back("NAND");
                                                gate_list.push_back("NOR");
                                                goto ok_alias;
                                        }
                                        if (g == "cmos3") {
+                                               if (!remove_gates)
+                                                       cmos_cost = true;
                                                gate_list.push_back("NAND");
                                                gate_list.push_back("NOR");
                                                gate_list.push_back("AOI3");
@@ -1641,6 +1658,8 @@ struct AbcPass : public Pass {
                                                goto ok_alias;
                                        }
                                        if (g == "cmos4") {
+                                               if (!remove_gates)
+                                                       cmos_cost = true;
                                                gate_list.push_back("NAND");
                                                gate_list.push_back("NOR");
                                                gate_list.push_back("AOI3");
@@ -1649,6 +1668,21 @@ struct AbcPass : public Pass {
                                                gate_list.push_back("OAI4");
                                                goto ok_alias;
                                        }
+                                       if (g == "cmos") {
+                                               if (!remove_gates)
+                                                       cmos_cost = true;
+                                               gate_list.push_back("NAND");
+                                               gate_list.push_back("NOR");
+                                               gate_list.push_back("AOI3");
+                                               gate_list.push_back("OAI3");
+                                               gate_list.push_back("AOI4");
+                                               gate_list.push_back("OAI4");
+                                               gate_list.push_back("NMUX");
+                                               gate_list.push_back("MUX");
+                                               gate_list.push_back("XOR");
+                                               gate_list.push_back("XNOR");
+                                               goto ok_alias;
+                                       }
                                        if (g == "gates") {
                                                gate_list.push_back("AND");
                                                gate_list.push_back("NAND");
index 591bc43dd5651ee4cfcbf076706f27a4f88b5647..b541ceb6b8a7723199c56fefe8d2eb2ff16794cc 100644 (file)
@@ -86,7 +86,7 @@ struct ExtractFaWorker
                for (auto cell : module->selected_cells())
                {
                        if (cell->type.in( "$_BUF_", "$_NOT_", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_",
-                                       "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", "$_MUX_",
+                                       "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", "$_MUX_", "$_NMUX_",
                                        "$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_"))
                        {
                                SigBit y = sigmap(SigBit(cell->getPort("\\Y")));
index 289673e82c4ee10d8dc2ad3e06c4aba30b9156eb..64720e598595f710108132ce0ac40aff8ca997c1 100644 (file)
@@ -228,6 +228,25 @@ output Y;
 assign Y = S ? B : A;
 endmodule
 
+//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//-     $_NMUX_ (A, B, S, Y)
+//-
+//- A 2-input inverting MUX gate.
+//-
+//- Truth table:    A B S | Y
+//-                -------+---
+//-                 0 - 0 | 1
+//-                 1 - 0 | 0
+//-                 - 0 1 | 1
+//-                 - 1 1 | 0
+//-
+module \$_NMUX_ (A, B, S, Y);
+input A, B, S;
+output Y;
+assign Y = S ? !B : !A;
+endmodule
+
 //  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 //-
 //-     $_MUX4_ (A, B, C, D, S, T, Y)