不枉初心,砥砺前行

皮皮祥的博客

欢迎留言,评论

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

Xilinx FPGA资源解析与使用系列——DSP48E使用实例(三)

 

Xilinx FPGA资源解析与使用系列——DSP48E使用实例(三)

)


前言

前面我们介绍了DSP48E1资源可以非常的灵活的使用,而且也给出了它的原语模型,现在我们用一个例子来说明它的妙用。

实现功能

在某些扩频信号解调中,例如GPS信号,我们一般需要进行相干累加,例如将接收的基带信号与本地PN码进行相乘并且累加,每隔1ms截取结果,并将累加器清0,然后重新累加。
用公式描述就是:

P1 = P1+ B1 *C1
P2 = P2+ B2 *C1
C1 = -1 OR 1
(一个乘法器实现2个24bit的累加器)

一般写法

这里给出这个相关器的代码

module corr_module (
    input         i_clk ,
    input         i_corr_en ,
    input         i_pn_code ,
    input         i_dump    ,
    output        o_dump_en,   
    input  [4 :0] i_base_i  ,
    input  [4 :0] i_base_q  ,
    output [15:0] o_accu_i  ,
    output [15:0] o_accu_q
);

reg [17:0] r_accu_i_temp = 0;
reg [17:0] r_accu_q_temp = 0;

assign o_dump_en = i_dump;

assign o_accu_i = r_accu_i_temp[17:2];
assign o_accu_q = r_accu_q_temp[17:2];


always @(posedge i_clk)
begin
    if(i_corr_en == 0 || i_dump)
    begin
        r_accu_i_temp <= 0;
        r_accu_q_temp <= 0;
    end
    else
    begin
        if(i_pn_code == 0)
        begin
            r_accu_i_temp <= r_accu_i_temp + {{13{i_base_i[4]}},i_base_i};
            r_accu_q_temp <= r_accu_q_temp + {{13{i_base_q[4]}},i_base_q};
        end
        else
        begin
            r_accu_i_temp <= r_accu_i_temp - {{13{i_base_i[4]}},i_base_i};
            r_accu_q_temp <= r_accu_q_temp - {{13{i_base_q[4]}},i_base_q};
        end
    end

end
endmodule

想必大家看这个应该问题不大

用DSP48E1实现

module corr_module_dsp(
    input         i_clk ,
    input         i_corr_en ,
    input         i_pn_code ,
    input         i_dump    ,
    output        o_dump_en,   
    input  [4 :0] i_base_i  ,
    input  [4 :0] i_base_q  ,
    output [15:0] o_accu_i  ,
    output [15:0] o_accu_q
    );
    
wire [47:0]acc_in;
wire [23:0]i_acc_in;
wire [23:0]q_acc_in;
wire [3:0]ALUMODE;
wire [47:0]acc_result;
wire [47:0]accu_i_temp_dsp;
wire [47:0]accu_q_temp_dsp;

assign ALUMODE = (i_pn_code == 0) ? 4'b0000 : 4'b0011; //加减控制代码
assign o_dump_en = i_dump;

assign i_acc_in = {{19{i_base_i[4]}},i_base_i};
assign q_acc_in = {{19{i_base_q[4]}},i_base_q};
assign acc_in   = {i_acc_in,q_acc_in} ;
assign accu_i_temp_dsp = acc_result[47:24];
assign accu_q_temp_dsp = acc_result[23:0];

