added tests for spram, dpram & fifo macros
diff --git a/ql-qlf-plugin/tests/Makefile b/ql-qlf-plugin/tests/Makefile
index 661e92e..cd1c7e1 100644
--- a/ql-qlf-plugin/tests/Makefile
+++ b/ql-qlf-plugin/tests/Makefile
@@ -37,26 +37,39 @@
# qlf_k6n10_bram \
SIM_TESTS = \
- qlf_k6n10f/sim_dsp_mult_cfg_ports \
- qlf_k6n10f/sim_dsp_mult_cfg_params \
- qlf_k6n10f/sim_dsp_mult_r_cfg_ports \
- qlf_k6n10f/sim_dsp_mult_r_cfg_params \
- qlf_k6n10f/sim_dsp_fir_cfg_ports \
- qlf_k6n10f/sim_dsp_fir_cfg_params \
- qlf_k6n10f/sim_dsp_simd_cfg_ports \
- qlf_k6n10f/sim_dsp_simd_cfg_params \
- qlf_k6n10f/sim_tc36fifo
+ qlf_k6n10f/sim_dsp_mult_cfg_ports \
+ qlf_k6n10f/sim_dsp_mult_cfg_ports \
+ qlf_k6n10f/sim_dsp_mult_cfg_params \
+ qlf_k6n10f/sim_dsp_mult_r_cfg_ports \
+ qlf_k6n10f/sim_dsp_mult_r_cfg_params \
+ qlf_k6n10f/sim_dsp_fir_cfg_ports \
+ qlf_k6n10f/sim_dsp_fir_cfg_params \
+ qlf_k6n10f/sim_dsp_simd_cfg_ports \
+ qlf_k6n10f/sim_dsp_simd_cfg_params \
+ qlf_k6n10f/sim_tc36fifo
# Those tests perform synthesis and simulation of synthesis results
POST_SYNTH_SIM_TESTS = \
- qlf_k6n10f/bram_tdp \
- qlf_k6n10f/bram_sdp \
- qlf_k6n10f/bram_tdp_split \
- qlf_k6n10f/bram_sdp_split \
- qlf_k6n10f/dsp_mult_post_synth_sim \
- qlf_k6n10f/dsp_simd_post_synth_sim \
- qlf_k6n10f/bram_asymmetric_wider_write \
- qlf_k6n10f/bram_asymmetric_wider_read
+ qlf_k6n10f/asymmetric_bram36k_sfifo \
+ qlf_k6n10f/asymmetric_bram36k_afifo \
+ qlf_k6n10f/bram36k_sfifo \
+ qlf_k6n10f/bram36k_afifo \
+ qlf_k6n10f/bram18k_afifo \
+ qlf_k6n10f/bram18k_sfifo \
+ qlf_k6n10f/bram18k_tdp \
+ qlf_k6n10f/bram36k_tdp \
+ qlf_k6n10f/bram18k_sdp \
+ qlf_k6n10f/bram36k_sdp \
+ qlf_k6n10f/asymmetric_bram36k_sdp \
+ qlf_k6n10f/asymmetric_bram18k_sdp \
+ qlf_k6n10f/bram_tdp \
+ qlf_k6n10f/bram_sdp \
+ qlf_k6n10f/bram_tdp_split \
+ qlf_k6n10f/bram_sdp_split \
+ qlf_k6n10f/dsp_mult_post_synth_sim \
+ qlf_k6n10f/dsp_simd_post_synth_sim \
+ qlf_k6n10f/bram_asymmetric_wider_write \
+ qlf_k6n10f/bram_asymmetric_wider_read
include $(shell pwd)/../../Makefile_test.common
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram18k_sdp/asymmetric_bram18k_sdp.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram18k_sdp/asymmetric_bram18k_sdp.tcl
new file mode 100644
index 0000000..0579462
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram18k_sdp/asymmetric_bram18k_sdp.tcl
@@ -0,0 +1,27 @@
+yosys -import
+
+if { [info procs ql-qlf-k6n10f] == {} } { plugin -i ql-qlf }
+yosys -import ;
+
+read_verilog $::env(DESIGN_TOP).v
+design -save asymmetric_bram18k_sdp
+
+select spram_9x2048_18x1024
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_9x2048_18x1024 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_9x2048_18x1024_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X9_RD_X18_split
+
+select -clear
+design -load asymmetric_bram18k_sdp
+select spram_18x1024_9x2048
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_18x1024_9x2048 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_18x1024_9x2048_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X18_RD_X9_split
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram18k_sdp/asymmetric_bram18k_sdp.v b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram18k_sdp/asymmetric_bram18k_sdp.v
new file mode 100644
index 0000000..272696b
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram18k_sdp/asymmetric_bram18k_sdp.v
@@ -0,0 +1,93 @@
+module spram_9x2048_18x1024 (
+ WEN_i,
+ REN_i,
+ clock0,
+ clock1,
+ WR_ADDR_i,
+ RD_ADDR_i,
+ WDATA_i,
+ RDATA_o
+);
+
+parameter WR_ADDR_WIDTH = 11;
+parameter RD_ADDR_WIDTH = 10;
+parameter WR_DATA_WIDTH = 9;
+parameter RD_DATA_WIDTH = 18;
+parameter BE_WIDTH = 1;
+
+input wire WEN_i;
+input wire REN_i;
+input wire clock0;
+input wire clock1;
+input wire [WR_ADDR_WIDTH-1 :0] WR_ADDR_i;
+input wire [RD_ADDR_WIDTH-1 :0] RD_ADDR_i;
+input wire [WR_DATA_WIDTH-1 :0] WDATA_i;
+output wire [RD_DATA_WIDTH-1 :0] RDATA_o;
+
+RAM_18K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH),
+ .BE_WIDTH(BE_WIDTH)
+ ) spram_x18_inst (
+
+ .WEN_i(WEN_i),
+ .WR_BE_i(1'b1),
+ .REN_i(REN_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR_i),
+ .RD_ADDR_i(RD_ADDR_i),
+ .WDATA_i(WDATA_i),
+ .RDATA_o(RDATA_o)
+ );
+
+endmodule
+
+module spram_18x1024_9x2048 (
+ WEN_i,
+ REN_i,
+ clock0,
+ clock1,
+ WR_ADDR_i,
+ RD_ADDR_i,
+ WDATA_i,
+ RDATA_o
+);
+
+parameter WR_ADDR_WIDTH = 10;
+parameter RD_ADDR_WIDTH = 11;
+parameter WR_DATA_WIDTH = 18;
+parameter RD_DATA_WIDTH = 9;
+parameter BE_WIDTH = 2;
+
+input wire WEN_i;
+input wire REN_i;
+input wire clock0;
+input wire clock1;
+input wire [WR_ADDR_WIDTH-1 :0] WR_ADDR_i;
+input wire [RD_ADDR_WIDTH-1 :0] RD_ADDR_i;
+input wire [WR_DATA_WIDTH-1 :0] WDATA_i;
+output wire [RD_DATA_WIDTH-1 :0] RDATA_o;
+
+RAM_18K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH),
+ .BE_WIDTH(BE_WIDTH)
+ ) spram_x18_inst (
+
+ .WEN_i(WEN_i),
+ .WR_BE_i(2'b11),
+ .REN_i(REN_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR_i),
+ .RD_ADDR_i(RD_ADDR_i),
+ .WDATA_i(WDATA_i),
+ .RDATA_o(RDATA_o)
+ );
+
+endmodule
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram18k_sdp/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram18k_sdp/sim/Makefile
new file mode 100644
index 0000000..3c8c84a
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram18k_sdp/sim/Makefile
@@ -0,0 +1,39 @@
+# Copyright (C) 2019-2022 The SymbiFlow Authors
+#
+# Use of this source code is governed by a ISC-style
+# license that can be found in the LICENSE file or at
+# https://opensource.org/licenses/ISC
+#
+# SPDX-License-Identifier: ISC
+
+TESTBENCH = asymmetric_bram18k_sdp_tb.v
+POST_SYNTH = spram_9x2048_18x1024_post_synth spram_18x1024_9x2048_post_synth
+ADDR_WIDTH0 = 11 10
+DATA_WIDTH0 = 9 18
+ADDR_WIDTH1 = 10 11
+DATA_WIDTH1 = 18 9
+TOP = spram_9x2048_18x1024 spram_18x1024_9x2048
+ADDR0_DEFINES = $(foreach awidth0, $(ADDR_WIDTH0),-DADDR_WIDTH0="$(awidth0)")
+ADDR1_DEFINES = $(foreach awidth1, $(ADDR_WIDTH1),-DADDR_WIDTH1="$(awidth1)")
+DATA0_DEFINES = $(foreach dwidth0, $(DATA_WIDTH0),-DDATA_WIDTH0="$(dwidth0)")
+DATA1_DEFINES = $(foreach dwidth1, $(DATA_WIDTH1),-DDATA_WIDTH1="$(dwidth1)")
+TOP_DEFINES = $(foreach top, $(TOP),-DTOP="$(top)")
+VCD_DEFINES = $(foreach vcd, $(POST_SYNTH),-DVCD="$(vcd).vcd")
+
+SIM_LIBS = $(shell find ../../../../qlf_k6n10f -name "*.v" -not -name "*_map.v")
+
+define simulate_post_synth
+ @iverilog -vvvv -g2005 $(word $(1),$(ADDR0_DEFINES)) $(word $(1),$(ADDR1_DEFINES)) $(word $(1),$(DATA0_DEFINES)) $(word $(1),$(DATA1_DEFINES)) $(word $(1),$(TOP_DEFINES)) $(word $(1),$(VCD_DEFINES)) -o $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).v $(SIM_LIBS) $(TESTBENCH) > $(word $(1),$(POST_SYNTH)).vvp.log 2>&1
+ @vvp -vvvv $(word $(1),$(POST_SYNTH)).vvp > $(word $(1),$(POST_SYNTH)).vcd.log 2>&1
+endef
+
+define clean_post_synth_sim
+ @rm -rf $(word $(1),$(POST_SYNTH)).vcd $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).vvp.log $(word $(1),$(POST_SYNTH)).vcd.log
+endef
+
+#FIXME: $(call simulate_post_synth,3)
+sim:
+ $(call simulate_post_synth,1)
+ $(call clean_post_synth_sim,1)
+ $(call simulate_post_synth,2)
+ $(call clean_post_synth_sim,2)
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram18k_sdp/sim/asymmetric_bram18k_sdp_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram18k_sdp/sim/asymmetric_bram18k_sdp_tb.v
new file mode 100644
index 0000000..86abcec
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram18k_sdp/sim/asymmetric_bram18k_sdp_tb.v
@@ -0,0 +1,170 @@
+// Copyright (C) 2019-2022 The SymbiFlow Authors
+//
+// Use of this source code is governed by a ISC-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/ISC
+//
+// SPDX-License-Identifier: ISC
+
+`timescale 1ns/1ps
+
+`define STRINGIFY(x) `"x`"
+
+module TB;
+ localparam PERIOD = 50;
+ localparam ADDR_INCR = 1;
+
+ reg clk_0;
+ reg clk_1;
+ reg rce;
+ reg [`ADDR_WIDTH1-1:0] ra;
+ wire [`DATA_WIDTH1-1:0] rq;
+ reg wce;
+ reg [`ADDR_WIDTH0-1:0] wa;
+ reg [`DATA_WIDTH0-1:0] wd;
+
+ initial clk_0 = 0;
+ initial clk_1 = 0;
+ initial ra = 0;
+ initial wa = 0;
+ initial wd = 0;
+ initial rce = 0;
+ initial wce = 0;
+ initial forever #(PERIOD / 2.0) clk_0 = ~clk_0;
+ //initial forever #(PERIOD / 2.0) clk_1 = ~clk_1;
+ initial begin
+ #(PERIOD / 4.0);
+ forever #(PERIOD / 2.0) clk_1 = ~clk_1;
+ end
+ initial begin
+ $dumpfile(`STRINGIFY(`VCD));
+ $dumpvars;
+ end
+
+ integer a;
+ integer b;
+
+ reg done_0;
+ initial done_0 = 1'b0;
+ wire done_sim = done_0;
+
+ reg [`DATA_WIDTH1-1:0] expected_0;
+
+ reg read_test_0;
+ initial read_test_0 = 0;
+
+
+ wire error_0 = (read_test_0) ? (rq !== expected_0) : 0;
+
+ integer error_0_cnt = 0;
+
+ always @ (posedge clk_1)
+ begin
+ if (error_0)
+ error_0_cnt <= error_0_cnt + 1'b1;
+ end
+
+case (`STRINGIFY(`TOP))
+"spram_9x2048_18x1024": begin
+ initial #(1) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk_0) begin
+ wa = a[`ADDR_WIDTH0-1:0];
+ wd = a[9:1];
+ wce = 1;
+ end
+ @(posedge clk_0) begin
+ #(PERIOD/10) wce = 0;
+ end
+ end
+ // Read data
+ read_test_0 = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(negedge clk_1) begin
+ ra = a;
+ rce = 1;
+ end
+ @(posedge clk_1) begin
+ expected_0 <= {a[8],a[8],a[7:0],a[7:0]};
+ #(PERIOD/10) rce = 0;
+ if ( rq !== expected_0) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, rq, expected_0, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, rq, expected_0, a);
+ end
+ end
+ end
+ done_0 = 1'b1;
+ a = 0;
+ end
+end
+"spram_18x1024_9x2048": begin
+ initial #(1) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk_0) begin
+ wa = a[`ADDR_WIDTH0-1:0];
+ wd = {a[8],a[8],a[7:0],a[7:0]};
+ wce = 1;
+ end
+ @(posedge clk_0) begin
+ #(PERIOD/10) wce = 0;
+ end
+ end
+ // Read data
+ read_test_0 = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(negedge clk_1) begin
+ ra = a;
+ rce = 1;
+ end
+ @(posedge clk_1) begin
+ expected_0 <= {a[9:1]};
+ #(PERIOD/10) rce = 0;
+ if ( rq !== expected_0) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, rq, expected_0, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, rq, expected_0, a);
+ end
+ end
+ end
+ done_0 = 1'b1;
+ a = 0;
+ end
+end
+endcase
+
+ // Scan for simulation finish
+ always @(posedge clk_1) begin
+ if (done_sim)
+ $finish_and_return( (error_0_cnt == 0) ? 0 : -1 );
+ end
+
+ case (`STRINGIFY(`TOP))
+ "spram_9x2048_18x1024": begin
+ spram_9x2048_18x1024 #() bram (
+ .clock0(clk_0),
+ .clock1(clk_1),
+ .REN_i(rce),
+ .RD_ADDR_i(ra),
+ .RDATA_o(rq),
+ .WEN_i(wce),
+ .WR_ADDR_i(wa),
+ .WDATA_i(wd)
+ );
+ end
+ "spram_18x1024_9x2048": begin
+ spram_18x1024_9x2048 #() bram (
+ .clock0(clk_0),
+ .clock1(clk_1),
+ .REN_i(rce),
+ .RD_ADDR_i(ra),
+ .RDATA_o(rq),
+ .WEN_i(wce),
+ .WR_ADDR_i(wa),
+ .WDATA_i(wd)
+ );
+ end
+ endcase
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_afifo/asymmetric_bram36k_afifo.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_afifo/asymmetric_bram36k_afifo.tcl
new file mode 100644
index 0000000..66e2686
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_afifo/asymmetric_bram36k_afifo.tcl
@@ -0,0 +1,49 @@
+yosys -import
+
+if { [info procs ql-qlf-k6n10f] == {} } { plugin -i ql-qlf }
+yosys -import ;
+
+read_verilog $::env(DESIGN_TOP).v
+design -save asymmetric_bram36k_afifo
+
+select af4096x9_1024x36
+select *
+synth_quicklogic -family qlf_k6n10f -top af4096x9_1024x36 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/af4096x9_1024x36_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_ASYNC_WR_X9_RD_X36_nonsplit
+
+select -clear
+design -load asymmetric_bram36k_afifo
+select af2048x18_1024x36
+select *
+synth_quicklogic -family qlf_k6n10f -top af2048x18_1024x36 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/af2048x18_1024x36_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_ASYNC_WR_X18_RD_X36_nonsplit
+
+select -clear
+design -load asymmetric_bram36k_afifo
+select af2048x18_4098x9
+select *
+synth_quicklogic -family qlf_k6n10f -top af2048x18_4098x9 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/af2048x18_4098x9_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_ASYNC_WR_X18_RD_X9_nonsplit
+
+select -clear
+design -load asymmetric_bram36k_afifo
+select af1024x36_4098x9
+select *
+synth_quicklogic -family qlf_k6n10f -top af1024x36_4098x9 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/af1024x36_4098x9_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_ASYNC_WR_X36_RD_X9_nonsplit
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_afifo/asymmetric_bram36k_afifo.v b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_afifo/asymmetric_bram36k_afifo.v
new file mode 100644
index 0000000..81ceaa8
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_afifo/asymmetric_bram36k_afifo.v
@@ -0,0 +1,168 @@
+module af4096x9_1024x36 (DIN,PUSH,POP,clock0,clock1,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 9;
+parameter RD_DATA_WIDTH = 36;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0,clock1;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+
+AFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .Push_Clk(clock0),
+ .Pop_Clk(clock1),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module af2048x18_1024x36 (DIN,PUSH,POP,clock0,clock1,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 18;
+parameter RD_DATA_WIDTH = 36;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0,clock1;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+AFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .Push_Clk(clock0),
+ .Pop_Clk(clock1),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module af2048x18_4098x9 (DIN,PUSH,POP,clock0,clock1,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 18;
+parameter RD_DATA_WIDTH = 9;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0,clock1;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+AFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .Push_Clk(clock0),
+ .Pop_Clk(clock1),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module af1024x36_4098x9 (DIN,PUSH,POP,clock0,clock1,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 36;
+parameter RD_DATA_WIDTH = 9;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0,clock1;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+AFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .Push_Clk(clock0),
+ .Pop_Clk(clock1),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_afifo/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_afifo/sim/Makefile
new file mode 100644
index 0000000..e3bd2bd
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_afifo/sim/Makefile
@@ -0,0 +1,43 @@
+# Copyright (C) 2019-2022 The SymbiFlow Authors
+#
+# Use of this source code is governed by a ISC-style
+# license that can be found in the LICENSE file or at
+# https://opensource.org/licenses/ISC
+#
+# SPDX-License-Identifier: ISC
+
+TESTBENCH = asymmetric_bram36k_afifo_tb.v
+POST_SYNTH = af4096x9_1024x36_post_synth af2048x18_1024x36_post_synth af2048x18_4098x9_post_synth af1024x36_4098x9_post_synth
+ADDR_WIDTH0 = 12 11 11 10
+DATA_WIDTH0 = 9 18 18 36
+ADDR_WIDTH1 = 10 10 12 12
+DATA_WIDTH1 = 36 36 9 9
+TOP = af4096x9_1024x36 af2048x18_1024x36 af2048x18_4098x9 af1024x36_4098x9
+ADDR0_DEFINES = $(foreach awidth0, $(ADDR_WIDTH0),-DADDR_WIDTH0="$(awidth0)")
+ADDR1_DEFINES = $(foreach awidth1, $(ADDR_WIDTH1),-DADDR_WIDTH1="$(awidth1)")
+DATA0_DEFINES = $(foreach dwidth0, $(DATA_WIDTH0),-DDATA_WIDTH0="$(dwidth0)")
+DATA1_DEFINES = $(foreach dwidth1, $(DATA_WIDTH1),-DDATA_WIDTH1="$(dwidth1)")
+TOP_DEFINES = $(foreach top, $(TOP),-DTOP="$(top)")
+VCD_DEFINES = $(foreach vcd, $(POST_SYNTH),-DVCD="$(vcd).vcd")
+
+SIM_LIBS = $(shell find ../../../../qlf_k6n10f -name "*.v" -not -name "*_map.v")
+
+define simulate_post_synth
+ @iverilog -vvvv -g2005 $(word $(1),$(ADDR0_DEFINES)) $(word $(1),$(ADDR1_DEFINES)) $(word $(1),$(DATA0_DEFINES)) $(word $(1),$(DATA1_DEFINES)) $(word $(1),$(TOP_DEFINES)) $(word $(1),$(VCD_DEFINES)) -o $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).v $(SIM_LIBS) $(TESTBENCH) > $(word $(1),$(POST_SYNTH)).vvp.log 2>&1
+ @vvp -vvvv $(word $(1),$(POST_SYNTH)).vvp > $(word $(1),$(POST_SYNTH)).vcd.log 2>&1
+endef
+
+define clean_post_synth_sim
+ @rm -rf $(word $(1),$(POST_SYNTH)).vcd $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).vvp.log $(word $(1),$(POST_SYNTH)).vcd.log
+endef
+
+#FIXME: $(call simulate_post_synth,3)
+sim:
+ $(call simulate_post_synth,1)
+ $(call clean_post_synth_sim,1)
+ $(call simulate_post_synth,2)
+ $(call clean_post_synth_sim,2)
+ $(call simulate_post_synth,3)
+ $(call clean_post_synth_sim,3)
+ $(call simulate_post_synth,4)
+ $(call clean_post_synth_sim,4)
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_afifo/sim/asymmetric_bram36k_afifo_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_afifo/sim/asymmetric_bram36k_afifo_tb.v
new file mode 100644
index 0000000..17ac3c0
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_afifo/sim/asymmetric_bram36k_afifo_tb.v
@@ -0,0 +1,284 @@
+// Copyright (C) 2019-2022 The SymbiFlow Authors
+//
+// Use of this source code is governed by a ISC-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/ISC
+//
+// SPDX-License-Identifier: ISC
+
+`timescale 1ns/1ps
+
+`define STRINGIFY(x) `"x`"
+
+module TB;
+ localparam PERIOD = 30;
+ localparam ADDR_INCR = 1;
+
+ reg clk0;
+ reg clk1;
+ reg flush;
+ reg pop;
+ wire [`DATA_WIDTH1-1:0] dout;
+ reg push;
+ reg [`DATA_WIDTH0-1:0] din;
+ wire almost_full,almost_empty;
+ wire full, empty;
+ wire full_watermark, empty_watermark;
+ wire overrun_error, underrun_error;
+
+ initial
+ begin
+ clk0 = 0;
+ clk1 = 0;
+ pop = 0;
+ push = 0;
+ flush = 1;
+ din = 0;
+ #40
+ flush = 0;
+ end
+
+ initial forever #(PERIOD / 3.0) clk0 = ~clk0;
+ initial forever #(PERIOD / 2.0) clk1 = ~clk1;
+
+ initial begin
+ $dumpfile(`STRINGIFY(`VCD));
+ $dumpvars;
+ end
+
+ integer a;
+
+ reg done;
+ initial done = 1'b0;
+
+ reg read_test;
+ initial read_test = 0;
+
+ reg [`DATA_WIDTH1-1:0] expected;
+ initial expected = 0;
+
+ wire error = (read_test) ? dout !== expected : 0;
+
+ integer error_cnt = 0;
+ always @ (posedge clk1)
+ begin
+ if (error)
+ error_cnt <= error_cnt + 1'b1;
+ end
+
+case (`STRINGIFY(`TOP))
+"af4096x9_1024x36": begin
+ initial #(50) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk0) begin
+ din = a[10:2];
+ push = 1;
+ end
+ @(posedge clk0) begin
+ #(PERIOD/10) push = 0;
+ end
+ end
+ // Read data
+ read_test = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(posedge clk1) begin
+ expected <= {a[8],a[8],a[7:0],a[7:0],a[8],a[8],a[7:0],a[7:0]};
+ #(PERIOD/10) pop = 0;
+ if ( dout !== expected) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, dout, expected, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, dout, expected, a);
+ end
+ end
+ @(negedge clk1) begin
+ pop = 1;
+ end
+ end
+ done = 1'b1;
+ a = 0;
+ end
+end
+"af2048x18_1024x36": begin
+ initial #(50) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk0) begin
+ din = a[18:1];
+ push = 1;
+ end
+ @(posedge clk0) begin
+ #(PERIOD/10) push = 0;
+ end
+ end
+ // Read data
+ read_test = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(posedge clk1) begin
+ expected <= {a[17:0],a[17:0]};
+ #(PERIOD/10) pop = 0;
+ if ( dout !== expected) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, dout, expected, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, dout, expected, a);
+ end
+ end
+ @(negedge clk1) begin
+ pop = 1;
+ end
+ end
+ done = 1'b1;
+ a = 0;
+ end
+end
+"af2048x18_4098x9": begin
+ initial #(50) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk0) begin
+ din = {a[8],a[8],a[7:0],a[7:0]};
+ push = 1;
+ end
+ @(posedge clk0) begin
+ #(PERIOD/10) push = 0;
+ end
+ end
+ // Read data
+ read_test = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(posedge clk1) begin
+ expected <= {a[9:1]};
+ #(PERIOD/10) pop = 0;
+ if ( dout !== expected) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, dout, expected, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, dout, expected, a);
+ end
+ end
+ @(negedge clk1) begin
+ pop = 1;
+ end
+ end
+ done = 1'b1;
+ a = 0;
+ end
+end
+"af1024x36_4098x9": begin
+ initial #(50) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk0) begin
+ din = {a[8],a[8],a[7:0],a[7:0],a[8],a[8],a[7:0],a[7:0]};
+ push = 1;
+ end
+ @(posedge clk0) begin
+ #(PERIOD/10) push = 0;
+ end
+ end
+ // Read data
+ read_test = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(posedge clk1) begin
+ expected <= {a[10:2]};
+ #(PERIOD/10) pop = 0;
+ if ( dout !== expected) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, dout, expected, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, dout, expected, a);
+ end
+ end
+ @(negedge clk1) begin
+ pop = 1;
+ end
+ end
+ done = 1'b1;
+ a = 0;
+ end
+end
+endcase
+
+ // Scan for simulation finish
+ always @(posedge clk1) begin
+ if (done)
+ $finish_and_return( (error_cnt == 0) ? 0 : -1 );
+ end
+
+ case (`STRINGIFY(`TOP))
+ "af4096x9_1024x36": begin
+ af4096x9_1024x36 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .clock1(clk1),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "af2048x18_1024x36": begin
+ af2048x18_1024x36 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .clock1(clk1),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "af2048x18_4098x9": begin
+ af2048x18_4098x9 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .clock1(clk1),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "af1024x36_4098x9": begin
+ af1024x36_4098x9 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .clock1(clk1),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ endcase
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sdp/asymmetric_bram36k_sdp.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sdp/asymmetric_bram36k_sdp.tcl
new file mode 100644
index 0000000..827914a
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sdp/asymmetric_bram36k_sdp.tcl
@@ -0,0 +1,49 @@
+yosys -import
+
+if { [info procs ql-qlf-k6n10f] == {} } { plugin -i ql-qlf }
+yosys -import ;
+
+read_verilog $::env(DESIGN_TOP).v
+design -save asymmetric_bram36k_sdp
+
+select spram_9x4096_36x1024
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_9x4096_36x1024 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_9x4096_36x1024_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X9_RD_X36_nonsplit
+
+select -clear
+design -load asymmetric_bram36k_sdp
+select spram_18x2048_36x1024
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_18x2048_36x1024 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_18x2048_36x1024_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X18_RD_X36_nonsplit
+
+select -clear
+design -load asymmetric_bram36k_sdp
+select spram_18x2048_9x4096
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_18x2048_9x4096 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_18x2048_9x4096_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X18_RD_X9_nonsplit
+
+select -clear
+design -load asymmetric_bram36k_sdp
+select spram_36x1024_18x2048
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_36x1024_18x2048 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_36x1024_18x2048_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X36_RD_X18_nonsplit
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sdp/asymmetric_bram36k_sdp.v b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sdp/asymmetric_bram36k_sdp.v
new file mode 100644
index 0000000..e964b23
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sdp/asymmetric_bram36k_sdp.v
@@ -0,0 +1,187 @@
+module spram_9x4096_36x1024 (
+ WEN_i,
+ REN_i,
+ clock0,
+ clock1,
+ WR_ADDR_i,
+ RD_ADDR_i,
+ WDATA_i,
+ RDATA_o
+);
+
+parameter WR_ADDR_WIDTH = 12;
+parameter RD_ADDR_WIDTH = 10;
+parameter WR_DATA_WIDTH = 9;
+parameter RD_DATA_WIDTH = 36;
+parameter BE_WIDTH = 1;
+
+input wire WEN_i;
+input wire REN_i;
+input wire clock0;
+input wire clock1;
+input wire [WR_ADDR_WIDTH-1 :0] WR_ADDR_i;
+input wire [RD_ADDR_WIDTH-1 :0] RD_ADDR_i;
+input wire [WR_DATA_WIDTH-1 :0] WDATA_i;
+output wire [RD_DATA_WIDTH-1 :0] RDATA_o;
+
+RAM_36K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH),
+ .BE_WIDTH(BE_WIDTH)
+ ) spram_x36_inst (
+
+ .WEN_i(WEN_i),
+ .WR_BE_i(1'b1),
+ .REN_i(REN_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR_i),
+ .RD_ADDR_i(RD_ADDR_i),
+ .WDATA_i(WDATA_i),
+ .RDATA_o(RDATA_o)
+ );
+
+endmodule
+
+module spram_18x2048_36x1024 (
+ WEN_i,
+ REN_i,
+ clock0,
+ clock1,
+ WR_ADDR_i,
+ RD_ADDR_i,
+ WDATA_i,
+ RDATA_o
+);
+
+parameter WR_ADDR_WIDTH = 11;
+parameter RD_ADDR_WIDTH = 10;
+parameter WR_DATA_WIDTH = 18;
+parameter RD_DATA_WIDTH = 36;
+parameter BE_WIDTH = 2;
+
+input wire WEN_i;
+input wire REN_i;
+input wire clock0;
+input wire clock1;
+input wire [WR_ADDR_WIDTH-1 :0] WR_ADDR_i;
+input wire [RD_ADDR_WIDTH-1 :0] RD_ADDR_i;
+input wire [WR_DATA_WIDTH-1 :0] WDATA_i;
+output wire [RD_DATA_WIDTH-1 :0] RDATA_o;
+
+RAM_36K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH),
+ .BE_WIDTH(BE_WIDTH)
+ ) spram_x36_inst (
+
+ .WEN_i(WEN_i),
+ .WR_BE_i(2'b11),
+ .REN_i(REN_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR_i),
+ .RD_ADDR_i(RD_ADDR_i),
+ .WDATA_i(WDATA_i),
+ .RDATA_o(RDATA_o)
+ );
+
+endmodule
+
+module spram_18x2048_9x4096 (
+ WEN_i,
+ REN_i,
+ clock0,
+ clock1,
+ WR_ADDR_i,
+ RD_ADDR_i,
+ WDATA_i,
+ RDATA_o
+);
+
+parameter WR_ADDR_WIDTH = 11;
+parameter RD_ADDR_WIDTH = 12;
+parameter WR_DATA_WIDTH = 18;
+parameter RD_DATA_WIDTH = 9;
+parameter BE_WIDTH = 2;
+
+input wire WEN_i;
+input wire REN_i;
+input wire clock0;
+input wire clock1;
+input wire [WR_ADDR_WIDTH-1 :0] WR_ADDR_i;
+input wire [RD_ADDR_WIDTH-1 :0] RD_ADDR_i;
+input wire [WR_DATA_WIDTH-1 :0] WDATA_i;
+output wire [RD_DATA_WIDTH-1 :0] RDATA_o;
+
+RAM_36K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH),
+ .BE_WIDTH(BE_WIDTH)
+ ) spram_x36_inst (
+
+ .WEN_i(WEN_i),
+ .WR_BE_i(2'b11),
+ .REN_i(REN_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR_i),
+ .RD_ADDR_i(RD_ADDR_i),
+ .WDATA_i(WDATA_i),
+ .RDATA_o(RDATA_o)
+ );
+
+endmodule
+
+module spram_36x1024_18x2048 (
+ WEN_i,
+ REN_i,
+ clock0,
+ clock1,
+ WR_ADDR_i,
+ RD_ADDR_i,
+ WDATA_i,
+ RDATA_o
+);
+
+parameter WR_ADDR_WIDTH = 10;
+parameter RD_ADDR_WIDTH = 11;
+parameter WR_DATA_WIDTH = 36;
+parameter RD_DATA_WIDTH = 18;
+parameter BE_WIDTH = 4;
+
+input wire WEN_i;
+input wire REN_i;
+input wire clock0;
+input wire clock1;
+input wire [WR_ADDR_WIDTH-1 :0] WR_ADDR_i;
+input wire [RD_ADDR_WIDTH-1 :0] RD_ADDR_i;
+input wire [WR_DATA_WIDTH-1 :0] WDATA_i;
+output wire [RD_DATA_WIDTH-1 :0] RDATA_o;
+
+RAM_36K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH),
+ .BE_WIDTH(BE_WIDTH)
+ ) spram_x36_inst (
+
+ .WEN_i(WEN_i),
+ .WR_BE_i(4'b1111),
+ .REN_i(REN_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR_i),
+ .RD_ADDR_i(RD_ADDR_i),
+ .WDATA_i(WDATA_i),
+ .RDATA_o(RDATA_o)
+ );
+
+endmodule
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sdp/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sdp/sim/Makefile
new file mode 100644
index 0000000..fc7c0e9
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sdp/sim/Makefile
@@ -0,0 +1,43 @@
+# Copyright (C) 2019-2022 The SymbiFlow Authors
+#
+# Use of this source code is governed by a ISC-style
+# license that can be found in the LICENSE file or at
+# https://opensource.org/licenses/ISC
+#
+# SPDX-License-Identifier: ISC
+
+TESTBENCH = asymmetric_bram36k_sdp_tb.v
+POST_SYNTH = spram_9x4096_36x1024_post_synth spram_18x2048_36x1024_post_synth spram_18x2048_9x4096_post_synth spram_36x1024_18x2048_post_synth
+ADDR_WIDTH0 = 12 11 11 10
+DATA_WIDTH0 = 9 18 18 36
+ADDR_WIDTH1 = 10 10 12 11
+DATA_WIDTH1 = 36 36 9 18
+TOP = spram_9x4096_36x1024 spram_18x2048_36x1024 spram_18x2048_9x4096 spram_36x1024_18x2048
+ADDR0_DEFINES = $(foreach awidth0, $(ADDR_WIDTH0),-DADDR_WIDTH0="$(awidth0)")
+ADDR1_DEFINES = $(foreach awidth1, $(ADDR_WIDTH1),-DADDR_WIDTH1="$(awidth1)")
+DATA0_DEFINES = $(foreach dwidth0, $(DATA_WIDTH0),-DDATA_WIDTH0="$(dwidth0)")
+DATA1_DEFINES = $(foreach dwidth1, $(DATA_WIDTH1),-DDATA_WIDTH1="$(dwidth1)")
+TOP_DEFINES = $(foreach top, $(TOP),-DTOP="$(top)")
+VCD_DEFINES = $(foreach vcd, $(POST_SYNTH),-DVCD="$(vcd).vcd")
+
+SIM_LIBS = $(shell find ../../../../qlf_k6n10f -name "*.v" -not -name "*_map.v")
+
+define simulate_post_synth
+ @iverilog -vvvv -g2005 $(word $(1),$(ADDR0_DEFINES)) $(word $(1),$(ADDR1_DEFINES)) $(word $(1),$(DATA0_DEFINES)) $(word $(1),$(DATA1_DEFINES)) $(word $(1),$(TOP_DEFINES)) $(word $(1),$(VCD_DEFINES)) -o $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).v $(SIM_LIBS) $(TESTBENCH) > $(word $(1),$(POST_SYNTH)).vvp.log 2>&1
+ @vvp -vvvv $(word $(1),$(POST_SYNTH)).vvp > $(word $(1),$(POST_SYNTH)).vcd.log 2>&1
+endef
+
+define clean_post_synth_sim
+ @rm -rf $(word $(1),$(POST_SYNTH)).vcd $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).vvp.log $(word $(1),$(POST_SYNTH)).vcd.log
+endef
+
+#FIXME: $(call simulate_post_synth,3)
+sim:
+ $(call simulate_post_synth,1)
+ $(call clean_post_synth_sim,1)
+ $(call simulate_post_synth,2)
+ $(call clean_post_synth_sim,2)
+ $(call simulate_post_synth,3)
+ $(call clean_post_synth_sim,3)
+ $(call simulate_post_synth,4)
+ $(call clean_post_synth_sim,4)
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sdp/sim/asymmetric_bram36k_sdp_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sdp/sim/asymmetric_bram36k_sdp_tb.v
new file mode 100644
index 0000000..87cab86
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sdp/sim/asymmetric_bram36k_sdp_tb.v
@@ -0,0 +1,262 @@
+// Copyright (C) 2019-2022 The SymbiFlow Authors
+//
+// Use of this source code is governed by a ISC-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/ISC
+//
+// SPDX-License-Identifier: ISC
+
+`timescale 1ns/1ps
+
+`define STRINGIFY(x) `"x`"
+
+module TB;
+ localparam PERIOD = 50;
+ localparam ADDR_INCR = 1;
+
+ reg clk_0;
+ reg clk_1;
+ reg rce;
+ reg [`ADDR_WIDTH1-1:0] ra;
+ wire [`DATA_WIDTH1-1:0] rq;
+ reg wce;
+ reg [`ADDR_WIDTH0-1:0] wa;
+ reg [`DATA_WIDTH0-1:0] wd;
+
+ initial clk_0 = 0;
+ initial clk_1 = 0;
+ initial ra = 0;
+ initial wa = 0;
+ initial wd = 0;
+ initial rce = 0;
+ initial wce = 0;
+ initial forever #(PERIOD / 2.0) clk_0 = ~clk_0;
+ //initial forever #(PERIOD / 2.0) clk_1 = ~clk_1;
+ initial begin
+ #(PERIOD / 4.0);
+ forever #(PERIOD / 2.0) clk_1 = ~clk_1;
+ end
+ initial begin
+ $dumpfile(`STRINGIFY(`VCD));
+ $dumpvars;
+ end
+
+ integer a;
+ integer b;
+
+ reg done_0;
+ initial done_0 = 1'b0;
+ wire done_sim = done_0;
+
+ reg [`DATA_WIDTH1-1:0] expected_0;
+
+ reg read_test_0;
+ initial read_test_0 = 0;
+
+
+ wire error_0 = (read_test_0) ? (rq !== expected_0) : 0;
+
+ integer error_0_cnt = 0;
+
+ always @ (posedge clk_1)
+ begin
+ if (error_0)
+ error_0_cnt <= error_0_cnt + 1'b1;
+ end
+
+case (`STRINGIFY(`TOP))
+"spram_9x4096_36x1024": begin
+ initial #(1) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk_0) begin
+ wa = a[`ADDR_WIDTH0-1:0];
+ wd = a[10:2];
+ wce = 1;
+ end
+ @(posedge clk_0) begin
+ #(PERIOD/10) wce = 0;
+ end
+ end
+ // Read data
+ read_test_0 = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(negedge clk_1) begin
+ ra = a;
+ rce = 1;
+ end
+ @(posedge clk_1) begin
+ expected_0 <= {a[8],a[8],a[7:0],a[7:0],a[8],a[8],a[7:0],a[7:0]};
+ #(PERIOD/10) rce = 0;
+ if ( rq !== expected_0) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, rq, expected_0, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, rq, expected_0, a);
+ end
+ end
+ end
+ done_0 = 1'b1;
+ a = 0;
+ end
+end
+"spram_18x2048_36x1024": begin
+ initial #(1) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk_0) begin
+ wa = a[`ADDR_WIDTH0-1:0];
+ wd = a[18:1];
+ wce = 1;
+ end
+ @(posedge clk_0) begin
+ #(PERIOD/10) wce = 0;
+ end
+ end
+ // Read data
+ read_test_0 = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(negedge clk_1) begin
+ ra = a;
+ rce = 1;
+ end
+ @(posedge clk_1) begin
+ expected_0 <= {a[17:0],a[17:0]};
+ #(PERIOD/10) rce = 0;
+ if ( rq !== expected_0) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, rq, expected_0, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, rq, expected_0, a);
+ end
+ end
+ end
+ done_0 = 1'b1;
+ a = 0;
+ end
+end
+"spram_18x2048_9x4096": begin
+ initial #(1) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk_0) begin
+ wa = a[`ADDR_WIDTH0-1:0];
+ wd = {a[8],a[8],a[7:0],a[7:0]};
+ wce = 1;
+ end
+ @(posedge clk_0) begin
+ #(PERIOD/10) wce = 0;
+ end
+ end
+ // Read data
+ read_test_0 = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(negedge clk_1) begin
+ ra = a;
+ rce = 1;
+ end
+ @(posedge clk_1) begin
+ expected_0 <= {a[9:1]};
+ #(PERIOD/10) rce = 0;
+ if ( rq !== expected_0) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, rq, expected_0, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, rq, expected_0, a);
+ end
+ end
+ end
+ done_0 = 1'b1;
+ a = 0;
+ end
+end
+"spram_36x1024_18x2048": begin
+ initial #(1) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk_0) begin
+ wa = a[`ADDR_WIDTH0-1:0];
+ wd = {a[17:0],a[17:0]};
+ wce = 1;
+ end
+ @(posedge clk_0) begin
+ #(PERIOD/10) wce = 0;
+ end
+ end
+ // Read data
+ read_test_0 = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(negedge clk_1) begin
+ ra = a;
+ rce = 1;
+ end
+ @(posedge clk_1) begin
+ expected_0 <= {a[18:1]};
+ #(PERIOD/10) rce = 0;
+ if ( rq !== expected_0) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, rq, expected_0, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, rq, expected_0, a);
+ end
+ end
+ end
+ done_0 = 1'b1;
+ a = 0;
+ end
+end
+endcase
+
+ // Scan for simulation finish
+ always @(posedge clk_1) begin
+ if (done_sim)
+ $finish_and_return( (error_0_cnt == 0) ? 0 : -1 );
+ end
+
+ case (`STRINGIFY(`TOP))
+ "spram_9x4096_36x1024": begin
+ spram_9x4096_36x1024 #() bram (
+ .clock0(clk_0),
+ .clock1(clk_1),
+ .REN_i(rce),
+ .RD_ADDR_i(ra),
+ .RDATA_o(rq),
+ .WEN_i(wce),
+ .WR_ADDR_i(wa),
+ .WDATA_i(wd)
+ );
+ end
+ "spram_18x2048_36x1024": begin
+ spram_18x2048_36x1024 #() bram (
+ .clock0(clk_0),
+ .clock1(clk_1),
+ .REN_i(rce),
+ .RD_ADDR_i(ra),
+ .RDATA_o(rq),
+ .WEN_i(wce),
+ .WR_ADDR_i(wa),
+ .WDATA_i(wd)
+ );
+ end
+ "spram_18x2048_9x4096": begin
+ spram_18x2048_9x4096 #() bram (
+ .clock0(clk_0),
+ .clock1(clk_1),
+ .REN_i(rce),
+ .RD_ADDR_i(ra),
+ .RDATA_o(rq),
+ .WEN_i(wce),
+ .WR_ADDR_i(wa),
+ .WDATA_i(wd)
+ );
+ end
+ "spram_36x1024_18x2048": begin
+ spram_36x1024_18x2048 #() bram (
+ .clock0(clk_0),
+ .clock1(clk_1),
+ .REN_i(rce),
+ .RD_ADDR_i(ra),
+ .RDATA_o(rq),
+ .WEN_i(wce),
+ .WR_ADDR_i(wa),
+ .WDATA_i(wd)
+ );
+ end
+ endcase
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sfifo/asymmetric_bram36k_sfifo.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sfifo/asymmetric_bram36k_sfifo.tcl
new file mode 100644
index 0000000..4b24470
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sfifo/asymmetric_bram36k_sfifo.tcl
@@ -0,0 +1,49 @@
+yosys -import
+
+if { [info procs ql-qlf-k6n10f] == {} } { plugin -i ql-qlf }
+yosys -import ;
+
+read_verilog $::env(DESIGN_TOP).v
+design -save asymmetric_bram36k_sfifo
+
+select f4096x9_1024x36
+select *
+synth_quicklogic -family qlf_k6n10f -top f4096x9_1024x36 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/f4096x9_1024x36_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_SYNC_WR_X9_RD_X36_nonsplit
+
+select -clear
+design -load asymmetric_bram36k_sfifo
+select f2048x18_1024x36
+select *
+synth_quicklogic -family qlf_k6n10f -top f2048x18_1024x36 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/f2048x18_1024x36_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_SYNC_WR_X18_RD_X36_nonsplit
+
+select -clear
+design -load asymmetric_bram36k_sfifo
+select f2048x18_4098x9
+select *
+synth_quicklogic -family qlf_k6n10f -top f2048x18_4098x9 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/f2048x18_4098x9_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_SYNC_WR_X18_RD_X9_nonsplit
+
+select -clear
+design -load asymmetric_bram36k_sfifo
+select f1024x36_2048x18
+select *
+synth_quicklogic -family qlf_k6n10f -top f1024x36_2048x18 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/f1024x36_2048x18_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_SYNC_WR_X36_RD_X18_nonsplit
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sfifo/asymmetric_bram36k_sfifo.v b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sfifo/asymmetric_bram36k_sfifo.v
new file mode 100644
index 0000000..15274bb
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sfifo/asymmetric_bram36k_sfifo.v
@@ -0,0 +1,163 @@
+module f4096x9_1024x36 (DIN,PUSH,POP,clock0,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 9;
+parameter RD_DATA_WIDTH = 36;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+SFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .CLK(clock0),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module f2048x18_1024x36 (DIN,PUSH,POP,clock0,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 18;
+parameter RD_DATA_WIDTH = 36;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+SFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .CLK(clock0),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module f2048x18_4098x9 (DIN,PUSH,POP,clock0,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 18;
+parameter RD_DATA_WIDTH = 9;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+SFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .CLK(clock0),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module f1024x36_2048x18 (DIN,PUSH,POP,clock0,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 36;
+parameter RD_DATA_WIDTH = 18;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+SFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .CLK(clock0),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sfifo/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sfifo/sim/Makefile
new file mode 100644
index 0000000..71bef81
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sfifo/sim/Makefile
@@ -0,0 +1,43 @@
+# Copyright (C) 2019-2022 The SymbiFlow Authors
+#
+# Use of this source code is governed by a ISC-style
+# license that can be found in the LICENSE file or at
+# https://opensource.org/licenses/ISC
+#
+# SPDX-License-Identifier: ISC
+
+TESTBENCH = asymmetric_bram36k_sfifo_tb.v
+POST_SYNTH = f4096x9_1024x36_post_synth f2048x18_1024x36_post_synth f2048x18_4098x9_post_synth f1024x36_2048x18_post_synth
+ADDR_WIDTH0 = 12 11 11 10
+DATA_WIDTH0 = 9 18 18 36
+ADDR_WIDTH1 = 10 10 12 11
+DATA_WIDTH1 = 36 36 9 18
+TOP = f4096x9_1024x36 f2048x18_1024x36 f2048x18_4098x9 f1024x36_2048x18
+ADDR0_DEFINES = $(foreach awidth0, $(ADDR_WIDTH0),-DADDR_WIDTH0="$(awidth0)")
+ADDR1_DEFINES = $(foreach awidth1, $(ADDR_WIDTH1),-DADDR_WIDTH1="$(awidth1)")
+DATA0_DEFINES = $(foreach dwidth0, $(DATA_WIDTH0),-DDATA_WIDTH0="$(dwidth0)")
+DATA1_DEFINES = $(foreach dwidth1, $(DATA_WIDTH1),-DDATA_WIDTH1="$(dwidth1)")
+TOP_DEFINES = $(foreach top, $(TOP),-DTOP="$(top)")
+VCD_DEFINES = $(foreach vcd, $(POST_SYNTH),-DVCD="$(vcd).vcd")
+
+SIM_LIBS = $(shell find ../../../../qlf_k6n10f -name "*.v" -not -name "*_map.v")
+
+define simulate_post_synth
+ @iverilog -vvvv -g2005 $(word $(1),$(ADDR0_DEFINES)) $(word $(1),$(ADDR1_DEFINES)) $(word $(1),$(DATA0_DEFINES)) $(word $(1),$(DATA1_DEFINES)) $(word $(1),$(TOP_DEFINES)) $(word $(1),$(VCD_DEFINES)) -o $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).v $(SIM_LIBS) $(TESTBENCH) > $(word $(1),$(POST_SYNTH)).vvp.log 2>&1
+ @vvp -vvvv $(word $(1),$(POST_SYNTH)).vvp > $(word $(1),$(POST_SYNTH)).vcd.log 2>&1
+endef
+
+define clean_post_synth_sim
+ @rm -rf $(word $(1),$(POST_SYNTH)).vcd $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).vvp.log $(word $(1),$(POST_SYNTH)).vcd.log
+endef
+
+#FIXME: $(call simulate_post_synth,3)
+sim:
+ $(call simulate_post_synth,1)
+ $(call clean_post_synth_sim,1)
+ $(call simulate_post_synth,2)
+ $(call clean_post_synth_sim,2)
+ $(call simulate_post_synth,3)
+ $(call clean_post_synth_sim,3)
+ $(call simulate_post_synth,4)
+ $(call clean_post_synth_sim,4)
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sfifo/sim/asymmetric_bram36k_sfifo_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sfifo/sim/asymmetric_bram36k_sfifo_tb.v
new file mode 100644
index 0000000..d2fcbbd
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/asymmetric_bram36k_sfifo/sim/asymmetric_bram36k_sfifo_tb.v
@@ -0,0 +1,277 @@
+// Copyright (C) 2019-2022 The SymbiFlow Authors
+//
+// Use of this source code is governed by a ISC-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/ISC
+//
+// SPDX-License-Identifier: ISC
+
+`timescale 1ns/1ps
+
+`define STRINGIFY(x) `"x`"
+
+module TB;
+ localparam PERIOD = 30;
+ localparam ADDR_INCR = 1;
+
+ reg clk0;
+ reg flush;
+ reg pop;
+ wire [`DATA_WIDTH1-1:0] dout;
+ reg push;
+ reg [`DATA_WIDTH0-1:0] din;
+ wire almost_full,almost_empty;
+ wire full, empty;
+ wire full_watermark, empty_watermark;
+ wire overrun_error, underrun_error;
+
+ initial
+ begin
+ clk0 = 0;
+ pop = 0;
+ push = 0;
+ flush = 1;
+ din = 0;
+ #40
+ flush = 0;
+ end
+
+ initial forever #(PERIOD / 3.0) clk0 = ~clk0;
+
+ initial begin
+ $dumpfile(`STRINGIFY(`VCD));
+ $dumpvars;
+ end
+
+ integer a;
+
+ reg done;
+ initial done = 1'b0;
+
+ reg read_test;
+ initial read_test = 0;
+
+ reg [`DATA_WIDTH1-1:0] expected;
+ initial expected = 0;
+
+ wire error = (read_test) ? dout !== expected : 0;
+
+ integer error_cnt = 0;
+ always @ (posedge clk0)
+ begin
+ if (error)
+ error_cnt <= error_cnt + 1'b1;
+ end
+
+case (`STRINGIFY(`TOP))
+"f4096x9_1024x36": begin
+ initial #(50) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk0) begin
+ din = a[10:2];
+ push = 1;
+ end
+ @(posedge clk0) begin
+ #(PERIOD/10) push = 0;
+ end
+ end
+ // Read data
+ read_test = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(posedge clk0) begin
+ expected <= {a[8],a[8],a[7:0],a[7:0],a[8],a[8],a[7:0],a[7:0]};
+ #(PERIOD/10) pop = 0;
+ if ( dout !== expected) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, dout, expected, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, dout, expected, a);
+ end
+ end
+ @(negedge clk0) begin
+ pop = 1;
+ end
+ end
+ done = 1'b1;
+ a = 0;
+ end
+end
+"f2048x18_1024x36": begin
+ initial #(50) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk0) begin
+ din = a[18:1];
+ push = 1;
+ end
+ @(posedge clk0) begin
+ #(PERIOD/10) push = 0;
+ end
+ end
+ // Read data
+ read_test = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(posedge clk0) begin
+ expected <= {a[17:0],a[17:0]};
+ #(PERIOD/10) pop = 0;
+ if ( dout !== expected) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, dout, expected, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, dout, expected, a);
+ end
+ end
+ @(negedge clk0) begin
+ pop = 1;
+ end
+ end
+ done = 1'b1;
+ a = 0;
+ end
+end
+"f2048x18_4098x9": begin
+ initial #(50) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk0) begin
+ din = {a[8],a[8],a[7:0],a[7:0]};
+ push = 1;
+ end
+ @(posedge clk0) begin
+ #(PERIOD/10) push = 0;
+ end
+ end
+ // Read data
+ read_test = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(posedge clk0) begin
+ expected <= {a[9:1]};
+ #(PERIOD/10) pop = 0;
+ if ( dout !== expected) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, dout, expected, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, dout, expected, a);
+ end
+ end
+ @(negedge clk0) begin
+ pop = 1;
+ end
+ end
+ done = 1'b1;
+ a = 0;
+ end
+end
+"f1024x36_2048x18": begin
+ initial #(50) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) ; a = a + ADDR_INCR) begin
+ @(negedge clk0) begin
+ din = {a[17:0],a[17:0]};
+ push = 1;
+ end
+ @(posedge clk0) begin
+ #(PERIOD/10) push = 0;
+ end
+ end
+ // Read data
+ read_test = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(posedge clk0) begin
+ expected <= {a[18:1]};
+ #(PERIOD/10) pop = 0;
+ if ( dout !== expected) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, dout, expected, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, dout, expected, a);
+ end
+ end
+ @(negedge clk0) begin
+ pop = 1;
+ end
+ end
+ done = 1'b1;
+ a = 0;
+ end
+end
+endcase
+
+ // Scan for simulation finish
+ always @(posedge clk0) begin
+ if (done)
+ $finish_and_return( (error_cnt == 0) ? 0 : -1 );
+ end
+
+ case (`STRINGIFY(`TOP))
+ "f4096x9_1024x36": begin
+ f4096x9_1024x36 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "f2048x18_1024x36": begin
+ f2048x18_1024x36 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "f2048x18_4098x9": begin
+ f2048x18_4098x9 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "f1024x36_2048x18": begin
+ f1024x36_2048x18 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ endcase
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_afifo/bram18k_afifo.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_afifo/bram18k_afifo.tcl
new file mode 100644
index 0000000..99c7405
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_afifo/bram18k_afifo.tcl
@@ -0,0 +1,49 @@
+yosys -import
+
+if { [info procs ql-qlf-k6n10f] == {} } { plugin -i ql-qlf }
+yosys -import ;
+
+read_verilog $::env(DESIGN_TOP).v
+design -save bram18k_afifo
+
+select af1024x18_1024x18
+select *
+synth_quicklogic -family qlf_k6n10f -top af1024x18_1024x18 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/af1024x18_1024x18_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_ASYNC_WR_X18_RD_X18_split
+
+select -clear
+design -load bram18k_afifo
+select af1024x16_1024x16
+select *
+synth_quicklogic -family qlf_k6n10f -top af1024x16_1024x16 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/af1024x16_1024x16_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_ASYNC_WR_X18_RD_X18_split
+
+select -clear
+design -load bram18k_afifo
+select af2048x9_2048x9
+select *
+synth_quicklogic -family qlf_k6n10f -top af2048x9_2048x9 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/af2048x9_2048x9_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_ASYNC_WR_X9_RD_X9_split
+
+select -clear
+design -load bram18k_afifo
+select af2048x8_2048x8
+select *
+synth_quicklogic -family qlf_k6n10f -top af2048x8_2048x8 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/af2048x8_2048x8_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_ASYNC_WR_X9_RD_X9_split
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_afifo/bram18k_afifo.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_afifo/bram18k_afifo.v
new file mode 100644
index 0000000..69d4f32
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_afifo/bram18k_afifo.v
@@ -0,0 +1,167 @@
+module af1024x18_1024x18 (DIN,PUSH,POP,clock0,clock1,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 18;
+parameter RD_DATA_WIDTH = 18;
+parameter UPAE_DBITS = 11'd10;
+parameter UPAF_DBITS = 11'd10;
+
+input clock0,clock1;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+AFIFO_18K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .Push_Clk(clock0),
+ .Pop_Clk(clock1),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module af1024x16_1024x16 (DIN,PUSH,POP,clock0,clock1,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 16;
+parameter RD_DATA_WIDTH = 16;
+parameter UPAE_DBITS = 11'd10;
+parameter UPAF_DBITS = 11'd10;
+
+input clock0,clock1;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+AFIFO_18K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .Push_Clk(clock0),
+ .Pop_Clk(clock1),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module af2048x9_2048x9 (DIN,PUSH,POP,clock0,clock1,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 9;
+parameter RD_DATA_WIDTH = 9;
+parameter UPAE_DBITS = 11'd10;
+parameter UPAF_DBITS = 11'd10;
+
+input clock0,clock1;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+AFIFO_18K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .Push_Clk(clock0),
+ .Pop_Clk(clock1),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module af2048x8_2048x8 (DIN,PUSH,POP,clock0,clock1,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 8;
+parameter RD_DATA_WIDTH = 8;
+parameter UPAE_DBITS = 11'd10;
+parameter UPAF_DBITS = 11'd10;
+
+input clock0,clock1;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+AFIFO_18K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .Push_Clk(clock0),
+ .Pop_Clk(clock1),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_afifo/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_afifo/sim/Makefile
new file mode 100644
index 0000000..0153897
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_afifo/sim/Makefile
@@ -0,0 +1,51 @@
+# Copyright 2020-2022 F4PGA Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+TESTBENCH = bram18k_afifo_tb.v
+POST_SYNTH = af1024x18_1024x18_post_synth af1024x16_1024x16_post_synth af2048x9_2048x9_post_synth af2048x8_2048x8_post_synth
+ADDR_WIDTH0 = 10 10 11 11
+DATA_WIDTH0 = 18 16 9 8
+ADDR_WIDTH1 = 10 10 11 11
+DATA_WIDTH1 = 18 16 9 8
+TOP = af1024x18_1024x18 af1024x16_1024x16 af2048x9_2048x9 af2048x8_2048x8
+ADDR0_DEFINES = $(foreach awidth0, $(ADDR_WIDTH0),-DADDR_WIDTH0="$(awidth0)")
+ADDR1_DEFINES = $(foreach awidth1, $(ADDR_WIDTH1),-DADDR_WIDTH1="$(awidth1)")
+DATA0_DEFINES = $(foreach dwidth0, $(DATA_WIDTH0),-DDATA_WIDTH0="$(dwidth0)")
+DATA1_DEFINES = $(foreach dwidth1, $(DATA_WIDTH1),-DDATA_WIDTH1="$(dwidth1)")
+TOP_DEFINES = $(foreach top, $(TOP),-DTOP="$(top)")
+VCD_DEFINES = $(foreach vcd, $(POST_SYNTH),-DVCD="$(vcd).vcd")
+
+SIM_LIBS = $(shell find ../../../../qlf_k6n10f -name "*.v" -not -name "*_map.v")
+
+define simulate_post_synth
+ @iverilog -vvvv -g2005 $(word $(1),$(ADDR0_DEFINES)) $(word $(1),$(ADDR1_DEFINES)) $(word $(1),$(DATA0_DEFINES)) $(word $(1),$(DATA1_DEFINES)) $(word $(1),$(TOP_DEFINES)) $(word $(1),$(VCD_DEFINES)) -o $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).v $(SIM_LIBS) $(TESTBENCH) > $(word $(1),$(POST_SYNTH)).vvp.log 2>&1
+ @vvp -vvvv $(word $(1),$(POST_SYNTH)).vvp > $(word $(1),$(POST_SYNTH)).vcd.log 2>&1
+endef
+
+define clean_post_synth_sim
+ @rm -rf $(word $(1),$(POST_SYNTH)).vcd $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).vvp.log $(word $(1),$(POST_SYNTH)).vcd.log
+endef
+
+# FIXME: $(call simulate_post_synth,5)
+sim:
+ $(call simulate_post_synth,1)
+ $(call clean_post_synth_sim,1)
+ $(call simulate_post_synth,2)
+ $(call clean_post_synth_sim,2)
+ $(call simulate_post_synth,3)
+ $(call clean_post_synth_sim,3)
+ $(call simulate_post_synth,4)
+ $(call clean_post_synth_sim,4)
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_afifo/sim/bram18k_afifo_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_afifo/sim/bram18k_afifo_tb.v
new file mode 100644
index 0000000..62460b1
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_afifo/sim/bram18k_afifo_tb.v
@@ -0,0 +1,195 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+`timescale 1ns/1ps
+
+`define STRINGIFY(x) `"x`"
+
+module TB;
+ localparam PERIOD = 30;
+ localparam ADDR_INCR = 1;
+
+ reg clk0;
+ reg clk1;
+ reg flush;
+ reg pop;
+ wire [`DATA_WIDTH1-1:0] dout;
+ reg push;
+ reg [`DATA_WIDTH0-1:0] din;
+ wire almost_full,almost_empty;
+ wire full, empty;
+ wire full_watermark, empty_watermark;
+ wire overrun_error, underrun_error;
+
+ initial
+ begin
+ clk0 = 0;
+ clk1 = 0;
+ pop = 0;
+ push = 0;
+ flush = 1;
+ din = 0;
+ #40
+ flush = 0;
+ end
+
+ initial forever #(PERIOD / 3.0) clk0 = ~clk0;
+ initial forever #(PERIOD / 2.0) clk1 = ~clk1;
+
+ initial begin
+ $dumpfile(`STRINGIFY(`VCD));
+ $dumpvars;
+ end
+
+ integer a;
+
+ reg done;
+ initial done = 1'b0;
+
+ reg read_test;
+ initial read_test = 0;
+
+ reg [`DATA_WIDTH1-1:0] expected;
+ initial expected = 0;
+
+ always @(posedge clk1) begin
+ expected <= (a | (a << 20) | 20'h55000) & {`DATA_WIDTH1{1'b1}};
+ end
+
+ wire error = ((a != 0) && read_test) ? dout !== expected : 0;
+
+ integer error_cnt = 0;
+ always @ (posedge clk1)
+ begin
+ if (error)
+ error_cnt <= error_cnt + 1'b1;
+ end
+
+ initial #(50) begin
+ @(posedge clk0)
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0); a = a + ADDR_INCR) begin
+ @(negedge clk0) begin
+ din = a | (a << 20) | 20'h55000;
+ push = 1;
+ end
+ @(posedge clk0) begin
+ #(PERIOD/10) push = 0;
+ end
+ end
+ // Read data
+ read_test = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(posedge clk1) begin
+ #(PERIOD/10) pop = 0;
+ if ( dout !== expected) begin
+ $display("%d: FAIL: mismatch act=%x exp=%x at %x", $time, dout, expected, a);
+ end else begin
+ $display("%d: OK: act=%x exp=%x at %x", $time, dout, expected, a);
+ end
+ end
+ @(negedge clk1) begin
+ pop = 1;
+ end
+ end
+ done = 1'b1;
+ end
+
+ // Scan for simulation finish
+ always @(posedge clk1) begin
+ if (done)
+ $finish_and_return( (error_cnt == 0) ? 0 : -1 );
+ end
+
+ case (`STRINGIFY(`TOP))
+ "af1024x18_1024x18": begin
+ af1024x18_1024x18 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .clock1(clk1),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "af1024x16_1024x16": begin
+ af1024x16_1024x16 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .clock1(clk1),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "af2048x9_2048x9": begin
+ af2048x9_2048x9 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .clock1(clk1),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "af2048x8_2048x8": begin
+ af2048x8_2048x8 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .clock1(clk1),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ endcase
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sdp/bram18k_sdp.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sdp/bram18k_sdp.tcl
new file mode 100644
index 0000000..092d4c2
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sdp/bram18k_sdp.tcl
@@ -0,0 +1,39 @@
+yosys -import
+
+if { [info procs ql-qlf-k6n10f] == {} } { plugin -i ql-qlf }
+yosys -import ;
+
+read_verilog $::env(DESIGN_TOP).v
+design -save bram18k_sdp
+
+select spram_18x1024_2x
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_18x1024_2x -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_18x1024_2x_post_synth.v
+select -assert-count 2 t:TDP36K_BRAM_WR_X18_RD_X18_split
+
+select -clear
+design -load bram18k_sdp
+select spram_9x2048_x2
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_9x2048_x2 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_9x2048_x2_post_synth.v
+select -assert-count 2 t:TDP36K_BRAM_WR_X9_RD_X9_split
+
+select -clear
+design -load bram18k_sdp
+select spram_9x2048_18x1024
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_9x2048_18x1024 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_9x2048_18x1024_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X9_RD_X9_split
+select -assert-count 1 t:TDP36K_BRAM_WR_X18_RD_X18_split
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sdp/bram18k_sdp.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sdp/bram18k_sdp.v
new file mode 100644
index 0000000..e014d7f
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sdp/bram18k_sdp.v
@@ -0,0 +1,260 @@
+module spram_18x1024_2x (
+ WEN0_i,
+ REN0_i,
+ clock0,
+ WR_ADDR0_i,
+ RD_ADDR0_i,
+ WDATA0_i,
+ RDATA0_o,
+
+ WEN1_i,
+ REN1_i,
+ clock1,
+ WR_ADDR1_i,
+ RD_ADDR1_i,
+ WDATA1_i,
+ RDATA1_o
+);
+
+parameter WR_ADDR_WIDTH0 = 10;
+parameter RD_ADDR_WIDTH0 = 10;
+parameter WR_DATA_WIDTH0 = 18;
+parameter RD_DATA_WIDTH0 = 18;
+parameter BE_WIDTH0 = 2;
+
+parameter WR_ADDR_WIDTH1 = 10;
+parameter RD_ADDR_WIDTH1 = 10;
+parameter WR_DATA_WIDTH1 = 18;
+parameter RD_DATA_WIDTH1 = 18;
+parameter BE_WIDTH1 = 2;
+
+input wire WEN0_i;
+input wire REN0_i;
+input wire clock0;
+input wire [WR_ADDR_WIDTH0-1 :0] WR_ADDR0_i;
+input wire [RD_ADDR_WIDTH0-1 :0] RD_ADDR0_i;
+input wire [WR_DATA_WIDTH0-1 :0] WDATA0_i;
+output wire [RD_DATA_WIDTH0-1 :0] RDATA0_o;
+
+input wire WEN1_i;
+input wire REN1_i;
+input wire clock1;
+input wire [WR_ADDR_WIDTH0-1 :0] WR_ADDR1_i;
+input wire [RD_ADDR_WIDTH0-1 :0] RD_ADDR1_i;
+input wire [WR_DATA_WIDTH0-1 :0] WDATA1_i;
+output wire [RD_DATA_WIDTH0-1 :0] RDATA1_o;
+
+
+RAM_18K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH0),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH0),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH0),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH0),
+ .BE_WIDTH(BE_WIDTH0)
+ ) spram_x18_inst1 (
+
+ .WEN_i(WEN0_i),
+ .WR_BE_i(2'b11),
+ .REN_i(REN0_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock0),
+ .WR_ADDR_i(WR_ADDR0_i),
+ .RD_ADDR_i(RD_ADDR0_i),
+ .WDATA_i(WDATA0_i),
+ .RDATA_o(RDATA0_o)
+ );
+
+RAM_18K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH1),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH1),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH1),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH1),
+ .BE_WIDTH(BE_WIDTH1)
+ ) spram_x18_inst2 (
+
+ .WEN_i(WEN1_i),
+ .WR_BE_i(2'b11),
+ .REN_i(REN1_i),
+ .WR_CLK_i(clock1),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR1_i),
+ .RD_ADDR_i(RD_ADDR1_i),
+ .WDATA_i(WDATA1_i),
+ .RDATA_o(RDATA1_o)
+ );
+
+endmodule
+
+module spram_9x2048_x2 (
+ WEN0_i,
+ REN0_i,
+ clock0,
+ WR_ADDR0_i,
+ RD_ADDR0_i,
+ WDATA0_i,
+ RDATA0_o,
+
+ WEN1_i,
+ REN1_i,
+ clock1,
+ WR_ADDR1_i,
+ RD_ADDR1_i,
+ WDATA1_i,
+ RDATA1_o
+);
+
+parameter WR_ADDR_WIDTH0 = 11;
+parameter RD_ADDR_WIDTH0 = 11;
+parameter WR_DATA_WIDTH0 = 9;
+parameter RD_DATA_WIDTH0 = 9;
+parameter BE_WIDTH0 = 1;
+
+parameter WR_ADDR_WIDTH1 = 11;
+parameter RD_ADDR_WIDTH1 = 11;
+parameter WR_DATA_WIDTH1 = 9;
+parameter RD_DATA_WIDTH1 = 9;
+parameter BE_WIDTH1 = 1;
+
+input wire WEN0_i;
+input wire REN0_i;
+input wire clock0;
+input wire [WR_ADDR_WIDTH0-1 :0] WR_ADDR0_i;
+input wire [RD_ADDR_WIDTH0-1 :0] RD_ADDR0_i;
+input wire [WR_DATA_WIDTH0-1 :0] WDATA0_i;
+output wire [RD_DATA_WIDTH0-1 :0] RDATA0_o;
+
+input wire WEN1_i;
+input wire REN1_i;
+input wire clock1;
+input wire [WR_ADDR_WIDTH1-1 :0] WR_ADDR1_i;
+input wire [RD_ADDR_WIDTH1-1 :0] RD_ADDR1_i;
+input wire [WR_DATA_WIDTH1-1 :0] WDATA1_i;
+output wire [RD_DATA_WIDTH1-1 :0] RDATA1_o;
+
+
+RAM_18K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH0),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH0),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH0),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH0),
+ .BE_WIDTH(BE_WIDTH0)
+ ) spram_x18_inst1 (
+
+ .WEN_i(WEN0_i),
+ .WR_BE_i(2'b11),
+ .REN_i(REN0_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock0),
+ .WR_ADDR_i(WR_ADDR0_i),
+ .RD_ADDR_i(RD_ADDR0_i),
+ .WDATA_i(WDATA0_i),
+ .RDATA_o(RDATA0_o)
+ );
+
+RAM_18K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH1),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH1),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH1),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH1),
+ .BE_WIDTH(BE_WIDTH1)
+ ) spram_x18_inst2 (
+
+ .WEN_i(WEN1_i),
+ .WR_BE_i(2'b11),
+ .REN_i(REN1_i),
+ .WR_CLK_i(clock1),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR1_i),
+ .RD_ADDR_i(RD_ADDR1_i),
+ .WDATA_i(WDATA1_i),
+ .RDATA_o(RDATA1_o)
+ );
+
+endmodule
+
+module spram_9x2048_18x1024 (
+ WEN0_i,
+ REN0_i,
+ clock0,
+ WR_ADDR0_i,
+ RD_ADDR0_i,
+ WDATA0_i,
+ RDATA0_o,
+
+ WEN1_i,
+ REN1_i,
+ clock1,
+ WR_ADDR1_i,
+ RD_ADDR1_i,
+ WDATA1_i,
+ RDATA1_o
+);
+
+parameter WR_ADDR_WIDTH0 = 11;
+parameter RD_ADDR_WIDTH0 = 11;
+parameter WR_DATA_WIDTH0 = 9;
+parameter RD_DATA_WIDTH0 = 9;
+parameter BE_WIDTH0 = 1;
+
+parameter WR_ADDR_WIDTH1 = 10;
+parameter RD_ADDR_WIDTH1 = 10;
+parameter WR_DATA_WIDTH1 = 18;
+parameter RD_DATA_WIDTH1 = 18;
+parameter BE_WIDTH1 = 2;
+
+input wire WEN0_i;
+input wire REN0_i;
+input wire clock0;
+input wire [WR_ADDR_WIDTH0-1 :0] WR_ADDR0_i;
+input wire [RD_ADDR_WIDTH0-1 :0] RD_ADDR0_i;
+input wire [WR_DATA_WIDTH0-1 :0] WDATA0_i;
+output wire [RD_DATA_WIDTH0-1 :0] RDATA0_o;
+
+input wire WEN1_i;
+input wire REN1_i;
+input wire clock1;
+input wire [WR_ADDR_WIDTH1-1 :0] WR_ADDR1_i;
+input wire [RD_ADDR_WIDTH1-1 :0] RD_ADDR1_i;
+input wire [WR_DATA_WIDTH1-1 :0] WDATA1_i;
+output wire [RD_DATA_WIDTH1-1 :0] RDATA1_o;
+
+
+RAM_18K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH0),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH0),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH0),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH0),
+ .BE_WIDTH(BE_WIDTH0)
+ ) spram_x18_inst1 (
+
+ .WEN_i(WEN0_i),
+ .WR_BE_i(1'b1),
+ .REN_i(REN0_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock0),
+ .WR_ADDR_i(WR_ADDR0_i),
+ .RD_ADDR_i(RD_ADDR0_i),
+ .WDATA_i(WDATA0_i),
+ .RDATA_o(RDATA0_o)
+ );
+
+RAM_18K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH1),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH1),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH1),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH1),
+ .BE_WIDTH(BE_WIDTH1)
+ ) spram_x18_inst2 (
+
+ .WEN_i(WEN1_i),
+ .WR_BE_i(2'b11),
+ .REN_i(REN1_i),
+ .WR_CLK_i(clock1),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR1_i),
+ .RD_ADDR_i(RD_ADDR1_i),
+ .WDATA_i(WDATA1_i),
+ .RDATA_o(RDATA1_o)
+ );
+
+endmodule
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sdp/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sdp/sim/Makefile
new file mode 100644
index 0000000..184c0a5
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sdp/sim/Makefile
@@ -0,0 +1,41 @@
+# Copyright (C) 2019-2022 The SymbiFlow Authors
+#
+# Use of this source code is governed by a ISC-style
+# license that can be found in the LICENSE file or at
+# https://opensource.org/licenses/ISC
+#
+# SPDX-License-Identifier: ISC
+
+TESTBENCH = bram18k_sdp_tb.v
+POST_SYNTH = spram_18x1024_2x_post_synth spram_9x2048_x2_post_synth spram_9x2048_18x1024_post_synth
+ADDR_WIDTH0 = 10 11 11
+DATA_WIDTH0 = 18 9 9
+ADDR_WIDTH1 = 10 11 10
+DATA_WIDTH1 = 18 9 18
+TOP = spram_18x1024_2x spram_9x2048_x2 spram_9x2048_18x1024
+ADDR0_DEFINES = $(foreach awidth0, $(ADDR_WIDTH0),-DADDR_WIDTH0="$(awidth0)")
+ADDR1_DEFINES = $(foreach awidth1, $(ADDR_WIDTH1),-DADDR_WIDTH1="$(awidth1)")
+DATA0_DEFINES = $(foreach dwidth0, $(DATA_WIDTH0),-DDATA_WIDTH0="$(dwidth0)")
+DATA1_DEFINES = $(foreach dwidth1, $(DATA_WIDTH1),-DDATA_WIDTH1="$(dwidth1)")
+TOP_DEFINES = $(foreach top, $(TOP),-DTOP="$(top)")
+VCD_DEFINES = $(foreach vcd, $(POST_SYNTH),-DVCD="$(vcd).vcd")
+
+SIM_LIBS = $(shell find ../../../../qlf_k6n10f -name "*.v" -not -name "*_map.v")
+
+define simulate_post_synth
+ @iverilog -vvvv -g2005 $(word $(1),$(ADDR0_DEFINES)) $(word $(1),$(ADDR1_DEFINES)) $(word $(1),$(DATA0_DEFINES)) $(word $(1),$(DATA1_DEFINES)) $(word $(1),$(TOP_DEFINES)) $(word $(1),$(VCD_DEFINES)) -o $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).v $(SIM_LIBS) $(TESTBENCH) > $(word $(1),$(POST_SYNTH)).vvp.log 2>&1
+ @vvp -vvvv $(word $(1),$(POST_SYNTH)).vvp > $(word $(1),$(POST_SYNTH)).vcd.log 2>&1
+endef
+
+define clean_post_synth_sim
+ @rm -rf $(word $(1),$(POST_SYNTH)).vcd $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).vvp.log $(word $(1),$(POST_SYNTH)).vcd.log
+endef
+
+#FIXME: $(call simulate_post_synth,3)
+sim:
+ $(call simulate_post_synth,1)
+ $(call clean_post_synth_sim,1)
+ $(call simulate_post_synth,2)
+ $(call clean_post_synth_sim,2)
+ $(call simulate_post_synth,3)
+ $(call clean_post_synth_sim,3)
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sdp/sim/bram18k_sdp_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sdp/sim/bram18k_sdp_tb.v
new file mode 100644
index 0000000..aa8616a
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sdp/sim/bram18k_sdp_tb.v
@@ -0,0 +1,222 @@
+// Copyright (C) 2019-2022 The SymbiFlow Authors
+//
+// Use of this source code is governed by a ISC-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/ISC
+//
+// SPDX-License-Identifier: ISC
+
+`timescale 1ns/1ps
+
+`define STRINGIFY(x) `"x`"
+
+module TB;
+ localparam PERIOD = 50;
+ localparam ADDR_INCR = 1;
+
+ reg clk_0;
+ reg rce_0;
+ reg [`ADDR_WIDTH0-1:0] ra_0;
+ wire [`DATA_WIDTH0-1:0] rq_0;
+ reg wce_0;
+ reg [`ADDR_WIDTH0-1:0] wa_0;
+ reg [`DATA_WIDTH0-1:0] wd_0;
+
+ reg clk_1;
+ reg rce_1;
+ reg [`ADDR_WIDTH1-1:0] ra_1;
+ wire [`DATA_WIDTH1-1:0] rq_1;
+ reg wce_1;
+ reg [`ADDR_WIDTH1-1:0] wa_1;
+ reg [`DATA_WIDTH1-1:0] wd_1;
+
+
+ initial clk_0 = 0;
+ initial clk_1 = 0;
+ initial ra_0 = 0;
+ initial ra_1 = 0;
+ initial rce_0 = 0;
+ initial rce_1 = 0;
+ initial forever #(PERIOD / 2.0) clk_0 = ~clk_0;
+ initial begin
+ #(PERIOD / 4.0);
+ forever #(PERIOD / 2.0) clk_1 = ~clk_1;
+ end
+ initial begin
+ $dumpfile(`STRINGIFY(`VCD));
+ $dumpvars;
+ end
+
+ integer a;
+ integer b;
+
+ reg done_0;
+ reg done_1;
+ initial done_0 = 1'b0;
+ initial done_1 = 1'b0;
+ wire done_sim = done_0 & done_1;
+
+ reg [`DATA_WIDTH0-1:0] expected_0;
+ reg [`DATA_WIDTH1-1:0] expected_1;
+
+ reg read_test_0;
+ reg read_test_1;
+ initial read_test_0 = 0;
+ initial read_test_1 = 0;
+
+ always @(posedge clk_0) begin
+ expected_0 <= (a | (a << 20) | 20'h55000) & {`DATA_WIDTH0{1'b1}};
+ end
+ always @(posedge clk_1) begin
+ expected_1 <= ((b+1) | ((b+1) << 20) | 20'h55000) & {`DATA_WIDTH1{1'b1}};
+ end
+
+ wire error_0 = ((a != 0) && read_test_0) ? (rq_0 !== expected_0) : 0;
+ wire error_1 = ((b != (1<<`ADDR_WIDTH1) / 2) && read_test_1) ? (rq_1 !== expected_1) : 0;
+
+ integer error_0_cnt = 0;
+ integer error_1_cnt = 0;
+
+ always @ (posedge clk_0)
+ begin
+ if (error_0)
+ error_0_cnt <= error_0_cnt + 1'b1;
+ end
+ always @ (posedge clk_1)
+ begin
+ if (error_1)
+ error_1_cnt <= error_1_cnt + 1'b1;
+ end
+
+ // PART 0
+ initial #(1) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0) / 2; a = a + ADDR_INCR) begin
+ @(negedge clk_0) begin
+ wa_0 = a;
+ wd_0 = a | (a << 20) | 20'h55000;
+ wce_0 = 1;
+ end
+ @(posedge clk_0) begin
+ #(PERIOD/10) wce_0 = 0;
+ end
+ end
+ // Read data
+ read_test_0 = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH0) / 2; a = a + ADDR_INCR) begin
+ @(negedge clk_0) begin
+ ra_0 = a;
+ rce_0 = 1;
+ end
+ @(posedge clk_0) begin
+ #(PERIOD/10) rce_0 = 0;
+ if ( rq_0 !== expected_0) begin
+ $display("%d: PORT 0: FAIL: mismatch act=%x exp=%x at %x", $time, rq_0, expected_0, a);
+ end else begin
+ $display("%d: PORT 0: OK: act=%x exp=%x at %x", $time, rq_0, expected_0, a);
+ end
+ end
+ end
+ done_0 = 1'b1;
+ a = 0;
+ end
+
+ // PART 1
+ initial #(1) begin
+ // Write data
+ for (b = (1<<`ADDR_WIDTH1) / 2; b < (1<<`ADDR_WIDTH1); b = b + ADDR_INCR) begin
+ @(negedge clk_1) begin
+ wa_1 = b;
+ wd_1 = (b+1) | ((b+1) << 20) | 20'h55000;
+ wce_1 = 1;
+ end
+ @(posedge clk_1) begin
+ #(PERIOD/10) wce_1 = 0;
+ end
+ end
+ // Read data
+ read_test_1 = 1;
+ for (b = (1<<`ADDR_WIDTH1) / 2; b < (1<<`ADDR_WIDTH1); b = b + ADDR_INCR) begin
+ @(negedge clk_1) begin
+ ra_1 = b;
+ rce_1 = 1;
+ end
+ @(posedge clk_1) begin
+ #(PERIOD/10) rce_1 = 0;
+ if ( rq_1 !== expected_1) begin
+ $display("%d: PORT 1: FAIL: mismatch act=%x exp=%x at %x", $time, rq_1, expected_1, b);
+ end else begin
+ $display("%d: PORT 1: OK: act=%x exp=%x at %x", $time, rq_1, expected_1, b);
+ end
+ end
+ end
+ done_1 = 1'b1;
+ b = (1<<`ADDR_WIDTH1) / 2;
+ end
+
+ // Scan for simulation finish
+ always @(posedge clk_0, posedge clk_1) begin
+ if (done_sim)
+ $finish_and_return( (error_0_cnt == 0 & error_1_cnt == 0) ? 0 : -1 );
+ end
+
+ case (`STRINGIFY(`TOP))
+ "spram_18x1024_2x": begin
+ spram_18x1024_2x #() bram (
+ .clock0(clk_0),
+ .REN0_i(rce_0),
+ .RD_ADDR0_i(ra_0),
+ .RDATA0_o(rq_0),
+ .WEN0_i(wce_0),
+ .WR_ADDR0_i(wa_0),
+ .WDATA0_i(wd_0),
+
+ .clock1(clk_1),
+ .REN1_i(rce_1),
+ .RD_ADDR1_i(ra_1),
+ .RDATA1_o(rq_1),
+ .WEN1_i(wce_1),
+ .WR_ADDR1_i(wa_1),
+ .WDATA1_i(wd_1)
+ );
+ end
+ "spram_9x2048_x2": begin
+ spram_9x2048_x2 #() bram (
+ .clock0(clk_0),
+ .REN0_i(rce_0),
+ .RD_ADDR0_i(ra_0),
+ .RDATA0_o(rq_0),
+ .WEN0_i(wce_0),
+ .WR_ADDR0_i(wa_0),
+ .WDATA0_i(wd_0),
+
+ .clock1(clk_1),
+ .REN1_i(rce_1),
+ .RD_ADDR1_i(ra_1),
+ .RDATA1_o(rq_1),
+ .WEN1_i(wce_1),
+ .WR_ADDR1_i(wa_1),
+ .WDATA1_i(wd_1)
+ );
+ end
+ "spram_9x2048_18x1024": begin
+ spram_9x2048_18x1024 #() bram (
+ .clock0(clk_0),
+ .REN0_i(rce_0),
+ .RD_ADDR0_i(ra_0),
+ .RDATA0_o(rq_0),
+ .WEN0_i(wce_0),
+ .WR_ADDR0_i(wa_0),
+ .WDATA0_i(wd_0),
+
+ .clock1(clk_1),
+ .REN1_i(rce_1),
+ .RD_ADDR1_i(ra_1),
+ .RDATA1_o(rq_1),
+ .WEN1_i(wce_1),
+ .WR_ADDR1_i(wa_1),
+ .WDATA1_i(wd_1)
+ );
+ end
+ endcase
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sfifo/bram18k_sfifo.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sfifo/bram18k_sfifo.tcl
new file mode 100644
index 0000000..a5ff276
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sfifo/bram18k_sfifo.tcl
@@ -0,0 +1,49 @@
+yosys -import
+
+if { [info procs ql-qlf-k6n10f] == {} } { plugin -i ql-qlf }
+yosys -import ;
+
+read_verilog $::env(DESIGN_TOP).v
+design -save bram18k_sfifo
+
+select f1024x18_1024x18
+select *
+synth_quicklogic -family qlf_k6n10f -top f1024x18_1024x18 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/f1024x18_1024x18_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_SYNC_WR_X18_RD_X18_split
+
+select -clear
+design -load bram18k_sfifo
+select f1024x16_1024x16
+select *
+synth_quicklogic -family qlf_k6n10f -top f1024x16_1024x16 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/f1024x16_1024x16_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_SYNC_WR_X18_RD_X18_split
+
+select -clear
+design -load bram18k_sfifo
+select f2048x9_2048x9
+select *
+synth_quicklogic -family qlf_k6n10f -top f2048x9_2048x9 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/f2048x9_2048x9_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_SYNC_WR_X9_RD_X9_split
+
+select -clear
+design -load bram18k_sfifo
+select f2048x8_2048x8
+select *
+synth_quicklogic -family qlf_k6n10f -top f2048x8_2048x8 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/f2048x8_2048x8_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_SYNC_WR_X9_RD_X9_split
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sfifo/bram18k_sfifo.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sfifo/bram18k_sfifo.v
new file mode 100644
index 0000000..7930804
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sfifo/bram18k_sfifo.v
@@ -0,0 +1,163 @@
+module f1024x18_1024x18 (DIN,PUSH,POP,clock0,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 18;
+parameter RD_DATA_WIDTH = 18;
+parameter UPAE_DBITS = 11'd10;
+parameter UPAF_DBITS = 11'd10;
+
+input clock0;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+SFIFO_18K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .CLK(clock0),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module f1024x16_1024x16 (DIN,PUSH,POP,clock0,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 16;
+parameter RD_DATA_WIDTH = 16;
+parameter UPAE_DBITS = 11'd10;
+parameter UPAF_DBITS = 11'd10;
+
+input clock0;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+SFIFO_18K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .CLK(clock0),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module f2048x9_2048x9 (DIN,PUSH,POP,clock0,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 9;
+parameter RD_DATA_WIDTH = 9;
+parameter UPAE_DBITS = 11'd10;
+parameter UPAF_DBITS = 11'd10;
+
+input clock0;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+SFIFO_18K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .CLK(clock0),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module f2048x8_2048x8 (DIN,PUSH,POP,clock0,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 8;
+parameter RD_DATA_WIDTH = 8;
+parameter UPAE_DBITS = 11'd10;
+parameter UPAF_DBITS = 11'd10;
+
+input clock0;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+SFIFO_18K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .CLK(clock0),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sfifo/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sfifo/sim/Makefile
new file mode 100644
index 0000000..2a46d29
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sfifo/sim/Makefile
@@ -0,0 +1,51 @@
+# Copyright 2020-2022 F4PGA Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+TESTBENCH = bram18k_sfifo_tb.v
+POST_SYNTH = f1024x18_1024x18_post_synth f1024x16_1024x16_post_synth f2048x9_2048x9_post_synth f2048x8_2048x8_post_synth
+ADDR_WIDTH0 = 10 10 11 11
+DATA_WIDTH0 = 18 16 9 8
+ADDR_WIDTH1 = 10 10 11 11
+DATA_WIDTH1 = 18 16 9 8
+TOP = f1024x18_1024x18 f1024x16_1024x16 f2048x9_2048x9 f2048x8_2048x8
+ADDR0_DEFINES = $(foreach awidth0, $(ADDR_WIDTH0),-DADDR_WIDTH0="$(awidth0)")
+ADDR1_DEFINES = $(foreach awidth1, $(ADDR_WIDTH1),-DADDR_WIDTH1="$(awidth1)")
+DATA0_DEFINES = $(foreach dwidth0, $(DATA_WIDTH0),-DDATA_WIDTH0="$(dwidth0)")
+DATA1_DEFINES = $(foreach dwidth1, $(DATA_WIDTH1),-DDATA_WIDTH1="$(dwidth1)")
+TOP_DEFINES = $(foreach top, $(TOP),-DTOP="$(top)")
+VCD_DEFINES = $(foreach vcd, $(POST_SYNTH),-DVCD="$(vcd).vcd")
+
+SIM_LIBS = $(shell find ../../../../qlf_k6n10f -name "*.v" -not -name "*_map.v")
+
+define simulate_post_synth
+ @iverilog -vvvv -g2005 $(word $(1),$(ADDR0_DEFINES)) $(word $(1),$(ADDR1_DEFINES)) $(word $(1),$(DATA0_DEFINES)) $(word $(1),$(DATA1_DEFINES)) $(word $(1),$(TOP_DEFINES)) $(word $(1),$(VCD_DEFINES)) -o $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).v $(SIM_LIBS) $(TESTBENCH) > $(word $(1),$(POST_SYNTH)).vvp.log 2>&1
+ @vvp -vvvv $(word $(1),$(POST_SYNTH)).vvp > $(word $(1),$(POST_SYNTH)).vcd.log 2>&1
+endef
+
+define clean_post_synth_sim
+ @rm -rf $(word $(1),$(POST_SYNTH)).vcd $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).vvp.log $(word $(1),$(POST_SYNTH)).vcd.log
+endef
+
+# FIXME: $(call simulate_post_synth,5)
+sim:
+ $(call simulate_post_synth,1)
+ $(call clean_post_synth_sim,1)
+ $(call simulate_post_synth,2)
+ $(call clean_post_synth_sim,2)
+ $(call simulate_post_synth,3)
+ $(call clean_post_synth_sim,3)
+ $(call simulate_post_synth,4)
+ $(call clean_post_synth_sim,4)
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sfifo/sim/bram18k_sfifo_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sfifo/sim/bram18k_sfifo_tb.v
new file mode 100644
index 0000000..f5c56cf
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_sfifo/sim/bram18k_sfifo_tb.v
@@ -0,0 +1,188 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+`timescale 1ns/1ps
+
+`define STRINGIFY(x) `"x`"
+
+module TB;
+ localparam PERIOD = 30;
+ localparam ADDR_INCR = 1;
+
+ reg clk;
+ reg flush;
+ reg pop;
+ wire [`DATA_WIDTH1-1:0] dout;
+ reg push;
+ reg [`DATA_WIDTH0-1:0] din;
+ wire almost_full,almost_empty;
+ wire full, empty;
+ wire full_watermark, empty_watermark;
+ wire overrun_error, underrun_error;
+
+ initial
+ begin
+ clk = 0;
+ pop = 0;
+ push = 0;
+ flush = 1;
+ din = 0;
+ #40
+ flush = 0;
+ end
+
+ initial forever #(PERIOD / 3.0) clk = ~clk;
+
+ initial begin
+ $dumpfile(`STRINGIFY(`VCD));
+ $dumpvars;
+ end
+
+ integer a;
+
+ reg done;
+ initial done = 1'b0;
+
+ reg read_test;
+ initial read_test = 0;
+
+ reg [`DATA_WIDTH1-1:0] expected;
+ initial expected = 0;
+
+ always @(posedge clk) begin
+ expected <= (a | (a << 20) | 20'h55000) & {`DATA_WIDTH1{1'b1}};
+ end
+
+ wire error = ((a != 0) && read_test) ? dout !== expected : 0;
+
+ integer error_cnt = 0;
+ always @ (posedge clk)
+ begin
+ if (error)
+ error_cnt <= error_cnt + 1'b1;
+ end
+
+ initial #(50) begin
+ @(posedge clk)
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0); a = a + ADDR_INCR) begin
+ @(negedge clk) begin
+ din = a | (a << 20) | 20'h55000;
+ push = 1;
+ end
+ @(posedge clk) begin
+ #(PERIOD/10) push = 0;
+ end
+ end
+ // Read data
+ read_test = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(posedge clk) begin
+ #(PERIOD/10) pop = 0;
+ if ( dout !== expected) begin
+ $display("%d: FAIL: mismatch act=%x exp=%x at %x", $time, dout, expected, a);
+ end else begin
+ $display("%d: OK: act=%x exp=%x at %x", $time, dout, expected, a);
+ end
+ end
+ @(negedge clk) begin
+ pop = 1;
+ end
+ end
+ done = 1'b1;
+ end
+
+ // Scan for simulation finish
+ always @(posedge clk) begin
+ if (done)
+ $finish_and_return( (error_cnt == 0) ? 0 : -1 );
+ end
+
+ case (`STRINGIFY(`TOP))
+ "f1024x18_1024x18": begin
+ f1024x18_1024x18 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "f1024x16_1024x16": begin
+ f1024x16_1024x16 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "f2048x9_2048x9": begin
+ f2048x9_2048x9 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "f2048x8_2048x8": begin
+ f2048x8_2048x8 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ endcase
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_tdp/bram18k_tdp.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_tdp/bram18k_tdp.tcl
new file mode 100644
index 0000000..e42cd16
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_tdp/bram18k_tdp.tcl
@@ -0,0 +1,39 @@
+yosys -import
+
+if { [info procs ql-qlf-k6n10f] == {} } { plugin -i ql-qlf }
+yosys -import ;
+
+read_verilog $::env(DESIGN_TOP).v
+design -save bram18k_tdp
+
+select dpram_18x1024_x2
+select *
+synth_quicklogic -family qlf_k6n10f -top dpram_18x1024_x2 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/dpram_18x1024_x2_post_synth.v
+select -assert-count 2 t:TDP36K_BRAM_WR_X18_RD_X18_split
+
+select -clear
+design -load bram18k_tdp
+select dpram_9x2048_x2
+select *
+synth_quicklogic -family qlf_k6n10f -top dpram_9x2048_x2 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/dpram_9x2048_x2_post_synth.v
+select -assert-count 2 t:TDP36K_BRAM_WR_X9_RD_X9_split
+
+select -clear
+design -load bram18k_tdp
+select dpram_18x1024_9x2048
+select *
+synth_quicklogic -family qlf_k6n10f -top dpram_18x1024_9x2048 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/dpram_18x1024_9x2048_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X18_RD_X18_split
+select -assert-count 1 t:TDP36K_BRAM_WR_X9_RD_X9_split
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_tdp/bram18k_tdp.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_tdp/bram18k_tdp.v
new file mode 100644
index 0000000..8fb7d00
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_tdp/bram18k_tdp.v
@@ -0,0 +1,380 @@
+module dpram_18x1024_x2 (
+ clk_a_0,
+ WEN_a_0,
+ REN_a_0,
+ WR_ADDR_a_0,
+ RD_ADDR_a_0,
+ WDATA_a_0,
+ RDATA_a_0,
+
+ clk_b_0,
+ WEN_b_0,
+ REN_b_0,
+ WR_ADDR_b_0,
+ RD_ADDR_b_0,
+ WDATA_b_0,
+ RDATA_b_0,
+
+ clk_a_1,
+ WEN_a_1,
+ REN_a_1,
+ WR_ADDR_a_1,
+ RD_ADDR_a_1,
+ WDATA_a_1,
+ RDATA_a_1,
+
+ clk_b_1,
+ WEN_b_1,
+ REN_b_1,
+ WR_ADDR_b_1,
+ RD_ADDR_b_1,
+ WDATA_b_1,
+ RDATA_b_1
+);
+
+parameter ADDR_WIDTH0 = 10;
+parameter DATA_WIDTH0 = 18;
+parameter BE1_WIDTH0 = 2;
+parameter BE2_WIDTH0 = 2;
+
+parameter ADDR_WIDTH1 = 10;
+parameter DATA_WIDTH1 = 18;
+parameter BE1_WIDTH1 = 2;
+parameter BE2_WIDTH1 = 2;
+
+input wire clk_a_0;
+input wire WEN_a_0;
+input wire REN_a_0;
+input wire [ADDR_WIDTH0-1 :0] WR_ADDR_a_0;
+input wire [ADDR_WIDTH0-1 :0] RD_ADDR_a_0;
+input wire [DATA_WIDTH0-1 :0] WDATA_a_0;
+output wire [DATA_WIDTH0-1 :0] RDATA_a_0;
+
+input wire clk_b_0;
+input wire WEN_b_0;
+input wire REN_b_0;
+input wire [ADDR_WIDTH0-1 :0] WR_ADDR_b_0;
+input wire [ADDR_WIDTH0-1 :0] RD_ADDR_b_0;
+input wire [DATA_WIDTH0-1 :0] WDATA_b_0;
+output wire [DATA_WIDTH0-1 :0] RDATA_b_0;
+
+input wire clk_a_1;
+input wire WEN_a_1;
+input wire REN_a_1;
+input wire [ADDR_WIDTH1-1 :0] WR_ADDR_a_1;
+input wire [ADDR_WIDTH1-1 :0] RD_ADDR_a_1;
+input wire [DATA_WIDTH1-1 :0] WDATA_a_1;
+output wire [DATA_WIDTH1-1 :0] RDATA_a_1;
+
+input wire clk_b_1;
+input wire WEN_b_1;
+input wire REN_b_1;
+input wire [ADDR_WIDTH1-1 :0] WR_ADDR_b_1;
+input wire [ADDR_WIDTH1-1 :0] RD_ADDR_b_1;
+input wire [DATA_WIDTH1-1 :0] WDATA_b_1;
+output wire [DATA_WIDTH1-1 :0] RDATA_b_1;
+
+DPRAM_18K_BLK #(
+ .ADDR_WIDTH(ADDR_WIDTH0),
+ .DATA_WIDTH(DATA_WIDTH0),
+ .BE1_WIDTH(BE1_WIDTH0),
+ .BE2_WIDTH(BE2_WIDTH0)
+ ) dpram_x18_inst0 (
+
+ .CLK1_i(clk_a_0),
+ .WEN1_i(WEN_a_0),
+ .REN1_i(REN_a_0),
+ .WR1_ADDR_i(WR_ADDR_a_0),
+ .RD1_ADDR_i(RD_ADDR_a_0),
+ .WDATA1_i(WDATA_a_0),
+ .RDATA1_o(RDATA_a_0),
+
+ .CLK2_i(clk_b_0),
+ .WEN2_i(WEN_b_0),
+ .REN2_i(REN_b_0),
+ .WR2_ADDR_i(WR_ADDR_b_0),
+ .RD2_ADDR_i(RD_ADDR_b_0),
+ .WDATA2_i(WDATA_b_0),
+ .RDATA2_o(RDATA_b_0)
+ );
+
+
+DPRAM_18K_BLK #(
+ .ADDR_WIDTH(ADDR_WIDTH1),
+ .DATA_WIDTH(DATA_WIDTH1),
+ .BE1_WIDTH(BE1_WIDTH1),
+ .BE2_WIDTH(BE2_WIDTH1)
+ ) dpram_x18_inst1 (
+
+ .CLK1_i(clk_a_1),
+ .WEN1_i(WEN_a_1),
+ .REN1_i(REN_a_1),
+ .WR1_ADDR_i(WR_ADDR_a_1),
+ .RD1_ADDR_i(RD_ADDR_a_1),
+ .WDATA1_i(WDATA_a_1),
+ .RDATA1_o(RDATA_a_1),
+
+ .CLK2_i(clk_b_1),
+ .WEN2_i(WEN_b_1),
+ .REN2_i(REN_b_1),
+ .WR2_ADDR_i(WR_ADDR_b_1),
+ .RD2_ADDR_i(RD_ADDR_b_1),
+ .WDATA2_i(WDATA_b_1),
+ .RDATA2_o(RDATA_b_1)
+ );
+
+endmodule
+
+module dpram_9x2048_x2 (
+ clk_a_0,
+ WEN_a_0,
+ REN_a_0,
+ WR_ADDR_a_0,
+ RD_ADDR_a_0,
+ WDATA_a_0,
+ RDATA_a_0,
+
+ clk_b_0,
+ WEN_b_0,
+ REN_b_0,
+ WR_ADDR_b_0,
+ RD_ADDR_b_0,
+ WDATA_b_0,
+ RDATA_b_0,
+
+ clk_a_1,
+ WEN_a_1,
+ REN_a_1,
+ WR_ADDR_a_1,
+ RD_ADDR_a_1,
+ WDATA_a_1,
+ RDATA_a_1,
+
+ clk_b_1,
+ WEN_b_1,
+ REN_b_1,
+ WR_ADDR_b_1,
+ RD_ADDR_b_1,
+ WDATA_b_1,
+ RDATA_b_1
+);
+
+parameter ADDR_WIDTH0 = 11;
+parameter DATA_WIDTH0 = 9;
+parameter BE1_WIDTH0 = 1;
+parameter BE2_WIDTH0 = 1;
+
+parameter ADDR_WIDTH1 = 11;
+parameter DATA_WIDTH1 = 9;
+parameter BE1_WIDTH1 = 1;
+parameter BE2_WIDTH1 = 1;
+
+input wire clk_a_0;
+input wire WEN_a_0;
+input wire REN_a_0;
+input wire [ADDR_WIDTH0-1 :0] WR_ADDR_a_0;
+input wire [ADDR_WIDTH0-1 :0] RD_ADDR_a_0;
+input wire [DATA_WIDTH0-1 :0] WDATA_a_0;
+output wire [DATA_WIDTH0-1 :0] RDATA_a_0;
+
+input wire clk_b_0;
+input wire WEN_b_0;
+input wire REN_b_0;
+input wire [ADDR_WIDTH0-1 :0] WR_ADDR_b_0;
+input wire [ADDR_WIDTH0-1 :0] RD_ADDR_b_0;
+input wire [DATA_WIDTH0-1 :0] WDATA_b_0;
+output wire [DATA_WIDTH0-1 :0] RDATA_b_0;
+
+input wire clk_a_1;
+input wire WEN_a_1;
+input wire REN_a_1;
+input wire [ADDR_WIDTH1-1 :0] WR_ADDR_a_1;
+input wire [ADDR_WIDTH1-1 :0] RD_ADDR_a_1;
+input wire [DATA_WIDTH1-1 :0] WDATA_a_1;
+output wire [DATA_WIDTH1-1 :0] RDATA_a_1;
+
+input wire clk_b_1;
+input wire WEN_b_1;
+input wire REN_b_1;
+input wire [ADDR_WIDTH1-1 :0] WR_ADDR_b_1;
+input wire [ADDR_WIDTH1-1 :0] RD_ADDR_b_1;
+input wire [DATA_WIDTH1-1 :0] WDATA_b_1;
+output wire [DATA_WIDTH1-1 :0] RDATA_b_1;
+
+DPRAM_18K_BLK #(
+ .ADDR_WIDTH(ADDR_WIDTH0),
+ .DATA_WIDTH(DATA_WIDTH0),
+ .BE1_WIDTH(BE1_WIDTH0),
+ .BE2_WIDTH(BE2_WIDTH0)
+ ) dpram_x18_inst0 (
+
+ .CLK1_i(clk_a_0),
+ .WEN1_i(WEN_a_0),
+ .REN1_i(REN_a_0),
+ .WR1_ADDR_i(WR_ADDR_a_0),
+ .RD1_ADDR_i(RD_ADDR_a_0),
+ .WDATA1_i(WDATA_a_0),
+ .RDATA1_o(RDATA_a_0),
+
+ .CLK2_i(clk_b_0),
+ .WEN2_i(WEN_b_0),
+ .REN2_i(REN_b_0),
+ .WR2_ADDR_i(WR_ADDR_b_0),
+ .RD2_ADDR_i(RD_ADDR_b_0),
+ .WDATA2_i(WDATA_b_0),
+ .RDATA2_o(RDATA_b_0)
+ );
+
+
+DPRAM_18K_BLK #(
+ .ADDR_WIDTH(ADDR_WIDTH1),
+ .DATA_WIDTH(DATA_WIDTH1),
+ .BE1_WIDTH(BE1_WIDTH1),
+ .BE2_WIDTH(BE2_WIDTH1)
+ ) dpram_x18_inst1 (
+
+ .CLK1_i(clk_a_1),
+ .WEN1_i(WEN_a_1),
+ .REN1_i(REN_a_1),
+ .WR1_ADDR_i(WR_ADDR_a_1),
+ .RD1_ADDR_i(RD_ADDR_a_1),
+ .WDATA1_i(WDATA_a_1),
+ .RDATA1_o(RDATA_a_1),
+
+ .CLK2_i(clk_b_1),
+ .WEN2_i(WEN_b_1),
+ .REN2_i(REN_b_1),
+ .WR2_ADDR_i(WR_ADDR_b_1),
+ .RD2_ADDR_i(RD_ADDR_b_1),
+ .WDATA2_i(WDATA_b_1),
+ .RDATA2_o(RDATA_b_1)
+ );
+
+endmodule
+
+module dpram_18x1024_9x2048 (
+ clk_a_0,
+ WEN_a_0,
+ REN_a_0,
+ WR_ADDR_a_0,
+ RD_ADDR_a_0,
+ WDATA_a_0,
+ RDATA_a_0,
+
+ clk_b_0,
+ WEN_b_0,
+ REN_b_0,
+ WR_ADDR_b_0,
+ RD_ADDR_b_0,
+ WDATA_b_0,
+ RDATA_b_0,
+
+ clk_a_1,
+ WEN_a_1,
+ REN_a_1,
+ WR_ADDR_a_1,
+ RD_ADDR_a_1,
+ WDATA_a_1,
+ RDATA_a_1,
+
+ clk_b_1,
+ WEN_b_1,
+ REN_b_1,
+ WR_ADDR_b_1,
+ RD_ADDR_b_1,
+ WDATA_b_1,
+ RDATA_b_1
+);
+
+parameter ADDR_WIDTH0 = 10;
+parameter DATA_WIDTH0 = 18;
+parameter BE1_WIDTH0 = 2;
+parameter BE2_WIDTH0 = 2;
+
+parameter ADDR_WIDTH1 = 11;
+parameter DATA_WIDTH1 = 9;
+parameter BE1_WIDTH1 = 1;
+parameter BE2_WIDTH1 = 1;
+
+input wire clk_a_0;
+input wire WEN_a_0;
+input wire REN_a_0;
+input wire [ADDR_WIDTH0-1 :0] WR_ADDR_a_0;
+input wire [ADDR_WIDTH0-1 :0] RD_ADDR_a_0;
+input wire [DATA_WIDTH0-1 :0] WDATA_a_0;
+output wire [DATA_WIDTH0-1 :0] RDATA_a_0;
+
+input wire clk_b_0;
+input wire WEN_b_0;
+input wire REN_b_0;
+input wire [ADDR_WIDTH0-1 :0] WR_ADDR_b_0;
+input wire [ADDR_WIDTH0-1 :0] RD_ADDR_b_0;
+input wire [DATA_WIDTH0-1 :0] WDATA_b_0;
+output wire [DATA_WIDTH0-1 :0] RDATA_b_0;
+
+input wire clk_a_1;
+input wire WEN_a_1;
+input wire REN_a_1;
+input wire [ADDR_WIDTH1-1 :0] WR_ADDR_a_1;
+input wire [ADDR_WIDTH1-1 :0] RD_ADDR_a_1;
+input wire [DATA_WIDTH1-1 :0] WDATA_a_1;
+output wire [DATA_WIDTH1-1 :0] RDATA_a_1;
+
+input wire clk_b_1;
+input wire WEN_b_1;
+input wire REN_b_1;
+input wire [ADDR_WIDTH1-1 :0] WR_ADDR_b_1;
+input wire [ADDR_WIDTH1-1 :0] RD_ADDR_b_1;
+input wire [DATA_WIDTH1-1 :0] WDATA_b_1;
+output wire [DATA_WIDTH1-1 :0] RDATA_b_1;
+
+DPRAM_18K_BLK #(
+ .ADDR_WIDTH(ADDR_WIDTH0),
+ .DATA_WIDTH(DATA_WIDTH0),
+ .BE1_WIDTH(BE1_WIDTH0),
+ .BE2_WIDTH(BE2_WIDTH0)
+ ) dpram_x18_inst0 (
+
+ .CLK1_i(clk_a_0),
+ .WEN1_i(WEN_a_0),
+ .REN1_i(REN_a_0),
+ .WR1_ADDR_i(WR_ADDR_a_0),
+ .RD1_ADDR_i(RD_ADDR_a_0),
+ .WDATA1_i(WDATA_a_0),
+ .RDATA1_o(RDATA_a_0),
+
+ .CLK2_i(clk_b_0),
+ .WEN2_i(WEN_b_0),
+ .REN2_i(REN_b_0),
+ .WR2_ADDR_i(WR_ADDR_b_0),
+ .RD2_ADDR_i(RD_ADDR_b_0),
+ .WDATA2_i(WDATA_b_0),
+ .RDATA2_o(RDATA_b_0)
+ );
+
+
+DPRAM_18K_BLK #(
+ .ADDR_WIDTH(ADDR_WIDTH1),
+ .DATA_WIDTH(DATA_WIDTH1),
+ .BE1_WIDTH(BE1_WIDTH1),
+ .BE2_WIDTH(BE2_WIDTH1)
+ ) dpram_x18_inst1 (
+
+ .CLK1_i(clk_a_1),
+ .WEN1_i(WEN_a_1),
+ .REN1_i(REN_a_1),
+ .WR1_ADDR_i(WR_ADDR_a_1),
+ .RD1_ADDR_i(RD_ADDR_a_1),
+ .WDATA1_i(WDATA_a_1),
+ .RDATA1_o(RDATA_a_1),
+
+ .CLK2_i(clk_b_1),
+ .WEN2_i(WEN_b_1),
+ .REN2_i(REN_b_1),
+ .WR2_ADDR_i(WR_ADDR_b_1),
+ .RD2_ADDR_i(RD_ADDR_b_1),
+ .WDATA2_i(WDATA_b_1),
+ .RDATA2_o(RDATA_b_1)
+ );
+
+endmodule
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_tdp/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_tdp/sim/Makefile
new file mode 100644
index 0000000..3d9d866
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_tdp/sim/Makefile
@@ -0,0 +1,41 @@
+# Copyright (C) 2019-2022 The SymbiFlow Authors
+#
+# Use of this source code is governed by a ISC-style
+# license that can be found in the LICENSE file or at
+# https://opensource.org/licenses/ISC
+#
+# SPDX-License-Identifier: ISC
+
+TESTBENCH = bram18k_tdp_tb.v
+POST_SYNTH = dpram_18x1024_9x2048_post_synth dpram_9x2048_x2_post_synth dpram_18x1024_x2_post_synth
+ADDR_WIDTH0 = 10 11 10
+DATA_WIDTH0 = 18 9 18
+ADDR_WIDTH1 = 11 11 10
+DATA_WIDTH1 = 9 9 18
+TOP = dpram_18x1024_9x2048 dpram_9x2048_x2 dpram_18x1024_x2
+ADDR_DEFINES0 = $(foreach awidth0, $(ADDR_WIDTH0),-DADDR_WIDTH0="$(awidth0)")
+ADDR_DEFINES1 = $(foreach awidth1, $(ADDR_WIDTH1),-DADDR_WIDTH1="$(awidth1)")
+DATA_DEFINES0 = $(foreach dwidth0, $(DATA_WIDTH0),-DDATA_WIDTH0="$(dwidth0)")
+DATA_DEFINES1 = $(foreach dwidth1, $(DATA_WIDTH1),-DDATA_WIDTH1="$(dwidth1)")
+TOP_DEFINES = $(foreach top, $(TOP),-DTOP="$(top)")
+VCD_DEFINES = $(foreach vcd, $(POST_SYNTH),-DVCD="$(vcd).vcd")
+
+SIM_LIBS = $(shell find ../../../../qlf_k6n10f -name "*.v" -not -name "*_map.v")
+
+define simulate_post_synth
+ @iverilog -vvvv -g2005 $(word $(1),$(ADDR_DEFINES0)) $(word $(1),$(ADDR_DEFINES1)) $(word $(1),$(DATA_DEFINES0)) $(word $(1),$(DATA_DEFINES1)) $(word $(1),$(TOP_DEFINES)) $(word $(1),$(VCD_DEFINES)) -o $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).v $(SIM_LIBS) $(TESTBENCH) > $(word $(1),$(POST_SYNTH)).vvp.log 2>&1
+ @vvp -vvvv $(word $(1),$(POST_SYNTH)).vvp > $(word $(1),$(POST_SYNTH)).vcd.log 2>&1
+endef
+
+define clean_post_synth_sim
+ @rm -rf $(word $(1),$(POST_SYNTH)).vcd $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).vvp.log $(word $(1),$(POST_SYNTH)).vcd.log
+endef
+
+#FIXME: $(call simulate_post_synth,3)
+sim:
+ $(call simulate_post_synth,1)
+ $(call clean_post_synth_sim,1)
+ $(call simulate_post_synth,2)
+ $(call clean_post_synth_sim,2)
+ $(call simulate_post_synth,3)
+ $(call clean_post_synth_sim,3)
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_tdp/sim/bram18k_tdp_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_tdp/sim/bram18k_tdp_tb.v
new file mode 100644
index 0000000..1e5baa7
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram18k_tdp/sim/bram18k_tdp_tb.v
@@ -0,0 +1,356 @@
+// Copyright (C) 2019-2022 The SymbiFlow Authors
+//
+// Use of this source code is governed by a ISC-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/ISC
+//
+// SPDX-License-Identifier: ISC
+
+`timescale 1ns/1ps
+
+`define STRINGIFY(x) `"x`"
+
+module TB;
+ localparam PERIOD = 50;
+ localparam ADDR_INCR = 1;
+
+ reg clk_a;
+ reg rce_a_0;
+ reg rce_a_1;
+ reg [`ADDR_WIDTH0-1:0] ra_a_0;
+ reg [`ADDR_WIDTH1-1:0] ra_a_1;
+ wire [`DATA_WIDTH0-1:0] rq_a_0;
+ wire [`DATA_WIDTH1-1:0] rq_a_1;
+ reg wce_a_0;
+ reg wce_a_1;
+ reg [`ADDR_WIDTH0-1:0] wa_a_0;
+ reg [`ADDR_WIDTH1-1:0] wa_a_1;
+ reg [`DATA_WIDTH0-1:0] wd_a_0;
+ reg [`DATA_WIDTH1-1:0] wd_a_1;
+
+ reg clk_b;
+ reg rce_b_0;
+ reg rce_b_1;
+ reg [`ADDR_WIDTH0-1:0] ra_b_0;
+ reg [`ADDR_WIDTH1-1:0] ra_b_1;
+ wire [`DATA_WIDTH0-1:0] rq_b_0;
+ wire [`DATA_WIDTH1-1:0] rq_b_1;
+ reg wce_b_0;
+ reg wce_b_1;
+ reg [`ADDR_WIDTH0-1:0] wa_b_0;
+ reg [`ADDR_WIDTH1-1:0] wa_b_1;
+ reg [`DATA_WIDTH0-1:0] wd_b_0;
+ reg [`DATA_WIDTH1-1:0] wd_b_1;
+
+
+ initial clk_a = 0;
+ initial clk_b = 0;
+ initial ra_a_0 = 0;
+ initial ra_a_1 = 0;
+ initial ra_b_0 = 0;
+ initial ra_b_1 = 0;
+ initial rce_a_0 = 0;
+ initial rce_a_1 = 0;
+ initial rce_b_0 = 0;
+ initial rce_b_1 = 0;
+ initial wce_a_0 = 0;
+ initial wce_a_1 = 0;
+ initial wce_b_0 = 0;
+ initial wce_b_1 = 0;
+ initial forever #(PERIOD / 2.0) clk_a = ~clk_a;
+ initial begin
+ #(PERIOD / 4.0);
+ forever #(PERIOD / 2.0) clk_b = ~clk_b;
+ end
+ initial begin
+ $dumpfile(`STRINGIFY(`VCD));
+ $dumpvars;
+ end
+
+ integer a0;
+ integer b0;
+ integer a1;
+ integer b1;
+
+ reg done_a0;
+ reg done_b0;
+ reg done_a1;
+ reg done_b1;
+ initial done_a0 = 1'b0;
+ initial done_b0 = 1'b0;
+ initial done_a1 = 1'b0;
+ initial done_b1 = 1'b0;
+ wire done_sim = done_a0 & done_b0 & done_a1 & done_b1;
+
+ reg [`DATA_WIDTH0-1:0] expected_a_0;
+ reg [`DATA_WIDTH1-1:0] expected_a_1;
+ reg [`DATA_WIDTH0-1:0] expected_b_0;
+ reg [`DATA_WIDTH1-1:0] expected_b_1;
+
+ always @(posedge clk_a) begin
+ expected_a_0 <= (a0 | (a0 << 20) | 20'h55000) & {`DATA_WIDTH0{1'b1}};
+ expected_a_1 <= ((a1+1) | ((a1+1) << 20) | 20'h55000) & {`DATA_WIDTH1{1'b1}};
+ end
+ always @(posedge clk_b) begin
+ expected_b_0 <= ((b0+2) | ((b0+2) << 20) | 20'h55000) & {`DATA_WIDTH0{1'b1}};
+ expected_b_1 <= ((b1+3) | ((b1+3) << 20) | 20'h55000) & {`DATA_WIDTH1{1'b1}};
+ end
+
+ wire error_a_0 = a0 != 0 ? (rq_a_0 !== expected_a_0) : 0;
+ wire error_a_1 = a1 != 0 ? (rq_a_1 !== expected_a_1) : 0;
+ wire error_b_0 = b0 != (1<<`ADDR_WIDTH0) / 2 ? (rq_b_0 !== expected_b_0) : 0;
+ wire error_b_1 = b1 != (1<<`ADDR_WIDTH1) / 2 ? (rq_b_1 !== expected_b_1) : 0;
+
+ integer error_a_0_cnt = 0;
+ integer error_a_1_cnt = 0;
+ integer error_b_0_cnt = 0;
+ integer error_b_1_cnt = 0;
+
+ always @ (posedge clk_a)
+ begin
+ if (error_a_0)
+ error_a_0_cnt <= error_a_0_cnt + 1'b1;
+ if (error_a_1)
+ error_a_1_cnt <= error_a_1_cnt + 1'b1;
+ end
+ always @ (posedge clk_b)
+ begin
+ if (error_b_0)
+ error_b_0_cnt <= error_b_0_cnt + 1'b1;
+ if (error_b_1)
+ error_b_1_cnt <= error_b_1_cnt + 1'b1;
+ end
+
+ // PORTs A0
+ initial #(1) begin
+ // Write data
+ for (a0 = 0; a0 < (1<<`ADDR_WIDTH0) / 2; a0 = a0 + ADDR_INCR) begin
+ @(negedge clk_a) begin
+ wa_a_0 = a0;
+ wd_a_0 = a0 | (a0 << 20) | 20'h55000;
+ wce_a_0 = 1;
+ end
+ @(posedge clk_a) begin
+ #(PERIOD/10) wce_a_0 = 0;
+ end
+ end
+ // Read data
+ for (a0 = 0; a0 < (1<<`ADDR_WIDTH0) / 2; a0 = a0 + ADDR_INCR) begin
+ @(negedge clk_a) begin
+ ra_a_0 = a0;
+ rce_a_0 = 1;
+ end
+ @(posedge clk_a) begin
+ #(PERIOD/10) rce_a_0 = 0;
+ if ( rq_a_0 !== expected_a_0) begin
+ $display("%d: PORT A0: FAIL: mismatch act=%x exp=%x at %x", $time, rq_a_0, expected_a_0, a0);
+ end else begin
+ $display("%d: PORT A0: OK: act=%x exp=%x at %x", $time, rq_a_0, expected_a_0, a0);
+ end
+ end
+ end
+ done_a0 = 1'b1;
+ a0 = 0;
+ // PORTs B0
+ @(posedge clk_b)
+ #2;
+ // Write data
+ for (b0 = (1<<`ADDR_WIDTH0) / 2; b0 < (1<<`ADDR_WIDTH0); b0 = b0 + ADDR_INCR) begin
+ @(negedge clk_b) begin
+ wa_b_0 = b0;
+ wd_b_0 = (b0+2) | ((b0+2) << 20) | 20'h55000;
+ wce_b_0 = 1;
+ end
+ @(posedge clk_b) begin
+ #(PERIOD/10) wce_b_0 = 0;
+ end
+ end
+ // Read data
+ for (b0 = (1<<`ADDR_WIDTH0) / 2; b0 < (1<<`ADDR_WIDTH0); b0 = b0 + ADDR_INCR) begin
+ @(negedge clk_b) begin
+ ra_b_0 = b0;
+ rce_b_0 = 1;
+ end
+ @(posedge clk_b) begin
+ #(PERIOD/10) rce_b_0 = 0;
+ if ( rq_b_0 !== expected_b_0) begin
+ $display("%d: PORT B0: FAIL: mismatch act=%x exp=%x at %x", $time, rq_b_0, expected_b_0, b0);
+ end else begin
+ $display("%d: PORT B0: OK: act=%x exp=%x at %x", $time, rq_b_0, expected_b_0, b0);
+ end
+ end
+ end
+ done_b0 = 1'b1;
+ b0 = (1<<`ADDR_WIDTH0) / 2;
+ // PORTs A1
+ @(posedge clk_a)
+ #2;
+ // Write data
+ for (a1 = 0; a1 < (1<<`ADDR_WIDTH1) / 2; a1 = a1 + ADDR_INCR) begin
+ @(negedge clk_a) begin
+ wa_a_1 = a1;
+ wd_a_1 = (a1+1) | ((a1+1) << 20) | 20'h55000;
+ wce_a_1 = 1;
+ end
+ @(posedge clk_a) begin
+ #(PERIOD/10) wce_a_1 = 0;
+ end
+ end
+ // Read data
+ for (a1 = 0; a1 < (1<<`ADDR_WIDTH1) / 2; a1 = a1 + ADDR_INCR) begin
+ @(negedge clk_a) begin
+ ra_a_1 = a1;
+ rce_a_1 = 1;
+ end
+ @(posedge clk_a) begin
+ #(PERIOD/10) rce_a_1 = 0;
+ if ( rq_a_1 !== expected_a_1) begin
+ $display("%d: PORT A1: FAIL: mismatch act=%x exp=%x at %x", $time, rq_a_1, expected_a_1, a1);
+ end else begin
+ $display("%d: PORT A1: OK: act=%x exp=%x at %x", $time, rq_a_1, expected_a_1, a1);
+ end
+ end
+ end
+ done_a1 = 1'b1;
+ a1 = 0;
+ // PORTs B1
+ @(posedge clk_b)
+ #2;
+ // Write data
+ for (b1 = (1<<`ADDR_WIDTH1) / 2; b1 < (1<<`ADDR_WIDTH1); b1 = b1 + ADDR_INCR) begin
+ @(negedge clk_b) begin
+ wa_b_1 = b1;
+ wd_b_1 = (b1+3) | ((b1+3) << 20) | 20'h55000;
+ wce_b_1 = 1;
+ end
+ @(posedge clk_b) begin
+ #(PERIOD/10) wce_b_1 = 0;
+ end
+ end
+ // Read data
+ for (b1 = (1<<`ADDR_WIDTH1) / 2; b1 < (1<<`ADDR_WIDTH1); b1 = b1 + ADDR_INCR) begin
+ @(negedge clk_b) begin
+ ra_b_1 = b1;
+ rce_b_1 = 1;
+ end
+ @(posedge clk_b) begin
+ #(PERIOD/10) rce_b_1 = 0;
+ if ( rq_b_1 !== expected_b_1) begin
+ $display("%d: PORT B1: FAIL: mismatch act=%x exp=%x at %x", $time, rq_b_1, expected_b_1, b1);
+ end else begin
+ $display("%d: PORT B1: OK: act=%x exp=%x at %x", $time, rq_b_1, expected_b_1, b1);
+ end
+ end
+ end
+ done_b1 = 1'b1;
+ b1 = (1<<`ADDR_WIDTH1) / 2;
+ end
+
+ // Scan for simulation finish
+ always @(posedge clk_a, posedge clk_b) begin
+ if (done_sim)
+ $finish_and_return( (error_a_0_cnt == 0 & error_b_0_cnt == 0 & error_a_1_cnt == 0 & error_b_1_cnt == 0) ? 0 : -1 );
+ end
+
+ case (`STRINGIFY(`TOP))
+ "dpram_18x1024_9x2048": begin
+ dpram_18x1024_9x2048 #() bram (
+ .clk_a_0(clk_a),
+ .REN_a_0(rce_a_0),
+ .RD_ADDR_a_0(ra_a_0),
+ .RDATA_a_0(rq_a_0),
+ .WEN_a_0(wce_a_0),
+ .WR_ADDR_a_0(wa_a_0),
+ .WDATA_a_0(wd_a_0),
+ .clk_b_0(clk_b),
+ .REN_b_0(rce_b_0),
+ .RD_ADDR_b_0(ra_b_0),
+ .RDATA_b_0(rq_b_0),
+ .WEN_b_0(wce_b_0),
+ .WR_ADDR_b_0(wa_b_0),
+ .WDATA_b_0(wd_b_0),
+
+ .clk_a_1(clk_a),
+ .REN_a_1(rce_a_1),
+ .RD_ADDR_a_1(ra_a_1),
+ .RDATA_a_1(rq_a_1),
+ .WEN_a_1(wce_a_1),
+ .WR_ADDR_a_1(wa_a_1),
+ .WDATA_a_1(wd_a_1),
+ .clk_b_1(clk_b),
+ .REN_b_1(rce_b_1),
+ .RD_ADDR_b_1(ra_b_1),
+ .RDATA_b_1(rq_b_1),
+ .WEN_b_1(wce_b_1),
+ .WR_ADDR_b_1(wa_b_1),
+ .WDATA_b_1(wd_b_1)
+ );
+ end
+ "dpram_9x2048_x2": begin
+ dpram_9x2048_x2 #() bram (
+ .clk_a_0(clk_a),
+ .REN_a_0(rce_a_0),
+ .RD_ADDR_a_0(ra_a_0),
+ .RDATA_a_0(rq_a_0),
+ .WEN_a_0(wce_a_0),
+ .WR_ADDR_a_0(wa_a_0),
+ .WDATA_a_0(wd_a_0),
+ .clk_b_0(clk_b),
+ .REN_b_0(rce_b_0),
+ .RD_ADDR_b_0(ra_b_0),
+ .RDATA_b_0(rq_b_0),
+ .WEN_b_0(wce_b_0),
+ .WR_ADDR_b_0(wa_b_0),
+ .WDATA_b_0(wd_b_0),
+
+ .clk_a_1(clk_a),
+ .REN_a_1(rce_a_1),
+ .RD_ADDR_a_1(ra_a_1),
+ .RDATA_a_1(rq_a_1),
+ .WEN_a_1(wce_a_1),
+ .WR_ADDR_a_1(wa_a_1),
+ .WDATA_a_1(wd_a_1),
+ .clk_b_1(clk_b),
+ .REN_b_1(rce_b_1),
+ .RD_ADDR_b_1(ra_b_1),
+ .RDATA_b_1(rq_b_1),
+ .WEN_b_1(wce_b_1),
+ .WR_ADDR_b_1(wa_b_1),
+ .WDATA_b_1(wd_b_1)
+ );
+ end
+ "dpram_18x1024_x2": begin
+ dpram_18x1024_x2 #() bram (
+ .clk_a_0(clk_a),
+ .REN_a_0(rce_a_0),
+ .RD_ADDR_a_0(ra_a_0),
+ .RDATA_a_0(rq_a_0),
+ .WEN_a_0(wce_a_0),
+ .WR_ADDR_a_0(wa_a_0),
+ .WDATA_a_0(wd_a_0),
+ .clk_b_0(clk_b),
+ .REN_b_0(rce_b_0),
+ .RD_ADDR_b_0(ra_b_0),
+ .RDATA_b_0(rq_b_0),
+ .WEN_b_0(wce_b_0),
+ .WR_ADDR_b_0(wa_b_0),
+ .WDATA_b_0(wd_b_0),
+
+ .clk_a_1(clk_a),
+ .REN_a_1(rce_a_1),
+ .RD_ADDR_a_1(ra_a_1),
+ .RDATA_a_1(rq_a_1),
+ .WEN_a_1(wce_a_1),
+ .WR_ADDR_a_1(wa_a_1),
+ .WDATA_a_1(wd_a_1),
+ .clk_b_1(clk_b),
+ .REN_b_1(rce_b_1),
+ .RD_ADDR_b_1(ra_b_1),
+ .RDATA_b_1(rq_b_1),
+ .WEN_b_1(wce_b_1),
+ .WR_ADDR_b_1(wa_b_1),
+ .WDATA_b_1(wd_b_1)
+ );
+ end
+ endcase
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_afifo/bram36k_afifo.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_afifo/bram36k_afifo.tcl
new file mode 100644
index 0000000..dacbe77
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_afifo/bram36k_afifo.tcl
@@ -0,0 +1,38 @@
+yosys -import
+
+if { [info procs ql-qlf-k6n10f] == {} } { plugin -i ql-qlf }
+yosys -import ;
+
+read_verilog $::env(DESIGN_TOP).v
+design -save bram36k_afifo
+
+select af1024x36_1024x36
+select *
+synth_quicklogic -family qlf_k6n10f -top af1024x36_1024x36 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/af1024x36_1024x36_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_ASYNC_WR_X36_RD_X36_nonsplit
+
+select -clear
+design -load bram36k_afifo
+select af2048x18_2048x18
+select *
+synth_quicklogic -family qlf_k6n10f -top af2048x18_2048x18 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/af2048x18_2048x18_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_ASYNC_WR_X18_RD_X18_nonsplit
+
+select -clear
+design -load bram36k_afifo
+select af4096x9_4096x9
+select *
+synth_quicklogic -family qlf_k6n10f -top af4096x9_4096x9 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/af4096x9_4096x9_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_ASYNC_WR_X9_RD_X9_nonsplit
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_afifo/bram36k_afifo.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_afifo/bram36k_afifo.v
new file mode 100644
index 0000000..bdd8077
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_afifo/bram36k_afifo.v
@@ -0,0 +1,125 @@
+module af1024x36_1024x36 (DIN,PUSH,POP,clock0,clock1,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 36;
+parameter RD_DATA_WIDTH = 36;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0,clock1;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+AFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .Push_Clk(clock0),
+ .Pop_Clk(clock1),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module af2048x18_2048x18 (DIN,PUSH,POP,clock0,clock1,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 18;
+parameter RD_DATA_WIDTH = 18;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0,clock1;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+AFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .Push_Clk(clock0),
+ .Pop_Clk(clock1),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module af4096x9_4096x9 (DIN,PUSH,POP,clock0,clock1,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 9;
+parameter RD_DATA_WIDTH = 9;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0,clock1;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+AFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .Push_Clk(clock0),
+ .Pop_Clk(clock1),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_afifo/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_afifo/sim/Makefile
new file mode 100644
index 0000000..8b777b5
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_afifo/sim/Makefile
@@ -0,0 +1,49 @@
+# Copyright 2020-2022 F4PGA Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+TESTBENCH = bram36k_afifo_tb.v
+POST_SYNTH = af1024x36_1024x36_post_synth af2048x18_2048x18_post_synth af4096x9_4096x9_post_synth
+ADDR_WIDTH0 = 10 11 12
+DATA_WIDTH0 = 36 18 9
+ADDR_WIDTH1 = 10 11 12
+DATA_WIDTH1 = 36 18 9
+TOP = af1024x36_1024x36 af2048x18_2048x18 af4096x9_4096x9
+ADDR0_DEFINES = $(foreach awidth0, $(ADDR_WIDTH0),-DADDR_WIDTH0="$(awidth0)")
+ADDR1_DEFINES = $(foreach awidth1, $(ADDR_WIDTH1),-DADDR_WIDTH1="$(awidth1)")
+DATA0_DEFINES = $(foreach dwidth0, $(DATA_WIDTH0),-DDATA_WIDTH0="$(dwidth0)")
+DATA1_DEFINES = $(foreach dwidth1, $(DATA_WIDTH1),-DDATA_WIDTH1="$(dwidth1)")
+TOP_DEFINES = $(foreach top, $(TOP),-DTOP="$(top)")
+VCD_DEFINES = $(foreach vcd, $(POST_SYNTH),-DVCD="$(vcd).vcd")
+
+SIM_LIBS = $(shell find ../../../../qlf_k6n10f -name "*.v" -not -name "*_map.v")
+
+define simulate_post_synth
+ @iverilog -vvvv -g2005 $(word $(1),$(ADDR0_DEFINES)) $(word $(1),$(ADDR1_DEFINES)) $(word $(1),$(DATA0_DEFINES)) $(word $(1),$(DATA1_DEFINES)) $(word $(1),$(TOP_DEFINES)) $(word $(1),$(VCD_DEFINES)) -o $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).v $(SIM_LIBS) $(TESTBENCH) > $(word $(1),$(POST_SYNTH)).vvp.log 2>&1
+ @vvp -vvvv $(word $(1),$(POST_SYNTH)).vvp > $(word $(1),$(POST_SYNTH)).vcd.log 2>&1
+endef
+
+define clean_post_synth_sim
+ @rm -rf $(word $(1),$(POST_SYNTH)).vcd $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).vvp.log $(word $(1),$(POST_SYNTH)).vcd.log
+endef
+
+# FIXME: $(call simulate_post_synth,5)
+sim:
+ $(call simulate_post_synth,1)
+ $(call clean_post_synth_sim,1)
+ $(call simulate_post_synth,2)
+ $(call clean_post_synth_sim,2)
+ $(call simulate_post_synth,3)
+ $(call clean_post_synth_sim,3)
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_afifo/sim/bram36k_afifo_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_afifo/sim/bram36k_afifo_tb.v
new file mode 100644
index 0000000..addf547
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_afifo/sim/bram36k_afifo_tb.v
@@ -0,0 +1,177 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+`timescale 1ns/1ps
+
+`define STRINGIFY(x) `"x`"
+
+module TB;
+ localparam PERIOD = 30;
+ localparam ADDR_INCR = 1;
+
+ reg clk0;
+ reg clk1;
+ reg flush;
+ reg pop;
+ wire [`DATA_WIDTH1-1:0] dout;
+ reg push;
+ reg [`DATA_WIDTH0-1:0] din;
+ wire almost_full,almost_empty;
+ wire full, empty;
+ wire full_watermark, empty_watermark;
+ wire overrun_error, underrun_error;
+
+ initial
+ begin
+ clk0 = 0;
+ clk1 = 0;
+ pop = 0;
+ push = 0;
+ flush = 1;
+ din = 0;
+ #40
+ flush = 0;
+ end
+
+ initial forever #(PERIOD / 3.0) clk0 = ~clk0;
+ initial forever #(PERIOD / 2.0) clk1 = ~clk1;
+
+ initial begin
+ $dumpfile(`STRINGIFY(`VCD));
+ $dumpvars;
+ end
+
+ integer a;
+
+ reg done;
+ initial done = 1'b0;
+
+ reg read_test;
+ initial read_test = 0;
+
+ reg [`DATA_WIDTH1-1:0] expected;
+ initial expected = 0;
+
+ always @(posedge clk1) begin
+ expected <= (a | (a << 20) | 20'h55000) & {`DATA_WIDTH1{1'b1}};
+ end
+
+ wire error = ((a != 0) && read_test) ? dout !== expected : 0;
+
+ integer error_cnt = 0;
+ always @ (posedge clk1)
+ begin
+ if (error)
+ error_cnt <= error_cnt + 1'b1;
+ end
+
+
+ initial #(50) begin
+ @(posedge clk0)
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0); a = a + ADDR_INCR) begin
+ @(negedge clk0) begin
+ din = a | (a << 20) | 20'h55000;
+ push = 1;
+ end
+ @(posedge clk0) begin
+ #(PERIOD/10) push = 0;
+ end
+ end
+ // Read data
+ read_test = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(posedge clk1) begin
+ #(PERIOD/10) pop = 0;
+ if ( dout !== expected) begin
+ $display("%d: FAIL: mismatch act=%x exp=%x at %x", $time, dout, expected, a);
+ end else begin
+ $display("%d: OK: act=%x exp=%x at %x", $time, dout, expected, a);
+ end
+ end
+ @(negedge clk1) begin
+ pop = 1;
+ end
+ end
+ done = 1'b1;
+ end
+
+ // Scan for simulation finish
+ always @(posedge clk1) begin
+ if (done)
+ $finish_and_return( (error_cnt == 0) ? 0 : -1 );
+ end
+
+ case (`STRINGIFY(`TOP))
+ "af1024x36_1024x36": begin
+ af1024x36_1024x36 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .clock1(clk1),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "af2048x18_2048x18": begin
+ af2048x18_2048x18 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .clock1(clk1),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "af4096x9_4096x9": begin
+ af4096x9_4096x9 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk0),
+ .clock1(clk1),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ endcase
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sdp/bram36k_sdp.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sdp/bram36k_sdp.tcl
new file mode 100644
index 0000000..b5d38b0
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sdp/bram36k_sdp.tcl
@@ -0,0 +1,71 @@
+yosys -import
+
+if { [info procs ql-qlf-k6n10f] == {} } { plugin -i ql-qlf }
+yosys -import ;
+
+read_verilog $::env(DESIGN_TOP).v
+design -save bram36_sdp
+
+select spram_36x1024
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_36x1024 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_36x1024_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X36_RD_X36_nonsplit
+
+select -clear
+design -load bram36_sdp
+select spram_32x1024
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_32x1024 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_32x1024_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X36_RD_X36_nonsplit
+
+select -clear
+design -load bram36_sdp
+select spram_18x2048
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_18x2048 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_18x2048_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X18_RD_X18_nonsplit
+
+select -clear
+design -load bram36_sdp
+select spram_16x2048
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_16x2048 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_16x2048_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X18_RD_X18_nonsplit
+
+select -clear
+design -load bram36_sdp
+select spram_9x4096
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_9x4096 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_9x4096_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X9_RD_X9_nonsplit
+
+select -clear
+design -load bram36_sdp
+select spram_8x4096
+select *
+synth_quicklogic -family qlf_k6n10f -top spram_8x4096 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/spram_8x4096_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X9_RD_X9_nonsplit
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sdp/bram36k_sdp.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sdp/bram36k_sdp.v
new file mode 100644
index 0000000..3860511
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sdp/bram36k_sdp.v
@@ -0,0 +1,281 @@
+module spram_36x1024 (
+ WEN_i,
+ REN_i,
+ clock0,
+ clock1,
+ WR_ADDR_i,
+ RD_ADDR_i,
+ WDATA_i,
+ RDATA_o
+);
+
+parameter WR_ADDR_WIDTH = 10;
+parameter RD_ADDR_WIDTH = 10;
+parameter WR_DATA_WIDTH = 36;
+parameter RD_DATA_WIDTH = 36;
+parameter BE_WIDTH = 4;
+
+input wire WEN_i;
+input wire REN_i;
+input wire clock0;
+input wire clock1;
+input wire [WR_ADDR_WIDTH-1 :0] WR_ADDR_i;
+input wire [RD_ADDR_WIDTH-1 :0] RD_ADDR_i;
+input wire [WR_DATA_WIDTH-1 :0] WDATA_i;
+output wire [RD_DATA_WIDTH-1 :0] RDATA_o;
+
+RAM_36K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH),
+ .BE_WIDTH(BE_WIDTH)
+ ) spram_x36_inst (
+
+ .WEN_i(WEN_i),
+ .WR_BE_i(4'b1111),
+ .REN_i(REN_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR_i),
+ .RD_ADDR_i(RD_ADDR_i),
+ .WDATA_i(WDATA_i),
+ .RDATA_o(RDATA_o)
+ );
+
+endmodule
+
+module spram_32x1024 (
+ WEN_i,
+ REN_i,
+ clock0,
+ clock1,
+ WR_ADDR_i,
+ RD_ADDR_i,
+ WDATA_i,
+ RDATA_o
+);
+
+parameter WR_ADDR_WIDTH = 10;
+parameter RD_ADDR_WIDTH = 10;
+parameter WR_DATA_WIDTH = 32;
+parameter RD_DATA_WIDTH = 32;
+parameter BE_WIDTH = 4;
+
+input wire WEN_i;
+input wire REN_i;
+input wire clock0;
+input wire clock1;
+input wire [WR_ADDR_WIDTH-1 :0] WR_ADDR_i;
+input wire [RD_ADDR_WIDTH-1 :0] RD_ADDR_i;
+input wire [WR_DATA_WIDTH-1 :0] WDATA_i;
+output wire [RD_DATA_WIDTH-1 :0] RDATA_o;
+
+RAM_36K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH),
+ .BE_WIDTH(BE_WIDTH)
+ ) spram_x36_inst (
+
+ .WEN_i(WEN_i),
+ .WR_BE_i(4'b1111),
+ .REN_i(REN_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR_i),
+ .RD_ADDR_i(RD_ADDR_i),
+ .WDATA_i(WDATA_i),
+ .RDATA_o(RDATA_o)
+ );
+
+endmodule
+
+module spram_18x2048 (
+ WEN_i,
+ REN_i,
+ clock0,
+ clock1,
+ WR_ADDR_i,
+ RD_ADDR_i,
+ WDATA_i,
+ RDATA_o
+);
+
+parameter WR_ADDR_WIDTH = 11;
+parameter RD_ADDR_WIDTH = 11;
+parameter WR_DATA_WIDTH = 18;
+parameter RD_DATA_WIDTH = 18;
+parameter BE_WIDTH = 2;
+
+input wire WEN_i;
+input wire REN_i;
+input wire clock0;
+input wire clock1;
+input wire [WR_ADDR_WIDTH-1 :0] WR_ADDR_i;
+input wire [RD_ADDR_WIDTH-1 :0] RD_ADDR_i;
+input wire [WR_DATA_WIDTH-1 :0] WDATA_i;
+output wire [RD_DATA_WIDTH-1 :0] RDATA_o;
+
+RAM_36K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH),
+ .BE_WIDTH(BE_WIDTH)
+ ) spram_x36_inst (
+
+ .WEN_i(WEN_i),
+ .WR_BE_i(2'b11),
+ .REN_i(REN_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR_i),
+ .RD_ADDR_i(RD_ADDR_i),
+ .WDATA_i(WDATA_i),
+ .RDATA_o(RDATA_o)
+ );
+
+endmodule
+
+module spram_16x2048 (
+ WEN_i,
+ REN_i,
+ clock0,
+ clock1,
+ WR_ADDR_i,
+ RD_ADDR_i,
+ WDATA_i,
+ RDATA_o
+);
+
+parameter WR_ADDR_WIDTH = 11;
+parameter RD_ADDR_WIDTH = 11;
+parameter WR_DATA_WIDTH = 16;
+parameter RD_DATA_WIDTH = 16;
+parameter BE_WIDTH = 2;
+
+input wire WEN_i;
+input wire REN_i;
+input wire clock0;
+input wire clock1;
+input wire [WR_ADDR_WIDTH-1 :0] WR_ADDR_i;
+input wire [RD_ADDR_WIDTH-1 :0] RD_ADDR_i;
+input wire [WR_DATA_WIDTH-1 :0] WDATA_i;
+output wire [RD_DATA_WIDTH-1 :0] RDATA_o;
+
+RAM_36K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH),
+ .BE_WIDTH(BE_WIDTH)
+ ) spram_x36_inst (
+
+ .WEN_i(WEN_i),
+ .WR_BE_i(2'b11),
+ .REN_i(REN_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR_i),
+ .RD_ADDR_i(RD_ADDR_i),
+ .WDATA_i(WDATA_i),
+ .RDATA_o(RDATA_o)
+ );
+
+endmodule
+
+module spram_9x4096 (
+ WEN_i,
+ REN_i,
+ clock0,
+ clock1,
+ WR_ADDR_i,
+ RD_ADDR_i,
+ WDATA_i,
+ RDATA_o
+);
+
+parameter WR_ADDR_WIDTH = 12;
+parameter RD_ADDR_WIDTH = 12;
+parameter WR_DATA_WIDTH = 9;
+parameter RD_DATA_WIDTH = 9;
+parameter BE_WIDTH = 1;
+
+input wire WEN_i;
+input wire REN_i;
+input wire clock0;
+input wire clock1;
+input wire [WR_ADDR_WIDTH-1 :0] WR_ADDR_i;
+input wire [RD_ADDR_WIDTH-1 :0] RD_ADDR_i;
+input wire [WR_DATA_WIDTH-1 :0] WDATA_i;
+output wire [RD_DATA_WIDTH-1 :0] RDATA_o;
+
+RAM_36K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH),
+ .BE_WIDTH(BE_WIDTH)
+ ) spram_x36_inst (
+
+ .WEN_i(WEN_i),
+ .WR_BE_i(1'b1),
+ .REN_i(REN_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR_i),
+ .RD_ADDR_i(RD_ADDR_i),
+ .WDATA_i(WDATA_i),
+ .RDATA_o(RDATA_o)
+ );
+
+endmodule
+
+module spram_8x4096 (
+ WEN_i,
+ REN_i,
+ clock0,
+ clock1,
+ WR_ADDR_i,
+ RD_ADDR_i,
+ WDATA_i,
+ RDATA_o
+);
+
+parameter WR_ADDR_WIDTH = 12;
+parameter RD_ADDR_WIDTH = 12;
+parameter WR_DATA_WIDTH = 8;
+parameter RD_DATA_WIDTH = 8;
+parameter BE_WIDTH = 1;
+
+input wire WEN_i;
+input wire REN_i;
+input wire clock0;
+input wire clock1;
+input wire [WR_ADDR_WIDTH-1 :0] WR_ADDR_i;
+input wire [RD_ADDR_WIDTH-1 :0] RD_ADDR_i;
+input wire [WR_DATA_WIDTH-1 :0] WDATA_i;
+output wire [RD_DATA_WIDTH-1 :0] RDATA_o;
+
+RAM_36K_BLK #(
+ .WR_ADDR_WIDTH(WR_ADDR_WIDTH),
+ .RD_ADDR_WIDTH(RD_ADDR_WIDTH),
+ .WR_DATA_WIDTH(WR_DATA_WIDTH),
+ .RD_DATA_WIDTH(RD_DATA_WIDTH),
+ .BE_WIDTH(BE_WIDTH)
+ ) spram_x36_inst (
+
+ .WEN_i(WEN_i),
+ .WR_BE_i(1'b1),
+ .REN_i(REN_i),
+ .WR_CLK_i(clock0),
+ .RD_CLK_i(clock1),
+ .WR_ADDR_i(WR_ADDR_i),
+ .RD_ADDR_i(RD_ADDR_i),
+ .WDATA_i(WDATA_i),
+ .RDATA_o(RDATA_o)
+ );
+
+endmodule
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sdp/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sdp/sim/Makefile
new file mode 100644
index 0000000..ca7d1af
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sdp/sim/Makefile
@@ -0,0 +1,51 @@
+# Copyright 2020-2022 F4PGA Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+TESTBENCH = bram36k_sdp_tb.v
+POST_SYNTH = spram_36x1024_post_synth spram_32x1024_post_synth spram_18x2048_post_synth spram_16x2048_post_synth spram_9x4096_post_synth spram_8x4096_post_synth
+ADDR_WIDTH = 10 10 11 11 12 12
+DATA_WIDTH = 36 32 18 16 9 8
+TOP = spram_36x1024 spram_32x1024 spram_18x2048 spram_16x2048 spram_9x4096 spram_8x4096
+ADDR_DEFINES = $(foreach awidth, $(ADDR_WIDTH),-DADDR_WIDTH="$(awidth)")
+DATA_DEFINES = $(foreach dwidth, $(DATA_WIDTH),-DDATA_WIDTH="$(dwidth)")
+TOP_DEFINES = $(foreach top, $(TOP),-DTOP="$(top)")
+VCD_DEFINES = $(foreach vcd, $(POST_SYNTH),-DVCD="$(vcd).vcd")
+
+SIM_LIBS = $(shell find ../../../../qlf_k6n10f -name "*.v" -not -name "*_map.v")
+
+define simulate_post_synth
+ @iverilog -vvvv -g2005 $(word $(1),$(ADDR_DEFINES)) $(word $(1),$(DATA_DEFINES)) $(word $(1),$(TOP_DEFINES)) $(word $(1),$(VCD_DEFINES)) -o $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).v $(SIM_LIBS) $(TESTBENCH) > $(word $(1),$(POST_SYNTH)).vvp.log 2>&1
+ @vvp -vvvv $(word $(1),$(POST_SYNTH)).vvp > $(word $(1),$(POST_SYNTH)).vcd.log 2>&1
+endef
+
+define clean_post_synth_sim
+ @rm -rf $(word $(1),$(POST_SYNTH)).vcd $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).vvp.log $(word $(1),$(POST_SYNTH)).vcd.log
+endef
+
+# FIXME: $(call simulate_post_synth,5)
+sim:
+ $(call simulate_post_synth,1)
+ $(call clean_post_synth_sim,1)
+ $(call simulate_post_synth,2)
+ $(call clean_post_synth_sim,2)
+ $(call simulate_post_synth,3)
+ $(call clean_post_synth_sim,3)
+ $(call simulate_post_synth,4)
+ $(call clean_post_synth_sim,4)
+ $(call simulate_post_synth,5)
+ $(call clean_post_synth_sim,5)
+ $(call simulate_post_synth,6)
+ $(call clean_post_synth_sim,6)
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sdp/sim/bram36k_sdp_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sdp/sim/bram36k_sdp_tb.v
new file mode 100644
index 0000000..1c003ec
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sdp/sim/bram36k_sdp_tb.v
@@ -0,0 +1,176 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+`timescale 1ns/1ps
+
+`define STRINGIFY(x) `"x`"
+
+module TB;
+ localparam PERIOD = 50;
+ localparam ADDR_INCR = 1;
+
+ reg clk;
+ reg rce;
+ reg [`ADDR_WIDTH-1:0] ra;
+ wire [`DATA_WIDTH-1:0] rq;
+ reg wce;
+ reg [`ADDR_WIDTH-1:0] wa;
+ reg [`DATA_WIDTH-1:0] wd;
+
+ initial clk = 0;
+ initial ra = 0;
+ initial rce = 0;
+ initial forever #(PERIOD / 2.0) clk = ~clk;
+ initial begin
+ $dumpfile(`STRINGIFY(`VCD));
+ $dumpvars;
+ end
+
+ integer a;
+
+ reg done;
+ initial done = 1'b0;
+
+ reg [`DATA_WIDTH-1:0] expected;
+
+ always @(posedge clk) begin
+ expected <= (a | (a << 20) | 20'h55000) & {`DATA_WIDTH{1'b1}};
+ end
+
+ wire error = ((a != 0) && read_test) ? rq !== expected : 0;
+
+ integer error_cnt = 0;
+ always @ (posedge clk)
+ begin
+ if (error)
+ error_cnt <= error_cnt + 1'b1;
+ end
+
+ reg read_test;
+ initial read_test = 0;
+
+ initial #(1) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH); a = a + ADDR_INCR) begin
+ @(negedge clk) begin
+ wa = a;
+ wd = a | (a << 20) | 20'h55000;
+ wce = 1;
+ end
+ @(posedge clk) begin
+ #(PERIOD/10) wce = 0;
+ end
+ end
+ // Read data
+ read_test = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH); a = a + ADDR_INCR) begin
+ @(negedge clk) begin
+ ra = a;
+ rce = 1;
+ end
+ @(posedge clk) begin
+ #(PERIOD/10) rce = 0;
+ if ( rq !== expected) begin
+ $display("%d: FAIL: mismatch act=%x exp=%x at %x", $time, rq, expected, a);
+ end else begin
+ $display("%d: OK: act=%x exp=%x at %x", $time, rq, expected, a);
+ end
+ end
+ end
+ done = 1'b1;
+ end
+
+ // Scan for simulation finish
+ always @(posedge clk) begin
+ if (done)
+ $finish_and_return( (error_cnt == 0) ? 0 : -1 );
+ end
+
+ case (`STRINGIFY(`TOP))
+ "spram_36x1024": begin
+ spram_36x1024 #() bram (
+ .clock0(clk),
+ .clock1(clk),
+ .REN_i(rce),
+ .RD_ADDR_i(ra),
+ .RDATA_o(rq),
+ .WEN_i(wce),
+ .WR_ADDR_i(wa),
+ .WDATA_i(wd)
+ );
+ end
+ "spram_32x1024": begin
+ spram_32x1024 #() bram (
+ .clock0(clk),
+ .clock1(clk),
+ .REN_i(rce),
+ .RD_ADDR_i(ra),
+ .RDATA_o(rq),
+ .WEN_i(wce),
+ .WR_ADDR_i(wa),
+ .WDATA_i(wd)
+ );
+ end
+ "spram_18x2048": begin
+ spram_18x2048 #() bram (
+ .clock0(clk),
+ .clock1(clk),
+ .REN_i(rce),
+ .RD_ADDR_i(ra),
+ .RDATA_o(rq),
+ .WEN_i(wce),
+ .WR_ADDR_i(wa),
+ .WDATA_i(wd)
+ );
+ end
+ "spram_16x2048": begin
+ spram_16x2048 #() bram (
+ .clock0(clk),
+ .clock1(clk),
+ .REN_i(rce),
+ .RD_ADDR_i(ra),
+ .RDATA_o(rq),
+ .WEN_i(wce),
+ .WR_ADDR_i(wa),
+ .WDATA_i(wd)
+ );
+ end
+ "spram_9x4096": begin
+ spram_9x4096 #() bram (
+ .clock0(clk),
+ .clock1(clk),
+ .REN_i(rce),
+ .RD_ADDR_i(ra),
+ .RDATA_o(rq),
+ .WEN_i(wce),
+ .WR_ADDR_i(wa),
+ .WDATA_i(wd)
+ );
+ end
+ "spram_8x4096": begin
+ spram_8x4096 #() bram (
+ .clock0(clk),
+ .clock1(clk),
+ .REN_i(rce),
+ .RD_ADDR_i(ra),
+ .RDATA_o(rq),
+ .WEN_i(wce),
+ .WR_ADDR_i(wa),
+ .WDATA_i(wd)
+ );
+ end
+ endcase
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sfifo/bram36k_sfifo.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sfifo/bram36k_sfifo.tcl
new file mode 100644
index 0000000..8ffd95f
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sfifo/bram36k_sfifo.tcl
@@ -0,0 +1,38 @@
+yosys -import
+
+if { [info procs ql-qlf-k6n10f] == {} } { plugin -i ql-qlf }
+yosys -import ;
+
+read_verilog $::env(DESIGN_TOP).v
+design -save bram36k_sfifo
+
+select f1024x36_1024x36
+select *
+synth_quicklogic -family qlf_k6n10f -top f1024x36_1024x36 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/f1024x36_1024x36_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_SYNC_WR_X36_RD_X36_nonsplit
+
+select -clear
+design -load bram36k_sfifo
+select f2048x18_2048x18
+select *
+synth_quicklogic -family qlf_k6n10f -top f2048x18_2048x18 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/f2048x18_2048x18_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_SYNC_WR_X18_RD_X18_nonsplit
+
+select -clear
+design -load bram36k_sfifo
+select f4096x9_4096x9
+select *
+synth_quicklogic -family qlf_k6n10f -top f4096x9_4096x9 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/f4096x9_4096x9_post_synth.v
+select -assert-count 1 t:TDP36K_FIFO_SYNC_WR_X9_RD_X9_nonsplit
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sfifo/bram36k_sfifo.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sfifo/bram36k_sfifo.v
new file mode 100644
index 0000000..7cb07fa
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sfifo/bram36k_sfifo.v
@@ -0,0 +1,122 @@
+module f1024x36_1024x36 (DIN,PUSH,POP,clock0,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 36;
+parameter RD_DATA_WIDTH = 36;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+SFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .CLK(clock0),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module f2048x18_2048x18 (DIN,PUSH,POP,clock0,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 18;
+parameter RD_DATA_WIDTH = 18;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+SFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .CLK(clock0),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
+
+module f4096x9_4096x9 (DIN,PUSH,POP,clock0,Async_Flush,Almost_Full,Almost_Empty,Full,Empty,Full_Watermark,Empty_Watermark,Overrun_Error,Underrun_Error,DOUT);
+
+parameter WR_DATA_WIDTH = 9;
+parameter RD_DATA_WIDTH = 9;
+parameter UPAE_DBITS = 12'd10;
+parameter UPAF_DBITS = 12'd10;
+
+input clock0;
+input PUSH,POP;
+input [WR_DATA_WIDTH-1:0] DIN;
+input Async_Flush;
+output [RD_DATA_WIDTH-1:0] DOUT;
+output Almost_Full,Almost_Empty;
+output Full, Empty;
+output Full_Watermark, Empty_Watermark;
+output Overrun_Error, Underrun_Error;
+
+SFIFO_36K_BLK # (.WR_DATA_WIDTH(WR_DATA_WIDTH),.RD_DATA_WIDTH(RD_DATA_WIDTH),.UPAE_DBITS(UPAE_DBITS),.UPAF_DBITS(UPAF_DBITS)
+ )
+ FIFO_INST (
+ .DIN(DIN),
+ .PUSH(PUSH),
+ .POP(POP),
+ .CLK(clock0),
+ .Async_Flush(Async_Flush),
+
+ .Overrun_Error(Overrun_Error),
+ .Full_Watermark(Full_Watermark),
+ .Almost_Full(Almost_Full),
+ .Full(Full),
+
+ .Underrun_Error(Underrun_Error),
+ .Empty_Watermark(Empty_Watermark),
+ .Almost_Empty(Almost_Empty),
+ .Empty(Empty),
+
+ .DOUT(DOUT)
+ );
+
+endmodule
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sfifo/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sfifo/sim/Makefile
new file mode 100644
index 0000000..1cb26f3
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sfifo/sim/Makefile
@@ -0,0 +1,49 @@
+# Copyright 2020-2022 F4PGA Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+TESTBENCH = bram36k_sfifo_tb.v
+POST_SYNTH = f1024x36_1024x36_post_synth f2048x18_2048x18_post_synth f4096x9_4096x9_post_synth
+ADDR_WIDTH0 = 10 11 12
+DATA_WIDTH0 = 36 18 9
+ADDR_WIDTH1 = 10 11 12
+DATA_WIDTH1 = 36 18 9
+TOP = f1024x36_1024x36 f2048x18_2048x18 f4096x9_4096x9
+ADDR0_DEFINES = $(foreach awidth0, $(ADDR_WIDTH0),-DADDR_WIDTH0="$(awidth0)")
+ADDR1_DEFINES = $(foreach awidth1, $(ADDR_WIDTH1),-DADDR_WIDTH1="$(awidth1)")
+DATA0_DEFINES = $(foreach dwidth0, $(DATA_WIDTH0),-DDATA_WIDTH0="$(dwidth0)")
+DATA1_DEFINES = $(foreach dwidth1, $(DATA_WIDTH1),-DDATA_WIDTH1="$(dwidth1)")
+TOP_DEFINES = $(foreach top, $(TOP),-DTOP="$(top)")
+VCD_DEFINES = $(foreach vcd, $(POST_SYNTH),-DVCD="$(vcd).vcd")
+
+SIM_LIBS = $(shell find ../../../../qlf_k6n10f -name "*.v" -not -name "*_map.v")
+
+define simulate_post_synth
+ @iverilog -vvvv -g2005 $(word $(1),$(ADDR0_DEFINES)) $(word $(1),$(ADDR1_DEFINES)) $(word $(1),$(DATA0_DEFINES)) $(word $(1),$(DATA1_DEFINES)) $(word $(1),$(TOP_DEFINES)) $(word $(1),$(VCD_DEFINES)) -o $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).v $(SIM_LIBS) $(TESTBENCH) > $(word $(1),$(POST_SYNTH)).vvp.log 2>&1
+ @vvp -vvvv $(word $(1),$(POST_SYNTH)).vvp > $(word $(1),$(POST_SYNTH)).vcd.log 2>&1
+endef
+
+define clean_post_synth_sim
+ @rm -rf $(word $(1),$(POST_SYNTH)).vcd $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).vvp.log $(word $(1),$(POST_SYNTH)).vcd.log
+endef
+
+# FIXME: $(call simulate_post_synth,5)
+sim:
+ $(call simulate_post_synth,1)
+ $(call clean_post_synth_sim,1)
+ $(call simulate_post_synth,2)
+ $(call clean_post_synth_sim,2)
+ $(call simulate_post_synth,3)
+ $(call clean_post_synth_sim,3)
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sfifo/sim/bram36k_sfifo_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sfifo/sim/bram36k_sfifo_tb.v
new file mode 100644
index 0000000..df2362c
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_sfifo/sim/bram36k_sfifo_tb.v
@@ -0,0 +1,170 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+`timescale 1ns/1ps
+
+`define STRINGIFY(x) `"x`"
+
+module TB;
+ localparam PERIOD = 30;
+ localparam ADDR_INCR = 1;
+
+ reg clk;
+ reg flush;
+ reg pop;
+ wire [`DATA_WIDTH1-1:0] dout;
+ reg push;
+ reg [`DATA_WIDTH0-1:0] din;
+ wire almost_full,almost_empty;
+ wire full, empty;
+ wire full_watermark, empty_watermark;
+ wire overrun_error, underrun_error;
+
+ initial
+ begin
+ clk = 0;
+ pop = 0;
+ push = 0;
+ flush = 1;
+ din = 0;
+ #40
+ flush = 0;
+ end
+
+ initial forever #(PERIOD / 3.0) clk = ~clk;
+
+ initial begin
+ $dumpfile(`STRINGIFY(`VCD));
+ $dumpvars;
+ end
+
+ integer a;
+
+ reg done;
+ initial done = 1'b0;
+
+ reg read_test;
+ initial read_test = 0;
+
+ reg [`DATA_WIDTH1-1:0] expected;
+ initial expected = 0;
+
+ always @(posedge clk) begin
+ expected <= (a | (a << 20) | 20'h55000) & {`DATA_WIDTH1{1'b1}};
+ end
+
+ wire error = ((a != 0) && read_test) ? dout !== expected : 0;
+
+ integer error_cnt = 0;
+ always @ (posedge clk)
+ begin
+ if (error)
+ error_cnt <= error_cnt + 1'b1;
+ end
+
+ initial #(50) begin
+ @(posedge clk)
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH0); a = a + ADDR_INCR) begin
+ @(negedge clk) begin
+ din = a | (a << 20) | 20'h55000;
+ push = 1;
+ end
+ @(posedge clk) begin
+ #(PERIOD/10) push = 0;
+ end
+ end
+ // Read data
+ read_test = 1;
+ for (a = 0; a < (1<<`ADDR_WIDTH1); a = a + ADDR_INCR) begin
+ @(posedge clk) begin
+ #(PERIOD/10) pop = 0;
+ if ( dout !== expected) begin
+ $display("%d: FAIL: mismatch act=%x exp=%x at %x", $time, dout, expected, a);
+ end else begin
+ $display("%d: OK: act=%x exp=%x at %x", $time, dout, expected, a);
+ end
+ end
+ @(negedge clk) begin
+ pop = 1;
+ end
+ end
+ done = 1'b1;
+ end
+
+ // Scan for simulation finish
+ always @(posedge clk) begin
+ if (done)
+ $finish_and_return( (error_cnt == 0) ? 0 : -1 );
+ end
+
+ case (`STRINGIFY(`TOP))
+ "f1024x36_1024x36": begin
+ f1024x36_1024x36 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "f2048x18_2048x18": begin
+ f2048x18_2048x18 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ "f4096x9_4096x9": begin
+ f4096x9_4096x9 #() afifo (
+ .DIN(din),
+ .PUSH(push),
+ .POP(pop),
+ .clock0(clk),
+ .Async_Flush(flush),
+ .Almost_Full(almost_full),
+ .Almost_Empty(almost_empty),
+ .Full(full),
+ .Empty(empty),
+ .Full_Watermark(full_watermark),
+ .Empty_Watermark(empty_watermark),
+ .Overrun_Error(overrun_error),
+ .Underrun_Error(underrun_error),
+ .DOUT(dout)
+ );
+ end
+ endcase
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_tdp/bram36k_tdp.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_tdp/bram36k_tdp.tcl
new file mode 100644
index 0000000..df4591e
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_tdp/bram36k_tdp.tcl
@@ -0,0 +1,38 @@
+yosys -import
+
+if { [info procs ql-qlf-k6n10f] == {} } { plugin -i ql-qlf }
+yosys -import ;
+
+read_verilog $::env(DESIGN_TOP).v
+design -save bram36k_tdp
+
+select dpram_36x1024
+select *
+synth_quicklogic -family qlf_k6n10f -top dpram_36x1024 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/dpram_36x1024_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X36_RD_X36_nonsplit
+
+select -clear
+design -load bram36k_tdp
+select dpram_18x2048
+select *
+synth_quicklogic -family qlf_k6n10f -top dpram_18x2048 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/dpram_18x2048_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X18_RD_X18_nonsplit
+
+select -clear
+design -load bram36k_tdp
+select dpram_9x4096
+select *
+synth_quicklogic -family qlf_k6n10f -top dpram_9x4096 -bram_types
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/dpram_9x4096_post_synth.v
+select -assert-count 1 t:TDP36K_BRAM_WR_X9_RD_X9_nonsplit
\ No newline at end of file
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_tdp/bram36k_tdp.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_tdp/bram36k_tdp.v
new file mode 100644
index 0000000..b353a2f
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_tdp/bram36k_tdp.v
@@ -0,0 +1,197 @@
+module dpram_36x1024 (
+ clock0,
+ WEN1_i,
+ REN1_i,
+ WR1_ADDR_i,
+ RD1_ADDR_i,
+ WDATA1_i,
+ RDATA1_o,
+
+ clock1,
+ WEN2_i,
+ REN2_i,
+ WR2_ADDR_i,
+ RD2_ADDR_i,
+ WDATA2_i,
+ RDATA2_o
+);
+
+parameter ADDR_WIDTH = 10;
+parameter DATA_WIDTH = 36;
+parameter BE1_WIDTH = 4;
+parameter BE2_WIDTH = 4;
+
+input wire clock0;
+input wire WEN1_i;
+input wire REN1_i;
+input wire [ADDR_WIDTH-1 :0] WR1_ADDR_i;
+input wire [ADDR_WIDTH-1 :0] RD1_ADDR_i;
+input wire [DATA_WIDTH-1 :0] WDATA1_i;
+output wire [DATA_WIDTH-1 :0] RDATA1_o;
+
+input wire clock1;
+input wire WEN2_i;
+input wire REN2_i;
+input wire [ADDR_WIDTH-1 :0] WR2_ADDR_i;
+input wire [ADDR_WIDTH-1 :0] RD2_ADDR_i;
+input wire [DATA_WIDTH-1 :0] WDATA2_i;
+output wire [DATA_WIDTH-1 :0] RDATA2_o;
+
+DPRAM_36K_BLK #(
+ .ADDR_WIDTH(ADDR_WIDTH),
+ .DATA_WIDTH(DATA_WIDTH),
+ .BE1_WIDTH(BE1_WIDTH),
+ .BE2_WIDTH(BE2_WIDTH)
+ ) dpram_x36_inst (
+ .CLK1_i(clock0),
+ .WEN1_i(WEN1_i),
+ .WR1_BE_i(4'b1111),
+ .REN1_i(REN1_i),
+ .WR1_ADDR_i(WR1_ADDR_i),
+ .RD1_ADDR_i(RD1_ADDR_i),
+ .WDATA1_i(WDATA1_i),
+ .RDATA1_o(RDATA1_o),
+
+ .CLK2_i(clock1),
+ .WEN2_i(WEN2_i),
+ .WR2_BE_i(4'b1111),
+ .REN2_i(REN2_i),
+ .WR2_ADDR_i(WR2_ADDR_i),
+ .RD2_ADDR_i(RD2_ADDR_i),
+ .WDATA2_i(WDATA2_i),
+ .RDATA2_o(RDATA2_o)
+ );
+
+endmodule
+
+module dpram_18x2048 (
+ clock0,
+ WEN1_i,
+ REN1_i,
+ WR1_ADDR_i,
+ RD1_ADDR_i,
+ WDATA1_i,
+ RDATA1_o,
+
+ clock1,
+ WEN2_i,
+ REN2_i,
+ WR2_ADDR_i,
+ RD2_ADDR_i,
+ WDATA2_i,
+ RDATA2_o
+);
+
+parameter ADDR_WIDTH = 11;
+parameter DATA_WIDTH = 18;
+parameter BE1_WIDTH = 2;
+parameter BE2_WIDTH = 2;
+
+input wire clock0;
+input wire WEN1_i;
+input wire REN1_i;
+input wire [ADDR_WIDTH-1 :0] WR1_ADDR_i;
+input wire [ADDR_WIDTH-1 :0] RD1_ADDR_i;
+input wire [DATA_WIDTH-1 :0] WDATA1_i;
+output wire [DATA_WIDTH-1 :0] RDATA1_o;
+
+input wire clock1;
+input wire WEN2_i;
+input wire REN2_i;
+input wire [ADDR_WIDTH-1 :0] WR2_ADDR_i;
+input wire [ADDR_WIDTH-1 :0] RD2_ADDR_i;
+input wire [DATA_WIDTH-1 :0] WDATA2_i;
+output wire [DATA_WIDTH-1 :0] RDATA2_o;
+
+DPRAM_36K_BLK #(
+ .ADDR_WIDTH(ADDR_WIDTH),
+ .DATA_WIDTH(DATA_WIDTH),
+ .BE1_WIDTH(BE1_WIDTH),
+ .BE2_WIDTH(BE2_WIDTH)
+ ) dpram_x36_inst (
+ .CLK1_i(clock0),
+ .WEN1_i(WEN1_i),
+ .WR1_BE_i(2'b11),
+ .REN1_i(REN1_i),
+ .WR1_ADDR_i(WR1_ADDR_i),
+ .RD1_ADDR_i(RD1_ADDR_i),
+ .WDATA1_i(WDATA1_i),
+ .RDATA1_o(RDATA1_o),
+
+ .CLK2_i(clock1),
+ .WEN2_i(WEN2_i),
+ .WR2_BE_i(2'b11),
+ .REN2_i(REN2_i),
+ .WR2_ADDR_i(WR2_ADDR_i),
+ .RD2_ADDR_i(RD2_ADDR_i),
+ .WDATA2_i(WDATA2_i),
+ .RDATA2_o(RDATA2_o)
+ );
+
+endmodule
+
+module dpram_9x4096 (
+ clock0,
+ WEN1_i,
+ REN1_i,
+ WR1_ADDR_i,
+ RD1_ADDR_i,
+ WDATA1_i,
+ RDATA1_o,
+
+ clock1,
+ WEN2_i,
+ REN2_i,
+ WR2_ADDR_i,
+ RD2_ADDR_i,
+ WDATA2_i,
+ RDATA2_o
+);
+
+parameter ADDR_WIDTH = 12;
+parameter DATA_WIDTH = 9;
+parameter BE1_WIDTH = 1;
+parameter BE2_WIDTH = 1;
+
+input wire clock0;
+input wire WEN1_i;
+input wire REN1_i;
+input wire [ADDR_WIDTH-1 :0] WR1_ADDR_i;
+input wire [ADDR_WIDTH-1 :0] RD1_ADDR_i;
+input wire [DATA_WIDTH-1 :0] WDATA1_i;
+output wire [DATA_WIDTH-1 :0] RDATA1_o;
+
+input wire clock1;
+input wire WEN2_i;
+input wire REN2_i;
+input wire [ADDR_WIDTH-1 :0] WR2_ADDR_i;
+input wire [ADDR_WIDTH-1 :0] RD2_ADDR_i;
+input wire [DATA_WIDTH-1 :0] WDATA2_i;
+output wire [DATA_WIDTH-1 :0] RDATA2_o;
+
+DPRAM_36K_BLK #(
+ .ADDR_WIDTH(ADDR_WIDTH),
+ .DATA_WIDTH(DATA_WIDTH),
+ .BE1_WIDTH(BE1_WIDTH),
+ .BE2_WIDTH(BE2_WIDTH)
+ ) dpram_x36_inst (
+ .CLK1_i(clock0),
+ .WEN1_i(WEN1_i),
+ .WR1_BE_i(1'b1),
+ .REN1_i(REN1_i),
+ .WR1_ADDR_i(WR1_ADDR_i),
+ .RD1_ADDR_i(RD1_ADDR_i),
+ .WDATA1_i(WDATA1_i),
+ .RDATA1_o(RDATA1_o),
+
+ .CLK2_i(clock1),
+ .WEN2_i(WEN2_i),
+ .WR2_BE_i(1'b1),
+ .REN2_i(REN2_i),
+ .WR2_ADDR_i(WR2_ADDR_i),
+ .RD2_ADDR_i(RD2_ADDR_i),
+ .WDATA2_i(WDATA2_i),
+ .RDATA2_o(RDATA2_o)
+ );
+
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_tdp/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_tdp/sim/Makefile
new file mode 100644
index 0000000..2a0c20d
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_tdp/sim/Makefile
@@ -0,0 +1,45 @@
+# Copyright 2020-2022 F4PGA Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+TESTBENCH = bram36k_tdp_tb.v
+POST_SYNTH = dpram_36x1024_post_synth dpram_18x2048_post_synth dpram_9x4096_post_synth
+ADDR_WIDTH = 10 11 12
+DATA_WIDTH = 36 18 9
+TOP = dpram_36x1024 dpram_18x2048 dpram_9x4096
+ADDR_DEFINES = $(foreach awidth, $(ADDR_WIDTH),-DADDR_WIDTH="$(awidth)")
+DATA_DEFINES = $(foreach dwidth, $(DATA_WIDTH),-DDATA_WIDTH="$(dwidth)")
+TOP_DEFINES = $(foreach top, $(TOP),-DTOP="$(top)")
+VCD_DEFINES = $(foreach vcd, $(POST_SYNTH),-DVCD="$(vcd).vcd")
+
+SIM_LIBS = $(shell find ../../../../qlf_k6n10f -name "*.v" -not -name "*_map.v")
+
+define simulate_post_synth
+ @iverilog -vvvv -g2005 $(word $(1),$(ADDR_DEFINES)) $(word $(1),$(DATA_DEFINES)) $(word $(1),$(TOP_DEFINES)) $(word $(1),$(VCD_DEFINES)) -o $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).v $(SIM_LIBS) $(TESTBENCH) > $(word $(1),$(POST_SYNTH)).vvp.log 2>&1
+ @vvp -vvvv $(word $(1),$(POST_SYNTH)).vvp > $(word $(1),$(POST_SYNTH)).vcd.log 2>&1
+endef
+
+define clean_post_synth_sim
+ @rm -rf $(word $(1),$(POST_SYNTH)).vcd $(word $(1),$(POST_SYNTH)).vvp $(word $(1),$(POST_SYNTH)).vvp.log $(word $(1),$(POST_SYNTH)).vcd.log
+endef
+
+# FIXME: $(call simulate_post_synth,5)
+sim:
+ $(call simulate_post_synth,1)
+ $(call clean_post_synth_sim,1)
+ $(call simulate_post_synth,2)
+ $(call clean_post_synth_sim,2)
+ $(call simulate_post_synth,3)
+ $(call clean_post_synth_sim,3)
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_tdp/sim/bram36k_tdp_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_tdp/sim/bram36k_tdp_tb.v
new file mode 100644
index 0000000..01de7e7
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram36k_tdp/sim/bram36k_tdp_tb.v
@@ -0,0 +1,220 @@
+// Copyright 2020-2022 F4PGA Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+`timescale 1ns/1ps
+
+`define STRINGIFY(x) `"x`"
+
+module TB;
+ localparam PERIOD = 50;
+ localparam ADDR_INCR = 1;
+
+ reg clk_a;
+ reg rce_a;
+ reg [`ADDR_WIDTH-1:0] ra_a;
+ wire [`DATA_WIDTH-1:0] rq_a;
+ reg wce_a;
+ reg [`ADDR_WIDTH-1:0] wa_a;
+ reg [`DATA_WIDTH-1:0] wd_a;
+
+ reg clk_b;
+ reg rce_b;
+ reg [`ADDR_WIDTH-1:0] ra_b;
+ wire [`DATA_WIDTH-1:0] rq_b;
+ reg wce_b;
+ reg [`ADDR_WIDTH-1:0] wa_b;
+ reg [`DATA_WIDTH-1:0] wd_b;
+
+
+ initial clk_a = 0;
+ initial clk_b = 0;
+ initial ra_a = 0;
+ initial ra_b = 0;
+ initial rce_a = 0;
+ initial rce_b = 0;
+ initial forever #(PERIOD / 2.0) clk_a = ~clk_a;
+ initial begin
+ #(PERIOD / 4.0);
+ forever #(PERIOD / 2.0) clk_b = ~clk_b;
+ end
+ initial begin
+ $dumpfile(`STRINGIFY(`VCD));
+ $dumpvars;
+ end
+
+ integer a;
+ integer b;
+
+ reg done_a;
+ reg done_b;
+ initial done_a = 1'b0;
+ initial done_b = 1'b0;
+ wire done_sim = done_a & done_b;
+
+ reg [`DATA_WIDTH-1:0] expected_a;
+ reg [`DATA_WIDTH-1:0] expected_b;
+
+ always @(posedge clk_a) begin
+ expected_a <= (a | (a << 20) | 20'h55000) & {`DATA_WIDTH{1'b1}};
+ end
+ always @(posedge clk_b) begin
+ expected_b <= (b | (b << 20) | 20'h55000) & {`DATA_WIDTH{1'b1}};
+ end
+
+ wire error_a = a != 0 ? rq_a !== expected_a : 0;
+ wire error_b = b != (1<<`ADDR_WIDTH) / 2 ? rq_b !== expected_b : 0;
+
+ integer error_a_cnt = 0;
+ integer error_b_cnt = 0;
+
+ always @ (posedge clk_a)
+ begin
+ if (error_a)
+ error_a_cnt <= error_a_cnt + 1'b1;
+ end
+ always @ (posedge clk_b)
+ begin
+ if (error_b)
+ error_b_cnt <= error_b_cnt + 1'b1;
+ end
+ // PORT A
+ initial #(1) begin
+ // Write data
+ for (a = 0; a < (1<<`ADDR_WIDTH) / 2; a = a + ADDR_INCR) begin
+ @(negedge clk_a) begin
+ wa_a = a;
+ wd_a = a | (a << 20) | 20'h55000;
+ wce_a = 1;
+ end
+ @(posedge clk_a) begin
+ #(PERIOD/10) wce_a = 0;
+ end
+ end
+ // Read data
+ for (a = 0; a < (1<<`ADDR_WIDTH) / 2; a = a + ADDR_INCR) begin
+ @(negedge clk_a) begin
+ ra_a = a;
+ rce_a = 1;
+ end
+ @(posedge clk_a) begin
+ #(PERIOD/10) rce_a = 0;
+ if ( rq_a !== expected_a) begin
+ $display("%d: PORT A: FAIL: mismatch act=%x exp=%x at %x", $time, rq_a, expected_a, a);
+ end else begin
+ $display("%d: PORT A: OK: act=%x exp=%x at %x", $time, rq_a, expected_a, a);
+ end
+ end
+ end
+ done_a = 1'b1;
+ end
+
+ // PORT B
+ initial #(1) begin
+ // Write data
+ for (b = (1<<`ADDR_WIDTH) / 2; b < (1<<`ADDR_WIDTH); b = b + ADDR_INCR) begin
+ @(negedge clk_b) begin
+ wa_b = b;
+ wd_b = b | (b << 20) | 20'h55000;
+ wce_b = 1;
+ end
+ @(posedge clk_b) begin
+ #(PERIOD/10) wce_b = 0;
+ end
+ end
+ // Read data
+ for (b = (1<<`ADDR_WIDTH) / 2; b < (1<<`ADDR_WIDTH); b = b + ADDR_INCR) begin
+ @(negedge clk_b) begin
+ ra_b = b;
+ rce_b = 1;
+ end
+ @(posedge clk_b) begin
+ #(PERIOD/10) rce_b = 0;
+ if ( rq_b !== expected_b) begin
+ $display("%d: PORT B: FAIL: mismatch act=%x exp=%x at %x", $time, rq_b, expected_b, b);
+ end else begin
+ $display("%d: PORT B: OK: act=%x exp=%x at %x", $time, rq_b, expected_b, b);
+ end
+ end
+ end
+ done_b = 1'b1;
+ end
+
+ // Scan for simulation finish
+ always @(posedge clk_a, posedge clk_b) begin
+ if (done_sim)
+ $finish_and_return( (error_a_cnt == 0 & error_b_cnt == 0) ? 0 : -1 );
+ end
+
+ case (`STRINGIFY(`TOP))
+ "dpram_36x1024": begin
+ dpram_36x1024 #() bram (
+ .clock0(clk_a),
+ .REN1_i(rce_a),
+ .RD1_ADDR_i(ra_a),
+ .RDATA1_o(rq_a),
+ .WEN1_i(wce_a),
+ .WR1_ADDR_i(wa_a),
+ .WDATA1_i(wd_a),
+
+ .clock1(clk_b),
+ .REN2_i(rce_b),
+ .RD2_ADDR_i(ra_b),
+ .RDATA2_o(rq_b),
+ .WEN2_i(wce_b),
+ .WR2_ADDR_i(wa_b),
+ .WDATA2_i(wd_b)
+ );
+ end
+ "dpram_18x2048": begin
+ dpram_18x2048 #() bram (
+ .clock0(clk_a),
+ .REN1_i(rce_a),
+ .RD1_ADDR_i(ra_a),
+ .RDATA1_o(rq_a),
+ .WEN1_i(wce_a),
+ .WR1_ADDR_i(wa_a),
+ .WDATA1_i(wd_a),
+
+ .clock1(clk_b),
+ .REN2_i(rce_b),
+ .RD2_ADDR_i(ra_b),
+ .RDATA2_o(rq_b),
+ .WEN2_i(wce_b),
+ .WR2_ADDR_i(wa_b),
+ .WDATA2_i(wd_b)
+ );
+ end
+ "dpram_9x4096": begin
+ dpram_9x4096 #() bram (
+ .clock0(clk_a),
+ .REN1_i(rce_a),
+ .RD1_ADDR_i(ra_a),
+ .RDATA1_o(rq_a),
+ .WEN1_i(wce_a),
+ .WR1_ADDR_i(wa_a),
+ .WDATA1_i(wd_a),
+
+ .clock1(clk_b),
+ .REN2_i(rce_b),
+ .RD2_ADDR_i(ra_b),
+ .RDATA2_o(rq_b),
+ .WEN2_i(wce_b),
+ .WR2_ADDR_i(wa_b),
+ .WDATA2_i(wd_b)
+ );
+ end
+ endcase
+endmodule