intel_alm: Add multiply signedness to cells
authorDan Ravensloft <dan.ravensloft@gmail.com>
Wed, 26 Aug 2020 17:44:48 +0000 (18:44 +0100)
committerMarcelina Koƛcielnicka <mwk@0x04.net>
Wed, 26 Aug 2020 20:50:16 +0000 (22:50 +0200)
Quartus assumes unsigned multiplication by default, breaking signed
multiplies, so add an input signedness parameter to the MISTRAL_MUL*
cells to propagate to Quartus' <family>_mac cells.

techlibs/intel_alm/common/dsp_map.v
techlibs/intel_alm/common/dsp_sim.v
techlibs/intel_alm/common/megafunction_bb.v
techlibs/intel_alm/common/quartus_rename.v
techlibs/intel_alm/synth_intel_alm.cc
tests/arch/common/mul.v
tests/arch/intel_alm/mul.ys

index d1bc25e65852e840b0c66a1ec7b4756e5c35afe6..e12e777a4e40c57e0ae345c16afca70fc0208bb5 100644 (file)
@@ -1,3 +1,5 @@
+`default_nettype none
+
 module __MUL27X27(A, B, Y);
 
 parameter A_SIGNED = 1;
index 45fdebb3f085a09094f9da5be3d2b489fae9ee19..bdb6d18d561868c868501f1bb0c07818056d3d26 100644 (file)
@@ -1,38 +1,83 @@
 (* abc9_box *)
 module MISTRAL_MUL27X27(input [26:0] A, input [26:0] B, output [53:0] Y);
 
+parameter A_SIGNED = 1;
+parameter B_SIGNED = 1;
+
 // TODO: Cyclone 10 GX timings; the below are for Cyclone V
 specify
     (A *> Y) = 3732;
     (B *> Y) = 3928;
 endspecify
 
-assign Y = $signed(A) * $signed(B);
+wire [53:0] A_, B_;
+
+if (A_SIGNED)
+    assign A_ = $signed(A);
+else
+    assign A_ = $unsigned(A);
+
+if (B_SIGNED)
+    assign B_ = $signed(B);
+else
+    assign B_ = $unsigned(B);
+
+assign Y = A_ * B_;
 
 endmodule
 
 (* abc9_box *)
 module MISTRAL_MUL18X18(input [17:0] A, input [17:0] B, output [35:0] Y);
 
+parameter A_SIGNED = 1;
+parameter B_SIGNED = 1;
+
 // TODO: Cyclone 10 GX timings; the below are for Cyclone V
 specify
     (A *> Y) = 3180;
     (B *> Y) = 3982;
 endspecify
 
-assign Y = $signed(A) * $signed(B);
+wire [35:0] A_, B_;
+
+if (A_SIGNED)
+    assign A_ = $signed(A);
+else
+    assign A_ = $unsigned(A);
+
+if (B_SIGNED)
+    assign B_ = $signed(B);
+else
+    assign B_ = $unsigned(B);
+
+assign Y = A_ * B_;
 
 endmodule
 
 (* abc9_box *)
 module MISTRAL_MUL9X9(input [8:0] A, input [8:0] B, output [17:0] Y);
 
+parameter A_SIGNED = 1;
+parameter B_SIGNED = 1;
+
 // TODO: Cyclone 10 GX timings; the below are for Cyclone V
 specify
     (A *> Y) = 2818;
     (B *> Y) = 3051;
 endspecify
 
-assign Y = $signed(A) * $signed(B);
+wire [17:0] A_, B_;
+
+if (A_SIGNED)
+    assign A_ = $signed(A);
+else
+    assign A_ = $unsigned(A);
+
+if (B_SIGNED)
+    assign B_ = $signed(B);
+else
+    assign B_ = $unsigned(B);
+
+assign Y = A_ * B_;
 
 endmodule
index 530e44054bd6314f5ffd77d54bb0f88d23b22fa0..874f293b17f145e29495e3b212f6aca1990d3c14 100644 (file)
@@ -565,7 +565,9 @@ endmodule
 module cyclonev_mac(ax, ay, resulta);
 
 parameter ax_width = 9;
+parameter signed_max = "true";
 parameter ay_scan_in_width = 9;
+parameter signed_may = "true";
 parameter result_a_width = 18;
 parameter operation_mode = "M9x9";
 
@@ -579,7 +581,9 @@ endmodule
 module cyclone10gx_mac(ax, ay, resulta);
 
 parameter ax_width = 18;
+parameter signed_max = "true";
 parameter ay_scan_in_width = 18;
+parameter signed_may = "true";
 parameter result_a_width = 36;
 parameter operation_mode = "M18X18_FULL";
 
index 9bc532ca29379ded2eed942f0af75102145acfb1..3b4628675983307c78a1f6b26e3604a21b131b33 100644 (file)
@@ -174,20 +174,62 @@ endmodule
 
 module MISTRAL_MUL27X27(input [26:0] A, B, output [53:0] Y);
 
-`MAC #(.ax_width(27), .ay_scan_in_width(27), .result_a_width(54), .operation_mode("M27x27")) _TECHMAP_REPLACE_ (.ax(A), .ay(B), .resulta(Y));
+parameter A_SIGNED = 1;
+parameter B_SIGNED = 1;
+
+`MAC #(
+    .ax_width(27),
+    .signed_max(A_SIGNED ? "true" : "false"),
+    .ay_scan_in_width(27),
+    .signed_may(B_SIGNED ? "true" : "false"),
+    .result_a_width(54),
+    .operation_mode("M27x27")
+) _TECHMAP_REPLACE_ (
+    .ax(A),
+    .ay(B),
+    .resulta(Y)
+);
 
 endmodule
 
 
 module MISTRAL_MUL18X18(input [17:0] A, B, output [35:0] Y);
 
-`MAC #(.ax_width(18), .ay_scan_in_width(18), .result_a_width(36), .operation_mode("M18x18_FULL")) _TECHMAP_REPLACE_ (.ax(B), .ay(A), .resulta(Y));
+parameter A_SIGNED = 1;
+parameter B_SIGNED = 1;
+
+`MAC #(
+    .ax_width(18),
+    .signed_max(A_SIGNED ? "true" : "false"),
+    .ay_scan_in_width(18),
+    .signed_may(B_SIGNED ? "true" : "false"),
+    .result_a_width(36),
+    .operation_mode("M18x18_FULL")
+) _TECHMAP_REPLACE_ (
+    .ax(A),
+    .ay(B),
+    .resulta(Y)
+);
 
 endmodule
 
 
 module MISTRAL_MUL9X9(input [8:0] A, B, output [17:0] Y);
 
-`MAC #(.ax_width(9), .ay_scan_in_width(9), .result_a_width(18), .operation_mode("M9x9")) _TECHMAP_REPLACE_ (.ax(A), .ay(B), .resulta(Y));
+parameter A_SIGNED = 1;
+parameter B_SIGNED = 1;
+
+`MAC #(
+    .ax_width(9),
+    .signed_max(A_SIGNED ? "true" : "false"),
+    .ay_scan_in_width(9),
+    .signed_may(B_SIGNED ? "true" : "false"),
+    .result_a_width(18),
+    .operation_mode("M9x9")
+) _TECHMAP_REPLACE_ (
+    .ax(A),
+    .ay(B),
+    .resulta(Y)
+);
 
 endmodule
index 7ab50ef8f4092fef4160eada36222f6617c830f3..faa405df7c3418702dff2532c4133ce9df7f68d5 100644 (file)
@@ -214,15 +214,15 @@ struct SynthIntelALMPass : public ScriptPass {
                                run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp)");
                        } else if (!nodsp) {
                                // Cyclone V supports 9x9 multiplication, Cyclone 10 GX does not.
-                               run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=27 -D DSP_B_MAXWIDTH=27  -D DSP_A_MINWIDTH=19 -D DSP_B_MINWIDTH=19  -D DSP_SIGNEDONLY  -D DSP_NAME=__MUL27X27");
+                               run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=27 -D DSP_B_MAXWIDTH=27  -D DSP_A_MINWIDTH=19 -D DSP_B_MINWIDTH=19 -D DSP_NAME=__MUL27X27");
                                run("chtype -set $mul t:$__soft_mul");
                                if (family_opt == "cyclonev") {
-                                       run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18  -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=10  -D DSP_SIGNEDONLY  -D DSP_NAME=__MUL18X18");
+                                       run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18  -D DSP_A_MINWIDTH=10 -D DSP_B_MINWIDTH=10 -D DSP_NAME=__MUL18X18");
                                        run("chtype -set $mul t:$__soft_mul");
-                                       run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=9 -D DSP_B_MAXWIDTH=9  -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4  -D DSP_SIGNEDONLY  -D DSP_NAME=__MUL9X9");
+                                       run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=9 -D DSP_B_MAXWIDTH=9  -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=__MUL9X9");
                                        run("chtype -set $mul t:$__soft_mul");
                                } else if (family_opt == "cyclone10gx") {
-                                       run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18  -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4  -D DSP_SIGNEDONLY  -D DSP_NAME=__MUL18X18");
+                                       run("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18  -D DSP_A_MINWIDTH=4 -D DSP_B_MINWIDTH=4 -D DSP_NAME=__MUL18X18");
                                        run("chtype -set $mul t:$__soft_mul");
                                }
                        }
index 437a91cfcfd6b39f9756693e11d357d5f580d0c4..baed64fcdb01c2be30342d38538739ab9961f5a3 100644 (file)
@@ -1,9 +1,10 @@
 module top
+#(parameter X_WIDTH=6, Y_WIDTH=6, A_WIDTH=12)
 (
-    input [5:0] x,
-    input [5:0] y,
+    input [X_WIDTH-1:0] x,
+    input [Y_WIDTH-1:0] y,
 
-    output [11:0] A,
+    output [A_WIDTH-1:0] A,
 );
     assign A =  x * y;
 endmodule
index 92f00156ab2c9a276a331408c028632b0988335a..49934740f1c571518cf285b4fe0a2d78fbee76fe 100644 (file)
@@ -1,23 +1,60 @@
 read_verilog ../common/mul.v
+chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16
 hierarchy -top top
 proc
 equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclonev # equivalency check
 design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
 cd top # Constrain all select calls below inside the top module
 
-stat
-
 select -assert-count 1 t:MISTRAL_MUL9X9
 select -assert-none t:MISTRAL_MUL9X9 %% t:* %D
 
+# Cyclone 10 GX does not have 9x9 multipliers.
+
+design -reset
+read_verilog ../common/mul.v
+chparam -set X_WIDTH 17 -set Y_WIDTH 17 -set A_WIDTH 34
+hierarchy -top top
+proc
+equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 1 t:MISTRAL_MUL18X18
+select -assert-none t:MISTRAL_MUL18X18 %% t:* %D
+
 design -reset
 read_verilog ../common/mul.v
+chparam -set X_WIDTH 17 -set Y_WIDTH 17 -set A_WIDTH 34
 hierarchy -top top
 proc
 equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclone10gx # equivalency check
 design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
 cd top # Constrain all select calls below inside the top module
 
-# Cyclone 10 GX does not have 9x9 multipliers, so we use 18x18.
 select -assert-count 1 t:MISTRAL_MUL18X18
 select -assert-none t:MISTRAL_MUL18X18 %% t:* %D
+
+design -reset
+read_verilog ../common/mul.v
+chparam -set X_WIDTH 26 -set Y_WIDTH 26 -set A_WIDTH 52
+hierarchy -top top
+proc
+equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclonev # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 1 t:MISTRAL_MUL27X27
+select -assert-none t:MISTRAL_MUL27X27 %% t:* %D
+
+design -reset
+read_verilog ../common/mul.v
+chparam -set X_WIDTH 26 -set Y_WIDTH 26 -set A_WIDTH 52
+hierarchy -top top
+proc
+equiv_opt -assert -map +/intel_alm/common/dsp_sim.v synth_intel_alm -family cyclone10gx # equivalency check
+design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)
+cd top # Constrain all select calls below inside the top module
+
+select -assert-count 1 t:MISTRAL_MUL27X27
+select -assert-none t:MISTRAL_MUL27X27 %% t:* %D