Merge pull request #276 from antmicro/rename-uhdm-plugin
Rename the uhdm plugin to systemverilog
diff --git a/ql-qlf-plugin/qlf_k6n10f/arith_map.v b/ql-qlf-plugin/qlf_k6n10f/arith_map.v
index c5dd221..0d97131 100644
--- a/ql-qlf-plugin/qlf_k6n10f/arith_map.v
+++ b/ql-qlf-plugin/qlf_k6n10f/arith_map.v
@@ -60,7 +60,8 @@
);
endgenerate
genvar i;
- generate for (i = 0; i < Y_WIDTH-2; i = i + 1) begin:slice
+ generate if (Y_WIDTH > 2) begin
+ for (i = 0; i < Y_WIDTH-2; i = i + 1) begin:slice
adder_carry my_adder (
.cin(C[i]),
.g(AA[i]),
@@ -68,6 +69,7 @@
.cout(C[i+1]),
.sumout(Y[i])
);
+ end
end endgenerate
generate
adder_carry final_adder (
diff --git a/ql-qlf-plugin/qlf_k6n10f/brams.txt b/ql-qlf-plugin/qlf_k6n10f/brams.txt
index b8ba985..6951a4a 100644
--- a/ql-qlf-plugin/qlf_k6n10f/brams.txt
+++ b/ql-qlf-plugin/qlf_k6n10f/brams.txt
@@ -23,10 +23,49 @@
clkpol 1 1 1 1
endbram
+bram $__QLF_FACTOR_BRAM36_SDP
+ init 1
+ abits 10 @a10d36
+ dbits 36 @a10d36
+ abits 11 @a11d18
+ dbits 18 @a11d18
+ abits 12 @a12d9
+ dbits 9 @a12d9
+ abits 13 @a13d4
+ dbits 4 @a13d4
+ abits 14 @a14d2
+ 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
+
match $__QLF_FACTOR_BRAM36_TDP
- max dbits 36
- max abits 15
+ min wports 1
+ max wports 2
+ min rports 1
+ max rports 2
+ min efficiency 1
+ min bits 128
+ shuffle_enable B
+ make_transp
+ or_next_if_better
+endmatch
+
+match $__QLF_FACTOR_BRAM36_SDP
+ max wports 1
+ max rports 1
+ min efficiency 1
+ min bits 128
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 59fbdd7..a98d7f0 100644
--- a/ql-qlf-plugin/qlf_k6n10f/brams_map.v
+++ b/ql-qlf-plugin/qlf_k6n10f/brams_map.v
@@ -109,8 +109,8 @@
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);
+ assign PORT_A_ADDR = A1EN ? (A1ADDR_TOTAL << 2) : (B1EN ? (B1ADDR_TOTAL << 2) : 15'd0);
+ assign PORT_B_ADDR = C1EN ? (C1ADDR_TOTAL << 2) : (D1EN ? (D1ADDR_TOTAL << 2) : 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;
@@ -374,3 +374,248 @@
);
end endgenerate
endmodule
+
+module \$__QLF_FACTOR_BRAM36_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+ parameter CFG_ABITS = 10;
+ parameter CFG_DBITS = 36;
+ parameter CFG_ENABLE_B = 4;
+
+ parameter CLKPOL2 = 1;
+ parameter CLKPOL3 = 1;
+ parameter [36863:0] INIT = 36864'bx;
+
+ localparam MODE_36 = 3'b111; // 36 or 32-bit
+ localparam MODE_18 = 3'b110; // 18 or 16-bit
+ localparam MODE_9 = 3'b101; // 9 or 8-bit
+ localparam MODE_4 = 3'b100; // 4-bit
+ localparam MODE_2 = 3'b010; // 32-bit
+ localparam MODE_1 = 3'b001; // 32-bit
+
+ input CLK2;
+ input CLK3;
+
+ input [CFG_ABITS-1:0] A1ADDR;
+ output [CFG_DBITS-1:0] A1DATA;
+ input A1EN;
+
+ input [CFG_ABITS-1:0] B1ADDR;
+ input [CFG_DBITS-1:0] B1DATA;
+ input [CFG_ENABLE_B-1:0] B1EN;
+
+ wire [14:0] A1ADDR_15;
+ wire [14:0] B1ADDR_15;
+
+ wire [35:0] DOBDO;
+
+ wire [14:CFG_ABITS] A1ADDR_CMPL;
+ wire [14:CFG_ABITS] B1ADDR_CMPL;
+ wire [35:CFG_DBITS] A1DATA_CMPL;
+ wire [35:CFG_DBITS] B1DATA_CMPL;
+
+ wire [14:0] A1ADDR_TOTAL;
+ wire [14:0] B1ADDR_TOTAL;
+ wire [35:0] A1DATA_TOTAL;
+ wire [35:0] B1DATA_TOTAL;
+
+ wire FLUSH1;
+ wire FLUSH2;
+ wire [15:0] RAM_ID;
+
+ 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;
+
+ wire [2:0] WMODE;
+ wire [2:0] RMODE;
+
+ assign A1ADDR_CMPL = {15-CFG_ABITS{1'b0}};
+ assign B1ADDR_CMPL = {15-CFG_ABITS{1'b0}};
+
+ assign A1ADDR_TOTAL = {A1ADDR_CMPL, A1ADDR};
+ assign B1ADDR_TOTAL = {B1ADDR_CMPL, B1ADDR};
+
+ assign A1DATA_TOTAL = {A1DATA_CMPL, A1DATA};
+ assign B1DATA_TOTAL = {B1DATA_CMPL, B1DATA};
+
+ case (CFG_DBITS)
+ 1: begin
+ assign A1ADDR_15 = A1ADDR_TOTAL;
+ assign B1ADDR_15 = B1ADDR_TOTAL;
+ 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 A1ADDR_15 = A1ADDR_TOTAL << 1;
+ assign B1ADDR_15 = B1ADDR_TOTAL << 1;
+ 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 A1ADDR_15 = A1ADDR_TOTAL << 2;
+ assign B1ADDR_15 = B1ADDR_TOTAL << 2;
+ 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 A1ADDR_15 = A1ADDR_TOTAL << 3;
+ assign B1ADDR_15 = B1ADDR_TOTAL << 3;
+ 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 A1ADDR_15 = A1ADDR_TOTAL << 4;
+ assign B1ADDR_15 = B1ADDR_TOTAL << 4;
+ 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 A1ADDR_15 = A1ADDR_TOTAL << 5;
+ assign B1ADDR_15 = B1ADDR_TOTAL << 5;
+ 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 A1ADDR_15 = A1ADDR_TOTAL;
+ assign B1ADDR_15 = B1ADDR_TOTAL;
+ 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 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(18'h3FFFF),
+ .WDATA_A2_i(18'h3FFFF),
+ .RDATA_A1_o(A1DATA_TOTAL[17:0]),
+ .RDATA_A2_o(A1DATA_TOTAL[35:18]),
+ .ADDR_A1_i(A1ADDR_15),
+ .ADDR_A2_i(A1ADDR_15),
+ .CLK_A1_i(CLK2),
+ .CLK_A2_i(CLK2),
+ .REN_A1_i(A1EN),
+ .REN_A2_i(A1EN),
+ .WEN_A1_i(1'b0),
+ .WEN_A2_i(1'b0),
+ .BE_A1_i({A1EN, A1EN}),
+ .BE_A2_i({A1EN, A1EN}),
+
+ .WDATA_B1_i(B1DATA[17:0]),
+ .WDATA_B2_i(B1DATA[35:18]),
+ .RDATA_B1_o(DOBDO[17:0]),
+ .RDATA_B2_o(DOBDO[35:18]),
+ .ADDR_B1_i(B1ADDR_15),
+ .ADDR_B2_i(B1ADDR_15),
+ .CLK_B1_i(CLK3),
+ .CLK_B2_i(CLK3),
+ .REN_B1_i(1'b0),
+ .REN_B2_i(1'b0),
+ .WEN_B1_i(B1EN[0]),
+ .WEN_B2_i(B1EN[0]),
+ .BE_B1_i(B1EN[1:0]),
+ .BE_B2_i(B1EN[3: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/tests/Makefile b/ql-qlf-plugin/tests/Makefile
index 21b68b6..639fb63 100644
--- a/ql-qlf-plugin/tests/Makefile
+++ b/ql-qlf-plugin/tests/Makefile
@@ -33,7 +33,8 @@
# Those tests perform synthesis and simulation of synthesis results
POST_SYNTH_SIM_TESTS = \
- qlf_k6n10f/bram_tdp
+ qlf_k6n10f/bram_tdp \
+ qlf_k6n10f/bram_sdp
include $(shell pwd)/../../Makefile_test.common
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram_sdp/bram_sdp.tcl b/ql-qlf-plugin/tests/qlf_k6n10f/bram_sdp/bram_sdp.tcl
new file mode 100644
index 0000000..5e9379e
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram_sdp/bram_sdp.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_sdp
+
+select BRAM_SDP_32x512
+select *
+synth_quicklogic -family qlf_k6n10f -top BRAM_SDP_32x512
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/bram_sdp_32x512_post_synth.v
+select -assert-count 1 t:TDP_BRAM36
+
+select -clear
+design -load bram_sdp
+select BRAM_SDP_16x1024
+select *
+synth_quicklogic -family qlf_k6n10f -top BRAM_SDP_16x1024
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/bram_sdp_16x1024_post_synth.v
+select -assert-count 1 t:TDP_BRAM36
+
+select -clear
+design -load bram_sdp
+select BRAM_SDP_8x2048
+select *
+synth_quicklogic -family qlf_k6n10f -top BRAM_SDP_8x2048
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/bram_sdp_8x2048_post_synth.v
+select -assert-count 1 t:TDP_BRAM36
+
+select -clear
+design -load bram_sdp
+select BRAM_SDP_4x4096
+select *
+synth_quicklogic -family qlf_k6n10f -top BRAM_SDP_4x4096
+opt_expr -undriven
+opt_clean
+stat
+write_verilog sim/bram_sdp_4x4096_post_synth.v
+select -assert-count 1 t:TDP_BRAM36
+
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram_sdp/bram_sdp.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram_sdp/bram_sdp.v
new file mode 100644
index 0000000..8433c56
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram_sdp/bram_sdp.v
@@ -0,0 +1,177 @@
+// 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_SDP #(parameter AWIDTH = 9,
+parameter DWIDTH = 32)(
+ clk,
+ rce,
+ ra,
+ rq,
+ wce,
+ wa,
+ wd
+);
+
+ input clk;
+
+ input rce;
+ input [AWIDTH-1:0] ra;
+ output reg [DWIDTH-1:0] rq;
+
+ input wce;
+ input [AWIDTH-1:0] wa;
+ input [DWIDTH-1:0] wd;
+
+ reg [DWIDTH-1:0] memory[0:(1<<AWIDTH)-1];
+
+ always @(posedge clk) begin
+ if (rce)
+ rq <= memory[ra];
+
+ if (wce)
+ memory[wa] <= wd;
+ end
+
+ integer i;
+ initial
+ begin
+ for(i = 0; i < (1<<AWIDTH)-1; i = i + 1)
+ memory[i] = 0;
+ end
+
+endmodule
+
+module BRAM_SDP_32x512(
+ clk,
+ rce,
+ ra,
+ rq,
+ wce,
+ wa,
+ wd
+);
+
+parameter AWIDTH = 9;
+parameter DWIDTH = 32;
+
+ input clk;
+ input rce;
+ input [AWIDTH-1:0] ra;
+ output [DWIDTH-1:0] rq;
+ input wce;
+ input [AWIDTH-1:0] wa;
+ input [DWIDTH-1:0] wd;
+
+BRAM_SDP #(.AWIDTH(AWIDTH), .DWIDTH(DWIDTH))
+ BRAM_32x512 (.clk(clk),
+ .rce(rce),
+ .ra(ra),
+ .rq(rq),
+ .wce(wce),
+ .wa(wa),
+ .wd(wd));
+
+endmodule
+
+module BRAM_SDP_16x1024(
+ clk,
+ rce,
+ ra,
+ rq,
+ wce,
+ wa,
+ wd
+);
+
+parameter AWIDTH = 10;
+parameter DWIDTH = 16;
+
+ input clk;
+ input rce;
+ input [AWIDTH-1:0] ra;
+ output [DWIDTH-1:0] rq;
+ input wce;
+ input [AWIDTH-1:0] wa;
+ input [DWIDTH-1:0] wd;
+
+BRAM_SDP #(.AWIDTH(AWIDTH), .DWIDTH(DWIDTH))
+ BRAM_16x1024 (.clk(clk),
+ .rce(rce),
+ .ra(ra),
+ .rq(rq),
+ .wce(wce),
+ .wa(wa),
+ .wd(wd));
+
+
+endmodule
+
+module BRAM_SDP_8x2048(
+ clk,
+ rce,
+ ra,
+ rq,
+ wce,
+ wa,
+ wd
+);
+
+parameter AWIDTH = 11;
+parameter DWIDTH = 8;
+
+ input clk;
+ input rce;
+ input [AWIDTH-1:0] ra;
+ output [DWIDTH-1:0] rq;
+ input wce;
+ input [AWIDTH-1:0] wa;
+ input [DWIDTH-1:0] wd;
+
+BRAM_SDP #(.AWIDTH(AWIDTH), .DWIDTH(DWIDTH))
+ BRAM_8x2048 (.clk(clk),
+ .rce(rce),
+ .ra(ra),
+ .rq(rq),
+ .wce(wce),
+ .wa(wa),
+ .wd(wd));
+
+
+endmodule
+
+module BRAM_SDP_4x4096(
+ clk,
+ rce,
+ ra,
+ rq,
+ wce,
+ wa,
+ wd
+);
+
+parameter AWIDTH = 12;
+parameter DWIDTH = 4;
+
+ input clk;
+ input rce;
+ input [AWIDTH-1:0] ra;
+ output [DWIDTH-1:0] rq;
+ input wce;
+ input [AWIDTH-1:0] wa;
+ input [DWIDTH-1:0] wd;
+
+BRAM_SDP #(.AWIDTH(AWIDTH), .DWIDTH(DWIDTH))
+ BRAM_4x4096 (.clk(clk),
+ .rce(rce),
+ .ra(ra),
+ .rq(rq),
+ .wce(wce),
+ .wa(wa),
+ .wd(wd));
+
+endmodule
diff --git a/ql-qlf-plugin/tests/qlf_k6n10f/bram_sdp/sim/Makefile b/ql-qlf-plugin/tests/qlf_k6n10f/bram_sdp/sim/Makefile
new file mode 100644
index 0000000..0c9bab3
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram_sdp/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_sdp_tb.v
+POST_SYNTH = bram_sdp_32x512_post_synth bram_sdp_16x1024_post_synth bram_sdp_8x2048_post_synth bram_sdp_4x4096_post_synth
+ADDR_WIDTH = 9 10 11 12
+DATA_WIDTH = 32 16 8 4
+TOP = BRAM_SDP_32x512 BRAM_SDP_16x1024 BRAM_SDP_8x2048 BRAM_SDP_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_sdp/sim/bram_sdp_tb.v b/ql-qlf-plugin/tests/qlf_k6n10f/bram_sdp/sim/bram_sdp_tb.v
new file mode 100644
index 0000000..d5af767
--- /dev/null
+++ b/ql-qlf-plugin/tests/qlf_k6n10f/bram_sdp/sim/bram_sdp_tb.v
@@ -0,0 +1,140 @@
+// 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;
+ 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))
+ "BRAM_SDP_32x512": begin
+ BRAM_SDP_32x512 #() bram (
+ .clk(clk),
+ .rce(rce),
+ .ra(ra),
+ .rq(rq),
+ .wce(wce),
+ .wa(wa),
+ .wd(wd)
+ );
+ end
+ "BRAM_SDP_16x1024": begin
+ BRAM_SDP_16x1024 #() bram (
+ .clk(clk),
+ .rce(rce),
+ .ra(ra),
+ .rq(rq),
+ .wce(wce),
+ .wa(wa),
+ .wd(wd)
+ );
+ end
+ "BRAM_SDP_8x2048": begin
+ BRAM_SDP_8x2048 #() bram (
+ .clk(clk),
+ .rce(rce),
+ .ra(ra),
+ .rq(rq),
+ .wce(wce),
+ .wa(wa),
+ .wd(wd)
+ );
+ end
+ "BRAM_SDP_4x4096": begin
+ BRAM_SDP_4x4096 #() bram (
+ .clk(clk),
+ .rce(rce),
+ .ra(ra),
+ .rq(rq),
+ .wce(wce),
+ .wa(wa),
+ .wd(wd)
+ );
+ end
+ endcase
+endmodule