Vortex 3.0 + xcvu19p CMD_MEM_WRITE 调试

Vortex 3.0 + xcvu19p CMD_MEM_WRITE 调试

    • 一、背景
    • 二、调试过程
      • [第一阶段:人工排查 --- 怀疑 Block Design](#第一阶段:人工排查 — 怀疑 Block Design)
      • [第二阶段:思路转变 --- 从「找自己的错」到「找工具的错」](#第二阶段:思路转变 — 从「找自己的错」到「找工具的错」)
      • [第三阶段:引入 AI 协助 --- 综合后仿真定位根因](#第三阶段:引入 AI 协助 — 综合后仿真定位根因)
        • [3.1 综合后仿真初探](#3.1 综合后仿真初探)
        • [3.2 逐步缩小范围](#3.2 逐步缩小范围)
        • [3.3 确认根因](#3.3 确认根因)
        • [3.4 最小化修复](#3.4 最小化修复)
    • 三、根因总结
    • 四、心得与启示
      • [1. 「同一套 RTL,不同芯片不同结果」是最有价值的线索](#1. 「同一套 RTL,不同芯片不同结果」是最有价值的线索)
      • [2. 行为仿真通过 ≠ 硬件没问题](#2. 行为仿真通过 ≠ 硬件没问题)
      • [3. 综合属性不是万能的](#3. 综合属性不是万能的)
      • [4. 警惕硬件中的「成功假象」](#4. 警惕硬件中的「成功假象」)
      • [5. 保守使用语言特性的「边缘组合」](#5. 保守使用语言特性的「边缘组合」)
      • [6. 最小化修复,精准打击](#6. 最小化修复,精准打击)
      • [7. 善用 AI 加速调试闭环](#7. 善用 AI 加速调试闭环)
    • 五、调试方法论

一、背景

1、项目上下文

事情开始于将 Vortex 3.0 GPU 软核移植到 xcvu19p-fsva3824-2-e 芯片。在此之前,已有两条成熟的基线:

基线 芯片 状态
Vortex 3.0 + xcvu440-flga2892-1-c xcvu440 正常运行
Vortex 2.3 + xcvu19p-fsva3824-2-e xcvu19p 正常运行

本次任务需要在 xcvu19p 上同时运行 Vortex 3.0 和 PCIe Bridge。这意味着不能直接把 xcvu440 的工程搬过来------两款芯片的 PCIe IP 不同(xcvu440 和 xcvu19p 分别使用不同的 PCIe 硬核 IP),工程需要重新搭建。

幸运的是,xcvu19p 上已经有一个跑通了 PCIe Bridge 功能的 demo 工程,可以作为起点。

2、问题现象

在 xcvu19p 的 PCIe Bridge demo 基础上,加入 DDR 控制器和 Vortex 3.0 IP 后,测试发现:

  • CMD_MEM_WRITECMD_MEM_READ 命令执行后,DDR 上数据没有任何变化
  • 通过 ILA 抓取 m_axi_mem 接口,发现没有任何 AXI 请求发出
  • 但 Vortex 状态寄存器报告命令执行成功(无错误标志位置位)

环境:Vivado 2020.2,目标器件 xcvu19p-fsva3824-2-e。


二、调试过程

第一阶段:人工排查 --- 怀疑 Block Design

最开始,思路集中在「工程搭建是否正确」上。毕竟 xcvu440 上的 Vortex 3.0 工作正常,问题大概率出在 xcvu19p 工程本身。

尝试 1:照着 xcvu440 的 Block Design 重建

以 xcvu440 上正常工作的 Block Design 为蓝本,只替换 PCIe IP 为 xcvu19p 对应的版本,其余互联结构尽量保持一致。结果:问题依旧

尝试 2:尝试多种 AXI 互联方案

怀疑是 AXI Interconnect / SmartConnect 的配置或连接方式有问题,反复调整 Block Design 中的互联拓扑。结果:均以失败告终

尝试 3:RTL 行为仿真

既然硬件上不行,回头看仿真。跑了一遍 RTL 级行为仿真,结果完全正确------这也符合预期,毕竟同一套 RTL 在 xcvu440 上实机运行正常。行为仿真只能告诉你「RTL 逻辑没错」,但无法暴露综合/实现阶段的问题。

阶段性结论:RTL 逻辑正确,工程搭建无明显错误,问题可能出在综合或实现阶段。


第二阶段:思路转变 --- 从「找自己的错」到「找工具的错」

多条路走不通之后,一个关键事实开始浮现:

同一套 RTL,xcvu440 正常,xcvu19p 异常。这不可能仅仅是我工程搭建的问题。

这个认知将排查方向从「我哪里连错了」转向了「工具对两个芯片的处理有什么不同」。

尝试 4:寻找 LEC(逻辑等价性检查)工具

最直接的思路是:对两个芯片分别跑综合,然后用 LEC 工具对比生成的网表,看行为是否一致。如果能找到差异点,就能定位问题。

现实很骨感------没找到可用的 LEC 工具下载链接,这条路走不通。


第三阶段:引入 AI 协助 --- 综合后仿真定位根因

既然人工排查 + 传统工具都遇到了瓶颈,决定让 AI 介入,对 Vortex 3.0 IP 的 CMD_MEM_WRITE 数据路径做系统性的综合后仿真分析。

关键决策:不做 RTL 仿真(已经确认正确),直接跑综合后仿真,对比 xcvu440 和 xcvu19p 的综合网表行为。

3.1 综合后仿真初探

基于 Vivado 2020.2 环境,AI 首先对 xcvu440 跑了综合后仿真。出乎意料的是------xcvu440 的综合后仿真结果也不对。这说明即使是 xcvu440,在 Vivado 2020.2 下综合出的网表也存在问题,只是在该芯片上表现不同(可能恰好不影响实测结果,或者此前 xcvu440 用的是不同版本的 Vivado)。

分析网表后发现,DMA 相关的连线在综合后丢失 ,导致 m_axi_mem 无法发出 AXI 请求。这解释了一切:DMA 数据路径断了,写请求根本到不了 DDR。

3.2 逐步缩小范围

AI 对两个芯片的综合后仿真结果进行了系统对比,排查过程如下:

  1. 排除 FPU 嫌疑:xcvu19p 上 FPU 模块可能有问题?但 FPU 与 DMA 数据路径无关,排除。
  2. 排除 DMA 状态机本身:DMA 的逻辑在两个芯片上综合结果应一致,问题更可能在输入侧。
  3. 聚焦 VX_cp_unpack.sv :这是命令解包模块,负责从 AXI 数据中提取 cmd.arg0(DDR 目标地址)、cmd.arg1(Host 源地址)、cmd.arg2(DMA 传输字节数)。如果解包结果错了,DMA 收到的就是错误的命令参数。

尝试过的修复手段(均无效)

手段 结果
VX_cp_unpack 及其相关模块上加 KEEP_HIERARCHY + DONT_TOUCH 属性 无效
综合选项 -keep_equivalent_registers -no_lc -resource_sharing off 无效
(* keep = "true" *) 内部属性保护关键寄存器 无效
set_property DONT_TOUCH 通过约束文件施加 无效

综合工具铁了心要把这段逻辑「优化」掉,任何阻止它的尝试都失败了。

3.3 确认根因

最终定位到 VX_cp_unpack.sv 中使用了 Variable Part Select 语法的三个函数:

  • cl_byte --- 单字节提取
  • read64 --- 8 字节拼接为 64 位
  • read_hdr --- 命令头解析

问题代码模式:

根因 :Vivado 2020.2 在 xcvu19p (UltraScale+) 上,对 function automatic + int 参数 + 运行时 +: part-select + for 循环 + packed struct 返回值 这一组合的综合优化存在 bug,导致函数返回值被错误优化。具体表现为 cmd.arg2(DMA 传输长度)综合后恒为 0

verilog 复制代码
function automatic logic [63:0] read64(input int off);
  logic [63:0] result;
  for (int i = 0; i < 8; i++) begin
    result[i*8 +: 8] = cl_data[(off + i)*8 +: 8];  // 运行时变量 part-select
  end
  return result;
endfunction

cmd.arg2 = read64(off + 4 + 16);  // DMA 长度 → 综合后恒为 0

这完美解释了所有症状:

复制代码
arg2 = 0
  → DMA 认为没有数据要搬
    → 直接跳到 S_DONE 状态
      → 完成回写照常执行(所以状态寄存器报告「成功」)
        → m_axi_mem 从未收到任何写请求
          → DDR 数据不变
  • m_axi_host 有 ILA 波形 ✓ (命令抓取和完成回写仍通过 host 接口执行)
  • 状态寄存器显示成功 ✓ (DMA 走了 S_DONEq_error 硬编码为 0)
  • m_axi_mem 无请求 ✓ (从未进入 S_REQ_AW / S_WRITE 状态)
  • DDR 数据不变 ✓
  • xcvu440 行为不同 ✓ (UltraScale 器件的综合优化策略不同,未触发此 bug)
3.4 最小化修复

AI 给出的修复方案极为克制------只需修改 VX_cp_unpack.sv 一个文件 ,将 cl_byteread64read_hdr 三个使用 Variable Part Select 的函数,改为 always_comb 显式逐字段赋值:

verilog 复制代码
// 修复前:function + 循环 + 运行时 part-select(触发综合 bug)
// function automatic logic [63:0] read64(input int off);
//   for (int i = 0; i < 8; i++)
//     result[i*8 +: 8] = cl_data[(off + i)*8 +: 8];
//   return result;
// endfunction
// cmd.arg2 = read64(off + 16);

// 修复后:always_comb 显式赋值(综合器无歧义)
always_comb begin
  cmd.arg0 = cl_data[off*8 +: 64];
  cmd.arg1 = cl_data[(off+8)*8 +: 64];
  cmd.arg2 = cl_data[(off+16)*8 +: 64];
  // ...
end

修复后,xcvu19p 综合后仿真日志中出现 DEV AW/W,DMA 正常发起写事务,仿真 PASS


三、根因总结

一句话 :Vivado 2020.2 在 xcvu19p (UltraScale+) 上对 function automatic + 运行时 +: variable part select 的综合优化存在 bug,导致 Vortex 命令解包模块中的 DMA 长度字段被错误优化为 0,DMA 控制器因此跳过了实际的内存写入操作。

受影响的 SystemVerilog 代码模式

verilog 复制代码
function automatic logic [W-1:0] extract(input int idx);
  for (int i = 0; i < W/8; i++)
    result[i*8 +: 8] = data[(idx + i)*8 +: 8];
  return result;
endfunction

为什么只影响 xcvu19p 而不影响 xcvu440:两款芯片架构不同(UltraScale+ vs UltraScale),Vivado 综合引擎使用不同的器件映射和优化策略。xcvu19p 的优化路径触发了这个 bug,而 xcvu440 没有。


四、心得与启示

1. 「同一套 RTL,不同芯片不同结果」是最有价值的线索

这个信息直接将排查方向从「RTL 逻辑错误」扭转为「工具行为差异」。如果两个芯片都失败,可能会在 RTL 层面浪费大量时间。当问题呈现器件相关性时,首先怀疑综合/实现工具链,而非自己的 RTL。

2. 行为仿真通过 ≠ 硬件没问题

RTL 行为仿真只能验证逻辑的正确性,无法暴露综合器的 bug。综合后仿真(post-synthesis simulation)是桥接 RTL 与硬件的关键验证步骤------它能发现综合工具对 RTL 的「误解」。在这个案例中,RTL 仿真完全正确,xcvu440 实机也正常,唯独 xcvu19p 的综合出了问题。如果没有综合后仿真,这个 bug 可能需要更长时间才能定位。

3. 综合属性不是万能的

DONT_TOUCHKEEP_HIERARCHY(* keep = "true" *) 等属性在本案例中全部失灵。工具 bug 不会因为你说「请保留这段逻辑」就正确地保留它------综合器根本不知道自己在做错误的优化。当综合属性无效时,重构代码往往比与工具对抗更高效。

4. 警惕硬件中的「成功假象」

本案例中,状态寄存器报告命令执行成功,但实际数据完全没有写入 DDR。原因有三:

  • q_error 硬编码为 32'd0,根本不反映实际错误状态
  • cp_error 未从子模块(DMA、fetch 等)正确聚合
  • DMA 即使跳过了数据搬运,仍然走到了 S_DONE 状态并发送了完成回写

教训:不要信任未经充分验证的状态寄存器。芯片设计时,错误报告路径和正常数据路径同样重要。

5. 保守使用语言特性的「边缘组合」

function automatic + int 参数 + 循环中的 +: part-select + 返回 packed struct,这个组合在仿真中完全正确,在大多数综合器中也正确,但它恰好踩中了 Vivado 2020.2 在特定器件上的 bug。

对于数据路径上的关键逻辑,优先使用更「保守」的写法。 always_comb + 静态 part-select 的语义没有任何歧义,综合器几乎不可能出错。减少对工具优化正确性的依赖,本质上是降低不确定性。

6. 最小化修复,精准打击

最终的修复只修改了一个文件(VX_cp_unpack.sv),只改动了真正触发 bug 的三个函数。在大型 FPGA 工程中,每增加一行改动就多一分引入新问题的风险。找到根因后,用最小的改动解决问题。这不只是优雅,更是工程纪律。

7. 善用 AI 加速调试闭环

如果没有 AI 协助,手动对比两个芯片的综合后仿真结果、逐模块排查网表差异,将是一个极其耗时且容易遗漏的过程。AI 在以下环节发挥了关键作用:

  • 穷举式代码审查:通读全部 ~100 个源文件,不遗漏任何可疑点
  • 自动化综合后仿真:对两个芯片分别跑综合→仿真→日志分析,形成闭环
  • 网表差异分析:从海量网表信号中快速定位 DMA 连线丢失
  • 最小化修复:在理解整个数据路径的基础上,给出只触及根因的修改方案

AI 不是替代工程师的判断,而是放大了工程师的分析带宽。


五、调试方法论

回顾整个调试过程,可以归纳为以下推进节奏:

复制代码
观察现象 (DDR无变化, ILA无信号)
  → 复现确认 (CMD_MEM_WRITE/READ 均异常)
    → 排除工程问题 (Block Design重建, 多种互联方案)
      → 排除RTL逻辑 (行为仿真通过)
        → 思路转变 (芯片差异 → 怀疑工具)
          → 寻找对比手段 (LEC未果 → 转向综合后仿真)
            → 系统对比 (xcvu440 vs xcvu19p综合网表)
              → 定位模块 (DMA连线丢失 → VX_cp_unpack)
                → 确认根因 (Variable Part Select触发综合bug)
                  → 最小化修复 (改一个文件)
                    → 验证通过 (综合后仿真 PASS)

核心理念:调试不是靠一次想对,而是靠系统性地排除错的。 每一步排除都在缩小搜索空间。从 Block Design → RTL 逻辑 → 综合工具 → 具体模块 → 具体语法,每个阶段的结论都在为下一阶段导航。最终剩下的那个解释,无论多么意外(谁会想到是综合器在特定器件上对特定语法的 bug?),就是答案

相关推荐
Hi202402177 天前
Cortex-A53 + GIC700 + Boot BRAM Vivado 全流程复现
arm·fpga·vivado
Eloudy7 天前
Holoscan Sensor Bridge 入门指南(Getting Started)
gpu·fpga·rdma
Eloudy9 天前
RFSoC-PYNQ → RK-XCKU5P-F 移植记录
fpga
ARM+FPGA+AI工业主板定制专家10 天前
国产化RK3576+FPGA架构|晶圆传输机器人高速定位+AI瑕疵检测一体化方案
fpga开发·架构·机器人·嵌入式·fpga·工控·机器人运控
Eloudy11 天前
申请 Xilinx 免费 IP 许可的步骤笔记
fpga
零涂毕业设计12 天前
毕业设计模块开发-OLED显示屏(IIC协议0.96寸)STM32 ESP32 FPGA Linux驱动免费分享
linux·stm32·单片机·嵌入式·esp32·fpga·oled
神电测控15 天前
新品发布:国产新型三合一多功能PG-ZYNQ7100 sbRIO板卡(PCIe+USB3.0+Ethernet+FMC+4个40pin扩展口)
fpga·zynq·crio·神电测控·王电令·sbrio·linuxrt
ALINX技术博客16 天前
ALINX 亮相 2026 WAIC 世界人工智能大会,展示 AI 视觉 FPGA+GPU 异构计算与电子后视镜解决方案
人工智能·ai·fpga·世界人工智能大会·电子后视镜
Eloudy18 天前
RFSoC 4x2 参考手册
fpga