概述
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
Xilinx FPGA资源解析与使用系列——DSP48E使用实例(三)
- 前言
- 实现功能
- 一般写法
- 用DSP48E1实现
- 功能对比分析
- 资源对比分析
- 时序性能分析
- 总结
- 写在最后
)
前言
前面我们介绍了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个小时,全都是下班业余的时间,大家都只看不点赞不收藏,我刷抖音去不香么!谢谢各位支持。
最后
以上就是知性心情为你收集整理的Xilinx FPGA资源解析与使用系列——DSP48E使用实例(三)前言实现功能一般写法用DSP48E1实现功能对比分析资源对比分析时序性能分析总结写在最后的全部内容,希望文章能够帮你解决Xilinx FPGA资源解析与使用系列——DSP48E使用实例(三)前言实现功能一般写法用DSP48E1实现功能对比分析资源对比分析时序性能分析总结写在最后所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复