Xilinx DSP48E1原语的介绍和使用


一、什么是DSP48E1?

  DSP48E1是7系列底层资源之一,用来做数字逻辑运算的。代码里的大位宽的加法、乘法都会综合成DSP来计算,我们调用的加法器IP、乘法器IP也大多数是调用这个原语。因此,我们学会底层原语的使用有时候比直接调用IP更灵活。我们打开芯片结构图可以看到:

在这里插入图片描述
  DSP48E1一列一列的存在slicem周围,这样能尽可能保证我们的运算结果到达FF里的路径最短,降低布线延迟。

二、DSP48E1的内部结构

  DSP48E1的结构顶层框图如下所示;对于大部分用户使用情况来看只有五个端口,输入ABCD,输出P:

在这里插入图片描述

  1. 输入A为30位宽,输入B为18位宽,输入C为48位宽,输入D为25位宽,输出P为48位宽。
  2. ①为预加器,可以将A + D 的结果输出给下一级。
  3. ②为乘法器,可以将A + D 的结果 和 B相乘,一起实现 (A+D)*B。
  4. ③为累加器,可以将输入的信号相与、相加、相减,一起实现(A+D)*B ± C 或者 (A+D)*B ± P
  5. Pattern Detector 为模式匹配器,可以设定对应的匹配模式然后输出对应的信号。

  整个DSP48E1的内部详细结构路径如下所示:
在这里插入图片描述

  1. 走线箭头上的 / 表示数据位宽
  2. 带 * 号的表示与级联相关,走的是专用路径,用户不能直接指定它的路由路径
  3. 除了上面说的输入 ABCD 和输出 P 五个端口,其它的都是配置信号,用来配置整个DSP工作模式和流水级数的
  4. Dual B Register 为输入端口B 的流水寄存器,主要是对B进行打拍的
  5. Dual A,D and Pre-adder 为 输入端口A和D的流水线寄存器和预加器,预加的结果取最低25位给后级的乘法器与B相乘

  Dual B Register 和Dual A,D and Pre-adder 的结构如下所示:

在这里插入图片描述

  1. 在Dual B Register中,输入为B端口或者上一级DSP级联过来的B端口,然后可配置流水级数,通过CEB1、CEB2,以及INMODE[4]选择输出。
  2. 在Dual A,D and Pre-adder中,A的路径和B端口一致,输入端口D可以选择一级流水然后和A相加或者相减,取结果的25位然后输出给后级。

三、DSP48E1原语端口

  下图显示了 DSP48E1 原语以及输入和输出端口以及每个端口的位宽:

在这里插入图片描述

  1. 为用户输入数据端口
  2. 为配置模式端口
  3. 为数据寄存器使能端口
  4. 为模式寄存器使能端口
  5. 为寄存器复位端口
  6. 级联输入端口
  7. 为级联输出端口
  8. 运算结果输出端口
  9. 级联输出端口
  10. 模式检测信号输出
  11. 溢出指示信号
