Inferring DSP

The Titanium DSP Block supports multiply, add, shift, and cascade functions.

If the signals are registered, use the same clock for all DSP Block inputs and outputs. Additionally, if you use the reset or clock enable, the clocks should be the same. However, not all registers require a reset or clock enable.
  • 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.
Notice: Refer to the Trion®, Topaz, and Titanium Quantum primitives user guides for more details on the DSP Block primitives.

The following examples show code to infer them.

Figure 1. Inferring Multipliers
When inferring multipliers, synthesis uses different primitives, depending on the width:
  • <= 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

Figure 2. Inferring Multiply-Accumulate

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 

Figure 3. Inferring Multiply-Accumulate with Cascading

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 

Figure 4. Inferring Multiply-Accumulate with Output Feeding Back to Accumulate

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

Figure 5. Inferring a Standalone Feedback Accumulate

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

Figure 6. Inferring a Shifter

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

Figure 7. Inferring a Subtract Operation

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