From f7753720feaf466a089f4b96fca27ed4130b5be8 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 08:45:35 -0700
Subject: [PATCH 01/13] Don't copy ref if exists already

---
 techlibs/ice40/tests/test_dsp_model.sh | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/techlibs/ice40/tests/test_dsp_model.sh b/techlibs/ice40/tests/test_dsp_model.sh
index 1bc0cc688..2d42c23ad 100644
--- a/techlibs/ice40/tests/test_dsp_model.sh
+++ b/techlibs/ice40/tests/test_dsp_model.sh
@@ -1,7 +1,9 @@
 #!/bin/bash
 set -ex
 sed 's/SB_MAC16/SB_MAC16_UUT/; /SB_MAC16_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp_model_uut.v
-cat /opt/lscc/iCEcube2.2017.01/verilog/sb_ice_syn.v > test_dsp_model_ref.v
+if [ ! -f "test_dsp_model_ref.v" ]; then
+	cat /opt/lscc/iCEcube2.2017.01/verilog/sb_ice_syn.v > test_dsp_model_ref.v
+fi
 for tb in testbench \
 		testbench_comb_8x8_A testbench_comb_8x8_B testbench_comb_16x16 \
 		testbench_seq_16x16_A testbench_seq_16x16_B

From 171cd2ff738cdb8027b9b6efb988bab8744264a9 Mon Sep 17 00:00:00 2001
From: Eddie Hung <eddie@fpgeh.com>
Date: Fri, 19 Jul 2019 08:52:49 -0700
Subject: [PATCH 02/13] Add tests for all combinations of A and B signedness
 for comb mul

---
 techlibs/ice40/tests/test_dsp_model.sh |   5 +-
 techlibs/ice40/tests/test_dsp_model.v  | 225 +++++++++++++++++++++++++
 2 files changed, 229 insertions(+), 1 deletion(-)

diff --git a/techlibs/ice40/tests/test_dsp_model.sh b/techlibs/ice40/tests/test_dsp_model.sh
index 2d42c23ad..75f95ab29 100644
--- a/techlibs/ice40/tests/test_dsp_model.sh
+++ b/techlibs/ice40/tests/test_dsp_model.sh
@@ -6,7 +6,10 @@ if [ ! -f "test_dsp_model_ref.v" ]; then
 fi
 for tb in testbench \
 		testbench_comb_8x8_A testbench_comb_8x8_B testbench_comb_16x16 \
-		testbench_seq_16x16_A testbench_seq_16x16_B
+		testbench_seq_16x16_A testbench_seq_16x16_B \
+		testbench_comb_8x8_A_signedA testbench_comb_8x8_A_signedB testbench_comb_8x8_A_signedAB \
+		testbench_comb_8x8_B_signedA testbench_comb_8x8_B_signedB testbench_comb_8x8_B_signedAB \
+		testbench_comb_16x16_B_signedA testbench_comb_16x16_B_signedB testbench_comb_16x16_B_signedAB
 do
 	iverilog -s $tb -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v
 	vvp -N ./test_dsp_model
diff --git a/techlibs/ice40/tests/test_dsp_model.v b/techlibs/ice40/tests/test_dsp_model.v
index 594bd4ad3..f4f6858f0 100644
--- a/techlibs/ice40/tests/test_dsp_model.v
+++ b/techlibs/ice40/tests/test_dsp_model.v
@@ -241,6 +241,81 @@ module testbench_comb_8x8_A;
 	) testbench ();
 endmodule
 
