The DSP48 Primitive - Instantiating the DSP48

 

Behavioral inference has many advantages - relatively simple and compact code, works with signed and unsigned operands of any size, hides the intricacies of the DSP48 primitive from the user. It should definitely be the first choice when coding a DSP based design if it produces the desired results in terms of device utilization and clock speed.

 

That's a big if, when things do not go as you want there isn't much you can do - fighting with the synthesis tool is a waste of time and a game you normally cannot win.

 

Primitive instantiation gives you the total level of control you need but that's the only advantage and the list of drawbacks is long: the HDL code is large, verbose, hard to understand and maintain, the operands are of a very particular type and size with no flexibility, functional simulation is slower and you really need to understand how the primitive works and know what you are doing (I am not sure this is a disadvantage).

 

The DSP48 is a case apart from the other primitives that can be inferred through HDL synthesis, it is much bigger and more complex compared with the other CLB primitives. The 7-series DSP48E1 version has 25 generics and 49 ports. The UltraScale/UltraScale+ DSP48E2 version has 46 generics and 50 ports - a single DSP48 primitive instantiation is about 100 lines of HDL code and it is hard to tell what the primitive is doing just by looking at the code. This post is too short to include here example code even for a single DSP48 but you can find it in the Vivado GUI, in the Tools/Language Templates menu under Device Primitive Instantiation/ARITHMETIC/DSP, both VHDL and Verilog version for every FPGA family.

 

On top of that, there are complex interactions between the generic values and the ports, especially in the pre-adder input portion of the primitive and it is very easy to misconfigure it and get unexpected results- you should always simulate any DSP48 instantiation to make sure it does what you think it does. Corner case testing is another thorny issue, your design seems to work with a few simple testcases that you tried but how do you know you have not missed some rare combination of inputs that produces a functional failure?

 

Is there a way to combine the advantages of the two design flows while avoiding most of their disadvantages? There is no perfect solution but there are ways to make the life of the user instantiating DSP48 primitives easier. The solution I normally use is to create a wrapper file around the primitive and hide all the unpleasantness inside this wrapper.

 

The basic requirements in creating this wrapper are:

 

1. It should make instantiation easier, typically 10 lines instead of 100 lines of HDL code - we achieve this by having sensible default values on all generics and input ports so if you do not need to change them we can omit them in the instantiation. Similarly, output ports we do not use can be left unconnected and omitted

2. It should provide access to every possible DSP48 feature and every operating mode - every single DSP48 generic and port is also a generic and port at the wrapper level

3. The main operand ports A, B, C and D and the output result P are unconstrained arbitrary precision fixed point types instead of STD_LOGIC_VECTORs of a fixed size - the operands are sign extended at the MSB end and zero padded at the LSB end automatically and the result is truncated by dropping MSBs and LSBs as needed, no rounding or saturation is done explicitly and it is the user's responsibility to handle that outside the wrapper

4. The binary points of the input operands and the result are aligned automatically by the wrapper, there is no need for the user to consider implicit binary point position or shift the operands and the result to maintain proper numerical representation when using fractional numbers

5. No extra logic is generated inside the wrapper module, it will always contain only the DSP48 primitive

6. Ability to use X and Y generics to floorplan the primitive from HDL code

 

These features make the instantiation flow almost as compact and generic as behavioral inference, while still giving you access to all possible features and operating modes of the DSP48, something inference can never achieve. You still have to understand thoroughly the inner working of the primitive and simulate it to make sure it is configured properly. A good design practice is to keep the behavioral equivalent of the primitive commented out as part of the code for design documentation purposes. And of course, reading and understanding UG579, The UltraScale Architecture DSP Slice User Guide https://www.xilinx.com/support/documentation/user_guides/ug579-ultrascale-dsp.pdf is mandatory.

 

So here is how the DSP48E2 version of this generic wrapper would look:

 

library IEEE; 
use IEEE.STD_LOGIC_1164.all; 

