From 25ff27e37fcb12c6a298267eda2464431304d713 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 12:34:04 -0700
Subject: [PATCH 01/53] SigSpec::extract to take negative lengths

---
 kernel/rtlil.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index a09f4a0d1..85b013bdc 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -3353,7 +3353,7 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const
 {
 	unpack();
 	cover("kernel.rtlil.sigspec.extract_pos");
-	return std::vector<RTLIL::SigBit>(bits_.begin() + offset, bits_.begin() + offset + length);
+	return std::vector<RTLIL::SigBit>(bits_.begin() + offset, length >= 0 ? bits_.begin() + offset + length : bits_.end() + length + 1);
 }
 
 void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal)

From 3839bd50f28a16f1253a56d5871465763e72180c Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 12:43:02 -0700
Subject: [PATCH 02/53] Add test

---
 tests/various/wreduce.ys | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
 create mode 100644 tests/various/wreduce.ys

diff --git a/tests/various/wreduce.ys b/tests/various/wreduce.ys
new file mode 100644
index 000000000..0b5403fa1
--- /dev/null
+++ b/tests/various/wreduce.ys
@@ -0,0 +1,22 @@
+
+read_verilog <<EOT
+module wreduce_add_test(input [3:0] i, input [7:0] j, output [7:0] o);
+    assign o = (i << 4) + j;
+endmodule
+EOT
+
+hierarchy -top wreduce_add_test
+proc
+design -save gold
+
+prep
+
+select -assert-count 1 t:$add r:A_WIDTH=4 r:B_WIDTH=4 %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter

From 4e9b1d36fa896a8280e9c4295cf9a4e2a084f927 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 12:50:11 -0700
Subject: [PATCH 03/53] Add tests for sub too

---
 tests/various/wreduce.ys | 49 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/tests/various/wreduce.ys b/tests/various/wreduce.ys
index 0b5403fa1..ee03e008d 100644
--- a/tests/various/wreduce.ys
+++ b/tests/various/wreduce.ys
@@ -5,7 +5,7 @@ module wreduce_add_test(input [3:0] i, input [7:0] j, output [7:0] o);
 endmodule
 EOT
 
-hierarchy -top wreduce_add_test
+hierarchy -auto-top
 proc
 design -save gold
 
@@ -20,3 +20,50 @@ design -import gate -as gate
 
 miter -equiv -flatten -make_assert -make_outputs gold gate miter
 sat -verify -prove-asserts -show-ports miter
+
+
+### X - 0
+read_verilog <<EOT
+module wreduce_sub_test1(input [3:0] i, input [7:0] j, output [7:0] o);
+    assign o = j - (i << 4);
+endmodule
+EOT
+
+hierarchy -auto-top
+proc
+design -save gold
+
+prep
+
+select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+### 0 - X
+read_verilog <<EOT
+module wreduce_sub_test1(input [3:0] i, input [7:0] j, output [7:0] o);
+    assign o = (i << 4) - j;
+endmodule
+EOT
+
+hierarchy -auto-top
+proc
+design -save gold
+
+prep
+
+select -assert-count 1 t:$sub r:A_WIDTH=8 r:B_WIDTH=8 %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter

From fc0e36d1c02c22a578020aa1f2c90c86844fefe6 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 12:50:21 -0700
Subject: [PATCH 04/53] wreduce for $sub

---
 passes/opt/wreduce.cc | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 1fbc41082..e8c2cb726 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -365,6 +365,29 @@ struct WreduceWorker
 			}
 		}
 
+		if (cell->type.in("$add", "$sub")) {
+			SigSpec A = cell->getPort("\\A");
+			SigSpec B = cell->getPort("\\B");
+			bool sub = cell->type == "$sub";
+
+			int i;
+			for (i = 0; i < GetSize(sig); i++) {
+				if (B[i] != S0 && (sub || A[i] != S0))
+					break;
+				if (B[i] == S0)
+					module->connect(sig[i], A[i]);
+				else if (A[i] == S0)
+					module->connect(sig[i], B[i]);
+				else log_abort();
+			}
+			if (i > 0) {
+				cell->setPort("\\A", A.extract(i, -1));
+				cell->setPort("\\B", B.extract(i, -1));
+				sig.remove(0, i);
+				bits_removed += i;
+			}
+		}
+
 		if (GetSize(sig) == 0) {
 			log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
 			module->remove(cell);

From 415a2716df8c41193650804158281ef73e7fc655 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 12:53:18 -0700
Subject: [PATCH 05/53] Be more explicit

---
 tests/various/wreduce.ys | 35 +++++++++++++++++++++++++++++------
 1 file changed, 29 insertions(+), 6 deletions(-)

diff --git a/tests/various/wreduce.ys b/tests/various/wreduce.ys
index ee03e008d..f9e5ed4e3 100644
--- a/tests/various/wreduce.ys
+++ b/tests/various/wreduce.ys
@@ -1,6 +1,6 @@
 
 read_verilog <<EOT
-module wreduce_add_test(input [3:0] i, input [7:0] j, output [7:0] o);
+module wreduce_add_test(input [3:0] i, input [7:0] j, output [8:0] o);
     assign o = (i << 4) + j;
 endmodule
 EOT
@@ -11,7 +11,7 @@ design -save gold
 
 prep
 
-select -assert-count 1 t:$add r:A_WIDTH=4 r:B_WIDTH=4 %i %i
+select -assert-count 1 t:$add r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
 
 design -stash gate
 
@@ -24,7 +24,7 @@ sat -verify -prove-asserts -show-ports miter
 
 ### X - 0
 read_verilog <<EOT
-module wreduce_sub_test1(input [3:0] i, input [7:0] j, output [7:0] o);
+module wreduce_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o);
     assign o = j - (i << 4);
 endmodule
 EOT
@@ -35,7 +35,7 @@ design -save gold
 
 prep
 
-select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 %i %i
+select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
 
 design -stash gate
 
@@ -47,7 +47,7 @@ sat -verify -prove-asserts -show-ports miter
 
 ### 0 - X
 read_verilog <<EOT
-module wreduce_sub_test1(input [3:0] i, input [7:0] j, output [7:0] o);
+module wreduce_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o);
     assign o = (i << 4) - j;
 endmodule
 EOT
@@ -58,7 +58,30 @@ design -save gold
 
 prep
 
-select -assert-count 1 t:$sub r:A_WIDTH=8 r:B_WIDTH=8 %i %i
+select -assert-count 1 t:$sub r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+### 0 - X
+read_verilog <<EOT
+module wreduce_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o);
+    assign o = (i << 4) - j;
+endmodule
+EOT
+
+hierarchy -auto-top
+proc
+design -save gold
+
+prep
+
+select -assert-count 1 t:$sub r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i
 
 design -stash gate
 

From 5bd088a686ce040c39a8353cf3a7cfe31581d635 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 13:11:30 -0700
Subject: [PATCH 06/53] Add one more test with trimming Y_WIDTH of $sub

---
 tests/various/wreduce.ys | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/tests/various/wreduce.ys b/tests/various/wreduce.ys
index f9e5ed4e3..8030c005e 100644
--- a/tests/various/wreduce.ys
+++ b/tests/various/wreduce.ys
@@ -9,7 +9,7 @@ hierarchy -auto-top
 proc
 design -save gold
 
-prep
+prep # calls wreduce
 
 select -assert-count 1 t:$add r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
 
@@ -21,8 +21,8 @@ design -import gate -as gate
 miter -equiv -flatten -make_assert -make_outputs gold gate miter
 sat -verify -prove-asserts -show-ports miter
 
+##########
 
-### X - 0
 read_verilog <<EOT
 module wreduce_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o);
     assign o = j - (i << 4);
@@ -33,7 +33,7 @@ hierarchy -auto-top
 proc
 design -save gold
 
-prep
+prep # calls wreduce
 
 select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
 
@@ -45,9 +45,10 @@ design -import gate -as gate
 miter -equiv -flatten -make_assert -make_outputs gold gate miter
 sat -verify -prove-asserts -show-ports miter
 
-### 0 - X
+##########
+
 read_verilog <<EOT
-module wreduce_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o);
+module wreduce_sub_test2(input [3:0] i, input [7:0] j, output [8:0] o);
     assign o = (i << 4) - j;
 endmodule
 EOT
@@ -56,7 +57,7 @@ hierarchy -auto-top
 proc
 design -save gold
 
-prep
+prep # calls wreduce
 
 select -assert-count 1 t:$sub r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i
 
@@ -68,10 +69,11 @@ design -import gate -as gate
 miter -equiv -flatten -make_assert -make_outputs gold gate miter
 sat -verify -prove-asserts -show-ports miter
 
-### 0 - X
+##########
+
 read_verilog <<EOT
-module wreduce_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o);
-    assign o = (i << 4) - j;
+module wreduce_sub_test3(input [3:0] i, input [7:0] j, output [8:0] o);
+    assign o = (j >> 4) - i;
 endmodule
 EOT
 
@@ -79,9 +81,10 @@ hierarchy -auto-top
 proc
 design -save gold
 
-prep
+prep # calls wreduce
 
-select -assert-count 1 t:$sub r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i
+dump
+select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
 
 design -stash gate
 

From bcd802718256efbacaf0a73f99347af40b61e464 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 13:11:48 -0700
Subject: [PATCH 07/53] Also optimise MSB of $sub

---
 passes/opt/wreduce.cc | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index e8c2cb726..dff1c5370 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -342,9 +342,9 @@ struct WreduceWorker
 			}
 		}
 
-		if (cell->type.in("$pos", "$add", "$mul", "$and", "$or", "$xor"))
+		if (cell->type.in("$pos", "$add", "$mul", "$and", "$or", "$xor", "$sub"))
 		{
-			bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
+			bool is_signed = cell->getParam("\\A_SIGNED").as_bool() || cell->type == "$sub";
 
 			int a_size = 0, b_size = 0;
 			if (cell->hasPort("\\A")) a_size = GetSize(cell->getPort("\\A"));
@@ -352,7 +352,7 @@ struct WreduceWorker
 
 			int max_y_size = max(a_size, b_size);
 
-			if (cell->type == "$add")
+			if (cell->type.in("$add", "$sub"))
 				max_y_size++;
 
 			if (cell->type == "$mul")

From 31b0002e8c0e1b7a8ad054e02b1200c03461b581 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 13:20:45 -0700
Subject: [PATCH 08/53] Remove "top" from message

---
 passes/opt/wreduce.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index dff1c5370..23e14f7f5 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -395,7 +395,7 @@ struct WreduceWorker
 		}
 
 		if (bits_removed) {
-			log("Removed top %d bits (of %d) from port Y of cell %s.%s (%s).\n",
+			log("Removed %d bits (of %d) from port Y of cell %s.%s (%s).\n",
 					bits_removed, GetSize(sig) + bits_removed, log_id(module), log_id(cell), log_id(cell->type));
 			cell->setPort("\\Y", sig);
 			did_something = true;

From 3a87dc35242598b6951fb70d4302ede60c2a96b2 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 13:23:07 -0700
Subject: [PATCH 09/53] Wrap A and B in sigmap

---
 passes/opt/wreduce.cc | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 23e14f7f5..294f0d57e 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -366,8 +366,8 @@ struct WreduceWorker
 		}
 
 		if (cell->type.in("$add", "$sub")) {
-			SigSpec A = cell->getPort("\\A");
-			SigSpec B = cell->getPort("\\B");
+			SigSpec A = mi.sigmap(cell->getPort("\\A"));
+			SigSpec B = mi.sigmap(cell->getPort("\\B"));
 			bool sub = cell->type == "$sub";
 
 			int i;

From 54708dfbd786032e841f48f15af4875c1eabbbfe Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 13:54:57 -0700
Subject: [PATCH 10/53] Add an SigSpec::at(offset, defval) convenience method

---
 kernel/rtlil.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 82cbfaf28..f9412e776 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -818,6 +818,7 @@ public:
 
 	operator std::vector<RTLIL::SigChunk>() const { return chunks(); }
 	operator std::vector<RTLIL::SigBit>() const { return bits(); }
+	RTLIL::SigBit at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; }
 
 	unsigned int hash() const { if (!hash_) updhash(); return hash_; };
 

From cb0fd0521531a69632102f5fad8cdc9996ed4dee Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 13:58:50 -0700
Subject: [PATCH 11/53] Do not access beyond bounds

---
 passes/opt/wreduce.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 294f0d57e..908a85d5b 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -372,7 +372,7 @@ struct WreduceWorker
 
 			int i;
 			for (i = 0; i < GetSize(sig); i++) {
-				if (B[i] != S0 && (sub || A[i] != S0))
+				if (B.at(i, Sx) != S0 && (sub || A.at(i, Sx) != S0))
 					break;
 				if (B[i] == S0)
 					module->connect(sig[i], A[i]);

From c926eeb43a9c42a0ecc34871f383f4181b7a45f9 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 14:02:46 -0700
Subject: [PATCH 12/53] Add another test

---
 tests/various/wreduce.ys | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/tests/various/wreduce.ys b/tests/various/wreduce.ys
index 8030c005e..deb99304d 100644
--- a/tests/various/wreduce.ys
+++ b/tests/various/wreduce.ys
@@ -83,7 +83,6 @@ design -save gold
 
 prep # calls wreduce
 
-dump
 select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
 
 design -stash gate
@@ -93,3 +92,27 @@ design -import gate -as gate
 
 miter -equiv -flatten -make_assert -make_outputs gold gate miter
 sat -verify -prove-asserts -show-ports miter
+
+##########
+
+read_verilog <<EOT
+module wreduce_sub_test4(input [3:0] i, output [8:0] o);
+    assign o = 5'b00010 - i;
+endmodule
+EOT
+
+hierarchy -auto-top
+proc
+design -save gold
+
+prep # calls wreduce
+
+select -assert-count 1 t:$sub r:A_WIDTH=2 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter

From 09beeee38a5af767f70d24e86c976e43b1b27547 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 14:40:57 -0700
Subject: [PATCH 13/53] Try and fix again

---
 passes/opt/wreduce.cc | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 908a85d5b..22af0bd8b 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -372,13 +372,12 @@ struct WreduceWorker
 
 			int i;
 			for (i = 0; i < GetSize(sig); i++) {
-				if (B.at(i, Sx) != S0 && (sub || A.at(i, Sx) != S0))
-					break;
-				if (B[i] == S0)
+				if (B.at(i, Sx) == S0 && A.at(i, Sx) != Sx)
 					module->connect(sig[i], A[i]);
-				else if (A[i] == S0)
+				else if (!sub && A.at(i, Sx) == S0 && B.at(i, Sx) != Sx)
 					module->connect(sig[i], B[i]);
-				else log_abort();
+				else
+					break;
 			}
 			if (i > 0) {
 				cell->setPort("\\A", A.extract(i, -1));

From 67b4ce06e07fde80d5ac11cad4d673c501bdd421 Mon Sep 17 00:00:00 2001
From: Dan Ravensloft <dan.ravensloft@gmail.com>
Date: Mon, 22 Jul 2019 12:15:22 +0100
Subject: [PATCH 14/53] intel: Map M9K BRAM only on families that have it

This regresses Cyclone V and Cyclone 10 substantially, but these
numbers were artificial, targeting a BRAM that they did not contain.

Amusingly, synth_intel still does better when synthesizing PicoSoC
than Quartus when neither are inferring block RAM.
---
 techlibs/intel/Makefile.inc                         |  4 ++--
 techlibs/intel/common/{brams.txt => brams_m9k.txt}  |  0
 .../intel/common/{brams_map.v => brams_map_m9k.v}   |  0
 techlibs/intel/synth_intel.cc                       | 13 ++++++++++---
 4 files changed, 12 insertions(+), 5 deletions(-)
 rename techlibs/intel/common/{brams.txt => brams_m9k.txt} (100%)
 rename techlibs/intel/common/{brams_map.v => brams_map_m9k.v} (100%)

diff --git a/techlibs/intel/Makefile.inc b/techlibs/intel/Makefile.inc
index ec7cea379..7a3d2c71a 100644
--- a/techlibs/intel/Makefile.inc
+++ b/techlibs/intel/Makefile.inc
@@ -3,8 +3,8 @@ OBJS += techlibs/intel/synth_intel.o
 
 $(eval $(call add_share_file,share/intel/common,techlibs/intel/common/m9k_bb.v))
 $(eval $(call add_share_file,share/intel/common,techlibs/intel/common/altpll_bb.v))
-$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams.txt))
-$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_map.v))
+$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_m9k.txt))
+$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_map_m9k.v))
 $(eval $(call add_share_file,share/intel/max10,techlibs/intel/max10/cells_sim.v))
 $(eval $(call add_share_file,share/intel/a10gx,techlibs/intel/a10gx/cells_sim.v))
 $(eval $(call add_share_file,share/intel/cyclonev,techlibs/intel/cyclonev/cells_sim.v))
