Merge pull request #263 from antmicro/pcza/ql-qlf-k6n10f-tdp-inference

ql-qlf: qlf_k6n10f: add TDP_BRAM36 inference
diff --git a/Makefile_test.common b/Makefile_test.common
index db3cc3c..ca6ec18 100644
--- a/Makefile_test.common
+++ b/Makefile_test.common
@@ -95,6 +95,47 @@
 
 endef
 
+define test_post_synth_sim_tpl =
+$(1): $(1)/ok
+	@printf "Test %-18s \e[32mPASSED\e[0m @ %s\n" $(1) $(CURDIR);
+
+$(1)/ok: $(1)/synth
+	@make -C $(1)/sim sim; \
+	if [ $$$$? -ne 0 ]; then \
+		printf "Test %-18s \e[31;1mFAILED\e[0m @ %s\n" $(1) $(CURDIR); \
+		false; \
+	else \
+		touch $$@; \
+		true; \
+	fi
+
+$(1)/synth: $(1)/$$(notdir $(1).v)
+	@set +e; \
+	cd $(1); \
+	echo "source $(TEST_UTILS)" > run-$$(notdir $(1)).tcl ;\
+	echo "source $$(notdir $(1)).tcl" >> run-$$(notdir $(1)).tcl ;\
+	DESIGN_TOP=$$(notdir $(1)) TEST_OUTPUT_PREFIX=./ \
+	yosys -c "run-$$(notdir $(1)).tcl" -q -q -l $$(notdir $(1)).log; \
+	RETVAL=$$$$?; \
+	rm -f run-$$(notdir $(1)).tcl; \
+	if [ ! -z "$$($(1)_negative)" ] && [ $$($(1)_negative) -eq 1 ]; then \
+		if [ $$$$RETVAL -ne 0 ]; then \
+			printf "Negative test %-20s \e[32mPASSED\e[0m @ %s\n" $(1) $(CURDIR); \
+			true; \
+		else \
+			printf "Negative test %-20s \e[31;1mFAILED\e[0m @ %s\n" $(1) $(CURDIR); \
+			false; \
+		fi \
+	else \
+		if [ $$$$RETVAL -ne 0 ]; then \
+			echo "Unexpected runtime error"; \
+		    printf "Test %-20s \e[31;1mFAILED\e[0m @ %s\n" $(1) $(CURDIR); \
+			false; \
+		fi \
+	fi
+
+endef
+
 define unit_test_tpl =
 $(1): $(1)/$(1).test
 	@$$<
@@ -109,7 +150,7 @@
 
 diff_test = diff $(1)/$(1).golden.$(2) $(1)/$(1).$(2)
 
-all: $(TESTS) $(SIM_TESTS) $(UNIT_TESTS)
+all: $(TESTS) $(SIM_TESTS) $(POST_SYNTH_SIM_TESTS) $(UNIT_TESTS)
 
 $(GTEST_DIR)/build/lib/libgtest.a $(GTEST_DIR)/build/lib/libgtest_main.a:
 	@mkdir -p $(GTEST_DIR)/build
@@ -121,10 +162,12 @@
 
 $(foreach test,$(TESTS),$(eval $(call test_tpl,$(test))))
 $(foreach test,$(SIM_TESTS),$(eval $(call test_sim_tpl,$(test))))
