diff options
-rw-r--r-- | passes/pmgen/ice40_dsp.pmg | 2 | ||||
-rw-r--r-- | techlibs/common/mul2dsp.v | 23 | ||||
-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/dsp_map.v | 6 |
7 files changed, 265 insertions, 20 deletions
diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg index 1f3590d4e..f2b7f2169 100644 --- a/passes/pmgen/ice40_dsp.pmg +++ b/passes/pmgen/ice40_dsp.pmg @@ -6,7 +6,7 @@ state <SigSpec> sigA sigB sigY sigS state <Cell*> addAB muxAB match mul - select mul->type.in($mul) + select mul->type.in($mul, $__MUL16X16) select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10 select GetSize(mul->getPort(\Y)) > 10 endmatch diff --git a/techlibs/common/mul2dsp.v b/techlibs/common/mul2dsp.v index da1c7c0c7..b6aa02834 100644 --- a/techlibs/common/mul2dsp.v +++ b/techlibs/common/mul2dsp.v @@ -8,9 +8,6 @@ $error("Macro DSP_A_MAXWIDTH must be defined"); `ifndef DSP_B_MAXWIDTH
$error("Macro DSP_B_MAXWIDTH must be defined");
`endif
-`ifndef DSP_SIGNEDONLY
-`define DSP_SIGNEDONLY 0
-`endif
`ifndef DSP_NAME
$error("Macro DSP_NAME must be defined");
@@ -33,7 +30,8 @@ module \$mul (A, B, Y); generate
if (A_SIGNED != B_SIGNED)
wire _TECHMAP_FAIL_ = 1;
- else if (`DSP_SIGNEDONLY && !A_SIGNED) begin
+`ifdef DSP_SIGNEDONLY
+ else if (!A_SIGNED) begin
wire [1:0] dummy;
\$mul #(
.A_SIGNED(1),
@@ -47,6 +45,7 @@ module \$mul (A, B, Y); .Y({dummy, Y})
);
end
+`endif
// NB: A_SIGNED == B_SIGNED == 0 from here
else if (A_WIDTH >= B_WIDTH)
\$__mul_gen #(
@@ -109,7 +108,7 @@ module \$__mul_gen (A, B, Y); end
\$__mul_gen #(
- .A_SIGNED(0),
+ .A_SIGNED(sign_headroom),
.B_SIGNED(B_SIGNED),
.A_WIDTH(`DSP_A_MAXWIDTH),
.B_WIDTH(B_WIDTH),
@@ -123,7 +122,7 @@ module \$__mul_gen (A, B, Y); for (i = 1; i < n-1; i=i+1) begin:slice
\$__mul_gen #(
- .A_SIGNED(0),
+ .A_SIGNED(sign_headroom),
.B_SIGNED(B_SIGNED),
.A_WIDTH(`DSP_A_MAXWIDTH),
.B_WIDTH(B_WIDTH),
@@ -164,7 +163,7 @@ module \$__mul_gen (A, B, Y); \$__mul_gen #(
.A_SIGNED(A_SIGNED),
- .B_SIGNED(0),
+ .B_SIGNED(sign_headroom),
.A_WIDTH(A_WIDTH),
.B_WIDTH(`DSP_B_MAXWIDTH),
.Y_WIDTH(partial_Y_WIDTH)
@@ -178,7 +177,7 @@ module \$__mul_gen (A, B, Y); for (i = 1; i < n-1; i=i+1) begin:slice
\$__mul_gen #(
.A_SIGNED(A_SIGNED),
- .B_SIGNED(0),
+ .B_SIGNED(sign_headroom),
.A_WIDTH(A_WIDTH),
.B_WIDTH(`DSP_B_MAXWIDTH),
.Y_WIDTH(partial_Y_WIDTH)
@@ -214,7 +213,13 @@ module \$__mul_gen (A, B, Y); else
wire [`DSP_B_MAXWIDTH-1:0] Bext = B;
- `DSP_NAME _TECHMAP_REPLACE_ (
+ `DSP_NAME #(
+ .A_SIGNED(A_SIGNED),
+ .B_SIGNED(B_SIGNED),
+ .A_WIDTH(`DSP_A_MAXWIDTH),
+ .B_WIDTH(`DSP_B_MAXWIDTH),
+ .Y_WIDTH(`DSP_A_MAXWIDTH+`DSP_B_MAXWIDTH),
+ ) _TECHMAP_REPLACE_ (
.A(Aext),
.B(Bext),
.Y(Y)
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..5053e445d 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_NAME=$__MUL16X16"); 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/dsp_map.v b/techlibs/xilinx/dsp_map.v index 32f570935..3d7b09d69 100644 --- a/techlibs/xilinx/dsp_map.v +++ b/techlibs/xilinx/dsp_map.v @@ -1,4 +1,10 @@ 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 |