diff --git a/techlibs/intel/common/brams.txt b/techlibs/intel/common/brams_m9k.txt
similarity index 100%
rename from techlibs/intel/common/brams.txt
rename to techlibs/intel/common/brams_m9k.txt
diff --git a/techlibs/intel/common/brams_map.v b/techlibs/intel/common/brams_map_m9k.v
similarity index 100%
rename from techlibs/intel/common/brams_map.v
rename to techlibs/intel/common/brams_map_m9k.v
diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc
index d7b089503..87d83f0db 100644
--- a/techlibs/intel/synth_intel.cc
+++ b/techlibs/intel/synth_intel.cc
@@ -187,8 +187,15 @@ struct SynthIntelPass : public ScriptPass {
 		}
 
 		if (!nobram && check_label("map_bram", "(skip if -nobram)")) {
-			run("memory_bram -rules +/intel/common/brams.txt");
-			run("techmap -map +/intel/common/brams_map.v");
+                        if (family_opt == "cycloneiv" ||
+                            family_opt == "cycloneive" ||
+                            family_opt == "max10" ||
+                            help_mode) {
+				run("memory_bram -rules +/intel/common/brams_m9k.txt", "(if applicable for family)");
+				run("techmap -map +/intel/common/brams_map_m9k.v", "(if applicable for family)");
+			} else {
+				log_warning("BRAM mapping is not currently supported for %s.\n", family_opt.c_str());
+			}
 		}
 
 		if (check_label("map_ffram")) {
@@ -217,7 +224,7 @@ struct SynthIntelPass : public ScriptPass {
 		if (check_label("map_cells")) {
 			if (!noiopads)
 				run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
-                        run(stringf("techmap -map +/intel/%s/cells_map.v", family_opt.c_str()));
+			run(stringf("techmap -map +/intel/%s/cells_map.v", family_opt.c_str()));
 
 			run("dffinit -highlow -ff dffeas q power_up");
 			run("clean -purge");

From 49528ed3bd391c1ba3d50f2a904b6ffdb9d11250 Mon Sep 17 00:00:00 2001
From: Dan Ravensloft <dan.ravensloft@gmail.com>
Date: Wed, 24 Jul 2019 10:38:15 +0100
Subject: [PATCH 15/53] intel: Make -noiopads the default

---
 techlibs/intel/synth_intel.cc | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc
index d7b089503..539ba379f 100644
--- a/techlibs/intel/synth_intel.cc
+++ b/techlibs/intel/synth_intel.cc
@@ -61,8 +61,8 @@ struct SynthIntelPass : public ScriptPass {
 		log("        from label is synonymous to 'begin', and empty to label is\n");
 		log("        synonymous to the end of the command list.\n");
 		log("\n");
-		log("    -noiopads\n");
-		log("        do not use IO pad cells in output netlist\n");
+		log("    -iopads\n");
+		log("        use IO pad cells in output netlist\n");
 		log("\n");
 		log("    -nobram\n");
 		log("        do not use block RAM cells in output netlist\n");
@@ -79,7 +79,7 @@ struct SynthIntelPass : public ScriptPass {
 	}
 
 	string top_opt, family_opt, vout_file, blif_file;
-	bool retime, flatten, nobram, noiopads;
+	bool retime, flatten, nobram, iopads;
 
 	void clear_flags() YS_OVERRIDE
 	{
@@ -90,7 +90,7 @@ struct SynthIntelPass : public ScriptPass {
 		retime = false;
 		flatten = true;
 		nobram = false;
-		noiopads = false;
+		iopads = false;
 	}
 
 	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -125,8 +125,8 @@ struct SynthIntelPass : public ScriptPass {
 				run_to = args[argidx].substr(pos + 1);
 				continue;
 			}
-			if (args[argidx] == "-noiopads") {
-				noiopads = true;
+			if (args[argidx] == "-iopads") {
+				iopads = true;
 				continue;
 			}
 			if (args[argidx] == "-nobram") {
@@ -215,8 +215,8 @@ struct SynthIntelPass : public ScriptPass {
 		}
 
 		if (check_label("map_cells")) {
-			if (!noiopads)
-				run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
+			if (iopads || help_mode)
+				run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(if -iopads)");
                         run(stringf("techmap -map +/intel/%s/cells_map.v", family_opt.c_str()));
 
 			run("dffinit -highlow -ff dffeas q power_up");

From 25685a9a5b20c7c03b02d67f0a029702f0019e9d Mon Sep 17 00:00:00 2001
From: Jakob Wenzel <wenzel@rs.tu-darmstadt.de>
Date: Wed, 24 Jul 2019 13:33:07 +0200
Subject: [PATCH 16/53] made ObjectIterator extend std::iterator

this makes it possible to use std algorithms on them
---
 kernel/rtlil.h | 20 ++++++++++++++++++--
 kernel/yosys.h |  1 +
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 82cbfaf28..10225cff2 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -420,7 +420,11 @@ namespace RTLIL
 	// It maintains a reference counter that is used to make sure that the container is not modified while being iterated over.
 
 	template<typename T>
-	struct ObjIterator
+	struct ObjIterator : public std::iterator<std::forward_iterator_tag,
+		T,
+		ptrdiff_t,
+		T *,
+		T &>
 	{
 		typename dict<RTLIL::IdString, T>::iterator it;
 		dict<RTLIL::IdString, T> *list_p;
@@ -474,13 +478,25 @@ namespace RTLIL
 			return it != other.it;
 		}
 
-		inline void operator++() {
+
+		inline bool operator==(const RTLIL::ObjIterator<T> &other) const {
+			return !(*this != other);
+		}
+
+		inline ObjIterator<T>& operator++() {
 			log_assert(list_p != nullptr);
 			if (++it == list_p->end()) {
 				(*refcount_p)--;
 				list_p = nullptr;
 				refcount_p = nullptr;
 			}
+			return *this;
+		}
+
+		inline const ObjIterator<T> operator++(int) {
+			ObjIterator<T> result(*this);
+			++(*this);
+			return result;
 		}
 	};
 
diff --git a/kernel/yosys.h b/kernel/yosys.h
index c7b671724..84c797b2d 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -52,6 +52,7 @@
 #include <stdexcept>
 #include <memory>
 #include <cmath>
+#include <cstddef>
 
 #include <sstream>
 #include <fstream>

From 173c97589471b5f4312acac4e396a250ee7158c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= <marcin@symbioticeda.com>
Date: Wed, 24 Jul 2019 18:41:39 +0200
Subject: [PATCH 17/53] Add a simple example for Spartan 6

---
 examples/mimas2/README       |  8 ++++++++
 examples/mimas2/example.ucf  | 13 +++++++++++++
 examples/mimas2/example.v    | 14 ++++++++++++++
 examples/mimas2/run.sh       |  8 ++++++++
 examples/mimas2/run_yosys.ys |  4 ++++
 5 files changed, 47 insertions(+)
 create mode 100644 examples/mimas2/README
 create mode 100644 examples/mimas2/example.ucf
 create mode 100644 examples/mimas2/example.v
 create mode 100644 examples/mimas2/run.sh
 create mode 100644 examples/mimas2/run_yosys.ys

diff --git a/examples/mimas2/README b/examples/mimas2/README
new file mode 100644
index 000000000..b12875cbc
--- /dev/null
+++ b/examples/mimas2/README
@@ -0,0 +1,8 @@
+A simple example design, based on the Numato Labs Mimas V2 board
+================================================================
+
+This example uses Yosys for synthesis and Xilinx ISE
+for place&route and bit-stream creation.
+
+To synthesize:
+  bash run.sh
diff --git a/examples/mimas2/example.ucf b/examples/mimas2/example.ucf
new file mode 100644
index 000000000..4e31b74ab
--- /dev/null
+++ b/examples/mimas2/example.ucf
@@ -0,0 +1,13 @@
+CONFIG VCCAUX = "3.3" ;
+
+
+NET "CLK"                   LOC = D9      | IOSTANDARD = LVCMOS33 | PERIOD = 12MHz ;
+
+NET "LED[7]"                     LOC = P15     | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[6]"                     LOC = P16     | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[5]"                     LOC = N15     | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[4]"                     LOC = N16     | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[3]"                     LOC = U17     | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[2]"                     LOC = U18     | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[1]"                     LOC = T17     | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
+NET "LED[0]"                     LOC = T18     | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ;
diff --git a/examples/mimas2/example.v b/examples/mimas2/example.v
new file mode 100644
index 000000000..2a9117393
--- /dev/null
+++ b/examples/mimas2/example.v
@@ -0,0 +1,14 @@
+module example(
+	input wire CLK,
+	output wire [7:0] LED
+);
+
+reg [27:0] ctr;
+initial ctr = 0;
+
+always @(posedge CLK)
+	ctr <= ctr + 1;
+
+assign LED = ctr[27:20];
+
+endmodule
diff --git a/examples/mimas2/run.sh b/examples/mimas2/run.sh
new file mode 100644
index 000000000..aafde78ed
--- /dev/null
+++ b/examples/mimas2/run.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+set -e
+yosys run_yosys.ys
+edif2ngd example.edif
+ngdbuild example -uc example.ucf -p xc6slx9csg324-3
+map -w example
+par -w example.ncd example_par.ncd
+bitgen -w example_par.ncd -g StartupClk:JTAGClk
diff --git a/examples/mimas2/run_yosys.ys b/examples/mimas2/run_yosys.ys
new file mode 100644
index 000000000..b3204b1ca
--- /dev/null
+++ b/examples/mimas2/run_yosys.ys
@@ -0,0 +1,4 @@
+read_verilog example.v
+synth_xilinx -top example -family xc6s
+iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I
+write_edif -pvector bra example.edif

From ab607e896e9f5faff939b4395b01344a36e9fc1b Mon Sep 17 00:00:00 2001
From: David Shah <dave@ds0.me>
Date: Thu, 25 Jul 2019 08:19:07 +0100
Subject: [PATCH 18/53] xilinx: Fix missing cell name underscore in cells_map.v

Signed-off-by: David Shah <dave@ds0.me>
---
 techlibs/xilinx/cells_map.v | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v
index 2eb9fa2c1..b8e5bafc7 100644
--- a/techlibs/xilinx/cells_map.v
+++ b/techlibs/xilinx/cells_map.v
@@ -24,9 +24,9 @@ module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_  _TECHMAP_REPLA
 (* techmap_celltype = "$_DFF_PN0_" *)
 module _90_dff_pn0_to_pp0 (input D, C, R, output Q); \$_DFF_PP0_  _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
 (* techmap_celltype = "$_DFF_NN1_" *)
-module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1   _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1_   _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
 (* techmap_celltype = "$_DFF_PN1_" *)
-module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1   _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
+module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1_   _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
 
 module \$__SHREG_ (input C, input D, input E, output Q);
   parameter DEPTH = 0;

From 70882a807074a521515d1525d83ed7321f982d7e Mon Sep 17 00:00:00 2001
From: Jakob Wenzel <wenzel@rs.tu-darmstadt.de>
Date: Thu, 25 Jul 2019 09:51:09 +0200
Subject: [PATCH 19/53] replaced std::iterator with using statements

---
 kernel/rtlil.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 10225cff2..712250b3e 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -420,12 +420,12 @@ namespace RTLIL
 	// It maintains a reference counter that is used to make sure that the container is not modified while being iterated over.
 
 	template<typename T>
-	struct ObjIterator : public std::iterator<std::forward_iterator_tag,
-		T,
-		ptrdiff_t,
-		T *,
-		T &>
-	{
+	struct ObjIterator {
+		using iterator_category = std::forward_iterator_tag;
+		using value_type = T;
+		using difference_type = ptrdiff_t;
+		using pointer = T*;
+		using reference = T&;
 		typename dict<RTLIL::IdString, T>::iterator it;
 		dict<RTLIL::IdString, T> *list_p;
 		int *refcount_p;

From c5e31ac9c3c49f38ddcb6e613ef4a092d69f71a2 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Thu, 25 Jul 2019 10:44:20 -0700
Subject: [PATCH 20/53] Bump abc to fix &mfs bug

---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index d33f27b63..3bc119800 100644
--- a/Makefile
+++ b/Makefile
@@ -122,7 +122,7 @@ OBJS = kernel/version_$(GIT_REV).o
 # is just a symlink to your actual ABC working directory, as 'make mrproper'
 # will remove the 'abc' directory and you do not want to accidentally
 # delete your work on ABC..
-ABCREV = 62487de
+ABCREV = 5776ad0
 ABCPULL = 1
 ABCURL ?= https://github.com/berkeley-abc/abc
 ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1

From 933db0410e096286c21772f5a2f44b03d2ed0b57 Mon Sep 17 00:00:00 2001
From: David Shah <dave@ds0.me>
Date: Fri, 26 Jul 2019 10:23:58 +0100
Subject: [PATCH 21/53] Add support for reading gzip'd input files

Signed-off-by: David Shah <dave@ds0.me>
---
 .travis.yml                     |   5 ++++
 Makefile                        |   7 ++++++
 README.md                       |   6 ++---
 kernel/register.cc              |  40 ++++++++++++++++++++++++++++++++
 tests/various/gzip_verilog.v.gz | Bin 0 -> 82 bytes
 tests/various/gzip_verilog.ys   |   2 ++
 6 files changed, 57 insertions(+), 3 deletions(-)
 create mode 100644 tests/various/gzip_verilog.v.gz
 create mode 100644 tests/various/gzip_verilog.ys

diff --git a/.travis.yml b/.travis.yml
index 957735f1d..4102f05fe 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -36,6 +36,7 @@ matrix:
             - libboost-system-dev
             - libboost-python-dev
             - libboost-filesystem-dev
+            - zlib1g-dev
       env:
         - MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8"
 
@@ -64,6 +65,7 @@ matrix:
             - libboost-system-dev
             - libboost-python-dev
             - libboost-filesystem-dev
+            - zlib1g-dev
       env:
         - MATRIX_EVAL="CONFIG=gcc && CC=gcc-6 && CXX=g++-6"
 
@@ -92,6 +94,7 @@ matrix:
             - libboost-system-dev
             - libboost-python-dev
             - libboost-filesystem-dev
+            - zlib1g-dev
       env:
         - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7"
 
@@ -121,6 +124,7 @@ matrix:
             - libboost-system-dev
             - libboost-python-dev
             - libboost-filesystem-dev
+            - zlib1g-dev
       env:
         - MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8"
 
@@ -149,6 +153,7 @@ matrix:
             - libboost-system-dev
             - libboost-python-dev
             - libboost-filesystem-dev
+            - zlib1g-dev
       env:
         - MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0"
 
diff --git a/Makefile b/Makefile
index d33f27b63..ea804e0d5 100644
--- a/Makefile
+++ b/Makefile
@@ -19,6 +19,7 @@ ENABLE_VERIFIC := 0
 ENABLE_COVER := 1
 ENABLE_LIBYOSYS := 0
 ENABLE_PROTOBUF := 0
+ENABLE_ZLIB := 1
 
 # python wrappers
 ENABLE_PYOSYS := 0
@@ -384,6 +385,12 @@ ifeq ($(ENABLE_GLOB),1)
 CXXFLAGS += -DYOSYS_ENABLE_GLOB
 endif
 
+ifeq ($(ENABLE_ZLIB),1)
+CXXFLAGS += -DYOSYS_ENABLE_ZLIB
+LDLIBS += -lz
+endif
+
+
 ifeq ($(ENABLE_TCL),1)
 TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
 ifeq ($(OS), FreeBSD)
diff --git a/README.md b/README.md
index 9e221be38..2a7081304 100644
--- a/README.md
+++ b/README.md
@@ -67,13 +67,13 @@ prerequisites for building yosys:
 	$ sudo apt-get install build-essential clang bison flex \
 		libreadline-dev gawk tcl-dev libffi-dev git \
 		graphviz xdot pkg-config python3 libboost-system-dev \
-		libboost-python-dev libboost-filesystem-dev
+		libboost-python-dev libboost-filesystem-dev zlib1g-dev
 
 Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies:
 
 	$ brew tap Homebrew/bundle && brew bundle
 	$ sudo port install bison flex readline gawk libffi \
-		git graphviz pkgconfig python36 boost
+		git graphviz pkgconfig python36 boost zlib
 
 On FreeBSD use the following command to install all prerequisites:
 
@@ -85,7 +85,7 @@ On FreeBSD system use gmake instead of make. To run tests use:
 
 For Cygwin use the following command to install all prerequisites, or select these additional packages:
 
-	setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build
+	setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build,zlib-devel
 
 There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well
 as a source distribution for Visual Studio. Visit the Yosys download page for
diff --git a/kernel/register.cc b/kernel/register.cc
index 26da96b95..4f1501330 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -25,6 +25,26 @@
 #include <stdio.h>
 #include <errno.h>
 
+#ifdef YOSYS_ENABLE_ZLIB
+#include <zlib.h>
+
+PRIVATE_NAMESPACE_BEGIN
+#define GZ_BUFFER_SIZE 8192
+void decompress_gzip(const std::string &filename, std::stringstream &out)
+{
+	char buffer[GZ_BUFFER_SIZE];
+	int bytes_read;
+	gzFile gzf = gzopen(filename.c_str(), "rb");
+	while(!gzeof(gzf)) {
+		bytes_read = gzread(gzf, reinterpret_cast<void *>(buffer), GZ_BUFFER_SIZE);
+		out.write(buffer, bytes_read);
+	}
+	gzclose(gzf);
+}
+PRIVATE_NAMESPACE_END
+
+#endif
+
 YOSYS_NAMESPACE_BEGIN
 
 #define MAX_REG_COUNT 1000
@@ -436,6 +456,26 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
 				delete ff;
 			else
 				f = ff;
+			// Check for gzip magic
+			unsigned char magic[3];
+			int n = readsome(*ff, reinterpret_cast<char*>(magic), 3);
+			if (n == 3 && magic[0] == 0x1f && magic[1] == 0x8b) {
+#ifdef YOSYS_ENABLE_ZLIB
+				log("Found gzip magic in file `%s', decompressing using zlib.\n", filename.c_str());
+				if (magic[2] != 8)
+					log_cmd_error("gzip file `%s' uses unsupported compression type %02x\n",
+						filename.c_str(), unsigned(magic[2]));
+				delete ff;
+				std::stringstream *df = new std::stringstream();
+				decompress_gzip(filename, *df);
+				f = df;
+#else
+				log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str());
+#endif
+			} else {
+				ff->clear();
+				ff->seekg(0, std::ios::beg);
+			}
 		}
 		if (f == NULL)
 			log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
diff --git a/tests/various/gzip_verilog.v.gz b/tests/various/gzip_verilog.v.gz
new file mode 100644
index 0000000000000000000000000000000000000000..c52a95358046dad231d5efe9103ce7e919b707a1
GIT binary patch
literal 82
zcmb2|=HSpjY8A`CoL-e#5MP#Bl$n#Cu2;rz`mDd^S<g_7llm7<=<8}~=mu(B+49Uw
mNAH}^`CyHZ4WR}h{zgE7v)(6JS3h~g#GuXoc)Jk;0|Nm4m>-h>

literal 0
HcmV?d00001

diff --git a/tests/various/gzip_verilog.ys b/tests/various/gzip_verilog.ys
new file mode 100644
index 000000000..870317e80
--- /dev/null
+++ b/tests/various/gzip_verilog.ys
@@ -0,0 +1,2 @@
+read_verilog gzip_verilog.v.gz
+select -assert-any top

From da6701c4cd26d559241c8a3de61b51ace1e03fe4 Mon Sep 17 00:00:00 2001
From: David Shah <dave@ds0.me>
Date: Fri, 26 Jul 2019 10:29:05 +0100
Subject: [PATCH 22/53] Fix frontend auto-detection for gzipped input

Signed-off-by: David Shah <dave@ds0.me>
---
 kernel/yosys.cc | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index a42a7c0b8..191b6d5c7 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -894,23 +894,26 @@ void run_frontend(std::string filename, std::string command, std::string *backen
 		design = yosys_design;
 
 	if (command == "auto") {
-		if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
+		std::string filename_trim = filename;
+		if (filename_trim.size() > 3 && filename_trim.substr(filename_trim.size()-3) == ".gz")
+			filename_trim.erase(filename_trim.size()-3);
+		if (filename_trim.size() > 2 && filename_trim.substr(filename_trim.size()-2) == ".v")
 			command = "verilog";
-		else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv")
+		else if (filename_trim.size() > 2 && filename_trim.substr(filename_trim.size()-3) == ".sv")
 			command = "verilog -sv";
-		else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".vhd")
+		else if (filename_trim.size() > 3 && filename_trim.substr(filename_trim.size()-4) == ".vhd")
 			command = "vhdl";
-		else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif")
+		else if (filename_trim.size() > 4 && filename_trim.substr(filename_trim.size()-5) == ".blif")
 			command = "blif";
-		else if (filename.size() > 5 && filename.substr(filename.size()-6) == ".eblif")
+		else if (filename_trim.size() > 5 && filename_trim.substr(filename_trim.size()-6) == ".eblif")
 			command = "blif";
-		else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".json")
+		else if (filename_trim.size() > 4 && filename_trim.substr(filename_trim.size()-5) == ".json")
 			command = "json";
-		else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
+		else if (filename_trim.size() > 3 && filename_trim.substr(filename_trim.size()-3) == ".il")
 			command = "ilang";
-		else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
+		else if (filename_trim.size() > 3 && filename_trim.substr(filename_trim.size()-3) == ".ys")
 			command = "script";
-		else if (filename.size() > 3 && filename.substr(filename.size()-4) == ".tcl")
+		else if (filename_trim.size() > 3 && filename_trim.substr(filename_trim.size()-4) == ".tcl")
 			command = "tcl";
 		else if (filename == "-")
 			command = "script";

From 92694ea3a997cc6d081b6896c213d308adb466d5 Mon Sep 17 00:00:00 2001
From: David Shah <dave@ds0.me>
Date: Fri, 26 Jul 2019 13:35:39 +0100
Subject: [PATCH 23/53] verilog_lexer: Increase YY_BUF_SIZE to 65536

Signed-off-by: David Shah <dave@ds0.me>
---
 frontends/verilog/verilog_lexer.l | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 951d9c66f..57e55b1f4 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -70,6 +70,9 @@ YOSYS_NAMESPACE_END
 #define YY_INPUT(buf,result,max_size) \
 	result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
 
+#undef YY_BUF_SIZE
+#define YY_BUF_SIZE 65536
+
 %}
 
 %option yylineno

From 482926cbd306cc71aebb81b1b8e825ced9b3f26d Mon Sep 17 00:00:00 2001
From: David Shah <dave@ds0.me>
Date: Fri, 26 Jul 2019 15:53:21 +0100
Subject: [PATCH 24/53] Update CHANGELOG

Signed-off-by: David Shah <dave@ds0.me>
---
 CHANGELOG | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CHANGELOG b/CHANGELOG
index 44d83c1bf..00b10c591 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -14,7 +14,7 @@ Yosys 0.9 .. Yosys 0.9-dev
     - Added "synth -abc9" (experimental)
     - Added "script -scriptwire
     - "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable)
-
+    - Added automatic gzip decompression for frontends
 
 Yosys 0.8 .. Yosys 0.8-dev
 --------------------------

From fc462c8243d60ebd769d5ce01142fb7ed49fa8f8 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Mon, 29 Jul 2019 10:29:36 +0200
Subject: [PATCH 25/53] Call "read_verilog" with -defer from "read"

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 frontends/verific/verific.cc | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index 2bf99e58e..06d58a44a 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -2484,7 +2484,7 @@ struct ReadPass : public Pass {
 				args[0] = "verific";
 			} else {
 				args[0] = "read_verilog";
-				args.erase(args.begin()+1, args.begin()+2);
+				args[1] = "-defer";
 			}
 			Pass::call(design, args);
 			return;
@@ -2498,6 +2498,7 @@ struct ReadPass : public Pass {
 				if (args[1] == "-formal")
 					args.insert(args.begin()+1, std::string());
 				args[1] = "-sv";
+				args.insert(args.begin()+1, "-defer");
 			}
 			Pass::call(design, args);
 			return;

From 5be5bd0fb61a9c8d1efa7e8c233ea0100cc32641 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Mon, 29 Jul 2019 10:40:30 +0200
Subject: [PATCH 26/53] Update README to use "read" instead of "read_verilog"

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 README.md | 67 ++++++++++++++++---------------------------------------
 1 file changed, 19 insertions(+), 48 deletions(-)

diff --git a/README.md b/README.md
index 2a7081304..d9989eb29 100644
--- a/README.md
+++ b/README.md
@@ -130,18 +130,15 @@ commands and ``help <command>`` to print details on the specified command:
 
 	yosys> help help
 
-reading the design using the Verilog frontend:
+reading and elaborating the design using the Verilog frontend:
 
-	yosys> read_verilog tests/simple/fiedler-cooley.v
+	yosys> read -sv tests/simple/fiedler-cooley.v
+	yosys> hierarchy -top up3down5
 
 writing the design to the console in Yosys's internal format:
 
 	yosys> write_ilang
 
-elaborate design hierarchy:
-
-	yosys> hierarchy
-
 convert processes (``always`` blocks) to netlist elements and perform
 some simple optimizations:
 
@@ -163,51 +160,26 @@ write design netlist to a new Verilog file:
 
 	yosys> write_verilog synth.v
 
-a similar synthesis can be performed using yosys command line options only:
-
-	$ ./yosys -o synth.v -p hierarchy -p proc -p opt \
-	                     -p techmap -p opt tests/simple/fiedler-cooley.v
-
 or using a simple synthesis script:
 
 	$ cat synth.ys
-	read_verilog tests/simple/fiedler-cooley.v
-	hierarchy; proc; opt; techmap; opt
+	read -sv tests/simple/fiedler-cooley.v
+	hierarchy -top up3down5
+	proc; opt; techmap; opt
 	write_verilog synth.v
 
 	$ ./yosys synth.ys
 
-It is also possible to only have the synthesis commands but not the read/write
-commands in the synthesis script:
-
-	$ cat synth.ys
-	hierarchy; proc; opt; techmap; opt
-
-	$ ./yosys -o synth.v tests/simple/fiedler-cooley.v synth.ys
-
-The following very basic synthesis script should work well with all designs:
-
-	# check design hierarchy
-	hierarchy
-
-	# translate processes (always blocks)
-	proc; opt
-
-	# detect and optimize FSM encodings
-	fsm; opt
-
-	# implement memories (arrays)
-	memory; opt
-
-	# convert to gate logic
-	techmap; opt
-
 If ABC is enabled in the Yosys build configuration and a cell library is given
 in the liberty file ``mycells.lib``, the following synthesis script will
 synthesize for the given cell library:
 
+	# read design
+	read -sv tests/simple/fiedler-cooley.v
+	hierarchy -top up3down5
+
 	# the high-level stuff
-	hierarchy; proc; fsm; opt; memory; opt
+	proc; fsm; opt; memory; opt
 
 	# mapping to internal cell library
 	techmap; opt
@@ -222,7 +194,8 @@ synthesize for the given cell library:
 	clean
 
 If you do not have a liberty file but want to test this synthesis script,
-you can use the file ``examples/cmos/cmos_cells.lib`` from the yosys sources.
+you can use the file ``examples/cmos/cmos_cells.lib`` from the yosys sources
+as simple example.
 
 Liberty file downloads for and information about free and open ASIC standard
 cell libraries can be found here:
@@ -231,20 +204,18 @@ cell libraries can be found here:
 - http://www.vlsitechnology.org/synopsys/vsclib013.lib
 
 The command ``synth`` provides a good default synthesis script (see
-``help synth``).  If possible a synthesis script should borrow from ``synth``.
-For example:
+``help synth``):
 
-	# the high-level stuff
-	hierarchy
-	synth -run coarse
+	read -sv tests/simple/fiedler-cooley.v
+	synth -top up3down5
 
-	# mapping to internal cells
-	techmap; opt -fast
+	# mapping to target cells
 	dfflibmap -liberty mycells.lib
 	abc -liberty mycells.lib
 	clean
 
-Yosys is under construction. A more detailed documentation will follow.
+The command ``prep`` provides a good default word-level synthesis script, as
+used in SMT-based formal verification.
 
 
 Unsupported Verilog-2005 Features

From 3e4307c104f5caf0f3449421a75b19e7c90a71fe Mon Sep 17 00:00:00 2001
From: Miodrag Milanovic <mmicko@gmail.com>
Date: Mon, 29 Jul 2019 12:29:13 +0200
Subject: [PATCH 27/53] Fix case when file does not exist

---
 kernel/register.cc | 40 +++++++++++++++++++++-------------------
 1 file changed, 21 insertions(+), 19 deletions(-)

diff --git a/kernel/register.cc b/kernel/register.cc
index 4f1501330..4c6e3591f 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -456,25 +456,27 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
 				delete ff;
 			else
 				f = ff;
-			// Check for gzip magic
-			unsigned char magic[3];
-			int n = readsome(*ff, reinterpret_cast<char*>(magic), 3);
-			if (n == 3 && magic[0] == 0x1f && magic[1] == 0x8b) {
-#ifdef YOSYS_ENABLE_ZLIB
-				log("Found gzip magic in file `%s', decompressing using zlib.\n", filename.c_str());
-				if (magic[2] != 8)
-					log_cmd_error("gzip file `%s' uses unsupported compression type %02x\n",
-						filename.c_str(), unsigned(magic[2]));
-				delete ff;
-				std::stringstream *df = new std::stringstream();
-				decompress_gzip(filename, *df);
-				f = df;
-#else
-				log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str());
-#endif
-			} else {
-				ff->clear();
-				ff->seekg(0, std::ios::beg);
+			if (f != NULL) {
+				// Check for gzip magic
+				unsigned char magic[3];
+				int n = readsome(*ff, reinterpret_cast<char*>(magic), 3);
+				if (n == 3 && magic[0] == 0x1f && magic[1] == 0x8b) {
+	#ifdef YOSYS_ENABLE_ZLIB
+					log("Found gzip magic in file `%s', decompressing using zlib.\n", filename.c_str());
+					if (magic[2] != 8)
+						log_cmd_error("gzip file `%s' uses unsupported compression type %02x\n",
+							filename.c_str(), unsigned(magic[2]));
+					delete ff;
+					std::stringstream *df = new std::stringstream();
+					decompress_gzip(filename, *df);
+					f = df;
+	#else
+					log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str());
+	#endif
+				} else {
+					ff->clear();
+					ff->seekg(0, std::ios::beg);
+				}
 			}
 		}
 		if (f == NULL)

From 66806085db7d730c27a330e541f8aecbba3bd342 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Mon, 29 Jul 2019 16:05:44 -0700
Subject: [PATCH 28/53] RST -> RSTBRST for RAMB8BWER

---
 techlibs/xilinx/xc6s_brams_map.v | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/techlibs/xilinx/xc6s_brams_map.v b/techlibs/xilinx/xc6s_brams_map.v
index c9b33af42..16fd15e74 100644
--- a/techlibs/xilinx/xc6s_brams_map.v
+++ b/techlibs/xilinx/xc6s_brams_map.v
@@ -52,7 +52,7 @@ module \$__XILINX_RAMB8BWER_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DAT
 		.CLKBRDCLK(CLK2 ^ !CLKPOL2),
 		.ENBRDEN(A1EN),
 		.REGCEBREGCE(|1),
-		.RSTB(|0)
+		.RSTBRST(|0)
 	);
 endmodule
 
@@ -217,7 +217,7 @@ module \$__XILINX_RAMB8BWER_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DAT
 			.CLKBRDCLK(CLK3 ^ !CLKPOL3),
 			.ENBRDEN(|1),
 			.REGCEBREGCE(|0),
-			.RSTB(|0),
+			.RSTBRST(|0),
 			.WEBWEU(B1EN_2)
 		);
 	end else begin
@@ -248,7 +248,7 @@ module \$__XILINX_RAMB8BWER_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DAT
 			.CLKBRDCLK(CLK3 ^ !CLKPOL3),
 			.ENBRDEN(|1),
 			.REGCEBREGCE(|0),
-			.RSTB(|0),
+			.RSTBRST(|0),
 			.WEBWEU(B1EN_2)
 		);
 	end endgenerate

From 35d28de47892d7905d8b37538a581950d4eb54c7 Mon Sep 17 00:00:00 2001
From: Miodrag Milanovic <mmicko@gmail.com>
Date: Wed, 31 Jul 2019 09:10:24 +0200
Subject: [PATCH 29/53] Visual Studio build fix

---
 backends/aiger/xaiger.cc | 2 +-
 passes/techmap/abc.cc    | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
index 69f63486c..6aa9cde54 100644
--- a/backends/aiger/xaiger.cc
+++ b/backends/aiger/xaiger.cc
@@ -53,7 +53,7 @@ PRIVATE_NAMESPACE_BEGIN
 
 inline int32_t to_big_endian(int32_t i32) {
 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
-	return __builtin_bswap32(i32);
+	return bswap32(i32);
 #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
 	return i32;
 #else
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 65c7d1bb8..19afb58cb 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -49,6 +49,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <cctype>
 #include <cerrno>
 #include <sstream>
 #include <climits>

From 3b8c917025e1be9695468588082e9175e918c9e9 Mon Sep 17 00:00:00 2001
From: Jim Lawson <ucbjrl@berkeley.edu>
Date: Wed, 31 Jul 2019 09:27:38 -0700
Subject: [PATCH 30/53] Support explicit FIRRTL properties for better
 accommodation of FIRRTL/Verilog semantic differences. Use FIRRTL spec vlaues
 for definition of FIRRTL widths. Added support for '$pos`, `$pow` and `$xnor`
 cells. Enable tests/simple/operators.v since all operators tested there are
 now supported. Disable FIRRTL tests of
 tests/simple/{defvalue.sv,implicit_ports.v,wandwor.v} since they currently
 generate FIRRTL compilation errors.

---
 backends/firrtl/firrtl.cc | 302 ++++++++++++++++++++++++++------------
 tests/simple/xfirrtl      |   4 +-
 2 files changed, 209 insertions(+), 97 deletions(-)

diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc
index 1c7a7351f..9ef6e311a 100644
--- a/backends/firrtl/firrtl.cc
+++ b/backends/firrtl/firrtl.cc
@@ -381,10 +381,10 @@ struct FirrtlWorker
 
 	// Given an expression for a shift amount, and a maximum width,
 	//  generate the FIRRTL expression for equivalent dynamic shift taking into account FIRRTL shift semantics.
-	std::string gen_dshl(const string b_expr, const int b_padded_width)
+	std::string gen_dshl(const string b_expr, const int b_width)
 	{
 		string result = b_expr;
-		if (b_padded_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) {
+		if (b_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) {
 			int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1;
 			string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1);
 			// Deal with the difference in semantics between FIRRTL and verilog
@@ -422,22 +422,33 @@ struct FirrtlWorker
 
 		for (auto cell : module->cells())
 		{
-			bool extract_y_bits = false;		// Assume no extraction of final bits will be required.
+			static Const ndef(0, 0);
+
 		    // Is this cell is a module instance?
 			if (cell->type[0] != '$')
 			{
 				process_instance(cell, wire_exprs);
 				continue;
 			}
+			// Not a module instance. Set up cell properties
+			bool extract_y_bits = false;		// Assume no extraction of final bits will be required.
+			int a_width = cell->parameters.at("\\A_WIDTH", ndef).as_int();	// The width of "A"
+			int b_width = cell->parameters.at("\\B_WIDTH", ndef).as_int();	// The width of "A"
+			const int y_width = cell->parameters.at("\\Y_WIDTH", ndef).as_int();	// The width of the result
+			const bool a_signed = cell->parameters.at("\\A_SIGNED", ndef).as_bool();
+			const bool b_signed = cell->parameters.at("\\B_SIGNED", ndef).as_bool();
+			bool firrtl_is_signed = a_signed;	// The result is signed (subsequent code may change this).
+			int firrtl_width = 0;
+			string primop;
+			bool always_uint = false;
+			string y_id = make_id(cell->name);
+
 			if (cell->type.in("$not", "$logic_not", "$neg", "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_bool", "$reduce_xnor"))
 			{
-				string y_id = make_id(cell->name);
-				bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
-				int y_width =  cell->parameters.at("\\Y_WIDTH").as_int();
 				string a_expr = make_expr(cell->getPort("\\A"));
 				wire_decls.push_back(stringf("    wire %s: UInt<%d>\n", y_id.c_str(), y_width));
 
-				if (cell->parameters.at("\\A_SIGNED").as_bool()) {
+				if (a_signed) {
 					a_expr = "asSInt(" + a_expr + ")";
 				}
 
@@ -446,12 +457,13 @@ struct FirrtlWorker
 					a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
 				}
 
-				string primop;
-				bool always_uint = false;
+				// Assume the FIRRTL width is a single bit.
+				firrtl_width = 1;
 				if (cell->type == "$not") primop = "not";
 				else if (cell->type == "$neg") {
 					primop = "neg";
-					is_signed = true;	// Result of "neg" is signed (an SInt).
+					firrtl_is_signed = true;	// Result of "neg" is signed (an SInt).
+					firrtl_width = a_width;
 				} else if (cell->type == "$logic_not") {
                                         primop = "eq";
                                         a_expr = stringf("%s, UInt(0)", a_expr.c_str());
@@ -466,14 +478,12 @@ struct FirrtlWorker
 				else if (cell->type == "$reduce_bool") {
 					primop = "neq";
 					// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
-					bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool();
-					int a_width =  cell->parameters.at("\\A_WIDTH").as_int();
 					a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width);
 				}
 
 				string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str());
 
-				if ((is_signed && !always_uint))
+				if ((firrtl_is_signed && !always_uint))
 					expr = stringf("asUInt(%s)", expr.c_str());
 
 				cell_exprs.push_back(stringf("    %s <= %s\n", y_id.c_str(), expr.c_str()));
@@ -481,81 +491,121 @@ struct FirrtlWorker
 
 				continue;
 			}
-			if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx",
+			if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$xnor", "$and", "$or", "$eq", "$eqx",
 							  "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
-							  "$logic_and", "$logic_or"))
+							  "$logic_and", "$logic_or", "$pow"))
 			{
-				string y_id = make_id(cell->name);
-				bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
-				int y_width =  cell->parameters.at("\\Y_WIDTH").as_int();
 				string a_expr = make_expr(cell->getPort("\\A"));
 				string b_expr = make_expr(cell->getPort("\\B"));
-				int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int();
 				wire_decls.push_back(stringf("    wire %s: UInt<%d>\n", y_id.c_str(), y_width));
 
-				if (cell->parameters.at("\\A_SIGNED").as_bool()) {
+				if (a_signed) {
 					a_expr = "asSInt(" + a_expr + ")";
-				}
-				// Shift amount is always unsigned, and needn't be padded to result width.
-				if (!cell->type.in("$shr", "$sshr", "$shl", "$sshl")) {
-					if (cell->parameters.at("\\B_SIGNED").as_bool()) {
-						b_expr = "asSInt(" + b_expr + ")";
+					// Expand the "A" operand to the result width
+					if (a_width < y_width) {
+						a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
+						a_width = y_width;
 					}
-					if (b_padded_width < y_width) {
-						auto b_sig = cell->getPort("\\B");
-						b_padded_width = y_width;
+				}
+				// Shift amount is always unsigned, and needn't be padded to result width,
+				//  otherwise, we need to cast the b_expr appropriately
+				if (b_signed && !cell->type.in("$shr", "$sshr", "$shl", "$sshl", "$pow")) {
+					b_expr = "asSInt(" + b_expr + ")";
+					// Expand the "B" operand to the result width
+					if (b_width < y_width) {
+						b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
+						b_width = y_width;
 					}
 				}
 
+				// For the arithmetic ops, expand operand widths to result widths befor performing the operation.
+				// This corresponds (according to iverilog) to what verilog compilers implement.
+				if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$xnor", "$and", "$or"))
+				{
+					if (a_width < y_width) {
+						a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
+						a_width = y_width;
+					}
+					if (b_width < y_width) {
+						b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
+						b_width = y_width;
+					}
+				}
+				// Assume the FIRRTL width is the width of "A"
+				firrtl_width = a_width;
 				auto a_sig = cell->getPort("\\A");
 
-				if (cell->parameters.at("\\A_SIGNED").as_bool()  & (cell->type == "$shr")) {
-					a_expr = "asUInt(" + a_expr + ")";
+				if (cell->type == "$add") {
+					primop = "add";
+					firrtl_is_signed = a_signed | b_signed;
+					firrtl_width = max(a_width, b_width);
+				} else if (cell->type == "$sub") {
+					primop = "sub";
+					firrtl_is_signed = true;
+					int a_widthInc = (!a_signed && b_signed) ? 2 : (a_signed && !b_signed) ? 1 : 0;
+					int b_widthInc = (a_signed && !b_signed) ? 2 : (!a_signed && b_signed) ? 1 : 0;
+					firrtl_width = max(a_width + a_widthInc, b_width + b_widthInc);
+				} else if (cell->type == "$mul") {
+					primop = "mul";
+					firrtl_is_signed = a_signed | b_signed;
+					firrtl_width = a_width + b_width;
+				} else if (cell->type == "$div") {
+					primop = "div";
+					firrtl_is_signed = a_signed | b_signed;
+					firrtl_width = a_width;
+				} else if (cell->type == "$mod") {
+					primop = "rem";
+					firrtl_width = min(a_width, b_width);
+				} else if (cell->type == "$and") {
+					primop = "and";
+					always_uint = true;
+					firrtl_width = max(a_width, b_width);
 				}
-
-				string primop;
-				bool always_uint = false;
-				if (cell->type == "$add") primop = "add";
-				else if (cell->type == "$sub") primop = "sub";
-				else if (cell->type == "$mul") primop = "mul";
-				else if (cell->type == "$div") primop = "div";
-				else if (cell->type == "$mod") primop = "rem";
-				else if (cell->type == "$and") {
-                                        primop = "and";
-                                        always_uint = true;
-                                }
 				else if (cell->type == "$or" ) {
-                                        primop =  "or";
-                                        always_uint = true;
-                                }
+					primop =  "or";
+					always_uint = true;
+					firrtl_width = max(a_width, b_width);
+				}
 				else if (cell->type == "$xor") {
-                                        primop = "xor";
-                                        always_uint = true;
-                                }
+					primop = "xor";
+					always_uint = true;
+					firrtl_width = max(a_width, b_width);
+				}
+				else if (cell->type == "$xnor") {
+					primop = "xnor";
+					always_uint = true;
+					firrtl_width = max(a_width, b_width);
+				}
 				else if ((cell->type == "$eq") | (cell->type == "$eqx")) {
-                                        primop = "eq";
-                                        always_uint = true;
-                                }
+					primop = "eq";
+					always_uint = true;
+					firrtl_width = 1;
+			    }
 				else if ((cell->type == "$ne") | (cell->type == "$nex")) {
-                                        primop = "neq";
-                                        always_uint = true;
-                                }
+					primop = "neq";
+					always_uint = true;
+					firrtl_width = 1;
+				}
 				else if (cell->type == "$gt") {
-                                        primop = "gt";
-                                        always_uint = true;
-                                }
+					primop = "gt";
+					always_uint = true;
+					firrtl_width = 1;
+				}
 				else if (cell->type == "$ge") {
-                                        primop = "geq";
-                                        always_uint = true;
-                                }
+					primop = "geq";
+					always_uint = true;
+					firrtl_width = 1;
+				}
 				else if (cell->type == "$lt") {
-                                        primop = "lt";
-                                        always_uint = true;
-                                }
+					primop = "lt";
+					always_uint = true;
+					firrtl_width = 1;
+				}
 				else if (cell->type == "$le") {
-                                        primop = "leq";
-                                        always_uint = true;
-                                }
+					primop = "leq";
+					always_uint = true;
+					firrtl_width = 1;
+				}
 				else if ((cell->type == "$shl") | (cell->type == "$sshl")) {
 					// FIRRTL will widen the result (y) by the amount of the shift.
 					// We'll need to offset this by extracting the un-widened portion as Verilog would do.
@@ -564,11 +614,14 @@ struct FirrtlWorker
 					auto b_sig = cell->getPort("\\B");
 					if (b_sig.is_fully_const()) {
 						primop = "shl";
-						b_expr = std::to_string(b_sig.as_int());
+						int shift_amount = b_sig.as_int();
+						b_expr = std::to_string(shift_amount);
+						firrtl_width = a_width + shift_amount;
 					} else {
 						primop = "dshl";
 						// Convert from FIRRTL left shift semantics.
-						b_expr = gen_dshl(b_expr, b_padded_width);
+						b_expr = gen_dshl(b_expr, b_width);
+						firrtl_width = a_width + (1 << b_width) - 1;
 					}
 				}
 				else if ((cell->type == "$shr") | (cell->type == "$sshr")) {
@@ -578,36 +631,86 @@ struct FirrtlWorker
 					auto b_sig = cell->getPort("\\B");
 					if (b_sig.is_fully_const()) {
 						primop = "shr";
-						b_expr = std::to_string(b_sig.as_int());
+						int shift_amount = b_sig.as_int();
+						b_expr = std::to_string(shift_amount);
+						firrtl_width = max(1, a_width - shift_amount);
 					} else {
 						primop = "dshr";
+						firrtl_width = a_width;
+					}
+					// We'll need to do some special fixups if the source (and thus result) is signed.
+					if (firrtl_is_signed) {
+						// If this is a "logical" shift right, pretend the source is unsigned.
+						if (cell->type == "$shr") {
+							a_expr = "asUInt(" + a_expr + ")";
+						}
 					}
 				}
 				else if ((cell->type == "$logic_and")) {
-                                        primop = "and";
-                                        a_expr = "neq(" + a_expr + ", UInt(0))";
-                                        b_expr = "neq(" + b_expr + ", UInt(0))";
-                                        always_uint = true;
-                                }
+					primop = "and";
+					a_expr = "neq(" + a_expr + ", UInt(0))";
+					b_expr = "neq(" + b_expr + ", UInt(0))";
+					always_uint = true;
+					firrtl_width = 1;
+				}
 				else if ((cell->type == "$logic_or")) {
-                                        primop = "or";
-                                        a_expr = "neq(" + a_expr + ", UInt(0))";
-                                        b_expr = "neq(" + b_expr + ", UInt(0))";
-                                        always_uint = true;
-                                }
+					primop = "or";
+					a_expr = "neq(" + a_expr + ", UInt(0))";
+					b_expr = "neq(" + b_expr + ", UInt(0))";
+					always_uint = true;
+					firrtl_width = 1;
+				}
+				else if ((cell->type == "$pow")) {
+					if (a_sig.is_fully_const() && a_sig.as_int() == 2) {
+						// We'll convert this to a shift. To simplify things, change the a_expr to "1"
+						//	so we can use b_expr directly as a shift amount.
+						// Only support 2 ** N (i.e., shift left)
+						// FIRRTL will widen the result (y) by the amount of the shift.
+						// We'll need to offset this by extracting the un-widened portion as Verilog would do.
+						a_expr = firrtl_is_signed ? "SInt(1)" : "UInt(1)";
+						extract_y_bits = true;
+						// Is the shift amount constant?
+						auto b_sig = cell->getPort("\\B");
+						if (b_sig.is_fully_const()) {
+							primop = "shl";
+							int shiftAmount = b_sig.as_int();
+							if (shiftAmount < 0) {
+								log_error("Negative power exponent - %d: %s.%s\n", shiftAmount, log_id(module), log_id(cell));
+							}
+							b_expr = std::to_string(shiftAmount);
+							firrtl_width = a_width + shiftAmount;
+						} else {
+							primop = "dshl";
+							// Convert from FIRRTL left shift semantics.
+							b_expr = gen_dshl(b_expr, b_width);
+							firrtl_width = a_width + (1 << b_width) - 1;
+						}
+					} else {
+						log_error("Non power 2: %s.%s\n", log_id(module), log_id(cell));
+					}
+				}
 
 				if (!cell->parameters.at("\\B_SIGNED").as_bool()) {
 					b_expr = "asUInt(" + b_expr + ")";
 				}
 
