diff options
Diffstat (limited to 'techlibs')
| -rw-r--r-- | techlibs/common/Makefile.inc | 1 | ||||
| -rw-r--r-- | techlibs/common/mul2dsp.v | 273 | ||||
| -rw-r--r-- | techlibs/ecp5/Makefile.inc | 1 | ||||
| -rw-r--r-- | techlibs/ecp5/dsp_map.v | 10 | ||||
| -rw-r--r-- | techlibs/ecp5/synth_ecp5.cc | 33 | ||||
| -rw-r--r-- | techlibs/ice40/cells_sim.v | 16 | ||||
| -rw-r--r-- | techlibs/ice40/synth_ice40.cc | 4 | ||||
| -rw-r--r-- | techlibs/ice40/tests/test_dsp_model.sh | 9 | ||||
| -rw-r--r-- | techlibs/ice40/tests/test_dsp_model.v | 225 | ||||
| -rw-r--r-- | techlibs/xilinx/Makefile.inc | 1 | ||||
| -rw-r--r-- | techlibs/xilinx/cells_sim.v | 147 | ||||
| -rw-r--r-- | techlibs/xilinx/cells_xtra.v | 82 | ||||
| -rw-r--r-- | techlibs/xilinx/dsp_map.v | 46 | ||||
| -rw-r--r-- | techlibs/xilinx/synth_xilinx.cc | 24 | 
14 files changed, 775 insertions, 97 deletions
| diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc index 0e05620bc..e6d1c2f29 100644 --- a/techlibs/common/Makefile.inc +++ b/techlibs/common/Makefile.inc @@ -28,3 +28,4 @@ $(eval $(call add_share_file,share,techlibs/common/dff2ff.v))  $(eval $(call add_share_file,share,techlibs/common/gate2lut.v))  $(eval $(call add_share_file,share,techlibs/common/cmp2lut.v))  $(eval $(call add_share_file,share,techlibs/common/cells.lib)) +$(eval $(call add_share_file,share,techlibs/common/mul2dsp.v)) diff --git a/techlibs/common/mul2dsp.v b/techlibs/common/mul2dsp.v new file mode 100644 index 000000000..5444d842a --- /dev/null +++ b/techlibs/common/mul2dsp.v @@ -0,0 +1,273 @@ +// From Eddie Hung
 +// extracted from: https://github.com/eddiehung/vtr-with-yosys/blob/vtr7-with-yosys/vtr_flow/misc/yosys_models.v#L220
 +// revised by Andre DeHon
 +// further revised by David Shah
 +`ifndef DSP_A_MAXWIDTH
 +$error("Macro DSP_A_MAXWIDTH must be defined");
 +`endif
 +`ifndef DSP_B_MAXWIDTH
 +$error("Macro DSP_B_MAXWIDTH must be defined");
 +`endif
 +
 +`ifndef DSP_NAME
 +$error("Macro DSP_NAME must be defined");
 +`endif
 +
 +`define MAX(a,b) (a > b ? a : b)
 +`define MIN(a,b) (a < b ? a : b)
 +
 +module \$mul (A, B, Y); 
 +	parameter A_SIGNED = 0;
 +	parameter B_SIGNED = 0;
 +	parameter A_WIDTH = 1;
 +	parameter B_WIDTH = 1;
 +	parameter Y_WIDTH = 1;
 +
 +	input [A_WIDTH-1:0] A;
 +	input [B_WIDTH-1:0] B;
 +	output [Y_WIDTH-1:0] Y;
 +
 +	generate
 +	if (A_SIGNED != B_SIGNED)
 +		wire _TECHMAP_FAIL_ = 1;
 +	else if (A_WIDTH <= `DSP_A_MAXWIDTH && B_WIDTH <= `DSP_B_MAXWIDTH)
 +		wire _TECHMAP_FAIL_ = 1;
 +	// NB: A_SIGNED == B_SIGNED == 0 from here
 +	else if (A_WIDTH >= B_WIDTH)
 +		\$__mul #(
 +			.A_SIGNED(A_SIGNED),
 +			.B_SIGNED(B_SIGNED),
 +			.A_WIDTH(A_WIDTH),
 +			.B_WIDTH(B_WIDTH),
 +			.Y_WIDTH(Y_WIDTH)
 +		) _TECHMAP_REPLACE_ (
 +			.A(A),
 +			.B(B),
 +			.Y(Y)
 +		);
 +	else
 +		\$__mul #(
 +			.A_SIGNED(B_SIGNED),
 +			.B_SIGNED(A_SIGNED),
 +			.A_WIDTH(B_WIDTH),
 +			.B_WIDTH(A_WIDTH),
 +			.Y_WIDTH(Y_WIDTH)
 +		) _TECHMAP_REPLACE_ (
 +			.A(B),
 +			.B(A),
 +			.Y(Y)
 +		);
 +	endgenerate
 +endmodule
 +
 +module \$__mul (A, B, Y);
 +	parameter A_SIGNED = 0;
 +	parameter B_SIGNED = 0;
 +	parameter A_WIDTH = 1;
 +	parameter B_WIDTH = 1;
 +	parameter Y_WIDTH = 1;
 +
 +	input [A_WIDTH-1:0] A;
 +	input [B_WIDTH-1:0] B;
 +	output [Y_WIDTH-1:0] Y;
 +
 +	wire [1023:0] _TECHMAP_DO_ = "proc; clean";
 +
 +`ifdef DSP_SIGNEDONLY
 +	localparam sign_headroom = 1;
 +`else
 +	localparam sign_headroom = 0;
 +`endif
 +
 +	genvar i;
 +	generate
 +		if (A_WIDTH <= 1 || B_WIDTH <= 1)
 +			wire _TECHMAP_FAIL_ = 1;
 +`ifdef DSP_MINWIDTH
 +		else if (A_WIDTH+B_WIDTH < `DSP_MINWIDTH || Y_WIDTH < `DSP_MINWIDTH)
 +			wire _TECHMAP_FAIL_ = 1;
 +`endif
 +		else if (A_WIDTH > `DSP_A_MAXWIDTH) begin
 +			localparam n = (A_WIDTH+`DSP_A_MAXWIDTH-sign_headroom-1) / (`DSP_A_MAXWIDTH-sign_headroom);
 +			localparam partial_Y_WIDTH = `MIN(Y_WIDTH, B_WIDTH+`DSP_A_MAXWIDTH);
 +			if (A_SIGNED && B_SIGNED) begin
 +				wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
 +				wire signed [Y_WIDTH-1:0] partial_sum [n-1:0];
 +			end
 +			else begin
 +				wire [partial_Y_WIDTH-1:0] partial [n-1:0];
 +				wire [Y_WIDTH-1:0] partial_sum [n-1:0];
 +			end
 +
 +			\$__mul #(
 +				.A_SIGNED(sign_headroom),
 +				.B_SIGNED(B_SIGNED),
 +				.A_WIDTH(`DSP_A_MAXWIDTH),
 +				.B_WIDTH(B_WIDTH),
 +				.Y_WIDTH(partial_Y_WIDTH)
 +			) mul_slice_first (
 +				.A({{sign_headroom{1'b0}}, A[`DSP_A_MAXWIDTH-sign_headroom-1 : 0]}),
 +				.B(B),
 +				.Y(partial[0])
 +			);
 +			assign partial_sum[0] = partial[0];
 +
 +			for (i = 1; i < n-1; i=i+1) begin:slice
 +				\$__mul #(
 +					.A_SIGNED(sign_headroom),
 +					.B_SIGNED(B_SIGNED),
 +					.A_WIDTH(`DSP_A_MAXWIDTH),
 +					.B_WIDTH(B_WIDTH),
 +					.Y_WIDTH(partial_Y_WIDTH)
 +				) mul_slice (
 +					.A({{sign_headroom{1'b0}}, A[i*(`DSP_A_MAXWIDTH-sign_headroom) +: `DSP_A_MAXWIDTH-sign_headroom]}),
 +					.B(B),
 +					.Y(partial[i])
 +				);
 +				assign partial_sum[i] = (partial[i] << i*(`DSP_A_MAXWIDTH-sign_headroom)) + partial_sum[i-1];
 +			end
 +
 +			\$__mul #(
 +				.A_SIGNED(A_SIGNED),
 +				.B_SIGNED(B_SIGNED),
 +				.A_WIDTH(A_WIDTH-(n-1)*(`DSP_A_MAXWIDTH-sign_headroom)),
 +				.B_WIDTH(B_WIDTH),
 +				.Y_WIDTH(partial_Y_WIDTH)
 +			) mul_slice_last (
 +				.A(A[A_WIDTH-1 : (n-1)*(`DSP_A_MAXWIDTH-sign_headroom)]),
 +				.B(B),
 +				.Y(partial[n-1])
 +			);
 +			assign partial_sum[n-1] = (partial[n-1] << (n-1)*(`DSP_A_MAXWIDTH-sign_headroom)) + partial_sum[n-2];
 +			assign Y = partial_sum[n-1];
 +		end
 +		else if (B_WIDTH > `DSP_B_MAXWIDTH) begin
 +			localparam n = (B_WIDTH+`DSP_B_MAXWIDTH-sign_headroom-1) / (`DSP_B_MAXWIDTH-sign_headroom);
 +			localparam partial_Y_WIDTH = `MIN(Y_WIDTH, A_WIDTH+`DSP_B_MAXWIDTH);
 +			if (A_SIGNED && B_SIGNED) begin
 +				wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
 +				wire signed [Y_WIDTH-1:0] partial_sum [n-1:0];
 +			end
 +			else begin
 +				wire [partial_Y_WIDTH-1:0] partial [n-1:0];
 +				wire [Y_WIDTH-1:0] partial_sum [n-1:0];
 +			end
 +
 +			\$__mul #(
 +				.A_SIGNED(A_SIGNED),
 +				.B_SIGNED(sign_headroom),
 +				.A_WIDTH(A_WIDTH),
 +				.B_WIDTH(`DSP_B_MAXWIDTH),
 +				.Y_WIDTH(partial_Y_WIDTH)
 +			) mul_first (
 +				.A(A),
 +				.B({{sign_headroom{1'b0}}, B[`DSP_B_MAXWIDTH-sign_headroom-1 : 0]}),
 +				.Y(partial[0])
 +			);
 +			assign partial_sum[0] = partial[0];
 +
 +			for (i = 1; i < n-1; i=i+1) begin:slice
 +				\$__mul #(
 +					.A_SIGNED(A_SIGNED),
 +					.B_SIGNED(sign_headroom),
 +					.A_WIDTH(A_WIDTH),
 +					.B_WIDTH(`DSP_B_MAXWIDTH),
 +					.Y_WIDTH(partial_Y_WIDTH)
 +				) mul (
 +					.A(A),
 +					.B({{sign_headroom{1'b0}}, B[i*(`DSP_B_MAXWIDTH-sign_headroom) +: `DSP_B_MAXWIDTH-sign_headroom]}),
 +					.Y(partial[i])
 +				);
 +				assign partial_sum[i] = (partial[i] << i*(`DSP_B_MAXWIDTH-sign_headroom)) + partial_sum[i-1];
 +			end
 +
 +			\$__mul #(
 +				.A_SIGNED(A_SIGNED),
 +				.B_SIGNED(B_SIGNED),
 +				.A_WIDTH(A_WIDTH),
 +				.B_WIDTH(B_WIDTH-(n-1)*(`DSP_B_MAXWIDTH-sign_headroom)),
 +				.Y_WIDTH(partial_Y_WIDTH)
 +			) mul_last (
 +				.A(A),
 +				.B(B[B_WIDTH-1 : (n-1)*(`DSP_B_MAXWIDTH-sign_headroom)]),
 +				.Y(partial[n-1])
 +			);
 +			assign partial_sum[n-1] = (partial[n-1] << (n-1)*(`DSP_B_MAXWIDTH-sign_headroom)) + partial_sum[n-2];
 +			assign Y = partial_sum[n-1];
 +		end
 +		else begin 
 +			if (A_SIGNED)
 +				wire signed [`DSP_A_MAXWIDTH-1:0] Aext = $signed(A);
 +			else
 +				wire [`DSP_A_MAXWIDTH-1:0] Aext = A;
 +			if (B_SIGNED)
 +				wire signed [`DSP_B_MAXWIDTH-1:0] Bext = $signed(B);
 +			else
 +				wire [`DSP_B_MAXWIDTH-1:0] Bext = B;
 +
 +			`DSP_NAME #(
 +				.A_SIGNED(A_SIGNED),
 +				.B_SIGNED(B_SIGNED),
 +				.A_WIDTH(`DSP_A_MAXWIDTH),
 +				.B_WIDTH(`DSP_B_MAXWIDTH),
 +				.Y_WIDTH(`MIN(Y_WIDTH,`DSP_A_MAXWIDTH+`DSP_B_MAXWIDTH)),
 +			) _TECHMAP_REPLACE_ (
 +				.A(Aext),
 +				.B(Bext),
 +				.Y(Y)
 +			);
 +		end
 +	endgenerate
 +endmodule
 +
 +(* techmap_celltype = "$__mul" *)
 +module _90_internal_mul_to_external (A, B, Y); 
 +	parameter A_SIGNED = 0;
 +	parameter B_SIGNED = 0;
 +	parameter A_WIDTH = 1;
 +	parameter B_WIDTH = 1;
 +	parameter Y_WIDTH = 1;
 +
 +	input [A_WIDTH-1:0] A;
 +	input [B_WIDTH-1:0] B;
 +	output [Y_WIDTH-1:0] Y;
 +
 +	generate
 +		if (A_SIGNED && !B_SIGNED)
 +			\$mul #(
 +				.A_SIGNED(A_SIGNED),
 +				.B_SIGNED(1),
 +				.A_WIDTH(A_WIDTH),
 +				.B_WIDTH(B_WIDTH+1),
 +				.Y_WIDTH(Y_WIDTH)
 +			) _TECHMAP_REPLACE_ (
 +				.A(A),
 +				.B({1'b0, B}),
 +				.Y(Y)
 +			);
 +		else if (!A_SIGNED && B_SIGNED)
 +			\$mul #(
 +				.A_SIGNED(1),
 +				.B_SIGNED(B_SIGNED),
 +				.A_WIDTH(A_WIDTH+1),
 +				.B_WIDTH(B_WIDTH),
 +				.Y_WIDTH(Y_WIDTH)
 +			) _TECHMAP_REPLACE_ (
 +				.A({1'b0, A}),
 +				.B(B),
 +				.Y(Y)
 +			);
 +		else
 +			\$mul #(
 +				.A_SIGNED(A_SIGNED),
 +				.B_SIGNED(B_SIGNED),
 +				.A_WIDTH(A_WIDTH),
 +				.B_WIDTH(B_WIDTH),
 +				.Y_WIDTH(Y_WIDTH)
 +			) _TECHMAP_REPLACE_ (
 +				.A(A),
 +				.B(B),
 +				.Y(Y)
 +			);
 +	endgenerate
 +endmodule
 diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index 73e18112f..c7d6eee02 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -10,6 +10,7 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/brams_map.v))  $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram.txt))  $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v))  $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dsp_map.v))  $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.box))  $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.lut)) diff --git a/techlibs/ecp5/dsp_map.v b/techlibs/ecp5/dsp_map.v new file mode 100644 index 000000000..24e28869e --- /dev/null +++ b/techlibs/ecp5/dsp_map.v @@ -0,0 +1,10 @@ +module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y); +	MULT18X18D _TECHMAP_REPLACE_ ( +		.A0(A[0]), .A1(A[1]), .A2(A[2]), .A3(A[3]), .A4(A[4]), .A5(A[5]), .A6(A[6]), .A7(A[7]), .A8(A[8]), .A9(A[9]), .A10(A[10]), .A11(A[11]), .A12(A[12]), .A13(A[13]), .A14(A[14]), .A15(A[15]), .A16(A[16]), .A17(A[17]), +		.B0(B[0]), .B1(B[1]), .B2(B[2]), .B3(B[3]), .B4(B[4]), .B5(B[5]), .B6(B[6]), .B7(B[7]), .B8(B[8]), .B9(B[9]), .B10(B[10]), .B11(B[11]), .B12(B[12]), .B13(B[13]), .B14(B[14]), .B15(B[15]), .B16(B[16]), .B17(B[17]), +		.C17(1'b0), .C16(1'b0), .C15(1'b0), .C14(1'b0), .C13(1'b0), .C12(1'b0), .C11(1'b0), .C10(1'b0), .C9(1'b0), .C8(1'b0), .C7(1'b0), .C6(1'b0), .C5(1'b0), .C4(1'b0), .C3(1'b0), .C2(1'b0), .C1(1'b0), .C0(1'b0), +		.SIGNEDA(1'b0), .SIGNEDB(1'b0), .SOURCEA(1'b0), .SOURCEB(1'b0), + +		.P0(Y[0]), .P1(Y[1]), .P2(Y[2]), .P3(Y[3]), .P4(Y[4]), .P5(Y[5]), .P6(Y[6]), .P7(Y[7]), .P8(Y[8]), .P9(Y[9]), .P10(Y[10]), .P11(Y[11]), .P12(Y[12]), .P13(Y[13]), .P14(Y[14]), .P15(Y[15]), .P16(Y[16]), .P17(Y[17]), .P18(Y[18]), .P19(Y[19]), .P20(Y[20]), .P21(Y[21]), .P22(Y[22]), .P23(Y[23]), .P24(Y[24]), .P25(Y[25]), .P26(Y[26]), .P27(Y[27]), .P28(Y[28]), .P29(Y[29]), .P30(Y[30]), .P31(Y[31]), .P32(Y[32]), .P33(Y[33]), .P34(Y[34]), .P35(Y[35]) +	); +endmodule diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 143d1f95c..3129ba929 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -89,6 +89,9 @@ struct SynthEcp5Pass : public ScriptPass  		log("        generate an output netlist (and BLIF file) suitable for VPR\n");  		log("        (this feature is experimental and incomplete)\n");  		log("\n"); +		log("    -dsp\n"); +		log("        map multipliers to MULT18X18D (EXPERIMENTAL)\n"); +		log("\n");  		log("\n");  		log("The following commands are executed by this synthesis command:\n");  		help_script(); @@ -96,7 +99,7 @@ struct SynthEcp5Pass : public ScriptPass  	}  	string top_opt, blif_file, edif_file, json_file; -	bool noccu2, nodffe, nobram, nolutram, nowidelut, flatten, retime, abc2, abc9, vpr; +	bool noccu2, nodffe, nobram, nolutram, nowidelut, flatten, retime, abc2, abc9, dsp, vpr;  	void clear_flags() YS_OVERRIDE  	{ @@ -114,6 +117,7 @@ struct SynthEcp5Pass : public ScriptPass  		abc2 = false;  		vpr = false;  		abc9 = false; +		dsp = false;  	}  	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE @@ -192,6 +196,10 @@ struct SynthEcp5Pass : public ScriptPass  				abc9 = true;  				continue;  			} +			if (args[argidx] == "-dsp") { +				dsp = true; +				continue; +			}  			break;  		}  		extra_args(args, argidx, design); @@ -228,7 +236,28 @@ struct SynthEcp5Pass : public ScriptPass  		if (check_label("coarse"))  		{ -			run("synth -run coarse"); +			run("opt_expr"); +			run("opt_clean"); +			run("check"); +			run("opt"); +			run("wreduce"); +			run("peepopt"); +			run("opt_clean"); +			run("share"); +			run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); +			run("opt_expr"); +			run("opt_clean"); +			if (dsp) { +				run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_NAME=$__MUL18X18"); +				run("clean"); +				run("techmap -map +/ecp5/dsp_map.v"); +			} +			run("alumacc"); +			run("opt"); +			run("fsm"); +			run("opt -fast"); +			run("memory -nomap"); +			run("opt_clean");  		}  		if (!nobram && check_label("map_bram", "(skip if -nobram)")) diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 609facc93..2205be27d 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -1363,13 +1363,13 @@ module SB_MAC16 (  	wire [15:0] p_Ah_Bh, p_Al_Bh, p_Ah_Bl, p_Al_Bl;  	wire [15:0] Ah, Al, Bh, Bl;  	assign Ah = {A_SIGNED ? {8{iA[15]}} : 8'b0, iA[15: 8]}; -	assign Al = {A_SIGNED ? {8{iA[ 7]}} : 8'b0, iA[ 7: 0]}; +	assign Al = {A_SIGNED && MODE_8x8 ? {8{iA[ 7]}} : 8'b0, iA[ 7: 0]};  	assign Bh = {B_SIGNED ? {8{iB[15]}} : 8'b0, iB[15: 8]}; -	assign Bl = {B_SIGNED ? {8{iB[ 7]}} : 8'b0, iB[ 7: 0]}; -	assign p_Ah_Bh = Ah * Bh; -	assign p_Al_Bh = Al * Bh; -	assign p_Ah_Bl = Ah * Bl; -	assign p_Al_Bl = Al * Bl; +	assign Bl = {B_SIGNED && MODE_8x8 ? {8{iB[ 7]}} : 8'b0, iB[ 7: 0]}; +	assign p_Ah_Bh = Ah * Bh; // F +	assign p_Al_Bh = {8'b0, Al[7:0]} * Bh; // J +	assign p_Ah_Bl = Ah * {8'b0, Bl[7:0]}; // K +	assign p_Al_Bl = Al * Bl; // G  	// Regs F and J  	reg [15:0] rF, rJ; @@ -1400,7 +1400,9 @@ module SB_MAC16 (  	assign iG = BOT_8x8_MULT_REG ? rG : p_Al_Bl;  	// Adder Stage -	assign iL = iG + (iK << 8) + (iJ << 8) + (iF << 16); +	wire [23:0] iK_e = {A_SIGNED ? {8{iK[15]}} : 8'b0, iK}; +	wire [23:0] iJ_e = {B_SIGNED ? {8{iJ[15]}} : 8'b0, iJ}; +	assign iL = iG + (iK_e << 8) + (iJ_e << 8) + (iF << 16);  	// Reg H  	reg [31:0] rH; diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index be60a0071..77bd0ac81 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -265,8 +265,10 @@ struct SynthIce40Pass : public ScriptPass  			run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4");  			run("opt_expr");  			run("opt_clean"); -			if (help_mode || dsp) +			if (help_mode || dsp) { +				run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=16 -D DSP_B_MAXWIDTH=16 -D DSP_MINWIDTH=11 -D DSP_NAME=$__MUL16X16", "(if -dsp)");  				run("ice40_dsp", "(if -dsp)"); +			}  			run("alumacc");  			run("opt");  			run("fsm"); diff --git a/techlibs/ice40/tests/test_dsp_model.sh b/techlibs/ice40/tests/test_dsp_model.sh index 1bc0cc688..1e564d1b2 100644 --- a/techlibs/ice40/tests/test_dsp_model.sh +++ b/techlibs/ice40/tests/test_dsp_model.sh @@ -1,10 +1,15 @@  #!/bin/bash  set -ex  sed 's/SB_MAC16/SB_MAC16_UUT/; /SB_MAC16_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp_model_uut.v -cat /opt/lscc/iCEcube2.2017.01/verilog/sb_ice_syn.v > test_dsp_model_ref.v +if [ ! -f "test_dsp_model_ref.v" ]; then +	cat /opt/lscc/iCEcube2.2017.01/verilog/sb_ice_syn.v > test_dsp_model_ref.v +fi  for tb in testbench \  		testbench_comb_8x8_A testbench_comb_8x8_B testbench_comb_16x16 \ -		testbench_seq_16x16_A testbench_seq_16x16_B +		testbench_seq_16x16_A testbench_seq_16x16_B \ +		testbench_comb_8x8_A_signedA testbench_comb_8x8_A_signedB testbench_comb_8x8_A_signedAB \ +		testbench_comb_8x8_B_signedA testbench_comb_8x8_B_signedB testbench_comb_8x8_B_signedAB \ +		testbench_comb_16x16_signedA testbench_comb_16x16_signedB testbench_comb_16x16_signedAB  do  	iverilog -s $tb -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v  	vvp -N ./test_dsp_model diff --git a/techlibs/ice40/tests/test_dsp_model.v b/techlibs/ice40/tests/test_dsp_model.v index 594bd4ad3..f4f6858f0 100644 --- a/techlibs/ice40/tests/test_dsp_model.v +++ b/techlibs/ice40/tests/test_dsp_model.v @@ -241,6 +241,81 @@ module testbench_comb_8x8_A;  	) testbench ();  endmodule +module testbench_comb_8x8_A_signedA; +	testbench #( +		.NEG_TRIGGER               (0), +		.C_REG                     (0), +		.A_REG                     (0), +		.B_REG                     (0), +		.D_REG                     (0), +		.TOP_8x8_MULT_REG          (0), +		.BOT_8x8_MULT_REG          (0), +		.PIPELINE_16x16_MULT_REG1  (0), +		.PIPELINE_16x16_MULT_REG2  (0), +		.TOPOUTPUT_SELECT          (2),   // 0=P, 1=Q, 2=8x8, 3=16x16 +		.TOPADDSUB_LOWERINPUT      (0),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT +		.TOPADDSUB_UPPERINPUT      (0),   // 0=Q, 1=C +		.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI +		.BOTOUTPUT_SELECT          (2),   // 0=R, 1=S, 2=8x8, 3=16x16 +		.BOTADDSUB_LOWERINPUT      (0),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT +		.BOTADDSUB_UPPERINPUT      (0),   // 0=S, 1=D +		.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI +		.MODE_8x8                  (0), +		.A_SIGNED                  (1), +		.B_SIGNED                  (0) +	) testbench (); +endmodule + +module testbench_comb_8x8_A_signedB; +	testbench #( +		.NEG_TRIGGER               (0), +		.C_REG                     (0), +		.A_REG                     (0), +		.B_REG                     (0), +		.D_REG                     (0), +		.TOP_8x8_MULT_REG          (0), +		.BOT_8x8_MULT_REG          (0), +		.PIPELINE_16x16_MULT_REG1  (0), +		.PIPELINE_16x16_MULT_REG2  (0), +		.TOPOUTPUT_SELECT          (2),   // 0=P, 1=Q, 2=8x8, 3=16x16 +		.TOPADDSUB_LOWERINPUT      (0),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT +		.TOPADDSUB_UPPERINPUT      (0),   // 0=Q, 1=C +		.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI +		.BOTOUTPUT_SELECT          (2),   // 0=R, 1=S, 2=8x8, 3=16x16 +		.BOTADDSUB_LOWERINPUT      (0),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT +		.BOTADDSUB_UPPERINPUT      (0),   // 0=S, 1=D +		.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI +		.MODE_8x8                  (0), +		.A_SIGNED                  (0), +		.B_SIGNED                  (1) +	) testbench (); +endmodule + +module testbench_comb_8x8_A_signedAB; +	testbench #( +		.NEG_TRIGGER               (0), +		.C_REG                     (0), +		.A_REG                     (0), +		.B_REG                     (0), +		.D_REG                     (0), +		.TOP_8x8_MULT_REG          (0), +		.BOT_8x8_MULT_REG          (0), +		.PIPELINE_16x16_MULT_REG1  (0), +		.PIPELINE_16x16_MULT_REG2  (0), +		.TOPOUTPUT_SELECT          (2),   // 0=P, 1=Q, 2=8x8, 3=16x16 +		.TOPADDSUB_LOWERINPUT      (0),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT +		.TOPADDSUB_UPPERINPUT      (0),   // 0=Q, 1=C +		.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI +		.BOTOUTPUT_SELECT          (2),   // 0=R, 1=S, 2=8x8, 3=16x16 +		.BOTADDSUB_LOWERINPUT      (0),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT +		.BOTADDSUB_UPPERINPUT      (0),   // 0=S, 1=D +		.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI +		.MODE_8x8                  (0), +		.A_SIGNED                  (1), +		.B_SIGNED                  (1) +	) testbench (); +endmodule +  module testbench_comb_8x8_B;  	testbench #(  		.NEG_TRIGGER               (0), @@ -266,6 +341,81 @@ module testbench_comb_8x8_B;  	) testbench ();  endmodule +module testbench_comb_8x8_B_signedA; +	testbench #( +		.NEG_TRIGGER               (0), +		.C_REG                     (0), +		.A_REG                     (0), +		.B_REG                     (0), +		.D_REG                     (0), +		.TOP_8x8_MULT_REG          (0), +		.BOT_8x8_MULT_REG          (0), +		.PIPELINE_16x16_MULT_REG1  (0), +		.PIPELINE_16x16_MULT_REG2  (0), +		.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16 +		.TOPADDSUB_LOWERINPUT      (1),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT +		.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C +		.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI +		.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16 +		.BOTADDSUB_LOWERINPUT      (1),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT +		.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D +		.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI +		.MODE_8x8                  (0), +		.A_SIGNED                  (1), +		.B_SIGNED                  (0) +	) testbench (); +endmodule + +module testbench_comb_8x8_B_signedB; +	testbench #( +		.NEG_TRIGGER               (0), +		.C_REG                     (0), +		.A_REG                     (0), +		.B_REG                     (0), +		.D_REG                     (0), +		.TOP_8x8_MULT_REG          (0), +		.BOT_8x8_MULT_REG          (0), +		.PIPELINE_16x16_MULT_REG1  (0), +		.PIPELINE_16x16_MULT_REG2  (0), +		.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16 +		.TOPADDSUB_LOWERINPUT      (1),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT +		.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C +		.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI +		.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16 +		.BOTADDSUB_LOWERINPUT      (1),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT +		.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D +		.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI +		.MODE_8x8                  (0), +		.A_SIGNED                  (0), +		.B_SIGNED                  (1) +	) testbench (); +endmodule + +module testbench_comb_8x8_B_signedAB; +	testbench #( +		.NEG_TRIGGER               (0), +		.C_REG                     (0), +		.A_REG                     (0), +		.B_REG                     (0), +		.D_REG                     (0), +		.TOP_8x8_MULT_REG          (0), +		.BOT_8x8_MULT_REG          (0), +		.PIPELINE_16x16_MULT_REG1  (0), +		.PIPELINE_16x16_MULT_REG2  (0), +		.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16 +		.TOPADDSUB_LOWERINPUT      (1),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT +		.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C +		.TOPADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI +		.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16 +		.BOTADDSUB_LOWERINPUT      (1),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT +		.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D +		.BOTADDSUB_CARRYSELECT     (0),   // 0=0, 1=1, 2=ACI, 3=CI +		.MODE_8x8                  (0), +		.A_SIGNED                  (1), +		.B_SIGNED                  (1) +	) testbench (); +endmodule +  module testbench_comb_16x16;  	testbench #(  		.NEG_TRIGGER               (0), @@ -291,6 +441,81 @@ module testbench_comb_16x16;  	) testbench ();  endmodule +module testbench_comb_16x16_signedA; +	testbench #( +		.NEG_TRIGGER               (0), +		.C_REG                     (0), +		.A_REG                     (0), +		.B_REG                     (0), +		.D_REG                     (0), +		.TOP_8x8_MULT_REG          (0), +		.BOT_8x8_MULT_REG          (0), +		.PIPELINE_16x16_MULT_REG1  (0), +		.PIPELINE_16x16_MULT_REG2  (0), +		.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16 +		.TOPADDSUB_LOWERINPUT      (2),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT +		.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C +		.TOPADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI +		.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16 +		.BOTADDSUB_LOWERINPUT      (2),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT +		.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D +		.BOTADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI +		.MODE_8x8                  (0), +		.A_SIGNED                  (1), +		.B_SIGNED                  (0) +	) testbench (); +endmodule + +module testbench_comb_16x16_signedB; +	testbench #( +		.NEG_TRIGGER               (0), +		.C_REG                     (0), +		.A_REG                     (0), +		.B_REG                     (0), +		.D_REG                     (0), +		.TOP_8x8_MULT_REG          (0), +		.BOT_8x8_MULT_REG          (0), +		.PIPELINE_16x16_MULT_REG1  (0), +		.PIPELINE_16x16_MULT_REG2  (0), +		.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16 +		.TOPADDSUB_LOWERINPUT      (2),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT +		.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C +		.TOPADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI +		.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16 +		.BOTADDSUB_LOWERINPUT      (2),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT +		.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D +		.BOTADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI +		.MODE_8x8                  (0), +		.A_SIGNED                  (0), +		.B_SIGNED                  (1) +	) testbench (); +endmodule + +module testbench_comb_16x16_signedAB; +	testbench #( +		.NEG_TRIGGER               (0), +		.C_REG                     (0), +		.A_REG                     (0), +		.B_REG                     (0), +		.D_REG                     (0), +		.TOP_8x8_MULT_REG          (0), +		.BOT_8x8_MULT_REG          (0), +		.PIPELINE_16x16_MULT_REG1  (0), +		.PIPELINE_16x16_MULT_REG2  (0), +		.TOPOUTPUT_SELECT          (0),   // 0=P, 1=Q, 2=8x8, 3=16x16 +		.TOPADDSUB_LOWERINPUT      (2),   // 0=A, 1=8x8, 2=16x16, 3=S-EXT +		.TOPADDSUB_UPPERINPUT      (1),   // 0=Q, 1=C +		.TOPADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI +		.BOTOUTPUT_SELECT          (0),   // 0=R, 1=S, 2=8x8, 3=16x16 +		.BOTADDSUB_LOWERINPUT      (2),   // 0=B, 1=8x8, 2=16x16, 3=S-EXT +		.BOTADDSUB_UPPERINPUT      (1),   // 0=S, 1=D +		.BOTADDSUB_CARRYSELECT     (2),   // 0=0, 1=1, 2=ACI, 3=CI +		.MODE_8x8                  (0), +		.A_SIGNED                  (1), +		.B_SIGNED                  (1) +	) testbench (); +endmodule +  module testbench_seq_16x16_A;  	testbench #(  		.NEG_TRIGGER               (0), diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index 2c6e7432e..b0251d621 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -38,6 +38,7 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))  $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))  $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))  $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/dsp_map.v))  $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.box))  $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.lut)) diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 05e46b4e7..33b2a8f62 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -378,3 +378,150 @@ module SRLC32E (        always @(posedge CLK) if (CE) r <= { r[30:0], D };    endgenerate  endmodule + +module DSP48E1 ( +    output [29:0] ACOUT, +    output [17:0] BCOUT, +    output CARRYCASCOUT, +    output [3:0] CARRYOUT, +    output MULTSIGNOUT, +    output OVERFLOW, +    output reg signed [47:0] P, +    output PATTERNBDETECT, +    output PATTERNDETECT, +    output [47:0] PCOUT, +    output UNDERFLOW, +    input signed [29:0] A, +    input [29:0] ACIN, +    input [3:0] ALUMODE, +    input signed [17:0] B, +    input [17:0] BCIN, +    input [47:0] C, +    input CARRYCASCIN, +    input CARRYIN, +    input [2:0] CARRYINSEL, +    input CEA1, +    input CEA2, +    input CEAD, +    input CEALUMODE, +    input CEB1, +    input CEB2, +    input CEC, +    input CECARRYIN, +    input CECTRL, +    input CED, +    input CEINMODE, +    input CEM, +    input CEP, +    input CLK, +    input [24:0] D, +    input [4:0] INMODE, +    input MULTSIGNIN, +    input [6:0] OPMODE, +    input [47:0] PCIN, +    input RSTA, +    input RSTALLCARRYIN, +    input RSTALUMODE, +    input RSTB, +    input RSTC, +    input RSTCTRL, +    input RSTD, +    input RSTINMODE, +    input RSTM, +    input RSTP +); +    parameter integer ACASCREG = 1; +    parameter integer ADREG = 1; +    parameter integer ALUMODEREG = 1; +    parameter integer AREG = 1; +    parameter AUTORESET_PATDET = "NO_RESET"; +    parameter A_INPUT = "DIRECT"; +    parameter integer BCASCREG = 1; +    parameter integer BREG = 1; +    parameter B_INPUT = "DIRECT"; +    parameter integer CARRYINREG = 1; +    parameter integer CARRYINSELREG = 1; +    parameter integer CREG = 1; +    parameter integer DREG = 1; +    parameter integer INMODEREG = 1; +    parameter integer MREG = 1; +    parameter integer OPMODEREG = 1; +    parameter integer PREG = 1; +    parameter SEL_MASK = "MASK"; +    parameter SEL_PATTERN = "PATTERN"; +    parameter USE_DPORT = "FALSE"; +    parameter USE_MULT = "MULTIPLY"; +    parameter USE_PATTERN_DETECT = "NO_PATDET"; +    parameter USE_SIMD = "ONE48"; +    parameter [47:0] MASK = 48'h3FFFFFFFFFFF; +    parameter [47:0] PATTERN = 48'h000000000000; +    parameter [3:0] IS_ALUMODE_INVERTED = 4'b0; +    parameter [0:0] IS_CARRYIN_INVERTED = 1'b0; +    parameter [0:0] IS_CLK_INVERTED = 1'b0; +    parameter [4:0] IS_INMODE_INVERTED = 5'b0; +    parameter [6:0] IS_OPMODE_INVERTED = 7'b0; + +    initial begin +`ifdef __ICARUS__ +        if (ACASCREG != 0)          $fatal(1, "Unsupported ACASCREG value"); +        if (ADREG != 0)             $fatal(1, "Unsupported ADREG value"); +        if (ALUMODEREG != 0)        $fatal(1, "Unsupported ALUMODEREG value"); +        if (AREG == 2)              $fatal(1, "Unsupported AREG value"); +        if (AUTORESET_PATDET != "NO_RESET") $fatal(1, "Unsupported AUTORESET_PATDET value"); +        if (A_INPUT != "DIRECT")    $fatal(1, "Unsupported A_INPUT value"); +        if (BCASCREG != 0)          $fatal(1, "Unsupported BCASCREG value"); +        if (BREG == 2)              $fatal(1, "Unsupported BREG value"); +        if (B_INPUT != "DIRECT")    $fatal(1, "Unsupported B_INPUT value"); +        if (CARRYINREG != 0)        $fatal(1, "Unsupported CARRYINREG value"); +        if (CARRYINSELREG != 0)     $fatal(1, "Unsupported CARRYINSELREG value"); +        if (CREG != 0)              $fatal(1, "Unsupported CREG value"); +        if (DREG != 0)              $fatal(1, "Unsupported DREG value"); +        if (INMODEREG != 0)         $fatal(1, "Unsupported INMODEREG value"); +        if (MREG != 0)              $fatal(1, "Unsupported MREG value"); +        if (OPMODEREG != 0)         $fatal(1, "Unsupported OPMODEREG value"); +        //if (PREG != 0)              $fatal(1, "Unsupported PREG value"); +        if (SEL_MASK != "MASK")     $fatal(1, "Unsupported SEL_MASK value"); +        if (SEL_PATTERN != "PATTERN") $fatal(1, "Unsupported SEL_PATTERN value"); +        if (USE_DPORT != "FALSE")   $fatal(1, "Unsupported USE_DPORT value"); +        if (USE_MULT != "MULTIPLY") $fatal(1, "Unsupported USE_MULT value"); +        if (USE_PATTERN_DETECT != "NO_PATDET") $fatal(1, "Unsupported USE_PATTERN_DETECT value"); +        if (USE_SIMD != "ONE48")    $fatal(1, "Unsupported USE_SIMD value"); +        if (IS_ALUMODE_INVERTED != 4'b0) $fatal(1, "Unsupported IS_ALUMODE_INVERTED value"); +        if (IS_CARRYIN_INVERTED != 1'b0) $fatal(1, "Unsupported IS_CARRYIN_INVERTED value"); +        if (IS_CLK_INVERTED != 1'b0) $fatal(1, "Unsupported IS_CLK_INVERTED value"); +        if (IS_INMODE_INVERTED != 5'b0) $fatal(1, "Unsupported IS_INMODE_INVERTED value"); +        if (IS_OPMODE_INVERTED != 7'b0) $fatal(1, "Unsupported IS_OPMODE_INVERTED value"); +`endif +    end + +    reg signed [29:0] Ar; +    reg signed [17:0] Br; +    reg signed [47:0] Pr; +    generate +        if (AREG == 1) begin always @(posedge CLK) if (CEA2) Ar <= A; end +        else           always @* Ar <= A; +        if (BREG == 1) begin always @(posedge CLK) if (CEB2) Br <= B; end +        else           always @* Br <= B; +    endgenerate + +    always @* begin +        Pr <= {48{1'bx}}; +`ifdef __ICARUS__ +        if (INMODE != 4'b0000)      $fatal(1, "Unsupported INMODE value"); +        if (ALUMODE != 4'b0000)     $fatal(1, "Unsupported ALUMODE value"); +        if (OPMODE != 7'b000101)    $fatal(1, "Unsupported OPMODE value"); +        if (CARRYINSEL != 3'b000)   $fatal(1, "Unsupported CARRYINSEL value"); +        if (ACIN != 30'b0)          $fatal(1, "Unsupported ACIN value"); +        if (BCIN != 18'b0)          $fatal(1, "Unsupported BCIN value"); +        if (PCIN != 48'b0)          $fatal(1, "Unsupported PCIN value"); +        if (CARRYIN != 1'b0)        $fatal(1, "Unsupported CARRYIN value"); +`endif +        Pr[42:0] <= $signed(Ar[24:0]) * Br; +    end + +    generate +        if (PREG == 1) begin always @(posedge CLK) if (CEP) P <= Pr; end +        else           always @* P <= Pr; +    endgenerate + +endmodule diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v index 15fa1b63a..d79349225 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/cells_xtra.v @@ -111,88 +111,6 @@ module DNA_PORT (...);      input CLK, DIN, READ, SHIFT;  endmodule -module DSP48E1 (...); -    parameter integer ACASCREG = 1; -    parameter integer ADREG = 1; -    parameter integer ALUMODEREG = 1; -    parameter integer AREG = 1; -    parameter AUTORESET_PATDET = "NO_RESET"; -    parameter A_INPUT = "DIRECT"; -    parameter integer BCASCREG = 1; -    parameter integer BREG = 1; -    parameter B_INPUT = "DIRECT"; -    parameter integer CARRYINREG = 1; -    parameter integer CARRYINSELREG = 1; -    parameter integer CREG = 1; -    parameter integer DREG = 1; -    parameter integer INMODEREG = 1; -    parameter integer MREG = 1; -    parameter integer OPMODEREG = 1; -    parameter integer PREG = 1; -    parameter SEL_MASK = "MASK"; -    parameter SEL_PATTERN = "PATTERN"; -    parameter USE_DPORT = "FALSE"; -    parameter USE_MULT = "MULTIPLY"; -    parameter USE_PATTERN_DETECT = "NO_PATDET"; -    parameter USE_SIMD = "ONE48"; -    parameter [47:0] MASK = 48'h3FFFFFFFFFFF; -    parameter [47:0] PATTERN = 48'h000000000000; -    parameter [3:0] IS_ALUMODE_INVERTED = 4'b0; -    parameter [0:0] IS_CARRYIN_INVERTED = 1'b0; -    parameter [0:0] IS_CLK_INVERTED = 1'b0; -    parameter [4:0] IS_INMODE_INVERTED = 5'b0; -    parameter [6:0] IS_OPMODE_INVERTED = 7'b0; -    output [29:0] ACOUT; -    output [17:0] BCOUT; -    output CARRYCASCOUT; -    output [3:0] CARRYOUT; -    output MULTSIGNOUT; -    output OVERFLOW; -    output [47:0] P; -    output PATTERNBDETECT; -    output PATTERNDETECT; -    output [47:0] PCOUT; -    output UNDERFLOW; -    input [29:0] A; -    input [29:0] ACIN; -    input [3:0] ALUMODE; -    input [17:0] B; -    input [17:0] BCIN; -    input [47:0] C; -    input CARRYCASCIN; -    input CARRYIN; -    input [2:0] CARRYINSEL; -    input CEA1; -    input CEA2; -    input CEAD; -    input CEALUMODE; -    input CEB1; -    input CEB2; -    input CEC; -    input CECARRYIN; -    input CECTRL; -    input CED; -    input CEINMODE; -    input CEM; -    input CEP; -    input CLK; -    input [24:0] D; -    input [4:0] INMODE; -    input MULTSIGNIN; -    input [6:0] OPMODE; -    input [47:0] PCIN; -    input RSTA; -    input RSTALLCARRYIN; -    input RSTALUMODE; -    input RSTB; -    input RSTC; -    input RSTCTRL; -    input RSTD; -    input RSTINMODE; -    input RSTM; -    input RSTP; -endmodule -  module EFUSE_USR (...);      parameter [31:0] SIM_EFUSE_VALUE = 32'h00000000;      output [31:0] EFUSEUSR; diff --git a/techlibs/xilinx/dsp_map.v b/techlibs/xilinx/dsp_map.v new file mode 100644 index 000000000..3d7b09d69 --- /dev/null +++ b/techlibs/xilinx/dsp_map.v @@ -0,0 +1,46 @@ +module \$__MUL25X18 (input signed [24:0] A, input signed [17:0] B, output signed [42:0] Y); +	parameter A_SIGNED = 0; +	parameter B_SIGNED = 0; +	parameter A_WIDTH = 0; +	parameter B_WIDTH = 0; +	parameter Y_WIDTH = 0; + +	wire [47:0] P_48; +	DSP48E1 #( +		// Disable all registers +		.ACASCREG(0), +		.ADREG(0), +		.A_INPUT("DIRECT"), +		.ALUMODEREG(0), +		.AREG(0), +		.BCASCREG(0), +		.B_INPUT("DIRECT"), +		.BREG(0), +		.CARRYINREG(0), +		.CARRYINSELREG(0), +		.CREG(0), +		.DREG(0), +		.INMODEREG(0), +		.MREG(0), +		.OPMODEREG(0), +		.PREG(0) +	) _TECHMAP_REPLACE_ ( +		//Data path +		.A({{5{A[24]}}, A}), +		.B(B), +		.C(48'b0), +		.D(24'b0), +		.P(P_48), + +		.INMODE(4'b0000), +		.ALUMODE(4'b0000), +		.OPMODE(7'b000101), +		.CARRYINSEL(3'b000), + +		.ACIN(30'b0), +		.BCIN(18'b0), +		.PCIN(48'b0), +		.CARRYIN(1'b0) +	); +	assign Y = P_48; +endmodule diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index b672a0d4f..e5a27015a 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -78,6 +78,9 @@ struct SynthXilinxPass : public ScriptPass  		log("    -nowidelut\n");  		log("        do not use MUXF[78] resources to implement LUTs larger than LUT6s\n");  		log("\n"); +		log("    -nodsp\n"); +		log("        do not use DSP48E1s to implement multipliers and associated logic\n"); +		log("\n");  		log("    -widemux <int>\n");  		log("        enable inference of hard multiplexer resources (MUXF[78]) for muxes at or\n");  		log("        above this number of inputs (minimum value 2, recommended value >= 5).\n"); @@ -104,7 +107,7 @@ struct SynthXilinxPass : public ScriptPass  	}  	std::string top_opt, edif_file, blif_file, family; -	bool flatten, retime, vpr, nobram, nodram, nosrl, nocarry, nowidelut, abc9; +	bool flatten, retime, vpr, nobram, nodram, nosrl, nocarry, nowidelut, nodsp, abc9;  	int widemux;  	void clear_flags() YS_OVERRIDE @@ -122,6 +125,7 @@ struct SynthXilinxPass : public ScriptPass  		nosrl = false;  		nocarry = false;  		nowidelut = false; +		nodsp = false;  		abc9 = false;  		widemux = 0;  	} @@ -202,6 +206,10 @@ struct SynthXilinxPass : public ScriptPass  				abc9 = true;  				continue;  			} +			if (args[argidx] == "-nodsp") { +				nodsp = true; +				continue; +			}  			break;  		}  		extra_args(args, argidx, design); @@ -249,8 +257,8 @@ struct SynthXilinxPass : public ScriptPass  		if (check_label("coarse")) {  			run("proc"); -			if (help_mode || flatten) -				run("flatten", "(if -flatten)"); +			if (flatten || help_mode) +				run("flatten", "(with '-flatten')");  			run("opt_expr");  			run("opt_clean");  			run("check"); @@ -275,6 +283,12 @@ struct SynthXilinxPass : public ScriptPass  			}  			run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6"); + +			if (!nodsp || help_mode) { +				// NB: Xilinx multipliers are signed only +				run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=25 -D DSP_B_MAXWIDTH=18 -D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18"); +			} +  			run("alumacc");  			run("share");  			run("opt"); @@ -317,6 +331,10 @@ struct SynthXilinxPass : public ScriptPass  			run("memory_map");  			run("dffsr2dff");  			run("dff2dffe"); +			if (help_mode || !nodsp) { +				run("techmap -map +/xilinx/dsp_map.v", "(skip if '-nodsp')"); +				run("xilinx_dsp", "                     (skip if '-nodsp')"); +			}  			if (help_mode) {  				run("simplemap t:$mux", "         ('-widemux' only)");  				run("muxcover <internal options>, ('-widemux' only)"); | 
