Xilinx Aurora IP 仿真测试
1 Aurora IP 简介
Aurora IP 核是Xilinx 推出的可扩展、轻量级、高速串行通信的链路层协议。通常在两个FPGA之间进行通信使用。使用Aurora协议通信交互的示意图如下:
Xilinx Aurora IP的本质的是Xilinx 在GTP/GTX/GTH的物理Serdes硬核基础上,实现了一套自定义的链路层交互。Xilinx Aurora支持 Aurora 8B10B和Aurora 64B66B两种编码协议的IP。
2 Aurora 8B10B IP 配置
以Aurora 8B10B IP为例,来说明Auraro配置参数的意义。需要注意的是只有Framing接口模式才支持CRC校验,因为Streaming接口没有last信号,IP无法判断CRC计算的起始。
3 Aurora 8B10B IP接口
接口名称 |
输入/输出 |
时钟域 | 描述 |
用户接口(S_AXI) | |||
s_axi_tx_tdata[0:(8n–1)] / s_axi_tx_tdata[(8n–1):0] |
输入 | user_clk | 发送数据,数据位宽是n*字节,可以配置大小端 |
s_axi_tx_tready | 输出 | user_clk | IP发送端准备好信号 |
s_axi_tx_tlast | 输入 | user_clk | Framing模式下的发送帧结束信号 |
s_axi_tx_tkeep[0:(n–1)] / s_axi_tx_tkeep[(n–1):0] |
输入 | user_clk | 指示last信号对应的字节数据是否有效 |
s_axi_tx_tvalid | 输入 | user_clk | 数据发送有效指示信号 |
m_axi_rx_tdata[0:8(n–1)] / m_axi_rx_tdata[8(n–1):0] |
输出 | user_clk | 接收数据,数据位宽是n*字节,可以配置大小端 |
m_axi_rx_tlast | 输出 | user_clk | Framing模式下的接收帧结束信号 |
m_axi_rx_tkeep[0:(n–1)] / m_axi_rx_tkeep[(n–1):0] |
输出 | user_clk | 指示接收last信号对应的字节数据是否有效 |
m_axi_rx_tvalid | 输出 | user_clk | 数据接收有效指示信号 |
状态与控制接口 | |||
channel_up / tx_channel_up / rx_channel_up |
输出 | user_clk |
当Aurora 8B/10B通道初始化完成并且通道已准备好进行数据传输时置1; tx_channel_up和rx_channel_up仅适用于收/发单工模式 |
lane_up[0:m–1] / tx_lane_up[0:m–1] / rx_lane_up[0:m–1] |
输出 | user_clk |
指示每一个通道的初始化成功,每个位代表一个通道; tx_lane_up[0:(m-1)]和rx_lane_up[0:(m-1)]仅适用于收/发单工模式 |
frame_err | 输出 | user_clk | 检测到信道帧/协议错误;信号为单时钟周期有效;不适用于单工TX模式 |
hard_err / tx_hard_err / rx_hard_err |
输出 | user_clk |
检测到硬错误(在Aurora 8B/10B IP 复位之前一直有效); tx_hard_err和rx_hard_err仅适用于收/发单工模式 |
soft_err | 输出 | 在传入的串行流中检测到软错误;不适用于单工TX模式 | |
reset / tx_system_reset / rx_system_reset |
输入 | async |
Aurora 8B/10B IP复位信号(高电平有效); 此信号必须至少持续六个user_clk周期; tx_system_reset和rx_system_reset仅适用于收/发单工模式 |
gt_reset | 输入 | GT收发器的复位信号 | |
link_reset_out | 输出 | init_clk | 如果热插拔达到一定次数,则会置1 |
init_clk_in | 输入 | NA |
init_clk_in是必须存在的,因为当gt_reset被置1时,user_clk会停止; 建议init_clk_in选择的频率低于GT参考时钟的输入频率 |
GT收发器接口 | |||
rxp[0:m–1] | 输入 | RX Serial Clock | 正差分串行数据输入信号 |
rxn[0:m–1] | 输入 | RX Serial Clock | 负差分串行数据输入信号 |
txp[0:m–1] | 输出 | TX Serial Clock | 正差分串行数据输出信号 |
txn[0:m–1] | 输出 | TX Serial Clock | 正差分串行数据输出信号 |
power_down | 输入 | user_clk | 驱动收发器的掉电输入;有关更多信息,请参阅适用的GT收发器用户指南 |
loopback[2:0] | 输入 | user_clk |
loopback[2:0]端口在收发器的正常操作和不同环回模式之间进行选择; 请参阅GTX/GTH收发器用户指南(UG476) |
tx_resetdone_out | 输出 | user_clk | GT收发器的TX侧复位完成指示信号 |
rx_resetdone_out | 输出 | user_clk | GT收发器的RX侧复位完成指示信号 |
tx_lock | 输出 | user_clk | 表示输入的串行收发器参考时钟refclk被收发器锁相环(PLL)锁定 |
GT收发器配置DRP接口(每一对收发lane独立一组) | |||
drpaddr_in/gt<>_drpaddr | 输入 | drpclk_in | DRP地址信号 |
drpclk_in/gt<>_drpclk | 输入 | drpclk_in | DRP接口时钟 |
drpdi_in/gt<>_drpdi | 输入 | drpclk_in | DRP配置写数据 |
drpdo_out/gt<>_drpdo | 输出 | drpclk_in | DRP配置读数据 |
drpen_in/gt<>_drpen | 输入 | drpclk_in | DRP使能信号 |
drprdy_out/gt<>_drprdy | 输出 | drpclk_in | 表示写入操作已完成,数据对读取操作有效 |
drpwe_in/gt<>_drpwe | 输入 | drpclk_in | DRP写入使能信号 |
时钟接口(共享逻辑在核内/GT参考时钟为refclk1/refclk2) | |||
gt_refclk1_p gt_refclk1_n |
输入 | NA | GT收发器参考时钟1 |
gt_refclk2_p gt_refclk2_n |
输入 | NA | GT收发器参考时钟2 |
gt_refclk1_out gt_refclk2_out |
输出 | NA |
GT收发器参考时钟1的IBUFDS_GTE2输出 GT收发器参考时钟2的IBUFDS_GTE2输出 |
user_clk_out | 输出 | NA | Aurora 8B/10B IP 共享并行时钟 |
sync_clk_out | 输出 | NA | Artix 7系列GTP收发器设计的txusrclk |
sys_reset_out | 输出 | NA | IP 输出的系统复位 |
gt_reset_out | 输出 | NA | IP 输出的GT复位 |
init_clk_p init_clk_n |
输入 | NA | 系统/板卡自由时钟 |
init_clk_out | NA | 自由时钟差分缓冲器输出 | |
gt0_pll0refclklost_out gt1_pll0refclklost_out |
输出 | NA | GTPE2_COMMON的refclklost端口 |
quad1_common_lock_out quad2_common_lock_out |
输出 | NA | GTPE2_COMMON的PLL锁定指示信号 |
gt0_pll0outclk_out gt0_pll1outclk_out gt0_pll0outrefclk_out gt0_pll1outrefclk_out gt1_pll0outclk_out gt1_pll1outclk_out gt1_pll0outrefclk_out gt1_pll1outrefclk_out |
输出 | NA | GTPE2_COMMON生成的时钟输出 |
tx_out_clk | 输出 | NA | Aurora 8B/10B IP 共享并行时钟 |
CRC模块接口 | |||
crc_valid | 输出 | user_clk | CRC有效指示;当为1时,会对CRC_pass_fail_n信号进行采样 |
crc_pass_fail_n | 输出 | user_clk | 当发送和接收的crc值相等时,crc_pass_fail_n为1,反之crc_pass_fail_n为0 |
4 Aurora 8B10B IP 用户接口操作时序
4.1 Framing数据接口时序
Framing数据接口TX端的操作时序如下图所示,RX端相对TX端少了axi_tready的信号,相当于RX的数据接口是没有弹性缓冲机制,若用户有弹性需求,其实只需要直接在RX数据端添加一个FIFO即可。
4.2 Streaming数据接口时序
5 Aurora 8B10B IP 仿真
5.1 仿真流程
例化两个Aurora 8B10B IP核,将他们的RX/TX Serdes 物理接口对接,也就是TX0-->RX1/TX1-->RX0。待双方链路建立完毕后,TX端发送数据,RX端接收数据并比较,比较出错产生error信号。
5.2 仿真TestBench

