From 05cdd58c8dc73968992681d0ee1cbfa89880b94f Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Wed, 17 May 2017 09:08:29 +0200
Subject: Add $_ANDNOT_ and $_ORNOT_ gates

---
 backends/blif/blif.cc               | 12 +++++++
 backends/simplec/simplec.cc         | 16 +++++-----
 backends/smt2/smt2.cc               |  2 ++
 backends/smv/smv.cc                 | 10 ++++--
 backends/verilog/verilog_backend.cc | 10 +++---
 kernel/cellaigs.cc                  | 16 ++++++++--
 kernel/celltypes.h                  |  2 ++
 kernel/cost.h                       | 28 +++++++++--------
 kernel/rtlil.cc                     | 56 +++++++++++++++++----------------
 kernel/rtlil.h                      | 28 +++++++++--------
 kernel/satgen.h                     | 19 +++++++++++-
 manual/CHAPTER_CellLib.tex          |  3 +-
 passes/techmap/abc.cc               | 62 ++++++++++++++++++++++++-------------
 techlibs/common/simcells.v          | 38 +++++++++++++++++++++++
 14 files changed, 211 insertions(+), 91 deletions(-)

diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc
index 4dbaca0bd..f9230a1e6 100644
--- a/backends/blif/blif.cc
+++ b/backends/blif/blif.cc
@@ -279,6 +279,18 @@ struct BlifDumper
 				continue;
 			}
 
