
1. 为什么要在 Versal 上折腾 AXI NoCVersal 这代 ACAP 平台跟之前的 Zynq MPSoC 完全不是一个玩法。Zynq 时代大家习惯了 AXI HP/HPC 口直连 DDR脑子里就一张简单的点对点连接图到了 VersalAMD 把整个片上互联换成了AXI NoCNetwork on Chip它本质上是一张可编程的片上网络把 PL、PS、DDR、AI Engine、PCIe、以太网这些主从设备全部挂在一张网里通过 NoC Master/Slave Unit 和 NoC 内部的交换矩阵来路由事务。我第一次接触 Versal 的 NoC 配置时最直观的感受就是它像给 FPGA 内部装了一个小型交换机。以前 PL 要访问 DDR你得手动例化 AXI Interconnect自己算位宽转换、时钟域跨越、仲裁优先级现在这些活儿大部分交给 NoC 了你只需要在 Vivado 里把 NoC 连接搭好配置带宽和 QoS剩下的交给工具去生成。但问题也来了——NoC 配置错了仿真能过上板直接挂。我踩过最典型的一个坑PL 侧通过 NoC 读 DDR仿真里数据全对上板跑起来读回来的数据每隔几百个 beat 就错一次。查了整整两天最后发现是 NoC Slave Unit 的 outstanding 事务数配得太激进超过了 DDR 控制器实际能承受的并发导致返回数据乱序后没有被正确重组。这种问题在纯 RTL 仿真里根本复现不出来因为仿真模型不会模拟真实的 DDR 调度延迟。所以这篇东西我想把AXI NoC 从配置、仿真到 QoS 调优这一整条链路完整走一遍。适合谁看如果你手上有 Versal 板子VCK190、VHK158、VPK120 这些都行正在做 PL 到 DDR 的高带宽数据通路或者要跑 AI Engine 和 PL 之间的数据流那这篇内容应该能帮你少走不少弯路。纯新手也能看我会把 NoC 的基本概念用生活化的方式讲清楚但前提是你得会用 Vivado至少知道怎么建 Block Design。2. AXI NoC 的整体设计与思路拆解2.1 NoC 到底解决了什么问题在 Zynq MPSoC 上PL 访问 DDR 走的是 AXI HP 口每个 HP 口位宽固定、时钟固定带宽上限摆在那里。你要想提高带宽只能多开几个 HP 口然后在 PL 里做 AXI Interconnect 把多个 master 汇聚起来。这种做法有几个硬伤一是 AXI Interconnect 本身消耗大量 LUT 和 BRAM二是仲裁策略固定没法针对不同 master 做差异化 QoS三是时钟域跨越要自己处理稍不注意就出亚稳态。Versal 的 NoC 把这些事情全部硬件化了。NoC 内部有专门的NoC Master UnitNMU和NoC Slave UnitNSUNMU 负责把 AXI 事务转换成 NoC 内部的流式包NSU 负责把包还原成 AXI 事务。中间经过 NoC 的交换矩阵支持多路径路由、动态带宽分配和 QoS 优先级调度。用个类比Zynq 的 AXI HP 口像是一条固定车道的公路车多了就堵Versal 的 NoC 像是一个智能交通系统可以根据车流量动态调整车道还能给救护车高优先级事务开绿灯。2.2 什么场景下必须用 NoC不是所有设计都需要 NoC。如果你只是做个低速外设控制PL 里几个寄存器读写用 AXI-Lite 直连 PS 的 M_AXI_LPD 就够了没必要上 NoC。但以下几种场景NoC 基本是唯一选择PL 到 DDR 的高带宽数据流比如视频采集、雷达信号处理数据率动辄几个 GB/s只有 NoC 能提供足够的带宽和灵活的位宽配置。AI Engine 与 PL 之间的数据交换AI Engine 阵列本身通过 AXI Stream 和 NoC 连接PL 要跟 AI Engine 通信必须经过 NoC。多 Master 共享 DDR 且需要差异化 QoS比如一个系统里同时有视频流、控制流和调试流视频流要求高带宽控制流要求低延迟NoC 的 QoS 机制可以给它们分配不同的优先级。需要动态重构 NoC 连接Versal 支持部分重配置NoC 的配置也可以在运行时修改这在多任务切换场景下很有用。2.3 NoC 配置的核心参数有哪些在 Vivado 里配置 NoC主要涉及以下几个关键参数我逐个解释它们的作用和选型逻辑位宽Data WidthNMU 和 NSU 都支持 32/64/128/256/512 位。位宽越大单次事务传输的数据量越大但消耗的 NoC 内部资源也越多。一般原则是如果数据流是连续的尽量用 128 或 256 位如果是随机小事务64 位就够了。时钟频率NoC 的时钟可以独立于 PL 和 PS 的时钟。频率越高带宽越大但功耗也越高。VCK190 上 NoC 最高可以跑到 1GHz 左右但实际设计中我一般跑 500-800MHz留点余量。Outstanding 事务数这是最容易踩坑的参数。它决定了 NMU 可以同时发出多少个未完成的事务。设得太小带宽上不去设得太大DDR 控制器可能处理不过来导致数据错乱。一般建议从 8 开始试逐步往上加同时用性能计数器观察 DDR 的利用率。QoS 优先级NoC 支持 0-15 共 16 个优先级。数值越大优先级越高。高优先级事务会抢占低优先级事务的带宽。但注意优先级不是越高越好如果所有 master 都设成最高优先级等于没有优先级。路由策略NoC 支持多种路由算法包括最短路径、负载均衡等。默认的最短路径在大多数场景下够用但如果 NoC 内部出现拥塞可以考虑切换到负载均衡模式。2.4 仿真策略的选择NoC 的仿真分两个层次功能仿真和性能仿真。功能仿真用 Vivado 自带的 AXI VIPVerification IP主要验证 AXI 事务的正确性比如读写数据是否一致、握手信号是否合规。这种仿真速度快但不会模拟 NoC 内部的拥塞和延迟。性能仿真需要用到 NoC 的性能模型AMD 提供了 NoC Performance Model可以模拟不同配置下的带宽和延迟。这种仿真跑得慢但能提前发现 QoS 配置不合理的问题。我的建议是功能仿真必做性能仿真选做。如果设计里 NoC 的负载不高性能仿真可以跳过但如果多个 master 同时抢带宽性能仿真能帮你省下大量上板调试的时间。3. 核心细节解析与实操要点3.1 在 Vivado 中搭建 NoC 连接打开 Vivado 2022.2 或更新版本新建工程选择对应的 Versal 器件。在 Block Design 里你会看到 IP 目录中有AXI NoC IP。但更常用的方式是通过Versal ACAP 的 CIPSControl, Interface, and Processing SystemIP来配置 NoC因为 CIPS 里已经集成了 PS 和 NoC 的接口。具体步骤在 Block Design 中添加 CIPS IP双击配置。在PS-PL Interfaces选项卡里使能AXI NoC接口。根据需要选择 NoC 的 master 和 slave 端口数量。比如你要从 PL 访问 DDR就需要一个 NoC Master 端口PL 侧和一个 NoC Slave 端口DDR 侧。配置每个端口的位宽和时钟。PL 侧的时钟一般跟 PL 逻辑时钟一致DDR 侧的时钟跟 DDR 控制器时钟一致。在NoC QoS选项卡里为每个 master 端口设置优先级和带宽限制。这里有个细节NoC 的时钟必须由 Clocking Wizard 或外部时钟源提供不能直接用 PS 的时钟。因为 NoC 的时钟域是独立的直接连 PS 时钟会导致时序问题。3.2 NoC 连接的正确性检查配置完 NoC 后Vivado 会自动生成 NoC 的连接逻辑。但别急着生成比特流先做几项检查地址映射在 Address Editor 里确认每个 master 能访问的地址范围是否正确。NoC 的地址映射跟普通 AXI 不一样它有一个专门的地址转换表。位宽匹配NMU 和 NSU 的位宽必须匹配或者通过 NoC 内部的位宽转换器自动转换。如果手动配置要确保转换逻辑正确。时钟域跨越如果 NMU 和 NSU 的时钟不同NoC 会自动插入异步 FIFO。但要确认 FIFO 的深度是否足够太浅会导致吞吐量下降。注意NoC 的地址映射一旦配错仿真可能不报错但上板后访问会直接挂死。建议在仿真阶段就用 AXI VIP 做一次全地址范围的读写测试。3.3 QoS 参数的配置逻辑QoS 是 NoC 最核心的功能之一但也是最容易被滥用的。我见过不少设计把所有 master 的优先级都设成最高结果 NoC 内部的仲裁器直接懵了带宽反而下降。正确的做法是按业务重要性分级业务类型优先级带宽限制说明实时控制流12-15不限制延迟敏感数据量小视频/雷达数据流8-11设上限带宽敏感可容忍一定延迟调试/日志流0-3严格限制非关键业务不能抢带宽普通数据流4-7设上限一般业务带宽限制的单位是 MB/s设置时要参考 NoC 的总带宽。比如 NoC 总带宽是 10GB/s视频流占 6GB/s控制流占 1GB/s剩下的留给其他业务。3.4 仿真环境的搭建NoC 的功能仿真需要以下组件AXI VIP作为 master 和 slave模拟 AXI 事务。NoC 仿真模型Vivado 会自动生成不需要手动例化。测试激励用 SystemVerilog 或 Python 写测试序列。一个典型的仿真流程// 伪代码示例 initial begin // 初始化 AXI VIP axi_master.init_master(); axi_slave.init_slave(); // 配置 NoC 寄存器 noc_config.set_qos(0, 15); // master 0 优先级 15 noc_config.set_bandwidth(0, 0); // 不限制带宽 // 发起读写事务 axi_master.write(32h0000_1000, 32hDEAD_BEEF); axi_master.read(32h0000_1000, rdata); // 检查结果 if (rdata ! 32hDEAD_BEEF) begin $error(Read data mismatch!); end end仿真跑起来后重点观察以下几个信号AWVALID/AWREADY写地址握手是否正常。WVALID/WREADY写数据握手是否正常。BVALID/BREADY写响应是否正常。ARVALID/ARREADY读地址握手是否正常。RVALID/RREADY读数据是否正常。如果某个握手信号长时间不拉高说明 NoC 内部出现了反压需要检查 QoS 配置或 outstanding 事务数。4. 实操过程与核心环节实现4.1 从零搭建一个 PL 到 DDR 的 NoC 通路假设我们要做一个视频采集系统PL 侧从摄像头接收数据通过 NoC 写入 DDR然后 PS 侧读取 DDR 做后续处理。以下是完整步骤第一步创建 Vivado 工程选择器件xcvc1902-vsva2197-2MP-e-SVCK190 的器件型号。工程建好后创建一个 Block Design。第二步添加并配置 CIPS在 Block Design 中添加 CIPS IP。双击配置在PS-PL Interfaces里使能PL to DDR的 NoC 接口。配置 NoC Master 端口数量为 1Slave 端口数量为 1。Master 端口位宽设为 128 位Slave 端口位宽设为 256 位DDR 侧位宽可以更大。Master 端口时钟设为 300MHzSlave 端口时钟设为 500MHz。第三步添加 NoC IP 并连接在 IP 目录里搜索AXI NoC添加到 Block Design。将 CIPS 的 NoC Master 端口和 NoC IP 的 Slave 端口连接NoC IP 的 Master 端口连接到 DDR 控制器。这里要注意NoC IP 的时钟输入必须来自独立的 Clocking Wizard不能直接连 CIPS 的时钟输出。我一般会加一个 Clocking Wizard输出 300MHz 和 500MHz 两路时钟分别给 NoC 的 Master 和 Slave 侧。第四步配置 QoS双击 NoC IP在QoS选项卡里将 Master 0 的优先级设为 10视频流较高优先级。带宽限制设为 4000 MB/s假设 NoC 总带宽 10GB/s。Outstanding 事务数设为 16。第五步地址映射在 Address Editor 里将 DDR 的地址范围映射到 NoC Master 0。假设 DDR 起始地址是0x0000_0000大小 2GB那么 Master 0 的地址范围就是0x0000_0000到0x7FFF_FFFF。第六步生成比特流并导出 XSA完成 Block Design 后生成 HDL Wrapper跑综合和实现最后生成比特流。导出 XSA 文件供 Vitis 使用。4.2 仿真验证的关键步骤仿真环境搭建好后按以下步骤验证复位释放确保 NoC 的复位信号正确释放。NoC 的复位需要至少 16 个时钟周期。寄存器配置通过 AXI-Lite 接口配置 NoC 的 QoS 寄存器。配置顺序很重要先配优先级再配带宽限制最后使能 NoC。发起事务用 AXI VIP 发起读写事务。建议先做小数据量的读写测试确认通路正常后再加大数据量。性能统计在仿真中统计读写事务的延迟和吞吐量。如果延迟超过预期检查 QoS 配置和 outstanding 事务数。一个实测数据在 VCK190 上128 位位宽、300MHz 时钟的 NoC Master理论带宽是 128/8 * 300M 4.8GB/s。实际跑下来读带宽约 3.8GB/s写带宽约 3.5GB/s效率在 75% 左右。这个效率在 NoC 里算正常因为 NoC 内部有协议开销。4.3 上板调试与性能计数器上板后Vivado 的 Hardware Manager 里可以查看 NoC 的性能计数器。这些计数器包括事务计数每个 master 发起的事务总数。带宽计数每个 master 的实际带宽。延迟计数事务的平均延迟。拥塞计数NoC 内部出现拥塞的次数。如果发现某个 master 的带宽远低于配置值先检查 QoS 优先级是否被其他 master 抢占。如果拥塞计数很高说明 NoC 内部路由出现了瓶颈可以考虑调整路由策略或增加 NoC 的时钟频率。实操心得NoC 的性能计数器在默认情况下是关闭的需要在 CIPS 配置里手动使能。使能后会消耗少量 NoC 资源但对性能影响不大。4.4 QoS 调优的实战案例我之前做过一个项目系统里有三个 master视频流Master 0、控制流Master 1、调试流Master 2。初始配置是三个 master 优先级都是 8带宽都不限制。结果跑起来后调试流疯狂刷日志把视频流的带宽抢了一大半视频出现卡顿。调优过程先把调试流的优先级降到 2带宽限制到 100MB/s。视频卡顿明显改善但偶尔还有丢帧。再把视频流的优先级提到 12控制流提到 10。视频流稳定了但控制流的延迟偶尔超标。最后给控制流单独分配了一个 NoC 虚拟通道Virtual Channel让它和视频流走不同的物理路径。这样控制流的延迟稳定在 100ns 以内视频流也不再丢帧。这个案例说明QoS 调优不是一蹴而就的需要根据实际业务的表现逐步调整。而且虚拟通道是 NoC 的一个高级功能可以在物理资源允许的情况下提供更好的隔离性。5. 常见问题与排查技巧实录5.1 NoC 配置后仿真能过但上板挂死这是最经典的问题。原因通常有三个地址映射错误仿真时 AXI VIP 的地址范围是手动指定的可能跟 NoC 的实际地址映射不一致。上板后 PS 访问的地址不在 NoC 的映射范围内直接挂死。Outstanding 事务数过大仿真模型不会模拟 DDR 的调度延迟所以 outstanding 设多大都能过。上板后 DDR 控制器处理不过来返回数据乱序。时钟频率不匹配仿真时用的时钟频率可能跟实际上板的不一样。比如仿真跑 100MHz上板跑 300MHz时序余量不够。排查方法先用 ILA 抓 NoC 的 AXI 接口信号看握手是否正常。如果 AWVALID 拉高但 AWREADY 一直不拉高说明 NoC 内部反压了检查 QoS 和 outstanding 配置。5.2 NoC 带宽远低于理论值理论带宽 位宽/8 * 时钟频率。实际带宽通常只有理论值的 60%-80%。如果低于 60%检查以下几点位宽转换如果 NMU 和 NSU 位宽不一致NoC 内部会做位宽转换这会引入额外开销。尽量让两边位宽一致。时钟域跨越如果 NMU 和 NSU 时钟不同异步 FIFO 的深度会影响吞吐量。FIFO 太浅会导致频繁反压。QoS 抢占高优先级 master 抢占了带宽。用性能计数器确认每个 master 的实际带宽。DDR 瓶颈如果多个 master 同时访问 DDRDDR 控制器本身可能成为瓶颈。VCK190 的 DDR4 控制器理论带宽约 19GB/s实际能用到 12-14GB/s。5.3 NoC 仿真速度太慢NoC 的功能仿真本身不慢但如果测试序列太长仿真时间会线性增长。加速方法减少测试数据量功能仿真不需要跑完整的数据流用少量数据验证通路正确性即可。关闭不必要的调试信号Vivado 仿真器默认会记录所有信号的波形关闭不需要的信号可以大幅提速。使用事务级建模TLM如果只是验证 NoC 的配置逻辑可以用 TLM 模型代替 RTL 仿真速度快 10 倍以上。5.4 常见问题速查表问题现象可能原因排查方法解决方案仿真过上板挂死地址映射错误检查 Address Editor修正地址范围带宽低于理论值 60%位宽不匹配检查 NMU/NSU 位宽统一位宽数据偶发错误Outstanding 过大降低 outstanding 数从 8 开始逐步增加延迟超标QoS 优先级低查看性能计数器提高优先级或分配虚拟通道仿真速度慢测试序列太长减少数据量用 TLM 模型NoC 复位失败复位脉冲太短检查复位信号至少 16 个时钟周期5.5 几个容易忽略的细节NoC 的复位顺序NoC 必须在 CIPS 复位释放之前完成配置否则 NoC 会处于未定义状态。我一般会在 CIPS 配置里把 NoC 的复位和 CIPS 复位绑定在一起。NoC 的时钟必须稳定如果 NoC 时钟在运行过程中丢失NoC 会直接挂死而且不会自动恢复。所以 Clocking Wizard 的锁定信号要接到 NoC 的复位逻辑里。NoC 的功耗NoC 是全速运行的即使没有事务它也会消耗静态功耗。在低功耗场景下可以通过 CIPS 关闭未使用的 NoC 端口。NoC 的仿真模型版本Vivado 不同版本的 NoC 仿真模型可能有差异。建议用跟实际工程一致的 Vivado 版本做仿真避免版本不匹配导致的问题。6. 一些个人体会NoC 这个东西刚上手的时候觉得复杂配置项一大堆文档又厚。但用熟了之后会发现它其实比传统的 AXI Interconnect 省心得多。以前在 Zynq 上做多 master 共享 DDR光调仲裁和位宽转换就能耗掉一周现在在 Versal 上NoC 把这些都封装好了你只需要关注 QoS 和带宽这两个核心参数。我个人的经验是NoC 的配置不要一次到位要迭代。先配一个保守的版本跑通功能然后用性能计数器看瓶颈在哪里再逐步调整 QoS 和 outstanding。这样比一开始就追求最优配置要稳妥得多。另外仿真阶段一定要做地址映射的全覆盖测试。我吃过这个亏仿真只测了一小段地址上板后 PS 访问了另一段地址直接挂死查了一整天才发现是 Address Editor 里漏配了一段。最后再分享一个小技巧Vivado 的 NoC 配置可以导出成 Tcl 脚本下次建工程的时候直接 source 这个脚本几秒钟就能把 NoC 配好比手动点界面快多了。这个脚本还可以纳入版本管理方便追溯配置变更。