-				string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
-
-				// Deal with FIRRTL's "shift widens" semantics
-				if (extract_y_bits) {
-					expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1);
+				string expr;
+				// Deal with $xnor == ~^ (not xor)
+				if (primop == "xnor") {
+					expr = stringf("not(xor(%s, %s))", a_expr.c_str(), b_expr.c_str());
+				} else {
+					expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
 				}
 
-				if ((is_signed && !always_uint) || cell->type.in("$sub"))
+				// Deal with FIRRTL's "shift widens" semantics, or the need to widen the FIRRTL result.
+				// If the operation is signed, the FIRRTL width will be 1 one bit larger.
+				if (extract_y_bits) {
+					expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1);
+				} else if (firrtl_is_signed && (firrtl_width + 1) < y_width) {
+					expr = stringf("pad(%s, %d)", expr.c_str(), y_width);
+				}
+
+				if ((firrtl_is_signed && !always_uint))
 					expr = stringf("asUInt(%s)", expr.c_str());
 
 				cell_exprs.push_back(stringf("    %s <= %s\n", y_id.c_str(), expr.c_str()));
@@ -618,7 +721,6 @@ struct FirrtlWorker
 
 			if (cell->type.in("$mux"))
 			{
-				string y_id = make_id(cell->name);
 				int width = cell->parameters.at("\\WIDTH").as_int();
 				string a_expr = make_expr(cell->getPort("\\A"));
 				string b_expr = make_expr(cell->getPort("\\B"));
@@ -762,15 +864,14 @@ struct FirrtlWorker
 				if (clkpol == false)
 					log_error("Negative edge clock on FF %s.%s.\n", log_id(module), log_id(cell));
 
-				string q_id = make_id(cell->name);
 				int width = cell->parameters.at("\\WIDTH").as_int();
 				string expr = make_expr(cell->getPort("\\D"));
 				string clk_expr = "asClock(" + make_expr(cell->getPort("\\CLK")) + ")";
 
-				wire_decls.push_back(stringf("    reg %s: UInt<%d>, %s\n", q_id.c_str(), width, clk_expr.c_str()));
+				wire_decls.push_back(stringf("    reg %s: UInt<%d>, %s\n", y_id.c_str(), width, clk_expr.c_str()));
 
-				cell_exprs.push_back(stringf("    %s <= %s\n", q_id.c_str(), expr.c_str()));
-				register_reverse_wire_map(q_id, cell->getPort("\\Q"));
+				cell_exprs.push_back(stringf("    %s <= %s\n", y_id.c_str(), expr.c_str()));
+				register_reverse_wire_map(y_id, cell->getPort("\\Q"));
 
 				continue;
 			}
