1. 从零开始为什么你需要Aurora 64B/66B如果你正在捣鼓FPGA尤其是涉及到板卡之间、或者板卡与高速外设之间的数据交换那你肯定对“高速串行通信”这个词不陌生。传统的并行总线数据线越拉越多时钟频率越来越高不仅布线是个噩梦信号完整性也让人头疼。这时候像Aurora 64B/66B这样的高速串行协议IP核就成了FPGA工程师手里的“神器”。简单来说Aurora 64B/66B是Xilinx现在属于AMD了提供的一个“协议栈”IP核。它帮你把一堆复杂的事情都打包好了怎么把并行的用户数据变成高速的串行比特流发出去编码怎么在接收端把串行流再变回来解码怎么检测传输过程中的错误怎么管理链路状态。你只需要关心两件事把要发的数据塞给它从它那里把收到的数据取出来。剩下的物理层、链路层那些脏活累活IP核全包了。我第一次接触Aurora是在一个数据采集项目里需要把一块ADC采集卡上的高速数据实时传到另一块FPGA做处理。当时评估了各种方案最后还是选了Aurora。原因很简单它足够轻量级协议开销小延迟低而且最关键的是Xilinx的IP核和自家的GTGigabit Transceiver收发器硬核是深度绑定的性能和稳定性有保障不用自己从头去啃那些复杂的SerDes手册。对于初学者可能会被“高速”、“协议”、“IP核”这些词吓到。别担心你可以把它想象成一个“黑盒子”或者一个“函数”。你按照说明书用户指南给它提供正确的“输入”时钟、复位、待发数据它就会给你预期的“输出”接收数据、状态信号。我们这篇实战指南的目的就是手把手带你走通第一次“调用”这个函数并验证它工作的全过程。我们会从在Vivado里找到这个IP开始一步步配置参数、理解关键信号、分析官方给的示例工程最后自己动手搭建一个最简单的回环测试亲眼看到数据发出去又收回来链路成功建立。这个过程走通了你对Aurora的理解就从纸面落到了实地以后再去做更复杂的多通道、跨板卡应用心里就有底了。2. 实战第一步在Vivado中配置你的第一个Aurora IP核好了理论先放一边我们打开Vivado真刀真枪地操作起来。我假设你已经安装好了Vivado2018.2及以上版本比较稳妥并且创建了一个空工程器件型号也选好了务必选一个带GT收发器的型号比如Kintex-7或UltraScale系列。### 2.1 找到并打开IP配置向导在Vivado左侧的“Flow Navigator”面板找到“IP INTEGRATOR”下面的“Create Block Design”。点一下给你的设计起个名字比如aurora_test然后确定。这会打开一个空白的Block Design画布。在画布空白处右键选择“Add IP…”或者直接使用快捷键CtrlI。这时会弹出IP目录窗口。在搜索框里输入“Aurora 64B/66B”你应该能看到一个叫“Aurora 64B/66B”的IP核来自Xilinx。双击它IP核就被添加到你的Block Design中了。### 2.2 关键参数配置详解别被选项吓到双击Block Design里那个刚添加进来的Aurora模块图标会打开一个配置向导。这里选项不少但第一次我们只关注几个最核心的其他的保持默认就好。Core Options核心选项标签页Lane Width通道宽度这个决定了你一条物理串行链路的数据宽度。对于Aurora 64B/66B固定是64B/66B编码所以这里通常不动。Line Rate线速率这是重中之重它决定了你的串行链路跑多快单位是Gbps。这个值不是随便设的它必须和你的参考时钟Reference Clock成倍数关系并且要在你所用FPGA型号的GT收发器支持的范围之内。举个例子如果你的参考时钟是156.25 MHz常见的线速率可以是10.3125 Gbps66倍关系、6.25 Gbps40倍等。一定要查你的FPGA手册和开发板原理图。Reference Clock参考时钟频率输入你的板子提供给GT收发器的参考时钟实际频率比如156.25 MHz。这个必须准确。DRP ClockDRP时钟频率动态重配置端口时钟一般用100 MHz就行这个时钟频率要求不高。Shared Logic共享逻辑标签页 这里有个重要选择Include shared logic in example design和Include shared logic in core。简单理解共享逻辑是GT收发器一些共用的控制逻辑比如时钟模块、复位模块。如果选择“在核心中”那么这些逻辑会打包在Aurora IP核内部你例化一个IP就行比较省事。如果选择“在示例设计中”那么这些逻辑会放在IP核外部适合一个设计里用多个Aurora IP核时共享资源以减少冗余。对于初学者我强烈建议选择“在核心中in core”这样IP核比较独立不容易出问题。GT SelectionGT选择标签页 这里让你选择使用哪个具体的GT收发器Quad四通道组和Channel通道。如果你只是做仿真或者回环测试可以随便选一个比如Quad 216 Channel 0。但如果是实际硬件必须根据你的板卡原理图找到Aurora链路实际连接的FPGA引脚对应的GT位置这里必须选对否则下载到板子上没法用。Example Design示例设计标签页请务必勾选“Generate Example Design”生成示例设计这是我们后续学习和测试的基石。它会在IP核生成时附带一个完整的、可运行的测试工程里面包含了数据生成、检查、时钟复位等所有模块相当于官方送给你一个“标准答案”能极大降低入门门槛。其他标签页比如“Flow Control”流控制、“CRC”循环冗余校验、“Loopback”回环等第一次都可以保持默认。特别是“Loopback”模式我们可以在代码里动态控制这里先选“None”无回环。所有参数检查无误后点击“OK”Vivado会开始生成IP核。完成后你可以在“Sources”窗口看到生成的IP核文件.xci以及一个example_design文件夹。注意线速率和参考时钟频率的匹配是硬件调试中最常见的坑。如果设错了链路永远无法初始化成功。拿不准的时候多翻翻开发板手册和FPGA的Transceiver用户指南。3. 读懂“语言”Aurora IP核的关键端口信号IP核生成了但它有一堆端口Port就像芯片有很多引脚一样。我们得知道哪些引脚是接电源的哪些是接数据的才能正确使用它。Aurora IP核的端口主要分为三大类用户数据接口、GT收发器接口、状态与控制接口。我们不需要一下子记住所有但以下几个是必须理解的“生命线”信号。### 3.1 用户数据接口你与IP核的握手这是你用户逻辑和Aurora IP核之间交换数据的“柜台”。遵循的是AXI4-Stream协议理解起来很简单就是“有效-就绪”握手。发送端TXs_axi_tx_tdata你要发送的数据总线。位宽就是你在IP核配置里设置的“用户数据宽度”比如64位。你把要发的数据放在这上面。s_axi_tx_tvalid你告诉IP核“我放在tdata上的数据现在是有效的你可以拿了”。这个信号由你控制拉高。s_axi_tx_treadyIP核告诉你“我现在准备好接收数据了你可以发过来了”。这个信号由IP核控制。只有当tvalid和tready同时为高的时钟周期一次数据传输才真正发生。这就是AXI-Stream的握手机制保证了数据不会丢失。接收端RXm_axi_rx_tdataIP核接收并解码后的数据位宽同样等于用户数据宽度。数据就在这里。m_axi_rx_tvalidIP核告诉你“tdata上的数据是有效的你可以取走了”。这个信号由IP核控制。m_axi_rx_tlast帧结束信号。当Aurora传输一个数据帧Frame时最后一拍数据对应的tlast会拉高。在简单的流模式下这个信号可能不用太关心。### 3.2 状态与控制接口链路的“健康监测仪”这些信号让你随时知道链路的状态是调试时最需要观察的。init_clk初始化时钟通常用一个独立的、稳定的低频时钟如100MHz或200MHz。IP核内部一些状态机和控制逻辑用它。user_clk用户时钟这是由IP核输出的时钟非常重要你的用户逻辑比如发送数据生成模块、接收数据处理模块应该使用这个时钟来同步所有与Aurora用户接口的交互。它的频率与线速率和编码方式相关。reset系统复位高有效。拉高后IP核和链路会重新初始化。channel_up这是最重要的状态信号当这个信号变为高电平时恭喜你表示Aurora链路已经成功建立收发通道已经同步可以开始安全地传输数据了。在它变高之前你发送的数据是无效的。调试时第一个要看的信号就是它。hard_err/soft_err硬错误和软错误指示。硬错误通常意味着严重的链路问题如失锁需要复位整个IP核。软错误可能由瞬时干扰引起协议层可能会尝试恢复。初期调试目标就是让它们一直为0。### 3.3 GT接口与回环控制GT接口如gt_refclk_p/ngt_txp/ngt_rxp/n等。这些是直接连接到FPGA GT收发器硬核的差分信号引脚用于连接外部物理链路。在仅做仿真或近端回环测试时我们不需要连接外部物理设备但IP核内部需要这些端口的存在。loopback3位宽的回环控制端口。这是实现“自娱自乐”测试的关键。把它设置为3‘b001就开启了近端PMA物理介质附加层回环模式。在这种模式下发送器TX的输出直接在芯片内部连接到接收器RX的输入完全绕过了外部引脚和PCB走线。这是验证IP核本身和你的逻辑是否正确的最快方式。理解这些端口后你再去看官方示例代码就会发现它们无非就是按照这些信号的规则在user_clk的节拍下有条不紊地组织数据发送和接收。接下来我们就钻进官方给的“示例设计”这个宝库里去一探究竟。4. 解剖官方示例framegen与framecheck是如何工作的Vivado为我们生成的example_design是一个极佳的学习模板。它不仅仅是一个测试更是一个展示了如何正确使用Aurora IP核的“最佳实践”工程。我们重点剖析其中两个核心模块framegen帧生成器和framecheck帧检查器。理解了它们你就掌握了与Aurora IP核交互的标准姿势。### 4.1 framegen数据的“发球机”framegen模块的任务很简单产生测试数据并以正确的格式和时序发送给Aurora IP核的TX用户接口。它是如何做到的呢内部状态机framegen内部通常有一个状态机。上电复位后它会等待一个“开始”信号在示例中可能链接到channel_up。一旦channel_up变高表明链路就绪状态机就进入工作状态。数据生成它并不是简单地从0开始计数。为了更有效地测试它通常会生成一种伪随机序列或者带有特定模式的计数数据。这样在接收端更容易验证数据的完整性和顺序。数据位宽与IP核配置的用户宽度一致。AXI-Stream握手这是关键步骤。framegen会把生成的数据放到TX_D对应IP核的s_axi_tx_tdata上同时拉高TX_SRC_RDY_N注意这里的_N表示低有效它对应IP核的s_axi_tx_tvalid但逻辑相反。然后它就开始等待。它会一直检查IP核返回的TX_DST_RDY_N对应IP核的s_axi_tx_tready。只有当TX_DST_RDY_N也为低时表示IP核 ready当前数据才会在时钟上升沿被采走framegen才会产生下一个数据。这完美体现了我们前面讲的“有效-就绪”握手。帧结构可选在一些更复杂的示例中framegen可能会生成带帧头、帧尾和长度信息的数据包模拟真实的网络帧。但在最基本的回环测试中它可能只是持续不断地发送数据流。你可以打开framegen.v的源码看看它的逻辑非常清晰。在实际项目中你可以把framegen替换成你自己的数据源模块比如从摄像头采集的数据、从DDR读取的数据等只要遵循相同的握手协议即可。### 4.2 framecheck数据的“质检员”数据发出去绕了一圈回环模式或者从远端传回来怎么知道数据没错呢这就是framecheck模块的工作。数据接收与同步framecheck连接到Aurora IP核的RX用户接口。它监听RX_SRC_RDY_N对应m_axi_rx_tvalid当这个信号有效时它就从RX_D对应m_axi_rx_tdata上读取数据。预期数据生成为了检查接收到的数据是否正确framecheck内部必须有一个和发送端framegen算法完全一致的数据生成器。也就是说它知道在某个时刻应该收到什么值。如果framegen发的是递增计数那么framecheck就预期收到连续的计数如果framegen发的是伪随机序列那么framecheck就用相同的种子和算法生成同样的伪随机序列来对比。实时比对每一个时钟周期只要收到有效数据framecheck就会将实际收到的数据与内部生成的预期数据进行比对。错误报告如果发现不匹配它就会增加一个内部错误计数器ERR_COUNT。这个计数器通常以信号形式输出到顶层模块。在仿真波形里我们最希望看到的就是这个ERR_COUNT永远为0。同时它可能还会拉高一些错误标志信号。framegen和framecheck就像一对双胞胎一个在发球一个在对面用同样的姿势接球并检查球的好坏。它们通过Aurora IP核这个“球场”连接起来。在回环测试中这个“球场”被设置成了内部直连模式球发出去立刻就能接回来。通过这对模块我们无需任何外部设备就能完整验证整个Aurora数据通路从用户逻辑发送经过IP核编码、串行化在回环模式下虚拟进行、再经过IP核解码最后回到用户逻辑并完成校验。整个流程的验证给了我们极大的信心。5. 动手搭建你的第一个回环测试工程看懂了示例我们现在来亲手搭建一个最小化的、可验证的回环测试工程。这个工程的目标非常明确让Aurora IP核在近端回环模式下工作用framegen发数据用framecheck收数据并确认无误。我们将通过仿真来观察结果。### 5.1 创建工程与IP核配置首先按照第2章的内容创建一个新的Vivado工程器件选KC705或任何你手头有的带GT的开发板型号仿真则无所谓。创建一个Block Design添加并配置Aurora 64B/66B IP核。为了简化我们采用最通用的配置线速率Line Rate 3.125 Gbps 这是一个较低且常见的速率参考时钟Reference Clock 125 MHz 线速率是它的25倍用户数据宽度User Data Width 4字节32位注意这里我们先选32位而不是默认的8字节64位。为什么因为对于64B/66B编码物理层处理的是64位块。但用户接口可以是32位或64位。选32位时IP核内部会做简单的宽度转换这让我们在仿真时观察数据更直观因为每个用户时钟周期传输的数据量少一半。共享逻辑包含在核心中Include Shared Logic in Core示例设计务必勾选生成。回环模式Loopback在IP核配置的“Ports and Interfaces”标签或“GT Selection”标签下可以找到先设置为“None”。我们将在代码中通过loopback端口控制。配置完成后点击生成。生成成功后在Source窗口中展开IP核下的example_design文件夹找到顶层文件通常是aurora_64b66b_0_exdes.v或类似名字。这就是官方给我们的完整测试平台。### 5.2 理解并简化顶层模块官方示例顶层模块可能包含一些时钟生成如MMCM、复位逻辑、以及可选的ILA集成逻辑分析仪调试核。为了最聚焦于Aurora本身我们可以先创建一个更简化的顶层模块。新建一个Verilog文件命名为aurora_loopback_top.v。模块声明与端口我们这个顶层模块暂时不需要外部端口因为时钟和复位我们都用内部仿真激励产生。所以模块可以很简单module aurora_loopback_top(); // 这里放置所有的内部信号、时钟生成和模块例化 endmodule时钟与复位生成在模块内部我们使用initial和always块来生成仿真时钟和复位信号。这是纯仿真环境下的做法。// 生成125MHz参考时钟 (gt_refclk) reg gt_refclk; initial gt_refclk 1b0; always #4 gt_refclk ~gt_refclk; // 周期8ns - 125MHz // 生成初始化时钟 init_clk例如100MHz reg init_clk; initial init_clk 1b0; always #5 init_clk ~init_clk; // 周期10ns - 100MHz // 生成系统复位信号 reg sys_rst; initial begin sys_rst 1b1; // 上电复位 #1000; // 保持复位一段时间 sys_rst 1b0; // 释放复位 end例化Aurora IP核从官方示例顶层文件中找到Aurora IP核的例化部分复制到我们的新顶层模块中。注意只需要例化IP核本身名字类似aurora_64b66b_0以及framegen和framecheck。官方示例中连接GT引脚到顶层端口的部分因为我们做回环测试且不连真实硬件可以删除或连接到未连接的wire。// 声明连接IP核所需的wire wire user_clk; wire channel_up; wire [31:0] tx_data; // 根据IP配置这里是32位 wire tx_src_rdy_n; wire tx_dst_rdy_n; wire [31:0] rx_data; wire rx_src_rdy_n; wire [2:0] loopback 3b001; // 关键设置为近端PMA回环模式 // 例化Aurora IP核 aurora_64b66b_0 your_aurora_instance_name ( // 用户接口 .s_axi_tx_tdata(tx_data), .s_axi_tx_tvalid(~tx_src_rdy_n), // 注意有效极性转换 .s_axi_tx_tready(~tx_dst_rdy_n), .m_axi_rx_tdata(rx_data), .m_axi_rx_tvalid(~rx_src_rdy_n), // ... 连接其他用户接口信号如tlast如果用到的话 // 时钟与复位 .init_clk(init_clk), .user_clk(user_clk), // 注意这是输出时钟需要驱动后续逻辑 .reset(sys_rst), .channel_up(channel_up), // GT接口 - 对于仿真回环可以悬空或接dummy wire .gt_refclk_p(gt_refclk), // 差分输入我们接单端信号 .gt_refclk_n(~gt_refclk), // 回环控制 .loopback(loopback), // ... 连接其他必要的GT端口和状态端口 ); // 例化framegen使用user_clk framegen framegen_i ( .RESET(sys_rst || !channel_up), // 复位或链路未建立时停止发数 .USER_CLK(user_clk), .TX_D(tx_data), .TX_SRC_RDY_N(tx_src_rdy_n), .TX_DST_RDY_N(tx_dst_rdy_n) ); // 例化framecheck使用user_clk wire [0:7] err_count; // 错误计数 framecheck framecheck_i ( .RESET(sys_rst || !channel_up), .USER_CLK(user_clk), .RX_D(rx_data), .RX_SRC_RDY_N(rx_src_rdy_n), .ERR_COUNT(err_count) );关键点loopback 3b001这是实现内部回环的魔法开关。user_clkframegen和framecheck的时钟必须使用IP核输出的user_clk以保证同步。复位逻辑framegen和framecheck的复位我加上了!channel_up条件。这意味着只有在链路建立后它们才开始工作这是一个好习惯。### 5.3 运行仿真与结果分析将我们新建的aurora_loopback_top.v设置为顶层然后运行行为仿真Behavioral Simulation。添加信号到波形窗口将关键信号拖进去sys_rstinit_clkgt_refclkuser_clkchannel_uploopbacktx_datatx_src_rdy_ntx_dst_rdy_nrx_datarx_src_rdy_nerr_count。运行仿真运行足够长的时间比如几十微秒。观察与分析初期复位释放后你会看到IP核开始初始化。channel_up信号会保持一段时间的低电平。链路建立经过一段时间可能几千到上万个时钟周期channel_up会突然跳变为高电平。这一刻标志着Aurora链路初始化成功收发器已经同步。这是第一个里程碑数据传输channel_up变高后framegen和framecheck的复位被释放。你应该立刻看到tx_src_rdy_n变低framegen数据有效并且很快tx_dst_rdy_n也变低IP核 ready握手成功tx_data开始变化。几乎同时rx_src_rdy_n变低rx_data上出现数据。数据验证仔细观察tx_data和rx_data。在回环模式下它们应该是完全相同的并且没有延迟在同一个user_clk周期内。这是因为数据在物理层内部直接绕回来了。终极成功标志观察err_count信号。它应该始终保持为0。如果它开始增加说明framecheck模块发现接收到的数据与预期不符那就需要排查问题了但在这个简单的官方示例回环中它理应一直为0。当你看到channel_up稳定为高err_count始终为0tx_data和rx_data流水般一致地变化时你的第一个Aurora回环测试就圆满成功了这个过程看似简单但它验证了从用户逻辑接口到GT收发器底层驱动再到协议层的整个数据通路。这为你后续将其应用到真实硬件项目比如连接光纤模块、背板连接器等打下了最坚实可靠的基础。在实际硬件调试中你也会遵循类似的观察顺序先确保时钟和复位正确再盯着channel_up等链路建立最后验证数据。这个实战经验比读十遍手册都管用。