intel_alm: Add multiply signedness to cells

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.
This commit is contained in:
Dan Ravensloft 2020-08-26 18:44:48 +01:00 committed by Marcelina Kościelnicka
parent 4f2b78e19a
commit 1a07b330f8
7 changed files with 147 additions and 16 deletions

View File

@ -1,3 +1,5 @@
`default_nettype none
module __MUL27X27(A, B, Y);
parameter A_SIGNED = 1;

View 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

View 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";

View 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

View 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");
}
}

View 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

View 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