端口名方向位宽 描述
A输入30 A[24:0] 是乘法器或预加法器的 A 输入,A[29:0] 是第二级加法器/减法器或逻辑函数的 A:B 连接输入的最高有效位
ACIN输入30 上一级DSP48E1的ACOUT 的级联数据输入
ACOUT输出30 级联数据输出至下一个DSP48E1的ACIN
ALUMODE输入4 控制第二级逻辑功能的选择,相加、相与、相减等
B输入18 乘法器的 B 输入。B[17:0] 是第二级加法器/减法器或逻辑函数的 A:B 连接输入的最低有效位
BCIN输入18 来自前一个 DSP48E1的BCOUT 的级联数据输入
BCOUT输出18 级联数据输出至下一个DSP48E1片的BCIN
C输入48 数据输入至第二级加法器/减法器、模式检测器或逻辑函数
CARRYCASCIN输入1 来自前一个 DSP48E1 切片的 CARRYCASCOUT 的级联进位输入
CARRYCASCOUT输出1 级联进位输出至下一个 DSP48E1 切片的 CARRYCASCIN
CARRYIN输入1 来自用户的FPGA逻辑输入
CARRYINSEL输入3 选择进位源
CARRYOUT输出4 累加器/加法器/逻辑单元的每个 12 位字段输出 4 位进位。常规 48 位操作仅使用 CARRYOUT3
CEA1输入1 第1个 A(输入)寄存器的时钟使能。仅当 AREG = 2 或 INMODE[0]= 1 时才使用 A1
CEA2输入1 第2个 A(输入)寄存器的时钟使能。仅当 AREG = 1 或 2 且 INMODE[0]=0 时才使用 A2
CEAD输入1 预加法器输出 AD 寄存器的时钟使能
CEALUMODE输入1 为 ALUMODE(控制输入)寄存器提供时钟使能
CEB1输入1 第1个 B(输入)寄存器的时钟使能。仅当 BREG = 2 或 INMODE[4] = 1 时才使用 B1
CEB2输入1 第2个 B(输入)寄存器的时钟使能。仅当 BREG = 1 或 2 且 INMODE[4]=0 时才使用 B2
CEC输入1 C(输入)寄存器的时钟使能
CECARRYIN输入1 CARRYIN(来自 FPGA 逻辑的输入)寄存器的时钟使能
CECTRL输入1 OPMODE 和 CARRYINSEL(控制输入)寄存器的时钟使能
CED输入1 D(输入)寄存器的时钟使能
CEINMODE输入1 INMODE 控制输入寄存器的时钟使能
CEM输入1 乘法 M寄存器的时钟使能
CEP输入1 P寄存器的时钟使能
CLK输入1 CLK 是 DSP48E1 输入时钟,所有内部寄存器和触发器共用
D输入25 25 位数据输入到预加法器或乘法器的另一个输入
INMODE输入5 这5个控制位选择预加法器、A、B 和 D 输入以及输入寄存器的功能。如果未连接,这些位应默认为 5’b00000
MULTSIGNIN输入1 用于 MACC 扩展的上一个 DSP48E1 切片的乘积结果的符号
MULTSIGNOUT输出1 乘法结果的符号级联到下一个 DSP48E1 切片,用于 MACC 扩展
OPMODE输入7 控制 DSP48E1 切片中的 X、Y 和 Z 多路复用器的输入
OVERFLOW输出1 与模式检测器的适当设置一起使用时的溢出指示器
P输出48 来自第二级加法器/减法器或逻辑函数的数据输出
PATTERNBDETECT输出1 P[47:0]与模式匹配指示信号
PATTERNDETECT输出1 P[47:0]与模式匹配指示信号
PCIN输入48 从上一个 DSP48E1 片的 PCOUT 级联数据输入到加法器
PCOUT输出48 级联数据输出至下一个DSP48E1片的PCIN

  其他的都是复位各个寄存器的复位信号了,这里就不一一展示了。

四、DSP48E1操作模式

  DSP48E1 芯片的数学部分由一个 25 位预加法器、一个 25 位 x 18 位二进制补码乘法器以及三个 48 位数据路径多路复用器(输出 X、Y 和 Z)组成。接下来是一个三输入加法器/减法器或双输入逻辑单元。

在这里插入图片描述
  下面公式展示了P输出的多种运算组合:

在这里插入图片描述

  乘法器的两个 43 位部分乘积在发送到加法器/减法器之前会进行符号扩展至 48 位。当不使用第一级乘法器时,48 位双输入按位逻辑函数可实现 AND、OR、NOT、NAND、NOR、XOR 和 XNOR。这些函数的输入是通过 X 和 Z 多路复用器选择的 A:B、C、P 或 PCIN,Y 多路复用器根据逻辑运算选择全 1 或全 0。

4.1 属性端口说明

