我是靠谱客的博主 知性心情,这篇文章主要介绍Xilinx FPGA资源解析与使用系列——DSP48E使用实例(三)前言实现功能一般写法用DSP48E1实现功能对比分析资源对比分析时序性能分析总结写在最后,现在分享给大家,希望可以做个参考。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

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

  • 前言
  • 实现功能
  • 一般写法
  • 用DSP48E1实现
  • 功能对比分析
  • 资源对比分析
  • 时序性能分析
  • 总结
  • 写在最后

)


前言

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

实现功能

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

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

一般写法

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

复制代码
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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实现

复制代码
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
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

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

复制代码
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
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内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(93)

评论列表共有 0 条评论

立即
投稿
返回
顶部