+			if (!config->icells_mode && cell->type == "$_ANDNOT_") {
+				f << stringf(".names %s %s %s\n10 1\n",
+						cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
+				continue;
+			}
+
+			if (!config->icells_mode && cell->type == "$_ORNOT_") {
+				f << stringf(".names %s %s %s\n1- 1\n-0 1\n",
+						cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
+				continue;
+			}
+
 			if (!config->icells_mode && cell->type == "$_AOI3_") {
 				f << stringf(".names %s %s %s %s\n-00 1\n0-0 1\n",
 						cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\C")), cstr(cell->getPort("\\Y")));
diff --git a/backends/simplec/simplec.cc b/backends/simplec/simplec.cc
index 15399831e..5768e3499 100644
--- a/backends/simplec/simplec.cc
+++ b/backends/simplec/simplec.cc
@@ -397,7 +397,7 @@ struct SimplecWorker
 			return;
 		}
 
-		if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
+		if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
 		{
 			SigBit a = sigmaps.at(work->module)(cell->getPort("\\A"));
 			SigBit b = sigmaps.at(work->module)(cell->getPort("\\B"));
@@ -407,12 +407,14 @@ struct SimplecWorker
 			string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0";
 			string expr;
 
-			if (cell->type == "$_AND_")  expr = stringf("%s & %s",    a_expr.c_str(), b_expr.c_str());
-			if (cell->type == "$_NAND_") expr = stringf("!(%s & %s)", a_expr.c_str(), b_expr.c_str());
-			if (cell->type == "$_OR_")   expr = stringf("%s | %s",    a_expr.c_str(), b_expr.c_str());
-			if (cell->type == "$_NOR_")  expr = stringf("!(%s | %s)", a_expr.c_str(), b_expr.c_str());
-			if (cell->type == "$_XOR_")  expr = stringf("%s ^ %s",    a_expr.c_str(), b_expr.c_str());
-			if (cell->type == "$_XNOR_") expr = stringf("!(%s ^ %s)", a_expr.c_str(), b_expr.c_str());
+			if (cell->type == "$_AND_")    expr = stringf("%s & %s",    a_expr.c_str(), b_expr.c_str());
+			if (cell->type == "$_NAND_")   expr = stringf("!(%s & %s)", a_expr.c_str(), b_expr.c_str());
+			if (cell->type == "$_OR_")     expr = stringf("%s | %s",    a_expr.c_str(), b_expr.c_str());
+			if (cell->type == "$_NOR_")    expr = stringf("!(%s | %s)", a_expr.c_str(), b_expr.c_str());
+			if (cell->type == "$_XOR_")    expr = stringf("%s ^ %s",    a_expr.c_str(), b_expr.c_str());
+			if (cell->type == "$_XNOR_")   expr = stringf("!(%s ^ %s)", a_expr.c_str(), b_expr.c_str());
+			if (cell->type == "$_ANDNOT_") expr = stringf("%s & (!%s)", a_expr.c_str(), b_expr.c_str());
+			if (cell->type == "$_ORNOT_")  expr = stringf("%s | (!%s)", a_expr.c_str(), b_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 372dbeb57..df189fc3f 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -434,6 +434,8 @@ struct Smt2Worker
 		if (cell->type == "$_NOR_") return export_gate(cell, "(not (or A B))");
 		if (cell->type == "$_XOR_") return export_gate(cell, "(xor A B)");
 		if (cell->type == "$_XNOR_") return export_gate(cell, "(not (xor A B))");
+		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 == "$_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))");
diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc
index 162ce4906..768969e6b 100644
--- a/backends/smv/smv.cc
+++ b/backends/smv/smv.cc
@@ -507,15 +507,19 @@ struct SmvWorker
 				continue;
 			}
 
-			if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
+			if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
 			{
 				string op;
 
-				if (cell->type.in("$_AND_", "$_NAND_")) op = "&";
-				if (cell->type.in("$_OR_", "$_NOR_")) op = "|";
+				if (cell->type.in("$_AND_", "$_NAND_", "$_ANDNOT_")) op = "&";
+				if (cell->type.in("$_OR_", "$_NOR_", "$_ORNOT_")) op = "|";
 				if (cell->type.in("$_XOR_"))  op = "xor";
 				if (cell->type.in("$_XNOR_"))  op = "xnor";
 
+				if (cell->type.in("$_ANDNOT_", "$_ORNOT_"))
+					assignments.push_back(stringf("%s := %s %s (!%s);", lvalue(cell->getPort("\\Y")),
+							rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
+				else
 				if (cell->type.in("$_NAND_", "$_NOR_"))
 					assignments.push_back(stringf("%s := !(%s %s %s);", lvalue(cell->getPort("\\Y")),
 							rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B"))));
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index 191553324..bb312944e 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -470,7 +470,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
 		return true;
 	}
 
-	if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) {
+	if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) {
 		f << stringf("%s" "assign ", indent.c_str());
 		dump_sigspec(f, cell->getPort("\\Y"));
 		f << stringf(" = ");
@@ -478,16 +478,18 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
 			f << stringf("~(");
 		dump_cell_expr_port(f, cell, "A", false);
 		f << stringf(" ");
-		if (cell->type.in("$_AND_", "$_NAND_"))
+		if (cell->type.in("$_AND_", "$_NAND_", "$_ANDNOT_"))
 			f << stringf("&");
-		if (cell->type.in("$_OR_", "$_NOR_"))
+		if (cell->type.in("$_OR_", "$_NOR_", "$_ORNOT_"))
 			f << stringf("|");
 		if (cell->type.in("$_XOR_", "$_XNOR_"))
 			f << stringf("^");
 		dump_attributes(f, "", cell->attributes, ' ');
 		f << stringf(" ");
+		if (cell->type.in("$_ANDNOT_", "$_ORNOT_"))
+			f << stringf("~(");
 		dump_cell_expr_port(f, cell, "B", false);
-		if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_"))
+		if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
 			f << stringf(")");
 		f << stringf(";\n");
 		return true;
diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc
index 41f81355d..5fd76afe5 100644
--- a/kernel/cellaigs.cc
+++ b/kernel/cellaigs.cc
@@ -202,6 +202,16 @@ struct AigMaker
 		return or_gate(and_gate(A, B), nor_gate(A, B));
 	}
 
+	int andnot_gate(int A, int B)
+	{
+		return and_gate(A, not_gate(B));
+	}
+
+	int ornot_gate(int A, int B)
+	{
+		return or_gate(A, not_gate(B));
+	}
+
 	int mux_gate(int A, int B, int S)
 	{
 		return or_gate(and_gate(A, not_gate(S)), and_gate(B, S));
@@ -290,7 +300,7 @@ Aig::Aig(Cell *cell)
 		goto optimize;
 	}
 
-	if (cell->type.in("$and", "$_AND_", "$_NAND_", "$or", "$_OR_", "$_NOR_", "$xor", "$xnor", "$_XOR_", "$_XNOR_"))
+	if (cell->type.in("$and", "$_AND_", "$_NAND_", "$or", "$_OR_", "$_NOR_", "$xor", "$xnor", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
 	{
 		for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) {
 			int A = mk.inport("\\A", i);
@@ -300,7 +310,9 @@ Aig::Aig(Cell *cell)
 			        cell->type.in("$or", "$_OR_")     ? mk.or_gate(A, B) :
 			        cell->type.in("$_NOR_")           ? mk.nor_gate(A, B) :
 			        cell->type.in("$xor", "$_XOR_")   ? mk.xor_gate(A, B) :
-			        cell->type.in("$xnor", "$_XNOR_") ? mk.xnor_gate(A, B) : -1;
+			        cell->type.in("$xnor", "$_XNOR_") ? mk.xnor_gate(A, B) :
+			        cell->type.in("$_ANDNOT_")        ? mk.andnot_gate(A, B) :
+			        cell->type.in("$_ORNOT_")         ? mk.ornot_gate(A, B) : -1;
 			mk.outport(Y, "\\Y", i);
 		}
 		goto optimize;
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index c43f685ac..b8a4cc74c 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -167,6 +167,8 @@ struct CellTypes
 		setup_type("$_NOR_",  {A, B}, {Y}, true);
 		setup_type("$_XOR_", {A, B}, {Y}, true);
 		setup_type("$_XNOR_", {A, B}, {Y}, true);
+		setup_type("$_ANDNOT_", {A, B}, {Y}, true);
+		setup_type("$_ORNOT_", {A, B}, {Y}, true);
 		setup_type("$_MUX_", {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);
diff --git a/kernel/cost.h b/kernel/cost.h
index 4f12889f4..84fd6cd6d 100644
--- a/kernel/cost.h
+++ b/kernel/cost.h
@@ -30,19 +30,21 @@ int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const
 		RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr)
 {
 	static dict<RTLIL::IdString, int> gate_cost = {
-		{ "$_BUF_",   1 },
-		{ "$_NOT_",   2 },
-		{ "$_AND_",   4 },
-		{ "$_NAND_",  4 },
-		{ "$_OR_",    4 },
-		{ "$_NOR_",   4 },
-		{ "$_XOR_",   8 },
-		{ "$_XNOR_",  8 },
-		{ "$_AOI3_",  6 },
-		{ "$_OAI3_",  6 },
-		{ "$_AOI4_",  8 },
-		{ "$_OAI4_",  8 },
-		{ "$_MUX_",   4 }
+		{ "$_BUF_",    1 },
+		{ "$_NOT_",    2 },
+		{ "$_AND_",    4 },
+		{ "$_NAND_",   4 },
+		{ "$_OR_",     4 },
+		{ "$_NOR_",    4 },
+		{ "$_ANDNOT_", 4 },
+		{ "$_ORNOT_",  4 },
+		{ "$_XOR_",    8 },
+		{ "$_XNOR_",   8 },
+		{ "$_AOI3_",   6 },
+		{ "$_OAI3_",   6 },
+		{ "$_AOI4_",   8 },
+		{ "$_OAI4_",   8 },
+		{ "$_MUX_",    4 }
 	};
 
 	if (gate_cost.count(type))
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 6ce3f1376..93cfef80e 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -1053,19 +1053,21 @@ namespace {
 				return;
 			}
 
-			if (cell->type == "$_BUF_")  { check_gate("AY"); return; }
-			if (cell->type == "$_NOT_")  { check_gate("AY"); return; }
-			if (cell->type == "$_AND_")  { check_gate("ABY"); return; }
-			if (cell->type == "$_NAND_") { check_gate("ABY"); return; }
-			if (cell->type == "$_OR_")   { check_gate("ABY"); return; }
-			if (cell->type == "$_NOR_")  { check_gate("ABY"); return; }
-			if (cell->type == "$_XOR_")  { check_gate("ABY"); return; }
-			if (cell->type == "$_XNOR_") { check_gate("ABY"); return; }
-			if (cell->type == "$_MUX_")  { 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; }
-			if (cell->type == "$_OAI4_") { check_gate("ABCDY"); return; }
+			if (cell->type == "$_BUF_")    { check_gate("AY"); return; }
+			if (cell->type == "$_NOT_")    { check_gate("AY"); return; }
+			if (cell->type == "$_AND_")    { check_gate("ABY"); return; }
+			if (cell->type == "$_NAND_")   { check_gate("ABY"); return; }
+			if (cell->type == "$_OR_")     { check_gate("ABY"); return; }
+			if (cell->type == "$_NOR_")    { check_gate("ABY"); return; }
+			if (cell->type == "$_XOR_")    { check_gate("ABY"); return; }
+			if (cell->type == "$_XNOR_")   { check_gate("ABY"); return; }
+			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 == "$_AOI3_")   { check_gate("ABCY"); return; }
+			if (cell->type == "$_OAI3_")   { check_gate("ABCY"); return; }
+			if (cell->type == "$_AOI4_")   { check_gate("ABCDY"); return; }
+			if (cell->type == "$_OAI4_")   { check_gate("ABCDY"); return; }
 
 			if (cell->type == "$_TBUF_")  { check_gate("AYE"); return; }
 
@@ -1729,19 +1731,21 @@ DEF_METHOD(Pmux,     "$pmux",       1)
 		add ## _func(name, sig1, sig2, sig3, sig4, sig5); \
 		return sig5;                                      \
 	}
-DEF_METHOD_2(BufGate,  "$_BUF_",  A, Y)
-DEF_METHOD_2(NotGate,  "$_NOT_",  A, Y)
-DEF_METHOD_3(AndGate,  "$_AND_",  A, B, Y)
-DEF_METHOD_3(NandGate, "$_NAND_", A, B, Y)
-DEF_METHOD_3(OrGate,   "$_OR_",   A, B, Y)
-DEF_METHOD_3(NorGate,  "$_NOR_",  A, B, Y)
-DEF_METHOD_3(XorGate,  "$_XOR_",  A, B, Y)
-DEF_METHOD_3(XnorGate, "$_XNOR_", A, B, Y)
-DEF_METHOD_4(MuxGate,  "$_MUX_",  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)
-DEF_METHOD_5(Oai4Gate, "$_OAI4_", A, B, C, D, Y)
+DEF_METHOD_2(BufGate,    "$_BUF_",    A, Y)
+DEF_METHOD_2(NotGate,    "$_NOT_",    A, Y)
+DEF_METHOD_3(AndGate,    "$_AND_",    A, B, Y)
+DEF_METHOD_3(NandGate,   "$_NAND_",   A, B, Y)
+DEF_METHOD_3(OrGate,     "$_OR_",     A, B, Y)
+DEF_METHOD_3(NorGate,    "$_NOR_",    A, B, Y)
+DEF_METHOD_3(XorGate,    "$_XOR_",    A, B, Y)
+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(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)
+DEF_METHOD_5(Oai4Gate,   "$_OAI4_",   A, B, C, D, Y)
 #undef DEF_METHOD_2
 #undef DEF_METHOD_3
 #undef DEF_METHOD_4
diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index ab8771256..034ce9c0c 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -1024,19 +1024,21 @@ public:
 	RTLIL::Cell* addDlatchsr (RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
 			RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity = true, bool set_polarity = true, bool clr_polarity = true);
 
-	RTLIL::Cell* addBufGate  (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y);
-	RTLIL::Cell* addNotGate  (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y);
-	RTLIL::Cell* addAndGate  (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
-	RTLIL::Cell* addNandGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
-	RTLIL::Cell* addOrGate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
-	RTLIL::Cell* addNorGate  (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
-	RTLIL::Cell* addXorGate  (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
-	RTLIL::Cell* addXnorGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
-	RTLIL::Cell* addMuxGate  (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y);
-	RTLIL::Cell* addAoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y);
-	RTLIL::Cell* addOai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y);
-	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);
-	RTLIL::Cell* addOai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y);
+	RTLIL::Cell* addBufGate    (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y);
+	RTLIL::Cell* addNotGate    (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_y);
+	RTLIL::Cell* addAndGate    (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+	RTLIL::Cell* addNandGate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+	RTLIL::Cell* addOrGate     (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+	RTLIL::Cell* addNorGate    (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+	RTLIL::Cell* addXorGate    (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+	RTLIL::Cell* addXnorGate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+	RTLIL::Cell* addAndnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+	RTLIL::Cell* addOrnotGate  (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y);
+	RTLIL::Cell* addMuxGate    (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y);
+	RTLIL::Cell* addAoi3Gate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y);
+	RTLIL::Cell* addOai3Gate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y);
+	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);
+	RTLIL::Cell* addOai4Gate   (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y);
 
 	RTLIL::Cell* addFfGate     (RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q);
 	RTLIL::Cell* addDffGate    (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true);
diff --git a/kernel/satgen.h b/kernel/satgen.h
index 25a22fd8a..8d760fff7 100644
--- a/kernel/satgen.h
+++ b/kernel/satgen.h
@@ -310,7 +310,7 @@ struct SatGen
 			arith_undef_handled = true;
 		}
 
-		if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_",
+		if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_",
 				"$and", "$or", "$xor", "$xnor", "$add", "$sub"))
 		{
 			std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
@@ -332,6 +332,10 @@ struct SatGen
 				ez->assume(ez->vec_eq(ez->vec_xor(a, b), yy));
 			if (cell->type == "$xnor" || cell->type == "$_XNOR_")
 				ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(a, b)), yy));
+			if (cell->type == "$_ANDNOT_")
+				ez->assume(ez->vec_eq(ez->vec_and(a, ez->vec_not(b)), yy));
+			if (cell->type == "$_ORNOT_")
+				ez->assume(ez->vec_eq(ez->vec_or(a, ez->vec_not(b)), yy));
 			if (cell->type == "$add")
 				ez->assume(ez->vec_eq(ez->vec_add(a, b), yy));
 			if (cell->type == "$sub")
@@ -360,6 +364,19 @@ struct SatGen
 					std::vector<int> yX = ez->vec_or(undef_a, undef_b);
 					ez->assume(ez->vec_eq(yX, undef_y));
 				}
+				else if (cell->type == "$_ANDNOT_") {
+					std::vector<int> a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a));
+					std::vector<int> b1 = ez->vec_and(b, ez->vec_not(undef_b));
+					std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b1)));
+					ez->assume(ez->vec_eq(yX, undef_y));
+				}
+
+				else if (cell->type == "$_ORNOT_") {
+					std::vector<int> a1 = ez->vec_and(a, ez->vec_not(undef_a));
+					std::vector<int> b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b));
+					std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b0)));
+					ez->assume(ez->vec_eq(yX, undef_y));
+				}
 				else
 					log_abort();
 
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index b2ba1fd88..c36e61b05 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -449,6 +449,7 @@ Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLA
 \end{fixme}
 
 \begin{fixme}