端口名设置(默认) 描述
ACASCREG 0, 1, 2 (1) 与 AREG 一起,选择 A 级联路径 ACOUT 上的 A 输入寄存器数量,此属性必须等于或小于 AREG 值:AREG = 0:ACASCREG 必须为 0 ;AREG = 1:ACASCREG 必须为 1 ;AREG = 2:ACASCREG 可以为 1 或 2
ADREG 0, 1 (1) 选择 AD寄存器的数量
ALUMODEREG 0, 1 (1) 选择 ALUMODE 输入寄存器的数量
AREG 0, 1, 2 (1) 选择 A 输入寄存器的数量。选择 1 时,使用 A2 寄存器
BCASCREG 0, 1, 2 (1) 与 BREG 一起,选择 B 级联路径 BCOUT 上的 B 输入寄存器数量。此属性必须等于或小于 BREG 值:BREG = 0:BCASCREG 必须为 0 ; BREG = 1:BCASCREG 必须为 1 ;BREG = 2:BCASCREG 可以为 1 或 2
BREG 0, 1, 2 (1) 选择B输入寄存器的数量。选择1时,使用B2寄存器
CARRYINREG 0, 1(1) 选择 CARRYIN 输入寄存器的数量
CARRYINSELREG 0, 1(1) 选择 CARRYINSEL 输入寄存器的数量
CREG 0, 1(1) 选择 C ​​输入寄存器的数量
DREG 0, 1(1) 选择 D ​​输入寄存器的数量
INMODEREG 0, 1(1) 选择 INMODE 输入寄存器的数量
MREG 0, 1(1) 选择 M 流水线寄存器的数量
OPMODEREG 0, 1(1) 选择 OPMODE 输入寄存器的数量
PREG 0, 1(1) 选择P输出寄存器的数量
A_INPUT DIRECT, CASCADE (DIRECT) 选择 A 端口的输入为直接输入 (DIRECT) 或来自前一个切片的级联输入 (CASCADE)
B_INPUT DIRECT, CASCADE (DIRECT) 选择 B 端口的输入为直接输入 (DIRECT) 或来自前一个切片的级联输入 (CASCADE)
USE_DPORT TRUE, FALSE (FALSE) 确定预加器和 D 端口是否使用
USE_MULT NONE, MULTIPLY, DYNAMIC (MULTIPLY) 选择乘法器的使用。设置为 NONE 可在仅使用加法器/逻辑单元时节省电量。 DYNAMIC 设置表示用户正在动态切换 A*B 和 A:B 操作
USE_SIMD ONE48, TWO24,FOUR12 (ONE48) 选择加法器/减法器的操作模式。属性设置可以是一个 48 位加法器模式 (ONE48)、两个 24 位加法器模式 (TWO24) 或四个 12 位加法器模式 (FOUR12)
AUTORESET_PATDETNO_RESET, RESET_MATCH, RESET_NOT_MATCH (NO_RESET) 如果在此时钟周期上发生了模式检测事件,则在下一个时钟周期自动重置 P 寄存器(累计值或计数器值)
MASK48 位字段 此 48 位值用于在模式检测期间屏蔽某些位。当 MASK 位设置为 1 时,将忽略相应的模式位。当 MASK 位设置为 0 时,将比较模式位
PATTERN48 位字段 该 48 位值用于模式检测器
SEL_MASK48 位字段 选择用于模式检测器的掩码。C 和 MASK 设置用于模式检测器的标准用途(计数器、溢出检测等)。ROUNDING_MODE1(Cbar 左移 1)和 ROUNDING_MODE2(C-bar 左移 2)
SEL_PATTERNPATTERN, C (PATTERN) 选择模式字段的输入源。输入源可以是 48 位动态“C”输入,也可以是 48 位静态属性字段
USE_PATTERN_DETECTNO_PATDET, PATDET (NO_PATDET) 选择是否使用 (PATDET) 或不使用 (NO_PATDET) 模式检测器和相关功能。此属性仅用于速度规范和仿真模型目的

4.2 INMODE[3:0] 功能

  INMODE是用来配置Dual B Register 和Dual A,D and Pre-adder流水级数的,具体配置路径如下所示:

在这里插入图片描述
在这里插入图片描述
  整个配置功能表如下所示:

在这里插入图片描述
  INMODE[4]选择B寄存器输出:

在这里插入图片描述

4.3 OPMODE[6:0] 功能

  OPMODE的功能主要是控制X、Y、Z多路选择器的输出:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.4 ALUMODE [3:0] 功能

  4 位 ALUMODE 控制第二级加法/减法/逻辑单元的行为。 ALUMODE = 0000 选择 Z + (X + Y + CIN) 形式的加法运算。CIN 是 CARRYIN 多路复用器的输出

在这里插入图片描述
  CARRYIN 多路复用器输出如下所示:

在这里插入图片描述
在这里插入图片描述
  通过使用第二级三输入加法器,DSP48E1 片能够执行加法、减法和简单的逻辑功能。 下表列出了可以在三输入加法器/减法器/逻辑单元的第二级中实现的逻辑功能:

在这里插入图片描述

