
前阵子调一块板卡两块FPGA之间要传一路视频流再带一路寄存器读写控制加起来大概3.2Gbps。一开始想走LVDS并行总线算了下差分对要三十多对PCB布线直接头大换PCIe的话又觉得杀鸡用牛刀光是枚举和驱动就够折腾。后来在Vivado的IP Catalog里翻到Chip2Chip这个核才意识到这就是干这活的合适人选。从配置到仿真再到上板前后花了一周链路终于稳定跑起来。这篇文章就把Chip2Chip IP核基于Aurora PHY的通信配置过程、仿真验证方法和我踩过的坑完整记下来给准备用高速串行链路做板间互联的朋友一个参考。1. 为什么需要Chip2Chip高速板间互联方案怎么选1.1 LVDS、PCIe、Aurora和Chip2Chip的定位区别板间高速互联的常规选择无非这么几种并行LVDS、PCIe、Aurora协议以及这里要重点说的Chip2Chip IP核。它们之间不是简单的“谁替代谁”而是适用场景差别很大。方案典型带宽资源开销复杂度适用场景LVDS并行总线几百Mbps到2Gbps大量IO引脚低短距离、低速率、带宽要求不高PCIe单通道2.5Gbps起硬核或PCIe IP DMA逻辑高主机与FPGA、系统级复杂互联Aurora 8B/10B从1Gbps到10Gbps以上GT Aurora IP 用户逻辑中任意两点间的高速流式传输Chip2Chip和Aurora一致GT Chip2Chip IP中低两块FPGA之间点对点数据传输和寄存器访问PCIe最大的问题不是性能而是“重”。一旦用了PCIe就得考虑链路训练、BAR空间映射、DMA引擎、驱动适配如果只是两块FPGA之间互相传数据这些全是额外负担。而直接用Aurora 8B/10B IP核功能很强但需要自己处理初始化时序、流控、错误恢复等一大堆协议细节对于只要“把数据从A点搬到B点”的场景来说学习成本略高。Chip2Chip本质上是在Aurora 8B/10B物理层之上包了一层简化协议把很多底层细节藏了起来用户看到的基本上是AXI-Stream或AXI接口。它的优势在于不需要写复杂的Aurora协议状态机配置完IP核后直接读写数据即可。同时它还支持远程寄存器访问这对需要跨板卡读写控制寄存器的场景特别实用。1.2 什么场景用Chip2Chip最划算根据我的实际使用体会以下场景优先考虑Chip2Chip两块FPGA之间需要稳定跑2Gbps以上的数据流比如视频流、高速ADC采样数据、雷达中频数据。需要跨板卡访问另一端的寄存器或存储空间希望像访问本地地址一样操作远端。不想自己维护Aurora协议的初始化、复位、错误处理逻辑。希望链路有相对确定的延迟而非类似以太网那样的不确定性转发。工程周期紧需要快速把物理层跑通把精力集中在业务逻辑上。反过来如果需要连接FPGA和主机CPU或者需要组网能力那还是老老实实用PCIe或EthernetChip2Chip只适合点对点场景这一点必须在方案定型前想清楚。2. 动手配置前先算好参数时钟、位宽和GT资源2.1 线速率与GT参考时钟频率的匹配关系Chip2Chip的物理层是GT收发器GT内部靠QPLL或CPLL将参考时钟倍频到串行线速率。所以线速率和参考时钟频率之间必须满足一个倍频关系不是随便组合都能用的。参考时钟频率、线速率和GT内部倍频系数的关系可以简单理解为线速率 参考时钟频率 × GT倍频系数举个例子如果线速率选2.5Gbps参考时钟用125MHz那么GT倍频系数就是20这在GT的合法配置范围内。如果线速率是3.125Gbps参考时钟同样给125MHz倍频系数就是25也常见。再比如5Gbps线速率搭配156.25MHz参考时钟倍频系数是32。配置IP核时Vivado会自动校验参考时钟频率和线速率是否匹配。如果匹配不上界面会直接报错或者在生成时弹警告。这里最容易踩的坑是自己想当然地给一个参考时钟觉得“FPGA内部PLL总能搞定”实际上GT的PLL是有分频系数范围限制的不同FPGA器件、不同GT类型的限制还不一样。我的建议是先定线速率再查器件手册或参考Vivado下拉列表里能选的参考时钟频率不要反推。Vivado的Chip2Chip配置界面里参考时钟那栏会列出该线速率下支持的合法频率选一个离自己板卡时钟树最近的值后面硬件设计会省很多事。2.2 用户时钟频率与数据位宽怎么算Chip2Chip的用户接口支持2字节和4字节两种数据位宽用户时钟频率直接取决于线速率和位宽计算公式如下用户时钟频率 线速率 / (10 × 数据位宽字节数)这里除以10是因为Aurora 8B/10B编码把每字节扩成了10bit传输。举个例子线速率2.5Gbps、数据位宽2字节用户时钟 2.5G / (10 × 2) 125MHz。线速率3.125Gbps、数据位宽2字节用户时钟 3.125G / 20 156.25MHz。线速率6.6Gbps、数据位宽4字节用户时钟 6.6G / 40 165MHz。这个结果一定要在IP配置之前算清楚因为它决定了工程里用户逻辑的时钟域。实际项目中很多第一次用Chip2Chip的人会在这一步犯迷糊尤其是选了4字节位宽后以为用户时钟还是和线速率差不多快结果后面跨时钟域处理全乱了。另外要注意虽然数据位宽增大后用户时钟频率会降低但GT通道占用数也会变化。2字节位宽对应1个GT通道4字节位宽对应2个GT通道这一点下面细说。2.3 Chip2Chip占用几个GT通道BANK怎么放Chip2Chip不像Aurora那样配置多条lane扩展它的通道数基本由数据位宽决定。2字节位宽单通道即可跑通4字节位宽需要2条GT通道两路并行分摊数据用户侧看到的就是更高带宽的并行接口。通道数确定后还要考虑GT在FPGA物理位置上的约束。GT收发器是按Quad组织的每个Quad包含4个GT通道。单通道Chip2Chip随便放双通道就尽量放在同一个Quad里这样QPLL资源可以共用时序也更容易收敛。如果板卡上有多个GT参考时钟输入务必让Chip2Chip使用的GT通道和参考时钟在同一个Quad或相邻Quad。有些FPGA里GT参考时钟的布线是有限制的跨太远会导致参考时钟无法布线或者在实现阶段出现严重的时序问题。这个坑在原理图设计阶段就要避掉等PCB做回来再发现就麻烦了。3. Chip2Chip IP核核心配置实操3.1 生成主从两个IP实例角色别选错Chip2Chip是成对使用的IP通信双方一端为主Primary另一端为从Secondary。配置时需要在Vivado IP Catalog里搜索chip2chip然后分别生成两个IP实例一个选Primary一个选Secondary。这里有个很容易忽略的细节两个实例虽然在配置界面上选项很多但协议类型、线速率、数据位宽必须完全一致否则物理层链路协商不起来。角色不同只影响初始化时的握手顺序和部分控制信号极性不影响数据面格式。接口类型按需选择。典型用法是数据通道用AXI4-Stream控制寄存器用AXI4-Lite。如果只想传流式数据AXI4-Stream就够了配置也最简单如果还需要跨板卡读写寄存器就再加上AXI4-Lite接口。两个接口可以同时存在于一个Chip2Chip IP核里只是会多占一些内部资源。生成完IP后建议先在IP Sources里打开Example Design把它作为学习参考。Example Design里包含完整的初始化模块、时钟模块和收发数据验证模块比对着用户手册硬啃高效得多。我一般习惯直接基于Example Design改而不是从空工程开始。3.2 协议层选项Aurora 8B/10B PHY、流控和CRCChip2Chip配置界面里物理层协议可以选择Aurora 8B/10B PHY或简化物理层不使用Aurora协议。如果只要两个Chip2Chip互相通信用哪种都能跑通。但考虑到可观测性和通用性我推荐选Aurora 8B/10B PHY原因有三个链路初始化、字节对齐、通道绑定这些底层操作由Aurora PHY的状态机管理稳定可靠。调试时可以直接参考Aurora的lane_up和channel_up信号判断物理层状态。如果以后需要改成和其他Aurora设备互通至少物理层是一致的。流控建议根据业务需求决定。如果两端的数据发送速率是固定的且接收端FIFO深度足够可以不开启流控简化逻辑。如果存在突发流量建议开启Native Flow Control这样接收端FIFO快满时能通知对端暂停发送避免丢数据。CRC校验属于可靠性增强选项。开启后Chip2Chip会在每个数据包尾部附加校验值接收端检测错误后可以上报。对于需要高可靠传输的场景我建议开启代价是有效带宽略降但对于大多数Gbps级别的应用来说可以接受。3.3 复位与初始化逻辑千万别填错Chip2Chip的初始化过程并不是上电后自己就乖乖完成的它需要用户侧提供合适的复位时序和初始化时钟。最核心的几点channel_init_clk是初始化模块的工作时钟频率不能太高通常建议50MHz左右。这个时钟要保证在GT复位期间持续稳定不能等channel_up之后再给。gt_reset信号必须有效复位一段时间后释放。释放太早可能导致GT的PLL还没完成锁定后面初始化卡死释放太晚也不会有什么问题就是浪费时间。gt_txresetdone和gt_rxresetdone两个信号是GT单元给出的复位完成标志Chip2Chip内部的Aurora初始化状态机依赖这两个信号推进状态。在Example Design里这些信号都被封装好了基本不用自己动。但如果自己搭工程最容易犯的错就是把channel_init_clk和user_clk接到同一个时钟上。有些用户时钟频率很高比如157MHz、165MHz拿来当初始化时钟可能会导致时序违例使初始化状态机乱跳。稳妥做法是单独分出一个50MHz时钟给初始化模块数据通路再跑高速用户时钟。还有一点关于power_down信号通常保持低电平即可。如果把GT的power_down意外拉高GT会进入低功耗模式链路怎么都练不起来初始化状态机会一直卡在等待复位完成那一步。仿真时不注意还容易忽略因为仿真模型里power_down拉高并不一定立刻报错。4. 仿真搭建与Aurora PHY初始化避坑4.1 用Example Design快速搭一个双端仿真工程Chip2Chip的仿真一定要由两个IP实例配合完成一端主、一端从GT发送端的差分信号txp/txn接到对端接收端的rxp/rxn。可以在顶层模块里先实例化两个IP然后把信号连起来。最快的起步方式是在生成IP后使用Vivado Tcl命令行打开Example Designopen_example_design -ip [get_ips chip2chip_0]Example Design里自带时钟模块、复位模块、数据生成和比对模块直接跑行为仿真就能看到channel_up拉高的完整时序。我第一次做的时候就是先把主从两端各自Example Design打开然后把两边的顶层里面与GT相连的差分收发信号互相交叉连接再跑仿真。仿真时间要设够。GT的PLL锁定和复位完成在仿真模型里会模拟出真实硬件的时间尺度通常需要几十微秒到几百微秒。如果仿真时间只给几微秒可能还没看到channel_up就结束了。建议至少跑到500微秒等channel_up稳定后再做数据收发验证。4.2 初始化时序里到底发生了什么Chip2Chip和Aurora PHY的初始化大致分三个阶段PMA初始化GT的模拟部分上电复位QPLL/CPLL开始锁定gt_txresetdone和gt_rxresetdone依次拉高。lane初始化发送端开始发送时钟对齐序列接收端通过8B/10B的comma字符完成字节对齐lane_up拉高。channel初始化两端交换初始化状态机信息完成通道握手最终channel_up拉高用户数据通路使能。仿真的时候可以拉出lane_up和channel_up信号观察它们抬起的顺序。正常情况下lane_up会先于channel_up。如果只看到lane_up拉高而channel_up一直不拉问题多半出在主从两端参数不一致或者状态机配置有差异。值得一提的是用户接口的复位信号通常是低有效复位也就是说axi_resetn在channel_up拉高后才能释放。如果外部逻辑不管三七二十一先把用户逻辑复位释放了而此时链路还没建立数据就会在发送端堆积恢复后可能出现先入先出的对齐问题。工程上建议直接用channel_up信号作为用户逻辑复位释放的条件或者至少用它做一次同步。4.3 数据回环验证从发计数器到收计数器比对链路初始化通过后第一件事不是跑业务数据而是做一个简单的回环验证。我常用的方法是在发送端用一个计数器循环发送0x0000到0xFFFF的数据接收端把收到的数据和本地产生的预期值进行比对一旦不一致就拉高错误标志。在Example Design里自带的验证模块已经做了类似事情可以省不少事。如果想自己写一个精简版核心代码逻辑大致是这样// 发送端16bit计数器循环递增 always (posedge user_clk) begin if (!tx_ready) tx_data tx_data 1b1; end // 接收端比对接收数据与本地递增计数 always (posedge user_clk) begin if (rx_valid) begin if (rx_data ! expected_data) error_flag 1b1; else expected_data expected_data 1b1; end end仿真时不要只比对一两个包建议连续跑几万个数据。如果链路存在偶发误码或者初始化过程复位不干净短时间内不一定暴露问题但长时间数据比对能大概率发现。数据验证通过后再引入实际业务逻辑。迭代时先保通道、再加业务这个顺序能极大减少排障时间。4.4 仿真中常见错误和解决方案速查我整理了一张自己在仿真中经常遇到的错误对照表基本覆盖了Chip2Chip初始化阶段的高频问题现象可能原因解决办法channel_up一直为低主从两端线速率或位宽不一致检查两端IP配置是否完全一致lane_up不拉高GT参考时钟没起振或频率不对查看仿真波形确认参考时钟频率正确gt_txresetdone不拉高gt_reset释放太早或channel_init_clk没跑拉长复位时间确保init_clk先运行数据偶发错位用户复位释放时机错误用channel_up同步释放axi_resetn仿真波形出现大量X态某些GT配置参数未初始化确认是否直接用了Example Design的仿真设置上板后链路正常但仿真不过仿真模型与实际硬件复位时间不同仿真中适当延长等待时间还有一个容易被忽视的问题仿真模型默认情况下不会模拟出真实的QPLL锁定失败场景。也就是说即使参考时钟频率不对行为仿真也可能看起来一切正常但上板后链路怎么都练不起来。所以仿真通过不等于硬件一定没问题这一点要特别留意。5. 上板调试时容易忽略的硬件细节5.1 参考时钟、差分走线和接地Chip2Chip跑的是高速串行信号物理层对参考时钟和差分走线非常敏感。参考时钟请使用时钟源专用引脚输入不要拿普通IO模拟差分时钟抖动会直接影响GT的误码率。如果条件允许用独立晶振或时钟芯片给GT参考时钟供给干净时钟源。差分走线要按100欧姆差分阻抗控制尽量短避免过孔。如果走线跨层记得在换层附近加回流地孔。两块FPGA板卡之间用连接器互连时连接器的信号完整性问题也要考虑最好选经过验证的高速连接器。还有一个容易被忽略的点两块板卡的GND必须可靠连通。如果地电位不一致GT的共模电压会漂移轻则误码率高重则链路完全无法建立。调试时先用万用表确认两端地线连接正常再上业务。5.2 上板后如何快速定位链路状态上板后如果链路不通不要急着改代码先看信号。我一般按这个顺序排查用逻辑分析仪或ILA观察gt_txresetdone和gt_rxresetdone是否拉高确认GT复位完成。观察lane_up状态确认字节对齐是否完成。观察channel_up状态确认两端握手是否成功。如果都能拉高再跑数据回环抓取接收端错误标志。FPGA内部这些信号都很容易引出到ILA。如果工程里不好加探针可以直接在顶层模块里把几个关键信号引出来连到空闲LED上用示波器或肉眼观察状态。LED虽然土但真到了现场调试往往比打开Vivado抓波形还快。上板调试另一个常见问题是误码率不稳。排除接线问题后优先尝试降低GT线速率比如从5G降到2.5G如果误码消失说明信号完整性问题比较大需要检查PCB走线和连接器。这个诊断方法简单有效能快速把问题范围缩小到信号完整性还是协议配置上。最后再说两句Chip2Chip这个IP核表面上看起来只是一个“串口加强版”用熟了以后才会发现它内部的Aurora PHY初始化其实藏着不少细节。它最友好的地方在于Xilinx用标准化封装把底层协议打包了让用户把精力放到数据通路和业务逻辑上。但我个人的体会是越是这样封装的核越要在仿真阶段把初始化时序吃透否则上板出了问题反而更不好排查。我后来的固定套路是新项目只要涉及Chip2Chip第一步一定是拿Example Design跑双端仿真看到channel_up稳定拉高后再改成自己的业务逻辑。这一步省掉了我不知道多少的回头调试时间。希望这篇实战经验能帮你少走弯路。