
Vivado做FPGA开发绕不开AXI总线。尤其到了Zynq这种带硬核处理器的平台PS和PL之间的数据通信全部压在AXI接口上而AXI Interconnect这个IP核就是那个把多个主设备和从设备组织起来的关键枢纽。以前手动连线时一个多主多从的设计光是地址译码、仲裁、跨时钟域处理就够折腾大半天。现在Vivado的Run Connection Automation越来越成熟5分钟把一堆AXI IP核自动连好已经不是新鲜事。但连上和连好是两码事这篇文章就把自动连接和后续的优化配置一次讲透不管你是刚摸Vivado的新手还是想排查AXI性能瓶颈的老手都能找到可以直接抄作业的内容。1. AXI Interconnect到底解决什么问题先搞清楚它为什么存在1.1 从点对点直连到多主多从互联的必然选择聊AXI Interconnect之前得先说清楚一个问题为什么不能直接把一个主设备和一个从设备的信号线接在一起如果你的设计里只存在一个主设备和一个从设备那确实可以不经过Interconnect直接握手对接就行接口上的AW、W、B、AR、R几组通道一一对应连上地址和数据的位宽一致时钟同源信号完全能跑通。但实际工程项目里这种纯点对点的场景少之又少。以Zynq平台为例PS端本身就带有M_AXI_GP0、M_AXI_GP1等多个AXI主接口PL侧如果还挂了DMA引擎、自定义加速器等主设备一下子就是四五个而挂在总线上的从设备同样不少DDR控制器、BRAM控制器、GPIO、UART、SPI、定时器哪个都要占用地址空间。一旦主从设备数量多起来手动连接就完全不现实了。每个主设备都要能访问每个从设备信号线交叉连接的数量会呈现爆炸式增长而且多个主设备同时发起访问时谁先谁后地址分配怎么去重这些逻辑都需要一个专门模块来处理。AXI Interconnect本质上就是这样一个总线路由器它的内部集成了地址译码、读写通道仲裁、跨时钟域处理、数据宽度转换、协议转换等多种功能让多个主设备可以并发访问不同的从设备同时又不必关心底层互联细节。我在带新人时经常打一个比方Interconnect就像办公楼里的转接口所有工位主设备要打印文件访问从设备不需要自己拉一条专线到打印机从设备只需要把请求扔到公共网络里路由器会自动帮你分配资源、处理好冲突。没有这个转接口每个工位都得单独拉线那楼里早就乱成一团了。1.2 AXI4、AXI4-Lite、AXI4-Stream三种接口怎么选Xilinx的IP核在AXI协议框架下主要使用三种接口很多新手配置Interconnect时看到一堆接口类型就晕其实只需要记住一个简单的区分逻辑。AXI4 Full带突发传输Burst的高性能接口一次可以连续读写一大块数据。它适合DDR控制器、DMA、PCIe这类需要高吞吐量的场景。Zynq PS端的HP接口High Performance就是AXI4 Full。AXI4-Lite轻量级接口每次只传一个数据不带突发。它主要用来访问寄存器比如GPIO的输出值、UART的状态寄存器、定时器的装载值一次读写一个32位数据就够了带宽需求很低。AXI4-Stream流式接口没有地址概念数据像流水一样不断从一个端口流到另一个端口。它适合ADC数据采集、图像传感器、高速串行收发等场景。Interconnect的每一个Slave接口和Master接口都能独立选择上述协议类型。这里要特别提醒一句AXI4-Stream接口不是内存映射接口不能直接接到普通的从设备比如BRAM控制器上必须要通过AXI DataMover或者DMA这类桥接IP来做转换。我在早期项目里试图把一个Stream主设备直接连到Interconnect的内存映射从接口上结果接口协议对不上Block Design直接报错折腾了一下午才反应过来。所以选择接口类型之前先想清楚这路数据到底走的是寄存器读写还是大块数据搬运还是流式透传三者对应Lite、Full、Stream选错了后面的连接就会非常别扭。2. 5分钟自动连接实操流程全记录2.1 准备工作创建Block Design、添加IP核Vivado软件的版本差异很大但从2016以后的版本来看Block Design的操作逻辑基本一致。我习惯用2020.2版本做演示大家使用的版本即使不同界面按钮的位置和名称也大同小异。打开Vivado工程后在左侧Flow Navigator里找到Create Block Design取个名字比如就叫system。Block Design其实就是Vivado里的图形化SoC设计环境你可以在里面拖放各种IP核然后用图形化连线的方式把它们连接起来。接着添加核心IP核。在Diagram窗口中点空白处输入AXI Interconnect搜索双击添加。如果工程里有Zynq或者Versal这样的硬核芯片可以一并把Zynq UltraScale MPSoC或者Zynq-7000添加进来如果是纯逻辑实现则添加MicroBlaze软核处理器作为主设备。这里以Zynq为例PS端配置好DDR、UART等外设后PL侧添加AXI Interconnect、AXI GPIO、AXI BRAM Controller这些常用从设备IP。初次打开的AXI Interconnect配置界面会让你设置接口数量。我建议暂时不要过于精确先留出富余量因为实际使用中接口数经常需要增减。比如你预计有一个主设备、三个从设备那Slave Interfaces就填1Master Interfaces先填3。当然如果后续发现不够还可以双击Interconnect再次修改Vivado允许重新配置后自动重新连接。2.2 Run Connection AutomationVivado的一键连线机制IP核全部添加完成后Diagram窗口里是一片散落的方块接口都是空的什么连接都没有。这时候就该咱们的主角上场了——Run Connection Automation。点击Diagram窗口工具栏上的绿色闪电图标鼠标悬停会显示Run Connection Automation或者在任意未连接的接口上右键选择Run Connection Automation...Vivado会弹出一个对话框列出当前所有未连接的接口。这个对话框是分组的每个接口项旁边有下拉菜单可以选择希望Vivado自动连接的目标比如Auto、Primary或者某个具体的接口名。我对新手的建议是先把所有接口左侧的复选框全部勾选然后用默认的Auto选项点击OK让Vivado自己推断连接关系。这一步看似简单背后Vivado做了大量工作自动从时钟源比如PS的FCLK_CLK0引出时钟连接到Interconnect和各个外设的时钟端口。自动连接复位信号通常会把外设的复位引脚接到proc_sys_reset产生的peripheral_aresetn上。自动把从设备的接口映射到Interconnect的一个Master端口上比如AXI GPIO会挂到Interconnect的M00_AXI。对于未用到的端口比如中断输出Vivado会自动拉高/拉低或者悬空避免DRC报错。点击OK后你会在几秒钟内看到Diagram里的线一根根自动连起来那种感觉确实非常解压。连接完成后整个Block Design从散落的碎片变成了一个完整的互联系统这也正是5分钟搞定说法的底气。需要特别说明的是Run Connection Automation虽然智能但它并不是万能钥匙。如果设计中存在多个主设备、多个时钟域自动连接后的结果经常不完全合理需要手动微调。比如当有两个主设备时Vivado默认会随机分配哪个主访问哪个从或者把高频时钟接到了低频外设上这时候就需要在Block Design中手动修改连接而不是盲目信任自动结果。2.3 地址映射让你的外设有门牌号自动连接只能解决线通不通的问题不能解决地址空间怎么分配的问题。地址映射是AXI互联中最关键的一步你必须手动在Address Editor地址编辑器里给每个从设备分配基地址和范围。在Block Design窗口下方切换到Address Editor标签页你会看到一张表以主设备为行、从设备为列的矩阵。Zynq PS作为主设备可以访问所有挂在Interconnect上的从设备所以你需要为每个从设备分配一段地址。常见做法是将GPIO放在0x40000000BRAM控制器放在0x80000000自定义寄存器模块放在0xA0000000依此类推每个地址区间的范围要覆盖设备的寄存器深度或存储深度。这里有个新手最容易踩的坑以为Vivado自动分配好了地址就不用管了结果调试时某个外设读回来全是0。我遇到过好几次这种情况原因几乎都是地址分配重叠或者分配到了芯片保留地址段上。比如Zynq的0x00000000区域是BootROM和OCM的保留区如果你把BRAM控制器误分到那里CPU实际访问的是内部OCM自然不会返回你想要的数据。在Address Editor中每一行的Segment列就是地址段你可以手动修改基地址Base Address和范围Range也可以点击右键选择Auto Assign Address让Vivado帮你分配。我个人的习惯是先用Auto Assign生成默认分配然后再逐个检查是否有重叠或明显不合理的地方。执行View Memory窗口可以可视化地查看整个地址空间的占用情况非常直观。另外如果设计里还有第二个主设备比如MicroBlaze或者自定义DMA在Address Editor中会多出这个主设备的视角。这时需要注意不同主设备看到的内存空间可能是不同的比如DMA要访问的BRAM缓存它的基地址需要和CPU视角保持一致才能让两个主设备协同读写同一片数据。3. 优化配置从能跑到跑得稳、跑得快3.1 Data Width与协议模式别让带宽卡在喉咙口自动连接完毕后AXI Interconnect还有几个参数需要仔细斟酌。其中影响最直接的就是数据位宽Data Width。打开AXI Interconnect的配置界面你会看到每个接口都有自己的Data Width选项默认通常是32位。如果主设备的接口是128位而从设备是32位Interconnect内部会自动插入数据宽度转换器Data Width Converter把128位数据切片成32位进行传输。这个转换虽然对用户透明但代价是性能损耗——等效带宽会被压缩因为一次128位传输需要拆成四次32位传输同时转换逻辑也会消耗额外的LUT和寄存器资源。那么Data Width应该怎么选呢我的经验法则是尽量让Interconnect两侧的位宽匹配。如果是DDR控制器这类高带宽从设备接口位宽应设置为64位或128位而寄存器类外设GPIO、UART用32位就够了。如果你的主设备是Zynq PS的HP接口它本身是64位/128位的那Interconnect至少也应该配置成64位才不会浪费PS端的带宽能力。实际上很多工程师会发现一个奇怪现象理论带宽算出来很高但实测吞吐量总上不去。排查到最后往往就是某个接口的数据位宽成了瓶颈。这里我可以给一个具体的计算方法做参考AXI4协议一次突发传输的数据量等于突发长度Burst Length最大256乘以数据位宽除以8得到字节数。在100MHz时钟下32位接口的理论峰值带宽是400MB/s。如果你的DDR带宽要求超过这个数就必须升级位宽或提高时钟频率。协议模式上Interconnect的每个接口都可以设置独立的协议类型。同一时刻一个从接口可能连着一个AXI4-Stream的DMA另一个从接口连着AXI4-Lite的逻辑。Interconnect内部会自动做协议转换但要注意Stream与内存映射之间必须通过DataMover等桥接这个之前提到过就不再重复。3.2 Pipeline Stages与时序收敛的关系Pipeline Stages流水线级数是AXI Interconnect配置里一个不起眼但影响深远的参数。它表示数据通路中可插入的寄存器级数默认值是2。流水线的作用是打断组合逻辑长路径。在复杂设计中Interconnect内部的仲裁、译码逻辑加上跨时钟域处理很容易形成很长的组合逻辑路径导致时序收敛困难——也就是常说的时序违规。Vivado如何优化时序这个问题经常被大家问到其中之一最简单有效的操作就是提高Interconnect的Pipeline Stages。如果工程时序紧张把你的Interconnect Pipeline Stages从2改为3或4通常能立刻缓解关键路径上的时序压力。代价是每个请求增加了几个时钟周期的延迟但对大多数读操作来说这点延迟完全可以忽略。如果是高频DDR控制器场景我建议至少设置4级流水线能显著提高时序裕量。如果是纯粹的低速寄存器访问Lite接口延迟影响很小设置4级也没问题。不过注意Pipeline Stages每加一级都会增加多个触发器资源占用而且并非无上限地越大越好。超过6级以后时序改善效果趋于平缓资源浪费却明显上升。我一般控制在2到4之间只有在非常特殊的高频场景下才会开到6。实际项目中我还发现一个问题有时修改Pipeline Stages后Block Design会出现黄色感叹号提示参数变化可能导致功能不一致。需要重新生成输出产品Generate Output Products并且刷新综合实现才能让新的流水线配置生效。这在旧版本的Vivado里尤其容易忘记导致修改了半天跑出来的时序结果还是老样子。3.3 时钟域处理同步与异步到底怎么选Block Design里经常出现多个时钟域。Zynq PS可以输出多路FCLK_CLK0/1/2/3PL侧可能还有DDR时钟、以太网时钟、transceiver参考时钟等。AXI Interconnect的最大价值之一就是能够在内部处理时钟域交叉的问题。在Interconnect的配置界面中每个接口都有Clock属性可以选择Synchronous同步还是Asynchronous异步。当两个对接接口的时钟同源、频率成整数倍关系时用Synchronous模式最省资源如果两个时钟完全异源则必须设置为Asynchronous。Interconnect的内部会自动插入跨时钟域同步逻辑进入异步模式的每个接口会增加一组异步FIFO保证数据在时钟间安全传递。在自动连接时Vivado通常默认把所有接口设为同一个时钟域也就是Synchronous。如果你的设计只有一个时钟域那不用操心。但如果你接了一个独立时钟域的IP比如以太网时钟域和处理器时钟域不同源就必须手动把对应接口的时钟属性改为Asynchronous并且把该接口的时钟引脚连接到对应的独立时钟线上。这个操作在Block Design中修改接口的时钟属性即可完成。关于这个还有个小坑异步模式下Interconnect需要额外的时钟信号来检测跨时钟事件如果对应接口的时钟没有正确连接仿真时数据可能会随机丢失表面上也看不出报错。所以养成一个习惯每次Block Design中涉及多时钟时手动打开Interconnect配置检查每一个接口的时钟源是否正确如果接口旁边出现橙色的时钟交叉图标要特别留意。4. 实际工程经验常见问题与排查技巧实录4.1 黄色感叹号连接不完整的处理思路Block Design中最烦人的就是一片黄色的感叹号图标。每个带感叹号的接口都代表一个未完成或者无效的连接。常见原因有三个缺少复位信号、缺少时钟信号、接口类型不匹配。处理思路其实很简单。首先再次点击Run Connection Automation看是否还有未连接的接口项可以自动连接其次打开Messages窗口找到对应IP核的警告信息Vivado通常会把missing clockmissing reset之类的提示写得很清楚最后如果以上两步都没有问题那就去看看该IP核的数据手册确认它是否需要额外的控制端口、中断线或者配置寄存器这些接口在Block Design中往往是自动连接到Constant模块的。一个实际案例某次我添加了一个自定义AXI从设备IP自动连接后该IP的所有AXI端口都正常但有一个error信号一直挂着黄色感叹号。排查后发现这个信号是IP内部逻辑向外部输出的错误状态标志如果不接就会导致DRC报output port must be connected。解决办法是右键这个端口选择Make External把错误标志引到顶层或者用一个Utility Vector Logic IP把它接上下拉电阻实际上不处理也可以但为了DRC干净还是接一下。这类面子连接在大型Block Design里很常见不影响功能但影响检查结果。另外提醒一句仿真时代多数问题不会暴露但设计进入Implementation阶段DRC会执行得非常细致任何未连接的端口都会被拉出来检查。所以一个干干净净的Block Design是后续实现流程顺利的前提。4.2 地址冲突与DRC报错RTSTAT-2这类问题的处理套路在Vivado中跑Implementation时报错类型千奇百怪但地址相关和DRC相关的错误占了很大比例。我在知乎、论坛和项目群里经常看到有人发Vivado报错DRC RTSTAT-2确实这类错误很常见而且描述比较晦涩中文资料也少。RTSTAT-2这类DRC错误本质上属于物理实现阶段的设计规则检查问题常见诱因包括I/O引脚未约束、布线资源冲突、或者某段逻辑在floorplanning阶段出现了物理布局问题。它不一定直接和AXI Interconnect相关但如果你的Interconnect配置比较特殊比如使用了大量异步时钟域、管道寄存器堆叠过多错误报告里经常能看到Interconnect相关网络的身影。我自己的排查流程大概是这样的第一步仔细阅读DRC报告的完整文本找准它具体指向哪条net或哪个cell实例。Vivado的DRC报告通常会给出一长串路径信息别只看第一行就慌了神。第二步对照Address Editor检查是否有地址重叠。在Block Design中如果两个从设备分配了重叠的地址区间Vivado在综合时不一定报错但DRC阶段几乎一定会抛出来。解决方式很简单改掉其中一个基地址就是。第三步检查I/O约束。如果是纯PL设计所有的对外引脚都必须有XDC约束。RTSTAT类错误有不少就是未约束逻辑端口导致的把所有引脚用set_property PACKAGE_PIN绑定到具体的芯片引脚上即可。值得一提的是很多时候DRC报错并不是一个雷而是一串连锁反应。比如一个地址冲突错误会衍生出好几个接口违规提示你修完根源性问题后其余报错自动就消掉了。所以我遇到DRC从不一个个去治标而是先找到第一个根本性报错处理完再重新跑一次。4.3 实测性能与仿真提速为什么带宽上不去配置好Interconnect后理论上整个数据通路已经形成。但在实际项目里你会发现实测带宽往往和理论值差得很远。以下几个是常见的性能杀手数据位宽转换过多。每次Interconnect做一次位宽转换都会明显降低有效吞吐量。我曾经在某个图像采集项目里为了节省资源把DDR接口的位宽从128位压到32位结果性能从预期的500MB/s掉到了200MB/s后来把DMA路径上的接口都对齐到128位之后性能立刻恢复了。时钟频率不够。Interconnect自身的频率如果比PS端接口时钟低相当于整条总线跑在低频率上性能自然上不去。自动连接时Vivado默认把Interconnect时钟接到FCLK_CLK0如果你在配置中改了频率一定要同步刷新所有关联时钟。仲裁冲突。多个主设备同时访问同一从设备时Interconnect内部仲裁器会串行化请求高优先级的主设备会抢占带宽。在Block Design中可以通过Interconnect的高级配置修改仲裁策略比如固定优先级或轮询但大部分场景下默认的轮询策略已经足够。还有一个经常被忽略的问题是仿真速度。用Vivado Simulator跑包含AXI Interconnect的仿真时因为Interconnect内部包含大量异步FIFO、时钟域转换逻辑仿真模型本身计算量非常大速度极慢。我常用的小技巧是在配置Interconnect时关闭Advanced Features里的Enable Data FIFO或降低Number of Pipeline Stages精简仿真模型。另外仿真前把所有没用的ILA调试核去掉仿真速度能有质的提升。这类优化不会影响最终硬件功能却能让你调试效率成倍提升。5. 写在最后一些跑了多年项目后真心想说的话用Vivado做AXI互联我最大的感受是自动化工具帮你省了八成工作量但剩下那两成知识如果你不懂出了问题会非常难受。我第一次接触Interconnect的时候也天真地以为连上线就大功告成了结果仿真的数据读回来全是0排查了整整一天最后发现不过是在Address Editor里少设了一段地址映射。从那以后我养成了两个习惯。第一个习惯是每次跑完Run Connection Automation无论Vivado有没有报警我都会手动打开Address Editor检查一遍所有从设备的基地址和范围。这个动作只要一分钟却能避免之后上百分钟的排查时间。第二个习惯是遇到性能问题先查Interconnect的时钟频率和数据位宽再查Pipeline Stages和仲裁配置不要一上来就怀疑自己的逻辑代码写错了。按这个顺序排查绝大多数AXI相关性能问题都能很快定位。有朋友问我为什么有时候自动连接出来的设计明明看起来没问题但实现后的时序就是不收敛。这种时候一定要回到配置源头看看是否有某个主从接口的数据宽度转换过于频繁、是否有多余的异步时钟域交叉没有被合理配置、是否是Pipeline级数太少导致组合逻辑过长。这几个点都与AXI Interconnect直接相关也是我反复思考后认为最值得投入时间去理解的核心维度。希望这篇文章能帮你少走一些弯路。