资讯动态

FPGA跨芯片AXI互联:Chip2Chip IP核原理与工程实战

发布时间:2026/10/6 7:13:36 来源:尧图企业网站定制
搞FPGA的人尤其是做过多板卡联调、多FPGA原型验证的基本都绕不开一个场景两个芯片之间要传大量数据、要像访问本地寄存器一样访问对面芯片里的外设甚至恨不得把整条AXI总线直接拉出芯片外面。早期我见过不少人自己用GPIO拼协议、用LVDS一根根拉地址数据线结果要么时序收敛不了要么协议各写各的联调的时候痛苦不堪。Xilinx其实给过一套现成的方案AXI Chip2Chip IP核对应的官方文档就是PG067手册。这篇文章不打算把PG067从头到尾翻译一遍而是顺着“为什么需要它、AXI事务怎么跨芯片走、Vivado里怎么配、出了问题怎么查”这条主线把Chip2Chip的完整脉络讲清楚。适合正在做多FPGA系统、想用AXI统一片内片间互联或者准备数字IC/FPGA面试时想搞清楚AXI在真实工程里如何落地的朋友。1. 为什么跨芯片要用AXIChip2Chip的定位1.1 单芯片AXI互联遇到的天花板先看单颗芯片内部的情况。AXI协议本身是面向片内互联设计的它假定所有master、slave都挂在同一个互联矩阵Interconnect上。这个矩阵负责仲裁、翻译地址、路由读数据master发起事务后经过若干周期就能拿到slave的响应。整个流程依赖的是芯片内部的布线资源、时钟同步和锁存时序只要综合时序能过事务的一致性基本不用你操心。但问题在于AXI协议栈里所有的信号比如AWADDR、WDATA、BVALID、ARADDR、RDATA这些本质上是“并行总线”。当你想把两个FPGA芯片连起来把这些并行信号直接引到引脚上是不现实的。一方面是引脚数量根本不够一个64位AXI4接口加上各种通道握手信号随随便便就要上百根线另一方面是同步时序问题芯片之间的布线延迟远大于片内你没法保证几百根线在同一个时钟沿被对面芯片采样到更别说跨板、跨背板之后信号完整性根本压不住。所以跨芯片通信必然要经过“并行转串行”的过程。行业内常见的出路有三条PCIe、以太网、自定义的SerDes点对点协议。PCIe生态成熟、带宽高但协议栈太重适合需要连接CPU、DMA、RC/EP这种场景以太网灵活但延迟高、MAC/PCS层开销大自定义SerDes协议灵活且低延迟但协议、时钟恢复、流控、错误处理全都要自己写工程量巨大。Chip2Chip走的就是第三条路的“半成品”方案物理层由Xilinx Aurora 8B/10B协议负责上层则直接替你打包AXI事务。你看到的接口仍然是一根AXI总线但背后数据已经被串行化送出了芯片。1.2 PG067到底是本什么手册PG067是Xilinx针对AXI Chip2Chip LogiCORE IP发布的产品指南。手册内容涵盖IP的功能特性、端口定义、寄存器描述、时序约束例程和参考设计。注意一个细节PG067并不是Aurora IP的手册Aurora的手册是PG046两者是不同层级的东西。Chip2Chip内部集成了一个Aurora 8B/10B物理层传输引擎换句话说它是在Aurora之上专门为AXI协议做了事务层封装把Aurora提供的字节流重新组织成AXI通道上的读、写、响应事务。这个IP有几种工作模式最常见的是把一个本地的AXI master接口“映射”到远端的一个AXI slave接口上。配置上你可以定义本地有几个master接口、远端有几个slave接口也可以反过来让远端master访问本地slave。两种访问方向可以同时存在。这实际上就是在两颗芯片之间建立了一张透明的AXI互联网络看起来就像把两个芯片用片内互联矩阵拼成了一个整体。在实际工程里我经常把它类比成“AXI总线延长线”。你在本地逻辑里发起一次写操作地址和数据进到Chip2Chip IPIP把AXI事务打包成一串串行报文从GT引脚发出去远端Chip2Chip IP收到后解包再以标准AXI时序去访问远端slave。整个过程中本地master不知道对面slave其实不在同一颗芯片里它看到的只是一次正常的AXI写事务。1.3 什么场景适合用Chip2Chip用不用Chip2Chip关键看访问模型。如果访问模型是“CPU去远端读写寄存器、搬数据、等中断”并且数据量不是极端的DDR带宽型Chip2Chip非常合适。常见的场景包括多FPGA原型验证平台把一个大的SoC设计拆分到两片FPGA子系统之间通过AXI访问对方的内存控制器或外设模型Chip2Chip可以把片间通信接口统一成AXI省掉自己封装桥接逻辑。数据采集处理分离板卡前端板用一片FPGA做ADC采样和预处理后端板用另一片FPGA做强实时处理。前端板把结果写到一段地址空间后端板直接读这段地址协议统一在AXI层不关心底层连接。多板级联的基带/信号处理系统多个通道板需要共享控制总线每个板卡上挂一组寄存器主控板像访问本地寄存器一样去配置远端不需要额外实现自定义命令解析。不过也要泼盆冷水Chip2Chip不是万能的。如果你要的是等长突发大带宽传输比如连续读DDR4每条AXI读突发长度很长Chip2Chip也能跑但协议开销和SerDes链路延迟会吃掉一部分效率。如果只是要“把数据从一个芯片扔到另一个芯片”不考虑地址映射和读写模型那直接用Aurora甚至IBERT的原始通道可能更简单。选型前一定先想清楚自己的数据通路是“地址化访问”还是“流式搬运”二者实现逻辑完全不同。2. 协议映射AXI事务如何穿过串行链路2.1 AXI的五个通道如何在一条链路上共存AXI协议最核心的特点是通道分离读地址通道AR、读数据通道R、写地址通道AW、写数据通道W、写响应通道B五个通道各自有各自的VALID/READY握手允许master和slave之间是流水化、乱序的。这在片内互联里非常高效但到了串行链路上就有个大麻烦——物理链路只有一条所有通道必须共享带宽。Chip2Chip的做法是给每个AXI事务加一个“协议头”。事务进入IP后先被解析成内部报文格式报文头部携带事务类型读请求、写请求、写数据、写响应、读数据、AXI ID、地址、突发长度、数据字节使能等信息然后经过排队和仲裁送入Aurora引擎串行发送。远端IP收到报文后根据事务类型把数据重新分发到对应的AXI通道上恢复出标准的VALID/READY握手时序。从工程角度理解这条串行链路本质上是一个时分复用的多通道总线。同一时刻链路上可能交替传输着来自不同AXI事务的报文。比如master连续发起两笔写请求和一笔读请求在链路上看就是一个AW报文、一个AR报文、一段W数据报文顺序不保证与AXI通道上的先后完全一致但只要远端能正确识别报文头部就能把它们分别送达对应的slave接口。正因为有了这一层事务层封装你在使用Chip2Chip时不需要关心Aurora的帧格式、流控、错误重传机制。Aurora负责把字节流可靠地从一端搬到另一端Chip2Chip负责把AXI事务变成字节流再恢复成AXI事务。这个分层关系和TCP/IP协议栈非常像AXI事务是应用层Chip2Chip的事务层相当于传输层Aurora 8B/10B是数据链路层GTX/GTH是物理层。2.2 从地址到远端地址映射与多接口扩展Chip2Chip支持在一个IP实例里配置多条独立的AXI接口用于连接多个master或多个slave。这个功能的本质是做了一个本地化的AXI互联矩阵。举个例子我在一块板卡上配置了Chip2Chip IP让它带2个AXI slave接口连接本地的2个master和1个AXI master接口连接本地的1个slave。作用就是允许芯片A上的2个master访问芯片B上的某个slave同时允许芯片B上的某个master访问芯片A上这个slave。每个本地master访问远端时需要分配一段“远端地址空间”。这个地址空间是由IP内部的地址译码逻辑决定的。配置时你要告诉IP本地master发出的地址落在哪个范围内时被路由到远端的哪个接口地址宽度支持到多少、数据宽度是32还是64还是128、ID宽度几位这些都会决定你能挂多少并发事务和能寻址多大空间。地址映射这一块我最想提醒的是地址对齐问题。Chip2Chip内部为了减少报文种类通常期望AXI突发地址与数据宽度对齐。如果你在master端发起了一个非对齐突发比如32位数据总线上地址是0x1001突发长度4IP内部要做的就是拆分事务或者插入数据移位逻辑。PG067手册里明确提到了事务边界处理但实际调试时如果不小心很容易出现“远端slave收到地址正常、数据却有错位”的诡异现象。保险的做法是跨芯片访问的地址全部按数据总线宽度对齐突发长度尽量覆盖完整的一整段地址。2.3 读写事务的完整流程与乱序处理把AXI事务完整走一遍有助于理解后面调试时看波形该盯哪里。写事务流程本地master拉高AWVALID并给出地址Chip2Chip的AXI slave接口握手成功后IP内部生成写请求报文送入Aurora发送队列紧接着W通道的数据报文也会被送出。为了效率IP允许写地址和写数据背靠背或乱序进入发送队列远端收到后恢复成AW和W通道的时序去写slave。当远端slave返回BVALID写响应后远端IP再生成一个写响应报文回传给本地本地IP把它还原成B通道的握手信号。整个写事务才算完成。读事务流程相对简单本地master发AR请求远端IP收到地址后以AXI读事务去读slave读回的数据由远端IP打包成读数据报文回传本地IP恢复出R通道的VALID/READY握手。这里面有一个非常重要的设计点ID和乱序。AXI协议规定了ID字段master可以给不同事务打不同ID允许slave以任意顺序返回读数据。Chip2Chip同样支持这种乱序返回IP内部为每个ID维护了独立的事务跟踪表。如果配置时把ID宽度设小了而master又同时发了超过ID数量上限的outstanding事务IP就可能因为内部跟踪资源不足而暂停握手甚至导致性能骤降。我在实际项目里就吃过这个亏一个DMA引擎发出了16笔outstanding读事务但IP的ID宽度只配了3位结果链路利用率只有60%后来把ID宽度扩到5位才跑满。配置时务必要统计一下各个master的最大outstanding深度和ID占用情况。3. 工程实操在Vivado里把链路搭起来3.1 IP配置里的关键参数打开Vivado的IP Catalog搜索Chip2Chip或者AXI Chip2Chip双击进入配置界面。不同版本Vivado的界面布局略有差异但核心参数是固定的。AXI接口协议可选AXI4、AXI3、AXI4-Lite。AXI4-Lite不支持突发适合寄存器访问AXI4支持突发适合数据搬运。如果对端slave是老式AXI3接口要选AXI3否则ID宽度和突发长度限制可能导致无法互联。数据宽度32、64、128位。这个宽度决定了本地AXI数据总线的宽度也决定了内部报文的数据载荷大小。数据宽度越宽链路利用率越高但占用的GT通道数也越多。地址宽度可配置到32位甚至更高。地址空间越大地址译码逻辑越复杂但一般工程32位足够用了。ID宽度常见1到16位。建议按系统中最大outstanding深度来计算公式大约是2^ID_WIDTH ≥ 最大outstanding事务数并且要留出余量。Master接口数量和Slave接口数量取决于两侧芯片的访问方向。本地需要访问远端几个地址域就配几个master接口远端需要访问本地几个slave就配几个slave接口。底层链路参数参考时钟频率、Aurora线速率、GT通道起始位置。这些参数要和实际硬件上的GT参考时钟、PCB走线匹配不能随意填。参数之间是强相关的。比如数据宽度128位、线速率是5Gbps时内部用户时钟可能只需要跑125MHz左右就够理论带宽但如果数据宽度是32位用户时钟就得跑到500MHz这在FPGA时序上很难收敛。所以推荐的搭配是宽数据位宽较低用户时钟频率也就是用面积换时序而不是一味往高频率冲。3.2 时钟、复位与GT资源Chip2Chip IP的时钟结构比普通AXI外设复杂因为它跨了一个物理层。IP对外会输出用户时钟user_clk和用户复位user_reset这两个信号通常由GT的恢复时钟或参考时钟经MMCM/PLL生成AXI接口侧的slave/master逻辑都要跑在这个user_clk上。复位这一块是重灾区。PG067手册里花了不少篇幅描述复位时序但实际工程中最常见的问题是只复位了AXI接口的逻辑没有正确复位内部的GT和Aurora引擎。Xilinx的Aurora 8B/10B IP核有gt_reset、reset、power_down这三个关键信号它们之间不是简单的“一起拉高再一起拉低”就完事。gt_reset是GT收发器的复位复位时间要满足GT的初始化序列要求power_down不能在上电后立刻拉高必须等GT的PLL锁定reset是Aurora协议的复位必须在GT初始化完成后才能释放。Chip2Chip内部虽然把这些信号封装了但用户仍然要保证IP的全局复位时序合理。我的习惯是这样把Chip2Chip的复位信号接在Vivado提供的Processor System Reset Moduleproc_sys_reset上由外部稳定的慢时钟域产生aux_reset再让proc_sys_reset输出interconnect_reset和peripheral_reset去驱动IP。外部复位至少保持1毫秒以上并且要在参考时钟稳定、GT供电完成后才能释放。如果在调试时发现链路反复init fail先别怀疑AXI逻辑优先检查复位时序和GT参考时钟。3.3 约束与例化集成Chip2Chip是硬核加软核的混合体约束比纯逻辑IP要多两层GT引脚约束和时钟约束。GT引脚约束主要靠Xilinx的XDC属性来做指定Aurora链路占用的GT通道位置、参考时钟引脚、LOOPBACK等。常见写法是set_property LOC GTYE4_CHANNEL_X1Y0 [get_cells inst/chip2chip_inst/gt_common/gtx_channel] set_property PACKAGE_PIN AY12 [get_ports refclk_p] set_property IOSTANDARD LVDS [get_ports refclk_p] create_clock -name gt_refclk -period 5.000 [get_ports refclk_p]时钟约束方面Aurora IP会自动生成GT参考时钟、RX恢复时钟的约束Chip2Chip IP也会生成user_clk相关的generated_clock。但如果你在外部额外加了MMCM、BUFG就要自己补充约束否则时序报告里会看到一堆unconstrained path。做时序收敛时重点看两个区域AXI接口侧的input/output delay是否按实际外部逻辑设置了GT侧的时钟组是否有误报的跨时钟域路径。例化方式有两种一种是让Chip2Chip IP生成例化模板直接在顶层例化另一种是配合Block Design用AXI接口连线。后者在做系统集成时效率更高尤其当你同时还要挂DMA、DDR控制器、中断控制器时。我自己更倾向于在RTL顶层例化因为更容易控制复位时序和调试信号引出也方便做仿真。3.4 带宽和延迟怎么估算配置完IP最好先做一轮带宽和延迟估算心里有数再上板。假设配置Aurora线速率5.0Gbps单通道8B/10B编码。扣除20%编码开销后有效数据带宽是4.0Gbps即500MB/s。如果AXI数据宽度是64位user_clk理论需要125MHz才能跑满加上AXI事务层报文头、突发间隙、响应报文占用的带宽实际可用带宽通常在70%~85%左右。也就是说持续写带宽乐观估计在350~420MB/s之间。如果配置双通道带宽翻倍到700~840MB/s。延迟方面GT收发器的串行/解串延迟大约在几十纳秒量级Aurora引擎和Chip2Chip事务打包解包会再增加几十个用户时钟周期。总体单向延迟大概在100~300纳秒之间。看起来不高但对于要求低延迟的控制环路比如每次读操作都等待远端响应再决定下一步的RTL逻辑总延迟是“读请求上行读数据下行”两个方向之和可能达到600纳秒以上。这个量级在多数寄存器和状态机交互场景下能接受但在依赖内存访问完成的DSP流水线里就要特别注意否则流水线会一直stall。4. 调试过程与常见坑4.1 链路起不来GT复位和初始化那些事上板调试遇到最多的就是链路起不来。现象通常是User Clock已经稳定输出但远端状态寄存器里的channel_up始终是0或者AXI接口一发起事务就超时。排查链路问题我建议按下面的顺序来看GT参考时钟是否真的到了。用Vivado Hardware Manager里的IBERT或者直接在逻辑里拉一个计数器统计REF_CLK没有参考时钟后面全是白搭。看gt_reset的上电时序。GT复位必须在参考时钟稳定、电源稳定完成后才能释放。如果复位信号来自CPLD或者GPIO确认释放时间晚于上电至少几十毫秒。确认power_down一直保持低电平。有些全局复位逻辑会把power_down误拉高GT直接被关掉表现为所有收发器状态全部无效。确认本地Chip2Chip与远端Chip2Chip的Aurora链路参数一致包括线速率、参考时钟频率、通道数。两端配置不一致Aurora会不停尝试握手但永远失败。打开Aurora或Chip2Chip暴露的状态寄存器看是lane_up没拉起来还是channel_up没拉起来对症下药。还有个很容易忽略的地方两端的GT参考时钟频率必须一致但相位不需要一致Chip2Chip本身支持参考时钟不同源的应用。如果你的系统里两片FPGA各用各的晶振链路可以正常建立但要注意这个时钟偏差会导致8B/10B码流里频繁插入comma对齐字符带宽利用率会略低于同源时钟方案。4.2 AXI事务超时或数据不对链路起来后第二个高发问题是事务超时和数据错位。事务超时最常见原因是地址映射没配对。在Vivado配置界面里给master接口分配地址范围时本地地址范围和远端slave实际地址范围要一一对应。比如你让本地master带着0x4000_0000的地址去访问远端结果远端slave挂在0x8000_0000上那么Chip2Chip不会帮你做地址翻译它会直接把这个地址原封不动发给远端slave对应的地址空间而远端slave根本不应该响应这个地址事务自然挂死。数据错位问题尤其是在非对齐突发时出现会引起定位困难。我曾经排查过一个案例DMA读取远端某段数据前几次突发结果正确后面每次返回数据都偏移了4字节。最后定位到是因为某个master发出的突发地址没有按64位对齐Chip2Chip内部的数据对齐逻辑把返回数据的字节通道进行了搬移而我的校验逻辑没考虑到这个shift。处理方法有两个二选一要么要求所有跨芯片访问地址严格对齐要么在远端slave地址前加一个alignment buffer把访问请求重排成对齐突发。图省事的话尽量做第一种。读数据时序问题也值得一提。如果远端slave响应读事务很慢比如RAM有固定延迟Chip2Chip会把RVALID拉低等待slave这没问题。但如果你本地master不支持读数据乱序而远端是多ID场景返回的读数据顺序可能与请求顺序不同master端就会出错。检查master是否支持乱序返回不支持的话就要把系统里的ID宽度和乱序能力限制住或者在上游加一个重排序缓冲。4.3 性能上不去先别怪链路性能达不到预期很多人第一反应是“SerDes带宽不够”。但从我调过的几个项目看瓶颈往往出现在AXI事务层而不是物理层。小突发是最典型的杀手。我做过一次对比测试同一个Chip2Chip链路一次写突发长度从16降为4实测吞吐率直接掉了接近50%。原因很容易理解每个突发都要在链路上发一个地址报文头突发越短地址报文头在总报文中的占比越高有效载荷占比自然下降。Chip2Chip又要求每一个突发都要有写响应返回响应报文同样占带宽。所以把多个小突发合并成一个大突发是提升跨芯片访问带宽最有效的手段。另外master端如果不是流水化发起事务而是发一笔、等完成、再发下一笔那么每笔事务都要等两个方向传播延迟之和才能发出下一笔。这种“停止等待”模型下链路利用率等于延迟乘带宽积的倒数通常连30%都到不了。解决办法是提前压入多笔outstanding事务让链路始终处于有事可做的状态。PG067手册里推荐的outstanding数量通常是保证链路带宽利用率达到80%以上的关键参数宁可多配几下不要抠门。4.4 调试工具怎么配合用Chip2Chip的调试我一般三层配合着查。第一层是ILA抓AXI接口波形。在Chip2Chip IP的Master/Slave接口上直接插入ILA观察握手信号是否正常、是否有事务挂着。这一层能迅速区分问题是出在AXI协议侧还是物理层侧。第二层是Aurora状态和GT状态。Chip2Chip会把一些底层状态信号暴露出来或者你可以单独例化一个Aurora IP Core的example design在回环模式下验证GT链路本身是否健康。用IBERT做误码率测试也很值得做一次完整的IBERT加压测试能排除绝大多数信号完整性方面的问题省得后面一边调协议一边怀疑硬件。第三层是完整的端到端回环测试。在远端FPGA内把一个AXI slave接口回环到Chip2Chip的master接口本地发起一系列特定pattern的读写事务比对返回数据是否和写入一致。这个测试覆盖了事务打包、链路传输、远端解包、AXI握手全链路一旦通过基本可以确认IP配置和硬件连接没有问题问题大概率在用户自己的逻辑侧。4.5 离线标准最后再分享一个小技巧也算是我个人的习惯。Chip2Chip配置里面有一个“模拟延迟”相关选项可以给R通道和B通道强行插入若干周期的延迟用来对齐跨时钟域路径。实际调试时如果遇到时序违例或握手建立时间不足别急着大改逻辑先试着把这个延迟调大几个周期有时问题就悄悄解决了。当然这只是应急手段最终还是要从DC时序报告里找到真正不满足的路径去做修复。从我实际做过的几块多FPGA板卡来看Chip2Chip这套方案最大的价值不在于某一次传输有多快而在于它把“片间通信”变成了“本地总线扩展”让团队里的软件工程师、验证工程师都能用统一的思想去开发协议栈内部再复杂也被IP和手册消化掉了。如果你正准备上多芯片项目又担心自己写桥接逻辑不靠谱不妨先把PG067里关于事务层和复位时序的几章吃透再动手配置IP。这个功课做在前面后面联调能省下好几天的折腾时间。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