-Add information about {\tt \$\_NAND\_}, {\tt \$\_NOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
+Add information about {\tt \$\_NAND\_}, {\tt \$\_NOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_ORNOT\_},
+{\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
 \end{fixme}
 
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index a1cea3aaf..386398e45 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -74,6 +74,8 @@ enum class gate_type_t {
 	G_NOR,
 	G_XOR,
 	G_XNOR,
+	G_ANDNOT,
+	G_ORNOT,
 	G_MUX,
 	G_AOI3,
 	G_OAI3,
@@ -207,7 +209,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
 		return;
 	}
 
-	if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_"))
+	if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
 	{
 		RTLIL::SigSpec sig_a = cell->getPort("\\A");
 		RTLIL::SigSpec sig_b = cell->getPort("\\B");
@@ -232,6 +234,10 @@ void extract_cell(RTLIL::Cell *cell, bool keepff)
 			map_signal(sig_y, G(XOR), mapped_a, mapped_b);
 		else if (cell->type == "$_XNOR_")
 			map_signal(sig_y, G(XNOR), mapped_a, mapped_b);
+		else if (cell->type == "$_ANDNOT_")
+			map_signal(sig_y, G(ANDNOT), mapped_a, mapped_b);
+		else if (cell->type == "$_ORNOT_")
+			map_signal(sig_y, G(ORNOT), mapped_a, mapped_b);
 		else
 			log_abort();
 
@@ -813,6 +819,13 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 			fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
 			fprintf(f, "00 1\n");
 			fprintf(f, "11 1\n");
+		} else if (si.type == G(ANDNOT)) {
+			fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+			fprintf(f, "10 1\n");
+		} else if (si.type == G(ORNOT)) {
+			fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id);
+			fprintf(f, "1- 1\n");
+			fprintf(f, "-0 1\n");
 		} else if (si.type == G(MUX)) {
 			fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id);
 			fprintf(f, "1-0 1\n");
@@ -858,38 +871,42 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 		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 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_"));
 		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", get_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", get_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", get_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", get_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", get_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", get_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_"));
+		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_"));
 		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", get_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", get_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", get_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", get_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", get_cell_cost("$_MUX_"));
 		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*get_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*get_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*get_cell_cost("$_MUX_"));
 		fclose(f);
 
 		if (!lut_costs.empty()) {
@@ -961,7 +978,8 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 					design->select(module, cell);
 					continue;
 				}
