ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Xilinx Aurora 8B/10B IP核配置与调试实战:FPGA高速互联链路设计

Xilinx Aurora 8B/10B IP核配置与调试实战:FPGA高速互联链路设计 开板那一刻总是最紧张的时候。去年我在一块多板互联的采集系统里第一次把 Xilinx Aurora 8B/10B IP核跑起来从那以后这玩意儿就成了我做高速接口的首选方案。说实话Aurora 8B/10B 在 Xilinx 的高速串行协议家族里算是门槛最低、最容易上手的它不像 PCIe 或 Ethernet 那样需要处理繁杂的分层协议而是直接给你一个干净的流式或帧式接口把 GT 收发器、8B/10B 编码、通道绑定、时钟修正这些脏活累活全包了。这篇博文我从配置讲起把 IP 核生成的每个选项、仿真里的每个时序节点还有实际调试中踩过的坑都摊开来讲。如果你正在准备做板间互联、ADC/DAC 高速数据传输或者只是想搞明白 Aurora 8B/10B 这 IP 到底怎么用这篇文章可以帮你少走不少弯路。我会尽量用“我实际动手时怎么操作”的口吻来写而不是念手册很多细节是官方文档里不会直接告诉你的。1. 理解 Aurora 8B/10B 的定位为什么不用自己写高速链路1.1 Aurora 协议栈到底长什么样Aurora 8B/10B 是 Xilinx 提供的一个轻量级链路层协议运行在 FPGA 内部的 GT 高速收发器之上。所谓 8B/10B指的是数据在发送前会被编码成 10bit 的符号从而保证直流平衡和足够的跳变沿方便接收端时钟恢复。这个协议本身不做端到端的报文解析也不管你上层跑的是什么业务它就负责把数据从一个 FPGA 搬到另一个 FPGA或者在同一片 FPGA 的两个 GT 通道之间做回环测试。在协议栈的划分上Aurora 8B/10B 位于 GT 收发器和用户逻辑之间。用户逻辑看到的是一个简单的并行数据接口数据宽度常见的有 2 字节、4 字节、8 字节甚至有 16 字节的配置。用户只需要按照握手信号把数据丢进去IP 核会负责把并行数据转成高速串行比特流在接收端再把串行数据恢复出来对齐好重新变成并行数据交给用户。整个过程对用户隐藏了 8B/10B 编解码、逗号检测、通道对齐、时钟修正等细节。那为什么不自己写一套高速收发逻辑呢我早期也干过这事儿用 GT 原语直接在用户逻辑里拼装数据结果光是把 RX 的 elastic buffer 和 bit slip 调明白就花了两周。Aurora IP 核帮你把 GT 原语的初始化、复位、时钟修正序列、通道绑定序列全部封装好了你只需要调用一个成熟的、经过验证的协议把精力留在上层业务上。这也是 Xilinx 官方明确推荐的做法除非你有极特殊的定制需求否则高速串行链路优先使用现成 IP。1.2 几个必须搞懂的概念线速率、参考时钟、流控Aurora 8B/10B 配置里最核心的参数是线速率Line Rate单位一般是 Gb/s。线速率决定了 GT 收发器工作在什么速度上。比如选 5.0 Gb/s再搭配 8B/10B 编码那有效数据吞吐大约是 5.0 * 8 / 10 4.0 Gb/s再乘以用户接口的数据宽度就能换算出用户时钟频率。这一点非常容易算错我见过有人直接把 5G 当作数据带宽去估算吞吐结果用户时钟频率配错了链路能起来但数据全乱。参考时钟Reference Clock是给 GT 收发器做时钟恢复和串并转换用的基础时钟一般来自板上的差分晶振频率通常是 100MHz、125MHz、148.5MHz、156.25MHz 等。GT 会通过内部的 PLL 把参考时钟倍频到需要的比特率。这里有一个硬性要求参考时钟频率必须能够通过整数分频/倍频关系得到你选定的线速率。Xilinx 的 IP 配置界面会自动列出可用的参考时钟频率组合如果你从外部导入的约束里指定了某个 GT 位置配套的参考时钟管脚界面会帮你检查匹配关系。流控Flow Control是 Aurora 8B/10B 的一个可选特性。关闭流控时用户逻辑必须自行保证不会在接收端还没准备好的情况下持续发送数据否则接收端 FIFO 可能溢出丢数。开启流控后IP 核会通过发送 pause 控制消息来阻止对端继续发送逻辑上更保险但会增加额外的开销和接线。实际工程里如果链路速率不高、数据连续性要求不太极端我通常先关掉流控把接口逻辑保持简单等调试稳定后再评估是否需要加。2. 动手配置 IP 核选型与参数计算2.1 打开 IP 核之前的硬件准备在 Vivado 里添加 Aurora 8B/10B IP 前先想清楚三件事用哪种 GT 类型、参考时钟从哪来、链路的物理拓扑是什么。不同器件系列的 GT 类型不一样7 系列一般是 GTP/GTXUltraScale 系列是 GTH/GTY。Aurora 8B/10B IP 会自动识别你所选器件支持的 GT 类型并在配置界面里显示。如果你用的是老一点的 Artix-7那大概率是 GTP线速率上限偏低如果是 Kintex-7 或 UltraScale用 GTX/GTH 能跑到更高速度。参考时钟来源要提前确定是板上有独立的差分参考时钟还是准备从 FPGA 的某个普通引脚通过 MMCM/PLL 转出来。这里我的建议是高速串行链路一定要用专用的 MGTREFCLK 引脚不要用普通逻辑生成时钟喂给 GT。因为 GT 的模拟前端对时钟抖动极其敏感用普通时钟网络绕一圈抖动性能会明显恶化误码率可能高到链路根本稳定不下来。物理拓扑也要心里有数是点对点直连还是经过连接器、背板、光模块Aurora 8B/10B 本身只定义了物理层和链路层传输介质由硬件决定。如果经过连接器或 PCB 走线较长需要在引脚约束里关注 GT 的接收端均衡RX Equalization配置这个通常在 GT 的属性里设置Aurora IP 的配置界面也会提供对应的选项。2.2 配置界面里的关键参数逐项说IP 配置界面打开后第一页经常会让你选 Core 类型Duplex双向还是 Simplex单向。Duplex 就是一个 GT 通道同时收发Simplex 则是只发或只收。大部分场景选 Duplex因为 FPGA 之间互联通常需要双向交互哪怕只是传个状态。如果确实只需要单向高速传输Simplex 可以省一半 GT 资源但别忘了另一端还得配一个反向的 Simplex 或者干脆用低速 GPIO 做握手。接下来是 Line Rate 和 Reference Clock。假设你要做 5.0 Gb/s 线速率而板上的参考时钟是 125MHzVivado 会直接算出需要的 GT PLL 分频倍频设置。这里有个常见疑问线速率和参考时钟一定要是整数倍关系吗答案是工程上最好是的因为非整数倍会引入额外的分频器配置有些器件支持但不推荐而且容易误码。我习惯在选型阶段就把线速率和参考时钟绑定一起定而不是分别定了再拼。数据宽度User Interface Data Width这一项会直接影响用户逻辑的时钟频率。Aurora 8B/10B 的 GT 并行内部总线是一个固定宽度但用户接口可以做 32-bit 或 64-bit 等不同选择。举个例子线速率 5.0 Gb/s选用 32-bit 用户接口那么用户时钟就是 5.0 Gb/s * 8 / 10 / 32 125 MHz。如果选用 64-bit 接口用户时钟就是 62.5 MHz。选择多大宽度取决于你上层逻辑的处理能力和数据位宽。宽接口慢时钟对时序收敛更友好窄接口快时钟则可能面临 FIFO 跨时钟域的处理没有绝对好坏看你核心逻辑跑多快。还要选接口模式Framing帧模式还是 Streaming流模式。Framing 接口里多了一组帧起始/帧结束信号适合按包传输的场景Streaming 接口直接把有效数据连续发送没有帧边界适合数据流业务。我个人在实际项目里更喜欢用 Streaming因为接口干净控制逻辑少。如果你的数据天然就是包形式的比如以太网帧、PCIe TLP 之类那 Framing 会帮你省掉自己包边界的处理。2.3 生成 Example Design 的方式配置完成后在 IP 核的 Example Design 页签下点 Generate Example DesignVivado 会拷贝一套完整的示例工程里面包含 GT 复位模块、初始化逻辑、一个简单的数据生成和校验模块以及配套的约束文件。这套例程是最好的学习素材我每次在新器件上使用 Aurora都会先导出一份 Example Design把它的复位时序和用户接口完整跑一遍仿真确认链路能起来再开始嫁接自己的业务逻辑。生成 Example Design 后直接打开工程顶层模块里会看到aurora_8b10b_0_support、aurora_8b10b_0_gt_frame_gen、aurora_8b10b_0_gt_frame_check这类模块。其中 support 模块负责例化 GT 和 IP 核frame_gen 和 frame_check 是在用户接口上模拟发数据和校验数据的回路专门用来做链路验证。你可以在 Vivado 里直接跑行为仿真也可以综合实现后上板测试。这个流程看着简单但能帮你排除掉一大半“链路起不来”的环境问题。3. 信号级设计与复位时序channel_up 和 lane_up 是灵魂3.1 复位拓扑和起站顺序Aurora 8B/10B IP 对外暴露的复位信号有好几个名字看起来差不多但作用完全不同。首先是reset它是整个 IP 的异步复位通常由 FPGA 全局复位或者上电复位控制然后是gt_reset它控制 GT 收发器的复位和reset有先后关系还有power_down控制 GT 的上电状态一般拉低表示正常上电。很多人一上来把所有复位都绑到一个按键上结果链路死活起不来就是因为这些复位的时序关系没满足要求。官方推荐的复位顺序大概是先把power_down置为有效低电平然后拉低gt_reset让 GT 内部完成 PLL 锁定、校准等初始化等gt_reset_done拉高后再释放reset让 Aurora 协议层开始发送初始化序列。GT 的复位时间从微秒级到毫秒级不等取决于器件速度和配置。Example Design 里的aurora_8b10b_0_reset_logic模块把这段时序都做好了我强烈建议你直接复用这个模块不要自己手写复位状态机。自己写的话很容易忽略 “GT_RESET 必须保持足够长时间的低电平” 这类细节导致 PLL 锁定不稳定。链路起来后最重要的两个状态信号是lane_up和channel_up。lane_up表示单条 GT 通道完成了通道对齐和 8B/10B 同步channel_up表示整个 Aurora 通道可能绑定多条 lane都完成了初始化可以开始传输数据。仿真或者调试时这两个信号是判断问题出在物理层还是协议层的分水岭如果lane_up都不拉高基本可以断定是 GT 物理层没搞定如果lane_up拉高了但channel_up不拉高那大概率是通道绑定或者对端协议初始化有问题。3.2 USER_CLK 和初始化完成信号的关系Aurora IP 会输出一个用户时钟user_clk所有用户接口信号都在这个时钟域下工作。user_clk的频率由线速率、用户接口宽度、8B/10B 编码共同决定前面已经讲过换算公式。需要特别注意的是只有channel_up拉高之后用户时钟下的数据通路才有效。在channel_up拉高之前不要往发送接口上送有效数据否则这些数据会被当成协议初始化序列的一部分接收端根本不会同步上。另外还有一个user_clk_active部分版本叫user_clk的 active 标志它表示用户时钟是否稳定。有的应用里用户时钟是外部提供的有的版本会由 IP 自己产生所以你要在逻辑里加一个判断等到user_clk_active为高、channel_up为高再接下去做业务。我在代码里通常是这么处理的用channel_up的上升沿去复位用户的发送 FIFO 和接收 FIFO等 FIFO 的复位释放后再开始搬运数据。这样比单纯判断电平更安全因为 FIFO 里的残留数据可能在链路刚刚建立时被误读。有个容易忽略的点user_clk的周期和 GT 的并行时钟并不是直接同源的。Aurora IP 内部会做跨时钟域处理所以在用户逻辑里看到的数据已经是经过 CDC 同步后的结果。这意味着你在 User Interface 上写的时序约束主要对用户逻辑生效不必去约束 GT 内部的比特时钟。但反过来如果你在用户逻辑里用user_clk做时序分析一定要确保约束文件里已经正确创建了user_clk的时钟定义。Example Design 自动生成的 XDC 里已经帮你建好了如果你自己从零搭工程千万别漏掉这一条。3.3 数据接口的握手细节用户接口上的数据通路最核心的是发送端s_axi_tx_tdata、s_axi_tx_tvalid、s_axi_tx_tready和接收端m_axi_rx_tdata、m_axi_rx_tvalid。这个名字一看就是 AXI4-Stream 风格的接口。实际上 Aurora 8B/10B 的用户接口确实遵循 AXI4-Stream 握手协议这一点对用过 FIFO IP 或者 AXI 总线的人来说非常熟悉。发送的时候要用s_axi_tx_tvalid和s_axi_tx_tready同时为高的周期才能把数据送进去。也就是说当你拉高tvalid时如果对方tready没拉高数据要保持在总线上不动直到握手成功。接收端类似tvalid拉高时数据才有效。这里面常见的错误是发送端的一个包中间不能停断吗Aurora Streaming 接口允许数据流中间断但是你的握手逻辑必须正确否则会出现数据错位。如果是 Framing 模式还会有s_axi_tx_tlast、s_axi_tx_tkeep这类信号。tlast标记一帧的结束tkeep标记最后一个周期里有几个字节有效。这些细节在做跨时钟域或者跨协议转换时经常出错我一般建议在白盒测试阶段就先用固定长度的帧数据做循环校验确认tlast和tkeep在接收端完全一致再接入真实业务。4. 仿真全流程实战从 testbench 到回环验证4.1 用 Example Design 跑通第一次仿真在 IP 的 Example Design 工程里Vivado 会生成一个 testbench 文件通常放在工程目录的sim文件夹下。直接把这套工程设置为顶层点击 Run Behavioral Simulation就能看到 Aurora 链路从复位到channel_up拉高的完整过程。第一次跑这个仿真时重点观察三个时间点gt_reset_done什么时候拉高、lane_up什么时候拉高、channel_up什么时候拉高。正常情况下复位释放后先是 GT 的 PLL 锁定内部校准完成gt_reset_done拉高再过一段时间接收端检测到发送端发来的初始化序列完成逗号对齐lane_up拉高最后双方交互握手channel_up拉高。整个仿真时间一般在几十微秒到几百微秒视线速率和仿真模型而定。如果仿真跑了很久channel_up都没拉起来先别急着改代码右键查看这几个信号确认复位时序是否和预期一致。Example Design 自带的 testbench 在上电后会自动拉高reset然后执行完整的初始化流程所以第一次仿真基本都能过。真正需要花心思的是第二步把这个 testbench 改成你自己的业务验证环境。把 Example Design 的 testbench 改成自己的有一个讨巧的方式保留它原有的初始化逻辑只替换用户接口上的数据生成和校验部分。也就是说frame_gen和frame_check这两个模块换成你的业务模块但reset_logic和aurora_8b10b_0_support的例化保持原样。这样做的好处是复位时序已经过验证你只需要专心调自己的数据通路。我在多个项目里都是这么起步的效率很高。4.2 自己写 testbench 时最容易出错的三个地方第一复位信号的处理。Aurora IP 的reset和gt_reset都是低电平有效还是高电平有效不同版本、不同配置可能不一样。写 testbench 之前先打开 IP 的例化模板看清楚每个信号的极性别想当然。很多人在仿真里看到链路不起来查了半天发现是把复位信号给反了。第二用户时钟的启动。仿真时user_clk是由 IP 内部逻辑生成的但初始阶段可能还没稳定。你如果太早去采样user_clk相关信号仿真器可能给出 X 态。最稳的做法是等channel_up拉高后再驱动用户数据而且所有用户接口信号都要在user_clk的时钟沿上变化不要用#100这种延时去硬凑。在 testbench 里用(posedge user_clk)这种写法最安全。第三接收数据的比较。Example Design 自带的校验模块是frame_check它会检测接收到的数据是否和发送端发出的递增序列一致。如果你改了发送端的数据模式记得同步修改接收端的期望值。好多人在改业务逻辑时忘了改frame_check的期望值仿真报一大堆数据错误还以为是链路不稳定。4.3 回环模式和外环模式的仿真区别Aurora 8B/10B IP 支持多种回环方式最常用的是近端回环Near-End PMA Loopback和远端回环Far-End PMA Loopback。近端回环是在本地 GT 的 PMA 层直接把发送数据环回给接收端不经过物理走线远端回环则是在远端的 GT 接收端把数据环回给发送端通常用来测链路两端的收发通路。在仿真里近端回环非常有用因为你可以在一套 testbench 里只例化一个 Aurora IP把gt_loopback信号设为010PMA loopback 模式就能看到发送数据被接收端自己收回来验证 IP 内部数据通路是否正常。在仿真中设置回环的方式有两种一种是在 testbench 里直接初始化gt_loopback端口另一种是通过gt_rxrecclk等信号间接控制。更常见的是直接用gt_loopback端口在复位完成后拉高一段时间观察lane_up和channel_up是否拉高。如果你使用了两个 IP 做点对点仿真那就不需要回环直接把两个 IP 的 GT 串行端口接起来中间加一个延时模型模拟 PCB 走线。这里有个细节两个 IP 如果使用同一个 testbench要注意它们内部的时钟频率是否一致。如果两侧线速率相同只是相位不同通常没问题如果线速率不同仿真会直接出错现实中链路也起不来。虽然用的是行为仿真但 GT 的模拟模型对时钟的要求很严格。不要在 testbench 里用always #5 user_clk ~user_clk;这种粗糙的时钟生成方式最好直接用 IP 输出的user_clk来驱动用户逻辑。在 Verilog 里你可以例化一个 PLL 或者直接使用assign user_clk user_clk_tb;但要保证它和 IP 的user_clk同源同频同相。一个常见的做法是在 testbench 顶层用一个 100MHz 晶振模型做参考时钟源让两个设备和它同步。这个看似不起眼但对仿真收敛很有帮助。5. 常见问题与排查技巧实录5.1 链路起不来的排查顺序链路起不来的问题在实际调试中占了七成以上。我在现场调试时一般按下面的顺序来效率最高先看电源和时钟。GT 的供电引脚如果电压不对或者纹波偏大PLL 根本锁不定gt_reset_done都不会拉高。用示波器量一下板上 GT 的模拟电源确认电压值在手册范围内。然后看参考时钟用示波器或者频率计测量 MGTREFCLK 引脚上的时钟频率和幅度如果用的是差分时钟确认差分摆幅足够最好能看到干净的 100MHz 或 125MHz 波形。这两项没问题再往下查复位逻辑。再看gt_reset的时序。如果gt_reset拉低的时间不够长或者和reset的释放顺序不对GT 内部的校准可能不完整。我建议直接用 Example Design 的reset_logic模块不要自己做。而且要注意gt_reset拉低之后要等gt_reset_done拉高再释放reset。这个关系在仿真里看得很明显但在上板调试时容易被忽略。然后看lane_up。如果lane_up一直不拉高重点检查发送端和接收端的线速率是否一致、8B/10B 配置是否一致、参考时钟频率是否匹配。如果是近端回环测试还要确认回环模式设置是否正确。lane_up拉高了说明物理层已经没问题如果channel_up还是拉不高那多半是协议层的通道绑定没有完成检查对端是否也在跑同一个 Aurora 配置以及两个端口的通道数是否一致。如果所有信号都正常但channel_up仍然下降那要检查是不是user_clk出现了毛刺或者相位不稳定。可以在 Vivado 的 Hardware Manager 里看 JK 触发器采样到的channel_up如果它频繁翻转说明链路在初始化失败后不断重试。这时候用逻辑分析仪抓lane_up和channel_up之间的关系能很快定位问题边界。5.2 数据误码的排查方向链路起来了但传数据偶尔出错这种问题也极其常见。第一步不要怀疑上层逻辑先做一个简单的回环测试把发送端的固定递增序列直接发出去接收端校验收到的序列是否一致。如果回环测试通过说明 GT 物理链路没有问题问题在上层数据通路或跨时钟域处理。如果回环测试就出错那就是物理层的问题重点查信号完整性和时钟质量。信号完整性方面常见的原因是 PCB 走线过长、换层过多、连接器接触不良。这些用眼图测试最直观。如果你的板子上有 IBERT IP 的资源强烈建议用 IBERT 直接对 GT 链路做压力测试。IBERT 基于 FPGA 内部的 PRBS 发生器能够在没有业务逻辑的情况下直接测误码率还可以调节 RX 均衡参数、TX 预加重参数帮助你把链路裕量调到最佳。Aurora 8B/10B IP 的gt_loopback只是基本回环而 IBERT 是专门的链路测试工具一定要学会用。另一个经常被忽略的点是参考时钟的抖动。Aurora 8B/10B 对参考时钟的抖动有明确要求比如总的周期抖动要在一定范围内。如果参考时钟来自普通 PLL 或 MMCM抖动可能超标。所以我在高速项目里坚持用专用的差分晶振或低抖动时钟芯片给 GT 提供参考时钟而不是复用 FPGA 内部逻辑产生的时钟。5.3 多通道绑定和跨板互联的坑Aurora 8B/10B 支持多通道绑定Channel Bonding即把多个 GT lane 合并成一个更高吞吐的逻辑通道。配置的时候要指定通道数比如 2 通道、4 通道。多通道模式下接收端会通过通道绑定序列把多条 lane 的边界对齐确保并行数据到达用户接口时是完整的。这里最常见的问题是两个端口的通道数不一致或者通道绑定序列被干扰导致绑定失败。还有一个非常现实的坑多板互联时两个 FPGA 的参考时钟源不同步。Aurora 8B/10B 支持异步时钟模式也就是两端使用各自的参考时钟只要频率在容差范围内协议会通过时钟修正序列来吸收频率偏差。这个特性让板间互联变得很灵活但代价是会增加一些额外的开销。同步时钟模式则要求两端的参考时钟同源吞吐效率更高但硬件上要实现时钟同步。设计时一定要搞清楚你的板子到底是同步还是异步时钟然后在 IP 配置里选对模式否则链路即使起来长期运行也会因为频率漂移导致误码。多通道绑定还有一个隐藏问题绑定后的用户接口数据宽度会成倍增加比如单通道 32-bit双通道就是 64-bit。此时user_clk的频率不变但每拍的数据量翻倍。对上层 FIFO 的设计来说位宽变化不是问题真正要注意的是字节顺序。Aurora IP 保证了通道绑定后数据的字节序正确但不同版本、不同配置下字节顺序可能不同。我有一次就是因为接收端的字节序没处理对数据看起来对但每个 32-bit 字内部高低字节是反的排查了很久才发现是两个设备的端序不一致。5.4 常见问题速查表问题现象可能原因排查思路gt_reset_done不拉高GT 电源不稳、参考时钟没给上、gt_reset释放太早量电源、量参考时钟、检查复位时序lane_up不拉高线速率不匹配、8B/10B 同步失败、回环配置错误确认两端参数一致检查近端回环模式lane_up拉高但channel_up不拉高通道绑定失败、对端未初始化、通道数不一致检查通道绑定序列和对端状态用户接口不握手user_clk没稳定、channel_up没拉高就发数据等channel_up拉高后再驱动数据回环测试误码信号完整性差、参考时钟抖动超标用 IBERT 测误码率调 RX 均衡数据字节序不对两端器件端序不一致做字节交换处理重新核对接线顺序这个表格是我在项目里沉淀下来的打印出来贴在工位上很管用。如果你自己遇到的问题不在表里也别急按“先物理层再协议层最后应用层”的思路逐层排查绝大多数问题都能定位。6. 从仿真到上板一些更实用的工程建议6.1 别急着上板先在仿真里把链路验证透我见过不少开发人员一拿到板子就急着把 Aurora IP 接上自己的逻辑然后烧进去发现链路起不来就开始对着板子量波形。其实很多问题在仿真阶段就能暴露出来。Aurora 8B/10B 的行为仿真模型非常成熟GT 模拟逻辑和真实硬件的初始化序列几乎一致所以在仿真里如果channel_up能拉高至少说明你的 IP 配置、复位时序、用户接口握手逻辑没有明显错误。上板之后再出问题排查范围会小很多。做仿真验证时我习惯跑三个用例第一个是纯回环测试验证 IP 内部的数据通路第二个是两个 IP 直连的测试验证点对点链路第三个是加入业务数据的测试验证用户逻辑和 Aurora 接口的握手是否正常。这三个用例全部通过后再上板测试基本不会出现“链路起不来”这种低级问题。6.2 时序约束和跨时钟域处理Aurora 8B/10B 的时钟域关系比较复杂。GT 内部的并行时钟和用户接口的user_clk之间是异步关系IP 内部已经做了 CDC 处理。但用户逻辑自己跨时钟域的时候要特别小心。比如你的业务时钟可能是 200MHz而user_clk是 125MHz那在把数据交给 Aurora 发送之前必须先经过一个异步 FIFO 做跨时钟域转换。很多人在这里直接用寄存器打两拍的方式处理结果数据从 200MHz 域跨到 125MHz 域时出现数据丢失。我比较推荐的做法是在用户逻辑和 Aurora 之间加一个独立的异步 FIFO IP。发送方向业务模块把数据写入 FIFOAurora 的发送接口从 FIFO 读数据接收方向反过来。这样既解决了跨时钟域问题又能在数据拥塞时提供缓冲。FIFO 的深度取决于你的业务突发长度一般 512 或 1024 足够。如果数据流是连续不间断的那还要考虑背压逻辑比如当 FIFO 水位超过阈值时暂停上游数据发送。6.3 用 ILA 抓内部信号的技巧上板调试时Vivado 的 ILA集成逻辑分析仪是利器。但 ILA 有个限制它只能看用户时钟域的信号看不了 GT 内部的高速信号。所以调试时你应该关注的是channel_up、lane_up、s_axi_tx_tvalid/tready、m_axi_rx_tvalid/tdata这些信号。把这些信号挂到 ILA 上触发条件设为channel_up的下降沿就能抓到链路掉线前一刻发生了什么。另一个有价值的触发点是s_axi_tx_tvalid !s_axi_tx_tready说明发送端遇到了背压可能是对端接收没准备好也可能是链路本身带宽不够。ILA 采样深度不用太大1024 或 2048 足够。关键是触发条件要选对。如果链路稳定运行几百秒才出一次错抓取的难度会很大这时候可以考虑利用 Aurora 的err_count相关信号或者自己在用户逻辑里做一个 CRC 校验出错了就标记并报警。总之不要把 ILA 当示波器用它是用来定位逻辑层时序的物理层问题还是交给 IBERT 和示波器。6.4 与上层协议配合的常见模式Aurora 8B/10B 本身是透明传输不关心数据内容所以它可以作为很多协议的底层承载。最常见的两种配合是一是和 DMA 引擎配合实现 FPGA 和 CPU 之间的高速数据交互二是作为厂商私有协议的物理层比如把自定义的控制字和数据包封装成 Aurora 帧。无论哪种方式都需要在用户逻辑里做封包和解包的处理。这里有一个通用建议在用户数据前面加一个头部字段里面包含数据长度、类型、序列号这样接收端可以快速判断链路是否出现了丢包或错序。不要依赖 Aurora 本身的流控来保证业务的可靠传输它的核心能力是高速传输不是可靠传输业务层的重传机制还得自己设计。如果你把 Aurora 链路做成背板总线连接多个 FPGA 甚至多个板卡那还要考虑多节点时隙分配和总线仲裁这些已经属于上层总线协议的范畴。Aurora 提供一个可靠的物理通道但协议细节一定要在上层解决否则你的系统在单链路测试时正常多节点组网时就会问题不断。7. 最后的经验分享如果非要说一条最想告诉后来者的话那一定是Aurora 8B/10B 看起来简单但一定要把手册里的时钟、复位、握手三件事吃透再动手。我见过太多人因为懒得看时序图直接复制网上的代码结果链路起不来或者数据错乱然后开始怀疑 IP 核有 bug。其实 Xilinx 官方 IP 经过大量验证绝大多数情况下问题都出在配置或使用方式上。仿真阶段多看时序波形上板之后多用 IBERT 和 ILA 定位能少走很多弯路。最后再分享一个小技巧如果你在调试中实在查不出问题可以尝试把线速率降一档重新生成 IP比如从 5.0 Gb/s 降到 3.125 Gb/s再跑一遍链路。这个方法不是治本但能帮你快速区分问题到底出在物理链路的信号完整性还是协议层的配置逻辑。跑通了再加回速率逐步逼近问题边界。搞高速链路调试稳扎稳打永远比瞎试快。
返回列表