五、原码、反码、补码的运算

  在验证DSP之前,我们来回顾一下在计算机中的运算机制。我们知道计算机只能识别二进制数,而数字分为有符号数,无符号数。那么为了计算机能区分出来有符号数,无符号数,就用最高位作为符号位来区分;也就有了原码、反码、补码的机制。
  我们知道,正数的原码、反码、补码相同;负数的反码等于原码(除了符号位)取反,补码等于反码 + 1。而在计算机中,数字通常是由补码的形式存放,计算也是以补码的形式计算。
  例如,一个8位正整数 5的原码、反码、补码都 = 0000_0101,一个8位正整数9的原码、反码、补码都=0000_1001;因此 8 + 5 = 0000_0101 + 0000_1001 = 0000_1110 = 14;乘法的话使用的是布斯公式,具体想了解的可以去搜一下,这里不过多讲解。
  例如,一个8位的负正数 -6的原码= 1000_0110,反码= 1111_1001,补码=1111_1010;一个8位负整数 -5的原码= 1000_0101,反码=1111_1010,补码=1111_1011;因此 -6 - 5 = 1111_1010 + 1111_1011 = 1_1111_0101,最高位舍弃得到补码1111_0101,符号位不变,取反+ 1 = 1000_1011 = -11。 在DSP48E1里面的运算也是基于二进制补码。

六、仿真验证

  前面介绍DSP内部结构以及端口说明,我们来实际仿真一下,根据自己的需求来例化不同的功能。由上面的端口说明可知,大部分使用DSP48E1只需要配置INMODE、OPMODE、ALUMODE就能定制出自己想要的算术功能。DSP48E1原语如下:

