Xilinx FPGA资源解析与使用系列——DSP48E使用实例(四)
)
实现功能
前面一个博文我们介绍了DSP48E1资源实现了一个DSP48E1实现2个24bit的累加器的功能
P1 = P1+ B1 *C1
P2 = P2+ B2 *C1
C1 = -1 OR 1
现在,我们在这里用一个DSP48E1来实现
P = P+ B *C (P=32bit B = 16bit C= 16bit)
代码写法
这里给出这个相关器的代码
module corr_module (
input i_clk ,
input i_corr_en ,
input [15 :0]i_pn_code ,
input i_dump ,
output o_dump_en,
input [15 :0] i_base_i ,
input [15 :0] i_base_q ,
output [31:0] o_accu_i ,
output [31:0] o_accu_q
);
reg [31:0] r_accu_i_temp = 0;
reg [31:0] r_accu_q_temp = 0;
assign o_dump_en = i_dump;
assign o_accu_i = r_accu_i_temp;
assign o_accu_q = r_accu_q_temp;
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
r_accu_i_temp <= r_accu_i_temp + $signed(i_base_i)*$signed(i_pn_code);
r_accu_q_temp <= r_accu_q_temp + $signed(i_base_q)*$signed(i_pn_code);
end
end
endmodule
想必大家看这个应该问题不大
用DSP48E1实现
module corr_module_dsp(
input i_clk ,
input i_corr_en ,
input [15 :0] i_pn_code ,
input i_dump ,
output o_dump_en,
input [15 :0] i_base_i ,
input [15 :0] i_base_q ,
output [31:0] o_accu_i ,
output [31:0] o_accu_q
);
wire [47:0]acc_in;
wire [23:0]i_acc_in;
wire [23:0]q_acc_in;
wire [47:0]acc_result_i;
wire [47:0]acc_result_q;
wire [29:0]a_input_i;
wire [29:0]a_input_q;
wire [17:0]b_input;
wire [17:0]accu_i_temp_t;
wire [17:0]accu_q_temp_t;
assign o_dump_en = i_dump;
assign b_input = {{2{i_pn_code[15]}},i_pn_code};
assign a_input_i = {{14{i_base_i[15]}},i_base_i};
assign a_input_q = {{14{i_base_q[15]}},i_base_q};
assign accu_i_temp_t = acc_result_i[31:0];
assign accu_q_temp_t = acc_result_q[31:0];
assign o_accu_i = accu_i_temp_t;
assign o_accu_q = accu_q_temp_t;
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(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_i), // 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(4'b0000), // 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_0101), // 7-bit input: Operation mode input
// Data: 30-bit (each) input: Data Ports
.A(a_input_i), // 30-bit input: A data input
.B(b_input), // 18-bit input: B data input
.C(0), // 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
);
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(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_inst1 (
// 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_q), // 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(4'b0000), // 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_0101), // 7-bit input: Operation mode input
// Data: 30-bit (each) input: Data Ports
.A(a_input_q), // 30-bit input: A data input
.B(b_input), // 18-bit input: B data input
.C(0), // 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
注意这里的DSP设置与上一篇博文有不同,可以对比一下
综合之后发现
资源对比分析
看看两种实现方式的资源占用情况:
啊,居然基本一模一样,怎么回事呢?
综合结果
corr_module 的综合结果:
corr_module_dsp 的综合结果:
这两个模块综合后几乎一模一样!不得不佩服现在的vivado综合工具推理能力太强大了。我还以为它会把corr_module这个模块综合成2个乘法器和2个累加器。结果是我太低估它了。
好吧,既然这样,也没必要在进行功能仿真了。
总结
尽管vivado综合工具推理能力很强大,但仍不失为一个灵活使用DSP48E的案例分析,实际上就是提醒我们,需要多关注自己的代码到底综合成什么元件了,怎么样才能更加高效的实现你的功能。
DSP48E1资源的使用就暂时写到这里了,它实在是太灵活了,真正想玩透它,花一个月的时间都不为过,也希望大家能够多多挖掘其使用方法,也许什么时候就能得到意想不到的效果
标签:
FPGA资源之DSP
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 百万级群聊的设计实践
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期