@@ -785,8 +886,6 @@ struct FirrtlWorker
 				// assign y = a[b +: y_width];
 				// We'll extract the correct bits as part of the primop.
 
-				string y_id = make_id(cell->name);
-				int y_width =  cell->parameters.at("\\Y_WIDTH").as_int();
 				string a_expr = make_expr(cell->getPort("\\A"));
 				// Get the initial bit selector
 				string b_expr = make_expr(cell->getPort("\\B"));
@@ -808,18 +907,15 @@ struct FirrtlWorker
 				// assign y = a >> b;
 				//  where b may be negative
 
-				string y_id = make_id(cell->name);
-				int y_width =  cell->parameters.at("\\Y_WIDTH").as_int();
 				string a_expr = make_expr(cell->getPort("\\A"));
 				string b_expr = make_expr(cell->getPort("\\B"));
 				auto b_string = b_expr.c_str();
-				int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int();
 				string expr;
 				wire_decls.push_back(stringf("    wire %s: UInt<%d>\n", y_id.c_str(), y_width));
 
 				if (cell->getParam("\\B_SIGNED").as_bool()) {
 					// We generate a left or right shift based on the sign of b.
-					std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_padded_width).c_str(), y_width);
+					std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_width).c_str(), y_width);
 					std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
 					expr = stringf("mux(%s < 0, %s, %s)",
 									 b_string,
@@ -833,6 +929,20 @@ struct FirrtlWorker
 				register_reverse_wire_map(y_id, cell->getPort("\\Y"));
 				continue;
 			}
+			if (cell->type == "$pos") {
+				// assign y = a;
+//				printCell(cell);
+				string a_expr = make_expr(cell->getPort("\\A"));
+				// Verilog appears to treat the result as signed, so if the result is wider than "A",
+				//  we need to pad.
+				if (a_width < y_width) {
+					a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
+				}
+				wire_decls.push_back(stringf("    wire %s: UInt<%d>\n", y_id.c_str(), y_width));
+				cell_exprs.push_back(stringf("    %s <= %s\n", y_id.c_str(), a_expr.c_str()));
+				register_reverse_wire_map(y_id, cell->getPort("\\Y"));
+				continue;
+			}
 			log_warning("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
 		}
 
diff --git a/tests/simple/xfirrtl b/tests/simple/xfirrtl
index ba61a4476..10063d2c2 100644
--- a/tests/simple/xfirrtl
+++ b/tests/simple/xfirrtl
@@ -1,10 +1,12 @@
 # This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures.
 arraycells.v	inst id[0] of
+defvalue.sv	Initial value not supported
 dff_different_styles.v
 dff_init.v	Initial value not supported
 generate.v	combinational loop
 hierdefparam.v	inst id[0] of
 i2c_master_tests.v   $adff
+implicit_ports.v     not fully initialized
 macros.v	drops modules
 mem2reg.v	drops modules
 mem_arst.v	$adff
@@ -12,7 +14,6 @@ memory.v	$adff
 multiplier.v	inst id[0] of
 muxtree.v	drops modules
 omsp_dbg_uart.v	$adff
-operators.v	$pow
 partsel.v	drops modules
 process.v	drops modules
 realexpr.v	drops modules