DSP48E1 #(
      // Feature Control Attributes: Data Path Selection
      .A_INPUT("DIRECT"),               // Selects A input source, "DIRECT" (A port) or "CASCADE" (ACIN port)
      .B_INPUT("DIRECT"),               // Selects B input source, "DIRECT" (B port) or "CASCADE" (BCIN port)
      .USE_DPORT("FALSE"),              // Select D port usage (TRUE or FALSE)
      .USE_MULT("MULTIPLY"),            // Select multiplier usage ("MULTIPLY", "DYNAMIC", or "NONE")
      .USE_SIMD("ONE48"),               // SIMD selection ("ONE48", "TWO24", "FOUR12")
      // Pattern Detector Attributes: Pattern Detection Configuration
      .AUTORESET_PATDET("NO_RESET"),    // "NO_RESET", "RESET_MATCH", "RESET_NOT_MATCH" 
      .MASK(48'h3fffffffffff),          // 48-bit mask value for pattern detect (1=ignore)
      .PATTERN(48'h000000000000),       // 48-bit pattern match for pattern detect
      .SEL_MASK("MASK"),                // "C", "MASK", "ROUNDING_MODE1", "ROUNDING_MODE2" 
      .SEL_PATTERN("PATTERN"),          // Select pattern value ("PATTERN" or "C")
      .USE_PATTERN_DETECT("NO_PATDET"), // Enable pattern detect ("PATDET" or "NO_PATDET")
      // Register Control Attributes: Pipeline Register Configuration
      .ACASCREG(1),                     // Number of pipeline stages between A/ACIN and ACOUT (0, 1 or 2)
      .ADREG(1),                        // Number of pipeline stages for pre-adder (0 or 1)
      .ALUMODEREG(1),                   // Number of pipeline stages for ALUMODE (0 or 1)
      .AREG(1),                         // Number of pipeline stages for A (0, 1 or 2)
      .BCASCREG(1),                     // Number of pipeline stages between B/BCIN and BCOUT (0, 1 or 2)
      .BREG(1),                         // Number of pipeline stages for B (0, 1 or 2)
      .CARRYINREG(1),                   // Number of pipeline stages for CARRYIN (0 or 1)
      .CARRYINSELREG(1),                // Number of pipeline stages for CARRYINSEL (0 or 1)
      .CREG(1),                         // Number of pipeline stages for C (0 or 1)
      .DREG(1),                         // Number of pipeline stages for D (0 or 1)
      .INMODEREG(1),                    // Number of pipeline stages for INMODE (0 or 1)
      .MREG(1),                         // Number of multiplier pipeline stages (0 or 1)
      .OPMODEREG(1),                    // Number of pipeline stages for OPMODE (0 or 1)
      .PREG(1)                          // Number of pipeline stages for P (0 or 1)
   )
   DSP48E1_inst (
      // Cascade: 30-bit (each) output: Cascade Ports
      .ACOUT(ACOUT),                   // 30-bit output: A port cascade output
      .BCOUT(BCOUT),                   // 18-bit output: B port cascade output
      .CARRYCASCOUT(CARRYCASCOUT),     // 1-bit output: Cascade carry output
      .MULTSIGNOUT(MULTSIGNOUT),       // 1-bit output: Multiplier sign cascade output
      .PCOUT(PCOUT),                   // 48-bit output: Cascade output
      // Control: 1-bit (each) output: Control Inputs/Status Bits
      .OVERFLOW(OVERFLOW),             // 1-bit output: Overflow in add/acc output
      .PATTERNBDETECT(PATTERNBDETECT), // 1-bit output: Pattern bar detect output
      .PATTERNDETECT(PATTERNDETECT),   // 1-bit output: Pattern detect output
      .UNDERFLOW(UNDERFLOW),           // 1-bit output: Underflow in add/acc output
      // Data: 4-bit (each) output: Data Ports
      .CARRYOUT(CARRYOUT),             // 4-bit output: Carry output
      .P(P),                           // 48-bit output: Primary data output
      // Cascade: 30-bit (each) input: Cascade Ports
      .ACIN(ACIN),                     // 30-bit input: A cascade data input
      .BCIN(BCIN),                     // 18-bit input: B cascade input
      .CARRYCASCIN(CARRYCASCIN),       // 1-bit input: Cascade carry input
      .MULTSIGNIN(MULTSIGNIN),         // 1-bit input: Multiplier sign input
      .PCIN(PCIN),                     // 48-bit input: P cascade input
      // Control: 4-bit (each) input: Control Inputs/Status Bits
      .ALUMODE(ALUMODE),               // 4-bit input: ALU control input
      .CARRYINSEL(CARRYINSEL),         // 3-bit input: Carry select input
      .CLK(CLK),                       // 1-bit input: Clock input
      .INMODE(INMODE),                 // 5-bit input: INMODE control input
      .OPMODE(OPMODE),                 // 7-bit input: Operation mode input
      // Data: 30-bit (each) input: Data Ports
      .A(A),                           // 30-bit input: A data input
      .B(B),                           // 18-bit input: B data input
      .C(C),                           // 48-bit input: C data input
      .CARRYIN(CARRYIN),               // 1-bit input: Carry input signal
      .D(D),                           // 25-bit input: D data input
      // Reset/Clock Enable: 1-bit (each) input: Reset/Clock Enable Inputs
      .CEA1(CEA1),                     // 1-bit input: Clock enable input for 1st stage AREG
      .CEA2(CEA2),                     // 1-bit input: Clock enable input for 2nd stage AREG
      .CEAD(CEAD),                     // 1-bit input: Clock enable input for ADREG
      .CEALUMODE(CEALUMODE),           // 1-bit input: Clock enable input for ALUMODE
      .CEB1(CEB1),                     // 1-bit input: Clock enable input for 1st stage BREG
      .CEB2(CEB2),                     // 1-bit input: Clock enable input for 2nd stage BREG
      .CEC(CEC),                       // 1-bit input: Clock enable input for CREG
      .CECARRYIN(CECARRYIN),           // 1-bit input: Clock enable input for CARRYINREG
      .CECTRL(CECTRL),                 // 1-bit input: Clock enable input for OPMODEREG and CARRYINSELREG
      .CED(CED),                       // 1-bit input: Clock enable input for DREG
      .CEINMODE(CEINMODE),             // 1-bit input: Clock enable input for INMODEREG
      .CEM(CEM),                       // 1-bit input: Clock enable input for MREG
      .CEP(CEP),                       // 1-bit input: Clock enable input for PREG
      .RSTA(RSTA),                     // 1-bit input: Reset input for AREG
      .RSTALLCARRYIN(RSTALLCARRYIN),   // 1-bit input: Reset input for CARRYINREG
      .RSTALUMODE(RSTALUMODE),         // 1-bit input: Reset input for ALUMODEREG
      .RSTB(RSTB),                     // 1-bit input: Reset input for BREG
      .RSTC(RSTC),                     // 1-bit input: Reset input for CREG
      .RSTCTRL(RSTCTRL),               // 1-bit input: Reset input for OPMODEREG and CARRYINSELREG
      .RSTD(RSTD),                     // 1-bit input: Reset input for DREG and ADREG
      .RSTINMODE(RSTINMODE),           // 1-bit input: Reset input for INMODEREG
      .RSTM(RSTM),                     // 1-bit input: Reset input for MREG
      .RSTP(RSTP)                      // 1-bit input: Reset input for PREG
   );

6.1 B*D的仿真

  我们先只使用乘法器;DSP48E1里面只有一个乘法器资源,两个输入位宽分别是25、18位,因此输出最大位宽为43位。由上面DSP48E1内部结构可知,乘法器的一个输入只能是B端口,另一端口输入可以是A[24:0],D、或者A+D的低25位。

  流水分析:

  • B端口可配置 0、1、2级流水
  • A端口可配置 0、1、2级流水
  • D端口只能配置0、1级流水
  • AD寄存器可以配置 0、1级流水
  • 乘法器输出后的M寄存器可配置0、1级流水
  • 输出P寄存器可配置0、1级流水

  因此我们在使用乘法器的时候,除了需要注意两个输入端口的流水一样,这样才符合平常的使用;还需要注意整个乘法器的流水级数可配置为0 ~ 4级流水,只有选择合适的流水线级数时,整个乘法器才能高速运行。我们先不设置流水线级数,即输入到输出0拍延迟,仿真代码如下:

`timescale 1ns / 1ps

module tb_mult_B18_D25();


    reg                                                 i_clk   ;
    reg                                                 rst     ;
    reg             [24:0]                              i_D     ;
    reg             [17:0]                              i_B     ;
    wire            [47:0]                              o_P     ;

initial begin
    i_clk = 0;
    rst   = 1 ;
    i_D = 25'd0;
    i_B = 18'd0;
    #1000;
     rst   = 0 ;
end

always #10 i_clk = ~i_clk;

always @(posedge i_clk) begin
    if(rst == 1'b1)begin
        i_D <= 'd0;
        i_B <= 'd0;
    end
    else begin
        i_D <= i_D + 1'b1 ;
        i_B <= i_B + 1'b1 ;
    end
end

mult_B18_D25#(
    .BREG    ( 0 ),
    .DREG    ( 0 ),
    .ALUMODE ( 4'b0000 ),
    .INMODE  ( 5'b00110 ),
    .OPMODE  ( 7'b0000101 )
)u_mult_B18_D25(
    .i_clk   ( i_clk   ),
    .i_D     ( i_D     ),
    .i_B     ( i_B     ),
    .o_P     ( o_P     )
);

endmodule

在这里插入图片描述
  乘法结果正确,输入输出0拍延迟,接下来我们仿真负数的乘法,仿真代码如下:

`timescale 1ns / 1ps

module tb_mult_B18_D25();


    reg                                                 i_clk   ;
    reg                                                 rst     ;
    reg             [24:0]                              i_D     ;
    reg             [17:0]                              i_B     ;
    wire            [47:0]                              o_P     ;

initial begin
    i_clk = 0;
    rst   = 1 ;
    i_D = 25'd0;
    i_B = 18'd0;
    #1000;
     rst   = 0 ;
end

always #10 i_clk = ~i_clk;

always @(posedge i_clk) begin
    if(rst == 1'b1)begin
        i_D <= 25'd0;
        i_B <= 18'd0;
    end
    else begin
        i_D <= -25'd30 ;
        i_B <= i_B - 1 ;
    end
end

mult_B18_D25#(
    .BREG    ( 0 ),
    .DREG    ( 0 ),
    .ALUMODE ( 4'b0000 ),
    .INMODE  ( 5'b00110 ),
    .OPMODE  ( 7'b0000101 )
)u_mult_B18_D25(
    .i_clk   ( i_clk   ),
    .i_D     ( i_D     ),
    .i_B     ( i_B     ),
    .o_P     ( o_P     )
);

endmodule

在这里插入图片描述
  负数乘法结果也是正确,接下来我们将流水设置1拍看一下结果:

在这里插入图片描述
  可以看到输出相对于输入有1拍的延迟,我们将流水设置2拍看一下结果:

在这里插入图片描述
  可以看到输出相对于输入有2拍的延迟,我们将流水设置3拍看一下结果:

在这里插入图片描述
  可以看到输出相对于输入有3拍的延迟,我们将流水设置4拍看一下结果:

在这里插入图片描述
  结果依然没问题。

6.2 (A+D)*B的仿真

  DSP48E1内部有个预加器,可以使得A和D先预加后,取低25位再和B相乘,上面我们验证了乘法器的功能,我们把A和D的预加器打开,因为D端口最多打1拍流水,A可以打2拍,因此想要A和D流水对齐再累加,后面还有一个AD寄存器。所以预加器的流水最多设置2拍,加上后面的M寄存器、P寄存器,整个DSP48E1的流水范围也是0~4拍,我们先来看0拍的情况,仿真代码如下:

`timescale 1ns / 1ps

module tb_add_A25_D25_mult_B18();

    reg                                                 i_clk   ;
    reg                                                 rst     ;
    reg             [29:0]                              i_A     ;
    reg             [24:0]                              i_D     ;
    reg             [17:0]                              i_B     ;
    wire            [47:0]                              o_P     ;

initial begin
    i_clk = 0;
    rst   = 1 ;
    i_D = 25'd0;
    i_B = 18'd0;
    i_A = 30'd0;
    #1000;
     rst   = 0 ;
end

always #10 i_clk = ~i_clk;

always @(posedge i_clk) begin
    if(rst == 1'b1)begin
        i_D <= 25'd0;
        i_B <= 18'd0;
        i_A <= 30'd0;
    end
    else begin
        i_D <= i_D + 1 ;
        i_B <= i_B + 1 ;
        i_A <= i_A + 1;
    end
end

add_A25_D25_mult_B18#(
    .BREG    ( 0 ),
    .DREG    ( 0 ),
    .AREG    ( 0 ),
    .ALUMODE ( 4'b0000 ),
    .INMODE  ( 5'b00100 ),
    .OPMODE  ( 7'b0000101 )
)u_add_A25_D25_mult_B18(
    .i_clk   ( i_clk   ),
    .i_A     ( i_A     ),
    .i_D     ( i_D     ),
    .i_B     ( i_B     ),
    .o_P     ( o_P     )
);

endmodule

在这里插入图片描述
  可以看到输出相对于输入有0拍的延迟,(1+1)*1=2;(2+2)*2=8,(3+3)*3=18,结果正确,我们接下来看负数的情况,仿真代码如下:

`timescale 1ns / 1ps

module tb_add_A25_D25_mult_B18();

    reg                                                 i_clk   ;
    reg                                                 rst     ;
    reg             [29:0]                              i_A     ;
    reg             [24:0]                              i_D     ;
    reg             [17:0]                              i_B     ;
    wire            [47:0]                              o_P     ;

initial begin
    i_clk = 0;
    rst   = 1 ;
    i_D = 25'd0;
    i_B = 18'd0;
    i_A = 30'd0;
    #1000;
     rst   = 0 ;
end

always #10 i_clk = ~i_clk;

always @(posedge i_clk) begin
    if(rst == 1'b1)begin
        i_D <= 25'd0;
        i_B <= 18'd0;
        i_A <= 30'd0;
    end
    else begin
        i_D <= i_D - $random % 10  ;
        i_B <= i_B + 1 ;
        i_A <= i_A + $random % 10  ;
    end
end

add_A25_D25_mult_B18#(
    .BREG    ( 0 ),
    .DREG    ( 0 ),
    .AREG    ( 0 ),
    .ALUMODE ( 4'b0000 ),
    .INMODE  ( 5'b00100 ),
    .OPMODE  ( 7'b0000101 )
)u_add_A25_D25_mult_B18(
    .i_clk   ( i_clk   ),
    .i_A     ( i_A     ),
    .i_D     ( i_D     ),
    .i_B     ( i_B     ),
    .o_P     ( o_P     )
);

endmodule

在这里插入图片描述
  可以看到输出相对于输入有0拍的延迟,(7-8)*1=-1;(23-27)*4=-16,(32-28)*5=20,负数计算的结果也是正确,1~4级的流水这里就不一一展示了,我们直接配置成4级流水,看看结果:

在这里插入图片描述
  可以看到输出相对于输入有4拍的延迟,结果也正确。

6.3 (A+D)*B±C的仿真

  由内部结构图可以知道C输入最多只有一个寄存器,因此流水最多打1拍。所以我们要把A、D、B到第二级的流水也最多设置1拍,再加上输出的P寄存器,因此整个功能的流水范围为0~2,仿真代码如下:

`timescale 1ns / 1ps

module tb_add_A25_D25_mult_B18_add_C48();

    reg                                                 i_clk   ;
    reg                                                 rst     ;
    reg             [29:0]                              i_A     ;
    reg             [24:0]                              i_D     ;
    reg             [17:0]                              i_B     ;
    reg             [47:0]                              i_C     ;
    wire            [47:0]                              o_P     ;

initial begin
    i_clk = 0;
    rst   = 1 ;
    i_D = 25'd0;
    i_B = 18'd0;
    i_A = 30'd0;
    i_C = 48'd0;
    #1000;
     rst   = 0 ;
end

always #10 i_clk = ~i_clk;

always @(posedge i_clk) begin
    if(rst == 1'b1)begin
        i_D <= 25'd0;
        i_B <= 18'd0;
        i_A <= 30'd0;
        i_C <= 48'd0;
    end
    else begin
        i_D <= i_D +1  ;
        i_B <= i_B + 1 ;
        i_A <= i_A +1  ;
        i_C <= i_C + 1;
    end
end

add_A25_D25_mult_B18_add_C48#(
    .BREG    ( 0 ),
    .DREG    ( 0 ),
    .AREG    ( 0 ),
    .CREG    ( 0 ),
    .ALUMODE ( 4'b0000 ),
    .INMODE  ( 5'b00100 ),
    .OPMODE  ( 7'b0110101 )
)u_add_A25_D25_mult_B18_add_C48(
    .i_clk   ( i_clk   ),
    .i_A     ( i_A     ),
    .i_D     ( i_D     ),
    .i_B     ( i_B     ),
    .i_C     ( i_C     ),
    .o_P     ( o_P     )
);


endmodule

在这里插入图片描述
  可以看到输出相对于输入有0拍的延迟,(1+1)*1 + 1=3;(2+2)*2 + 2=10,(3+3)*3 + 3=21,结果正确,我们配置成2级流水,看看结果:

在这里插入图片描述

  可以看到输出相对于输入有2拍的延迟,结果也是正确。

6.4 累加器的仿真

  DSP48E1输出有个模式检测器,用于检测 P 总线是否与指定模式匹配或是否与模式的补码完全匹配。如果加法器的输出与设定模式匹配,则 PATTERNDETECT (PD) 输出变为高电平。 如果加法器的输出与设定模式的补码匹配,则 PATTERNBDETECT (PBD) 输出变为高电平,如下所示:

在这里插入图片描述
在这里插入图片描述
  SEL_PATTERN控制匹配值的输入,输入源可以是 48 位动态“C”输入,也可以是 48 位静态属性字段。SEL_MASK选择掩码字段,当 MASK 位设置为 1 时,将忽略相应的模式位。当 MASK 位设置为 0 时,将比较模式位。我们来仿真一下,给定一个匹配值输入,让P进行累加,当P累加到匹配值后,看PATTERNDETECT是否拉高,仿真代码如下:

`timescale 1ns / 1ps
module tb_dsp48e1_acc();

    reg                                                 i_clk   ;

    wire            [47:0]                              o_P     ;
    wire                                                PATTERNDETECT   ;

initial begin
    i_clk = 0;
end

always #10 i_clk = ~i_clk;

dsp48e1_acc#(
    .MASK           ( 48'd0     ),
    .PATTERN        ( 48'd351   ),
    .SEL_PATTERN    ( "PATTERN" )
)u_dsp48e1_acc(
    .i_clk          ( i_clk          ),
    .i_C            ( {47'd0,1'b1}   ),
    .PATTERNDETECT  ( PATTERNDETECT  ),
    .o_P            ( o_P            )
);

endmodule

在这里插入图片描述
  可以看到,我们设置匹配值为351,当累加器累加到351时,PATTERNDETECT 拉高一个周期,表示匹配成功,至此,关于DSP48E1所有功能的仿真都已经完成,能满足绝大多数应用场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱奔跑的虎子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值