+module testbench_comb_8x8_A_signedA;
+	testbench #(
+		.NEG_TRIGGER               (0),
+		.C_REG                     (0),
+		.A_REG                     (0),
+		.B_REG                     (0),
+		.D_REG                     (0),
+		.TOP_8x8_MULT_REG          (0),
+		.BOT_8x8_MULT_REG          (0),
+		.PIPELINE_16x16_MULT_REG1  (0),
+		.PIPELINE_16x16_MULT_REG2  (0),
+		.TOPOUTPUT_SELECT          (2),   // 0=P, 1=Q, 2=8x8, 3=16x16
+		.TOPADDSUB_LOWERINPUT      (0),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+		.TOPADDSUB_UPPERINPUT      (0),   // 0=Q, 1=C
+		.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
+		.BOTOUTPUT_SELECT          (2),   // 0=R, 1=S, 2=8x8, 3=16x16
+		.BOTADDSUB_LOWERINPUT      (0),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+		.BOTADDSUB_UPPERINPUT      (0),   // 0=S, 1=D
+		.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
+		.MODE_8x8                  (0),
+		.A_SIGNED                  (1),
+		.B_SIGNED                  (0)
+	) testbench ();
+endmodule
+
+module testbench_comb_8x8_A_signedB;
+	testbench #(
+		.NEG_TRIGGER               (0),
+		.C_REG                     (0),
+		.A_REG                     (0),
+		.B_REG                     (0),
+		.D_REG                     (0),
+		.TOP_8x8_MULT_REG          (0),
+		.BOT_8x8_MULT_REG          (0),
+		.PIPELINE_16x16_MULT_REG1  (0),
+		.PIPELINE_16x16_MULT_REG2  (0),
+		.TOPOUTPUT_SELECT          (2),   // 0=P, 1=Q, 2=8x8, 3=16x16
+		.TOPADDSUB_LOWERINPUT      (0),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+		.TOPADDSUB_UPPERINPUT      (0),   // 0=Q, 1=C
+		.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
+		.BOTOUTPUT_SELECT          (2),   // 0=R, 1=S, 2=8x8, 3=16x16
+		.BOTADDSUB_LOWERINPUT      (0),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+		.BOTADDSUB_UPPERINPUT      (0),   // 0=S, 1=D
+		.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
+		.MODE_8x8                  (0),
+		.A_SIGNED                  (0),
+		.B_SIGNED                  (1)
+	) testbench ();
+endmodule
+
+module testbench_comb_8x8_A_signedAB;
+	testbench #(
+		.NEG_TRIGGER               (0),
+		.C_REG                     (0),
+		.A_REG                     (0),
+		.B_REG                     (0),
+		.D_REG                     (0),
+		.TOP_8x8_MULT_REG          (0),
+		.BOT_8x8_MULT_REG          (0),
+		.PIPELINE_16x16_MULT_REG1  (0),
+		.PIPELINE_16x16_MULT_REG2  (0),
+		.TOPOUTPUT_SELECT          (2),   // 0=P, 1=Q, 2=8x8, 3=16x16
+		.TOPADDSUB_LOWERINPUT      (0),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+		.TOPADDSUB_UPPERINPUT      (0),   // 0=Q, 1=C
+		.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
+		.BOTOUTPUT_SELECT          (2),   // 0=R, 1=S, 2=8x8, 3=16x16
+		.BOTADDSUB_LOWERINPUT      (0),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+		.BOTADDSUB_UPPERINPUT      (0),   // 0=S, 1=D
+		.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
+		.MODE_8x8                  (0),
+		.A_SIGNED                  (1),
+		.B_SIGNED                  (1)
+	) testbench ();
+endmodule
+
 module testbench_comb_8x8_B;
 	testbench #(
 		.NEG_TRIGGER               (0),
@@ -266,6 +341,81 @@ module testbench_comb_8x8_B;
 	) testbench ();
 endmodule
 
