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