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