`timescale 1 ns/1 ns `define clk_period 8 module aurora_test_tb(); reg rst ; reg gt_rst ; reg clk ; //-------------------u0-------------------// reg [31:0] u0_s_axi_tx_tdata ; reg [3:0] u0_s_axi_tx_tkeep ; reg u0_s_axi_tx_tvalid ; reg u0_s_axi_tx_tlast ; wire u0_s_axi_tx_tready ; wire [31:0] u0_m_axi_rx_tdata ; wire [3:0] u0_m_axi_rx_tkeep ; wire u0_m_axi_rx_tvalid ; wire u0_m_axi_rx_tlast ; wire u0_rxp ; wire u0_rxn ; wire u0_txp ; wire u0_txn ; wire u0_gt_refclk1_p ; wire u0_gt_refclk1_n ; wire u0_gt_refclk1_out ; wire u0_frame_err ; wire u0_hard_err ; wire u0_soft_err ; wire u0_lane_up ; wire u0_channel_up ; wire u0_crc_pass_fail_n ; wire u0_crc_valid ; wire u0_user_clk_out ; wire u0_sync_clk_out ; wire u0_gt_reset ; wire u0_reset ; wire u0_sys_reset_out ; wire u0_gt_reset_out ; reg u0_power_down = 0 ; reg [2:0] u0_loopback = 0 ; wire u0_tx_lock ; wire u0_init_clk_p ; wire u0_init_clk_n ; wire u0_init_clk_out ; wire u0_tx_resetdone_out ; wire u0_rx_resetdone_out ; wire u0_link_reset_out ; wire u0_drpclk_in ; wire [8:0] u0_drpaddr_in = 0 ; wire u0_drpen_in = 0 ; wire [15:0] u0_drpdi_in = 0 ; wire u0_drpwe_in = 0 ; wire u0_drprdy_out ; wire [15:0] u0_drpdo_out ; reg [31:0] u0_rx_data_cnt ; reg u0_rx_data_err ; //-------------------u1-------------------// reg [31:0] u1_s_axi_tx_tdata ; reg [3:0] u1_s_axi_tx_tkeep ; reg u1_s_axi_tx_tvalid ; reg u1_s_axi_tx_tlast ; wire u1_s_axi_tx_tready ; wire [31:0] u1_m_axi_rx_tdata ; wire [3:0] u1_m_axi_rx_tkeep ; wire u1_m_axi_rx_tvalid ; wire u1_m_axi_rx_tlast ; wire u1_rxp ; wire u1_rxn ; wire u1_txp ; wire u1_txn ; wire u1_gt_refclk1_p ; wire u1_gt_refclk1_n ; wire u1_gt_refclk1_out ; wire u1_frame_err ; wire u1_hard_err ; wire u1_soft_err ; wire u1_lane_up ; wire u1_channel_up ; wire u1_crc_pass_fail_n ; wire u1_crc_valid ; wire u1_user_clk_out ; wire u1_sync_clk_out ; wire u1_gt_reset ; wire u1_reset ; wire u1_sys_reset_out ; wire u1_gt_reset_out ; reg u1_power_down = 0 ; reg [2:0] u1_loopback = 0 ; wire u1_tx_lock ; wire u1_init_clk_p ; wire u1_init_clk_n ; wire u1_init_clk_out ; wire u1_tx_resetdone_out ; wire u1_rx_resetdone_out ; wire u1_link_reset_out ; wire u1_drpclk_in ; wire [8:0] u1_drpaddr_in = 0 ; wire u1_drpen_in = 0 ; wire [15:0] u1_drpdi_in = 0 ; wire u1_drpwe_in = 0 ; wire u1_drprdy_out ; wire [15:0] u1_drpdo_out ; reg [31:0] u1_rx_data_cnt ; reg u1_rx_data_err ; initial clk = 1; always #(`clk_period/2) clk = ~clk; initial begin rst = 1; gt_rst = 1; #1000 rst = 0; #4000 gt_rst = 0; #10000000; $display("Simulation Time Overflow %0t", $time); $stop; end assign u0_init_clk_p = clk; assign u0_init_clk_n = ~clk; assign u0_gt_refclk1_p = clk; assign u0_gt_refclk1_n = ~clk; assign u0_drpclk_in = clk; assign u1_init_clk_p = clk; assign u1_init_clk_n = ~clk; assign u1_gt_refclk1_p = clk; assign u1_gt_refclk1_n = ~clk; assign u1_drpclk_in = clk; assign u0_gt_reset = gt_rst; assign u0_reset = rst; assign u1_gt_reset = gt_rst; assign u1_reset = rst; assign u0_rxp = u1_txp; assign u0_rxn = u1_txn; assign u1_rxp = u0_txp; assign u1_rxn = u0_txn; //-------------------------------u0-------------------------------// always @(posedge u0_user_clk_out or posedge u0_sys_reset_out) begin if(u0_sys_reset_out) begin u0_s_axi_tx_tdata <= 'd0; u0_s_axi_tx_tkeep <= 'd0; u0_s_axi_tx_tvalid <= 'd0; u0_s_axi_tx_tlast <= 'd0; end else if(u0_s_axi_tx_tvalid && ~u0_s_axi_tx_tready) begin u0_s_axi_tx_tdata <= u0_s_axi_tx_tdata ; u0_s_axi_tx_tkeep <= u0_s_axi_tx_tkeep ; u0_s_axi_tx_tvalid <= u0_s_axi_tx_tvalid; u0_s_axi_tx_tlast <= u0_s_axi_tx_tlast ; end else if(u0_channel_up) begin u0_s_axi_tx_tdata <= u0_s_axi_tx_tdata + 1'b1; u0_s_axi_tx_tkeep <= 4'b1111; u0_s_axi_tx_tvalid <= 1'b1; u0_s_axi_tx_tlast <= &u0_s_axi_tx_tdata[3:0]; end else begin u0_s_axi_tx_tdata <= u0_s_axi_tx_tdata; u0_s_axi_tx_tkeep <= u0_s_axi_tx_tkeep; u0_s_axi_tx_tvalid <= 1'b0; u0_s_axi_tx_tlast <= 1'b0; end end always @(posedge u0_user_clk_out or posedge u0_sys_reset_out) begin if(u0_sys_reset_out) u0_rx_data_cnt <= 32'd3; else if(u0_m_axi_rx_tvalid) u0_rx_data_cnt <= u0_rx_data_cnt + 32'd3; end always @(posedge u0_user_clk_out or posedge u0_sys_reset_out) begin if(u0_sys_reset_out) u0_rx_data_err <= 1'b0; else if(u0_m_axi_rx_tvalid && u0_rx_data_cnt != u0_m_axi_rx_tdata) u0_rx_data_err <= 1'b1; end //-------------------------------u1-------------------------------// always @(posedge u1_user_clk_out or posedge u1_sys_reset_out) begin if(u1_sys_reset_out) begin u1_s_axi_tx_tdata <= 'd0; u1_s_axi_tx_tkeep <= 'd0; u1_s_axi_tx_tvalid <= 'd0; u1_s_axi_tx_tlast <= 'd0; end else if(u1_s_axi_tx_tvalid && ~u1_s_axi_tx_tready) begin u1_s_axi_tx_tdata <= u1_s_axi_tx_tdata ; u1_s_axi_tx_tkeep <= u1_s_axi_tx_tkeep ; u1_s_axi_tx_tvalid <= u1_s_axi_tx_tvalid; u1_s_axi_tx_tlast <= u1_s_axi_tx_tlast ; end else if(u1_channel_up) begin u1_s_axi_tx_tdata <= u1_s_axi_tx_tdata + 32'd3; u1_s_axi_tx_tkeep <= 4'b1111; u1_s_axi_tx_tvalid <= 1'b1; u1_s_axi_tx_tlast <= &u1_s_axi_tx_tdata[5:0]; end else begin u1_s_axi_tx_tdata <= u1_s_axi_tx_tdata; u1_s_axi_tx_tkeep <= u1_s_axi_tx_tkeep; u1_s_axi_tx_tvalid <= 1'b0; u1_s_axi_tx_tlast <= 1'b0; end end always @(posedge u1_user_clk_out or posedge u1_sys_reset_out) begin if(u1_sys_reset_out) u1_rx_data_cnt <= 32'd1; else if(u1_m_axi_rx_tvalid) u1_rx_data_cnt <= u1_rx_data_cnt + 32'd1; end always @(posedge u1_user_clk_out or posedge u1_sys_reset_out) begin if(u1_sys_reset_out) u1_rx_data_err <= 1'b0; else if(u1_m_axi_rx_tvalid && u1_rx_data_cnt != u1_m_axi_rx_tdata) u1_rx_data_err <= 1'b1; end aurora_8b10b_ip u0_aurora_8b10b_ip( // AXI TX Interface .s_axi_tx_tdata (u0_s_axi_tx_tdata ), .s_axi_tx_tkeep (u0_s_axi_tx_tkeep ), .s_axi_tx_tvalid (u0_s_axi_tx_tvalid ), .s_axi_tx_tlast (u0_s_axi_tx_tlast ), .s_axi_tx_tready (u0_s_axi_tx_tready ), // AXI RX Interface .m_axi_rx_tdata (u0_m_axi_rx_tdata ), .m_axi_rx_tkeep (u0_m_axi_rx_tkeep ), .m_axi_rx_tvalid (u0_m_axi_rx_tvalid ), .m_axi_rx_tlast (u0_m_axi_rx_tlast ), // GT Serial I/O .rxp (u0_rxp ), .rxn (u0_rxn ), .txp (u0_txp ), .txn (u0_txn ), // GT Reference Clock Interface .gt_refclk1_p (u0_gt_refclk1_p ), .gt_refclk1_n (u0_gt_refclk1_n ), .gt_refclk1_out (u0_gt_refclk1_out ), // Error Detection Interface .frame_err (u0_frame_err ), .hard_err (u0_hard_err ), .soft_err (u0_soft_err ), // Status .lane_up (u0_lane_up ), .channel_up (u0_channel_up ), //CRC output status signals .crc_pass_fail_n (u0_crc_pass_fail_n ), .crc_valid (u0_crc_valid ), // System Interface .user_clk_out (u0_user_clk_out ), .sync_clk_out (u0_sync_clk_out ), .gt_reset_out (u0_gt_reset_out ), .reset (u0_reset ), .sys_reset_out (u0_sys_reset_out ), .power_down (u0_power_down ), .loopback (u0_loopback ), .tx_lock (u0_tx_lock ), .init_clk_p (u0_init_clk_p ), .init_clk_n (u0_init_clk_n ), .init_clk_out (u0_init_clk_out ), .tx_resetdone_out (u0_tx_resetdone_out ), .rx_resetdone_out (u0_rx_resetdone_out ), .link_reset_out (u0_link_reset_out ), //DRP Ports .drpclk_in (u0_drpclk_in ), .drpaddr_in (u0_drpaddr_in ), .drpen_in (u0_drpen_in ), .drpdi_in (u0_drpdi_in ), .drprdy_out (u0_drprdy_out ), .drpdo_out (u0_drpdo_out ), .drpwe_in (u0_drpwe_in ), //____________________________COMMON PORTS_______________________________{ .gt0_pll0refclklost_out(), .quad1_common_lock_out (), //----------------------- Channel - Ref Clock Ports ------------------------ .gt0_pll0outclk_out (), .gt0_pll1outclk_out (), .gt0_pll0outrefclk_out (), .gt0_pll1outrefclk_out (), //____________________________COMMON PORTS_______________________________} .pll_not_locked_out () ); aurora_8b10b_ip u1_aurora_8b10b_ip( // AXI TX Interface .s_axi_tx_tdata (u1_s_axi_tx_tdata ), .s_axi_tx_tkeep (u1_s_axi_tx_tkeep ), .s_axi_tx_tvalid (u1_s_axi_tx_tvalid ), .s_axi_tx_tlast (u1_s_axi_tx_tlast ), .s_axi_tx_tready (u1_s_axi_tx_tready ), // AXI RX Interface .m_axi_rx_tdata (u1_m_axi_rx_tdata ), .m_axi_rx_tkeep (u1_m_axi_rx_tkeep ), .m_axi_rx_tvalid (u1_m_axi_rx_tvalid ), .m_axi_rx_tlast (u1_m_axi_rx_tlast ), // GT Serial I/O .rxp (u1_rxp ), .rxn (u1_rxn ), .txp (u1_txp ), .txn (u1_txn ), // GT Reference Clock Interface .gt_refclk1_p (u1_gt_refclk1_p ), .gt_refclk1_n (u1_gt_refclk1_n ), .gt_refclk1_out (u1_gt_refclk1_out ), // Error Detection Interface .frame_err (u1_frame_err ), .hard_err (u1_hard_err ), .soft_err (u1_soft_err ), // Status .lane_up (u1_lane_up ), .channel_up (u1_channel_up ), //CRC output status signals .crc_pass_fail_n (u1_crc_pass_fail_n ), .crc_valid (u1_crc_valid ), // System Interface .user_clk_out (u1_user_clk_out ), .sync_clk_out (u1_sync_clk_out ), .gt_reset_out (u1_gt_reset_out ), .reset (u1_reset ), .sys_reset_out (u1_sys_reset_out ), .power_down (u1_power_down ), .loopback (u1_loopback ), .tx_lock (u1_tx_lock ), .init_clk_p (u1_init_clk_p ), .init_clk_n (u1_init_clk_n ), .init_clk_out (u1_init_clk_out ), .tx_resetdone_out (u1_tx_resetdone_out ), .rx_resetdone_out (u1_rx_resetdone_out ), .link_reset_out (u1_link_reset_out ), //DRP Ports .drpclk_in (u1_drpclk_in ), .drpaddr_in (u1_drpaddr_in ), .drpen_in (u1_drpen_in ), .drpdi_in (u1_drpdi_in ), .drprdy_out (u1_drprdy_out ), .drpdo_out (u1_drpdo_out ), .drpwe_in (u1_drpwe_in ), //____________________________COMMON PORTS_______________________________{ .gt0_pll0refclklost_out(), .quad1_common_lock_out (), //----------------------- Channel - Ref Clock Ports ------------------------ .gt0_pll0outclk_out (), .gt0_pll1outclk_out (), .gt0_pll0outrefclk_out (), .gt0_pll1outrefclk_out (), //____________________________COMMON PORTS_______________________________} .pll_not_locked_out () ); endmodule
5.3 仿真波形
从仿真波形看出,channel_up信号大概在1085us左右置1,代表Serdes 所有链路建立完毕。两端的rx_data_err保持置0 ,说明两端数据交互正常。
6 Aurora IP 使用总结
6.1 从IP的源文件结构可以看出,Aurora本质是在GT收发器上添加的交互协议。
6.2 从仿真看出,lane_up和channel_up信号的复位训练过程是很长的,如果使用vivado平台直接仿真,那么仿真时间是比较久的。太长的仿真时间显然不太合理,看了底层源码后,发现xilinx是支持通过参数化配置来缩短仿真时间的。由于vivado软件的庞大,若使用vivado自带的仿真器,那么仿真会很慢,建议使用第三方仿真器和vivado联合仿真。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人