assign o_accu_i = accu_i_temp_dsp[17:2];
assign o_accu_q = accu_q_temp_dsp[17:2];


   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("NONE"),            // Select multiplier usage ("MULTIPLY", "DYNAMIC", or "NONE")
      .USE_SIMD("TWO24"),               // 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(0),                     // 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(0),                   // Number of pipeline stages for ALUMODE (0 or 1)
      .AREG(0),                         // Number of pipeline stages for A (0, 1 or 2)
      .BCASCREG(0),                     // Number of pipeline stages between B/BCIN and BCOUT (0, 1 or 2)
      .BREG(0),                         // 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(0),                         // Number of pipeline stages for C (0 or 1)
      .DREG(0),                         // Number of pipeline stages for D (0 or 1)
      .INMODEREG(1),                    // Number of pipeline stages for INMODE (0 or 1)
      .MREG(0),                         // 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(),                   // 30-bit output: A port cascade output
      .BCOUT(),                   // 18-bit output: B port cascade output
      .CARRYCASCOUT(),     // 1-bit output: Cascade carry output
      .MULTSIGNOUT(),       // 1-bit output: Multiplier sign cascade output
      .PCOUT(),                   // 48-bit output: Cascade output
      // Control: 1-bit (each) output: Control Inputs/Status Bits
      .OVERFLOW(),             // 1-bit output: Overflow in add/acc output
      .PATTERNBDETECT(), // 1-bit output: Pattern bar detect output
      .PATTERNDETECT(),   // 1-bit output: Pattern detect output
      .UNDERFLOW(),           // 1-bit output: Underflow in add/acc output
      // Data: 4-bit (each) output: Data Ports
      .CARRYOUT(),             // 4-bit output: Carry output
      .P(acc_result),                           // 48-bit output: Primary data output
      // Cascade: 30-bit (each) input: Cascade Ports
      .ACIN(30'd0),                     // 30-bit input: A cascade data input
      .BCIN(18'd0),                     // 18-bit input: B cascade input
      .CARRYCASCIN(1'b0),       // 1-bit input: Cascade carry input
      .MULTSIGNIN(1'b0),         // 1-bit input: Multiplier sign input
      .PCIN(48'b0),                     // 48-bit input: P cascade input
      // Control: 4-bit (each) input: Control Inputs/Status Bits
      .ALUMODE(ALUMODE),               // 4-bit input: ALU control input
      .CARRYINSEL(3'b000),         // 3-bit input: Carry select input
      .CLK(i_clk),                       // 1-bit input: Clock input
      .INMODE(5'b00000),                 // 5-bit input: INMODE control input
      .OPMODE(7'b010_1100),                 // 7-bit input: Operation mode input
      // Data: 30-bit (each) input: Data Ports
      .A(0),                           // 30-bit input: A data input
      .B(0),                           // 18-bit input: B data input
      .C(acc_in),                           // 48-bit input: C data input
      .CARRYIN(1'b0),               // 1-bit input: Carry input signal
      .D(0),                           // 25-bit input: D data input
      // Reset/Clock Enable: 1-bit (each) input: Reset/Clock Enable Inputs
      .CEA1(1'b1),                     // 1-bit input: Clock enable input for 1st stage AREG
      .CEA2(1'b1),                     // 1-bit input: Clock enable input for 2nd stage AREG
      .CEAD(1'b0),                     // 1-bit input: Clock enable input for ADREG
      .CEALUMODE(1'b1),           // 1-bit input: Clock enable input for ALUMODE
      .CEB1(1'b1),                     // 1-bit input: Clock enable input for 1st stage BREG
      .CEB2(1'b1),                     // 1-bit input: Clock enable input for 2nd stage BREG
      .CEC(1'b1),                       // 1-bit input: Clock enable input for CREG
      .CECARRYIN(1'b0),           // 1-bit input: Clock enable input for CARRYINREG
      .CECTRL(1'b1),                 // 1-bit input: Clock enable input for OPMODEREG and CARRYINSELREG
      .CED(1'b0),                       // 1-bit input: Clock enable input for DREG
      .CEINMODE(1'b1),             // 1-bit input: Clock enable input for INMODEREG
      .CEM(1'b1),                       // 1-bit input: Clock enable input for MREG
      .CEP(1'b1),                       // 1-bit input: Clock enable input for PREG
      .RSTA(1'b0),                     // 1-bit input: Reset input for AREG
      .RSTALLCARRYIN(1'b0),   // 1-bit input: Reset input for CARRYINREG
      .RSTALUMODE(1'b0),         // 1-bit input: Reset input for ALUMODEREG
      .RSTB(1'b0),                     // 1-bit input: Reset input for BREG
      .RSTC(1'b0),                     // 1-bit input: Reset input for CREG
      .RSTCTRL(1'b0),               // 1-bit input: Reset input for OPMODEREG and CARRYINSELREG
      .RSTD(1'b0),                     // 1-bit input: Reset input for DREG and ADREG
      .RSTINMODE(1'b0),           // 1-bit input: Reset input for INMODEREG
      .RSTM(1'b0),                     // 1-bit input: Reset input for MREG
      .RSTP(i_corr_en == 0 || i_dump)                      // 1-bit input: Reset input for PREG
   );    
    
    
endmodule

注意上面代码中重点地方:


assign ALUMODE = (pn_code == 0) ? 4'b0000 : 4'b0011; //加减控制代码
.USE_SIMD("TWO24"),               // SIMD selection ("ONE48", "TWO24", "FOUR12")
.USE_MULT("NONE"),            // Select multiplier usage ("MULTIPLY", "DYNAMIC", or "NONE")
.MREG(0),                         // Number of multiplier pipeline stages (0 or 1)
.PREG(1)                          // Number of pipeline stages for P (0 or 1)
.P(acc_result),                           // 48-bit output: Primary data output
.ALUMODE(ALUMODE),               // 4-bit input: ALU control input
.CARRYINSEL(3'b000),         // 3-bit input: Carry select input
.CLK(i_clk),                       // 1-bit input: Clock input
.INMODE(5'b00000),                 // 5-bit input: INMODE control input
.OPMODE(7'b010_1100),                 // 7-bit input: Operation mode input
.C(acc_in),                           // 48-bit input: C data input
.RSTP(i_corr_en == 0 || i_dump)                      // 1-bit input: Reset input for PREG

简单说明下:
1、MREG must be set to 0 when the multiplier is not used. MREG必须设置为0,当乘法器不使用
2、ALUMODE: 4’b0000 : Z+X+Y+CIN 实现加法器
4’b0011 : Z-(X+Y+CIN) 实现减法

3、OPMODE: 7’b011_0011 : X = A:B, Y = 0,Z = C
7’b010_0011 : X = A:B, Y = 0,Z = P OPMODE[6:4] = 010 MUST SELECT WITH PREG = 1
7’b010_1100 X = 0 , Y = C,Z = P 也能完成累加

如果看不明白,参考前面的博文

功能对比分析

这两个模块功能上是等效的。
这是仿真结果:

在这里插入图片描述
r_accu_i1 、r_accu_q1 、r_accu_i2 、r_accu_q2 这些信号就是两个模块输出的锁存结果,锁存指示为o_dump_en。可以看出,两个模块的输出是一模一样的。

资源对比分析

看看两种实现方式的资源占用情况:
在这里插入图片描述
使用dsp48E1完全实现了两个相关器(P = P +A*B)(A=-1 OR 1) 的功能,没占用一点逻辑资源。

相当于1个DSP 48E置换了 37个LUT+36个FF。这个片子有400个DSP,全部置换相当于LUT逻辑资源增加了20%!

时序性能分析

corr_module 的综合结果:

在这里插入图片描述
corr_module 的逻辑级数:
在这里插入图片描述
corr_module_dsp 的综合结果:

在这里插入图片描述

corr_module_dsp 的逻辑级数分析:
在这里插入图片描述
时序性能的好坏立竿见影!!!!

总结

本章阐述了用一个DSP48E1实现了两个相关器的功能,充分利用了DSP48E1的特点:
1、单指令多数据 (SIMD) 算术单元,可以用作两个24bit/四个12bit 加法器或者减法器或者累加器
2、加减法动态配置
这两个特点,实现了 DSP48E1和 LUT+FF的资源置换,对于FPGA资源的高效利用非常有意义。

写在最后

各位看官,如果觉得对你有用,麻烦点个赞,干货啊,估计CSDN全网都找不到第2篇这样的。写一篇这样的文章花了我3-4个小时,全都是下班业余的时间,大家都只看不点赞不收藏,我刷抖音去不香么!谢谢各位支持。

posted on   皮皮祥  阅读(2356)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 百万级群聊的设计实践
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
点击右上角即可分享
微信分享提示