@@ -23,5 +24,6 @@ specify.v	no code (empty module generates error
 subbytes.v	$adff
 task_func.v	drops modules
 values.v	combinational loop
+wandwor.v	Invalid connect to an expression that is not a reference or a WritePort.
 vloghammer.v	combinational loop
 wreduce.v	original verilog issues ( -x where x isn't declared signed)

From 15fae357f6c7a5c205d2733cd0b2640eecd17a2d Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Thu, 1 Aug 2019 12:34:52 +0200
Subject: [PATCH 31/53] Implement improved JSON attr/param encoding

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 backends/json/json.cc | 50 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 37 insertions(+), 13 deletions(-)

diff --git a/backends/json/json.cc b/backends/json/json.cc
index dda4dfedd..107009ee4 100644
--- a/backends/json/json.cc
+++ b/backends/json/json.cc
@@ -83,20 +83,43 @@ struct JsonWriter
 		return str + " ]";
 	}
 
+	void write_parameter_value(const Const &value)
+	{
+		if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) {
+			string str = value.decode_string();
+			int state = 0;
+			for (char c : str) {
+				if (state == 0) {
+					if (c == '0' || c == '1' || c == 'x' || c == 'z')
+						state = 0;
+					else if (c == ' ')
+						state = 1;
+					else
+						state = 2;
+				} else if (state == 1 && c != ' ')
+					state = 2;
+			}
+			if (state < 2)
+				str += " ";
+			f << get_string(str);
+		} else
+		if (GetSize(value) == 32 && value.is_fully_def()) {
+			if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
+				f << stringf("%d", value.as_int());
+			else
+				f << stringf("%u", value.as_int());
+		} else {
+			f << get_string(value.as_string());
+		}
+	}
+
 	void write_parameters(const dict<IdString, Const> &parameters, bool for_module=false)
 	{
 		bool first = true;
 		for (auto &param : parameters) {
 			f << stringf("%s\n", first ? "" : ",");
 			f << stringf("        %s%s: ", for_module ? "" : "    ", get_name(param.first).c_str());
-			if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0)
-				f << get_string(param.second.decode_string());
-			else if (GetSize(param.second.bits) > 32)
-				f << get_string(param.second.as_string());
-			else if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
-				f << stringf("%d", param.second.as_int());
-			else
-				f << stringf("%u", param.second.as_int());
+			write_parameter_value(param.second);
 			first = false;
 		}
 	}
@@ -342,12 +365,13 @@ struct JsonBackend : public Backend {
 		log("Module and cell ports and nets can be single bit wide or vectors of multiple\n");
 		log("bits. Each individual signal bit is assigned a unique integer. The <bit_vector>\n");
 		log("values referenced above are vectors of this integers. Signal bits that are\n");
-		log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n");
-		log("a number.\n");
+		log("connected to a constant driver are denoted as string \"0\", \"1\", \"x\", or\n");
+		log("\"z\" instead of a number.\n");
 		log("\n");
-		log("Numeric parameter and attribute values up to 32 bits are written as decimal\n");
-		log("values. Numbers larger than that are written as string holding the binary\n");
-		log("representation of the value.\n");
+		log("Numeric 32-bit parameter and attribute values are written as decimal values.\n");
+		log("Bit verctors of different sizes, or ones containing 'x' or 'z' bits, are written\n");
+		log("as string holding the binary representation of the value. Strings are written\n");
+		log("as strings, with an appended blank in cases of strings of the form /[01xz]* */.\n");
 		log("\n");
 		log("For example the following Verilog code:\n");
 		log("\n");

From 292f03355a425ede48051c79d5bf619591531080 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Thu, 1 Aug 2019 12:48:22 +0200
Subject: [PATCH 32/53] Update JSON front-end to process new attr/param
 encoding

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 frontends/json/jsonparse.cc | 57 ++++++++++++++++++++++---------------
 1 file changed, 34 insertions(+), 23 deletions(-)

diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc
index f5ae8eb72..7aceffbfc 100644
--- a/frontends/json/jsonparse.cc
+++ b/frontends/json/jsonparse.cc
@@ -25,7 +25,7 @@ struct JsonNode
 {
 	char type; // S=String, N=Number, A=Array, D=Dict
 	string data_string;
-	int data_number;
+	int64_t data_number;
 	vector<JsonNode*> data_array;
 	dict<string, JsonNode*> data_dict;
 	vector<string> data_dict_keys;
@@ -206,6 +206,38 @@ struct JsonNode
 	}
 };
 
+Const json_parse_attr_param_value(JsonNode *node)
+{
+	Const value;
+
+	if (node->type == 'S') {
+		string &s = node->data_string;
+		size_t cursor = s.find_first_not_of("01xz");
+		if (cursor == string::npos) {
+			value = Const::from_string(s);
+		} else if (s.find_first_not_of(' ', cursor) == string::npos) {
+			value = Const(s.substr(0, GetSize(s)-1));
+		} else {
+			value = Const(s);
+		}
+	} else
+	if (node->type == 'N') {
+		value = Const(node->data_number, 32);
+		if (node->data_number < 0)
+			value.flags |= RTLIL::CONST_FLAG_SIGNED;
+	} else
+	if (node->type == 'A') {
+		log_error("JSON attribute or parameter value is an array.\n");
+	} else
+	if (node->type == 'D') {
+		log_error("JSON attribute or parameter value is a dict.\n");
+	} else {
+		log_abort();
+	}
+
+	return value;
+}
+
 void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node)
 {
 	if (node->type != 'D')
@@ -214,28 +246,7 @@ void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node)
 	for (auto it : node->data_dict)
 	{
 		IdString key = RTLIL::escape_id(it.first.c_str());
-		JsonNode *value_node = it.second;
-		Const value;
-
-		if (value_node->type == 'S') {
-			string &s = value_node->data_string;
-			if (s.find_first_not_of("01xz") == string::npos)
-				value = Const::from_string(s);
-			else
-				value = Const(s);
-		} else
-		if (value_node->type == 'N') {
-			value = Const(value_node->data_number, 32);
-		} else
-		if (value_node->type == 'A') {
-			log_error("JSON attribute or parameter value is an array.\n");
-		} else
-		if (value_node->type == 'D') {
-			log_error("JSON attribute or parameter value is a dict.\n");
-		} else {
-			log_abort();
-		}
-
+		Const value = json_parse_attr_param_value(it.second);
 		results[key] = value;
 	}
 }

From 320bf2fde55f72e7c0b35a0d9452e3777f13183d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Nguyen?= <jf@lambdaconcept.com>
Date: Wed, 31 Jul 2019 14:26:09 +0200
Subject: [PATCH 33/53] proc_prune: Promote partially redundant assignments.

---
 passes/proc/proc_prune.cc | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/passes/proc/proc_prune.cc b/passes/proc/proc_prune.cc
index 9e00b0a8a..b47ee79c2 100644
--- a/passes/proc/proc_prune.cc
+++ b/passes/proc/proc_prune.cc
@@ -82,14 +82,23 @@ struct PruneWorker
 				if (root) {
 					bool promotable = true;
 					for (auto &bit : lhs) {
-						if (bit.wire && affected[bit]) {
+						if (bit.wire && affected[bit] && !assigned[bit]) {
 							promotable = false;
 							break;
 						}
 					}
 					if (promotable) {
+						RTLIL::SigSpec rhs = sigmap(it->second);
+						RTLIL::SigSig conn;
+						for (int i = 0; i < GetSize(lhs); i++) {
+							RTLIL::SigBit lhs_bit = lhs[i];
+							if (lhs_bit.wire && !assigned[lhs_bit]) {
+								conn.first.append_bit(lhs_bit);
+								conn.second.append(rhs.extract(i));
+							}
+						}
 						promoted_count++;
-						module->connect(*it);
+						module->connect(conn);
 						remove.insert(*it);
 					}
 				}

From 28b7053a01630def454e683f03953c74744da025 Mon Sep 17 00:00:00 2001
From: Miodrag Milanovic <mmicko@gmail.com>
Date: Wed, 31 Jul 2019 11:49:48 +0200
Subject: [PATCH 34/53] Fix formatting for msys2 mingw build using GetSize

---
 Makefile                                   |  2 ++
 backends/aiger/xaiger.cc                   | 12 ++++++------
 frontends/aiger/aigerparse.cc              |  4 ++++
 misc/launcher.c                            |  3 ++-
 passes/opt/opt_lut.cc                      |  8 ++++----
 passes/opt/rmports.cc                      |  2 +-
 passes/techmap/flowmap.cc                  | 10 +++++-----
 techlibs/anlogic/anlogic_determine_init.cc |  4 ++--
 techlibs/anlogic/anlogic_eqn.cc            |  4 ++--
 techlibs/gowin/determine_init.cc           |  4 ++--
 10 files changed, 30 insertions(+), 23 deletions(-)

diff --git a/Makefile b/Makefile
index c33864469..d049c2eda 100644
--- a/Makefile
+++ b/Makefile
@@ -869,9 +869,11 @@ config-mxe: clean
 
 config-msys2: clean
 	echo 'CONFIG := msys2' > Makefile.conf
+	echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
 
 config-msys2-64: clean
 	echo 'CONFIG := msys2-64' > Makefile.conf
+	echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
 
 config-cygwin: clean
 	echo 'CONFIG := cygwin' > Makefile.conf
diff --git a/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc
index 69f63486c..9f56d1ab6 100644
--- a/backends/aiger/xaiger.cc
+++ b/backends/aiger/xaiger.cc
@@ -610,15 +610,15 @@ struct XAigerWriter
 			std::stringstream h_buffer;
 			auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1);
 			write_h_buffer(1);
-			log_debug("ciNum = %zu\n", input_bits.size() + ci_bits.size());
+			log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ci_bits));
 			write_h_buffer(input_bits.size() + ci_bits.size());
-			log_debug("coNum = %zu\n", output_bits.size() + co_bits.size());
+			log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(co_bits));
 			write_h_buffer(output_bits.size() + co_bits.size());
-			log_debug("piNum = %zu\n", input_bits.size());
+			log_debug("piNum = %d\n", GetSize(input_bits));
 			write_h_buffer(input_bits.size());
-			log_debug("poNum = %zu\n", output_bits.size());
+			log_debug("poNum = %d\n", GetSize(output_bits));
 			write_h_buffer(output_bits.size());
-			log_debug("boxNum = %zu\n", box_list.size());
+			log_debug("boxNum = %d\n", GetSize(box_list));
 			write_h_buffer(box_list.size());
 
 			RTLIL::Module *holes_module = nullptr;
@@ -772,7 +772,7 @@ struct XAigerWriter
 
 				if (output_bits.count(b)) {
 					int o = ordered_outputs.at(b);
-					output_lines[o] += stringf("output %lu %d %s\n", o - co_bits.size(), i, log_id(wire));
+					output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), i, log_id(wire));
 					continue;
 				}
 
diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc
index 03c541b7c..bb97c5703 100644
--- a/frontends/aiger/aigerparse.cc
+++ b/frontends/aiger/aigerparse.cc
@@ -301,7 +301,11 @@ static uint32_t parse_xaiger_literal(std::istream &f)
 	uint32_t l;
 	f.read(reinterpret_cast<char*>(&l), sizeof(l));
 	if (f.gcount() != sizeof(l))
+#if defined(_WIN32) && defined(__MINGW32__)
+		log_error("Offset %I64d: unable to read literal!\n", static_cast<int64_t>(f.tellg()));
+#else
 		log_error("Offset %" PRId64 ": unable to read literal!\n", static_cast<int64_t>(f.tellg()));
+#endif
 	return from_big_endian(l);
 }
 
diff --git a/misc/launcher.c b/misc/launcher.c
index 157d68cf3..e0d8208f1 100644
--- a/misc/launcher.c
+++ b/misc/launcher.c
@@ -61,6 +61,7 @@ SOFTWARE. */
 #include <windows.h>
 #include <tchar.h>
 #include <fcntl.h>
+#include <unistd.h>
 
 int child_pid=0;
 
@@ -338,7 +339,7 @@ int run(int argc, char **argv, int is_gui) {
 
     if (is_gui) {
         /* Use exec, we don't need to wait for the GUI to finish */
-        execv(ptr, (const char * const *)(newargs));
+        execv(ptr, (char * const *)(newargs));
         return fail("Could not exec %s", ptr);   /* shouldn't get here! */
     }
 
diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc
index 182f63d99..587ef878a 100644
--- a/passes/opt/opt_lut.cc
+++ b/passes/opt/opt_lut.cc
@@ -81,7 +81,7 @@ struct OptLutWorker
 			}
 		}
 
-		log("Number of LUTs: %8zu\n", luts.size());
+		log("Number of LUTs: %8d\n", GetSize(luts));
 		for (int arity = 1; arity <= max_arity; arity++)
 		{
 			if (arity_counts[arity])
@@ -351,14 +351,14 @@ struct OptLutWorker
 
 					int lutM_arity = lutA_arity + lutB_arity - 1 - common_inputs.size();
 					if (lutA_dlogic_inputs.size())
-						log_debug("  Cell A is a %d-LUT with %zu dedicated connections. ", lutA_arity, lutA_dlogic_inputs.size());
+						log_debug("  Cell A is a %d-LUT with %d dedicated connections. ", lutA_arity, GetSize(lutA_dlogic_inputs));
 					else
 						log_debug("  Cell A is a %d-LUT. ", lutA_arity);
 					if (lutB_dlogic_inputs.size())
-						log_debug("Cell B is a %d-LUT with %zu dedicated connections.\n", lutB_arity, lutB_dlogic_inputs.size());
+						log_debug("Cell B is a %d-LUT with %d dedicated connections.\n", lutB_arity, GetSize(lutB_dlogic_inputs));
 					else
 						log_debug("Cell B is a %d-LUT.\n", lutB_arity);
-					log_debug("  Cells share %zu input(s) and can be merged into one %d-LUT.\n", common_inputs.size(), lutM_arity);
+					log_debug("  Cells share %d input(s) and can be merged into one %d-LUT.\n", GetSize(common_inputs), lutM_arity);
 
 					const int COMBINE_A = 1, COMBINE_B = 2, COMBINE_EITHER = COMBINE_A | COMBINE_B;
 					int combine_mask = 0;
diff --git a/passes/opt/rmports.cc b/passes/opt/rmports.cc
index fc1596ebf..32363dd68 100644
--- a/passes/opt/rmports.cc
+++ b/passes/opt/rmports.cc
@@ -171,7 +171,7 @@ struct RmportsPassPass : public Pass {
 			wire->port_output = false;
 			wire->port_id = 0;
 		}
-		log("Removed %zu unused ports.\n", unused_ports.size());
+		log("Removed %d unused ports.\n", GetSize(unused_ports));
 
 		// Re-number all of the wires that DO have ports still on them
 		for(size_t i=0; i<module->ports.size(); i++)
diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc
index f5892a60e..96d0df5f8 100644
--- a/passes/techmap/flowmap.cc
+++ b/passes/techmap/flowmap.cc
@@ -783,7 +783,7 @@ struct FlowmapWorker
 		int depth = 0;
 		for (auto label : labels)
 			depth = max(depth, label.second);
-		log("Mapped to %zu LUTs with maximum depth %d.\n", lut_nodes.size(), depth);
+		log("Mapped to %d LUTs with maximum depth %d.\n", GetSize(lut_nodes), depth);
 
 		if (debug)
 		{
@@ -1195,7 +1195,7 @@ struct FlowmapWorker
 
 	bool relax_depth_for_bound(bool first, int depth_bound, dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs)
 	{
-		size_t initial_count = lut_nodes.size();
+		int initial_count = GetSize(lut_nodes);
 
 		for (auto node : lut_nodes)
 		{
@@ -1215,7 +1215,7 @@ struct FlowmapWorker
 
 			if (potentials.empty())
 			{
-				log("  Relaxed to %zu (+%zu) LUTs.\n", lut_nodes.size(), lut_nodes.size() - initial_count);
+				log("  Relaxed to %d (+%d) LUTs.\n", GetSize(lut_nodes), GetSize(lut_nodes) - initial_count);
 				if (!first && break_num == 1)
 				{
 					log("  Design fully relaxed.\n");
@@ -1419,9 +1419,9 @@ struct FlowmapWorker
 			lut_area += lut_table.size();
 
 			if ((int)input_nodes.size() >= minlut)
-				log("  Packed into a %zu-LUT %s.%s.\n", input_nodes.size(), log_id(module), log_id(lut));
+				log("  Packed into a %d-LUT %s.%s.\n", GetSize(input_nodes), log_id(module), log_id(lut));
 			else
-				log("  Packed into a %zu-LUT %s.%s (implemented as %d-LUT).\n", input_nodes.size(), log_id(module), log_id(lut), minlut);
+				log("  Packed into a %d-LUT %s.%s (implemented as %d-LUT).\n", GetSize(input_nodes), log_id(module), log_id(lut), minlut);
 		}
 
 		for (auto node : mapped_nodes)
diff --git a/techlibs/anlogic/anlogic_determine_init.cc b/techlibs/anlogic/anlogic_determine_init.cc
index 34b1d4f8a..c4089dac2 100644
--- a/techlibs/anlogic/anlogic_determine_init.cc
+++ b/techlibs/anlogic/anlogic_determine_init.cc
@@ -50,7 +50,7 @@ struct AnlogicDetermineInitPass : public Pass {
 
 		extra_args(args, args.size(), design);
 
-		size_t cnt = 0;
+		int cnt = 0;
 		for (auto module : design->selected_modules())
 		{
 			for (auto cell : module->selected_cells())
@@ -65,7 +65,7 @@ struct AnlogicDetermineInitPass : public Pass {
 				}
 			}
 		}
-		log_header(design, "Updated %lu cells with determined init value.\n", cnt);
+		log_header(design, "Updated %d cells with determined init value.\n", cnt);
 	}
 } AnlogicDetermineInitPass;
 
diff --git a/techlibs/anlogic/anlogic_eqn.cc b/techlibs/anlogic/anlogic_eqn.cc
index 741bf04cc..070d39a20 100644
--- a/techlibs/anlogic/anlogic_eqn.cc
+++ b/techlibs/anlogic/anlogic_eqn.cc
@@ -69,7 +69,7 @@ struct AnlogicEqnPass : public Pass {
 
 		extra_args(args, args.size(), design);
 
-		size_t cnt = 0;
+		int cnt = 0;
 		for (auto module : design->selected_modules())
 		{
 			for (auto cell : module->selected_cells())
@@ -106,7 +106,7 @@ struct AnlogicEqnPass : public Pass {
 				}
 			}
 		}
-		log_header(design, "Updated %lu of AL_MAP_LUT* elements with equation.\n", cnt);
+		log_header(design, "Updated %d of AL_MAP_LUT* elements with equation.\n", cnt);
 	}
 } AnlogicEqnPass;
 
diff --git a/techlibs/gowin/determine_init.cc b/techlibs/gowin/determine_init.cc
index 991e5245a..d9a0880f6 100644
--- a/techlibs/gowin/determine_init.cc
+++ b/techlibs/gowin/determine_init.cc
@@ -50,7 +50,7 @@ struct DetermineInitPass : public Pass {
 
 		extra_args(args, args.size(), design);
 
-		size_t cnt = 0;
+		int cnt = 0;
 		for (auto module : design->selected_modules())
 		{
 			for (auto cell : module->selected_cells())
@@ -65,7 +65,7 @@ struct DetermineInitPass : public Pass {
 				}
 			}
 		}
-		log_header(design, "Updated %lu cells with determined init value.\n", cnt);
+		log_header(design, "Updated %d cells with determined init value.\n", cnt);
 	}
 } DetermineInitPass;
 