-				if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR" || c->type == "\\NAND" || c->type == "\\NOR" || c->type == "\\XNOR") {
+				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) + "_");
 					if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx;
 					cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]));
@@ -1297,7 +1315,7 @@ struct AbcPass : public Pass {
 		// log("\n");
 		log("    -g type1,type2,...\n");
 		log("        Map the the specified list of gate types. Supported gates types are:\n");
-		log("        AND, NAND, OR, NOR, XOR, XNOR, MUX, AOI3, OAI3, AOI4, OAI4.\n");
+		log("        AND, NAND, OR, NOR, XOR, XNOR, ANDNOT, ORNOT, MUX, AOI3, OAI3, AOI4, OAI4.\n");
 		log("        (The NOT gate is always added to this list automatically.)\n");
 		log("\n");
 		log("    -dff\n");
@@ -1468,6 +1486,8 @@ struct AbcPass : public Pass {
 					if (g == "NOR") goto ok_gate;
 					if (g == "XOR") goto ok_gate;
 					if (g == "XNOR") goto ok_gate;
+					if (g == "ANDNOT") goto ok_gate;
+					if (g == "ORNOT") goto ok_gate;
 					if (g == "MUX") goto ok_gate;
 					if (g == "AOI3") goto ok_gate;
 					if (g == "OAI3") goto ok_gate;
diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v
index e770c5453..937512e7c 100644
--- a/techlibs/common/simcells.v
+++ b/techlibs/common/simcells.v
@@ -173,6 +173,44 @@ output Y;
 assign Y = ~(A ^ B);
 endmodule
 
+//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//-     $_ANDNOT_ (A, B, Y)
+//-
+//- A 2-input AND-NOT gate.
+//-
+//- Truth table:    A B | Y
+//-                -----+---
+//-                 0 0 | 0
+//-                 0 1 | 0
+//-                 1 0 | 1
+//-                 1 1 | 0
+//-
+module \$_ANDNOT_ (A, B, Y);
+input A, B;
+output Y;
+assign Y = A & (~B);
+endmodule
+
+//  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+//-
+//-     $_ORNOT_ (A, B, Y)
+//-
+//- A 2-input OR-NOT gate.
+//-
+//- Truth table:    A B | Y
+//-                -----+---
+//-                 0 0 | 1
+//-                 0 1 | 0
+//-                 1 0 | 1
+//-                 1 1 | 1
+//-
+module \$_ORNOT_ (A, B, Y);
+input A, B;
+output Y;
+assign Y = A | (~B);
+endmodule
+
 //  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 //-
 //-     $_MUX_ (A, B, S, Y)
-- 
cgit v1.2.3