ARTICLE DETAIL

资讯详情

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

FPGA高速互联实战:Aurora 8B/10B协议解析与调试指南

FPGA高速互联实战:Aurora 8B/10B协议解析与调试指南 1. 为什么在高速串行方案里选了Aurora 8B/10B1.1 横向对比了PCIe、SRIO和自己撸原语之后做FPGA之间的高速数据互联可选的技术路线不少。我之前接触过直接调GTX原语的项目也评估过PCIe和SRIO最后在一个ADC采集板到FPGA处理板的数据搬运项目里把方案定成了Aurora 8B/10B。这个决策过程本身就有参考价值。直接撸GTX/GTH原语这条路适合极少数有充足时间和憋大招的团队。8B/10B编解码、逗号对齐、通道绑定、时钟补偿、误码检测这些功能全部从零写光是把握手和初始化状态机调明白就够耗掉一两个月。中间任何一个细节没处理对实际跑起来就是数据偶发错乱定位极其痛苦。PCIe的问题在于重。对“点对点把数据从一块板子搬到另一块板子”这种需求PCIe的事务层、配置空间、BAR映射、地址路由基本都是多余负载。初始化枚举、链路训练那一套下来业务数据还没影工程复杂度先上去了。SRIO虽然常用于DSP和FPGA互连但它的逻辑层包格式、维护事务、错误恢复机制都需要额外适配也不是开箱即用。Aurora 8B/10B恰好踩在需求和复杂度中间的那个点上。Xilinx把链路训练、通道对齐、时钟补偿这些脏活全部收进IP核对外暴露AXI4-Stream接口。我只需要关心数据怎么塞进去、怎么拿出来剩下的都由IP处理。它不支持多节点组网也不带重传机制但点对点、短距离、重视开发效率的场景这套协议天生合适。1.2 8B/10B编码的边界感8B/10B编码的核心作用一句话讲清楚把每个字节编码成10bit换来自流平衡和足够多的跳变沿。自流平衡保证了经过AC耦合电容后信号直流电平不会漂移跳变沿足够多是接收端CDR能恢复出时钟的前提。这两点对高速串行通信都是硬要求所以这个方案虽然牺牲了20%带宽但换来了稳定。选Aurora 8B/10B之前先算一笔账。线速率6.6Gbps扣除8B/10B的20%开销后有效吞吐约5.28Gbps再减去IP核插入的帧间隙、控制字符等开销真实可用吞吐大概是线速率的55%到60%。所以业务带宽接近线速率一半时就要当心够不够用。如果需求超过这个比例干脆把线速率往上提或者考虑Aurora 64B/66B那个协议的开销只有3%左右。8B/10B版本最适合的物理场景是板内芯片间、背板短距离、以及几米内的同轴线或光纤链路。线速率通常控制在3.125Gbps到10Gbps6.6Gbps以下最舒服。跨机柜、长距离光模块互连的场景Aurora 64B/66B优先级更高虽然它的IP配置复杂一点但带宽利用率和距离性能都好不少。2. 配置IP核之前先搞清楚这几个参数打开Vivado的IP定制界面之前有几个参数如果没想清楚后面改起来全是返工。我踩过这个坑所以建议按下面这个顺序先规划好。2.1 线速率、参考时钟、用户时钟之间的换算关系Line Rate是物理线速率GT Reference Clock是高速收发器的参考时钟User Clock是用户逻辑的工作时钟三者不是独立变量而是通过GT内部的PLL和内部数据宽度绑在一起的。用户时钟频率的计算公式很直接用户时钟频率 线速率 / (用户接口宽度(字节) × 10)例如6.6Gbps线速率、4字节接口用户时钟 6.6G / 40 165MHz。若是8字节接口则用户时钟 6.6G / 80 82.5MHz。这个时钟在Aurora IP里的名字叫user_clk所有用户侧AXI4-Stream信号都跑在这个时钟域上。参考时钟和线速率的约束更隐蔽。GT内部的CPLL/QPLL会把参考时钟倍频到VCO工作频率再分频得到线速率。也就是说参考时钟必须能通过PLL的整数倍频/分频关系生成目标线速率Vivado的IP配置界面会做合法性校验不匹配直接报错。实际工程里常用的组合有这些线速率用户接口宽度用户时钟参考时钟示例常见器件3.125Gbps4字节78.125MHz125MHz7系列GTX5Gbps4字节125MHz125MHz7系列GTX6.6Gbps4字节165MHz125MHz7系列GTX / UltraScale10Gbps8字节125MHz156.25MHzUltraScale选择线速率时我习惯留20%到30%的余量。明明业务8Gbps就够不要为了追求纸面性能硬上12.5Gbps板级信号质量、连接器损耗、电源噪声都是现实约束跑分爽快的配置到了硬件上未必稳定。2.2 用户接口选4字节还是8字节Aurora 8B/10B的用户数据接口有32bit和64bit两种宽度。选择标准不只是看习惯而要看后级逻辑的主频和位宽。如果数据处理逻辑在150MHz到200MHz之间工作得很舒服4字节接口足够。如果后续还想把逻辑时钟压到100MHz以内或者后级对接的是128bit的DMA总线那8字节接口更合适内部走线更宽跨时钟域FIFO深度也能相应减少。还要考虑一个工程细节接口宽度会影响你写数据控制逻辑的粒度。4字节接口下一个时钟传4字节tlast指示帧尾时需要精确到字节数8字节接口下一个时钟传8字节逻辑上要处理的字节使能信号更多。这些不会影响Aurora本身功能但会影响你自己状态机的复杂度。2.3 流控NFC、UFC还是干脆不选Aurora的流控分Native Flow ControlNFC和User Flow ControlUFC。NFC是协议内部的流控机制接收端缓存压力大时回传NFC消息发送端收到后暂停发送。UFC则是用户可以自定义的高优先级控制消息可以插在正常数据流里传输。我的建议很实际如果只是普通数据搬运接收端FIFO深度设计得足够大就不要选流控。少一层逻辑仿真和调试都省不少事。如果接收端消费速率确实不稳定选NFC它能自动控制发送端暂停代价是多了几个流控信号和额外的latency。如果需要在数据链路上插入带外控制消息再考虑UFC。选了流控后用户接口上会多出对应信号IP内部的数据调度策略也会变。调试时链路吞吐和延迟表现都不一样不要拿没选流控的经验去硬套容易分析错问题。2.4 共享逻辑独立GT还是共享GT Common这个选项叫GT Shared Logic有Independent GT和Shared Logic两种模式。GT的参考时钟和QPLL资源在Xilinx的高速收发器bank里是共享资源同一个bank里的多个GT可以共用。如果项目里同时规划了多路Aurora或者Aurora和PCIe在同一个GT bank建议把共享逻辑单独拉出来放在一个主核里其他核用Shared Logic模式引用它。配置少、GT资源不复杂的情况下Independent GT最省心。毕竟每个核管好自己的参考时钟和复位就行不用处理跨核的依赖关系。项目资源规划复杂时Shared Logic能省下QPLL和时钟资源但复位顺序、时钟分配都要统一设计否则多个核之间的链路会互相干扰。这个选项直接影响硬件管理方式值得在画原理图阶段就和硬件工程师对齐。3. 在Vivado里逐项配置Aurora 8B/10B IP核的完整记录3.1 新建IP和板级预设在Vivado的IP Catalog里搜索Aurora双击Aurora 8B/10B进入配置界面。组件名尽量用有业务含义的前缀比如aurora_adc_link、aurora_dsp_link不要用默认的aurora_8b10b_0。项目里同时挂着四五套Aurora链路时靠默认名管理完全是灾难。如果用的是开发板板级预设Board下拉框里选对应板卡会自动带入SFP或SMA对应的引脚约束。自己做板子就选CustomGT参考时钟引脚、用户时钟来源、复位按键引脚都放在自己的约束文件里维护。要注意的是GT参考时钟必须落在目标GT所在bank的MGTREFCLK引脚上这个位置关系在IP配置界面里不会提示只能靠设计者对照原理图确认。3.2 数据流模式和接口模式的取舍Dataflow Options有Duplex、TX Only、RX Only三个选项。Duplex是全双工TX Only/RX Only会省掉一半GT收发器资源。需要注意的是使用单工模式时IP内部仍然需要一定交互来实现链路训练不是砍掉一个方向就减少一半协议逻辑。如果项目里两块板子确实只需要单向传输用单工能省资源但省得有限开发成本反而可能增加。Interface Mode是Framing和Streaming二选一。我项目里统一用Framing因为接收端需要识别一次传输的边界。Framing模式下用户通过tlast信号指示帧结束IP会在帧头帧尾插入协议规定的控制字符Streaming模式则没有帧边界概念数据像水流一样持续传输适合视频流这类无包结构的数据。对绝大多数数据通信场景Framing更可控调试时也有明确的帧边界可以抓。3.3 共享逻辑和example design的生成共享逻辑选项按前面说的原则选。选完后配置界面还会要求确认一些GT覆写属性GT Attributes Overrides例如TX输出幅度差动电压、预加重、RX均衡参数等。默认值可以跑通但如果你的链路比较长或者信号质量差这些参数是后续调板的关键。IBERT扫出来的最优参数可以通过这里的Override方式填进Aurora IP。配置完成后记得勾选“Generate Example Design”。example design里包含了完整的参考工程IP例化、frame_gen数据生成模块、frame_check数据校验模块、GT参考时钟模块、复位逻辑还有一个现成的testbench。这是白给的一套验证环境后续仿真和上板验证都从它开始比自己从头写省太多时间。3.4 配置界面里几个容易翻车的小选项GT DRP Clock是一个低频稳定时钟用于驱动GT动态重配置端口一般选50MHz或100MHz。这个时钟必须真实存在悬空或接错地方会导致GT DRP操作失败严重时链路完全无法启动。还有一个我自己踩过的坑生成IP之后去手工修改.xci文件里的参数。有些参数表面改了IP核内部HDL没有同步更新出现的错误极其诡异编不过或者仿真行为异常都有可能。IP核的一切修改都要通过Vivado图形界面完成不要为了省事直接改配置文件。4. 复位、时钟和power_down链路能不能起来的胜负手4.1 gt_reset、reset、power_down各自的分工Aurora IP顶层常见三个名字相似的信号gt_reset、reset、power_down。它们的作用完全不同经常有人搞混。gt_reset复位的是GT收发器物理层包括PLL、TX/RX数据通路。释放gt_reset后GT内部要经历PLL锁定、Reset状态机完成等过程参考时钟在此之前必须已经稳定。reset复位的是Aurora核内的链路层逻辑包括初始化状态机、通道绑定、弹性缓冲、用户FIFO。它必须在gt_reset释放并且GT已经稳定之后才能释放顺序反了链路初始化状态机就可能进不了正确状态。power_down是GT的电源关断控制正常工作必须置为无效电平。有的设计误以为这跟reset一样或者在顶层悬空结果GT模型在仿真里默认拉高导致链路始终不起来。不用的power_down端口在IP配置里直接固定拉低别留在外面裸奔。下面是工程里实测可靠的一种复位时序描述上电后等待参考时钟稳定如果参考时钟来自可编程振荡器等待其LOCKED信号释放gt_reset等待gt_txresetdone和gt_rxresetdone拉高再等至少100个用户时钟周期释放reset最后观察channel_up拉高。这个流程适合用一个状态机实现不建议用延迟计数器硬凑因为上电时序里参考时钟稳定时间不可控延迟计数容易估算不足。复位状态机的简化Verilog结构可以这样写localparam S_IDLE 3d0; localparam S_GT_RESET 3d1; localparam S_WAIT_GT 3d2; localparam S_WAIT_USER 3d3; localparam S_RUN 3d4; always (posedge init_clk or posedge system_reset) begin if (system_reset) begin state S_IDLE; gt_reset 1b1; aurora_reset 1b1; end else begin case (state) S_IDLE: begin gt_reset 1b1; aurora_reset 1b1; if (refclk_locked) state S_GT_RESET; end S_GT_RESET: begin gt_reset 1b0; // 释放GT复位 state S_WAIT_GT; end S_WAIT_GT: begin if (gt_txresetdone gt_rxresetdone) state S_WAIT_USER; end S_WAIT_USER: begin aurora_reset 1b0; // 释放Aurora复位 state S_RUN; end S_RUN: begin // 正常工作 end endcase end end注意多lane场景下gt_txresetdone和gt_rxresetdone不一定同时拉高需要把所有lane的done信号AND在一起全部就绪才能进入下一步。example design里已经处理好了这些细节第一次做建议直接抄。4.2 example design里的复位逻辑值得抄我见过有人在板级调试时把gt_reset和reset接在同一个按键上结果链路时好时坏十次只能起来三次。问题表述像是“Aurora不稳定”实际却是复位顺序根本不对。Aurora example design里有一套完整的复位处理它把外部上电复位、GT Reset Done、IP复位、用户逻辑复位全部串成一个有序链。我不建议自己重新发明一套“更顺手”的逻辑至少首次设计时照着example的哲学来先物理层、再链路层、最后用户逻辑逐级释放。4.3 用户时钟、tx_out_clk和init_clk的来龙去脉Aurora IP的user_clk输出是用户逻辑的工作时钟频率就是之前算出的线速率除以接口宽度再除以10。在example design中这个时钟通常由GT的txoutclk经过MMCM/PLL生成所以不是GT输出的原始时钟而是经过频率变换后的稳定时钟。用户接口所有AXI4-Stream信号包括tdata、tvalid、tready、tlast全部工作在user_clk域。外部逻辑如果要操作Aurora用户接口必须用user_clk做同步如果外部逻辑运行在别的时钟域中间必须加异步FIFO。这里没有捷径跨时钟域处理不彻底高速跑起来偶发数据错乱查得头大。init_clk是用于IP初始化和DRP的低频时钟一般50MHz到100MHz即可在example design里通常由一个独立时钟模块产生。init_clk不需要和user_clk同频同相但要保证稳定。5. 从example design开始仿真实战5.1 先跑通现成的example design仿真Aurora 8B/10B的example design会自动创建一套仿真环境。直接点Run Simulation跑几十微秒就能看到完整的建链过程一开始gt_reset和reset都处于有效状态随后gt_reset释放过几个微秒gt_txresetdone、gt_rxresetdone拉高再往后channel_up拉高frame_gen开始向Aurora发送数据帧frame_check持续校验。第一次仿真建议把时长设到100us观察完整的链路建立和数据传输过程。如果仿真里frame_check模块报错先怀疑example design是不是被改过尽量保持默认跑通再迁移自己的设计。Aurora IP在仿真时用的是GT仿真模型不需要额外安装仿真库xsim会通过Vivado的IP编译流程自动加载。5.2 自己写testbench时最容易踩的复位深坑实际项目里不能一直用example design的testbench最终要为自己的顶层模块写独立tb。Aurora的仿真模型在xsim里正常例化就能用但testbench里复位时长不够是高频翻车点。GT仿真模型的PLL锁定和复位状态机需要一段模拟时间不同线速率下这个时间不一样。我写过的最小安全复位时间是gt_reset保持至少2us后再释放保险起见我一般拉高5us。释放后必须等待gt_txresetdone和gt_rxresetdone都拉高再释放Aurora核的reset。这和上板时序完全一致只在时间尺度上有区别。还有一点容易被忽略第二次、第三次复位测试时时序必须和第一次完全一样。如果第二次复位后链路起不来通常不是Aurora的问题而是自己测试逻辑里有些异步状态没复位干净或者FIFO里还残留旧数据。5.3 链路起不来的仿真排查链路仿真里channel_up一直拉不高别急着怀疑IP破坏按顺序查这几个位置gt_reset是否已经释放释放后gt_txresetdone是否拉高参考时钟是否真实存在。有些tb忘记激励gt_refclk或init_clkGT内部PLL不锁定后面全白搭power_down是否为无效电平。仿真模型里这个信号悬空可能默认拉高导致GT不工作reset是否在GT完成复位后才释放链路层复位抢跑会导致初始化状态机失败多lane场景下确认每条lane的tx/rxresetdone都拉高再查通道绑定状态。排查时把gt_refclk、gt_reset、gt_txresetdone、gt_rxresetdone、reset、channel_up、lane_up全部拉进波形窗口一屏看完时序关系基本一眼就能定位是复位顺序问题还是时钟缺失问题。5.4 仿真里把CRC校验加上才算真正验证example design里的frame_gen和frame_check只是自发自收示例实际业务肯定有自己特定的数据格式。为了保证用户逻辑侧没有接错可以在发送端对发送数据算CRC32接收端对收到的数据重算并比对。这一步在仿真里做一次能提前过滤掉大批AXI4-Stream接口错位的低级错误。Aurora IP对用户数据内容是完全透明的它不在帧内插入CRC也不校验用户数据正确性所以CRC逻辑必须自己做。仿真里验证通过后这个CRC逻辑可以继续保留到上板阶段做长时间误码统计一举两得。6. 上板调试仿真发现不了的现实问题6.1 先跑IBERT把GT物理层验明白再谈Aurora上板调试Aurora之前强烈建议先跑一遍Vivado自带的IBERTIntegrated Bit Error Ratio Tester。IBERT的作用是直接测试GT通道的物理层质量包括眼图、误码率、信号幅度还可以现场调整TX swing、预加重、RX均衡等参数。如果IBERT在目标线速率下眼图都收敛不了比如眼高不足、眼宽不够那Aurora配得再好也白搭问题在物理层。IBERT里找到一组能跑通的GT参数后把这组参数记下来回到Aurora IP的GT Attributes Override里重新填进去。很多板子IBERT能过、Aurora起不来不是Aurora的问题而是IBERT里改过的GT参数根本没同步到Aurora工程里。6.2 channel_up起不来的上板排查上板和仿真不同没有理想的零延迟波形所有信号都要用ILA实测。channel_up拉不高的排查我从参考时钟开始。用ILA抓gt_refclk确认时钟真的来了、频率正确、波形干净。很多板子的GT参考时钟来自可编程振荡器这类器件如果初始化配置不对输出可能根本没有。ILA抓一次就露馅。接着查复位时序。上板环境里gt_reset和reset可能来自按键、上电复位芯片或软复位寄存器时序关系比仿真复杂。ILA里同时抓gt_reset、gt_txresetdone、gt_rxresetdone、reset、channel_up五个信号一次触发看完整条时序链。如果gt_txresetdone一直不来查GT参考时钟和GT供电MGTAVCC、MGTAVTT这两个电源有问题GT会一直卡在复位状态。还有两个容易被忽略的问题。一个是SMA线缆接头的极性母头公头要配对有的转接头质量差高速信号断断续续channel_up一会儿有一会儿没。另一个是TXP/TXN极性接反如果你板上的走线或连接器导致极性反了Aurora链路也会无法建链。Xilinx的GT属性里有极性翻转选项确认硬件后可以在IP配置里直接设好不用改板子。6.3 误码和眼图信号质量排查思路链路起来之后长时间跑误码测试如果误码率偏高先看物理介质。SMA线材超过1米6.6Gbps信号衰减就非常明显。我实测过一种普通SMA线1.5米长跑到5Gbps眼图已经接近关闭把线速率降到3.125Gbps才恢复余量。所以高速板间互联的线缆和连接器要按信号的速率来选别拿手头最短的线凑合。再看电源纹波。GT的供电对纹波很敏感如果板上有个开关电源恰好靠近MGT bankAurora跑高速大概率偶发误码。排查时可以同时用示波器量MGTAVCC纹波用ILA统计误码计数。有些板子在FPGA电源附近加了LC滤波后误码立刻下降一个数量级这就是电源主导的典型特征。GT内部还有一堆可调参数比如TX差动电压幅度、预加重强度、RX均衡模式LPM/DFE。链路长了或者介质质量一般DFE通常比LPM抗干扰。具体参数值没有通用最优解用IBERT现场扫扫到满意值后同步回Aurora配置。调这类参数时每次只改一个变量改完跑几分钟BER再决定下一步多变量同时调容易把结论搞乱。6.4 版本迁移和IP升级的教训Aurora IP核在不同Vivado版本之间有差异。同一个.xci文件在高版本Vivado里重新生成后底层网表可能变化引脚、时钟、复位端口都可能多出或改名。尤其是大版本跳跃比如从Vivado 2019.1升级到2023.x建议把Aurora IP整个重新配置、重新生成example design再对照差异修改自己的设计。网上还能翻到不少老教程比如Xilinx SDK 2015.4时代的工程那些工程在旧版本上能跑拿新版本环境编译经常过不了。不是你的代码有问题是工具链变了。遇到这种情况不要浪费时间硬改老工程直接用新版Vivado基于当前IP版本重新搭建工程框架把业务逻辑迁移过来这样反而更快。在多个项目里反复用过Aurora 8B/10B之后我的体会是这个IP核的坑大部分都在IP核外部配置界面只要参数算对链路基本能起来真正的坑在复位时序、时钟域处理、GT物理参数和板级信号完整性上。多花时间把example design读懂跑通改透比自己去翻几百页手册高效得多。最后分享一个小技巧上板调试时把自己顶层模块里所有和Aurora用户接口相关的信号都做成ILA探针一旦链路状态或数据异常抓一次波形基本就能定位到是发送侧还是接收侧的问题省去的排查时间非常可观。
返回列表