From f767179c759065d4b31eb64c81594c378d626704 Mon Sep 17 00:00:00 2001
From: Miodrag Milanovic <mmicko@gmail.com>
Date: Wed, 31 Jul 2019 17:30:48 +0200
Subject: [PATCH 35/53] New mxe hacks needed to support 2ca237e

---
 kernel/yosys.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/kernel/yosys.h b/kernel/yosys.h
index 84c797b2d..09e8139bb 100644
--- a/kernel/yosys.h
+++ b/kernel/yosys.h
@@ -88,6 +88,10 @@ extern int Tcl_EvalFile(Tcl_Interp *interp, const char *fileName);
 extern void Tcl_Finalize(void);
 extern int Tcl_GetCommandInfo(Tcl_Interp *interp, const char *cmdName, Tcl_CmdInfo *infoPtr);
 extern const char *Tcl_GetStringResult(Tcl_Interp *interp);
+extern Tcl_Obj *Tcl_NewStringObj(const char *bytes, int length);
+extern Tcl_Obj *Tcl_NewIntObj(int intValue);
+extern Tcl_Obj *Tcl_NewListObj(int objc, Tcl_Obj *const objv[]);
+extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *part2Ptr, Tcl_Obj *newValuePtr, int flags);
 #  endif
 #endif
 

From 3f633690ae3d0c8753866d136851b8f0129cb643 Mon Sep 17 00:00:00 2001
From: Miodrag Milanovic <mmicko@gmail.com>
Date: Wed, 31 Jul 2019 17:31:07 +0200
Subject: [PATCH 36/53] Fix yosys linking for mxe

---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index d049c2eda..1560d6de6 100644
--- a/Makefile
+++ b/Makefile
@@ -401,7 +401,7 @@ endif
 
 ifeq ($(CONFIG),mxe)
 CXXFLAGS += -DYOSYS_ENABLE_TCL
-LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz
+LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz -luserenv
 else
 CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL
 ifeq ($(OS), FreeBSD)

From 7a65ed19a5921ff219fd208d2712e09b5e5894dd Mon Sep 17 00:00:00 2001
From: Miodrag Milanovic <mmicko@gmail.com>
Date: Wed, 31 Jul 2019 18:02:27 +0200
Subject: [PATCH 37/53] Fix linking issue for new mxe and pthread

---
 Makefile | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 1560d6de6..a697e9844 100644
--- a/Makefile
+++ b/Makefile
@@ -261,7 +261,8 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
 LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
 LDLIBS := $(filter-out -lrt,$(LDLIBS))
 ABCMKARGS += ARCHFLAGS="-DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
-ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc"
+# TODO: Try to solve pthread linking issue in more appropriate way
+ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" LDFLAGS="-Wl,--allow-multiple-definition" ABC_USE_NO_READLINE=1 CC="/usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc"
 EXE = .exe
 
 else ifeq ($(CONFIG),msys2)

From 837cb0a1b9c9a774512481d0812c28f927985e7b Mon Sep 17 00:00:00 2001
From: Miodrag Milanovic <mmicko@gmail.com>
Date: Sat, 3 Aug 2019 14:47:33 +0200
Subject: [PATCH 38/53] anlogic : Fix alu mapping

---
 techlibs/anlogic/arith_map.v | 24 ++++++++----------------
 1 file changed, 8 insertions(+), 16 deletions(-)

diff --git a/techlibs/anlogic/arith_map.v b/techlibs/anlogic/arith_map.v
index 11cd140ec..6d6a7ca37 100644
--- a/techlibs/anlogic/arith_map.v
+++ b/techlibs/anlogic/arith_map.v
@@ -42,10 +42,9 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
 	wire [Y_WIDTH-1:0] AA = A_buf;
 	wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
 	wire [Y_WIDTH+1:0] COx;
-	wire [Y_WIDTH+1:0] C = {COx, CI};
+	wire [Y_WIDTH+2:0] C = {COx, CI};
 
     wire dummy;
-	(* keep *)
     AL_MAP_ADDER #(
     	.ALUTYPE("ADD_CARRY"))
     adder_cin  (
@@ -55,19 +54,6 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
 
 	genvar i;
 	generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice
-	  if(i==Y_WIDTH-1) begin
-	  		(* keep *)
-			AL_MAP_ADDER #(
-				.ALUTYPE("ADD"))
-			adder_cout  (
-				.c(C[Y_WIDTH]),
-				.o(COx[Y_WIDTH])
-			);				
-            assign CO = COx[Y_WIDTH];
-          end
-	  else
-	  begin
-	  	(* keep *)
 	    AL_MAP_ADDER #(
             .ALUTYPE("ADD")
         ) adder_i (
@@ -76,9 +62,15 @@ module _80_anlogic_alu (A, B, CI, BI, X, Y, CO);
             .c(C[i+1]),
             .o({COx[i+1],Y[i]})
         );
-		end		
 	  end: slice
 	endgenerate
 	/* End implementation */
+	AL_MAP_ADDER #(
+		.ALUTYPE("ADD"))
+	adder_cout  (
+		.c(C[Y_WIDTH+1]),
+		.o(COx[Y_WIDTH+1])
+	);				
+	assign CO = COx[Y_WIDTH+1];
 	assign X = AA ^ BB;
 endmodule
\ No newline at end of file

From 023086bd46bc828621ebb171b159efe1398aaecf Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Tue, 6 Aug 2019 04:47:55 +0200
Subject: [PATCH 39/53] Add $_NMUX_, add "abc -g cmos", add proper cmos cell
 costs

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 CHANGELOG                           |  1 +
 backends/blif/blif.cc               |  7 +++
 backends/btor/btor.cc               |  8 ++-
 backends/simplec/simplec.cc         |  6 +-
 backends/smt2/smt2.cc               |  1 +
 backends/smv/smv.cc                 |  7 +++
 backends/verilog/verilog_backend.cc | 14 +++++
 kernel/cellaigs.cc                  |  2 +
 kernel/celltypes.h                  |  1 +
 kernel/consteval.h                  |  7 ++-
 kernel/cost.h                       | 34 +++++++++--
 kernel/rtlil.cc                     |  2 +
 kernel/rtlil.h                      |  2 +
 kernel/satgen.h                     |  7 ++-
 manual/CHAPTER_CellLib.tex          |  2 +-
 passes/cmds/stat.cc                 |  4 ++
 passes/techmap/abc.cc               | 90 ++++++++++++++++++++---------
 passes/techmap/extract_fa.cc        |  2 +-
 techlibs/common/simcells.v          | 19 ++++++
 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
@@ -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)

From f1f5b4e375f6347424cf7877ed6415bf9c71420e Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Tue, 6 Aug 2019 18:06:14 +0200
Subject: [PATCH 40/53] Fix handling of functions/tasks without top-level
 begin-end block, fixes #1231

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 frontends/ast/simplify.cc | 17 ++---------------
 1 file changed, 2 insertions(+), 15 deletions(-)

diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index e947125bf..6fb94d80b 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -3439,19 +3439,11 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
 {
 	std::map<std::string, AstNode*> backup_scope;
 	std::map<std::string, AstNode::varinfo_t> variables;
-	bool delete_temp_block = false;
-	AstNode *block = NULL;
+	AstNode *block = new AstNode(AST_BLOCK);
 
 	size_t argidx = 0;
 	for (auto child : children)
 	{
-		if (child->type == AST_BLOCK)
-		{
-			log_assert(block == NULL);
-			block = child;
-			continue;
-		}
-
 		if (child->type == AST_WIRE)
 		{
 			while (child->simplify(true, false, false, 1, -1, false, true)) { }
@@ -3468,13 +3460,9 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
 			continue;
 		}
 
-		log_assert(block == NULL);
-		delete_temp_block = true;
-		block = new AstNode(AST_BLOCK);
 		block->children.push_back(child->clone());
 	}
 
-	log_assert(block != NULL);
 	log_assert(variables.count(str) != 0);
 
 	while (!block->children.empty())
@@ -3642,8 +3630,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
 		log_abort();
 	}
 
-	if (delete_temp_block)
-		delete block;
+	delete block;
 
 	for (auto &it : backup_scope)
 		if (it.second == NULL)

From 27360ceda62691ab4f052f396a9174487076ce9a Mon Sep 17 00:00:00 2001
From: David Shah <dave@ds0.me>
Date: Mon, 29 Jul 2019 09:28:31 +0100
Subject: [PATCH 41/53] Add support for writing gzip-compressed files

Signed-off-by: David Shah <dave@ds0.me>
---
 CHANGELOG          |  1 +
 kernel/register.cc | 67 +++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 61 insertions(+), 7 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index 9e9bda6e9..661581433 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -16,6 +16,7 @@ Yosys 0.9 .. Yosys 0.9-dev
     - "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable)
     - Added automatic gzip decompression for frontends
     - Added $_NMUX_ cell type
+    - Added automatic gzip compression (based on filename extension) for backends
 
 Yosys 0.8 .. Yosys 0.8-dev
 --------------------------
diff --git a/kernel/register.cc b/kernel/register.cc
index 4c6e3591f..4f60338e9 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -41,6 +41,45 @@ void decompress_gzip(const std::string &filename, std::stringstream &out)
 	}
 	gzclose(gzf);
 }
+
+/*
+An output stream that uses a stringbuf to buffer data internally,
+using zlib to write gzip-compressed data every time the stream is flushed.
+*/
+class gzip_ostream : public std::ostream  {
+public:
+	gzip_ostream()
+	{
+		rdbuf(&outbuf);
+	}
+	bool open(const std::string &filename)
+	{
+		return outbuf.open(filename);
+	}
+private:
+	class gzip_streambuf : public std::stringbuf {
+	public:
+		gzip_streambuf() { };
+		bool open(const std::string &filename)
+		{
+			gzf = gzopen(filename.c_str(), "wb");
+			return gzf != nullptr;
+		}
+		virtual int sync() override
+		{
+			gzwrite(gzf, reinterpret_cast<const void *>(str().c_str()), unsigned(str().size()));
+			str("");
+			return 0;
+		}
+		~gzip_streambuf()
+		{
+			sync();
+			gzclose(gzf);
+		}
+	private:
+		gzFile gzf = nullptr;
+	} outbuf;
+};
 PRIVATE_NAMESPACE_END
 
 #endif
@@ -588,14 +627,28 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st
 
 		filename = arg;
 		rewrite_filename(filename);
-		std::ofstream *ff = new std::ofstream;
-		ff->open(filename.c_str(), std::ofstream::trunc);
-		yosys_output_files.insert(filename);
-		if (ff->fail()) {
-			delete ff;
-			log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+		if (filename.size() > 3 && filename.substr(filename.size()-3) == ".gz") {
+#ifdef YOSYS_ENABLE_ZLIB
+			gzip_ostream *gf = new gzip_ostream;
+			if (!gf->open(filename)) {
+				delete gf;
+				log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+			}
+			yosys_output_files.insert(filename);
+			f = gf;
+#else
+			log_cmd_error("Yosys is compiled without zlib support, unable to write gzip output.\n");
+#endif
+		} else {
+			std::ofstream *ff = new std::ofstream;
+			ff->open(filename.c_str(), std::ofstream::trunc);
+			yosys_output_files.insert(filename);
+			if (ff->fail()) {
+				delete ff;
+				log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+			}
+			f = ff;
 		}
-		f = ff;
 	}
 
 	if (called_with_fp)

From 3a3da678ad0902ad0b16fe48cbb10053cd7dcb28 Mon Sep 17 00:00:00 2001
From: David Shah <dave@ds0.me>
Date: Wed, 31 Jul 2019 13:58:27 +0100
Subject: [PATCH 42/53] Add test for writing gzip-compressed files

Signed-off-by: David Shah <dave@ds0.me>
---
 tests/various/.gitignore    |  2 ++
 tests/various/write_gzip.ys | 16 ++++++++++++++++
 2 files changed, 18 insertions(+)
 create mode 100644 tests/various/write_gzip.ys

