Python2Verilog vs Xilinx IP
两年前我用 HLS 做 MIMO-OFDM 收发器, FIR 性能死活不如 Xilinx FIR Compiler IP,不得不在 HLS 里调用 IP,接口位宽对不齐就特别痛苦。 这次用我们的 AI 设计框架 Python2Verilog (P2V) 重写一遍,看看能不能把 Xilinx IP 比下去。
22 / 33 落在 2 LSB 内
V6 联合仿真 · 14 比特对齐 · 0 个 P2V Bug
过去一周 P2V 累计生成了 33 个 FPGA 设计,跨 7 个家族 (CIC 抽取 + CIC 插值 + NCO/DDS + 混频 + DDC/DUC 复合链 + CIC+LPF 级联 + FIR Compiler PG149 全套 12 种配置),每个都和 Xilinx IP 在同一颗器件、 同一时序约束下实测对比。
P2V vs Xilinx IP 33 个设计的资源对比
1 为什么不直接拿 Xilinx IP 用就好
Xilinx IP 是手工优化过的产品,但是调用 IP 需要经过参数设置、代码例化等繁琐步骤,使用灵活性不够好:
❗ Important
算法长尾覆盖不到:N=51 对称 WLAN 前置滤波器、 R=4 N=5 + 7 抽对称 LPF 的 CIC 级联,IP 没有现成的也很难配。
❗ Important
资源开销奢侈:DDS Compiler 默认 7-9 级流水线、 7.5 个 RAMB36,边缘 FPGA 用不起。
❗ Important
黑盒调试 + 位宽对接痛苦:HLS 调用 IP 要专门定义对齐的数据类型、 一改设计就要重对。 P2V 让 RTL 整段重生、 位宽随设计走。
目标不是替代 IP,而是把 AI 设计能覆盖的部分做到和 IP 一样好甚至更好。
2 验证不是简单比对、 是逐拍核对
写一段 RTL 容易,证明它和 Xilinx IP "等价"难。 验证拆成 6 个独立维度,每一道关都必须严格验证通过才能放行:
6 个验证维度 全部跑通才算对得上 IP
V1 到 V5 证明 P2V 做对了"自己的算法";V6 证明 P2V 做的就是 IP 做的那个算法。
3 CIC 抽取 · 完胜 IP 不是因为偷工减料
CIC 是无线通信里最常见的多速率滤波器。 标准做法把所有寄存器开成最大位宽 ,但 Hogenauer 1981 §4 给了 逐级位宽剪裁公式。 我们让 P2V 直接按论文落地、 不留向后兼容/通用化的历史包袱:
CIC 抽取家族 P2V完胜 IP
三档参数全赢:LUT 平均 -52%,Fmax 平均 +24%。 商业 CIC Compiler v4.0 内部也用 Hogenauer,但 P2V 是从零按论文重写。
4 FIR 家族 · PG149 全套 12 种配置
Xilinx FIR Compiler v7.2 在 PG149 里列了 12 种主流配置 (单速率、 半带、 Hilbert、 IFIR、 分数倍、 多通道并行、 TDM 共享),P2V 全部实现了一遍。 衡量指标是 Msps/DSP (每颗 DSP 每秒输出多少采样):
FIR 家族 12 个 PG149 配置吞吐效率
FIR 三个亮点 每颗 DSP 吞吐效率
8 个 P2V 占优的根源都在 系数模式 — IFIR 稀疏、 Hilbert 反对称、 半带奇数项零。 P2V 按论文直接写、 不做通用化填充,Vivado 把零系数 DSP 自动折掉。 IP 强项是复数 TDM + 多通道并行的 AXI 包装与共享乘法器,P2V 用 \_systolic / \_hogenauer 变体追赶。
8 完胜、 1 持平、 3 紧追 — P2V 不是替代 IP,是覆盖 IP 不擅长的稀疏系数和反对称结构。
5 NCO/DDS · 用极少资源做同样的事
NCO DDS 家族 用极少资源做同样的事
NCO 实测 P2V 8 LUT / 7 FF / 1.5 BRAM36、 IP 66 / 169 / 7.5。 同算法、 P2V 用 1/8 的 LUT、 1/24 的 FF、 1/5 的 BRAM。 这不是"压一个数量级" (绝对值都不大、 xczu28dr 总 LUT 42 万),是 P2V 没有 IP 的兼容层 + 接口包装 + 通用化适配。
Fmax 是另一回事:P2V 默认 496 MHz、 IP 794 MHz (-38%) — IP 用了 5-7 级输出流水线、 P2V 默认 1-2 级。 P2V 也提供 \_pipelined 变体:+37 FF 把 Fmax 缺口缩到 -15%。
同一个算法、 同一颗器件、 P2V 用更少资源做完。 频率高低看场景挑变体。
6 优化轨迹 · 4 个阶段反超 IP
最早一版 P2V 在 LUT、 DSP、 Fmax 都落后于 IP 。 我们 没有打补丁、 没有 hack ,三步一阶按教材定理写正确实现,一阶段一阶段反超:
优化轨迹 4 个阶段反超 IP
每一步都是 教科书上的标准做法,不是新发明:Hogenauer 1981 §4 给的位宽剪裁公式、 Harris §3.6 的对称预加、 经典的输出流水线 retiming 。 那为什么以前没人这样做?因为商业 IP 携带兼容层、 通用化适配、 多年历史包袱。 P2V 是从零按论文写。
▍ 修前 / 修后 一目了然:
三种根因修复 修前修后
✅ Tip
这三种修复都是教科书做法。 它们之所以以前 P2V 没做,是因为最早一版实现时没意识到。 AI 设计 FPGA 的过程,本身就是不断把工程经验固化到 P2V 规则里的过程。
7 Pareto 多变体 · 一个算法、 多个版本
设计芯片是 多目标 Pareto 折中:面积、 频率、 延迟都要权衡。 P2V 不强行选一个最优,同时发布多个变体:
Pareto 多变体 按场景挑实现
每个变体都有 V2 比特对齐 PASS ,不是新算法、 而是同一算法的不同硬件落地。
8 V6 联合仿真 · 33 设计全跑 · 22 个误差落在 2 LSB 内
前面 V1-V5 证明 P2V RTL = 自己的 cycle 模型 = 数学规范;数学规范和 Xilinx IP 实现的是同一个算法。 但传递推理不如 直接证据。 V6 把两份 RTL 拉到同一个 Vivado xsim 测试床里、 喂同样的激励、 逐拍比特对比。
联合仿真 P2V RTL 直接对照 IP RTL
▍ 跑法:Vivado 2024.2 xsim、 同激励 (impulse / DC / sine / random ,各 1024 拍) ,自动检测 scale 与 lag 后逐拍 diff。 33 个设计跑了六轮专门修复。
V6 联合仿真结果 实测出来的对齐
▍ 14 / 33 完全比特对齐 IP (42%):
max_diff = 0 LSB 跨全部 4 种激励。 包括 4 个单速率 + 3 个半带 + 2 个特殊系数 (Hilbert / IFIR) + 3 个 CIC 插值 + 2 个复杂结构 (复数 TDM / TRUE-TDM) 。 多轮 wrapper 修复后,8 个原本读出 137M LSB / 17.5T LSB 巨大数字的设计,都收敛到 0 LSB。
▍ 8 / 33 在 ≤ 2 LSB 内 (24%):5 个 NCO/CFO + 3 个 CIC 抽取,是 IP 内禀截断+量化噪声本底,任何同精度实现都无法做得更小。
▍ 11 / 33 部分对齐 · 不是 P2V Bug:多数设计的 脉冲响应已经完全比特对齐,残差只在 DC / sine / random 模式上。 (具体根因下一节)
9 11 个残差为什么不是 Bug
把"差异不是 Bug"说清楚,比"零差异"重要。 经过 六轮逐设计闭关后的 11 个 V6 残差,每一个都有从 IP .xci 直接读出来 或 RTL 代码层 的架构证据:
11 个残差 4 个根因 0 个 P2V Bug
六轮闭关里的关键反转:
- ▶CIC+LPF 级联 第五轮误判过、 第六轮纠正:IP 的 LPF 系数
[-286, 0, 8252, 16835, 8252, 0, -286] 和 P2V 完全一样。 残差实际来自 CIC 抽取段的 Hogenauer 逐级位宽剪裁不同 (IP 各级 22/21/20 + 20/19/18 ,P2V 用统一 22 位累加 + 末级 22:6 截断) 。 为什么 P2V 用统一位宽:cascade RTL 是 v1.18.26 早期手写的、 那时 Hogenauer 家族 generator (v1.18.44+) 还没做出来。 工程债没还,不是设计选择。 (新写的 CIC 抽取 _hogenauer 变体已经用逐级剪裁 ,资源也比 IP 更省 — 见第三节) - ▶分数倍 3:2 第五轮+第六轮叠加修复:先纠正 cosim 配置 (用错了 L=1 M=1 的 IP) DC 直接归零 ,再用 6 排列多相相序测试器 发现 fw_offset=2 时 impulse 也归零。 2/4 个激励比特对齐。 剩下 sine/random 残差是 P2V 8 抽 vs IP 7 抽对称多相分解的真实结构差异。
- ▶TDM 测试床 不是 RTL 错,是 wrapper 速率失配。 修后 DC 和 impulse 都到 0 LSB。 第六轮试着继续优化 wrapper 反而退化 → 4× 稀释把 P2V 变成 11 抽 LPF 的 3 抽多相、 sine/random 频响不可能对齐。
- ▶NCO 算法 从 IP
.xci 读到 SFDR=45 配置下 Xilinx DDS Compiler 用 CORDIC (PG141 文档明确:LUT 模式仅在 SFDR ≤ 18 dB 配置下可用) ,P2V 用纯 LUT。 第六轮逐行检查 simple_ddc cosim wrapper、 确认无 wrapper Bug,残差来自 LUT 8-bit vs CORDIC 16-bit 相位精度差异。
六轮闭关、 11 个残差全部有 文件级具体证据 (.xci 配置、 RTL 代码、 PG141 文档) 。 关到 0 这件事可以、 但代价是 让 P2V 仿照 IP 的内部实现细节 — 改用 CORDIC、 抄 IP 的 Hogenauer 剪裁宽度。 V6 目的是验证 P2V 数学正确性、 不是把 P2V 改成 IP 的克隆体。
10 最终成绩单
最终成绩单 跨家族汇总
7 个家族 × LUT/FF/BRAM 资源 + Msps-DSP 吞吐效率/Fmax 时序,P2V 几乎全维度占优或持平。 唯一明显落后的是 NCO 复合链路 Fmax (-15% ~ -52%,已有 \_pipelined 变体作为 Pareto 选项)。 FIR 家族里复数 TDM / 多通道并行 3 个配置 Msps/DSP 略后于 IP,\_systolic 变体追赶中。
11写在最后
有意思的不是数字,而是过程。 最早一版 P2V LUT 比 IP 多 75-98%、 大多数维度落后。 修复路径不是猜、 不是堆补丁 — 而是 找根因 → 查教材 → 写正确实现 → 实测验证。 三种根因 (Hogenauer 剪裁 + 对称预加 + 流水线深度) 一一关上。
这不是 AI "比工程师还懂 FPGA",而是 AI 把工程师沉淀的经验、 严格按规则、 不打折扣地落地。 规则正确 + 实现机器化 = 稳定结果。
❗ Important
给同行一个建议:不要轻易相信"AI 生成的 RTL 比 IP 更好",但也不要轻易否定。 让 AI 把数字摆出来、 让实测说话。 这里走过的所有路径都是可追溯、 可复现的。
方法可复现
找根因 → 查教材 → 写实现 → 实测对比