+$(foreach test,$(POST_SYNTH_SIM_TESTS),$(eval $(call test_post_synth_sim_tpl,$(test))))
 $(foreach test,$(UNIT_TESTS),$(eval $(call unit_test_tpl,$(test))))
 
 clean:
 	@rm -rf $(foreach test,$(TESTS),$(test)/$(test).sdc $(test)/$(test)_[0-9].sdc $(test)/$(test).txt $(test)/$(test).eblif $(test)/$(test).json)
 	@rm -rf $(foreach test,$(SIM_TESTS),$(test)/*.vvp $(test)/*.vcd)
+	@rm -rf $(foreach test,$(POST_SYNTH_SIM_TESTS),$(test)/sim/*.vvp $(test)/sim/*.vcd $(test)/sim/*post_synth.v)
 	@rm -rf $(foreach test,$(UNIT_TESTS),$(test)/$(test).test.o $(test)/$(test).test.d $(test)/$(test).test)
 	@find . -name "ok" -or -name "*.log" | xargs rm -rf
diff --git a/ql-qlf-plugin/qlf_k6n10f/TDP18Kx18_FIFO.v b/ql-qlf-plugin/qlf_k6n10f/TDP18Kx18_FIFO.v
index bec428b..696c2a7 100644
--- a/ql-qlf-plugin/qlf_k6n10f/TDP18Kx18_FIFO.v
+++ b/ql-qlf-plugin/qlf_k6n10f/TDP18Kx18_FIFO.v
@@ -34,13 +34,8 @@
 	FWM,
 	OVERRUN,
 	FLUSH,
+	RAM_ID,
 	FMODE,
-	SYNC_FIFO,
-	POWERDN,
-	SLEEP,
-	PROTECT,
-	UPAF,
-	UPAE,
 	PL_INIT,
 	PL_ENA,
 	PL_WEN,
@@ -48,9 +43,15 @@
 	PL_CLK,
 	PL_ADDR,
 	PL_DATA_IN,
-	PL_DATA_OUT,
-	RAM_ID
+	PL_DATA_OUT
 );
+	parameter SYNC_FIFO = 1'b0;
+	parameter POWERDN = 1'b0;
+	parameter SLEEP = 1'b0;
+	parameter PROTECT = 1'b0;
+	parameter UPAF = 11'b0;
+	parameter UPAE = 11'b0;
+
 	input wire [2:0] RMODE_A;
 	input wire [2:0] RMODE_B;
 	input wire [2:0] WMODE_A;
@@ -80,13 +81,8 @@
 	output wire FWM;
 	output wire OVERRUN;
 	input wire FLUSH;
+	input wire [15:0] RAM_ID;
 	input wire FMODE;
-	input wire SYNC_FIFO;
-	input wire POWERDN;
-	input wire SLEEP;
-	input wire PROTECT;
-	input wire [10:0] UPAF;
-	input wire [10:0] UPAE;
 	input PL_INIT;
 	input PL_ENA;
 	input PL_WEN;
@@ -95,7 +91,6 @@
 	input [31:0] PL_ADDR;
 	input [17:0] PL_DATA_IN;
 	output reg [17:0] PL_DATA_OUT;
-	input [15:0] RAM_ID;
 	reg [17:0] wmsk_a;
 	reg [17:0] wmsk_b;
 	wire [8:0] addr_a;
diff --git a/ql-qlf-plugin/qlf_k6n10f/brams.txt b/ql-qlf-plugin/qlf_k6n10f/brams.txt
index 1664603..b8ba985 100644
--- a/ql-qlf-plugin/qlf_k6n10f/brams.txt
+++ b/ql-qlf-plugin/qlf_k6n10f/brams.txt
@@ -1,4 +1,3 @@
-
 bram $__QLF_FACTOR_BRAM36_TDP
   init 1
   abits 10     @a10d36
@@ -13,51 +12,21 @@
   dbits  2     @a14d2
   abits 15     @a15d1
   dbits  1     @a15d1
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 4   @a10d36
-  enable 1 2   @a11d18
-  enable 1 1   @a12d9 @a13d4 @a14d2 @a15d1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-bram $__QLF_FACTOR_BRAM18_TDP
-  init 1
-  abits 10     @a10d18
-  dbits 18     @a10d18
-  abits 11     @a11d9
-  dbits  9     @a11d9
-  abits 12     @a12d4
-  dbits  4     @a12d4
-  abits 13     @a13d2
-  dbits  2     @a13d2
-  abits 14     @a14d1
-  dbits  1     @a14d1
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 2   @a10d18
-  enable 1 1   @a11d9 @a12d4 @a13d2 @a14d1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
+  groups 4
+  ports  1 1 1 1
+  wrmode 0 1 0 1
+  enable 1 4 1 4 @a10d36
+  enable 1 2 1 2 @a11d18
+  enable 1 1 1 1 @a12d9 @a13d4 @a14d2 @a15d1
+  transp 0 0 0 0
+  clocks 1 1 2 2
+  clkpol 1 1 1 1
 endbram
 
 
 match $__QLF_FACTOR_BRAM36_TDP
-  min bits 128
-  min efficiency 2
-  shuffle_enable B
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__QLF_FACTOR_BRAM18_TDP
-  min bits 128
-  min efficiency 2
+  max dbits 36
+  max abits 15
   shuffle_enable B
   make_transp
 endmatch
diff --git a/ql-qlf-plugin/qlf_k6n10f/brams_map.v b/ql-qlf-plugin/qlf_k6n10f/brams_map.v
index be0b230..59fbdd7 100644
--- a/ql-qlf-plugin/qlf_k6n10f/brams_map.v
+++ b/ql-qlf-plugin/qlf_k6n10f/brams_map.v
@@ -6,17 +6,25 @@
 //
 // SPDX-License-Identifier:ISC
 
-module \$__QLF_FACTOR_BRAM36_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+`define MODE_36 3'b111	// 36 or 32-bit
+`define MODE_18 3'b110	// 18 or 16-bit
+`define MODE_9  3'b101	// 9 or 8-bit
+`define MODE_4  3'b100	// 4-bit
+`define MODE_2  3'b010	// 32-bit
+`define MODE_1  3'b001	// 32-bit
+
+module \$__QLF_FACTOR_BRAM36_TDP (A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN, C1ADDR, C1DATA, C1EN, CLK1, CLK2, D1ADDR, D1DATA, D1EN);
 	parameter CFG_ABITS = 10;
 	parameter CFG_DBITS = 36;
 	parameter CFG_ENABLE_B = 4;
+	parameter CFG_ENABLE_D = 4;
 
 	parameter CLKPOL2 = 1;
 	parameter CLKPOL3 = 1;
 	parameter [36863:0] INIT = 36864'bx;
 
+	input CLK1;
 	input CLK2;
-	input CLK3;
 
 	input [CFG_ABITS-1:0] A1ADDR;
 	output [CFG_DBITS-1:0] A1DATA;
@@ -26,106 +34,226 @@
 	input [CFG_DBITS-1:0] B1DATA;
 	input [CFG_ENABLE_B-1:0] B1EN;
 
-	wire [14:0] A1ADDR_15;
-	wire [14:0] B1ADDR_15; 
-	//wire [7:0] B1EN_8 = //B1EN;
+	input [CFG_ABITS-1:0] C1ADDR;
+	output [CFG_DBITS-1:0] C1DATA;
+	input C1EN;
 
-	wire [3:0] DIP, DOP;
-	wire [31:0] DI, DO;
+	input [CFG_ABITS-1:0] D1ADDR;
+	input [CFG_DBITS-1:0] D1DATA;
+	input [CFG_ENABLE_B-1:0] D1EN;
 
-	wire [31:0] DOBDO;
-	wire [3:0] DOPBDOP;
+	wire FLUSH1;
+	wire FLUSH2;
+	wire SPLIT;
+	wire [15:0] RAM_ID;
 
-	//wire [2:0] WRITEDATAWIDTHB;
-	//wire [2:0] READDATAWIDTHA;
-	assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
-	assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
+	wire PL_INIT_i;
+	wire PL_ENA_i;
+	wire PL_REN_i;
+	wire PL_CLK_i;
+	wire [1:0] PL_WEN_i;
+	wire [23:0] PL_ADDR_i;
+	wire [35:0] PL_DATA_i;
+	reg PL_INIT_o;
+	reg PL_ENA_o;
+	reg PL_REN_o;
+	reg PL_CLK_o;
+	reg [1:0] PL_WEN_o;
+	reg [23:0] PL_ADDR_o;
+	wire [35:0] PL_DATA_o;
 
-        assign A1ADDR_15[14:CFG_ABITS]  = 0;
-        assign A1ADDR_15[CFG_ABITS-1:0] = A1ADDR;
-        assign B1ADDR_15[14:CFG_ABITS]  = 0;
-        assign B1ADDR_15[CFG_ABITS-1:0] = B1ADDR;
+	wire [14:CFG_ABITS] A1ADDR_CMPL = {15-CFG_ABITS{1'b0}};
+	wire [14:CFG_ABITS] B1ADDR_CMPL = {15-CFG_ABITS{1'b0}};
+	wire [14:CFG_ABITS] C1ADDR_CMPL = {15-CFG_ABITS{1'b0}};
+	wire [14:CFG_ABITS] D1ADDR_CMPL = {15-CFG_ABITS{1'b0}};
 
-	/*if (CFG_DBITS == 1) begin
-	  assign WRITEDATAWIDTHB = 3'b000;
-	  assign READDATAWIDTHA = 3'b000;
-	end else if (CFG_DBITS == 2) begin
-          assign WRITEDATAWIDTHB = 3'b001;
-          assign READDATAWIDTHA = 3'b001;
-        end else if (CFG_DBITS > 2 && CFG_DBITS <= 4) begin
-          assign WRITEDATAWIDTHB = 3'b010;
-          assign READDATAWIDTHA = 3'b010;
-        end else if (CFG_DBITS > 4 && CFG_DBITS <= 9) begin
-          assign WRITEDATAWIDTHB = 3'b011;
-          assign READDATAWIDTHA = 3'b011;
-        end else if (CFG_DBITS > 9 && CFG_DBITS <= 18) begin
-          assign WRITEDATAWIDTHB = 3'b100;
-          assign READDATAWIDTHA = 3'b100;
-        end else if (CFG_DBITS > 18 && CFG_DBITS <= 36) begin
-          assign WRITEDATAWIDTHB = 3'b101;
-          assign READDATAWIDTHA = 3'b101;
-	end*/
-	generate if (CFG_DBITS > 8) begin
-		TDP_BRAM36 #(
-			//`include "brams_init_36.vh"
-                        .READ_WIDTH_A(CFG_DBITS),
-                        .READ_WIDTH_B(CFG_DBITS),
-                        .WRITE_WIDTH_A(CFG_DBITS),
-                        .WRITE_WIDTH_B(CFG_DBITS),
-		) _TECHMAP_REPLACE_ (
-			.WRITEDATAA(32'hFFFFFFFF),
-			.WRITEDATAAP(4'hF),
-			.READDATAA(DO[31:0]),
-			.READDATAAP(DOP[3:0]),
-			.ADDRA(A1ADDR_15),
-			.CLOCKA(CLK2),
-			.READENABLEA(A1EN),
-			.WRITEENABLEA(1'b0),
-			.BYTEENABLEA(4'b0),
-			//.WRITEDATAWIDTHA(3'b0),
-			//.READDATAWIDTHA(READDATAWIDTHA),
+	wire [14:0] A1ADDR_TOTAL = {A1ADDR_CMPL, A1ADDR};
+	wire [14:0] B1ADDR_TOTAL = {B1ADDR_CMPL, B1ADDR};
+	wire [14:0] C1ADDR_TOTAL = {C1ADDR_CMPL, C1ADDR};
+	wire [14:0] D1ADDR_TOTAL = {D1ADDR_CMPL, D1ADDR};
 
-			.WRITEDATAB(DI),
-			.WRITEDATABP(DIP),
-			.READDATAB(DOBDO),
-			.READDATABP(DOPBDOP),
-			.ADDRB(B1ADDR_15),
-			.CLOCKB(CLK3),
-			.READENABLEA(1'b0),
-			.WRITEENABLEB(1'b1),
-			.BYTEENABLEB(B1EN)
-			//.WRITEDATAWIDTHB(WRITEDATAWIDTHB),
-			//.READDATAWIDTHB(3'b0)
-		);
-	end else begin
-		TDP_BRAM36 #(
-			//`include "brams_init_32.vh"
-		) _TECHMAP_REPLACE_ (
-			.WRITEDATAA(32'hFFFFFFFF),
-			.WRITEDATAAP(4'hF),
-			.READDATAA(DO[31:0]),
-			.READDATAAP(DOP[3:0]),
-			.ADDRA(A1ADDR_15),
-			.CLOCKA(CLK2),
-			.READENABLEA(A1EN),
-			.WRITEENABLEA(1'b0),
-			.BYTEENABLEA(4'b0),
-			//.WRITEDATAWIDTHA(3'b0),
-			//.READDATAWIDTHA(READDATAWIDTHA),
+	wire [35:CFG_DBITS] A1DATA_CMPL;
+	wire [35:CFG_DBITS] C1DATA_CMPL;
 
-			.WRITEDATAB(DI),
-			.WRITEDATABP(DIP),
-			.READDATAB(DOBDO),
-			.READDATABP(DOPBDOP),
-			.ADDRB(B1ADDR_15),
-			.CLOCKB(CLK3),
-			.READENABLEB(1'b0),
-			.WRITEENABLEB(1'b1),
-			.BYTEENABLEB(B1EN)
-			//.WRITEDATAWIDTHB(WRITEDATAWIDTHB),
-			//.READDATAWIDTHB(3'b0)
-		);
-	end endgenerate
+	wire [35:0] A1DATA_TOTAL = {A1DATA_CMPL, A1DATA};
+	wire [35:0] C1DATA_TOTAL = {C1DATA_CMPL, C1DATA};
+
+	wire [14:0] PORT_A_ADDR;
+	wire [14:0] PORT_B_ADDR;
+
+	case (CFG_DBITS)
+		1: begin
+			assign PORT_A_ADDR = A1EN ? A1ADDR_TOTAL : (B1EN ? B1ADDR_TOTAL : 15'd0);
+			assign PORT_B_ADDR = C1EN ? C1ADDR_TOTAL : (D1EN ? D1ADDR_TOTAL : 15'd0);
+			defparam _TECHMAP_REPLACE_.WMODE_A1_i = `MODE_1;
+			defparam _TECHMAP_REPLACE_.WMODE_A2_i = `MODE_1;
+			defparam _TECHMAP_REPLACE_.RMODE_A1_i = `MODE_1;
+			defparam _TECHMAP_REPLACE_.RMODE_A2_i = `MODE_1;
+			defparam _TECHMAP_REPLACE_.WMODE_B1_i = `MODE_1;
+			defparam _TECHMAP_REPLACE_.WMODE_B2_i = `MODE_1;
+			defparam _TECHMAP_REPLACE_.RMODE_B1_i = `MODE_1;
+			defparam _TECHMAP_REPLACE_.RMODE_B2_i = `MODE_1;
+		end
+
+		2: begin
+			assign PORT_A_ADDR = A1EN ? (A1ADDR_TOTAL << 1) : (B1EN ? (B1ADDR_TOTAL << 1) : 15'd0);
+			assign PORT_B_ADDR = C1EN ? (C1ADDR_TOTAL << 1) : (D1EN ? (D1ADDR_TOTAL << 1) : 15'd0);
+			defparam _TECHMAP_REPLACE_.WMODE_A1_i = `MODE_2;
+			defparam _TECHMAP_REPLACE_.WMODE_A2_i = `MODE_2;
+			defparam _TECHMAP_REPLACE_.RMODE_A1_i = `MODE_2;
+			defparam _TECHMAP_REPLACE_.RMODE_A2_i = `MODE_2;
+			defparam _TECHMAP_REPLACE_.WMODE_B1_i = `MODE_2;
+			defparam _TECHMAP_REPLACE_.WMODE_B2_i = `MODE_2;
+			defparam _TECHMAP_REPLACE_.RMODE_B1_i = `MODE_2;
+			defparam _TECHMAP_REPLACE_.RMODE_B2_i = `MODE_2;
+		end
+
+		4: begin
+			assign PORT_A_ADDR = A1EN ? (A1ADDR_TOTAL << 5) : (B1EN ? (B1ADDR_TOTAL << 5) : 15'd0);
+			assign PORT_B_ADDR = C1EN ? (C1ADDR_TOTAL << 5) : (D1EN ? (D1ADDR_TOTAL << 5) : 15'd0);
+			defparam _TECHMAP_REPLACE_.WMODE_A1_i = `MODE_4;
+			defparam _TECHMAP_REPLACE_.WMODE_A2_i = `MODE_4;
+			defparam _TECHMAP_REPLACE_.RMODE_A1_i = `MODE_4;
+			defparam _TECHMAP_REPLACE_.RMODE_A2_i = `MODE_4;
+			defparam _TECHMAP_REPLACE_.WMODE_B1_i = `MODE_4;
+			defparam _TECHMAP_REPLACE_.WMODE_B2_i = `MODE_4;
+			defparam _TECHMAP_REPLACE_.RMODE_B1_i = `MODE_4;
+			defparam _TECHMAP_REPLACE_.RMODE_B2_i = `MODE_4;
+		end
+
+		8, 9: begin
+			assign PORT_A_ADDR = A1EN ? (A1ADDR_TOTAL << 3) : (B1EN ? (B1ADDR_TOTAL << 3) : 15'd0);
+			assign PORT_B_ADDR = C1EN ? (C1ADDR_TOTAL << 3) : (D1EN ? (D1ADDR_TOTAL << 3) : 15'd0);
+			defparam _TECHMAP_REPLACE_.WMODE_A1_i = `MODE_9;
+			defparam _TECHMAP_REPLACE_.WMODE_A2_i = `MODE_9;
+			defparam _TECHMAP_REPLACE_.RMODE_A1_i = `MODE_9;
+			defparam _TECHMAP_REPLACE_.RMODE_A2_i = `MODE_9;
+			defparam _TECHMAP_REPLACE_.WMODE_B1_i = `MODE_9;
+			defparam _TECHMAP_REPLACE_.WMODE_B2_i = `MODE_9;
+			defparam _TECHMAP_REPLACE_.RMODE_B1_i = `MODE_9;
+			defparam _TECHMAP_REPLACE_.RMODE_B2_i = `MODE_9;
+		end
+
+		16, 18: begin
+			assign PORT_A_ADDR = A1EN ? (A1ADDR_TOTAL << 4) : (B1EN ? (B1ADDR_TOTAL << 4) : 15'd0);
+			assign PORT_B_ADDR = C1EN ? (C1ADDR_TOTAL << 4) : (D1EN ? (D1ADDR_TOTAL << 4) : 15'd0);
+			defparam _TECHMAP_REPLACE_.WMODE_A1_i = `MODE_18;
+			defparam _TECHMAP_REPLACE_.WMODE_A2_i = `MODE_18;
+			defparam _TECHMAP_REPLACE_.RMODE_A1_i = `MODE_18;
+			defparam _TECHMAP_REPLACE_.RMODE_A2_i = `MODE_18;
+			defparam _TECHMAP_REPLACE_.WMODE_B1_i = `MODE_18;
+			defparam _TECHMAP_REPLACE_.WMODE_B2_i = `MODE_18;
+			defparam _TECHMAP_REPLACE_.RMODE_B1_i = `MODE_18;
+			defparam _TECHMAP_REPLACE_.RMODE_B2_i = `MODE_18;
+		end
+
+		32, 36: begin
+			assign PORT_A_ADDR = A1EN ? (A1ADDR_TOTAL << 5) : (B1EN ? (B1ADDR_TOTAL << 5) : 15'd0);
+			assign PORT_B_ADDR = C1EN ? (C1ADDR_TOTAL << 5) : (D1EN ? (D1ADDR_TOTAL << 5) : 15'd0);
+			defparam _TECHMAP_REPLACE_.WMODE_A1_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.WMODE_A2_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.RMODE_A1_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.RMODE_A2_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.WMODE_B1_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.WMODE_B2_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.RMODE_B1_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.RMODE_B2_i = `MODE_36;
+		end
+		default: begin
+			assign PORT_A_ADDR = A1EN ? A1ADDR_TOTAL : (B1EN ? B1ADDR_TOTAL : 15'd0);
+			assign PORT_B_ADDR = C1EN ? C1ADDR_TOTAL : (D1EN ? D1ADDR_TOTAL : 15'd0);
+			defparam _TECHMAP_REPLACE_.WMODE_A1_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.WMODE_A2_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.RMODE_A1_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.RMODE_A2_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.WMODE_B1_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.WMODE_B2_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.RMODE_B1_i = `MODE_36;
+			defparam _TECHMAP_REPLACE_.RMODE_B2_i = `MODE_36;
+		end
+	endcase
+
+
+	assign SPLIT = 1'b0;
+	assign FLUSH1 = 1'b0;
+	assign FLUSH2 = 1'b0;
+	assign RAM_ID = 16'b0;
+
+	assign PL_INIT_i = 1'b0;
+	assign PL_ENA_i = 1'b0;
+	assign PL_REN_i = 1'b0;
+	assign PL_CLK_i = 1'b0;
+	assign PL_WEN_i = 2'b0;
+	assign PL_ADDR_i = 24'b0;
+	assign PL_DATA_i = 36'b0;
+
+	TDP_BRAM36 #(
+		.UPAE1_i(12'd10),
+		.UPAF1_i(12'd10),
+		.UPAE2_i(12'd10),
+		.UPAF2_i(12'd10),
+		.SYNC_FIFO1_i(1'b0),
+		.SYNC_FIFO2_i(1'b0),
+		.FMODE1_i(1'b0),
+		.FMODE2_i(1'b0),
+		.POWERDN1_i(1'b0),
+		.POWERDN2_i(1'b0),
+		.SLEEP1_i(1'b0),
+		.SLEEP2_i(1'b0),
+		.PROTECT1_i(1'b0),
+		.PROTECT2_i(1'b0),
+		.SPLIT_i(1'b0)
+	) _TECHMAP_REPLACE_ (
+		.WDATA_A1_i(B1DATA[17:0]),
+		.WDATA_A2_i(B1DATA[35:18]),
+		.RDATA_A1_o(A1DATA_TOTAL[17:0]),
+		.RDATA_A2_o(A1DATA_TOTAL[35:18]),
+		.ADDR_A1_i(PORT_A_ADDR),
+		.ADDR_A2_i(PORT_A_ADDR),
+		.CLK_A1_i(CLK1),
+		.CLK_A2_i(CLK1),
+		.REN_A1_i(A1EN),
+		.REN_A2_i(A1EN),
+		.WEN_A1_i(B1EN[0]),
+		.WEN_A2_i(B1EN[0]),
+		.BE_A1_i({B1EN[1],B1EN[0]}),
+		.BE_A2_i({B1EN[3],B1EN[2]}),
+
+		.WDATA_B1_i(D1DATA[17:0]),
+		.WDATA_B2_i(D1DATA[35:18]),
+		.RDATA_B1_o(C1DATA_TOTAL[17:0]),
+		.RDATA_B2_o(C1DATA_TOTAL[35:18]),
+		.ADDR_B1_i(PORT_B_ADDR),
+		.ADDR_B2_i(PORT_B_ADDR),
+		.CLK_B1_i(CLK2),
+		.CLK_B2_i(CLK2),
+		.REN_B1_i(C1EN),
+		.REN_B2_i(C1EN),
+		.WEN_B1_i(D1EN[0]),
+		.WEN_B2_i(D1EN[0]),
+		.BE_B1_i({D1EN[1],D1EN[0]}),
+		.BE_B2_i({D1EN[3],D1EN[2]}),
+
+		.FLUSH1_i(FLUSH1),
+		.FLUSH2_i(FLUSH2),
+		.RAM_ID_i(RAM_ID),
+
+		.PL_INIT_i(PL_INIT_i),
+		.PL_ENA_i(PL_ENA_i),
+		.PL_WEN_i(PL_WEN_i),
+		.PL_REN_i(PL_REN_i),
+		.PL_CLK_i(PL_CLK_i),
+		.PL_ADDR_i(PL_ADDR_i),
+		.PL_DATA_i(PL_DATA_i),
+		.PL_INIT_o(PL_INIT_o),
+		.PL_ENA_o(PL_ENA_o),
+		.PL_WEN_o(PL_WEN_o),
+		.PL_REN_o(PL_REN_o),
+		.PL_CLK_o(PL_CLK_o),
+		.PL_ADDR_o(),
+		.PL_DATA_o(PL_DATA_o)
+
+	);
 endmodule
 
 // ------------------------------------------------------------------------
diff --git a/ql-qlf-plugin/qlf_k6n10f/cells_sim.v b/ql-qlf-plugin/qlf_k6n10f/cells_sim.v
index 95f3e78..240dbe8 100644
--- a/ql-qlf-plugin/qlf_k6n10f/cells_sim.v
+++ b/ql-qlf-plugin/qlf_k6n10f/cells_sim.v
@@ -503,17 +503,6 @@
 	RDATA_A1_o,
 	RDATA_B1_o,
 	FLUSH1_i,
-	SYNC_FIFO1_i,
-	RMODE_A1_i,
-	RMODE_B1_i,
-	WMODE_A1_i,
-	WMODE_B1_i,
-	FMODE1_i,
-	POWERDN1_i,
-	SLEEP1_i,
-	PROTECT1_i,
-	UPAE1_i,
-	UPAF1_i,
 	WEN_A2_i,
 	WEN_B2_i,
 	REN_A2_i,
@@ -529,18 +518,6 @@
 	RDATA_A2_o,
 	RDATA_B2_o,
 	FLUSH2_i,
-	SYNC_FIFO2_i,
-	RMODE_A2_i,
-	RMODE_B2_i,
-	WMODE_A2_i,
-	WMODE_B2_i,
-	FMODE2_i,
-	POWERDN2_i,
-	SLEEP2_i,
-	PROTECT2_i,
-	UPAE2_i,
-	UPAF2_i,
-	SPLIT_i,
 	RAM_ID_i,
 	PL_INIT_i,
 	PL_ENA_i,
@@ -557,6 +534,32 @@
 	PL_ADDR_o,
 	PL_DATA_o
 );
+	parameter SYNC_FIFO1_i = 1'b0;
+	parameter RMODE_A1_i = 3'b0;
+	parameter RMODE_B1_i = 3'b0;
+	parameter WMODE_A1_i = 3'b0;
+	parameter WMODE_B1_i = 3'b0;
+	parameter FMODE1_i = 1'b0;
+	parameter POWERDN1_i = 1'b0;
+	parameter SLEEP1_i = 1'b0;
+	parameter PROTECT1_i = 1'b0;
+	parameter UPAE1_i = 12'b0;
+	parameter UPAF1_i = 12'b0;
+
+	parameter SYNC_FIFO2_i = 1'b0;
+	parameter RMODE_A2_i = 3'b0;
+	parameter RMODE_B2_i = 3'b0;
+	parameter WMODE_A2_i = 3'b0;
+	parameter WMODE_B2_i = 3'b0;
+	parameter FMODE2_i = 1'b0;
+	parameter POWERDN2_i = 1'b0;
+	parameter SLEEP2_i = 1'b0;
+	parameter PROTECT2_i = 1'b0;
+	parameter UPAE2_i = 12'b0;
+	parameter UPAF2_i = 12'b0;
+
+	parameter SPLIT_i = 1'b0;
+
 	parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 	parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
 	parameter INITP_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
@@ -719,17 +722,6 @@
 	output reg [17:0] RDATA_A1_o;
 	output reg [17:0] RDATA_B1_o;
 	input wire FLUSH1_i;
-	input wire SYNC_FIFO1_i;
-	input wire [2:0] RMODE_A1_i;
-	input wire [2:0] RMODE_B1_i;
-	input wire [2:0] WMODE_A1_i;
-	input wire [2:0] WMODE_B1_i;
-	input wire FMODE1_i;
-	input wire POWERDN1_i;
-	input wire SLEEP1_i;
-	input wire PROTECT1_i;
-	input wire [11:0] UPAE1_i;
-	input wire [11:0] UPAF1_i;
 	input wire WEN_A2_i;
 	input wire WEN_B2_i;
 	input wire REN_A2_i;
@@ -747,19 +739,7 @@
 	output reg [17:0] RDATA_A2_o;
 	output reg [17:0] RDATA_B2_o;
 	input wire FLUSH2_i;
-	input wire SYNC_FIFO2_i;
-	input wire [2:0] RMODE_A2_i;
-	input wire [2:0] RMODE_B2_i;
-	input wire [2:0] WMODE_A2_i;
-	input wire [2:0] WMODE_B2_i;
-	input wire FMODE2_i;
-	input wire POWERDN2_i;
-	input wire SLEEP2_i;
-	input wire PROTECT2_i;
-	input wire [10:0] UPAE2_i;
-	input wire [10:0] UPAF2_i;
-	input SPLIT_i;
-	input [15:0] RAM_ID_i;
+	input wire [15:0] RAM_ID_i;
 	input wire PL_INIT_i;
 	input wire PL_ENA_i;
 	input wire PL_REN_i;
@@ -990,29 +970,27 @@
 			end
 		endcase
 	end
-	always @(*)
-		case (SPLIT_i)
-			0: begin
-				ram_rmode_a1 = (RMODE_A1_i == MODE_36 ? MODE_18 : RMODE_A1_i);
-				ram_rmode_a2 = (RMODE_A1_i == MODE_36 ? MODE_18 : RMODE_A1_i);
-				ram_wmode_a1 = (WMODE_A1_i == MODE_36 ? MODE_18 : (FMODE1_i ? MODE_18 : WMODE_A1_i));
-				ram_wmode_a2 = (WMODE_A1_i == MODE_36 ? MODE_18 : (FMODE1_i ? MODE_18 : WMODE_A1_i));
-				ram_rmode_b1 = (RMODE_B1_i == MODE_36 ? MODE_18 : (FMODE1_i ? MODE_18 : RMODE_B1_i));
-				ram_rmode_b2 = (RMODE_B1_i == MODE_36 ? MODE_18 : (FMODE1_i ? MODE_18 : RMODE_B1_i));
-				ram_wmode_b1 = (WMODE_B1_i == MODE_36 ? MODE_18 : WMODE_B1_i);
-				ram_wmode_b2 = (WMODE_B1_i == MODE_36 ? MODE_18 : WMODE_B1_i);
-			end
-			1: begin
-				ram_rmode_a1 = (RMODE_A1_i == MODE_36 ? MODE_18 : RMODE_A1_i);
-				ram_rmode_a2 = (RMODE_A2_i == MODE_36 ? MODE_18 : RMODE_A2_i);
-				ram_wmode_a1 = (WMODE_A1_i == MODE_36 ? MODE_18 : WMODE_A1_i);
-				ram_wmode_a2 = (WMODE_A2_i == MODE_36 ? MODE_18 : WMODE_A2_i);
-				ram_rmode_b1 = (RMODE_B1_i == MODE_36 ? MODE_18 : RMODE_B1_i);
-				ram_rmode_b2 = (RMODE_B2_i == MODE_36 ? MODE_18 : RMODE_B2_i);
-				ram_wmode_b1 = (WMODE_B1_i == MODE_36 ? MODE_18 : WMODE_B1_i);
-				ram_wmode_b2 = (WMODE_B2_i == MODE_36 ? MODE_18 : WMODE_B2_i);
-			end
-		endcase
+	always @(posedge CLK_A1_i or posedge CLK_B1_i or posedge CLK_A2_i or posedge CLK_B2_i) begin
+		if (!SPLIT_i) begin
+				ram_rmode_a1 <= (RMODE_A1_i == MODE_36 ? MODE_18 : RMODE_A1_i);
+				ram_rmode_a2 <= (RMODE_A1_i == MODE_36 ? MODE_18 : RMODE_A1_i);
+				ram_wmode_a1 <= (WMODE_A1_i == MODE_36 ? MODE_18 : (FMODE1_i ? MODE_18 : WMODE_A1_i));
+				ram_wmode_a2 <= (WMODE_A1_i == MODE_36 ? MODE_18 : (FMODE1_i ? MODE_18 : WMODE_A1_i));
+				ram_rmode_b1 <= (RMODE_B1_i == MODE_36 ? MODE_18 : (FMODE1_i ? MODE_18 : RMODE_B1_i));
+				ram_rmode_b2 <= (RMODE_B1_i == MODE_36 ? MODE_18 : (FMODE1_i ? MODE_18 : RMODE_B1_i));
+				ram_wmode_b1 <= (WMODE_B1_i == MODE_36 ? MODE_18 : WMODE_B1_i);
+				ram_wmode_b2 <= (WMODE_B1_i == MODE_36 ? MODE_18 : WMODE_B1_i);
+		end else begin
+				ram_rmode_a1 <= (RMODE_A1_i == MODE_36 ? MODE_18 : RMODE_A1_i);
+				ram_rmode_a2 <= (RMODE_A2_i == MODE_36 ? MODE_18 : RMODE_A2_i);
+				ram_wmode_a1 <= (WMODE_A1_i == MODE_36 ? MODE_18 : WMODE_A1_i);
+				ram_wmode_a2 <= (WMODE_A2_i == MODE_36 ? MODE_18 : WMODE_A2_i);
+				ram_rmode_b1 <= (RMODE_B1_i == MODE_36 ? MODE_18 : RMODE_B1_i);
+				ram_rmode_b2 <= (RMODE_B2_i == MODE_36 ? MODE_18 : RMODE_B2_i);
+				ram_wmode_b1 <= (WMODE_B1_i == MODE_36 ? MODE_18 : WMODE_B1_i);
+				ram_wmode_b2 <= (WMODE_B2_i == MODE_36 ? MODE_18 : WMODE_B2_i);
+		end
+	end
 	always @(*) begin : FIFO_READ_SEL
 		case (RMODE_B1_i)
 			MODE_36: fifo_rdata = {ram_rdata_b2[17:16], ram_rdata_b1[17:16], ram_rdata_b2[15:0], ram_rdata_b1[15:0]};
@@ -1115,19 +1093,24 @@
 	end
 	always @(posedge CLK_A1_i) laddr_a1 <= ADDR_A1_i;
 	always @(posedge CLK_B1_i) laddr_b1 <= ADDR_B1_i;
-	always @(*) begin
-		case (WMODE_A1_i)
-			default: fifo_wmode = 2'b00;
-			MODE_36: fifo_wmode = 2'b00;
-			MODE_18: fifo_wmode = 2'b01;
-			MODE_9: fifo_wmode = 2'b10;
-		endcase
-		case (RMODE_B1_i)
-			default: fifo_rmode = 2'b00;
-			MODE_36: fifo_rmode = 2'b00;
-			MODE_18: fifo_rmode = 2'b01;
-			MODE_9: fifo_rmode = 2'b10;
-		endcase
+	always @(posedge CLK_A1_i or posedge CLK_B1_i or posedge CLK_A2_i or posedge CLK_B2_i) begin
+		if (WMODE_A1_i == MODE_36)
+			fifo_wmode = 2'b00;
+		else if (WMODE_A1_i == MODE_18)
+			fifo_wmode = 2'b01;
+		else if (WMODE_A1_i == MODE_9)
+			fifo_wmode = 2'b10;
+		else
+			fifo_wmode = 2'b00;
+
+		if (RMODE_B1_i == MODE_36)
+			fifo_rmode = 2'b00;
+		else if (RMODE_B1_i == MODE_18)
+			fifo_rmode = 2'b01;
+		else if (RMODE_B1_i == MODE_9)
+			fifo_rmode = 2'b10;
+		else
+			fifo_rmode = 2'b00;
 	end
 	fifo_ctl #(
 		.ADDR_WIDTH(12),
@@ -1150,7 +1133,14 @@
 		.upaf(UPAF1_i),
 		.upae(UPAE1_i)
 	);
-	TDP18K_FIFO u1(
+	TDP18K_FIFO #(
+		.UPAF(UPAF1_i[10:0]),
+		.UPAE(UPAE1_i[10:0]),
+		.SYNC_FIFO(SYNC_FIFO1_i),
+		.POWERDN(POWERDN1_i),
+		.SLEEP(SLEEP1_i),
+		.PROTECT(PROTECT1_i)
+	)u1(
 		.RMODE_A(ram_rmode_a1),
 		.RMODE_B(ram_rmode_b1),
 		.WMODE_A(ram_wmode_a1),
@@ -1178,13 +1168,8 @@
 		.FWM(FWM1),
 		.OVERRUN(OVERRUN1),
 		.FLUSH(FLUSH1_i),
+		.RAM_ID({RAM_ID_i}),
 		.FMODE(ram_fmode1),
-		.UPAF(UPAF1_i[10:0]),
-		.UPAE(UPAE1_i[10:0]),
-		.SYNC_FIFO(SYNC_FIFO1_i),
-		.POWERDN(POWERDN1_i),
-		.SLEEP(SLEEP1_i),
-		.PROTECT(PROTECT1_i),
 		.PL_INIT(PL_INIT_i),
 		.PL_ENA(PL_ENA_i),
 		.PL_WEN(PL_WEN_i[0]),
@@ -1192,10 +1177,16 @@
 		.PL_CLK(PL_CLK_i),
 		.PL_ADDR(PL_ADDR_i),
 		.PL_DATA_IN({PL_DATA_i[33:32], PL_DATA_i[15:0]}),
-		.PL_DATA_OUT(pl_dout0),
-		.RAM_ID({RAM_ID_i})
+		.PL_DATA_OUT(pl_dout0)
 	);
-	TDP18K_FIFO u2(
+	TDP18K_FIFO #(
+		.UPAF(UPAF2_i[10:0]),
+		.UPAE(UPAE2_i[10:0]),
+		.SYNC_FIFO(SYNC_FIFO2_i),
+		.POWERDN(POWERDN2_i),
+		.SLEEP(SLEEP2_i),
+		.PROTECT(PROTECT2_i)
+	)u2(
 		.RMODE_A(ram_rmode_a2),
 		.RMODE_B(ram_rmode_b2),
 		.WMODE_A(ram_wmode_a2),
@@ -1223,13 +1214,8 @@
 		.FWM(FWM2),
 		.OVERRUN(OVERRUN2),
 		.FLUSH(FLUSH2_i),
+		.RAM_ID({RAM_ID_i}),
 		.FMODE(ram_fmode2),
-		.UPAF(UPAF2_i),
-		.UPAE(UPAE2_i),
-		.SYNC_FIFO(SYNC_FIFO2_i),
-		.POWERDN(POWERDN2_i),
-		.SLEEP(SLEEP2_i),
-		.PROTECT(PROTECT2_i),
 		.PL_INIT(PL_INIT_i),
 		.PL_ENA(PL_ENA_i),
 		.PL_WEN(PL_WEN_i[1]),
@@ -1237,8 +1223,7 @@
 		.PL_CLK(PL_CLK_i),
 		.PL_ADDR(PL_ADDR_i),
 		.PL_DATA_IN({PL_DATA_i[35:34], PL_DATA_i[31:16]}),
-		.PL_DATA_OUT(pl_dout1),
-		.RAM_ID(RAM_ID_i)
+		.PL_DATA_OUT(pl_dout1)
 	);
 	always @(*) begin
 		if (RAM_ID_i == PL_ADDR_i[31:16])
diff --git a/ql-qlf-plugin/tests/Makefile b/ql-qlf-plugin/tests/Makefile
index 77938e3..21b68b6 100644
--- a/ql-qlf-plugin/tests/Makefile
+++ b/ql-qlf-plugin/tests/Makefile
@@ -23,7 +23,7 @@
 	pp3_bram \
     qlf_k6n10f/dsp_mult \
     qlf_k6n10f/dsp_simd \
-    qlf_k6n10f/dsp_macc
+    qlf_k6n10f/dsp_macc \
 #	qlf_k6n10_bram \
 
 SIM_TESTS = \
@@ -31,6 +31,10 @@
     qlf_k6n10f/sim_dsp_mult_r \
     qlf_k6n10f/sim_dsp_fir
 
+# Those tests perform synthesis and simulation of synthesis results
+POST_SYNTH_SIM_TESTS = \
+    qlf_k6n10f/bram_tdp
+
 include $(shell pwd)/../../Makefile_test.common
 
 consts_verify = true
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram_tdp/bram_tdp.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/bram_tdp/bram_tdp.tcl
new file mode 100644
index 0000000..f3a5349
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram_tdp/bram_tdp.tcl
@@ -0,0 +1,50 @@
+yosys -import
+
+if { [info procs ql-qlf-k6n10f] == {} } { plugin -i ql-qlf }
+yosys -import  ;
+
+read_verilog $::env(DESIGN_TOP).v
+design -save bram_tdp
+
+select BRAM_TDP_32x512
+select *
+synth_quicklogic -family qlf_k6n10f -top BRAM_TDP_32x512
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/bram_tdp_32x512_post_synth.v
+select -assert-count 1 t:TDP_BRAM36
+
+select -clear
+design -load bram_tdp
+select BRAM_TDP_16x1024
+select *
+synth_quicklogic -family qlf_k6n10f -top BRAM_TDP_16x1024
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/bram_tdp_16x1024_post_synth.v
+select -assert-count 1 t:TDP_BRAM36
+
+select -clear
+design -load bram_tdp
+select BRAM_TDP_8x2048
+select *
+synth_quicklogic -family qlf_k6n10f -top BRAM_TDP_8x2048
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/bram_tdp_8x2048_post_synth.v
+select -assert-count 1 t:TDP_BRAM36
+
+select -clear
+design -load bram_tdp
+select BRAM_TDP_4x4096
+select *
+synth_quicklogic -family qlf_k6n10f -top BRAM_TDP_4x4096
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/bram_tdp_4x4096_post_synth.v
+select -assert-count 1 t:TDP_BRAM36
+
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram_tdp/bram_tdp.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram_tdp/bram_tdp.v
new file mode 100644
index 0000000..3486fa2
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram_tdp/bram_tdp.v
@@ -0,0 +1,284 @@
+// Copyright (C) 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
+
+module BRAM_TDP #(parameter AWIDTH = 9,
+parameter DWIDTH = 32)(
+	clk_a,
+	rce_a,
+	ra_a,
+	rq_a,
+	wce_a,
+	wa_a,
+	wd_a,
+
+	clk_b,
+	rce_b,
+	ra_b,
+	rq_b,
+	wce_b,
+	wa_b,
+	wd_b
+);
+
+	input			clk_a;
+	input                   rce_a;
+	input      [AWIDTH-1:0] ra_a;
+	output reg [DWIDTH-1:0] rq_a;
+	input                   wce_a;
+	input      [AWIDTH-1:0] wa_a;
+	input      [DWIDTH-1:0] wd_a;
+
+	input			clk_b;
+	input                   rce_b;
+	input      [AWIDTH-1:0] ra_b;
+	output reg [DWIDTH-1:0] rq_b;
+	input                   wce_b;
+	input      [AWIDTH-1:0] wa_b;
+	input      [DWIDTH-1:0] wd_b;
+
+	reg        [DWIDTH-1:0] memory[0:(1<<AWIDTH)-1];
+
+	always @(posedge clk_a) begin
+		if (rce_a)
+			rq_a <= memory[ra_a];
+
+		if (wce_a)
+			memory[wa_a] <= wd_a;
+	end
+
+	always @(posedge clk_b) begin
+		if (rce_b)
+			rq_b <= memory[ra_b];
+
+		if (wce_b)
+			memory[wa_b] <= wd_b;
+	end
+
+	integer i;
+	initial
+	begin
+		for(i = 0; i < (1<<AWIDTH)-1; i = i + 1)
+			memory[i] = 0;
+	end
+
+endmodule
+
+module BRAM_TDP_32x512(
+	clk_a,
+	rce_a,
+	ra_a,
+	rq_a,
+	wce_a,
+	wa_a,
+	wd_a,
+
+	clk_b,
+	rce_b,
+	ra_b,
+	rq_b,
+	wce_b,
+	wa_b,
+	wd_b
+);
+
+parameter AWIDTH = 9;
+parameter DWIDTH = 32;
+
+	input			clk_a;
+	input                   rce_a;
+	input      [AWIDTH-1:0] ra_a;
+	output     [DWIDTH-1:0] rq_a;
+	input                   wce_a;
+	input      [AWIDTH-1:0] wa_a;
+	input      [DWIDTH-1:0] wd_a;
+	input			clk_b;
+	input                   rce_b;
+	input      [AWIDTH-1:0] ra_b;
+	output     [DWIDTH-1:0] rq_b;
+	input                   wce_b;
+	input      [AWIDTH-1:0] wa_b;
+	input      [DWIDTH-1:0] wd_b;
+
+BRAM_TDP #(.AWIDTH(AWIDTH), .DWIDTH(DWIDTH))
+	BRAM_TDP_32x512 (.clk_a(clk_a),
+		 .rce_a(rce_a),
+		 .ra_a(ra_a),
+		 .rq_a(rq_a),
+		 .wce_a(wce_a),
+		 .wa_a(wa_a),
+		 .wd_a(wd_a),
+		 .clk_b(clk_b),
+		 .rce_b(rce_b),
+		 .ra_b(ra_b),
+		 .rq_b(rq_b),
+		 .wce_b(wce_b),
+		 .wa_b(wa_b),
+		 .wd_b(wd_b));
+
+endmodule
+
+module BRAM_TDP_16x1024(
+	clk_a,
+	rce_a,
+	ra_a,
+	rq_a,
+	wce_a,
+	wa_a,
+	wd_a,
+	clk_b,
+	rce_b,
+	ra_b,
+	rq_b,
+	wce_b,
+	wa_b,
+	wd_b
+);
+
+parameter AWIDTH = 10;
+parameter DWIDTH = 16;
+
+	input			clk_a;
+	input                   rce_a;
+	input      [AWIDTH-1:0] ra_a;
+	output     [DWIDTH-1:0] rq_a;
+	input                   wce_a;
+	input      [AWIDTH-1:0] wa_a;
+	input      [DWIDTH-1:0] wd_a;
+
+	input			clk_b;
+	input                   rce_b;
+	input      [AWIDTH-1:0] ra_b;
+	output     [DWIDTH-1:0] rq_b;
+	input                   wce_b;
+	input      [AWIDTH-1:0] wa_b;
+	input      [DWIDTH-1:0] wd_b;
+
+BRAM_TDP #(.AWIDTH(AWIDTH), .DWIDTH(DWIDTH))
+	BRAM_TDP_16x1024 (.clk_a(clk_a),
+		 .rce_a(rce_a),
+		 .ra_a(ra_a),
+		 .rq_a(rq_a),
+		 .wce_a(wce_a),
+		 .wa_a(wa_a),
+		 .wd_a(wd_a),
+		 .clk_b(clk_b),
+		 .rce_b(rce_b),
+		 .ra_b(ra_b),
+		 .rq_b(rq_b),
+		 .wce_b(wce_b),
+		 .wa_b(wa_b),
+		 .wd_b(wd_b));
+endmodule
+
+module BRAM_TDP_8x2048(
+	clk_a,
+	rce_a,
+	ra_a,
+	rq_a,
+	wce_a,
+	wa_a,
+	wd_a,
+
+	clk_b,
+	rce_b,
+	ra_b,
+	rq_b,
+	wce_b,
+	wa_b,
+	wd_b
+);
+
+parameter AWIDTH = 11;
+parameter DWIDTH = 8;
+
+	input			clk_a;
+	input                   rce_a;
+	input      [AWIDTH-1:0] ra_a;
+	output     [DWIDTH-1:0] rq_a;
+	input                   wce_a;
+	input      [AWIDTH-1:0] wa_a;
+	input      [DWIDTH-1:0] wd_a;
+
+	input			clk_b;
+	input                   rce_b;
+	input      [AWIDTH-1:0] ra_b;
+	output     [DWIDTH-1:0] rq_b;
+	input                   wce_b;
+	input      [AWIDTH-1:0] wa_b;
+	input      [DWIDTH-1:0] wd_b;
+
+BRAM_TDP #(.AWIDTH(AWIDTH), .DWIDTH(DWIDTH))
+	BRAM_TDP_8x2048 (.clk_a(clk_a),
+		 .rce_a(rce_a),
+		 .ra_a(ra_a),
+		 .rq_a(rq_a),
+		 .wce_a(wce_a),
+		 .wa_a(wa_a),
+		 .wd_a(wd_a),
+		 .clk_b(clk_b),
+		 .rce_b(rce_b),
+		 .ra_b(ra_b),
+		 .rq_b(rq_b),
+		 .wce_b(wce_b),
+		 .wa_b(wa_b),
+		 .wd_b(wd_b));
+endmodule
+
+module BRAM_TDP_4x4096(
+	clk_a,
+	rce_a,
+	ra_a,
+	rq_a,
+	wce_a,
+	wa_a,
+	wd_a,
+
+	clk_b,
+	rce_b,
+	ra_b,
+	rq_b,
+	wce_b,
+	wa_b,
+	wd_b
+);
+
+parameter AWIDTH = 12;
+parameter DWIDTH = 4;
+
+	input			clk_a;
+	input                   rce_a;
+	input      [AWIDTH-1:0] ra_a;
+	output     [DWIDTH-1:0] rq_a;
+	input                   wce_a;
+	input      [AWIDTH-1:0] wa_a;
+	input      [DWIDTH-1:0] wd_a;
+
+	input			clk_b;
+	input                   rce_b;
+	input      [AWIDTH-1:0] ra_b;
+	output     [DWIDTH-1:0] rq_b;
+	input                   wce_b;
+	input      [AWIDTH-1:0] wa_b;
+	input      [DWIDTH-1:0] wd_b;
+
+BRAM_TDP #(.AWIDTH(AWIDTH), .DWIDTH(DWIDTH))
+	BRAM_TDP_4x4096 (.clk_a(clk_a),
+		 .rce_a(rce_a),
+		 .ra_a(ra_a),
+		 .rq_a(rq_a),
+		 .wce_a(wce_a),
+		 .wa_a(wa_a),
+		 .wd_a(wd_a),
+		 .clk_b(clk_b),
+		 .rce_b(rce_b),
+		 .ra_b(ra_b),
+		 .rq_b(rq_b),
+		 .wce_b(wce_b),
+		 .wa_b(wa_b),
+		 .wd_b(wd_b));
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram_tdp/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/bram_tdp/sim/Makefile
new file mode 100644
index 0000000..06b45cc
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram_tdp/sim/Makefile
@@ -0,0 +1,35 @@
+# Copyright (C) 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 = bram_tdp_tb.v
+POST_SYNTH = bram_tdp_32x512_post_synth bram_tdp_16x1024_post_synth bram_tdp_8x2048_post_synth bram_tdp_4x4096_post_synth
+ADDR_WIDTH = 9 10 11 12
+DATA_WIDTH = 32 16 8 4
+TOP = BRAM_TDP_32x512 BRAM_TDP_16x1024 BRAM_TDP_8x2048 BRAM_TDP_4x4096
+TEST_CASES = $(seq 0 3)
+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
+
+sim:
+	$(call simulate_post_synth,1)
+	$(call simulate_post_synth,2)
+	$(call simulate_post_synth,3)
+	$(call simulate_post_synth,4)
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram_tdp/sim/bram_tdp_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram_tdp/sim/bram_tdp_tb.v
new file mode 100644
index 0000000..90cbf4e
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram_tdp/sim/bram_tdp_tb.v
@@ -0,0 +1,227 @@
+// Copyright (C) 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;
+	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))
+		"BRAM_TDP_32x512": begin
+			BRAM_TDP_32x512 #() bram (
+				.clk_a(clk_a),
+				.rce_a(rce_a),
+				.ra_a(ra_a),
+				.rq_a(rq_a),
+				.wce_a(wce_a),
+				.wa_a(wa_a),
+				.wd_a(wd_a),
+				.clk_b(clk_b),
+				.rce_b(rce_b),
+				.ra_b(ra_b),
+				.rq_b(rq_b),
+				.wce_b(wce_b),
+				.wa_b(wa_b),
+				.wd_b(wd_b)
+			);
+		end
+		"BRAM_TDP_16x1024": begin
+			BRAM_TDP_16x1024 #() bram (
+				.clk_a(clk_a),
+				.rce_a(rce_a),
+				.ra_a(ra_a),
+				.rq_a(rq_a),
+				.wce_a(wce_a),
+				.wa_a(wa_a),
+				.wd_a(wd_a),
+				.clk_b(clk_b),
+				.rce_b(rce_b),
+				.ra_b(ra_b),
+				.rq_b(rq_b),
+				.wce_b(wce_b),
+				.wa_b(wa_b),
+				.wd_b(wd_b)
+			);
+		end
+		"BRAM_TDP_8x2048": begin
+			BRAM_TDP_8x2048 #() bram (
+				.clk_a(clk_a),
+				.rce_a(rce_a),
+				.ra_a(ra_a),
+				.rq_a(rq_a),
+				.wce_a(wce_a),
+				.wa_a(wa_a),
+				.wd_a(wd_a),
+				.clk_b(clk_b),
+				.rce_b(rce_b),
+				.ra_b(ra_b),
+				.rq_b(rq_b),
+				.wce_b(wce_b),
+				.wa_b(wa_b),
+				.wd_b(wd_b)
+			);
+		end
+		"BRAM_TDP_4x4096": begin
+			BRAM_TDP_4x4096 #() bram (
+				.clk_a(clk_a),
+				.rce_a(rce_a),
+				.ra_a(ra_a),
+				.rq_a(rq_a),
+				.wce_a(wce_a),
+				.wa_a(wa_a),
+				.wd_a(wd_a),
+				.clk_b(clk_b),
+				.rce_b(rce_b),
+				.ra_b(ra_b),
+				.rq_b(rq_b),
+				.wce_b(wce_b),
+				.wa_b(wa_b),
+				.wd_b(wd_b)
+			);
+		end
+	endcase
+endmodule