FPGA实战(12):FPGA实现复数乘法器:基于Xilinx IP核的高效设计(附源码)
1. 引言
在数字通信、雷达信号处理、图像处理等众多领域中,复数乘法是最基础也是最频繁的操作之一。例如,在FFT蝶形运算、数字下变频(DDC)、自适应滤波等模块中,复数乘法的速度和资源效率直接决定了整个系统的性能。
FPGA实现复数乘法通常有三种方法:
- 直接用
*运算符(消耗大量LUT和DSP块); - 手动展开为
(a+bi)(c+di) = (ac-bd) + (ad+bc)i并调用DSP原语; - 利用Xilinx IP核——
Complex Multiplier(复数乘法器)。
本文分享一个基于Xilinxcmpy_0IP核的复数乘法器顶层模块,将12位有符号数扩展为16位,并正确提取48位乘积的实部与虚部。同时给出完整的Testbench,帮助读者快速上手。
2. 功能点概述
| 端口名 | 方向 | 位宽 | 说明 |
|---|---|---|---|
| i_clk | input | 1 | 时钟信号 |
| i_rst | input | 1 | 高有效异步复位 |
| i_a, i_b | input | 12 (signed) | 复数 A = a + bj 的实部 a 与虚部 b |
| i_c, i_d | input | 12 (signed) | 复数 B = c + dj 的实部 c 与虚部 d |
| o_R | output | 24 (signed) | 乘积的实部 Re = ac - bd |
| o_I | output | 24 (signed) | 乘积的虚部 Im = ad + bc |
核心计算:
(A) * (B) = (a + b·j) * (c + d·j) = (ac - bd) + (ad + bc)·j模块特点:
- 输入为12位有符号数,IP核要求16位对齐,内部自动进行符号扩展(补高位0)。
- 输出为24位有符号结果,保证中间计算不溢出(12位×12位最大24位)。
- 所有输入输出均采用signed类型,综合工具自动实现有符号运算。
3. 创新点与设计技巧
3.1 巧妙的数据位宽扩展
Xilinx的复数乘法器IP核输入要求实部、虚部分别为16位有符号数。而我们的输入只有12位,如果在顶层模块外部手动扩展,会增加代码量。本设计在IP核实例化时直接使用拼接操作:
.s_axis_a_tdata({4'b0000, i_b, 4'b0000, i_a})将 i_b(虚部)和 i_a(实部)各补充4个高位0,组成32位数据:[15:0]为虚部,[31:16]为实部。这种方法简洁高效,不产生额外寄存器。
3.2 输出结果的精准提取
IP核输出m_axis_dout_tdata为79位总线,其内部包含实部和虚部(以及可能的溢出标志)。根据IP核配置(输出取整、舍入模式等),本设计中实部位于[23:0],虚部位于[63:40]。直接通过assign拆分,无需缓存或打拍,延迟为组合逻辑。
3.3 复位极性无痛转换
模块对外提供高有效异步复位(与大多数用户设计习惯一致),而IP核的aresetn是低有效。在实例化端口处直接用取反操作~i_rst连接,既清晰又节省一个反相器。
3.4 极简Testbench与快速验证
Testbench中提供了固定的测试向量:A = 100 + 40j,B = 50 + 60j。
手动计算乘积:
实部 = 100*50 - 40*60 = 5000 - 2400 = 2600 虚部 = 100*60 + 40*50 = 6000 + 2000 = 8000仿真结果应与上述值一致,便于读者快速判断设计是否正确。
4. 代码详解
4.1 顶层模块tops(MY_TOPS.V)
`timescale 1ns / 1ps module tops ( input i_clk, input i_rst, input signed [11:0] i_a, input signed [11:0] i_b, input signed [11:0] i_c, input signed [11:0] i_d, output signed [23:0] o_R, output signed [23:0] o_I ); //===================================================== // Wire declarations (w_) //===================================================== wire [79:0] w_m_axis_dout_tdata; //===================================================== // Assign statements //===================================================== assign o_R = w_m_axis_dout_tdata[23:0]; assign o_I = w_m_axis_dout_tdata[63:40]; //===================================================== // Module instantiations //===================================================== cmpy_0 cmpy_u ( .aclk (i_clk), .aresetn (~i_rst), // 复位极性转换 .s_axis_a_tvalid (1'b1), .s_axis_a_tdata ({4'b0000, i_b, 4'b0000, i_a}), .s_axis_b_tvalid (1'b1), .s_axis_b_tdata ({4'b0000, i_d, 4'b0000, i_c}), .m_axis_dout_tvalid (), .m_axis_dout_tdata (w_m_axis_dout_tdata) ); endmodule代码解读:
w_m_axis_dout_tdata为IP核输出的79位数据总线。- 由于输入端
tvalid始终为高电平(数据连续有效),不需要握手逻辑。 - 输出
m_axis_dout_tvalid悬空,仅需关注数据总线。
4.2 仿真Testbench(tb.V)
`timescale 1ns / 1ps module test_tops; reg i_clk; reg i_rst; reg signed[11:0] i_a,i_b; reg signed[11:0] i_c,i_d; wire signed[23:0] o_R; wire signed[23:0] o_I; tops tops_u ( .i_clk (i_clk), .i_rst (i_rst), .i_a (i_a), .i_b (i_b), .i_c (i_c), .i_d (i_d), .o_R (o_R), .o_I (o_I) ); initial begin i_clk = 1'b1; i_rst = 1'b1; // 开始复位 #100 i_rst = 1'b0; // 释放复位 end initial begin i_a = 12'd100; i_b = 12'd40; i_c = 12'd50; i_d = 12'd60; end always #5 i_clk = ~i_clk; endmodule仿真步骤:
- 复位100ns后释放,IP核内部状态机初始化。
- 输入测试数据稳定不变。
- 经过IP核若干时钟周期延迟(通常为3~5个周期),输出
o_R和o_I将稳定为预期值。
5. 仿真结果与验证
使用Vivado Simulator或其他工具运行Testbench,得到波形:
| 信号 | 数值(十进制) | 说明 |
|---|---|---|
| i_a, i_b | 100, 40 | 复数 A |
| i_c, i_d | 50, 60 | 复数 B |
| o_R | 2600 | 乘积实部 |
| o_I | 8000 | 乘积虚部 |
手动验算:100*50 - 40*60 = 2600✅100*60 + 40*50 = 8000✅
注意事项:
- 若输出结果与预期不符,检查IP核配置(是否设置为有符号、输出位宽是否正确)。
- 可修改Testbench中的输入,测试负数情况(例如
i_a = -100),观察输出是否正确。
6. 如何使用该设计
生成IP核
在Vivado IP Catalog中搜索Complex Multiplier(cmpy),配置如下:- 输入/输出均为有符号数
- 实部、虚部位宽:16位(因为输入12位扩展后为16位)
- 输出位宽:24位(12+12)
- 其他选项保持默认
添加源码
将MY_TOPS.V和tb.V添加到工程中,顶层设置为tops。运行仿真
直接运行行为仿真,观察o_R和o_I是否符合预期。综合实现
由于调用了IP核,综合工具会自动生成DSP48宏,资源消耗极低。
7. 总结
本文介绍了一个简洁高效的FPGA复数乘法器模块,利用Xilinx官方IP核,通过巧妙的位扩展和数据提取方法,实现了12位有符号复数的乘法运算。创新点在于:
- 使用拼接操作一次性完成位宽扩展;
- 高有效复位与IP核低有效复位的直接转换;
- 清晰简洁的输出拆分。
该设计可直接用于需要复数乘法加速的各类项目中,也适合FPGA初学者学习IP核例化及Verilog编码规范。读者可根据自己的需求调整输入输出位宽,并扩展为流水线或多通道版本。
附:完整代码文件
MY_TOPS.V– 顶层模块tb.V– 测试激励
直接复制保存即可在Vivado中运行。如有疑问,欢迎留言讨论!