+module testbench_comb_8x8_B_signedA;
+	testbench #(
+		.NEG_TRIGGER               (0),
+		.C_REG                     (0),
+		.A_REG                     (0),
+		.B_REG                     (0),
+		.D_REG                     (0),
+		.TOP_8x8_MULT_REG          (0),
+		.BOT_8x8_MULT_REG          (0),
+		.PIPELINE_16x16_MULT_REG1  (0),
+		.PIPELINE_16x16_MULT_REG2  (0),
+		.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16
+		.TOPADDSUB_LOWERINPUT      (1),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+		.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C
+		.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
+		.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16
+		.BOTADDSUB_LOWERINPUT      (1),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+		.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D
+		.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
+		.MODE_8x8                  (0),
+		.A_SIGNED                  (1),
+		.B_SIGNED                  (0)
+	) testbench ();
+endmodule
+
+module testbench_comb_8x8_B_signedB;
+	testbench #(
+		.NEG_TRIGGER               (0),
+		.C_REG                     (0),
+		.A_REG                     (0),
+		.B_REG                     (0),
+		.D_REG                     (0),
+		.TOP_8x8_MULT_REG          (0),
+		.BOT_8x8_MULT_REG          (0),
+		.PIPELINE_16x16_MULT_REG1  (0),
+		.PIPELINE_16x16_MULT_REG2  (0),
+		.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16
+		.TOPADDSUB_LOWERINPUT      (1),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+		.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C
+		.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
+		.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16
+		.BOTADDSUB_LOWERINPUT      (1),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+		.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D
+		.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
+		.MODE_8x8                  (0),
+		.A_SIGNED                  (0),
+		.B_SIGNED                  (1)
+	) testbench ();
+endmodule
+
+module testbench_comb_8x8_B_signedAB;
+	testbench #(
+		.NEG_TRIGGER               (0),
+		.C_REG                     (0),
+		.A_REG                     (0),
+		.B_REG                     (0),
+		.D_REG                     (0),
+		.TOP_8x8_MULT_REG          (0),
+		.BOT_8x8_MULT_REG          (0),
+		.PIPELINE_16x16_MULT_REG1  (0),
+		.PIPELINE_16x16_MULT_REG2  (0),
+		.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16
+		.TOPADDSUB_LOWERINPUT      (1),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+		.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C
+		.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
+		.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16
+		.BOTADDSUB_LOWERINPUT      (1),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+		.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D
+		.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI
+		.MODE_8x8                  (0),
+		.A_SIGNED                  (1),
+		.B_SIGNED                  (1)
+	) testbench ();
+endmodule
+
 module testbench_comb_16x16;
 	testbench #(
 		.NEG_TRIGGER               (0),
@@ -291,6 +441,81 @@ module testbench_comb_16x16;
 	) testbench ();
 endmodule
 
+module testbench_comb_16x16_signedA;
+	testbench #(
+		.NEG_TRIGGER               (0),
+		.C_REG                     (0),
+		.A_REG                     (0),
+		.B_REG                     (0),
+		.D_REG                     (0),
+		.TOP_8x8_MULT_REG          (0),
+		.BOT_8x8_MULT_REG          (0),
+		.PIPELINE_16x16_MULT_REG1  (0),
+		.PIPELINE_16x16_MULT_REG2  (0),
+		.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16
+		.TOPADDSUB_LOWERINPUT      (2),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+		.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C
+		.TOPADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI
+		.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16
+		.BOTADDSUB_LOWERINPUT      (2),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+		.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D
+		.BOTADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI
+		.MODE_8x8                  (0),
+		.A_SIGNED                  (1),
+		.B_SIGNED                  (0)
+	) testbench ();
+endmodule
+
+module testbench_comb_16x16_signedB;
+	testbench #(
+		.NEG_TRIGGER               (0),
+		.C_REG                     (0),
+		.A_REG                     (0),
+		.B_REG                     (0),
+		.D_REG                     (0),
+		.TOP_8x8_MULT_REG          (0),
+		.BOT_8x8_MULT_REG          (0),
+		.PIPELINE_16x16_MULT_REG1  (0),
+		.PIPELINE_16x16_MULT_REG2  (0),
+		.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16
+		.TOPADDSUB_LOWERINPUT      (2),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+		.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C
+		.TOPADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI
+		.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16
+		.BOTADDSUB_LOWERINPUT      (2),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+		.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D
+		.BOTADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI
+		.MODE_8x8                  (0),
+		.A_SIGNED                  (0),
+		.B_SIGNED                  (1)
+	) testbench ();
+endmodule
+
+module testbench_comb_16x16_signedAB;
+	testbench #(
+		.NEG_TRIGGER               (0),
+		.C_REG                     (0),
+		.A_REG                     (0),
+		.B_REG                     (0),
+		.D_REG                     (0),
+		.TOP_8x8_MULT_REG          (0),
+		.BOT_8x8_MULT_REG          (0),
+		.PIPELINE_16x16_MULT_REG1  (0),
+		.PIPELINE_16x16_MULT_REG2  (0),
+		.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16
+		.TOPADDSUB_LOWERINPUT      (2),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT
+		.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C
+		.TOPADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI
+		.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16
+		.BOTADDSUB_LOWERINPUT      (2),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT
+		.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D
+		.BOTADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI
+		.MODE_8x8                  (0),
+		.A_SIGNED                  (1),
+		.B_SIGNED                  (1)
+	) testbench ();
+endmodule
+
 module testbench_seq_16x16_A;
 	testbench #(
 		.NEG_TRIGGER               (0),

