aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG1
-rw-r--r--backends/blif/blif.cc7
-rw-r--r--backends/btor/btor.cc8
-rw-r--r--backends/simplec/simplec.cc6
-rw-r--r--backends/smt2/smt2.cc1
-rw-r--r--backends/smv/smv.cc7
-rw-r--r--backends/verilog/verilog_backend.cc14
-rw-r--r--kernel/cellaigs.cc2
-rw-r--r--kernel/celltypes.h1
-rw-r--r--kernel/consteval.h7
-rw-r--r--kernel/cost.h34
-rw-r--r--kernel/rtlil.cc2
-rw-r--r--kernel/rtlil.h2
-rw-r--r--kernel/satgen.h7
-rw-r--r--manual/CHAPTER_CellLib.tex2
-rw-r--r--passes/cmds/stat.cc4
-rw-r--r--passes/techmap/abc.cc90
-rw-r--r--passes/techmap/extract_fa.cc2
-rw-r--r--techlibs/common/simcells.v19
19 files changed, 174 insertions, 42 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 00b10c591..9e9bda6e9 100644
--- 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
--------------------------
diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc
index a1761b662..f32b0f533 100644
--- a/backends/blif/blif.cc
+++ b/backends/blif/blif.cc
@@ -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")));
diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc
index a507b120b..7bacce2af 100644
--- a/backends/btor/btor.cc
+++ b/backends/btor/btor.cc
@@ -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;
}
diff --git a/backends/simplec/simplec.cc b/backends/simplec/simplec.cc
index 6f2ccbe20..54dbb84af 100644
--- a/backends/simplec/simplec.cc
+++ b/backends/simplec/simplec.cc
@@ -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) +
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
index e318a4051..ddd680782 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -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)))");
diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc
index d75456c1b..e9586fae0 100644
--- a/backends/smv/smv.cc
+++ b/backends/smv/smv.cc
@@ -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")),
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index e0b3a6f80..776f4eacb 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -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"));
diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc
index 26c625f89..fbc6d045e 100644
--- a/kernel/cellaigs.cc
+++ b/kernel/cellaigs.cc
@@ -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;
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index 758661c02..d2594bc46 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -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);
diff --git a/kernel/consteval.h b/kernel/consteval.h
index 154373a8d..f70dfa0fb 100644
--- a/kernel/consteval.h
+++ b/kernel/consteval.h
@@ -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)
diff --git a/kernel/cost.h b/kernel/cost.h
index 41a09eb63..e8e077ff5 100644
--- a/kernel/cost.h
+++ b/kernel/cost.h
@@ -24,10 +24,10 @@
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
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index a09f4a0d1..ba8472ec1 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -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)
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 712250b3e..1cfe71473 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -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 = "");
diff --git a/kernel/satgen.h b/kernel/satgen.h
index 210cca3f3..e9f3ecd44 100644
--- a/kernel/satgen.h
+++ b/kernel/satgen.h
@@ -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)
{
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index cb1bcf1be..0106059b6 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -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}
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 80b400e0c..89920ed55 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -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
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 19afb58cb..41a05c619 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -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");
diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc
index 591bc43dd..b541ceb6b 100644
--- a/passes/techmap/extract_fa.cc
+++ b/passes/techmap/extract_fa.cc
@@ -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")));
diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v
index 289673e82..64720e598 100644
--- a/techlibs/common/simcells.v
+++ b/techlibs/common/simcells.v
@@ -230,6 +230,25 @@ 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)
//-
//- A 4-input MUX gate.