use work.TYPES_PKG.all; –- this gives us access to the user defined SFIXED type

library UNISIM;
use UNISIM.vcomponents.all; –- this lets us instantiate the DSP48E2 primitive without the need of a component definition

entity DSP48E2GW is
 
generic(X,Y:INTEGER:=-1;                                           –- if positive place DSp48E2 at these coordinates, if negative leave floating
–- Feature Control Attributes: Data Path Selection
          AMULTSEL:STRING:="A";                                      –- Selects A input to multiplier (A, AD)
          A_INPUT:STRING:="DIRECT";                                  –- Selects A input source, "DIRECT" (A port) or "CASCADE" (ACIN port)
          BMULTSEL:STRING:="B";                                      –- Selects B input to multiplier (AD, B)
          B_INPUT:STRING:="DIRECT";                                  –- Selects B input source, "DIRECT" (B port) or "CASCADE" (BCIN port)
          PREADDINSEL:STRING:="A";                                   –- Selects input to preadder (A, B)
          RND:STD_LOGIC_VECTOR(47 downto 0):=X"000000000000";        –- Rounding Constant
          USE_MULT:STRING:="MULTIPLY";                               –- Select multiplier usage (DYNAMIC, MULTIPLY, NONE)
          USE_SIMD:STRING:="ONE48";                                  –- SIMD selection (FOUR12, ONE48, TWO24)
          USE_WIDEXOR:STRING:="FALSE";                               –- Use the Wide XOR function (FALSE, TRUE)
          XORSIMD:STRING:="XOR24_48_96";                             –- Mode of operation for the Wide XOR (XOR12, XOR24_48_96)
–- Pattern Detector Attributes: Pattern Detection Configuration
          AUTORESET_PATDET:STRING:="NO_RESET";                       –- NO_RESET, RESET_MATCH, RESET_NOT_MATCH
          AUTORESET_PRIORITY:STRING:="RESET";                        –- Priority of AUTORESET vs.CEP (CEP, RESET).
          MASK:STD_LOGIC_VECTOR(47 downto 0):=X"3fffffffffff";       –- 48-bit mask value for pattern detect (1=ignore)
          PATTERN:STD_LOGIC_VECTOR(47 downto 0):=X"000000000000";    –- 48-bit pattern match for pattern detect
          SEL_MASK:STRING:="MASK";                                   –- C, MASK, ROUNDING_MODE1, ROUNDING_MODE2
          SEL_PATTERN:STRING:="PATTERN";                             –- Select pattern value (C, PATTERN)
          USE_PATTERN_DETECT:STRING:="NO_PATDET";                    –- Enable pattern detect (NO_PATDET, PATDET)
– Programmable Inversion Attributes: Specifies built-in programmable inversion on specific pins
          IS_ALUMODE_INVERTED:STD_LOGIC_VECTOR(3 downto 0):=X"0";    –- Optional inversion for ALUMODE
          IS_CARRYIN_INVERTED:BIT:='0';                              –- Optional inversion for CARRYIN
          IS_CLK_INVERTED:
BIT:='0';                                  –- Optional inversion for CLK
          IS_INMODE_INVERTED:
STD_LOGIC_VECTOR(4 downto 0):="00000"–- Optional inversion for INMODE
          IS_OPMODE_INVERTED:STD_LOGIC_VECTOR(8 downto 0):="000000000"–- Optional inversion for OPMODE
          IS_RSTALLCARRYIN_INVERTED:
BIT:='0';                        –- Optional inversion for RSTALLCARRYIN
          IS_RSTALUMODE_INVERTED:BIT:='0';                           –- Optional inversion for RSTALUMODE
          IS_RSTA_INVERTED:BIT:='0';                                 –- Optional inversion for RSTA
          IS_RSTB_INVERTED:BIT:='0';                                 –- Optional inversion for RSTB
          IS_RSTCTRL_INVERTED:BIT:='0';                              –- Optional inversion for RSTCTRL
          IS_RSTC_INVERTED:BIT:='0';                                 –- Optional inversion for RSTC
          IS_RSTD_INVERTED:BIT:='0';                                 –- Optional inversion for RSTD
          IS_RSTINMODE_INVERTED:
BIT:='0';                            –- Optional inversion for RSTINMODE
          IS_RSTM_INVERTED:BIT:='0';                                 –- Optional inversion for RSTM
          IS_RSTP_INVERTED:BIT:='0';                                 –- Optional inversion for RSTP
– Register Control Attributes: Pipeline Register Configuration
          ACASCREG:INTEGER:=1;                                       –- Number of pipeline stages between A/ACIN and ACOUT (0-2)
          ADREG:INTEGER:=1;                                          –- Pipeline stages for pre-adder (0-1)
          ALUMODEREG:INTEGER:=1;                                     –- Pipeline stages for ALUMODE (0-1)
          AREG:INTEGER:=1;                                           –- Pipeline stages for A (0-2)
          BCASCREG:INTEGER:=1;                                       –- Number of pipeline stages between B/BCIN and BCOUT (0-2)
          BREG:INTEGER:=1;                                           –- Pipeline stages for B (0-2)
          CARRYINREG:INTEGER:=1;                                     –- Pipeline stages for CARRYIN (0-1)
          CARRYINSELREG:INTEGER:=1;                                  –- Pipeline stages for CARRYINSEL (0-1)
          CREG:INTEGER:=1;                                           –- Pipeline stages for C (0-1)
          DREG:INTEGER:=1;                                           –- Pipeline stages for D (0-1)
          INMODEREG:INTEGER:=1;                                      –- Pipeline stages for INMODE (0-1)
          MREG:INTEGER:=1;                                           –- Multiplier pipeline stages (0-1)
          OPMODEREG:INTEGER:=1;                                      –- Pipeline stages for OPMODE (0-1)
          PREG:INTEGER:=1);                                          –- Number of pipeline stages for P (0-1)
 