diff --git a/tests/various/.gitignore b/tests/various/.gitignore
index 7b3e8c68e..31078b298 100644
--- a/tests/various/.gitignore
+++ b/tests/various/.gitignore
@@ -1,2 +1,4 @@
 /*.log
 /*.out
+/write_gzip.v
+/write_gzip.v.gz
diff --git a/tests/various/write_gzip.ys b/tests/various/write_gzip.ys
new file mode 100644
index 000000000..030ec318e
--- /dev/null
+++ b/tests/various/write_gzip.ys
@@ -0,0 +1,16 @@
+read -vlog2k <<EOT
+module top(input a, output y);
+assign y = !a;
+endmodule
+EOT
+
+prep -top top
+write_verilog write_gzip.v.gz
+design -reset
+
+! rm -f write_gzip.v
+! gunzip write_gzip.v.gz
+read -vlog2k write_gzip.v
+! rm -f write_gzip.v
+hierarchy -top top
+select -assert-any top

From 95a6582f342537d387063be10cba55c001ed19f5 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Tue, 6 Aug 2019 19:21:37 +0200
Subject: [PATCH 43/53] Be less aggressive with running design->check()

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 kernel/driver.cc   |  6 ++++++
 kernel/register.cc | 10 +++-------
 kernel/yosys.cc    | 10 ++++++++--
 3 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/kernel/driver.cc b/kernel/driver.cc
index f273057dd..70a97c4b9 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -522,6 +522,12 @@ int main(int argc, char **argv)
 	if (!backend_command.empty())
 		run_backend(output_filename, backend_command);
 
+	yosys_design->check();
+	for (auto it : saved_designs)
+		it.second->check();
+	for (auto it : pushed_designs)
+		it->check();
+
 	if (!depsfile.empty())
 	{
 		FILE *f = fopen(depsfile.c_str(), "wt");
diff --git a/kernel/register.cc b/kernel/register.cc
index 4c6e3591f..8f8f2c971 100644
--- a/kernel/register.cc
+++ b/kernel/register.cc
@@ -256,8 +256,6 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
 	pass_register[args[0]]->post_execute(state);
 	while (design->selection_stack.size() > orig_sel_stack_pos)
 		design->selection_stack.pop_back();
-
-	design->check();
 }
 
 void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command)
@@ -339,8 +337,10 @@ void ScriptPass::run(std::string command, std::string info)
 			log("        %s\n", command.c_str());
 		else
 			log("        %s    %s\n", command.c_str(), info.c_str());
-	} else
+	} else {
 		Pass::call(active_design, command);
+		active_design->check();
+	}
 }
 
 void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to)
@@ -534,8 +534,6 @@ void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string
 			args.push_back(filename);
 		frontend_register[args[0]]->execute(args, design);
 	}
-
-	design->check();
 }
 
 Backend::Backend(std::string name, std::string short_help) :
@@ -645,8 +643,6 @@ void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string f
 
 	while (design->selection_stack.size() > orig_sel_stack_pos)
 		design->selection_stack.pop_back();
-
-	design->check();
 }
 
 static struct CellHelpMessages {
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index 191b6d5c7..a4cc53f1a 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -964,14 +964,18 @@ void run_frontend(std::string filename, std::string command, std::string *backen
 					command += next_line;
 				}
 				handle_label(command, from_to_active, run_from, run_to);
-				if (from_to_active)
+				if (from_to_active) {
 					Pass::call(design, command);
+					design->check();
+				}
 			}
 
 			if (!command.empty()) {
 				handle_label(command, from_to_active, run_from, run_to);
-				if (from_to_active)
+				if (from_to_active) {
 					Pass::call(design, command);
+					design->check();
+				}
 			}
 		}
 		catch (...) {
@@ -1000,6 +1004,7 @@ void run_frontend(std::string filename, std::string command, std::string *backen
 		Pass::call(design, vector<string>({command, filename}));
 	else
 		Frontend::frontend_call(design, NULL, filename, command);
+	design->check();
 }
 
 void run_frontend(std::string filename, std::string command, RTLIL::Design *design)
@@ -1183,6 +1188,7 @@ void shell(RTLIL::Design *design)
 				design->selection_stack.pop_back();
 			log_reset_stack();
 		}
+		design->check();
 	}
 	if (command == NULL)
 		printf("exit\n");

From 51b39219cda35e782fe4372409edf5432f86741f Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Tue, 6 Aug 2019 15:24:49 -0700
Subject: [PATCH 44/53] Move LSB tests from wreduce to opt_expr

---
 tests/various/opt_expr.ys |  98 ++++++++++++++++++++++++++++++++++++
 tests/various/wreduce.ys  | 102 ++------------------------------------
 2 files changed, 101 insertions(+), 99 deletions(-)
 create mode 100644 tests/various/opt_expr.ys

diff --git a/tests/various/opt_expr.ys b/tests/various/opt_expr.ys
new file mode 100644
index 000000000..2165802d6
--- /dev/null
+++ b/tests/various/opt_expr.ys
@@ -0,0 +1,98 @@
+
+read_verilog <<EOT
+module opt_expr_add_test(input [3:0] i, input [7:0] j, output [8:0] o);
+    assign o = (i << 4) + j;
+endmodule
+EOT
+
+hierarchy -auto-top
+proc
+design -save gold
+
+opt_expr -fine
+wreduce
+
+select -assert-count 1 t:$add r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+##########
+
+read_verilog <<EOT
+module opt_expr_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o);
+    assign o = j - (i << 4);
+endmodule
+EOT
+
+hierarchy -auto-top
+proc
+design -save gold
+
+opt_expr -fine
+wreduce
+
+select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+##########
+
+read_verilog <<EOT
+module opt_expr_sub_test2(input [3:0] i, input [7:0] j, output [8:0] o);
+    assign o = (i << 4) - j;
+endmodule
+EOT
+
+hierarchy -auto-top
+proc
+design -save gold
+
+opt_expr -fine
+wreduce
+
+select -assert-count 1 t:$sub r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+##########
+
+read_verilog <<EOT
+module opt_expr_sub_test4(input [3:0] i, output [8:0] o);
+    assign o = 5'b00010 - i;
+endmodule
+EOT
+
+hierarchy -auto-top
+proc
+design -save gold
+
+opt_expr -fine
+wreduce
+
+select -assert-count 1 t:$sub r:A_WIDTH=2 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
diff --git a/tests/various/wreduce.ys b/tests/various/wreduce.ys
index deb99304d..7e4f1765a 100644
--- a/tests/various/wreduce.ys
+++ b/tests/various/wreduce.ys
@@ -1,78 +1,5 @@
-
 read_verilog <<EOT
-module wreduce_add_test(input [3:0] i, input [7:0] j, output [8:0] o);
-    assign o = (i << 4) + j;
-endmodule
-EOT
-
-hierarchy -auto-top
-proc
-design -save gold
-
-prep # calls wreduce
-
-select -assert-count 1 t:$add r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
-
-design -stash gate
-
-design -import gold -as gold
-design -import gate -as gate
-
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -verify -prove-asserts -show-ports miter
-
-##########
-
-read_verilog <<EOT
-module wreduce_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o);
-    assign o = j - (i << 4);
-endmodule
-EOT
-
-hierarchy -auto-top
-proc
-design -save gold
-
-prep # calls wreduce
-
-select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
-
-design -stash gate
-
-design -import gold -as gold
-design -import gate -as gate
-
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -verify -prove-asserts -show-ports miter
-
-##########
-
-read_verilog <<EOT
-module wreduce_sub_test2(input [3:0] i, input [7:0] j, output [8:0] o);
-    assign o = (i << 4) - j;
-endmodule
-EOT
-
-hierarchy -auto-top
-proc
-design -save gold
-
-prep # calls wreduce
-
-select -assert-count 1 t:$sub r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i
-
-design -stash gate
-
-design -import gold -as gold
-design -import gate -as gate
-
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -verify -prove-asserts -show-ports miter
-
-##########
-
-read_verilog <<EOT
-module wreduce_sub_test3(input [3:0] i, input [7:0] j, output [8:0] o);
+module wreduce_sub_test(input [3:0] i, input [7:0] j, output [8:0] o);
     assign o = (j >> 4) - i;
 endmodule
 EOT
@@ -81,7 +8,8 @@ hierarchy -auto-top
 proc
 design -save gold
 
-prep # calls wreduce
+opt_expr
+wreduce
 
 select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
 
@@ -92,27 +20,3 @@ design -import gate -as gate
 
 miter -equiv -flatten -make_assert -make_outputs gold gate miter
 sat -verify -prove-asserts -show-ports miter
-
-##########
-
-read_verilog <<EOT
-module wreduce_sub_test4(input [3:0] i, output [8:0] o);
-    assign o = 5'b00010 - i;
-endmodule
-EOT
-
-hierarchy -auto-top
-proc
-design -save gold
-
-prep # calls wreduce
-
-select -assert-count 1 t:$sub r:A_WIDTH=2 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
-
-design -stash gate
-
-design -import gold -as gold
-design -import gate -as gate
-
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-sat -verify -prove-asserts -show-ports miter

From 0b56be8c5634f8b953cd3d087b4b6e2a11a2c173 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Tue, 6 Aug 2019 15:24:55 -0700
Subject: [PATCH 45/53] Restore original SigSpec::extract()

---
 kernel/rtlil.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index f2c81db72..ba8472ec1 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -3355,7 +3355,7 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const
 {
 	unpack();
 	cover("kernel.rtlil.sigspec.extract_pos");
-	return std::vector<RTLIL::SigBit>(bits_.begin() + offset, length >= 0 ? bits_.begin() + offset + length : bits_.end() + length + 1);
+	return std::vector<RTLIL::SigBit>(bits_.begin() + offset, bits_.begin() + offset + length);
 }
 
 void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal)

From 84f52aee0d01378796792c9a2f068a22d955f586 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Tue, 6 Aug 2019 15:25:11 -0700
Subject: [PATCH 46/53] Add SigSpec::extract_end() convenience function

---
 kernel/rtlil.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/rtlil.h b/kernel/rtlil.h
index 633cb51d6..c07d39c65 100644
--- a/kernel/rtlil.h
+++ b/kernel/rtlil.h
@@ -788,6 +788,7 @@ public:
 	RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;
 	RTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;
 	RTLIL::SigSpec extract(int offset, int length = 1) const;
+	RTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); }
 
 	void append(const RTLIL::SigSpec &signal);
 	void append_bit(const RTLIL::SigBit &bit);

From bfc7164af7bf64cb2fe5d00e87bbfead841a4dc2 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Tue, 6 Aug 2019 15:25:50 -0700
Subject: [PATCH 47/53] Move LSB-trimming functionality from wreduce to
 opt_expr

---
 passes/opt/opt_expr.cc | 25 +++++++++++++++++++++++++
 passes/opt/wreduce.cc  | 24 +-----------------------
 2 files changed, 26 insertions(+), 23 deletions(-)

diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index 512ef0cbf..acdc39937 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -641,6 +641,31 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
 					did_something = true;
 				}
 			}
+
+			if (cell->type.in("$add", "$sub")) {
+				RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A"));
+				RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B"));
+				RTLIL::SigSpec sig_y = cell->getPort("\\Y");
+				bool sub = cell->type == "$sub";
+
+				int i;
+				for (i = 0; i < GetSize(sig_y); i++) {
+					if (sig_b.at(i, State::Sx) == State::S0 && sig_a.at(i, State::Sx) != State::Sx)
+						module->connect(sig_y[i], sig_a[i]);
+					else if (!sub && sig_a.at(i, State::Sx) == State::S0 && sig_b.at(i, State::Sx) != State::Sx)
+						module->connect(sig_y[i], sig_b[i]);
+					else
+						break;
+				}
+				if (i > 0) {
+					cover_list("opt.opt_expr.fine", "$add", "$sub", cell->type.str());
+					cell->setPort("\\A", sig_a.extract_end(i));
+					cell->setPort("\\B", sig_b.extract_end(i));
+					cell->setPort("\\Y", sig_y.extract_end(i));
+					cell->fixup_parameters();
+					did_something = true;
+				}
+			}
 		}
 
 		if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || cell->type == "$shift" || cell->type == "$shiftx" ||
diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc
index 22af0bd8b..1eeca2748 100644
--- a/passes/opt/wreduce.cc
+++ b/passes/opt/wreduce.cc
@@ -365,28 +365,6 @@ struct WreduceWorker
 			}
 		}
 
-		if (cell->type.in("$add", "$sub")) {
-			SigSpec A = mi.sigmap(cell->getPort("\\A"));
-			SigSpec B = mi.sigmap(cell->getPort("\\B"));
-			bool sub = cell->type == "$sub";
-
-			int i;
-			for (i = 0; i < GetSize(sig); i++) {
-				if (B.at(i, Sx) == S0 && A.at(i, Sx) != Sx)
-					module->connect(sig[i], A[i]);
-				else if (!sub && A.at(i, Sx) == S0 && B.at(i, Sx) != Sx)
-					module->connect(sig[i], B[i]);
-				else
-					break;
-			}
-			if (i > 0) {
-				cell->setPort("\\A", A.extract(i, -1));
-				cell->setPort("\\B", B.extract(i, -1));
-				sig.remove(0, i);
-				bits_removed += i;
-			}
-		}
-
 		if (GetSize(sig) == 0) {
 			log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
 			module->remove(cell);
@@ -394,7 +372,7 @@ struct WreduceWorker
 		}
 
 		if (bits_removed) {
-			log("Removed %d bits (of %d) from port Y of cell %s.%s (%s).\n",
+			log("Removed top %d bits (of %d) from port Y of cell %s.%s (%s).\n",
 					bits_removed, GetSize(sig) + bits_removed, log_id(module), log_id(cell), log_id(cell->type));
 			cell->setPort("\\Y", sig);
 			did_something = true;

From 769c750c226cfde5efcd1f75940b25f51330d67b Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Tue, 6 Aug 2019 15:38:43 -0700
Subject: [PATCH 48/53] Add signed test

---
 tests/various/wreduce.ys | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/tests/various/wreduce.ys b/tests/various/wreduce.ys
index 7e4f1765a..4257292f5 100644
--- a/tests/various/wreduce.ys
+++ b/tests/various/wreduce.ys
@@ -20,3 +20,29 @@ design -import gate -as gate
 
 miter -equiv -flatten -make_assert -make_outputs gold gate miter
 sat -verify -prove-asserts -show-ports miter
+
+##########
+
+read_verilog <<EOT
+module wreduce_sub_signed_test(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o);
+    assign o = (j >>> 4) - i;
+endmodule
+EOT
+
+hierarchy -auto-top
+proc
+design -save gold
+
+opt_expr
+wreduce
+
+dump
+select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter

From 2d1b517b01b6cd1ec35018d4c63aaa091fcc1917 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Tue, 6 Aug 2019 15:40:30 -0700
Subject: [PATCH 49/53] Add signed opt_expr tests

---
 tests/various/opt_expr.ys | 50 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/tests/various/opt_expr.ys b/tests/various/opt_expr.ys
index 2165802d6..0c61ac881 100644
--- a/tests/various/opt_expr.ys
+++ b/tests/various/opt_expr.ys
@@ -24,6 +24,31 @@ sat -verify -prove-asserts -show-ports miter
 
 ##########
 
+read_verilog <<EOT
+module opt_expr_add_signed_test(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o);
+    assign o = (i << 4) + j;
+endmodule
+EOT
+
+hierarchy -auto-top
+proc
+design -save gold
+
+opt_expr -fine
+wreduce
+
+select -assert-count 1 t:$add r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+##########
+
 read_verilog <<EOT
 module opt_expr_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o);
     assign o = j - (i << 4);
@@ -49,6 +74,31 @@ sat -verify -prove-asserts -show-ports miter
 
 ##########
 
+read_verilog <<EOT
+module opt_expr_sub_signed_test1(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o);
+    assign o = j - (i << 4);
+endmodule
+EOT
+
+hierarchy -auto-top
+proc
+design -save gold
+
+opt_expr -fine
+wreduce
+
+select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i
+
+design -stash gate
+
+design -import gold -as gold
+design -import gate -as gate
+
+miter -equiv -flatten -make_assert -make_outputs gold gate miter
+sat -verify -prove-asserts -show-ports miter
+
+##########
+
 read_verilog <<EOT
 module opt_expr_sub_test2(input [3:0] i, input [7:0] j, output [8:0] o);
     assign o = (i << 4) - j;

From 100c377451f18503fd85112d62d11ebdb6ac9d5a Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Wed, 7 Aug 2019 01:12:14 +0200
Subject: [PATCH 50/53] Redesign of cell cost API

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 kernel/cost.h         | 158 ++++++++++++++++++++++--------------------
 passes/techmap/abc.cc |  42 ++++++-----
 2 files changed, 102 insertions(+), 98 deletions(-)

diff --git a/kernel/cost.h b/kernel/cost.h
index e8e077ff5..7ff11eba2 100644
--- a/kernel/cost.h
+++ b/kernel/cost.h
@@ -24,86 +24,92 @@
 
 YOSYS_NAMESPACE_BEGIN
 
-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, bool cmos_cost = false)
+struct CellCosts
 {
-	static dict<RTLIL::IdString, int> gate_cost = {
-		{ "$_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 },
-		{ "$_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);
-
-	if (parameters.empty() && design && design->module(type))
-	{
-		RTLIL::Module *mod = design->module(type);
-
-		if (mod->attributes.count("\\cost"))
-			return mod->attributes.at("\\cost").as_int();
-
-		dict<RTLIL::IdString, int> local_mod_cost_cache;
-		if (mod_cost_cache == nullptr)
-			mod_cost_cache = &local_mod_cost_cache;
-
-		if (mod_cost_cache->count(mod->name))
-			return mod_cost_cache->at(mod->name);
-
-		int module_cost = 1;
-		for (auto c : mod->cells())
-			module_cost += get_cell_cost(c, mod_cost_cache);
-
-		(*mod_cost_cache)[mod->name] = module_cost;
-		return module_cost;
+	static const dict<RTLIL::IdString, int>& default_gate_cost() {
+		static const dict<RTLIL::IdString, int> db = {
+			{ "$_BUF_",    1 },
+			{ "$_NOT_",    2 },
+			{ "$_AND_",    4 },
+			{ "$_NAND_",   4 },
+			{ "$_OR_",     4 },
+			{ "$_NOR_",    4 },
+			{ "$_ANDNOT_", 4 },
+			{ "$_ORNOT_",  4 },
+			{ "$_XOR_",    6 },
+			{ "$_XNOR_",   6 },
+			{ "$_AOI3_",   6 },
+			{ "$_OAI3_",   6 },
+			{ "$_AOI4_",   8 },
+			{ "$_OAI4_",   8 },
+			{ "$_MUX_",    4 },
+			{ "$_NMUX_",   4 }
+		};
+		return db;
 	}
 
-	log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters));
-	return 1;
-}
+	static const dict<RTLIL::IdString, int>& cmos_gate_cost() {
+		static const dict<RTLIL::IdString, int> db = {
+			{ "$_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 }
+		};
+		return db;
+	}
 
-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, cmos_cost);
-}
+	dict<RTLIL::IdString, int> mod_cost_cache;
+	const dict<RTLIL::IdString, int> *gate_cost = nullptr;
+	Design *design = nullptr;
+
+	int get(RTLIL::IdString type) const
+	{
+		if (gate_cost && gate_cost->count(type))
+			return gate_cost->at(type);
+
+		log_warning("Can't determine cost of %s cell.\n", log_id(type));
+		return 1;
+	}
+
+	int get(RTLIL::Cell *cell)
+	{
+		if (gate_cost && gate_cost->count(cell->type))
+			return gate_cost->at(cell->type);
+
+		if (design && design->module(cell->type) && cell->parameters.empty())
+		{
+			RTLIL::Module *mod = design->module(cell->type);
+
+			if (mod->attributes.count("\\cost"))
+				return mod->attributes.at("\\cost").as_int();
+
+			if (mod_cost_cache.count(mod->name))
+				return mod_cost_cache.at(mod->name);
+
+			int module_cost = 1;
+			for (auto c : mod->cells())
+				module_cost += get(c);
+
+			mod_cost_cache[mod->name] = module_cost;
+			return module_cost;
+		}
+
+		log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters));
+		return 1;
+	}
+};
 
 YOSYS_NAMESPACE_END
 
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 41a05c619..c0cfe2f36 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -931,9 +931,7 @@ 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);
-		};
+		auto &cell_cost = cmos_cost ? CellCosts::cmos_gate_cost() : CellCosts::default_gate_cost();
 
 		buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str());
 		f = fopen(buffer.c_str(), "wt");
@@ -941,42 +939,42 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 			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", cell_cost("$_BUF_"));
-		fprintf(f, "GATE NOT    %d Y=!A;                 PIN * INV     1 999 1 0 1 0\n", cell_cost("$_NOT_"));
+		fprintf(f, "GATE BUF    %d Y=A;                  PIN * NONINV  1 999 1 0 1 0\n", cell_cost.at("$_BUF_"));
+		fprintf(f, "GATE NOT    %d Y=!A;                 PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_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", cell_cost("$_AND_"));
+			fprintf(f, "GATE AND    %d Y=A*B;                PIN * NONINV  1 999 1 0 1 0\n", cell_cost.at("$_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", cell_cost("$_NAND_"));
+			fprintf(f, "GATE NAND   %d Y=!(A*B);             PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_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", cell_cost("$_OR_"));
+			fprintf(f, "GATE OR     %d Y=A+B;                PIN * NONINV  1 999 1 0 1 0\n", cell_cost.at("$_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", cell_cost("$_NOR_"));
+			fprintf(f, "GATE NOR    %d Y=!(A+B);             PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_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", cell_cost("$_XOR_"));
+			fprintf(f, "GATE XOR    %d Y=(A*!B)+(!A*B);      PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_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", cell_cost("$_XNOR_"));
+			fprintf(f, "GATE XNOR   %d Y=(A*B)+(!A*!B);      PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_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", cell_cost("$_ANDNOT_"));
+			fprintf(f, "GATE ANDNOT %d Y=A*!B;               PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_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", cell_cost("$_ORNOT_"));
+			fprintf(f, "GATE ORNOT  %d Y=A+!B;               PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_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", cell_cost("$_AOI3_"));
+			fprintf(f, "GATE AOI3   %d Y=!((A*B)+C);         PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_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", cell_cost("$_OAI3_"));
+			fprintf(f, "GATE OAI3   %d Y=!((A+B)*C);         PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_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", cell_cost("$_AOI4_"));
+			fprintf(f, "GATE AOI4   %d Y=!((A*B)+(C*D));     PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_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", cell_cost("$_OAI4_"));
+			fprintf(f, "GATE OAI4   %d Y=!((A+B)*(C+D));     PIN * INV     1 999 1 0 1 0\n", cell_cost.at("$_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", 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.at("$_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_"));
+			fprintf(f, "GATE NMUX   %d Y=!((A*B)+(S*B)+(!S*A)); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at("$_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*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.at("$_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*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.at("$_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*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.at("$_MUX_"));
 		fclose(f);
 
 		if (!lut_costs.empty()) {

From 338f6765ebeb6bd07197dbef8e22fa077bf2d043 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Wed, 7 Aug 2019 10:25:51 +0200
Subject: [PATCH 51/53] Tweak default gate costs, cleanup "stat -tech cmos"

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 kernel/cost.h       |  8 ++++----
 passes/cmds/stat.cc | 22 ++++++----------------
 2 files changed, 10 insertions(+), 20 deletions(-)

diff --git a/kernel/cost.h b/kernel/cost.h
index 7ff11eba2..10fa50fb3 100644
--- a/kernel/cost.h
+++ b/kernel/cost.h
@@ -36,12 +36,12 @@ struct CellCosts
 			{ "$_NOR_",    4 },
 			{ "$_ANDNOT_", 4 },
 			{ "$_ORNOT_",  4 },
-			{ "$_XOR_",    6 },
-			{ "$_XNOR_",   6 },
+			{ "$_XOR_",    5 },
+			{ "$_XNOR_",   5 },
 			{ "$_AOI3_",   6 },
 			{ "$_OAI3_",   6 },
-			{ "$_AOI4_",   8 },
-			{ "$_OAI4_",   8 },
+			{ "$_AOI4_",   7 },
+			{ "$_OAI4_",   7 },
 			{ "$_MUX_",    4 },
 			{ "$_NMUX_",   4 }
 		};
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 89920ed55..c8e4f3981 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -17,11 +17,10 @@
  *
  */
 