From 3c84271543379a5a3845d5dcdb49a5e6fbafbc66 Mon Sep 17 00:00:00 2001
From: David Shah <dave@ds0.me>
Date: Fri, 19 Jul 2019 17:13:34 +0100
Subject: [PATCH 03/13] ice40/cells_sim.v: LSB of A/B only signed in 8x8 mode

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

diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index 609facc93..4402f8d36 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -1363,9 +1363,9 @@ module SB_MAC16 (
 	wire [15:0] p_Ah_Bh, p_Al_Bh, p_Ah_Bl, p_Al_Bl;
 	wire [15:0] Ah, Al, Bh, Bl;
 	assign Ah = {A_SIGNED ? {8{iA[15]}} : 8'b0, iA[15: 8]};
-	assign Al = {A_SIGNED ? {8{iA[ 7]}} : 8'b0, iA[ 7: 0]};
+	assign Al = {A_SIGNED && MODE_8x8 ? {8{iA[ 7]}} : 8'b0, iA[ 7: 0]};
 	assign Bh = {B_SIGNED ? {8{iB[15]}} : 8'b0, iB[15: 8]};
-	assign Bl = {B_SIGNED ? {8{iB[ 7]}} : 8'b0, iB[ 7: 0]};
+	assign Bl = {B_SIGNED && MODE_8x8 ? {8{iB[ 7]}} : 8'b0, iB[ 7: 0]};
 	assign p_Ah_Bh = Ah * Bh;
 	assign p_Al_Bh = Al * Bh;
 	assign p_Ah_Bl = Ah * Bl;

From 79f14c751417685e7405855a96fc7a37f5bc7fbf Mon Sep 17 00:00:00 2001
From: David Shah <dave@ds0.me>
Date: Fri, 19 Jul 2019 17:33:41 +0100
Subject: [PATCH 04/13] ice40/cells_sim.v: Fix sign of J and K partial products

Signed-off-by: David Shah <dave@ds0.me>
---
 techlibs/ice40/cells_sim.v | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index 4402f8d36..2205be27d 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -1366,10 +1366,10 @@ module SB_MAC16 (
 	assign Al = {A_SIGNED && MODE_8x8 ? {8{iA[ 7]}} : 8'b0, iA[ 7: 0]};
 	assign Bh = {B_SIGNED ? {8{iB[15]}} : 8'b0, iB[15: 8]};
 	assign Bl = {B_SIGNED && MODE_8x8 ? {8{iB[ 7]}} : 8'b0, iB[ 7: 0]};
-	assign p_Ah_Bh = Ah * Bh;
-	assign p_Al_Bh = Al * Bh;
-	assign p_Ah_Bl = Ah * Bl;
-	assign p_Al_Bl = Al * Bl;
+	assign p_Ah_Bh = Ah * Bh; // F
+	assign p_Al_Bh = {8'b0, Al[7:0]} * Bh; // J
+	assign p_Ah_Bl = Ah * {8'b0, Bl[7:0]}; // K
+	assign p_Al_Bl = Al * Bl; // G
 
 	// Regs F and J
 	reg [15:0] rF, rJ;
@@ -1400,7 +1400,9 @@ module SB_MAC16 (
 	assign iG = BOT_8x8_MULT_REG ? rG : p_Al_Bl;
 
 	// Adder Stage
-	assign iL = iG + (iK << 8) + (iJ << 8) + (iF << 16);
+	wire [23:0] iK_e = {A_SIGNED ? {8{iK[15]}} : 8'b0, iK};
+	wire [23:0] iJ_e = {B_SIGNED ? {8{iJ[15]}} : 8'b0, iJ};
+	assign iL = iG + (iK_e << 8) + (iJ_e << 8) + (iF << 16);
 
 	// Reg H
 	reg [31:0] rH;

From 80884d6f7bd10d79e89ad3893ae557aa64af9742 Mon Sep 17 00:00:00 2001
From: David Shah <dave@ds0.me>
Date: Fri, 19 Jul 2019 17:33:57 +0100
Subject: [PATCH 05/13] ice40: Fix test_dsp_model.sh

Signed-off-by: David Shah <dave@ds0.me>
---
 techlibs/ice40/tests/test_dsp_model.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/techlibs/ice40/tests/test_dsp_model.sh b/techlibs/ice40/tests/test_dsp_model.sh
index 75f95ab29..1e564d1b2 100644
--- a/techlibs/ice40/tests/test_dsp_model.sh
+++ b/techlibs/ice40/tests/test_dsp_model.sh
@@ -9,7 +9,7 @@ for tb in testbench \
 		testbench_seq_16x16_A testbench_seq_16x16_B \
 		testbench_comb_8x8_A_signedA testbench_comb_8x8_A_signedB testbench_comb_8x8_A_signedAB \
 		testbench_comb_8x8_B_signedA testbench_comb_8x8_B_signedB testbench_comb_8x8_B_signedAB \
-		testbench_comb_16x16_B_signedA testbench_comb_16x16_B_signedB testbench_comb_16x16_B_signedAB
+		testbench_comb_16x16_signedA testbench_comb_16x16_signedB testbench_comb_16x16_signedAB
 do
 	iverilog -s $tb -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v
 	vvp -N ./test_dsp_model

From c6d8692c9711e4b65aa89ad60986c9df7e053fc7 Mon Sep 17 00:00:00 2001
From: Clifford Wolf <clifford@clifford.at>
Date: Sat, 20 Jul 2019 15:06:28 +0200
Subject: [PATCH 06/13] Add "stat -tech cmos"

Signed-off-by: Clifford Wolf <clifford@clifford.at>
---
 passes/cmds/stat.cc | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index 27c5fb60c..80b400e0c 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -223,6 +223,33 @@ struct statdata_t
 			log("\n");
 			log("   Estimated number of LCs: %10d\n", lc_cnt);
 		}
+
+		if (tech == "cmos")
+		{
+			int tran_cnt = 0;
+			bool tran_cnt_exact = true;
+
+			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("$_DFF_P_", "$_DFF_N_"))
+					tran_cnt += 16*cnum;
+				else
+					tran_cnt_exact = false;
+			}
+
+			log("\n");
+			log("   Estimated number of transistors: %10d%s\n", tran_cnt, tran_cnt_exact ? "" : "+");
+		}
 	}
 };
 
@@ -286,7 +313,7 @@ struct StatPass : public Pass {
 		log("\n");
 		log("    -tech <technology>\n");
 		log("        print area estemate for the specified technology. Currently supported\n");
-		log("        values for <technology>: xilinx\n");
+		log("        values for <technology>: xilinx, cmos\n");
 		log("\n");
 		log("    -width\n");
 		log("        annotate internal cell types with their word width.\n");
@@ -330,7 +357,7 @@ struct StatPass : public Pass {
 		}
 		extra_args(args, argidx, design);
 
-		if (techname != "" && techname != "xilinx")
+		if (techname != "" && techname != "xilinx" && techname != "cmos")
 			log_cmd_error("Unsupported technology: '%s'\n", techname.c_str());
 
 		for (auto mod : design->selected_modules())

From e2fe8e0a4fd3108de8b7db556be45efc8122173d Mon Sep 17 00:00:00 2001
From: Jakob Wenzel <wenzel@rs.tu-darmstadt.de>
Date: Mon, 22 Jul 2019 10:37:40 +0200
Subject: [PATCH 07/13] initialize noblackbox and nowb in AstModule::clone

---
 frontends/ast/ast.cc | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index 3d066af53..943466ee3 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -1551,7 +1551,9 @@ RTLIL::Module *AstModule::clone() const
 	new_mod->nomeminit = nomeminit;
 	new_mod->nomem2reg = nomem2reg;
 	new_mod->mem2reg = mem2reg;
+	new_mod->noblackbox = noblackbox;
 	new_mod->lib = lib;
+	new_mod->nowb = nowb;
 	new_mod->noopt = noopt;
 	new_mod->icells = icells;
 	new_mod->pwires = pwires;

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 08/13] 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 09/13] 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 10/13] 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 11/13] 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 12/13] 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 13/13] 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;