xilinx: Support multiplier mapping for all families.

This supports several older families that are not yet supported for
actual logic synthesis — the intention is to add them soon.
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index 1e59f0a..3354605 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -42,7 +42,13 @@
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_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/xc3s_mult_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc3sda_dsp_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_dsp_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc4v_dsp_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc5v_dsp_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_dsp_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcu_dsp_map.v))
 
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_map.v))
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_unmap.v))
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 6f8254b..6566da8 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -343,14 +343,51 @@
 			if (!nodsp || help_mode) {
 				run("memory_dff"); // xilinx_dsp will merge registers, reserve memory port registers first
 				// NB: Xilinx multipliers are signed only
-				run("techmap -map +/mul2dsp.v -map +/xilinx/dsp_map.v -D DSP_A_MAXWIDTH=25 "
-					"-D DSP_A_MAXWIDTH_PARTIAL=18 -D DSP_B_MAXWIDTH=18 "    // Partial multipliers are intentionally
-												// limited to 18x18 in order to take
-												// advantage of the (PCOUT << 17) -> PCIN
-												// dedicated cascade chain capability
-					"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
-					"-D DSP_Y_MINWIDTH=9 " // UG901 suggests small multiplies are those 4x4 and smaller
-					"-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18");
+				if (help_mode)
+					run("techmap -map +/mul2dsp.v -map +/xilinx/{family}_dsp_map.v {options}");
+				else if (family == "xc2v" || family == "xc3s" || family == "xc3se" || family == "xc3sa")
+					run("techmap -map +/mul2dsp.v -map +/xilinx/xc3s_mult_map.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 "
+						"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
+						"-D DSP_Y_MINWIDTH=9 " // UG901 suggests small multiplies are those 4x4 and smaller
+						"-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL18X18");
+				else if (family == "xc3sda")
+					run("techmap -map +/mul2dsp.v -map +/xilinx/xc3sda_dsp_map.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 "
+						"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
+						"-D DSP_Y_MINWIDTH=9 " // UG901 suggests small multiplies are those 4x4 and smaller
+						"-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL18X18");
+				else if (family == "xc6s")
+					run("techmap -map +/mul2dsp.v -map +/xilinx/xc6s_dsp_map.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 "
+						"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
+						"-D DSP_Y_MINWIDTH=9 " // UG901 suggests small multiplies are those 4x4 and smaller
+						"-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL18X18");
+				else if (family == "xc4v")
+					run("techmap -map +/mul2dsp.v -map +/xilinx/xc4v_dsp_map.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 "
+						"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
+						"-D DSP_Y_MINWIDTH=9 " // UG901 suggests small multiplies are those 4x4 and smaller
+						"-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL18X18");
+				else if (family == "xc5v")
+					run("techmap -map +/mul2dsp.v -map +/xilinx/xc5v_dsp_map.v -D DSP_A_MAXWIDTH=25 -D DSP_B_MAXWIDTH=18 "
+						"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
+						"-D DSP_Y_MINWIDTH=9 " // UG901 suggests small multiplies are those 4x4 and smaller
+						"-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18");
+				else if (family == "xc6v" || family == "xc7")
+					run("techmap -map +/mul2dsp.v -map +/xilinx/xc7_dsp_map.v -D DSP_A_MAXWIDTH=25 -D DSP_B_MAXWIDTH=18 "
+						"-D DSP_A_MAXWIDTH_PARTIAL=18 "	// Partial multipliers are intentionally
+										// limited to 18x18 in order to take
+										// advantage of the (PCOUT << 17) -> PCIN
+										// dedicated cascade chain capability
+						"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
+						"-D DSP_Y_MINWIDTH=9 " // UG901 suggests small multiplies are those 4x4 and smaller
+						"-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL25X18");
+				else if (family == "xcu" || family == "xcup")
+					run("techmap -map +/mul2dsp.v -map +/xilinx/xcu_dsp_map.v -D DSP_A_MAXWIDTH=27 -D DSP_B_MAXWIDTH=18 "
+						"-D DSP_A_MAXWIDTH_PARTIAL=18 "	// Partial multipliers are intentionally
+										// limited to 18x18 in order to take
+										// advantage of the (PCOUT << 17) -> PCIN
+										// dedicated cascade chain capability
+						"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
+						"-D DSP_Y_MINWIDTH=9 " // UG901 suggests small multiplies are those 4x4 and smaller
+						"-D DSP_SIGNEDONLY=1 -D DSP_NAME=$__MUL27X18");
 				run("select a:mul2dsp");
 				run("setattr -unset mul2dsp");
 				run("opt_expr -fine");
diff --git a/techlibs/xilinx/xc3s_mult_map.v b/techlibs/xilinx/xc3s_mult_map.v
new file mode 100644
index 0000000..67cd4ac
--- /dev/null
+++ b/techlibs/xilinx/xc3s_mult_map.v
@@ -0,0 +1,14 @@
+module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y);
+	parameter A_SIGNED = 0;
+	parameter B_SIGNED = 0;
+	parameter A_WIDTH = 0;
+	parameter B_WIDTH = 0;
+	parameter Y_WIDTH = 0;
+
+	MULT18X18 _TECHMAP_REPLACE_ (
+		.A(A),
+		.B(B),
+		.P(Y)
+	);
+endmodule
+
diff --git a/techlibs/xilinx/xc3sda_dsp_map.v b/techlibs/xilinx/xc3sda_dsp_map.v
new file mode 100644
index 0000000..87348a1
--- /dev/null
+++ b/techlibs/xilinx/xc3sda_dsp_map.v
@@ -0,0 +1,34 @@
+module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35: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;
+	DSP48A #(
+		// Disable all registers
+		.A0REG(0),
+		.A1REG(0),
+		.B0REG(0),
+		.B1REG(0),
+		.CARRYINREG(0),
+		.CARRYINSEL("OPMODE5"),
+		.CREG(0),
+		.DREG(0),
+		.MREG(0),
+		.OPMODEREG(0),
+		.PREG(0)
+	) _TECHMAP_REPLACE_ (
+		//Data path
+		.A(A),
+		.B(B),
+		.C(48'b0),
+		.D(18'b0),
+		.P(P_48),
+
+		.OPMODE(8'b0000010)
+	);
+	assign Y = P_48;
+endmodule
+
diff --git a/techlibs/xilinx/xc4v_dsp_map.v b/techlibs/xilinx/xc4v_dsp_map.v
new file mode 100644
index 0000000..69c42f3
--- /dev/null
+++ b/techlibs/xilinx/xc4v_dsp_map.v
@@ -0,0 +1,38 @@
+module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35: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;
+	DSP48 #(
+		// Disable all registers
+		.AREG(0),
+		.BREG(0),
+		.B_INPUT("DIRECT"),
+		.CARRYINREG(0),
+		.CARRYINSELREG(0),
+		.CREG(0),
+		.MREG(0),
+		.OPMODEREG(0),
+		.PREG(0),
+		.SUBTRACTREG(0),
+		.LEGACY_MODE("MULT18X18")
+	) _TECHMAP_REPLACE_ (
+		//Data path
+		.A(A),
+		.B(B),
+		.C(48'b0),
+		.P(P_48),
+
+		.SUBTRACT(1'b0),
+		.OPMODE(7'b000101),
+		.CARRYINSEL(2'b00),
+
+		.BCIN(18'b0),
+		.PCIN(48'b0),
+		.CARRYIN(1'b0)
+	);
+	assign Y = P_48;
+endmodule
diff --git a/techlibs/xilinx/xc5v_dsp_map.v b/techlibs/xilinx/xc5v_dsp_map.v
new file mode 100644
index 0000000..fc7ba46
--- /dev/null
+++ b/techlibs/xilinx/xc5v_dsp_map.v
@@ -0,0 +1,45 @@
+module \$__MUL25X18 (input [24:0] A, input [17:0] B, output [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;
+	DSP48E #(
+		// Disable all registers
+		.ACASCREG(0),
+		.A_INPUT("DIRECT"),
+		.ALUMODEREG(0),
+		.AREG(0),
+		.BCASCREG(0),
+		.B_INPUT("DIRECT"),
+		.BREG(0),
+		.MULTCARRYINREG(0),
+		.CARRYINREG(0),
+		.CARRYINSELREG(0),
+		.CREG(0),
+		.MREG(0),
+		.OPMODEREG(0),
+		.PREG(0),
+		.USE_MULT("MULT"),
+		.USE_SIMD("ONE48")
+	) _TECHMAP_REPLACE_ (
+		//Data path
+		.A({{5{A[24]}}, A}),
+		.B(B),
+		.C(48'b0),
+		.P(P_48),
+
+		.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/xc6s_dsp_map.v b/techlibs/xilinx/xc6s_dsp_map.v
new file mode 100644
index 0000000..e870572
--- /dev/null
+++ b/techlibs/xilinx/xc6s_dsp_map.v
@@ -0,0 +1,35 @@
+module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35: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;
+	DSP48A1 #(
+		// Disable all registers
+		.A0REG(0),
+		.A1REG(0),
+		.B0REG(0),
+		.B1REG(0),
+		.CARRYINREG(0),
+		.CARRYINSEL("OPMODE5"),
+		.CREG(0),
+		.DREG(0),
+		.MREG(0),
+		.OPMODEREG(0),
+		.PREG(0)
+	) _TECHMAP_REPLACE_ (
+		//Data path
+		.A(A),
+		.B(B),
+		.C(48'b0),
+		.D(18'b0),
+		.P(P_48),
+
+		.OPMODE(8'b0000010)
+	);
+	assign Y = P_48;
+endmodule
+
+
diff --git a/techlibs/xilinx/dsp_map.v b/techlibs/xilinx/xc7_dsp_map.v
similarity index 100%
rename from techlibs/xilinx/dsp_map.v
rename to techlibs/xilinx/xc7_dsp_map.v
diff --git a/techlibs/xilinx/xcu_dsp_map.v b/techlibs/xilinx/xcu_dsp_map.v
new file mode 100644
index 0000000..fa95a57
--- /dev/null
+++ b/techlibs/xilinx/xcu_dsp_map.v
@@ -0,0 +1,51 @@
+module \$__MUL27X18 (input [26:0] A, input [17:0] B, output [44: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;
+	DSP48E2 #(
+		// 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),
+		.USE_MULT("MULTIPLY"),
+		.USE_SIMD("ONE48"),
+		.AMULTSEL("A"),
+		.BMULTSEL("B")
+	) _TECHMAP_REPLACE_ (
+		//Data path
+		.A({{3{A[26]}}, A}),
+		.B(B),
+		.C(48'b0),
+		.D(27'b0),
+		.P(P_48),
+
+		.INMODE(5'b00000),
+		.ALUMODE(4'b0000),
+		.OPMODE(9'b00000101),
+		.CARRYINSEL(3'b000),
+
+		.ACIN(30'b0),
+		.BCIN(18'b0),
+		.PCIN(48'b0),
+		.CARRYIN(1'b0)
+	);
+	assign Y = P_48;
+endmodule
+