diff options
Diffstat (limited to 'techlibs/ice40')
-rw-r--r-- | techlibs/ice40/.gitignore | 4 | ||||
-rw-r--r-- | techlibs/ice40/Makefile.inc | 33 | ||||
-rw-r--r-- | techlibs/ice40/arith_map.v | 70 | ||||
-rw-r--r-- | techlibs/ice40/brams.txt | 40 | ||||
-rw-r--r-- | techlibs/ice40/brams_init.py | 14 | ||||
-rw-r--r-- | techlibs/ice40/brams_map.v | 311 | ||||
-rw-r--r-- | techlibs/ice40/cells_map.v | 57 | ||||
-rw-r--r-- | techlibs/ice40/cells_sim.v | 883 | ||||
-rw-r--r-- | techlibs/ice40/ice40_ffinit.cc | 167 | ||||
-rw-r--r-- | techlibs/ice40/ice40_ffssr.cc | 123 | ||||
-rw-r--r-- | techlibs/ice40/ice40_opt.cc | 193 | ||||
-rw-r--r-- | techlibs/ice40/latches_map.v | 11 | ||||
-rw-r--r-- | techlibs/ice40/synth_ice40.cc | 250 | ||||
-rw-r--r-- | techlibs/ice40/tests/.gitignore | 2 | ||||
-rw-r--r-- | techlibs/ice40/tests/test_arith.v | 3 | ||||
-rw-r--r-- | techlibs/ice40/tests/test_arith.ys | 10 | ||||
-rw-r--r-- | techlibs/ice40/tests/test_bram.sh | 19 | ||||
-rw-r--r-- | techlibs/ice40/tests/test_bram.v | 24 | ||||
-rw-r--r-- | techlibs/ice40/tests/test_bram_tb.v | 110 | ||||
-rw-r--r-- | techlibs/ice40/tests/test_ffs.sh | 20 | ||||
-rw-r--r-- | techlibs/ice40/tests/test_ffs.v | 42 |
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 |