aboutsummaryrefslogtreecommitdiffstats
path: root/techlibs/ice40
diff options
context:
space:
mode:
Diffstat (limited to 'techlibs/ice40')
-rw-r--r--techlibs/ice40/.gitignore4
-rw-r--r--techlibs/ice40/Makefile.inc33
-rw-r--r--techlibs/ice40/arith_map.v70
-rw-r--r--techlibs/ice40/brams.txt40
-rw-r--r--techlibs/ice40/brams_init.py14
-rw-r--r--techlibs/ice40/brams_map.v311
-rw-r--r--techlibs/ice40/cells_map.v57
-rw-r--r--techlibs/ice40/cells_sim.v883
-rw-r--r--techlibs/ice40/ice40_ffinit.cc167
-rw-r--r--techlibs/ice40/ice40_ffssr.cc123
-rw-r--r--techlibs/ice40/ice40_opt.cc193
-rw-r--r--techlibs/ice40/latches_map.v11
-rw-r--r--techlibs/ice40/synth_ice40.cc250
-rw-r--r--techlibs/ice40/tests/.gitignore2
-rw-r--r--techlibs/ice40/tests/test_arith.v3
-rw-r--r--techlibs/ice40/tests/test_arith.ys10
-rw-r--r--techlibs/ice40/tests/test_bram.sh19
-rw-r--r--techlibs/ice40/tests/test_bram.v24
-rw-r--r--techlibs/ice40/tests/test_bram_tb.v110
-rw-r--r--techlibs/ice40/tests/test_ffs.sh20
-rw-r--r--techlibs/ice40/tests/test_ffs.v42
21 files changed, 2386 insertions, 0 deletions
diff --git a/techlibs/ice40/.gitignore b/techlibs/ice40/.gitignore
new file mode 100644
index 000000000..6bf3b6717
--- /dev/null
+++ b/techlibs/ice40/.gitignore
@@ -0,0 +1,4 @@
+brams_init.mk
+brams_init1.vh
+brams_init2.vh
+brams_init3.vh
diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc
new file mode 100644
index 000000000..14761c6c8
--- /dev/null
+++ b/techlibs/ice40/Makefile.inc
@@ -0,0 +1,33 @@
+
+OBJS += techlibs/ice40/synth_ice40.o
+OBJS += techlibs/ice40/ice40_ffssr.o
+OBJS += techlibs/ice40/ice40_ffinit.o
+OBJS += techlibs/ice40/ice40_opt.o
+
+GENFILES += techlibs/ice40/brams_init1.vh
+GENFILES += techlibs/ice40/brams_init2.vh
+GENFILES += techlibs/ice40/brams_init3.vh
+
+EXTRA_OBJS += techlibs/ice40/brams_init.mk
+.SECONDARY: techlibs/ice40/brams_init.mk
+
+techlibs/ice40/brams_init.mk: techlibs/ice40/brams_init.py
+ $(Q) mkdir -p techlibs/ice40
+ $(P) python3 $<
+ $(Q) touch techlibs/ice40/brams_init.mk
+
+techlibs/ice40/brams_init1.vh: techlibs/ice40/brams_init.mk
+techlibs/ice40/brams_init2.vh: techlibs/ice40/brams_init.mk
+techlibs/ice40/brams_init3.vh: techlibs/ice40/brams_init.mk
+
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/arith_map.v))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_map.v))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/brams_map.v))
+
+$(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init1.vh))
+$(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init2.vh))
+$(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init3.vh))
+
diff --git a/techlibs/ice40/arith_map.v b/techlibs/ice40/arith_map.v
new file mode 100644
index 000000000..4449fdc1b
--- /dev/null
+++ b/techlibs/ice40/arith_map.v
@@ -0,0 +1,70 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+(* techmap_celltype = "$alu" *)
+module _80_ice40_alu (A, B, CI, BI, X, Y, CO);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] X, Y;
+
+ input CI, BI;
+ output [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
+
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
+ wire [Y_WIDTH-1:0] C = {CO, CI};
+
+ genvar i;
+ generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
+ SB_CARRY carry (
+ .I0(AA[i]),
+ .I1(BB[i]),
+ .CI(C[i]),
+ .CO(CO[i])
+ );
+ SB_LUT4 #(
+ // I0: 1010 1010 1010 1010
+ // I1: 1100 1100 1100 1100
+ // I2: 1111 0000 1111 0000
+ // I3: 1111 1111 0000 0000
+ .LUT_INIT(16'b 0110_1001_1001_0110)
+ ) adder (
+ .I0(1'b0),
+ .I1(AA[i]),
+ .I2(BB[i]),
+ .I3(C[i]),
+ .O(Y[i])
+ );
+ end endgenerate
+
+ assign X = AA ^ BB;
+endmodule
+
diff --git a/techlibs/ice40/brams.txt b/techlibs/ice40/brams.txt
new file mode 100644
index 000000000..03d596111
--- /dev/null
+++ b/techlibs/ice40/brams.txt
@@ -0,0 +1,40 @@
+bram $__ICE40_RAM4K_M0
+ init 1
+ abits 8
+ dbits 16
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 1 16
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+bram $__ICE40_RAM4K_M123
+ init 1
+ abits 9 @M1
+ dbits 8 @M1
+ abits 10 @M2
+ dbits 4 @M2
+ abits 11 @M3
+ dbits 2 @M3
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 1 1
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+match $__ICE40_RAM4K_M0
+ min efficiency 2
+ make_transp
+ or_next_if_better
+endmatch
+
+match $__ICE40_RAM4K_M123
+ min efficiency 2
+ make_transp
+endmatch
diff --git a/techlibs/ice40/brams_init.py b/techlibs/ice40/brams_init.py
new file mode 100644
index 000000000..4a1485110
--- /dev/null
+++ b/techlibs/ice40/brams_init.py
@@ -0,0 +1,14 @@
+#!/usr/bin/env python3
+
+def write_init_vh(filename, initbits):
+ with open(filename, "w") as f:
+ for i in range(16):
+ print("localparam [255:0] INIT_%X = {" % i, file=f)
+ for k in range(32):
+ print(" %s%s" % (", ".join(["INIT[%4d]" % initbits[i*256 + 255 - k*8 - l] for l in range(8)]), "," if k != 31 else ""), file=f)
+ print("};", file=f);
+
+write_init_vh("techlibs/ice40/brams_init1.vh", [i//2 + 2048*(i%2) for i in range(4096)])
+write_init_vh("techlibs/ice40/brams_init2.vh", [i//4 + 1024*(i%4) for i in range(4096)])
+write_init_vh("techlibs/ice40/brams_init3.vh", [i//8 + 512*(i%8) for i in range(4096)])
+
diff --git a/techlibs/ice40/brams_map.v b/techlibs/ice40/brams_map.v
new file mode 100644
index 000000000..19a61d73b
--- /dev/null
+++ b/techlibs/ice40/brams_map.v
@@ -0,0 +1,311 @@
+
+module \$__ICE40_RAM4K (
+ output [15:0] RDATA,
+ input RCLK, RCLKE, RE,
+ input [10:0] RADDR,
+ input WCLK, WCLKE, WE,
+ input [10:0] WADDR,
+ input [15:0] MASK, WDATA
+);
+ parameter integer READ_MODE = 0;
+ parameter integer WRITE_MODE = 0;
+ parameter [0:0] NEGCLK_R = 0;
+ parameter [0:0] NEGCLK_W = 0;
+
+ parameter [255:0] INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter [255:0] INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+
+ generate
+ case ({NEGCLK_R, NEGCLK_W})
+ 2'b00:
+ SB_RAM40_4K #(
+ .READ_MODE(READ_MODE),
+ .WRITE_MODE(WRITE_MODE),
+ .INIT_0(INIT_0),
+ .INIT_1(INIT_1),
+ .INIT_2(INIT_2),
+ .INIT_3(INIT_3),
+ .INIT_4(INIT_4),
+ .INIT_5(INIT_5),
+ .INIT_6(INIT_6),
+ .INIT_7(INIT_7),
+ .INIT_8(INIT_8),
+ .INIT_9(INIT_9),
+ .INIT_A(INIT_A),
+ .INIT_B(INIT_B),
+ .INIT_C(INIT_C),
+ .INIT_D(INIT_D),
+ .INIT_E(INIT_E),
+ .INIT_F(INIT_F)
+ ) _TECHMAP_REPLACE_ (
+ .RDATA(RDATA),
+ .RCLK (RCLK ),
+ .RCLKE(RCLKE),
+ .RE (RE ),
+ .RADDR(RADDR),
+ .WCLK (WCLK ),
+ .WCLKE(WCLKE),
+ .WE (WE ),
+ .WADDR(WADDR),
+ .MASK (MASK ),
+ .WDATA(WDATA)
+ );
+ 2'b01:
+ SB_RAM40_4KNW #(
+ .READ_MODE(READ_MODE),
+ .WRITE_MODE(WRITE_MODE),
+ .INIT_0(INIT_0),
+ .INIT_1(INIT_1),
+ .INIT_2(INIT_2),
+ .INIT_3(INIT_3),
+ .INIT_4(INIT_4),
+ .INIT_5(INIT_5),
+ .INIT_6(INIT_6),
+ .INIT_7(INIT_7),
+ .INIT_8(INIT_8),
+ .INIT_9(INIT_9),
+ .INIT_A(INIT_A),
+ .INIT_B(INIT_B),
+ .INIT_C(INIT_C),
+ .INIT_D(INIT_D),
+ .INIT_E(INIT_E),
+ .INIT_F(INIT_F)
+ ) _TECHMAP_REPLACE_ (
+ .RDATA(RDATA),
+ .RCLK (RCLK ),
+ .RCLKE(RCLKE),
+ .RE (RE ),
+ .RADDR(RADDR),
+ .WCLKN(WCLK ),
+ .WCLKE(WCLKE),
+ .WE (WE ),
+ .WADDR(WADDR),
+ .MASK (MASK ),
+ .WDATA(WDATA)
+ );
+ 2'b10:
+ SB_RAM40_4KNR #(
+ .READ_MODE(READ_MODE),
+ .WRITE_MODE(WRITE_MODE),
+ .INIT_0(INIT_0),
+ .INIT_1(INIT_1),
+ .INIT_2(INIT_2),
+ .INIT_3(INIT_3),
+ .INIT_4(INIT_4),
+ .INIT_5(INIT_5),
+ .INIT_6(INIT_6),
+ .INIT_7(INIT_7),
+ .INIT_8(INIT_8),
+ .INIT_9(INIT_9),
+ .INIT_A(INIT_A),
+ .INIT_B(INIT_B),
+ .INIT_C(INIT_C),
+ .INIT_D(INIT_D),
+ .INIT_E(INIT_E),
+ .INIT_F(INIT_F)
+ ) _TECHMAP_REPLACE_ (
+ .RDATA(RDATA),
+ .RCLKN(RCLK ),
+ .RCLKE(RCLKE),
+ .RE (RE ),
+ .RADDR(RADDR),
+ .WCLK (WCLK ),
+ .WCLKE(WCLKE),
+ .WE (WE ),
+ .WADDR(WADDR),
+ .MASK (MASK ),
+ .WDATA(WDATA)
+ );
+ 2'b11:
+ SB_RAM40_4KNRNW #(
+ .READ_MODE(READ_MODE),
+ .WRITE_MODE(WRITE_MODE),
+ .INIT_0(INIT_0),
+ .INIT_1(INIT_1),
+ .INIT_2(INIT_2),
+ .INIT_3(INIT_3),
+ .INIT_4(INIT_4),
+ .INIT_5(INIT_5),
+ .INIT_6(INIT_6),
+ .INIT_7(INIT_7),
+ .INIT_8(INIT_8),
+ .INIT_9(INIT_9),
+ .INIT_A(INIT_A),
+ .INIT_B(INIT_B),
+ .INIT_C(INIT_C),
+ .INIT_D(INIT_D),
+ .INIT_E(INIT_E),
+ .INIT_F(INIT_F)
+ ) _TECHMAP_REPLACE_ (
+ .RDATA(RDATA),
+ .RCLKN(RCLK ),
+ .RCLKE(RCLKE),
+ .RE (RE ),
+ .RADDR(RADDR),
+ .WCLKN(WCLK ),
+ .WCLKE(WCLKE),
+ .WE (WE ),
+ .WADDR(WADDR),
+ .MASK (MASK ),
+ .WDATA(WDATA)
+ );
+ endcase
+ endgenerate
+endmodule
+
+
+module \$__ICE40_RAM4K_M0 (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+ parameter [0:0] CLKPOL2 = 1;
+ parameter [0:0] CLKPOL3 = 1;
+
+ parameter [4095:0] INIT = 4096'bx;
+
+ input CLK2;
+ input CLK3;
+
+ input [7:0] A1ADDR;
+ output [15:0] A1DATA;
+ input A1EN;
+
+ input [7:0] B1ADDR;
+ input [15:0] B1DATA;
+ input [15:0] B1EN;
+
+ wire [10:0] A1ADDR_11 = A1ADDR;
+ wire [10:0] B1ADDR_11 = B1ADDR;
+
+ \$__ICE40_RAM4K #(
+ .READ_MODE(0),
+ .WRITE_MODE(0),
+ .NEGCLK_R(!CLKPOL2),
+ .NEGCLK_W(!CLKPOL3),
+ .INIT_0(INIT[ 0*256 +: 256]),
+ .INIT_1(INIT[ 1*256 +: 256]),
+ .INIT_2(INIT[ 2*256 +: 256]),
+ .INIT_3(INIT[ 3*256 +: 256]),
+ .INIT_4(INIT[ 4*256 +: 256]),
+ .INIT_5(INIT[ 5*256 +: 256]),
+ .INIT_6(INIT[ 6*256 +: 256]),
+ .INIT_7(INIT[ 7*256 +: 256]),
+ .INIT_8(INIT[ 8*256 +: 256]),
+ .INIT_9(INIT[ 9*256 +: 256]),
+ .INIT_A(INIT[10*256 +: 256]),
+ .INIT_B(INIT[11*256 +: 256]),
+ .INIT_C(INIT[12*256 +: 256]),
+ .INIT_D(INIT[13*256 +: 256]),
+ .INIT_E(INIT[14*256 +: 256]),
+ .INIT_F(INIT[15*256 +: 256])
+ ) _TECHMAP_REPLACE_ (
+ .RDATA(A1DATA),
+ .RADDR(A1ADDR_11),
+ .RCLK(CLK2),
+ .RCLKE(A1EN),
+ .RE(1'b1),
+ .WDATA(B1DATA),
+ .WADDR(B1ADDR_11),
+ .MASK(~B1EN),
+ .WCLK(CLK3),
+ .WCLKE(|B1EN),
+ .WE(1'b1)
+ );
+endmodule
+
+module \$__ICE40_RAM4K_M123 (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+ parameter CFG_ABITS = 9;
+ parameter CFG_DBITS = 8;
+
+ parameter [0:0] CLKPOL2 = 1;
+ parameter [0:0] CLKPOL3 = 1;
+
+ parameter [4095:0] INIT = 4096'bx;
+
+ localparam MODE =
+ CFG_ABITS == 9 ? 1 :
+ CFG_ABITS == 10 ? 2 :
+ CFG_ABITS == 11 ? 3 : 'bx;
+
+ input CLK2;
+ input CLK3;
+
+ input [CFG_ABITS-1:0] A1ADDR;
+ output [CFG_DBITS-1:0] A1DATA;
+ input A1EN;
+
+ input [CFG_ABITS-1:0] B1ADDR;
+ input [CFG_DBITS-1:0] B1DATA;
+ input B1EN;
+
+ wire [10:0] A1ADDR_11 = A1ADDR;
+ wire [10:0] B1ADDR_11 = B1ADDR;
+
+ wire [15:0] A1DATA_16, B1DATA_16;
+
+ generate
+ if (MODE == 1) begin
+ assign A1DATA = {A1DATA_16[14], A1DATA_16[12], A1DATA_16[10], A1DATA_16[ 8],
+ A1DATA_16[ 6], A1DATA_16[ 4], A1DATA_16[ 2], A1DATA_16[ 0]};
+ assign {B1DATA_16[14], B1DATA_16[12], B1DATA_16[10], B1DATA_16[ 8],
+ B1DATA_16[ 6], B1DATA_16[ 4], B1DATA_16[ 2], B1DATA_16[ 0]} = B1DATA;
+ `include "brams_init1.vh"
+ end
+ if (MODE == 2) begin
+ assign A1DATA = {A1DATA_16[13], A1DATA_16[9], A1DATA_16[5], A1DATA_16[1]};
+ assign {B1DATA_16[13], B1DATA_16[9], B1DATA_16[5], B1DATA_16[1]} = B1DATA;
+ `include "brams_init2.vh"
+ end
+ if (MODE == 3) begin
+ assign A1DATA = {A1DATA_16[11], A1DATA_16[3]};
+ assign {B1DATA_16[11], B1DATA_16[3]} = B1DATA;
+ `include "brams_init3.vh"
+ end
+ endgenerate
+
+ \$__ICE40_RAM4K #(
+ .READ_MODE(MODE),
+ .WRITE_MODE(MODE),
+ .NEGCLK_R(!CLKPOL2),
+ .NEGCLK_W(!CLKPOL3),
+ .INIT_0(INIT_0),
+ .INIT_1(INIT_1),
+ .INIT_2(INIT_2),
+ .INIT_3(INIT_3),
+ .INIT_4(INIT_4),
+ .INIT_5(INIT_5),
+ .INIT_6(INIT_6),
+ .INIT_7(INIT_7),
+ .INIT_8(INIT_8),
+ .INIT_9(INIT_9),
+ .INIT_A(INIT_A),
+ .INIT_B(INIT_B),
+ .INIT_C(INIT_C),
+ .INIT_D(INIT_D),
+ .INIT_E(INIT_E),
+ .INIT_F(INIT_F)
+ ) _TECHMAP_REPLACE_ (
+ .RDATA(A1DATA_16),
+ .RADDR(A1ADDR_11),
+ .RCLK(CLK2),
+ .RCLKE(A1EN),
+ .RE(1'b1),
+ .WDATA(B1DATA_16),
+ .WADDR(B1ADDR_11),
+ .WCLK(CLK3),
+ .WCLKE(|B1EN),
+ .WE(1'b1)
+ );
+endmodule
+
diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v
new file mode 100644
index 000000000..0227ffadb
--- /dev/null
+++ b/techlibs/ice40/cells_map.v
@@ -0,0 +1,57 @@
+module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule
+module \$_DFF_P_ (input D, C, output Q); SB_DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule
+
+module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
+module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule
+
+module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
+module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule
+
+module \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
+module \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
+module \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule
+module \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule
+
+module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
+module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
+module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule
+module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule
+
+module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
+module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
+module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule
+module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule
+
+module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
+module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule
+module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
+module \$__DFFE_PP1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule
+
+module \$lut (A, Y);
+ parameter WIDTH = 0;
+ parameter LUT = 0;
+
+ input [WIDTH-1:0] A;
+ output Y;
+
+ generate
+ if (WIDTH == 1) begin
+ SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0));
+ end else
+ if (WIDTH == 2) begin
+ SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(1'b0), .I3(1'b0));
+ end else
+ if (WIDTH == 3) begin
+ SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(1'b0));
+ end else
+ if (WIDTH == 4) begin
+ SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3]));
+ end else begin
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ endgenerate
+endmodule
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
new file mode 100644
index 000000000..7778b5519
--- /dev/null
+++ b/techlibs/ice40/cells_sim.v
@@ -0,0 +1,883 @@
+
+`define SB_DFF_REG reg Q = 0;
+// `define SB_DFF_REG reg Q;
+
+// SiliconBlue IO Cells
+
+module SB_IO (
+ inout PACKAGE_PIN,
+ input LATCH_INPUT_VALUE,
+ input CLOCK_ENABLE,
+ input INPUT_CLK,
+ input OUTPUT_CLK,
+ input OUTPUT_ENABLE,
+ input D_OUT_0,
+ input D_OUT_1,
+ output D_IN_0,
+ output D_IN_1
+);
+ parameter [5:0] PIN_TYPE = 6'b000000;
+ parameter [0:0] PULLUP = 1'b0;
+ parameter [0:0] NEG_TRIGGER = 1'b0;
+ parameter IO_STANDARD = "SB_LVCMOS";
+
+`ifndef BLACKBOX
+ reg dout, din_0, din_1;
+ reg din_q_0, din_q_1;
+ reg dout_q_0, dout_q_1;
+ reg outena_q;
+
+ generate if (!NEG_TRIGGER) begin
+ always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN;
+ always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN;
+ always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0;
+ always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1;
+ always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE;
+ end else begin
+ always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN;
+ always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN;
+ always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0;
+ always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1;
+ always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE;
+ end endgenerate
+
+ always @* begin
+ if (!PIN_TYPE[1] || !LATCH_INPUT_VALUE)
+ din_0 = PIN_TYPE[0] ? PACKAGE_PIN : din_q_0;
+ din_1 = din_q_1;
+ end
+
+ // work around simulation glitches on dout in DDR mode
+ reg outclk_delayed_1;
+ reg outclk_delayed_2;
+ always @* outclk_delayed_1 <= OUTPUT_CLK;
+ always @* outclk_delayed_2 <= outclk_delayed_1;
+
+ always @* begin
+ if (PIN_TYPE[3])
+ dout = PIN_TYPE[2] ? !dout_q_0 : D_OUT_0;
+ else
+ dout = (outclk_delayed_2 ^ NEG_TRIGGER) || PIN_TYPE[2] ? dout_q_0 : dout_q_1;
+ end
+
+ assign D_IN_0 = din_0, D_IN_1 = din_1;
+
+ generate
+ if (PIN_TYPE[5:4] == 2'b01) assign PACKAGE_PIN = dout;
+ if (PIN_TYPE[5:4] == 2'b10) assign PACKAGE_PIN = OUTPUT_ENABLE ? dout : 1'bz;
+ if (PIN_TYPE[5:4] == 2'b11) assign PACKAGE_PIN = outena_q ? dout : 1'bz;
+ endgenerate
+`endif
+endmodule
+
+module SB_GB_IO (
+ inout PACKAGE_PIN,
+ output GLOBAL_BUFFER_OUTPUT,
+ input LATCH_INPUT_VALUE,
+ input CLOCK_ENABLE,
+ input INPUT_CLK,
+ input OUTPUT_CLK,
+ input OUTPUT_ENABLE,
+ input D_OUT_0,
+ input D_OUT_1,
+ output D_IN_0,
+ output D_IN_1
+);
+ parameter [5:0] PIN_TYPE = 6'b000000;
+ parameter [0:0] PULLUP = 1'b0;
+ parameter [0:0] NEG_TRIGGER = 1'b0;
+ parameter IO_STANDARD = "SB_LVCMOS";
+
+ assign GLOBAL_BUFFER_OUTPUT = PACKAGE_PIN;
+
+ SB_IO #(
+ .PIN_TYPE(PIN_TYPE),
+ .PULLUP(PULLUP),
+ .NEG_TRIGGER(NEG_TRIGGER),
+ .IO_STANDARD(IO_STANDARD)
+ ) IO (
+ .PACKAGE_PIN(PACKAGE_PIN),
+ .LATCH_INPUT_VALUE(LATCH_INPUT_VALUE),
+ .CLOCK_ENABLE(CLOCK_ENABLE),
+ .INPUT_CLK(INPUT_CLK),
+ .OUTPUT_CLK(OUTPUT_CLK),
+ .OUTPUT_ENABLE(OUTPUT_ENABLE),
+ .D_OUT_0(D_OUT_0),
+ .D_OUT_1(D_OUT_1),
+ .D_IN_0(D_IN_0),
+ .D_IN_1(D_IN_1)
+ );
+endmodule
+
+module SB_GB (
+ input USER_SIGNAL_TO_GLOBAL_BUFFER,
+ output GLOBAL_BUFFER_OUTPUT
+);
+ assign GLOBAL_BUFFER_OUTPUT = USER_SIGNAL_TO_GLOBAL_BUFFER;
+endmodule
+
+// SiliconBlue Logic Cells
+
+module SB_LUT4 (output O, input I0, I1, I2, I3);
+ parameter [15:0] LUT_INIT = 0;
+ wire [7:0] s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0];
+ wire [3:0] s2 = I2 ? s3[ 7:4] : s3[3:0];
+ wire [1:0] s1 = I1 ? s2[ 3:2] : s2[1:0];
+ assign O = I0 ? s1[1] : s1[0];
+endmodule
+
+module SB_CARRY (output CO, input I0, I1, CI);
+ assign CO = (I0 && I1) || ((I0 || I1) && CI);
+endmodule
+
+// Positive Edge SiliconBlue FF Cells
+
+module SB_DFF (output Q, input C, D);
+ `SB_DFF_REG
+ always @(posedge C)
+ Q <= D;
+endmodule
+
+module SB_DFFE (output Q, input C, E, D);
+ `SB_DFF_REG
+ always @(posedge C)
+ if (E)
+ Q <= D;
+endmodule
+
+module SB_DFFSR (output Q, input C, R, D);
+ `SB_DFF_REG
+ always @(posedge C)
+ if (R)
+ Q <= 0;
+ else
+ Q <= D;
+endmodule
+
+module SB_DFFR (output Q, input C, R, D);
+ `SB_DFF_REG
+ always @(posedge C, posedge R)
+ if (R)
+ Q <= 0;
+ else
+ Q <= D;
+endmodule
+
+module SB_DFFSS (output Q, input C, S, D);
+ `SB_DFF_REG
+ always @(posedge C)
+ if (S)
+ Q <= 1;
+ else
+ Q <= D;
+endmodule
+
+module SB_DFFS (output Q, input C, S, D);
+ `SB_DFF_REG
+ always @(posedge C, posedge S)
+ if (S)
+ Q <= 1;
+ else
+ Q <= D;
+endmodule
+
+module SB_DFFESR (output Q, input C, E, R, D);
+ `SB_DFF_REG
+ always @(posedge C)
+ if (E) begin
+ if (R)
+ Q <= 0;
+ else
+ Q <= D;
+ end
+endmodule
+
+module SB_DFFER (output Q, input C, E, R, D);
+ `SB_DFF_REG
+ always @(posedge C, posedge R)
+ if (R)
+ Q <= 0;
+ else if (E)
+ Q <= D;
+endmodule
+
+module SB_DFFESS (output Q, input C, E, S, D);
+ `SB_DFF_REG
+ always @(posedge C)
+ if (E) begin
+ if (S)
+ Q <= 1;
+ else
+ Q <= D;
+ end
+endmodule
+
+module SB_DFFES (output Q, input C, E, S, D);
+ `SB_DFF_REG
+ always @(posedge C, posedge S)
+ if (S)
+ Q <= 1;
+ else if (E)
+ Q <= D;
+endmodule
+
+// Negative Edge SiliconBlue FF Cells
+
+module SB_DFFN (output Q, input C, D);
+ `SB_DFF_REG
+ always @(negedge C)
+ Q <= D;
+endmodule
+
+module SB_DFFNE (output Q, input C, E, D);
+ `SB_DFF_REG
+ always @(negedge C)
+ if (E)
+ Q <= D;
+endmodule
+
+module SB_DFFNSR (output Q, input C, R, D);
+ `SB_DFF_REG
+ always @(negedge C)
+ if (R)
+ Q <= 0;
+ else
+ Q <= D;
+endmodule
+
+module SB_DFFNR (output Q, input C, R, D);
+ `SB_DFF_REG
+ always @(negedge C, posedge R)
+ if (R)
+ Q <= 0;
+ else
+ Q <= D;
+endmodule
+
+module SB_DFFNSS (output Q, input C, S, D);
+ `SB_DFF_REG
+ always @(negedge C)
+ if (S)
+ Q <= 1;
+ else
+ Q <= D;
+endmodule
+
+module SB_DFFNS (output Q, input C, S, D);
+ `SB_DFF_REG
+ always @(negedge C, posedge S)
+ if (S)
+ Q <= 1;
+ else
+ Q <= D;
+endmodule
+
+module SB_DFFNESR (output Q, input C, E, R, D);
+ `SB_DFF_REG
+ always @(negedge C)
+ if (E) begin
+ if (R)
+ Q <= 0;
+ else
+ Q <= D;
+ end
+endmodule
+
+module SB_DFFNER (output Q, input C, E, R, D);
+ `SB_DFF_REG
+ always @(negedge C, posedge R)
+ if (R)
+ Q <= 0;
+ else if (E)
+ Q <= D;
+endmodule
+
+module SB_DFFNESS (output Q, input C, E, S, D);
+ `SB_DFF_REG
+ always @(negedge C)
+ if (E) begin
+ if (S)
+ Q <= 1;
+ else
+ Q <= D;
+ end
+endmodule
+
+module SB_DFFNES (output Q, input C, E, S, D);
+ `SB_DFF_REG
+ always @(negedge C, posedge S)
+ if (S)
+ Q <= 1;
+ else if (E)
+ Q <= D;
+endmodule
+
+// SiliconBlue RAM Cells
+
+module SB_RAM40_4K (
+ output [15:0] RDATA,
+ input RCLK, RCLKE, RE,
+ input [10:0] RADDR,
+ input WCLK, WCLKE, WE,
+ input [10:0] WADDR,
+ input [15:0] MASK, WDATA
+);
+ // MODE 0: 256 x 16
+ // MODE 1: 512 x 8
+ // MODE 2: 1024 x 4
+ // MODE 3: 2048 x 2
+ parameter WRITE_MODE = 0;
+ parameter READ_MODE = 0;
+
+ parameter INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+
+`ifndef BLACKBOX
+ wire [15:0] WMASK_I;
+ wire [15:0] RMASK_I;
+
+ reg [15:0] RDATA_I;
+ wire [15:0] WDATA_I;
+
+ generate
+ case (WRITE_MODE)
+ 0: assign WMASK_I = MASK;
+
+ 1: assign WMASK_I = WADDR[ 8] == 0 ? 16'b 1010_1010_1010_1010 :
+ WADDR[ 8] == 1 ? 16'b 0101_0101_0101_0101 : 16'bx;
+
+ 2: assign WMASK_I = WADDR[ 9:8] == 0 ? 16'b 1110_1110_1110_1110 :
+ WADDR[ 9:8] == 1 ? 16'b 1101_1101_1101_1101 :
+ WADDR[ 9:8] == 2 ? 16'b 1011_1011_1011_1011 :
+ WADDR[ 9:8] == 3 ? 16'b 0111_0111_0111_0111 : 16'bx;
+
+ 3: assign WMASK_I = WADDR[10:8] == 0 ? 16'b 1111_1110_1111_1110 :
+ WADDR[10:8] == 1 ? 16'b 1111_1101_1111_1101 :
+ WADDR[10:8] == 2 ? 16'b 1111_1011_1111_1011 :
+ WADDR[10:8] == 3 ? 16'b 1111_0111_1111_0111 :
+ WADDR[10:8] == 4 ? 16'b 1110_1111_1110_1111 :
+ WADDR[10:8] == 5 ? 16'b 1101_1111_1101_1111 :
+ WADDR[10:8] == 6 ? 16'b 1011_1111_1011_1111 :
+ WADDR[10:8] == 7 ? 16'b 0111_1111_0111_1111 : 16'bx;
+ endcase
+
+ case (READ_MODE)
+ 0: assign RMASK_I = 16'b 0000_0000_0000_0000;
+
+ 1: assign RMASK_I = RADDR[ 8] == 0 ? 16'b 1010_1010_1010_1010 :
+ RADDR[ 8] == 1 ? 16'b 0101_0101_0101_0101 : 16'bx;
+
+ 2: assign RMASK_I = RADDR[ 9:8] == 0 ? 16'b 1110_1110_1110_1110 :
+ RADDR[ 9:8] == 1 ? 16'b 1101_1101_1101_1101 :
+ RADDR[ 9:8] == 2 ? 16'b 1011_1011_1011_1011 :
+ RADDR[ 9:8] == 3 ? 16'b 0111_0111_0111_0111 : 16'bx;
+
+ 3: assign RMASK_I = RADDR[10:8] == 0 ? 16'b 1111_1110_1111_1110 :
+ RADDR[10:8] == 1 ? 16'b 1111_1101_1111_1101 :
+ RADDR[10:8] == 2 ? 16'b 1111_1011_1111_1011 :
+ RADDR[10:8] == 3 ? 16'b 1111_0111_1111_0111 :
+ RADDR[10:8] == 4 ? 16'b 1110_1111_1110_1111 :
+ RADDR[10:8] == 5 ? 16'b 1101_1111_1101_1111 :
+ RADDR[10:8] == 6 ? 16'b 1011_1111_1011_1111 :
+ RADDR[10:8] == 7 ? 16'b 0111_1111_0111_1111 : 16'bx;
+ endcase
+
+ case (WRITE_MODE)
+ 0: assign WDATA_I = WDATA;
+
+ 1: assign WDATA_I = {WDATA[14], WDATA[14], WDATA[12], WDATA[12],
+ WDATA[10], WDATA[10], WDATA[ 8], WDATA[ 8],
+ WDATA[ 6], WDATA[ 6], WDATA[ 4], WDATA[ 4],
+ WDATA[ 2], WDATA[ 2], WDATA[ 0], WDATA[ 0]};
+
+ 2: assign WDATA_I = {WDATA[13], WDATA[13], WDATA[13], WDATA[13],
+ WDATA[ 9], WDATA[ 9], WDATA[ 9], WDATA[ 9],
+ WDATA[ 5], WDATA[ 5], WDATA[ 5], WDATA[ 5],
+ WDATA[ 1], WDATA[ 1], WDATA[ 1], WDATA[ 1]};
+
+ 3: assign WDATA_I = {WDATA[11], WDATA[11], WDATA[11], WDATA[11],
+ WDATA[11], WDATA[11], WDATA[11], WDATA[11],
+ WDATA[ 3], WDATA[ 3], WDATA[ 3], WDATA[ 3],
+ WDATA[ 3], WDATA[ 3], WDATA[ 3], WDATA[ 3]};
+ endcase
+
+ case (READ_MODE)
+ 0: assign RDATA = RDATA_I;
+ 1: assign RDATA = {1'b0, |RDATA_I[15:14], 1'b0, |RDATA_I[13:12], 1'b0, |RDATA_I[11:10], 1'b0, |RDATA_I[ 9: 8],
+ 1'b0, |RDATA_I[ 7: 6], 1'b0, |RDATA_I[ 5: 4], 1'b0, |RDATA_I[ 3: 2], 1'b0, |RDATA_I[ 1: 0]};
+ 2: assign RDATA = {2'b0, |RDATA_I[15:12], 3'b0, |RDATA_I[11: 8], 3'b0, |RDATA_I[ 7: 4], 3'b0, |RDATA_I[ 3: 0], 1'b0};
+ 3: assign RDATA = {4'b0, |RDATA_I[15: 8], 7'b0, |RDATA_I[ 7: 0], 3'b0};
+ endcase
+ endgenerate
+
+ integer i;
+ reg [15:0] memory [0:255];
+
+ initial begin
+ for (i=0; i<16; i=i+1) begin
+ memory[ 0*16 + i] <= INIT_0[16*i +: 16];
+ memory[ 1*16 + i] <= INIT_1[16*i +: 16];
+ memory[ 2*16 + i] <= INIT_2[16*i +: 16];
+ memory[ 3*16 + i] <= INIT_3[16*i +: 16];
+ memory[ 4*16 + i] <= INIT_4[16*i +: 16];
+ memory[ 5*16 + i] <= INIT_5[16*i +: 16];
+ memory[ 6*16 + i] <= INIT_6[16*i +: 16];
+ memory[ 7*16 + i] <= INIT_7[16*i +: 16];
+ memory[ 8*16 + i] <= INIT_8[16*i +: 16];
+ memory[ 9*16 + i] <= INIT_9[16*i +: 16];
+ memory[10*16 + i] <= INIT_A[16*i +: 16];
+ memory[11*16 + i] <= INIT_B[16*i +: 16];
+ memory[12*16 + i] <= INIT_C[16*i +: 16];
+ memory[13*16 + i] <= INIT_D[16*i +: 16];
+ memory[14*16 + i] <= INIT_E[16*i +: 16];
+ memory[15*16 + i] <= INIT_F[16*i +: 16];
+ end
+ end
+
+ always @(posedge WCLK) begin
+ if (WE && WCLKE) begin
+ if (!WMASK_I[ 0]) memory[WADDR[7:0]][ 0] <= WDATA_I[ 0];
+ if (!WMASK_I[ 1]) memory[WADDR[7:0]][ 1] <= WDATA_I[ 1];
+ if (!WMASK_I[ 2]) memory[WADDR[7:0]][ 2] <= WDATA_I[ 2];
+ if (!WMASK_I[ 3]) memory[WADDR[7:0]][ 3] <= WDATA_I[ 3];
+ if (!WMASK_I[ 4]) memory[WADDR[7:0]][ 4] <= WDATA_I[ 4];
+ if (!WMASK_I[ 5]) memory[WADDR[7:0]][ 5] <= WDATA_I[ 5];
+ if (!WMASK_I[ 6]) memory[WADDR[7:0]][ 6] <= WDATA_I[ 6];
+ if (!WMASK_I[ 7]) memory[WADDR[7:0]][ 7] <= WDATA_I[ 7];
+ if (!WMASK_I[ 8]) memory[WADDR[7:0]][ 8] <= WDATA_I[ 8];
+ if (!WMASK_I[ 9]) memory[WADDR[7:0]][ 9] <= WDATA_I[ 9];
+ if (!WMASK_I[10]) memory[WADDR[7:0]][10] <= WDATA_I[10];
+ if (!WMASK_I[11]) memory[WADDR[7:0]][11] <= WDATA_I[11];
+ if (!WMASK_I[12]) memory[WADDR[7:0]][12] <= WDATA_I[12];
+ if (!WMASK_I[13]) memory[WADDR[7:0]][13] <= WDATA_I[13];
+ if (!WMASK_I[14]) memory[WADDR[7:0]][14] <= WDATA_I[14];
+ if (!WMASK_I[15]) memory[WADDR[7:0]][15] <= WDATA_I[15];
+ end
+ end
+
+ always @(posedge RCLK) begin
+ if (RE && RCLKE) begin
+ RDATA_I <= memory[RADDR[7:0]] & ~RMASK_I;
+ end
+ end
+`endif
+endmodule
+
+module SB_RAM40_4KNR (
+ output [15:0] RDATA,
+ input RCLKN, RCLKE, RE,
+ input [10:0] RADDR,
+ input WCLK, WCLKE, WE,
+ input [10:0] WADDR,
+ input [15:0] MASK, WDATA
+);
+ parameter WRITE_MODE = 0;
+ parameter READ_MODE = 0;
+
+ parameter INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+
+ SB_RAM40_4K #(
+ .WRITE_MODE(WRITE_MODE),
+ .READ_MODE (READ_MODE ),
+ .INIT_0 (INIT_0 ),
+ .INIT_1 (INIT_1 ),
+ .INIT_2 (INIT_2 ),
+ .INIT_3 (INIT_3 ),
+ .INIT_4 (INIT_4 ),
+ .INIT_5 (INIT_5 ),
+ .INIT_6 (INIT_6 ),
+ .INIT_7 (INIT_7 ),
+ .INIT_8 (INIT_8 ),
+ .INIT_9 (INIT_9 ),
+ .INIT_A (INIT_A ),
+ .INIT_B (INIT_B ),
+ .INIT_C (INIT_C ),
+ .INIT_D (INIT_D ),
+ .INIT_E (INIT_E ),
+ .INIT_F (INIT_F )
+ ) RAM (
+ .RDATA(RDATA),
+ .RCLK (~RCLKN),
+ .RCLKE(RCLKE),
+ .RE (RE ),
+ .RADDR(RADDR),
+ .WCLK (WCLK ),
+ .WCLKE(WCLKE),
+ .WE (WE ),
+ .WADDR(WADDR),
+ .MASK (MASK ),
+ .WDATA(WDATA)
+ );
+endmodule
+
+module SB_RAM40_4KNW (
+ output [15:0] RDATA,
+ input RCLK, RCLKE, RE,
+ input [10:0] RADDR,
+ input WCLKN, WCLKE, WE,
+ input [10:0] WADDR,
+ input [15:0] MASK, WDATA
+);
+ parameter WRITE_MODE = 0;
+ parameter READ_MODE = 0;
+
+ parameter INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+
+ SB_RAM40_4K #(
+ .WRITE_MODE(WRITE_MODE),
+ .READ_MODE (READ_MODE ),
+ .INIT_0 (INIT_0 ),
+ .INIT_1 (INIT_1 ),
+ .INIT_2 (INIT_2 ),
+ .INIT_3 (INIT_3 ),
+ .INIT_4 (INIT_4 ),
+ .INIT_5 (INIT_5 ),
+ .INIT_6 (INIT_6 ),
+ .INIT_7 (INIT_7 ),
+ .INIT_8 (INIT_8 ),
+ .INIT_9 (INIT_9 ),
+ .INIT_A (INIT_A ),
+ .INIT_B (INIT_B ),
+ .INIT_C (INIT_C ),
+ .INIT_D (INIT_D ),
+ .INIT_E (INIT_E ),
+ .INIT_F (INIT_F )
+ ) RAM (
+ .RDATA(RDATA),
+ .RCLK (RCLK ),
+ .RCLKE(RCLKE),
+ .RE (RE ),
+ .RADDR(RADDR),
+ .WCLK (~WCLKN),
+ .WCLKE(WCLKE),
+ .WE (WE ),
+ .WADDR(WADDR),
+ .MASK (MASK ),
+ .WDATA(WDATA)
+ );
+endmodule
+
+module SB_RAM40_4KNRNW (
+ output [15:0] RDATA,
+ input RCLKN, RCLKE, RE,
+ input [10:0] RADDR,
+ input WCLKN, WCLKE, WE,
+ input [10:0] WADDR,
+ input [15:0] MASK, WDATA
+);
+ parameter WRITE_MODE = 0;
+ parameter READ_MODE = 0;
+
+ parameter INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+ parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
+
+ SB_RAM40_4K #(
+ .WRITE_MODE(WRITE_MODE),
+ .READ_MODE (READ_MODE ),
+ .INIT_0 (INIT_0 ),
+ .INIT_1 (INIT_1 ),
+ .INIT_2 (INIT_2 ),
+ .INIT_3 (INIT_3 ),
+ .INIT_4 (INIT_4 ),
+ .INIT_5 (INIT_5 ),
+ .INIT_6 (INIT_6 ),
+ .INIT_7 (INIT_7 ),
+ .INIT_8 (INIT_8 ),
+ .INIT_9 (INIT_9 ),
+ .INIT_A (INIT_A ),
+ .INIT_B (INIT_B ),
+ .INIT_C (INIT_C ),
+ .INIT_D (INIT_D ),
+ .INIT_E (INIT_E ),
+ .INIT_F (INIT_F )
+ ) RAM (
+ .RDATA(RDATA),
+ .RCLK (~RCLKN),
+ .RCLKE(RCLKE),
+ .RE (RE ),
+ .RADDR(RADDR),
+ .WCLK (~WCLKN),
+ .WCLKE(WCLKE),
+ .WE (WE ),
+ .WADDR(WADDR),
+ .MASK (MASK ),
+ .WDATA(WDATA)
+ );
+endmodule
+
+// Packed IceStorm Logic Cells
+
+module ICESTORM_LC (
+ input I0, I1, I2, I3, CIN, CLK, CEN, SR,
+ output LO, O, COUT
+);
+ parameter [15:0] LUT_INIT = 0;
+
+ parameter [0:0] NEG_CLK = 0;
+ parameter [0:0] CARRY_ENABLE = 0;
+ parameter [0:0] DFF_ENABLE = 0;
+ parameter [0:0] SET_NORESET = 0;
+ parameter [0:0] ASYNC_SR = 0;
+
+ wire COUT = CARRY_ENABLE ? (I1 && I2) || ((I1 || I2) && CIN) : 1'bx;
+
+ wire [7:0] lut_s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0];
+ wire [3:0] lut_s2 = I2 ? lut_s3[ 7:4] : lut_s3[3:0];
+ wire [1:0] lut_s1 = I1 ? lut_s2[ 3:2] : lut_s2[1:0];
+ wire lut_o = I0 ? lut_s1[ 1] : lut_s1[ 0];
+
+ assign LO = lut_o;
+
+ wire polarized_clk;
+ assign polarized_clk = CLK ^ NEG_CLK;
+
+ reg o_reg;
+ always @(posedge polarized_clk)
+ if (CEN)
+ o_reg <= SR ? SET_NORESET : lut_o;
+
+ reg o_reg_async;
+ always @(posedge polarized_clk, posedge SR)
+ if (SR)
+ o_reg <= SET_NORESET;
+ else if (CEN)
+ o_reg <= lut_o;
+
+ assign O = DFF_ENABLE ? ASYNC_SR ? o_reg_async : o_reg : lut_o;
+endmodule
+
+// SiliconBlue PLL Cells
+
+(* blackbox *)
+module SB_PLL40_CORE (
+ input REFERENCECLK,
+ output PLLOUTCORE,
+ output PLLOUTGLOBAL,
+ input EXTFEEDBACK,
+ input [7:0] DYNAMICDELAY,
+ output LOCK,
+ input BYPASS,
+ input RESETB,
+ input LATCHINPUTVALUE,
+ output SDO,
+ input SDI,
+ input SCLK
+);
+ parameter FEEDBACK_PATH = "SIMPLE";
+ parameter DELAY_ADJUSTMENT_MODE_FEEDBACK = "FIXED";
+ parameter DELAY_ADJUSTMENT_MODE_RELATIVE = "FIXED";
+ parameter SHIFTREG_DIV_MODE = 1'b0;
+ parameter FDA_FEEDBACK = 4'b0000;
+ parameter FDA_RELATIVE = 4'b0000;
+ parameter PLLOUT_SELECT = "GENCLK";
+ parameter DIVR = 4'b0000;
+ parameter DIVF = 7'b0000000;
+ parameter DIVQ = 3'b000;
+ parameter FILTER_RANGE = 3'b000;
+ parameter ENABLE_ICEGATE = 1'b0;
+ parameter TEST_MODE = 1'b0;
+ parameter EXTERNAL_DIVIDE_FACTOR = 1;
+endmodule
+
+(* blackbox *)
+module SB_PLL40_PAD (
+ input PACKAGEPIN,
+ output PLLOUTCORE,
+ output PLLOUTGLOBAL,
+ input EXTFEEDBACK,
+ input [7:0] DYNAMICDELAY,
+ output LOCK,
+ input BYPASS,
+ input RESETB,
+ input LATCHINPUTVALUE,
+ output SDO,
+ input SDI,
+ input SCLK
+);
+ parameter FEEDBACK_PATH = "SIMPLE";
+ parameter DELAY_ADJUSTMENT_MODE_FEEDBACK = "FIXED";
+ parameter DELAY_ADJUSTMENT_MODE_RELATIVE = "FIXED";
+ parameter SHIFTREG_DIV_MODE = 1'b0;
+ parameter FDA_FEEDBACK = 4'b0000;
+ parameter FDA_RELATIVE = 4'b0000;
+ parameter PLLOUT_SELECT = "GENCLK";
+ parameter DIVR = 4'b0000;
+ parameter DIVF = 7'b0000000;
+ parameter DIVQ = 3'b000;
+ parameter FILTER_RANGE = 3'b000;
+ parameter ENABLE_ICEGATE = 1'b0;
+ parameter TEST_MODE = 1'b0;
+ parameter EXTERNAL_DIVIDE_FACTOR = 1;
+endmodule
+
+(* blackbox *)
+module SB_PLL40_2_PAD (
+ input PACKAGEPIN,
+ output PLLOUTCOREA,
+ output PLLOUTGLOBALA,
+ output PLLOUTCOREB,
+ output PLLOUTGLOBALB,
+ input EXTFEEDBACK,
+ input [7:0] DYNAMICDELAY,
+ output LOCK,
+ input BYPASS,
+ input RESETB,
+ input LATCHINPUTVALUE,
+ output SDO,
+ input SDI,
+ input SCLK
+);
+ parameter FEEDBACK_PATH = "SIMPLE";
+ parameter DELAY_ADJUSTMENT_MODE_FEEDBACK = "FIXED";
+ parameter DELAY_ADJUSTMENT_MODE_RELATIVE = "FIXED";
+ parameter SHIFTREG_DIV_MODE = 1'b0;
+ parameter FDA_FEEDBACK = 4'b0000;
+ parameter FDA_RELATIVE = 4'b0000;
+ parameter PLLOUT_SELECT_PORTB = "GENCLK";
+ parameter DIVR = 4'b0000;
+ parameter DIVF = 7'b0000000;
+ parameter DIVQ = 3'b000;
+ parameter FILTER_RANGE = 3'b000;
+ parameter ENABLE_ICEGATE_PORTA = 1'b0;
+ parameter ENABLE_ICEGATE_PORTB = 1'b0;
+ parameter TEST_MODE = 1'b0;
+ parameter EXTERNAL_DIVIDE_FACTOR = 1;
+endmodule
+
+(* blackbox *)
+module SB_PLL40_2F_CORE (
+ input REFERENCECLK,
+ output PLLOUTCOREA,
+ output PLLOUTGLOBALA,
+ output PLLOUTCOREB,
+ output PLLOUTGLOBALB,
+ input EXTFEEDBACK,
+ input [7:0] DYNAMICDELAY,
+ output LOCK,
+ input BYPASS,
+ input RESETB,
+ input LATCHINPUTVALUE,
+ output SDO,
+ input SDI,
+ input SCLK
+);
+ parameter FEEDBACK_PATH = "SIMPLE";
+ parameter DELAY_ADJUSTMENT_MODE_FEEDBACK = "FIXED";
+ parameter DELAY_ADJUSTMENT_MODE_RELATIVE = "FIXED";
+ parameter SHIFTREG_DIV_MODE = 1'b0;
+ parameter FDA_FEEDBACK = 4'b0000;
+ parameter FDA_RELATIVE = 4'b0000;
+ parameter PLLOUT_SELECT_PORTA = "GENCLK";
+ parameter PLLOUT_SELECT_PORTB = "GENCLK";
+ parameter DIVR = 4'b0000;
+ parameter DIVF = 7'b0000000;
+ parameter DIVQ = 3'b000;
+ parameter FILTER_RANGE = 3'b000;
+ parameter ENABLE_ICEGATE_PORTA = 1'b0;
+ parameter ENABLE_ICEGATE_PORTB = 1'b0;
+ parameter TEST_MODE = 1'b0;
+ parameter EXTERNAL_DIVIDE_FACTOR = 1;
+endmodule
+
+(* blackbox *)
+module SB_PLL40_2F_PAD (
+ input PACKAGEPIN,
+ output PLLOUTCOREA,
+ output PLLOUTGLOBALA,
+ output PLLOUTCOREB,
+ output PLLOUTGLOBALB,
+ input EXTFEEDBACK,
+ input [7:0] DYNAMICDELAY,
+ output LOCK,
+ input BYPASS,
+ input RESETB,
+ input LATCHINPUTVALUE,
+ output SDO,
+ input SDI,
+ input SCLK
+);
+ parameter FEEDBACK_PATH = "SIMPLE";
+ parameter DELAY_ADJUSTMENT_MODE_FEEDBACK = "FIXED";
+ parameter DELAY_ADJUSTMENT_MODE_RELATIVE = "FIXED";
+ parameter SHIFTREG_DIV_MODE = 2'b00;
+ parameter FDA_FEEDBACK = 4'b0000;
+ parameter FDA_RELATIVE = 4'b0000;
+ parameter PLLOUT_SELECT_PORTA = "GENCLK";
+ parameter PLLOUT_SELECT_PORTB = "GENCLK";
+ parameter DIVR = 4'b0000;
+ parameter DIVF = 7'b0000000;
+ parameter DIVQ = 3'b000;
+ parameter FILTER_RANGE = 3'b000;
+ parameter ENABLE_ICEGATE_PORTA = 1'b0;
+ parameter ENABLE_ICEGATE_PORTB = 1'b0;
+ parameter TEST_MODE = 1'b0;
+ parameter EXTERNAL_DIVIDE_FACTOR = 1;
+endmodule
+
+// SiliconBlue Device Configuration Cells
+
+(* blackbox, keep *)
+module SB_WARMBOOT (
+ input BOOT,
+ input S1,
+ input S0
+);
+endmodule
diff --git a/techlibs/ice40/ice40_ffinit.cc b/techlibs/ice40/ice40_ffinit.cc
new file mode 100644
index 000000000..8a2c30d6a
--- /dev/null
+++ b/techlibs/ice40/ice40_ffinit.cc
@@ -0,0 +1,167 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct Ice40FfinitPass : public Pass {
+ Ice40FfinitPass() : Pass("ice40_ffinit", "iCE40: handle FF init values") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" ice40_ffinit [options] [selection]\n");
+ log("\n");
+ log("Remove zero init values for FF output signals. Add inverters to implement\n");
+ log("nonzero init values.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing ICE40_FFINIT pass (implement FF init values).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-singleton") {
+ // singleton_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ log("Handling FF init values in %s.\n", log_id(module));
+
+ SigMap sigmap(module);
+ pool<Wire*> init_wires;
+ dict<SigBit, State> initbits;
+ dict<SigBit, SigBit> initbit_to_wire;
+ pool<SigBit> handled_initbits;
+
+ for (auto wire : module->selected_wires())
+ {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+
+ SigSpec wirebits = sigmap(wire);
+ Const initval = wire->attributes.at("\\init");
+ init_wires.insert(wire);
+
+ for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++)
+ {
+ SigBit bit = wirebits[i];
+ State val = initval[i];
+
+ if (val != State::S0 && val != State::S1)
+ continue;
+
+ if (initbits.count(bit)) {
+ if (initbits.at(bit) != val)
+ log_error("Conflicting init values for signal %s (%s = %s, %s = %s).\n",
+ log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val),
+ log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit)));
+ continue;
+ }
+
+ initbits[bit] = val;
+ initbit_to_wire[bit] = SigBit(wire, i);
+ }
+ }
+
+ pool<IdString> sb_dff_types = {
+ "\\SB_DFF", "\\SB_DFFE", "\\SB_DFFSR", "\\SB_DFFR", "\\SB_DFFSS", "\\SB_DFFS", "\\SB_DFFESR",
+ "\\SB_DFFER", "\\SB_DFFESS", "\\SB_DFFES", "\\SB_DFFN", "\\SB_DFFNE", "\\SB_DFFNSR", "\\SB_DFFNR",
+ "\\SB_DFFNSS", "\\SB_DFFNS", "\\SB_DFFNESR", "\\SB_DFFNER", "\\SB_DFFNESS", "\\SB_DFFNES"
+ };
+
+ for (auto cell : module->selected_cells())
+ {
+ if (!sb_dff_types.count(cell->type))
+ continue;
+
+ SigBit sig_d = sigmap(cell->getPort("\\D"));
+ SigBit sig_q = sigmap(cell->getPort("\\Q"));
+
+ if (!initbits.count(sig_q))
+ continue;
+
+ State val = initbits.at(sig_q);
+ handled_initbits.insert(sig_q);
+
+ log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type),
+ log_signal(sig_q), val != State::S0 ? '1' : '0');
+
+ if (val == State::S0)
+ continue;
+
+ string type_str = cell->type.str();
+
+ if (type_str.back() == 'S') {
+ type_str.back() = 'R';
+ cell->type = type_str;
+ cell->setPort("\\R", cell->getPort("\\S"));
+ cell->unsetPort("\\S");
+ } else
+ if (type_str.back() == 'R') {
+ type_str.back() = 'S';
+ cell->type = type_str;
+ cell->setPort("\\S", cell->getPort("\\R"));
+ cell->unsetPort("\\R");
+ }
+
+ Wire *new_sig_d = module->addWire(NEW_ID);
+ Wire *new_sig_q = module->addWire(NEW_ID);
+
+ module->addNotGate(NEW_ID, sig_d, new_sig_d);
+ module->addNotGate(NEW_ID, new_sig_q, sig_q);
+
+ cell->setPort("\\D", new_sig_d);
+ cell->setPort("\\Q", new_sig_q);
+ }
+
+ for (auto wire : init_wires)
+ {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+
+ SigSpec wirebits = sigmap(wire);
+ Const &initval = wire->attributes.at("\\init");
+ bool remove_attribute = true;
+
+ for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) {
+ if (handled_initbits.count(wirebits[i]))
+ initval[i] = State::Sx;
+ else if (initval[i] != State::Sx)
+ remove_attribute = false;
+ }
+
+ if (remove_attribute)
+ wire->attributes.erase("\\init");
+ }
+ }
+ }
+} Ice40FfinitPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/ice40/ice40_ffssr.cc b/techlibs/ice40/ice40_ffssr.cc
new file mode 100644
index 000000000..9a6d69df0
--- /dev/null
+++ b/techlibs/ice40/ice40_ffssr.cc
@@ -0,0 +1,123 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct Ice40FfssrPass : public Pass {
+ Ice40FfssrPass() : Pass("ice40_ffssr", "iCE40: merge synchronous set/reset into FF cells") { }
+ virtual void help()
+ {
+ log("\n");
+ log(" ice40_ffssr [options] [selection]\n");
+ log("\n");
+ log("Merge synchronous set/reset $_MUX_ cells into iCE40 FFs.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing ICE40_FFSSR pass (merge synchronous set/reset into FF cells).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-singleton") {
+ // singleton_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ pool<IdString> sb_dff_types;
+ sb_dff_types.insert("\\SB_DFF");
+ sb_dff_types.insert("\\SB_DFFE");
+ sb_dff_types.insert("\\SB_DFFN");
+ sb_dff_types.insert("\\SB_DFFNE");
+
+ for (auto module : design->selected_modules())
+ {
+ log("Merging set/reset $_MUX_ cells into SB_FFs in %s.\n", log_id(module));
+
+ SigMap sigmap(module);
+ dict<SigBit, Cell*> sr_muxes;
+ vector<Cell*> ff_cells;
+
+ for (auto cell : module->selected_cells())
+ {
+ if (sb_dff_types.count(cell->type)) {
+ ff_cells.push_back(cell);
+ continue;
+ }
+
+ if (cell->type != "$_MUX_")
+ continue;
+
+ SigBit bit_a = sigmap(cell->getPort("\\A"));
+ SigBit bit_b = sigmap(cell->getPort("\\B"));
+
+ if (bit_a.wire == nullptr || bit_b.wire == nullptr)
+ sr_muxes[sigmap(cell->getPort("\\Y"))] = cell;
+ }
+
+ for (auto cell : ff_cells)
+ {
+ SigBit bit_d = sigmap(cell->getPort("\\D"));
+
+ if (sr_muxes.count(bit_d) == 0)
+ continue;
+
+ Cell *mux_cell = sr_muxes.at(bit_d);
+ SigBit bit_a = sigmap(mux_cell->getPort("\\A"));
+ SigBit bit_b = sigmap(mux_cell->getPort("\\B"));
+ SigBit bit_s = sigmap(mux_cell->getPort("\\S"));
+
+ log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
+ log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
+
+ SigBit sr_val, sr_sig;
+ if (bit_a.wire == nullptr) {
+ bit_d = bit_b;
+ sr_val = bit_a;
+ sr_sig = module->NotGate(NEW_ID, bit_s);
+ } else {
+ log_assert(bit_b.wire == nullptr);
+ bit_d = bit_a;
+ sr_val = bit_b;
+ sr_sig = bit_s;
+ }
+
+ if (sr_val == State::S1) {
+ cell->type = cell->type.str() + "SS";
+ cell->setPort("\\S", sr_sig);
+ cell->setPort("\\D", bit_d);
+ } else {
+ cell->type = cell->type.str() + "SR";
+ cell->setPort("\\R", sr_sig);
+ cell->setPort("\\D", bit_d);
+ }
+ }
+ }
+ }
+} Ice40FfssrPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/ice40/ice40_opt.cc b/techlibs/ice40/ice40_opt.cc
new file mode 100644
index 000000000..ae72f5d64
--- /dev/null
+++ b/techlibs/ice40/ice40_opt.cc
@@ -0,0 +1,193 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "passes/techmap/simplemap.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+static void run_ice40_opts(Module *module, bool unlut_mode)
+{
+ pool<SigBit> optimized_co;
+ vector<Cell*> sb_lut_cells;
+ SigMap sigmap(module);
+
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type == "\\SB_LUT4")
+ {
+ sb_lut_cells.push_back(cell);
+ continue;
+ }
+
+ if (cell->type == "\\SB_CARRY")
+ {
+ SigSpec non_const_inputs, replacement_output;
+ int count_zeros = 0, count_ones = 0;
+
+ SigBit inbit[3] = {cell->getPort("\\I0"), cell->getPort("\\I1"), cell->getPort("\\CI")};
+ for (int i = 0; i < 3; i++)
+ if (inbit[i].wire == nullptr) {
+ if (inbit[i] == State::S1)
+ count_ones++;
+ else
+ count_zeros++;
+ } else
+ non_const_inputs.append(inbit[i]);
+
+ if (count_zeros >= 2)
+ replacement_output = State::S0;
+ else if (count_ones >= 2)
+ replacement_output = State::S1;
+ else if (GetSize(non_const_inputs) == 1)
+ replacement_output = non_const_inputs;
+
+ if (GetSize(replacement_output)) {
+ optimized_co.insert(sigmap(cell->getPort("\\CO")));
+ module->connect(cell->getPort("\\CO"), replacement_output);
+ module->design->scratchpad_set_bool("opt.did_something", true);
+ log("Optimized away SB_CARRY cell %s.%s: CO=%s\n",
+ log_id(module), log_id(cell), log_signal(replacement_output));
+ module->remove(cell);
+ }
+ continue;
+ }
+ }
+
+ for (auto cell : sb_lut_cells)
+ {
+ SigSpec inbits;
+
+ inbits.append(cell->getPort("\\I0"));
+ inbits.append(cell->getPort("\\I1"));
+ inbits.append(cell->getPort("\\I2"));
+ inbits.append(cell->getPort("\\I3"));
+ sigmap.apply(inbits);
+
+ if (unlut_mode)
+ goto remap_lut;
+
+ if (optimized_co.count(inbits[0])) goto remap_lut;
+ if (optimized_co.count(inbits[1])) goto remap_lut;
+ if (optimized_co.count(inbits[2])) goto remap_lut;
+ if (optimized_co.count(inbits[3])) goto remap_lut;
+
+ if (!sigmap(inbits).is_fully_const())
+ continue;
+
+ remap_lut:
+ module->design->scratchpad_set_bool("opt.did_something", true);
+ log("Mapping SB_LUT4 cell %s.%s back to logic.\n", log_id(module), log_id(cell));
+
+ cell->type ="$lut";
+ cell->setParam("\\WIDTH", 4);
+ cell->setParam("\\LUT", cell->getParam("\\LUT_INIT"));
+ cell->unsetParam("\\LUT_INIT");
+
+ cell->setPort("\\A", SigSpec({cell->getPort("\\I3"), cell->getPort("\\I2"), cell->getPort("\\I1"), cell->getPort("\\I0")}));
+ cell->setPort("\\Y", cell->getPort("\\O"));
+ cell->unsetPort("\\I0");
+ cell->unsetPort("\\I1");
+ cell->unsetPort("\\I2");
+ cell->unsetPort("\\I3");
+ cell->unsetPort("\\O");
+
+ cell->check();
+ simplemap_lut(module, cell);
+ module->remove(cell);
+ }
+}
+
+struct Ice40OptPass : public Pass {
+ Ice40OptPass() : Pass("ice40_opt", "iCE40: perform simple optimizations") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" ice40_opt [options] [selection]\n");
+ log("\n");
+ log("This command executes the following script:\n");
+ log("\n");
+ log(" do\n");
+ log(" <ice40 specific optimizations>\n");
+ log(" opt_expr -mux_undef -undriven [-full]\n");
+ log(" opt_merge\n");
+ log(" opt_rmdff\n");
+ log(" opt_clean\n");
+ log(" while <changed design>\n");
+ log("\n");
+ log("When called with the option -unlut, this command will transform all already\n");
+ log("mapped SB_LUT4 cells back to logic.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ string opt_expr_args = "-mux_undef -undriven";
+ bool unlut_mode = false;
+
+ log_header(design, "Executing ICE40_OPT pass (performing simple optimizations).\n");
+ log_push();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-full") {
+ opt_expr_args += " -full";
+ continue;
+ }
+ if (args[argidx] == "-unlut") {
+ unlut_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ while (1)
+ {
+ design->scratchpad_unset("opt.did_something");
+
+ log_header(design, "Running ICE40 specific optimizations.\n");
+ for (auto module : design->selected_modules())
+ run_ice40_opts(module, unlut_mode);
+
+ Pass::call(design, "opt_expr " + opt_expr_args);
+ Pass::call(design, "opt_merge");
+ Pass::call(design, "opt_rmdff");
+ Pass::call(design, "opt_clean");
+
+ if (design->scratchpad_get_bool("opt.did_something") == false)
+ break;
+
+ log_header(design, "Rerunning OPT passes. (Removed registers in this run.)\n");
+ }
+
+ design->optimize();
+ design->sort();
+ design->check();
+
+ log_header(design, "Finished OPT passes. (There is nothing left to do.)\n");
+ log_pop();
+ }
+} Ice40OptPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/ice40/latches_map.v b/techlibs/ice40/latches_map.v
new file mode 100644
index 000000000..c28f88cf7
--- /dev/null
+++ b/techlibs/ice40/latches_map.v
@@ -0,0 +1,11 @@
+module \$_DLATCH_N_ (E, D, Q);
+ wire [1023:0] _TECHMAP_DO_ = "simplemap; opt";
+ input E, D;
+ output Q = !E ? D : Q;
+endmodule
+
+module \$_DLATCH_P_ (E, D, Q);
+ wire [1023:0] _TECHMAP_DO_ = "simplemap; opt";
+ input E, D;
+ output Q = E ? D : Q;
+endmodule
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc
new file mode 100644
index 000000000..38a9cf9d6
--- /dev/null
+++ b/techlibs/ice40/synth_ice40.cc
@@ -0,0 +1,250 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct SynthIce40Pass : public ScriptPass
+{
+ SynthIce40Pass() : ScriptPass("synth_ice40", "synthesis for iCE40 FPGAs") { }
+
+ virtual void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth_ice40 [options]\n");
+ log("\n");
+ log("This command runs synthesis for iCE40 FPGAs. This work is experimental.\n");
+ log("\n");
+ log(" -top <module>\n");
+ log(" use the specified module as top module (default='top')\n");
+ log("\n");
+ log(" -blif <file>\n");
+ log(" write the design to the specified BLIF file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -edif <file>\n");
+ log(" write the design to the specified edif file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -run <from_label>:<to_label>\n");
+ log(" only run the commands between the labels (see below). an empty\n");
+ 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(" -noflatten\n");
+ log(" do not flatten design before synthesis\n");
+ log("\n");
+ log(" -retime\n");
+ log(" run 'abc' with -dff option\n");
+ log("\n");
+ log(" -nocarry\n");
+ log(" do not use SB_CARRY cells in output netlist\n");
+ log("\n");
+ log(" -nobram\n");
+ log(" do not use SB_RAM40_4K* cells in output netlist\n");
+ log("\n");
+ log(" -abc2\n");
+ log(" run two passes of 'abc' for slightly improved logic density\n");
+ log("\n");
+ log("\n");
+ log("The following commands are executed by this synthesis command:\n");
+ help_script();
+ log("\n");
+ }
+
+ string top_opt, blif_file, edif_file;
+ bool nocarry, nobram, flatten, retime, abc2;
+
+ virtual void clear_flags() YS_OVERRIDE
+ {
+ top_opt = "-auto-top";
+ blif_file = "";
+ edif_file = "";
+ nocarry = false;
+ nobram = false;
+ flatten = true;
+ retime = false;
+ abc2 = false;
+ }
+
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ string run_from, run_to;
+ clear_flags();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-top" && argidx+1 < args.size()) {
+ top_opt = "-top " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-blif" && argidx+1 < args.size()) {
+ blif_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-edif" && argidx+1 < args.size()) {
+ edif_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-run" && argidx+1 < args.size()) {
+ size_t pos = args[argidx+1].find(':');
+ if (pos == std::string::npos)
+ break;
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos+1);
+ continue;
+ }
+ if (args[argidx] == "-flatten") {
+ flatten = true;
+ continue;
+ }
+ if (args[argidx] == "-noflatten") {
+ flatten = false;
+ continue;
+ }
+ if (args[argidx] == "-retime") {
+ retime = true;
+ continue;
+ }
+ if (args[argidx] == "-nocarry") {
+ nocarry = true;
+ continue;
+ }
+ if (args[argidx] == "-nobram") {
+ nobram = true;
+ continue;
+ }
+ if (args[argidx] == "-abc2") {
+ abc2 = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!design->full_selection())
+ log_cmd_error("This comannd only operates on fully selected designs!\n");
+
+ log_header(design, "Executing SYNTH_ICE40 pass.\n");
+ log_push();
+
+ run_script(design, run_from, run_to);
+
+ log_pop();
+ }
+
+ virtual void script() YS_OVERRIDE
+ {
+ if (check_label("begin"))
+ {
+ run("read_verilog -lib +/ice40/cells_sim.v");
+ run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
+ }
+
+ if (flatten && check_label("flatten", "(unless -noflatten)"))
+ {
+ run("proc");
+ run("flatten");
+ run("tribuf -logic");
+ run("deminout");
+ }
+
+ if (check_label("coarse"))
+ {
+ run("synth -run coarse");
+ }
+
+ if (!nobram && check_label("bram", "(skip if -nobram)"))
+ {
+ run("memory_bram -rules +/ice40/brams.txt");
+ run("techmap -map +/ice40/brams_map.v");
+ }
+
+ if (check_label("fine"))
+ {
+ run("opt -fast -mux_undef -undriven -fine");
+ run("memory_map");
+ run("opt -undriven -fine");
+ if (nocarry)
+ run("techmap");
+ else
+ run("techmap -map +/techmap.v -map +/ice40/arith_map.v");
+ if (retime || help_mode)
+ run("abc -dff", "(only if -retime)");
+ run("ice40_opt");
+ }
+
+ if (check_label("map_ffs"))
+ {
+ run("dffsr2dff");
+ run("dff2dffe -direct-match $_DFF_*");
+ run("techmap -map +/ice40/cells_map.v");
+ run("opt_expr -mux_undef");
+ run("simplemap");
+ run("ice40_ffinit");
+ run("ice40_ffssr");
+ run("ice40_opt -full");
+ }
+
+ if (check_label("map_luts"))
+ {
+ if (abc2 || help_mode) {
+ run("abc", " (only if -abc2)");
+ run("ice40_opt", "(only if -abc2)");
+ }
+ run("techmap -map +/ice40/latches_map.v");
+ run("abc -lut 4");
+ run("clean");
+ }
+
+ if (check_label("map_cells"))
+ {
+ run("techmap -map +/ice40/cells_map.v");
+ run("clean");
+ }
+
+ if (check_label("check"))
+ {
+ run("hierarchy -check");
+ run("stat");
+ run("check -noinit");
+ }
+
+ if (check_label("blif"))
+ {
+ if (!blif_file.empty() || help_mode)
+ run(stringf("write_blif -gates -attr -param %s", help_mode ? "<file-name>" : blif_file.c_str()));
+ }
+
+ if (check_label("edif"))
+ {
+ if (!edif_file.empty() || help_mode)
+ run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str()));
+ }
+ }
+} SynthIce40Pass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/ice40/tests/.gitignore b/techlibs/ice40/tests/.gitignore
new file mode 100644
index 000000000..b58f9ad4a
--- /dev/null
+++ b/techlibs/ice40/tests/.gitignore
@@ -0,0 +1,2 @@
+test_ffs_[01][01][01][01][01]_*
+test_bram_[0-9]*
diff --git a/techlibs/ice40/tests/test_arith.v b/techlibs/ice40/tests/test_arith.v
new file mode 100644
index 000000000..77f79b973
--- /dev/null
+++ b/techlibs/ice40/tests/test_arith.v
@@ -0,0 +1,3 @@
+module test(input [4:0] a, b, c, output [4:0] y);
+ assign y = ((a+b) ^ (a-c)) - ((a*b) + (a*c) - (b*c));
+endmodule
diff --git a/techlibs/ice40/tests/test_arith.ys b/techlibs/ice40/tests/test_arith.ys
new file mode 100644
index 000000000..160c767fb
--- /dev/null
+++ b/techlibs/ice40/tests/test_arith.ys
@@ -0,0 +1,10 @@
+read_verilog test_arith.v
+synth_ice40
+techmap -map ../cells_sim.v
+rename test gate
+
+read_verilog test_arith.v
+rename test gold
+
+miter -equiv -flatten -make_outputs gold gate miter
+sat -verify -prove trigger 0 -show-ports miter
diff --git a/techlibs/ice40/tests/test_bram.sh b/techlibs/ice40/tests/test_bram.sh
new file mode 100644
index 000000000..d4d641a9c
--- /dev/null
+++ b/techlibs/ice40/tests/test_bram.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -ex
+
+for abits in 7 8 9 10 11 12; do
+for dbits in 2 4 8 16 24 32; do
+ id="test_bram_${abits}_${dbits}"
+ iadr=$((RANDOM % (1 << abits)))
+ idat=$((RANDOM % ((1 << dbits) - 1) + 1))
+ sed -re "s/(ABITS = )0/\1$abits/g; s/(DBITS = )0/\1$dbits/g; s/(INIT_ADDR = )0/\1$iadr/g; s/(INIT_DATA = )0/\1$idat/g;" < test_bram.v > ${id}.v
+ sed -re "s/(ABITS = )0/\1$abits/g; s/(DBITS = )0/\1$dbits/g; s/(INIT_ADDR = )0/\1$iadr/g; s/(INIT_DATA = )0/\1$idat/g;" < test_bram_tb.v > ${id}_tb.v
+ ../../../yosys -ql ${id}_syn.log -p "synth_ice40" -o ${id}_syn.v ${id}.v
+ # iverilog -s bram_tb -o ${id}_tb ${id}_syn.v ${id}_tb.v /opt/lscc/iCEcube2.2014.08/verilog/sb_ice_syn.v
+ iverilog -s bram_tb -o ${id}_tb ${id}_syn.v ${id}_tb.v ../cells_sim.v
+ ./${id}_tb > ${id}_tb.txt
+ if grep -H ERROR ${id}_tb.txt; then false; fi
+done; done
+echo OK
+
diff --git a/techlibs/ice40/tests/test_bram.v b/techlibs/ice40/tests/test_bram.v
new file mode 100644
index 000000000..320735d07
--- /dev/null
+++ b/techlibs/ice40/tests/test_bram.v
@@ -0,0 +1,24 @@
+module bram #(
+ parameter ABITS = 8, DBITS = 8,
+ parameter INIT_ADDR = 0, INIT_DATA = 0
+) (
+ input clk,
+
+ input [ABITS-1:0] WR_ADDR,
+ input [DBITS-1:0] WR_DATA,
+ input WR_EN,
+
+ input [ABITS-1:0] RD_ADDR,
+ output reg [DBITS-1:0] RD_DATA
+);
+ reg [DBITS-1:0] memory [0:2**ABITS-1];
+
+ initial begin
+ memory[INIT_ADDR] <= INIT_DATA;
+ end
+
+ always @(posedge clk) begin
+ if (WR_EN) memory[WR_ADDR] <= WR_DATA;
+ RD_DATA <= memory[RD_ADDR];
+ end
+endmodule
diff --git a/techlibs/ice40/tests/test_bram_tb.v b/techlibs/ice40/tests/test_bram_tb.v
new file mode 100644
index 000000000..bdb8d4560
--- /dev/null
+++ b/techlibs/ice40/tests/test_bram_tb.v
@@ -0,0 +1,110 @@
+module bram_tb #(
+ parameter ABITS = 8, DBITS = 8,
+ parameter INIT_ADDR = 0, INIT_DATA = 0
+);
+ reg clk;
+ reg [ABITS-1:0] WR_ADDR;
+ reg [DBITS-1:0] WR_DATA;
+ reg WR_EN;
+ reg [ABITS-1:0] RD_ADDR;
+ wire [DBITS-1:0] RD_DATA;
+
+ bram uut (
+ .clk (clk ),
+ .WR_ADDR(WR_ADDR),
+ .WR_DATA(WR_DATA),
+ .WR_EN (WR_EN ),
+ .RD_ADDR(RD_ADDR),
+ .RD_DATA(RD_DATA)
+ );
+
+ reg [63:0] xorshift64_state = 64'd88172645463325252 ^ (ABITS << 24) ^ (DBITS << 16);
+
+ task xorshift64_next;
+ begin
+ // see page 4 of Marsaglia, George (July 2003). "Xorshift RNGs". Journal of Statistical Software 8 (14).
+ xorshift64_state = xorshift64_state ^ (xorshift64_state << 13);
+ xorshift64_state = xorshift64_state ^ (xorshift64_state >> 7);
+ xorshift64_state = xorshift64_state ^ (xorshift64_state << 17);
+ end
+ endtask
+
+ reg [ABITS-1:0] randaddr1;
+ reg [ABITS-1:0] randaddr2;
+ reg [ABITS-1:0] randaddr3;
+
+ function [31:0] getaddr(input [3:0] n);
+ begin
+ case (n)
+ 0: getaddr = 0;
+ 1: getaddr = 2**ABITS-1;
+ 2: getaddr = 'b101 << (ABITS / 3);
+ 3: getaddr = 'b101 << (2*ABITS / 3);
+ 4: getaddr = 'b11011 << (ABITS / 4);
+ 5: getaddr = 'b11011 << (2*ABITS / 4);
+ 6: getaddr = 'b11011 << (3*ABITS / 4);
+ 7: getaddr = randaddr1;
+ 8: getaddr = randaddr2;
+ 9: getaddr = randaddr3;
+ default: begin
+ getaddr = 1 << (2*n-16);
+ if (!getaddr) getaddr = xorshift64_state;
+ end
+ endcase
+ end
+ endfunction
+
+ reg [DBITS-1:0] memory [0:2**ABITS-1];
+ reg [DBITS-1:0] expected_rd, expected_rd_masked;
+
+ event error;
+ integer i, j;
+
+ initial begin
+ // $dumpfile("testbench.vcd");
+ // $dumpvars(0, bram_tb);
+
+ memory[INIT_ADDR] <= INIT_DATA;
+
+ xorshift64_next;
+ xorshift64_next;
+ xorshift64_next;
+ xorshift64_next;
+
+ randaddr1 = xorshift64_state;
+ xorshift64_next;
+
+ randaddr2 = xorshift64_state;
+ xorshift64_next;
+
+ randaddr3 = xorshift64_state;
+ xorshift64_next;
+
+ clk <= 0;
+ for (i = 0; i < 512; i = i+1) begin
+ WR_DATA = xorshift64_state;
+ xorshift64_next;
+
+ WR_ADDR = getaddr(i < 256 ? i[7:4] : xorshift64_state[63:60]);
+ xorshift64_next;
+
+ RD_ADDR = i == 0 ? INIT_ADDR : getaddr(i < 256 ? i[3:0] : xorshift64_state[59:56]);
+ WR_EN = xorshift64_state[55] && ((WR_ADDR & 'hff) != (RD_ADDR & 'hff));
+ xorshift64_next;
+
+ #1; clk <= 1;
+ #1; clk <= 0;
+
+ expected_rd = memory[RD_ADDR];
+ if (WR_EN) memory[WR_ADDR] = WR_DATA;
+
+ for (j = 0; j < DBITS; j = j+1)
+ expected_rd_masked[j] = expected_rd[j] !== 1'bx ? expected_rd[j] : RD_DATA[j];
+
+ $display("#OUT# %3d | WA=%x WD=%x WE=%x | RA=%x RD=%x (%x) | %s",
+ i, WR_ADDR, WR_DATA, WR_EN, RD_ADDR, RD_DATA, expected_rd,
+ expected_rd_masked === RD_DATA ? "ok" : "ERROR");
+ if (expected_rd_masked !== RD_DATA) begin -> error; end
+ end
+ end
+endmodule
diff --git a/techlibs/ice40/tests/test_ffs.sh b/techlibs/ice40/tests/test_ffs.sh
new file mode 100644
index 000000000..ff79ec534
--- /dev/null
+++ b/techlibs/ice40/tests/test_ffs.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+set -ex
+for CLKPOL in 0 1; do
+for ENABLE_EN in 0 1; do
+for RESET_EN in 0 1; do
+for RESET_VAL in 0 1; do
+for RESET_SYN in 0 1; do
+ pf="test_ffs_${CLKPOL}${ENABLE_EN}${RESET_EN}${RESET_VAL}${RESET_SYN}"
+ sed -e "s/CLKPOL = 0/CLKPOL = ${CLKPOL}/;" -e "s/ENABLE_EN = 0/ENABLE_EN = ${ENABLE_EN}/;" \
+ -e "s/RESET_EN = 0/RESET_EN = ${RESET_EN}/;" -e "s/RESET_VAL = 0/RESET_VAL = ${RESET_VAL}/;" \
+ -e "s/RESET_SYN = 0/RESET_SYN = ${RESET_SYN}/;" test_ffs.v > ${pf}_gold.v
+ ../../../yosys -o ${pf}_gate.v -p "synth_ice40" ${pf}_gold.v
+ ../../../yosys -p "proc; opt; test_autotb ${pf}_tb.v" ${pf}_gold.v
+ iverilog -s testbench -o ${pf}_gold ${pf}_gold.v ${pf}_tb.v
+ iverilog -s testbench -o ${pf}_gate ${pf}_gate.v ${pf}_tb.v ../cells_sim.v
+ ./${pf}_gold > ${pf}_gold.txt
+ ./${pf}_gate > ${pf}_gate.txt
+ cmp ${pf}_gold.txt ${pf}_gate.txt
+done; done; done; done; done
+echo OK.
diff --git a/techlibs/ice40/tests/test_ffs.v b/techlibs/ice40/tests/test_ffs.v
new file mode 100644
index 000000000..1f6883f3c
--- /dev/null
+++ b/techlibs/ice40/tests/test_ffs.v
@@ -0,0 +1,42 @@
+module test(D, C, E, R, Q);
+ parameter [0:0] CLKPOL = 0;
+ parameter [0:0] ENABLE_EN = 0;
+ parameter [0:0] RESET_EN = 0;
+ parameter [0:0] RESET_VAL = 0;
+ parameter [0:0] RESET_SYN = 0;
+
+ (* gentb_clock *)
+ input D, C, E, R;
+
+ output Q;
+
+ wire gated_reset = R & RESET_EN;
+ wire gated_enable = E | ~ENABLE_EN;
+ reg posedge_q, negedge_q, posedge_sq, negedge_sq;
+
+ always @(posedge C, posedge gated_reset)
+ if (gated_reset)
+ posedge_q <= RESET_VAL;
+ else if (gated_enable)
+ posedge_q <= D;
+
+ always @(negedge C, posedge gated_reset)
+ if (gated_reset)
+ negedge_q <= RESET_VAL;
+ else if (gated_enable)
+ negedge_q <= D;
+
+ always @(posedge C)
+ if (gated_reset)
+ posedge_sq <= RESET_VAL;
+ else if (gated_enable)
+ posedge_sq <= D;
+
+ always @(negedge C)
+ if (gated_reset)
+ negedge_sq <= RESET_VAL;
+ else if (gated_enable)
+ negedge_sq <= D;
+
+ assign Q = RESET_SYN ? (CLKPOL ? posedge_sq : negedge_sq) : (CLKPOL ? posedge_q : negedge_q);
+endmodule