Inferring DSP
The Titanium DSP Block supports multiply, add, shift, and cascade functions.
- Example 1—You use the DSP A_REG, B_REG, and W_REG. They all must be clocked by the same clock signal.
- Example 2—A_REG and C_REG use a reset signal. B_REG cannot use a different reset clock, but B_REG is not required to have a reset.
The following examples show code to infer them.
- <= 4 infers an EFX_DSP12
- <= 8 infers an EFX_DSP24
- <= 19,18, infers an EFX_DSP48
`define AWIDTH 4
`define BWIDTH 4
module mult(a, b, x);
input signed [`AWIDTH-1:0] a;
input signed [`BWIDTH-1:0] b;
output signed [`AWIDTH+`BWIDTH-1:0] x;
assign x = a * b;
endmodule
This multiply-add can be packed into a single EFX_DSP48 primitive because the width of C fits into tbe C port.
module dsp_multadd_s(a, b, c, o);
input signed [17:0] a;
input signed [17:0] b;
input signed [17:0] c;
output signed [35:0] o;
wire signed [35:0] p;
assign p = a * b;
assign o = p + c;
endmodule
Generally, a multiply-add cannot be packed into a single EFX_DSP48 primitive because the width of C does not fit into the C port. With the syn_use_dsp attribute, synthesis uses the A:B:C cascade of another DSP Block to produce a multiply-accumulate.
module dsp_multadd_s(a, b, c, o);
input signed [17:0] a;
input signed [17:0] b;
input signed [35:0] c;
output signed [35:0] o;
wire signed [35:0] p;
(* syn_use_dsp = "yes" *) wire [35:0] sum;
assign p = a * b;
assign sum = p + c;
assign o = sum;
endmodule
The feedback path can take output of the DSP Block and feed it back for accumulation. You enable it with the syn_use_dsp attribute.
module dsp_multadd_s(a, b, clk, o);
input signed [17:0] a;
input signed [17:0] b;
input clk;
output signed [35:0] o;
wire signed [35:0] p;
(* syn_use_dsp = "yes" *) reg [35:0] sum;
assign p = a * b;
always @(posedge clk) begin
sum <= p + sum;
end
assign o = sum;
endmodule
The
DSP block has a feedback path to take the output of the DSP block and feed it
back for accumulation. In the following example, input a is
wired to the DSP block's C port. The M_SEL
parameter is set to C, the N_SEL parameter is
set to W, and W_REG is
used.
module dsp_add_s(a, clk, o);
input signed [17:0] a;
input clk;
output signed [35:0] o;
(* syn_use_dsp = "yes" *) reg [35:0] sum;
always @(posedge clk) begin
sum <= a + sum;
end
assign o = sum;
endmodule
The
DSP block has a shift function between the W and
O registers. The following code infers the shifter with
shift value s connected to C. The
SHIFTER parameter is set to 1, and the
P_REG and O_REG parameters are used. You
must also register the shift value with the same clock.
`define SIZEA 8
`define SIZEB 8
module dsp_shiftout (a, b, s, clk, x);
input clk;
input [`SIZEA-1:0] a;
input [`SIZEB-1:0] b;
input [3:0] s;
output [`SIZEA+`SIZEB-1:0] x;
reg [`SIZEA+`SIZEB-1:0] p1, p2, p3;
reg [3:0] sreg;
always @(posedge clk) begin
p1 <= a * b;
p3 <= p1 >> sreg;
sreg <= s;
end
assign x = p3;
endmodule
In
this case, because of a narrower width, the software infers a DSP12 primitive.
The first DSP primitive performs the p2 = d*c operation and the
output is fed through the CASCOUT output to the second DSP
primitive, which handles the p1 = a*b and x =
p1-p2 operations (by assigning 2'b01 to the OP
input).
module dsp_cas_sub (a, b, c, d, x);
input [3:0]a, b, c, d;
output [7:0]x;
wire [7:0] p1,p2;
assign p1 = a*b;
assign p2 = d*c;
assign x = p1-p2;
endmodule