-#include "kernel/register.h"
+#include "kernel/yosys.h"
 #include "kernel/celltypes.h"
 #include "passes/techmap/libparse.h"
-
-#include "kernel/log.h"
+#include "kernel/cost.h"
 
 USING_YOSYS_NAMESPACE
 PRIVATE_NAMESPACE_BEGIN
@@ -228,25 +227,16 @@ struct statdata_t
 		{
 			int tran_cnt = 0;
 			bool tran_cnt_exact = true;
+			auto &gate_costs = CellCosts::cmos_gate_cost();
 
 			for (auto it : num_cells_by_type) {
 				auto ctype = it.first;
 				auto cnum = it.second;
 
-				if (ctype == "$_NOT_")
-					tran_cnt += 2*cnum;
-				else if (ctype.in("$_NAND_", "$_NOR_"))
-					tran_cnt += 4*cnum;
-				else if (ctype.in("$_AOI3_", "$_OAI3_"))
-					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;
+				if (gate_costs.count(ctype))
+					tran_cnt += cnum * gate_costs.at(ctype);
 				else if (ctype.in("$_DFF_P_", "$_DFF_N_"))
-					tran_cnt += 16*cnum;
+					tran_cnt += cnum * 16;
 				else
 					tran_cnt_exact = false;
 			}

From 607c7fa7e15f2d64685d2aab2c9c9f860037da17 Mon Sep 17 00:00:00 2001
From: David Shah <dave@ds0.me>
Date: Wed, 7 Aug 2019 10:56:32 +0100
Subject: [PATCH 52/53] Update CHANGELOG

Signed-off-by: David Shah <dave@ds0.me>
---
 CHANGELOG | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/CHANGELOG b/CHANGELOG
index 661581433..638c36121 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -17,6 +17,8 @@ Yosys 0.9 .. Yosys 0.9-dev
     - Added automatic gzip decompression for frontends
     - Added $_NMUX_ cell type
     - Added automatic gzip compression (based on filename extension) for backends
+    - Improve attribute and parameter encoding in JSON to avoid ambiguities between
+      bit vectors and strings containing [01xz]*
 
 Yosys 0.8 .. Yosys 0.8-dev
 --------------------------

From a36fd8582e52524a292702fa88b94ee40fc8acc4 Mon Sep 17 00:00:00 2001
From: David Shah <dave@ds0.me>
Date: Wed, 7 Aug 2019 14:19:31 +0100
Subject: [PATCH 53/53] ecp5: Make cells_sim.v consistent with nextpnr

Signed-off-by: David Shah <dave@ds0.me>
---
 techlibs/ecp5/cells_sim.v | 331 +++++++++++++++++++++++++++-----------
 1 file changed, 237 insertions(+), 94 deletions(-)

diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v
index ca88d0a5b..3d343b315 100644
--- a/techlibs/ecp5/cells_sim.v
+++ b/techlibs/ecp5/cells_sim.v
@@ -333,6 +333,31 @@ module TRELLIS_SLICE(
 	parameter [127:0] CCU2_INJECT1_0 = "NO";
 	parameter [127:0] CCU2_INJECT1_1 = "NO";
 	parameter WREMUX = "WRE";
+	parameter WCKMUX = "WCK";
+
+	parameter A0MUX = "A0";
+	parameter A1MUX = "A1";
+	parameter B0MUX = "B0";
+	parameter B1MUX = "B1";
+	parameter C0MUX = "C0";
+	parameter C1MUX = "C1";
+	parameter D0MUX = "D0";
+	parameter D1MUX = "D1";
+
+	wire A0m, B0m, C0m, D0m;
+	wire A1m, B1m, C1m, D1m;
+
+	generate
+		if (A0MUX == "1") assign A0m = 1'b1; else assign A0m = A0;
+		if (B0MUX == "1") assign B0m = 1'b1; else assign B0m = B0;
+		if (C0MUX == "1") assign C0m = 1'b1; else assign C0m = C0;
+		if (D0MUX == "1") assign D0m = 1'b1; else assign D0m = D0;
+		if (A1MUX == "1") assign A1m = 1'b1; else assign A1m = A1;
+		if (B1MUX == "1") assign B1m = 1'b1; else assign B1m = B1;
+		if (C1MUX == "1") assign C1m = 1'b1; else assign C1m = C1;
+		if (D1MUX == "1") assign D1m = 1'b1; else assign D1m = D1;
+
+	endgenerate
 
 	function [15:0] permute_initval;
 		input [15:0] initval;
@@ -350,13 +375,13 @@ module TRELLIS_SLICE(
 			LUT4 #(
 				.INIT(LUT0_INITVAL)
 			) lut4_0 (
-				.A(A0), .B(B0), .C(C0), .D(D0),
+				.A(A0m), .B(B0m), .C(C0m), .D(D0m),
 				.Z(F0)
 			);
 			LUT4 #(
 				.INIT(LUT1_INITVAL)
 			) lut4_1 (
-				.A(A1), .B(B1), .C(C1), .D(D1),
+				.A(A1m), .B(B1m), .C(C1m), .D(D1m),
 				.Z(F1)
 			);
 			// LUT expansion muxes
@@ -370,20 +395,20 @@ module TRELLIS_SLICE(
 				.INJECT1_1(CCU2_INJECT1_1)
 		  ) ccu2c_i (
 				.CIN(FCI),
-				.A0(A0), .B0(B0), .C0(C0), .D0(D0),
-				.A1(A1), .B1(B1), .C1(C1), .D1(D1),
+				.A0(A0m), .B0(B0m), .C0(C0m), .D0(D0m),
+				.A1(A1m), .B1(B1m), .C1(C1m), .D1(D1m),
 				.S0(F0), .S1(F1),
 				.COUT(FCO)
 			);
 		end else if (MODE == "RAMW") begin
-			assign WDO0 = C1;
-			assign WDO1 = A1;
-			assign WDO2 = D1;
-			assign WDO3 = B1;
-			assign WADO0 = D0;
-			assign WADO1 = B0;
-			assign WADO2 = C0;
-			assign WADO3 = A0;
+			assign WDO0 = C1m;
+			assign WDO1 = A1m;
+			assign WDO2 = D1m;
+			assign WDO3 = B1m;
+			assign WADO0 = D0m;
+			assign WADO1 = B0m;
+			assign WADO2 = C0m;
+			assign WADO3 = A0m;
 		end else if (MODE == "DPRAM") begin
 			TRELLIS_RAM16X2 #(
 				.INITVAL_0(permute_initval(LUT0_INITVAL)),
@@ -393,17 +418,19 @@ module TRELLIS_SLICE(
 				.DI0(WD0), .DI1(WD1),
 				.WAD0(WAD0), .WAD1(WAD1), .WAD2(WAD2), .WAD3(WAD3),
 				.WRE(WRE), .WCK(WCK),
-				.RAD0(D0), .RAD1(B0), .RAD2(C0), .RAD3(A0),
+				.RAD0(D0m), .RAD1(B0m), .RAD2(C0m), .RAD3(A0m),
 				.DO0(F0), .DO1(F1)
 			);
 			// TODO: confirm RAD and INITVAL ordering
 			// DPRAM mode contract?
+`ifdef FORMAL
 			always @(*) begin
-				assert(A0==A1);
-				assert(B0==B1);
-				assert(C0==C1);
-				assert(D0==D1);
+				assert(A0m==A1m);
+				assert(B0m==B1m);
+				assert(C0m==C1m);
+				assert(D0m==D1m);
 			end
+`endif
 		end else begin
 			ERROR_UNKNOWN_SLICE_MODE error();
 		end
@@ -455,90 +482,206 @@ module DP16KD(
   input CSB2, CSB1, CSB0,
   output DOB17, DOB16, DOB15, DOB14, DOB13, DOB12, DOB11, DOB10, DOB9, DOB8, DOB7, DOB6, DOB5, DOB4, DOB3, DOB2, DOB1, DOB0
 );
-  parameter DATA_WIDTH_A = 18;
-  parameter DATA_WIDTH_B = 18;
+	parameter DATA_WIDTH_A = 18;
+	parameter DATA_WIDTH_B = 18;
 
-  parameter REGMODE_A = "NOREG";
-  parameter REGMODE_B = "NOREG";
+	parameter REGMODE_A = "NOREG";
+	parameter REGMODE_B = "NOREG";
 
-  parameter RESETMODE = "SYNC";
-  parameter ASYNC_RESET_RELEASE = "SYNC";
+	parameter RESETMODE = "SYNC";
+	parameter ASYNC_RESET_RELEASE = "SYNC";
 
-  parameter CSDECODE_A = "0b000";
-  parameter CSDECODE_B = "0b000";
+	parameter CSDECODE_A = "0b000";
+	parameter CSDECODE_B = "0b000";
 
-  parameter WRITEMODE_A = "NORMAL";
-  parameter WRITEMODE_B = "NORMAL";
+	parameter WRITEMODE_A = "NORMAL";
+	parameter WRITEMODE_B = "NORMAL";
 
-  parameter CLKAMUX = "CLKA";
-  parameter CLKBMUX = "CLKB";
+	parameter DIA17MUX = "DIA17";
+	parameter DIA16MUX = "DIA16";
+	parameter DIA15MUX = "DIA15";
+	parameter DIA14MUX = "DIA14";
+	parameter DIA13MUX = "DIA13";
+	parameter DIA12MUX = "DIA12";
+	parameter DIA11MUX = "DIA11";
+	parameter DIA10MUX = "DIA10";
+	parameter DIA9MUX = "DIA9";
+	parameter DIA8MUX = "DIA8";
+	parameter DIA7MUX = "DIA7";
+	parameter DIA6MUX = "DIA6";
+	parameter DIA5MUX = "DIA5";
+	parameter DIA4MUX = "DIA4";
+	parameter DIA3MUX = "DIA3";
+	parameter DIA2MUX = "DIA2";
+	parameter DIA1MUX = "DIA1";
+	parameter DIA0MUX = "DIA0";
+	parameter ADA13MUX = "ADA13";
+	parameter ADA12MUX = "ADA12";
+	parameter ADA11MUX = "ADA11";
+	parameter ADA10MUX = "ADA10";
+	parameter ADA9MUX = "ADA9";
+	parameter ADA8MUX = "ADA8";
+	parameter ADA7MUX = "ADA7";
+	parameter ADA6MUX = "ADA6";
+	parameter ADA5MUX = "ADA5";
+	parameter ADA4MUX = "ADA4";
+	parameter ADA3MUX = "ADA3";
+	parameter ADA2MUX = "ADA2";
+	parameter ADA1MUX = "ADA1";
+	parameter ADA0MUX = "ADA0";
+	parameter CEAMUX = "CEA";
+	parameter OCEAMUX = "OCEA";
+	parameter CLKAMUX = "CLKA";
+	parameter WEAMUX = "WEA";
+	parameter RSTAMUX = "RSTA";
+	parameter CSA2MUX = "CSA2";
+	parameter CSA1MUX = "CSA1";
+	parameter CSA0MUX = "CSA0";
+	parameter DOA17MUX = "DOA17";
+	parameter DOA16MUX = "DOA16";
+	parameter DOA15MUX = "DOA15";
+	parameter DOA14MUX = "DOA14";
+	parameter DOA13MUX = "DOA13";
+	parameter DOA12MUX = "DOA12";
+	parameter DOA11MUX = "DOA11";
+	parameter DOA10MUX = "DOA10";
+	parameter DOA9MUX = "DOA9";
+	parameter DOA8MUX = "DOA8";
+	parameter DOA7MUX = "DOA7";
+	parameter DOA6MUX = "DOA6";
+	parameter DOA5MUX = "DOA5";
+	parameter DOA4MUX = "DOA4";
+	parameter DOA3MUX = "DOA3";
+	parameter DOA2MUX = "DOA2";
+	parameter DOA1MUX = "DOA1";
+	parameter DOA0MUX = "DOA0";
+	parameter DIB17MUX = "DIB17";
+	parameter DIB16MUX = "DIB16";
+	parameter DIB15MUX = "DIB15";
+	parameter DIB14MUX = "DIB14";
+	parameter DIB13MUX = "DIB13";
+	parameter DIB12MUX = "DIB12";
+	parameter DIB11MUX = "DIB11";
+	parameter DIB10MUX = "DIB10";
+	parameter DIB9MUX = "DIB9";
+	parameter DIB8MUX = "DIB8";
+	parameter DIB7MUX = "DIB7";
+	parameter DIB6MUX = "DIB6";
+	parameter DIB5MUX = "DIB5";
+	parameter DIB4MUX = "DIB4";
+	parameter DIB3MUX = "DIB3";
+	parameter DIB2MUX = "DIB2";
+	parameter DIB1MUX = "DIB1";
+	parameter DIB0MUX = "DIB0";
+	parameter ADB13MUX = "ADB13";
+	parameter ADB12MUX = "ADB12";
+	parameter ADB11MUX = "ADB11";
+	parameter ADB10MUX = "ADB10";
+	parameter ADB9MUX = "ADB9";
+	parameter ADB8MUX = "ADB8";
+	parameter ADB7MUX = "ADB7";
+	parameter ADB6MUX = "ADB6";
+	parameter ADB5MUX = "ADB5";
+	parameter ADB4MUX = "ADB4";
+	parameter ADB3MUX = "ADB3";
+	parameter ADB2MUX = "ADB2";
+	parameter ADB1MUX = "ADB1";
+	parameter ADB0MUX = "ADB0";
+	parameter CEBMUX = "CEB";
+	parameter OCEBMUX = "OCEB";
+	parameter CLKBMUX = "CLKB";
+	parameter WEBMUX = "WEB";
+	parameter RSTBMUX = "RSTB";
+	parameter CSB2MUX = "CSB2";
+	parameter CSB1MUX = "CSB1";
+	parameter CSB0MUX = "CSB0";
+	parameter DOB17MUX = "DOB17";
+	parameter DOB16MUX = "DOB16";
+	parameter DOB15MUX = "DOB15";
+	parameter DOB14MUX = "DOB14";
+	parameter DOB13MUX = "DOB13";
+	parameter DOB12MUX = "DOB12";
+	parameter DOB11MUX = "DOB11";
+	parameter DOB10MUX = "DOB10";
+	parameter DOB9MUX = "DOB9";
+	parameter DOB8MUX = "DOB8";
+	parameter DOB7MUX = "DOB7";
+	parameter DOB6MUX = "DOB6";
+	parameter DOB5MUX = "DOB5";
+	parameter DOB4MUX = "DOB4";
+	parameter DOB3MUX = "DOB3";
+	parameter DOB2MUX = "DOB2";
+	parameter DOB1MUX = "DOB1";
+	parameter DOB0MUX = "DOB0";
 
-  parameter GSR = "ENABLED";
+	parameter WID = 0;
 
-  parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
-  parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter GSR = "ENABLED";
+
+	parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
+	parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000;
 endmodule
 
 // TODO: Diamond flip-flops