port(
–- Cascade inputs: Cascade Ports
       ACIN:in STD_LOGIC_VECTOR(29 downto 0):=(others=>'0');         –- 30-bit input: A cascade data
       BCIN:in STD_LOGIC_VECTOR(17 downto 0):=(others=>'0');         –- 18-bit input: B cascade
       CARRYCASCIN:in STD_LOGIC:='0';                                –- 1-bit input: Cascade carry
       MULTSIGNIN:in STD_LOGIC:='0';                                 –- 1-bit input: Multiplier sign cascade
       PCIN:in STD_LOGIC_VECTOR(47 downto 0):=(others=>'0');         –- 48-bit input: P cascade
–- Control inputs: Control Inputs/Status Bits
       ALUMODE:in STD_LOGIC_VECTOR(3 downto 0):=X"0";                –- 4-bit input: ALU control
       CARRYINSEL:in STD_LOGIC_VECTOR(2 downto 0):="000";            –- 3-bit input: Carry select
       CLK:in STD_LOGIC:='0';                                        –- 1-bit input: Clock
       INMODE:in STD_LOGIC_VECTOR(4 downto 0):="00000";              –- 5-bit input: INMODE control
       OPMODE:in STD_LOGIC_VECTOR(8 downto 0):="000110101";          –- 9-bit input: Operation mode - default is P<=C+A*B
–- Data inputs: Data Ports
       A:
in SFIXED;                                                  -– up to 30-bit input: A data
       B:in SFIXED;                                                  -– up to 18-bit input: B data
       C:in SFIXED;                                                  -– up to 48-bit input: C data
       CARRYIN:in STD_LOGIC:='0';                                    –- 1-bit input: Carry-in
       D:in SFIXED;                                                  –- up to 27-bit input: D data
–- Reset/Clock Enable inputs: Reset/Clock Enable Inputs
       CEA1:in STD_LOGIC:='1';                                       –- 1-bit input: Clock enable for 1st stage AREG
       CEA2:in STD_LOGIC:='1';                                       –- 1-bit input: Clock enable for 2nd stage AREG
       CEAD:in STD_LOGIC:='1';                                       –- 1-bit input: Clock enable for ADREG
       CEALUMODE:in STD_LOGIC:='1';                                  –- 1-bit input: Clock enable for ALUMODE
       CEB1:in STD_LOGIC:='1';                                       –- 1-bit input: Clock enable for 1st stage BREG
       CEB2:in STD_LOGIC:='1';                                       –- 1-bit input: Clock enable for 2nd stage BREG
       CEC:in STD_LOGIC:='1';                                        –- 1-bit input: Clock enable for CREG
       CECARRYIN:in STD_LOGIC:='1';                                  –- 1-bit input: Clock enable for CARRYINREG
       CECTRL:in STD_LOGIC:='1';                                     –- 1-bit input: Clock enable for OPMODEREG and CARRYINSELREG
       CED:in STD_LOGIC:='1';                                        –- 1-bit input: Clock enable for DREG
       CEINMODE:in STD_LOGIC:='1';                                   –- 1-bit input: Clock enable for INMODEREG
       CEM:
in STD_LOGIC:='1';                                        –- 1-bit input: Clock enable for MREG
       CEP:in STD_LOGIC:='1';                                        –- 1-bit input: Clock enable for PREG
       RSTA:
in STD_LOGIC:='0';                                       –- 1-bit input: Reset for AREG
       RSTALLCARRYIN:in STD_LOGIC:='0';                              –- 1-bit input: Reset for CARRYINREG
       RSTALUMODE:in STD_LOGIC:='0';                                 –- 1-bit input: Reset for ALUMODEREG
       RSTB:in STD_LOGIC:='0';                                       –- 1-bit input: Reset for BREG
       RSTC:in STD_LOGIC:='0';                                       –- 1-bit input: Reset for CREG
       RSTCTRL:in STD_LOGIC:='0';                                    –- 1-bit input: Reset for OPMODEREG and CARRYINSELREG
       RSTD:in STD_LOGIC:='0';                                       –- 1-bit input: Reset for DREG and ADREG
       RSTINMODE:in STD_LOGIC:='0';                                  –- 1-bit input: Reset for INMODEREG
       RSTM:in STD_LOGIC:='0';                                       –- 1-bit input: Reset for MREG
       RSTP:in STD_LOGIC:='0';                                       –- 1-bit input: Reset for PREG
–- Cascade outputs: Cascade Ports
       ACOUT:out STD_LOGIC_VECTOR(29 downto 0);                      –- 30-bit output: A port cascade
       BCOUT:out STD_LOGIC_VECTOR(17 downto 0);                      –- 18-bit output: B cascade
       CARRYCASCOUT:out STD_LOGIC;                                   –- 1-bit output: Cascade carry
       MULTSIGNOUT:out STD_LOGIC;                                    –- 1-bit output: Multiplier sign cascade
       PCOUT:out STD_LOGIC_VECTOR(47 downto 0);                      –- 48-bit output: Cascade output
–- Control outputs: Control Inputs/Status Bits
       OVERFLOW:out STD_LOGIC;                                       –- 1-bit output: Overflow in add/acc
       PATTERNBDETECT:out STD_LOGIC;                                 –- 1-bit output: Pattern bar detect
       PATTERNDETECT:out STD_LOGIC;                                  –- 1-bit output: Pattern detect
       UNDERFLOW:out STD_LOGIC;                                      –- 1-bit output: Underflow in add/acc
–- Data outputs: Data Ports
       CARRYOUT:out STD_LOGIC_VECTOR(3 downto 0);                    –- 4-bit output: Carry
       P:out SFIXED;                                                 –- up to 48-bit output: Primary data
       XOROUT:out STD_LOGIC_VECTOR(7 downto 0));                     –- 8-bit output: XOR data
end entityarchitecture WRAPPER of DSP48E2GW is
-
– internal STD_LOGIC_VECTOR signals of the right range for DSP48E2 primitive instantiation
 
signal slvA:STD_LOGIC_VECTOR(29 downto 0);
 
signal slvB:STD_LOGIC_VECTOR(17 downto 0);
 
signal slvD:STD_LOGIC_VECTOR(26 downto 0);
 
signal slvC,slvP:STD_LOGIC_VECTOR(47 downto 0);
-– resize SFIXED and convert to STD_LOGIC_VECTOR
 
function SFIXED_TO_SLV_RESIZE(I:SFIXED;hi,lo:INTEGER) return STD_LOGIC_VECTOR is
   
variable O:STD_LOGIC_VECTOR(hi-lo downto 0);
 
begin
   
for K in O'range loop
     
if K<I'low-lo then
        O(K):='0';
     
elsif K<I'length then
        O(K):=I(K+lo);
     
else
        O(K):=I(I'high);
     
end if;
   
end loop;
   
return O;
 
end;
-– convert STD_LOGIC_VECTOR to SFIXED and resize
 
function SLV_TO_SFIXED_RESIZE(I:STD_LOGIC_VECTOR;hi,lo:INTEGER;ofs:INTEGER:=0) return SFIXED is
   
variable O:SFIXED(hi downto lo);
 
begin
   
for K in O'range loop
     
if K<I'low+lo+ofs then
        O(K):='0';
     
elsif K-lo-ofs<I'length then
        O(K):=I(K-lo-ofs);
     
else
        O(K):=I(I'high);
     
end if;
   
end loop;
   
return O;
 
end;

 
function MIN(X,Y:INTEGER) return INTEGER is
 
begin
   
if X<Y then
     
return X;
   
else
     
return Y;
   
end if;
 
end

  function LOC_STRING(X,Y:INTEGER) return STRING is
 
begin
   
if (X>=0) and (Y>=0) then
     
return "DSP48E2_X"&INTEGER'image(X)&"Y"&INTEGER'image(Y);
   
else
      return "";
   
end if;
 
end;
 
attribute loc:STRING;
 
attribute loc of ds:label is LOC_STRING(X,Y);

 
constant AD_low:INTEGER:=MIN(A'low,D'low);
 
constant BD_low:INTEGER:=MIN(B'low,D'low);
 
constant CAD_low:INTEGER:=MIN(AD_low+B'low,P'low);
 
constant CBD_low:INTEGER:=MIN(BD_low+A'low,P'low);
begin
-– sign extend and zero pad inputs and convert from SFIXED to STD_LOGIC_VECTOR
  slvA<=SFIXED_TO_SLV_RESIZE(A,AD_low+slvA'length-1,AD_low) when PREADDINSEL="A" else
        SFIXED_TO_SLV_RESIZE(A,A'low+slvA'length-1,A'low); -– when PREADDINSEL="B"
  slvB<=SFIXED_TO_SLV_RESIZE(B,B'low+slvB'length-1,B'low) when PREADDINSEL="A" else
        SFIXED_TO_SLV_RESIZE(B,BD_low+slvB'length-1,BD_low); -– when PREADDINSEL="B"
  slvC<=SFIXED_TO_SLV_RESIZE(C,CAD_low+slvC'length-1,CAD_low) when PREADDINSEL="A" else
        SFIXED_TO_SLV_RESIZE(C,CBD_low+slvC'length-1,CBD_low); -– when PREADDINSEL="B"
  slvD<=SFIXED_TO_SLV_RESIZE(D,AD_low+slvD'length-1,AD_low) when PREADDINSEL="A" else
        SFIXED_TO_SLV_RESIZE(D,BD_low+slvD'length-1,BD_low); –- when PREADDINSEL="B"
-– actual DSP48E2 primitive instantiation
  ds:DSP48E2 generic map(
-– Feature Control Attributes: Data Path Selection
                         AMULTSEL => AMULTSEL,                                   –- Selects A input to multiplier (A, AD)
                         A_INPUT => A_INPUT,                                     –- Selects A input source, "DIRECT" (A port) or "CASCADE" (ACIN port)
                         BMULTSEL => BMULTSEL,                                   –- Selects B input to multiplier (AD, B)
                         B_INPUT => B_INPUT,                                     –- Selects B input source, "DIRECT" (B port) or "CASCADE" (BCIN port)
                         PREADDINSEL => PREADDINSEL,                             –- Selects input to preadder (A, B)
                         RND => RND,                                             –- Rounding Constant
                         USE_MULT => USE_MULT,                                   –- Select multiplier usage (DYNAMIC, MULTIPLY, NONE)
                         USE_SIMD => USE_SIMD,                                  
–- SIMD selection (FOUR12, ONE48, TWO24)
                         USE_WIDEXOR => USE_WIDEXOR,                             –- Use the Wide XOR function (FALSE, TRUE)
                         XORSIMD => XORSIMD,                                     –- Mode of operation for the Wide XOR (XOR12, XOR24_48_96)
-
– Pattern Detector Attributes: Pattern Detection Configuration
                         AUTORESET_PATDET => AUTORESET_PATDET,                   –- NO_RESET, RESET_MATCH, RESET_NOT_MATCH
                         AUTORESET_PRIORITY => AUTORESET_PRIORITY,               –- Priority of AUTORESET vs.CEP (CEP, RESET).
                         MASK => MASK,                                           –- 48-bit mask value for pattern detect (1=ignore)
                         PATTERN => PATTERN,                                     –- 48-bit pattern match for pattern detect
                         SEL_MASK => SEL_MASK,                                   –- C, MASK, ROUNDING_MODE1, ROUNDING_MODE2
                         SEL_PATTERN => SEL_PATTERN,                             –- Select pattern value (C, PATTERN)
                         USE_PATTERN_DETECT => USE_PATTERN_DETECT,               –- Enable pattern detect (NO_PATDET, PATDET)
-– Programmable Inversion Attributes: Specifies built-in programmable inversion on specific pins

                         IS_ALUMODE_INVERTED => IS_ALUMODE_INVERTED,            
–- Optional inversion for ALUMODE
                         IS_CARRYIN_INVERTED => IS_CARRYIN_INVERTED,             –- Optional inversion for CARRYIN
                         IS_CLK_INVERTED => IS_CLK_INVERTED,                     –- Optional inversion for CLK
                         IS_INMODE_INVERTED => IS_INMODE_INVERTED,               –- Optional inversion for INMODE
                         IS_OPMODE_INVERTED => IS_OPMODE_INVERTED,               –- Optional inversion for OPMODE
                         IS_RSTALLCARRYIN_INVERTED => IS_RSTALLCARRYIN_INVERTED, –- Optional inversion for RSTALLCARRYIN
                         IS_RSTALUMODE_INVERTED => IS_RSTALUMODE_INVERTED,       –- Optional inversion for RSTALUMODE
                         IS_RSTA_INVERTED => IS_RSTA_INVERTED,                   –- Optional inversion for RSTA
                         IS_RSTB_INVERTED => IS_RSTB_INVERTED,                   –- Optional inversion for RSTB
                         IS_RSTCTRL_INVERTED => IS_RSTCTRL_INVERTED,             –- Optional inversion for RSTCTRL
                         IS_RSTC_INVERTED => IS_RSTC_INVERTED,                   –- Optional inversion for RSTC
                         IS_RSTD_INVERTED => IS_RSTD_INVERTED,                   –- Optional inversion for RSTD
                         IS_RSTINMODE_INVERTED => IS_RSTINMODE_INVERTED,         –- Optional inversion for RSTINMODE
                         IS_RSTM_INVERTED => IS_RSTM_INVERTED,                   –- Optional inversion for RSTM
                         IS_RSTP_INVERTED => IS_RSTP_INVERTED,                   –- Optional inversion for RSTP
-
– Register Control Attributes: Pipeline Register Configuration
                         ACASCREG => ACASCREG,                                   –- Number of pipeline stages between A/ACIN and ACOUT (0-2)
                         ADREG => ADREG,                                         –- Pipeline stages for pre-adder (0-1)
                         ALUMODEREG => ALUMODEREG,                               –- Pipeline stages for ALUMODE (0-1)
                         AREG => AREG,                                           –- Pipeline stages for A (0-2)
                         BCASCREG => BCASCREG,                                   –- Number of pipeline stages between B/BCIN and BCOUT (0-2)
                         BREG => BREG,                                           –- Pipeline stages for B (0-2)
                         CARRYINREG => CARRYINREG,                               –- Pipeline stages for CARRYIN (0-1)
                         CARRYINSELREG => CARRYINSELREG,                         –- Pipeline stages for CARRYINSEL (0-1)
                         CREG => CREG,                                           –- Pipeline stages for C (0-1)
                         DREG => DREG,                                           –- Pipeline stages for D (0-1)
                         INMODEREG => INMODEREG,                                 –- Pipeline stages for INMODE (0-1)
                         MREG => MREG,                                           –- Multiplier pipeline stages (0-1)
                         OPMODEREG => OPMODEREG,                                 –- Pipeline stages for OPMODE (0-1)
                         PREG => PREG)                                           –- Number of pipeline stages for P (0-1)
            
port map(
– Cascade inputs: Cascade Ports
                      ACIN => ACIN,                                              –- 30-bit input: A cascade data
                      BCIN => BCIN,                                              –- 18-bit input: B cascade
                      CARRYCASCIN => CARRYCASCIN,                                –- 1-bit input: Cascade carry
                      MULTSIGNIN => MULTSIGNIN,                                  –- 1-bit input: Multiplier sign cascade
                      PCIN => PCIN,                                              –- 48-bit input: P cascade
-– Control inputs: Control Inputs/Status Bits
                      ALUMODE => ALUMODE,                                        –- 4-bit input: ALU control
                      CARRYINSEL => CARRYINSEL,                                  –- 3-bit input: Carry select
                      CLK => CLK,                                                –- 1-bit input: Clock
                      INMODE => INMODE,                                          –- 5-bit input: INMODE control
                      OPMODE => OPMODE,                                          –- 9-bit input: Operation mode
-
– Data inputs: Data Ports
                      A => slvA,                                                 –- 30-bit input: A data
                      B => slvB,                                                 –- 18-bit input: B data
                      C => slvC,                                                 –- 48-bit input: C data
                      CARRYIN => CARRYIN,                                        –- 1-bit input: Carry-in
                      D => slvD,                                                 –- 27-bit input: D data
-– Reset/Clock Enable inputs: Reset/Clock Enable Inputs

                      CEA1 => CEA1,                                             
–- 1-bit input: Clock enable for 1st stage AREG
                      CEA2 => CEA2,                                              –- 1-bit input: Clock enable for 2nd stage AREG
                      CEAD => CEAD,                                              –- 1-bit input: Clock enable for ADREG
                      CEALUMODE => CEALUMODE,                                    –- 1-bit input: Clock enable for ALUMODE
                      CEB1 => CEB1,                                              –- 1-bit input: Clock enable for 1st stage BREG
                      CEB2 => CEB2,                                              –- 1-bit input: Clock enable for 2nd stage BREG
                      CEC => CEC,                                                –- 1-bit input: Clock enable for CREG
                      CECARRYIN => CECARRYIN,                                    –- 1-bit input: Clock enable for CARRYINREG
                      CECTRL => CECTRL,                                          –- 1-bit input: Clock enable for OPMODEREG and CARRYINSELREG
                      CED => CED,                                                –- 1-bit input: Clock enable for DREG
                      CEINMODE => CEINMODE,                                      –- 1-bit input: Clock enable for INMODEREG
                      CEM => CEM,                                                –- 1-bit input: Clock enable for MREG
                      CEP => CEP,                                                –- 1-bit input: Clock enable for PREG
                      RSTA => RSTA,                                              –- 1-bit input: Reset for AREG
                      RSTALLCARRYIN => RSTALLCARRYIN,                            –- 1-bit input: Reset for CARRYINREG
                      RSTALUMODE => RSTALUMODE,                                  –- 1-bit input: Reset for ALUMODEREG
                      RSTB => RSTB,                                              –- 1-bit input: Reset for BREG
                      RSTC => RSTC,                                              –- 1-bit input: Reset for CREG
                      RSTCTRL => RSTCTRL,                                        –- 1-bit input: Reset for OPMODEREG and CARRYINSELREG
                      RSTD => RSTD,                                              –- 1-bit input: Reset for DREG and ADREG
                      RSTINMODE => RSTINMODE,                                    –- 1-bit input: Reset for INMODEREG
                      RSTM => RSTM,                                             
–- 1-bit input: Reset for MREG
                      RSTP => RSTP,                                              –- 1-bit input: Reset for PREG
-– Cascade outputs: Cascade Ports

                      ACOUT => ACOUT,                                           
–- 30-bit output: A port cascade
                      BCOUT => BCOUT,                                            –- 18-bit output: B cascade
                      CARRYCASCOUT => CARRYCASCOUT,                              –- 1-bit output: Cascade carry
                      MULTSIGNOUT => MULTSIGNOUT,                                –- 1-bit output: Multiplier sign cascade
                      PCOUT => PCOUT,                                            –- 48-bit output: Cascade output
-
– Control outputs: Control Inputs/Status Bits
                      OVERFLOW => OVERFLOW,                                      –- 1-bit output: Overflow in add/acc
                      PATTERNBDETECT => PATTERNBDETECT,                          –- 1-bit output: Pattern bar detect
                      PATTERNDETECT => PATTERNDETECT,                            –- 1-bit output: Pattern detect
                      UNDERFLOW => UNDERFLOW,                                    –- 1-bit output: Underflow in add/acc
-
– Data outputs: Data Ports
                      CARRYOUT => CARRYOUT,                                     
–- 4-bit output: Carry
                      P => slvP,                                                 –- 48-bit output: Primary data
                      XOROUT => XOROUT);                                        
–- 8-bit output: XOR data – resize output result

  P<=SLV_TO_SFIXED_RESIZE(slvP,P'high,P'low,A'low+B'low-P'low);
end WRAPPER;

 

It is quite big, this is the kind of primitive instantiation verbosity that the wrapper will help us avoid. The wrapper is called DSP48E2GW and it has exactly the same generics and ports as the actual primitive, with a few notable exceptions. All generics and input ports have sensible default values, for example, all clock enable inputs are tied high, all synchronous resets are tied low, all internal pipeline registers are enabled and so on. You can even change these default values if you would prefer slightly different ones. There are two new generics X and Y, if you omit them the -1 default values will ensure there is no LOC constraint but if you assign them both positive values the DSP48E2 primitive will be placed at that particular device location. The five ports A, B, C, D and P are not STD_LOGIC_VECTOR but instead unconstrained SFIXED, which means that they cannot be omitted, even when not used - just define a constant SFIXED signal of proper range, give it a value of 0.0 and tie the unused ports low. Everything else is exactly as the DSP48E2 primitive itself. Inside the wrapper a couple of functions are used to convert between SFIXED and STD_LOGIC_VECTOR, sign extending and zero padding or truncating when needed. The binary point alignment between these five SFIXED ports is also handled automatically by the wrapper.

 

This DSP48E2 generic wrapper module is not trivial and is the result of a lot of frustration with the instantiation of the raw primitive. I no longer instantiate DSP48E2 primitives in my designs as such, when not using behavioral inference I exclusively use this generic wrapper and I strongly suggest you do the same or at least develop your own along the same lines.

 

In the next post we will see how to use this DSP48 generic wrapper to create the non-symmetric and symmetric FIR examples we tried to infer in the previous posts with mixed results.

 

Back to the top: The Art of FPGA Design