FPGA 高速接口Aurora8B/10B 协议详解与IP仿真
1 摘要
Aurora 8B/10B 是一种用于高速串行通讯的协议,通常用于 FPGA 计划和其他数字通讯应用。即一种编码方案,旨在在传输数据时提供可靠性、时钟规复和错误检测。主要用于在点对点串行链路间移动数据的可扩展轻量级链路层协议,为板对板、芯片对芯片以及一些单向链接提供低成本低资源的解决方案。
2 Aurora8B/10B协议IP原理及适用场景及
2.1 IP核的结构原理
Aurora 8B/10B IP 核心框如图
①Lane Logic :每一个驱动一个GT(GTP,GTX,GTH)收发器,而且初始化对应的GT收发器和处置处罚控制字符的编码和解码以及错误检测。
②Global Logic:执行通道初始化的绑定和验证阶段。在运行过程中,该模块生成 Aurora 协议所需的随机空闲字符,并监控全部通道逻辑模块是否存在错误。
③RX User Interface:AXI4-Stream RX 用户接口将数据从通道移动到应用程序并执行流控制功能。
④TX User Interface:AXI4-Stream TX 用户界面将数据从应用程序移动到通道并执行流控制 TX 功能。标准时钟赔偿模块嵌入在内核中。该模块控制时钟赔偿 (CC) 字符的定期传输
2.2 适用场景
Aurora 8B/10B协议常用于芯片与芯片之间的通讯,特别是在FPGA与FPGA之间的通讯中。它可以通过一个或多个收发器在装备之间传输数据,支持全双工和单工模式。最多可实现16个收发器,吞吐量可从480 Mb/s扩展到84.48 Gb/s。Aurora 8B/10B IP核是全双工模式,数据通过多条Lane发送到另一个Aurora IP核,并通过用户接口将接收到的数据发送给用户。
1)、芯片到芯片的链路:
更换高速串行连接的芯片之间的并联连接可以显着减少 PCB 上所需的迹线和层数。 核心提供了使用 GTP,GTX 和 GTH 收发器所需的逻辑,FPGA 资源成本最低。
2)、板对板和背板连接:
IP CORE 使用标准的 8B / 10B 编码,使其与现有的电缆和背板硬件标准兼容。 Aurora 8B / 10B内核可以在线速率和通道宽度上进行缩放,以便在新的高性能体系中使用便宜的传统硬件。
3)、单向连接(单向):
Aurora 协议提供了替代方法执行单向通道初始化,使 GTP,GTX 和 GTH 收发器在没有反向通道的环境下使用,并降低由于未使用的全双工资源而造成的成本。
3 信号界说
3.1 时钟
信号 | 源 | 信号描述 | ref_clk | 时钟源 | GT的外部时钟 | INIT CLK | 时钟源 | 全局复位,低电平有用 | DRP CLK | 时钟源 | DRP时钟,动态重配置时钟 | user_clk_out | 时钟源 | 用户传输的数据钟及逻辑时钟域 | 3.2 状态信号
Aurora IP还提供了一系列的指示接口信号
信号 | 方向 | 信号描述 | loopback | 输入 | 回环模式,实际使用一样寻常接到低 | power down | 输入 | 掉电信号,GT会进入非工作、低功耗的模式 | lane_up | 输出 | 当对应的Lane初始化完成指示信号 | hard_err | 输出 | 硬件类错误指示 | soft_er | 输出 | 软件类错误指示 | frame_err | 输出 | 帧类错误指示 | 3.3 用户信号
用户接口完全兼容使用 axi-stream协议,我们最关注的信号主要是:TVALID、TREADY、TLAST、TDATA。
发送端接口主要使用的信号
信号 | 方向 | 信号描述 | s_axi_tx_tdata[(8n–1):0] | 输入 | 用户要发送的数据 | s_axi_tx_tready | 输出 | 准备接收数据指示信号 | s_axi_tx_tlast | 输入 | 发送的最后一个数据指示信号 | s_axi_tx_tkeep[(n–1):0] | 输入 | 指示发送的最后一个数据的有用字节 | s_axi_tx_tvalid | 输入 | 用户发送的数据有用信号 | 接收端接口主要使用的信号
信号 | 方向 | 信号描述 | m_axi_rx_tdata[8(n–1):0] | 输出 | 接收到的数据 | m_axi_rx_tlast | 输出 | 接收的最后一个数据指示信号 | m_axi_rx_tkeep[(n–1):0] | 输出 | 指示接收的最后一个数据的有用字节 | m_axi_rx_tvalid | 输入 | 指示当前接收的数据有用 | 4 用户数据接口
用户接口主要分为两种
(1)Framing接口(帧传输接口)。在AXI4-Stream的底子上添加了帧头、帧尾等控制信号,使得传输更准确,但是会降低传输效率和使用较多资源
(2)Streaming接口(流传输接口)。根本上就是一个非常简化的AXI4-Stream接口,只有数据有用、握手和数据信号,此种方式传输效率高,但无法保证传输的准确性
4.1 Framing接口
1)帧构成结构
发送子模块将每个接收的用户帧通过TX接口转换为Aurora 8B / 10B帧。 帧开始(SOF)通过在帧开始处添加2字节的SCP代码组来指示。 帧结束(EOF)是通过在帧的末尾添加一个2字节的信道结束通道协议(ECP)码组来确定。 数据不可用时插入空闲代码组。 代码组是8B / 10B编码字节对,全部数据都作为代码对发送,因此具有奇数个字节的用户帧具有称为PAD的控制字符,附加到帧的末尾以填写最终的代码组。 下图显示了具有偶数数据字节的典型Aurora 8B / 10B帧。
2)发送案例
①Simple Data Transfer(简朴数据传输)
时序图可知,当valid信号与ready信号握手乐成期间传输数据,传输到最后一个数据DATA2时,拉高tlast信号,表明此时传输的是最后一个数据。tkeep信号表现最后一个数据的那些字节是有用的。
②Data Transfer with Pad(奇数字节数据传输)
时序图可知,当valid信号与ready信号握手乐成期间传输数据,传输到最后一个数据DATA2时,拉高tlast信号,表明此时传输的是最后一个数据。tkeep信号表现最后一个数据的那些字节是有用的。根据协议要求,Aurora 8B/10B 内核会为字节数为奇数的帧添加一个添补字符。由于此时传输的是奇数个字节,以是最后一个数据中存在无效字节,故tkeep信号的值为N-1。
③Data Transfer with Pause(带有暂停的数据传输)
时序图可知,当valid信号与ready信号握手乐成期间传输数据,传输到最后一个数据DATA2时,拉高tlast信号,表明此时传输的是最后一个数据。tkeep信号表现最后一个数据的那些字节是有用的。在握手期间,用户通过拉低valid信号中断了握手,实现了数据发送的暂停(流控)。用户应用程序在传输完前 n 个字节后,会通过断开 s_axi_tx_tvalid 来暂停数据流,转而传输空闲数据。暂停将不停持续到 s_axi_tx_tvalid 失效。
④Data Transfer with Clock Compensation(带时钟赔偿的数据传输)
在Aurora 8B/10B 内核发送时钟赔偿序列时会自动中断数据传输。时钟赔偿序列每 10,000 字节对每个通道会造成 12 字节的开销。
4.2 Streaming接口
相比于 Framing接口Streaming接口用法比力简,使用Framing接口的帧框架使得必要使用keep和last这两个信号来控制帧的长度,而Streaming接口则没有帧框架,使用数据流模式通道,不再关注keep和last这两个信号。在发送端发送数据只要在tvalid信号和tready信号握手乐成时就可以发送;而接收端接收数据就只要关注tvalid信号,当tvalid为高时接收的数据有用。
典型的数据发送
典型的数据接收
5 仿真实践
5.1 工程搭建及IP使用
1)使用官方IP生成例程
2)选择共享逻辑
3)生成工程
)
5.2 仿真测试
TestBench代码
- `timescale 1 ns / 1 ps
- module aurora_8b10b_0_TB;
- //*************************Parameter Declarations**************************
- parameter SIM_MAX_TIME = 9500000; //To quit the simulation
- //125.0MHz GT Reference clock
- parameter CLOCKPERIOD_1 = 8.0 ;
- parameter CLOCKPERIOD_2 = 8.0 ;
- //parameter CLOCKPERIOD_1 = 8.0;
- //parameter CLOCKPERIOD_2 = 8.0;
- parameter DRP_CLOCKPERIOD = 20.000 ; //GT DRP Clock
- parameter INIT_CLOCKPERIOD = 20.0 ; // Board/System Clock
-
- //************************Internal Register Declarations*****************************
- //Freerunning Clock
- reg reference_clk_1_n_r;
- reg reference_clk_2_n_r;
- reg drp_clk_r;
- reg init_clk_p;
- //Global signals
- reg gt_reset_in;
- reg gsr_r;
- reg gts_r;
- reg reset_i;
- //********************************Wire Declarations**********************************
-
- //Freerunning Clock
- wire reference_clk_1_p_r;
- wire reference_clk_2_p_r;
- wire init_clk_n;
- //Dut1
- //Error Detection Interface
- wire hard_err_1_i;
- wire soft_err_1_i;
- //Status
- wire channel_up_1_i;
- wire lane_up_1_i;
- //GT Serial I/O
- wire rxp_1_i;
- wire rxn_1_i;
-
- wire txp_1_i;
- wire txn_1_i;
- // Error signals from the Local Link packet checker
- wire [0:7] err_count_1_i;
- //Dut2
- //Error Detection Interface
- wire hard_err_2_i;
- wire soft_err_2_i;
- //Status
- wire channel_up_2_i;
- wire lane_up_2_i;
- //GT Serial I/O
- wire rxp_2_i;
- wire rxn_2_i;
-
- wire txp_2_i;
- wire txn_2_i;
- // Error signals from the Local Link packet checker
- wire [0:7] err_count_2_i;
- //*********************************Main Body of Code**********************************
- //_________________________Serial Connections________________
-
-
- assign rxn_1_i = txn_2_i;
- assign rxp_1_i = txp_2_i;
- assign rxn_2_i = txn_1_i;
- assign rxp_2_i = txp_1_i;
-
- //__________________________Global Signals_____________________________
-
- //Simultate the global reset that occurs after configuration at the beginning
- //of the simulation. Note that both GT smart models use the same global signals.
- assign glbl.GSR = gsr_r;
- assign glbl.GTS = gts_r;
- initial
- begin
- gts_r = 1'b0;
- gsr_r = 1'b1;
- gt_reset_in = 1'b1;
- #5000;
- gsr_r = 1'b0;
- gt_reset_in = 1'b0;
- repeat(10) @(posedge init_clk_p);
- gt_reset_in = 1'b1;
- repeat(10) @(posedge init_clk_p);
- gt_reset_in = 1'b0;
- end
- //____________________________Clocks____________________________
- initial
- reference_clk_1_n_r = 1'b0;
- always
- #(CLOCKPERIOD_1 / 2) reference_clk_1_n_r = !reference_clk_1_n_r;
- assign reference_clk_1_p_r = !reference_clk_1_n_r;
- initial
- reference_clk_2_n_r = 1'b0;
- always
- #(CLOCKPERIOD_2 / 2) reference_clk_2_n_r = !reference_clk_2_n_r;
- assign reference_clk_2_p_r = !reference_clk_2_n_r;
- initial
- drp_clk_r = 1'b0;
- always
- #(DRP_CLOCKPERIOD / 2) drp_clk_r = !drp_clk_r;
- initial
- init_clk_p = 1'b0;
- always
- #(INIT_CLOCKPERIOD / 2) init_clk_p = !init_clk_p;
- assign init_clk_n = !init_clk_p;
-
- //____________________________Resets____________________________
-
- initial
- begin
- reset_i = 1'b1;
- #1000 reset_i = 1'b0;
- end
- //________________________Instantiate Dut 1 ________________
- aurora_8b10b_0_exdes example_design_1_i
- (
- // User IO
- .RESET(reset_i),
- // Error signals from Aurora
- .HARD_ERR(hard_err_1_i),
- .SOFT_ERR(soft_err_1_i),
- // Status Signals
- .LANE_UP(lane_up_1_i),
- .CHANNEL_UP(channel_up_1_i),
- .INIT_CLK_P(init_clk_p),
- .INIT_CLK_N(init_clk_n),
- .DRP_CLK_IN(drp_clk_r),
- .GT_RESET_IN(gt_reset_in),
- // Clock Signals
- .GTXQ0_P(reference_clk_1_p_r),
- .GTXQ0_N(reference_clk_1_n_r),
- // GT I/O
- .RXP(rxp_1_i),
- .RXN(rxn_1_i),
- .TXP(txp_1_i),
- .TXN(txn_1_i),
- // Error signals from the Local Link packet checker
- .ERR_COUNT(err_count_1_i)
- );
- //________________________Instantiate Dut 2 ________________
- aurora_8b10b_0_exdes example_design_2_i
- (
- // User IO
- .RESET(reset_i),
- // Error signals from Aurora
- .HARD_ERR(hard_err_2_i),
- .SOFT_ERR(soft_err_2_i),
- // Status Signals
- .LANE_UP(lane_up_2_i),
- .CHANNEL_UP(channel_up_2_i),
- .INIT_CLK_P(init_clk_p),
- .INIT_CLK_N(init_clk_n),
- .DRP_CLK_IN(drp_clk_r),
- .GT_RESET_IN(gt_reset_in),
- // Clock Signals
- .GTXQ0_P(reference_clk_2_p_r),
- .GTXQ0_N(reference_clk_2_n_r),
- // GT I/O
- .RXP(rxp_2_i),
- .RXN(rxn_2_i),
- .TXP(txp_2_i),
- .TXN(txn_2_i),
- // Error signals from the Local Link packet checker
- .ERR_COUNT(err_count_2_i)
- );
- always @ (posedge channel_up_1_i or posedge channel_up_2_i)
- begin
- if((channel_up_1_i == 1'b1) && (channel_up_2_i == 1'b1))
- begin
- $display("\naurora_8b10b_0_TB : INFO : @Time : %t CHANNEL_UP is asserted in both DUT\n", $time);
- #5000 $display("\naurora_8b10b_0_TB : INFO : Test Completed Successfully\n");
- $finish;
- end
- end
- always @ (posedge err_count_1_i[7] or posedge err_count_2_i[7])
- begin
- if((err_count_1_i >= 8'b0000_0001) || (err_count_2_i >= 8'b0000_0001))
- begin
- $display("\nAURORA_TB : ERROR : TEST FAIL\n");
- $display("\nAURORA_TB : INFO : ERR_COUNT1 = %b ERR_COUNT2 = %b\n",err_count_1_i,err_count_2_i);
- #1000 $display("AURORA_TB : INFO : Exiting from simulation ....\n");
- $finish;
- end
- end
- //Abort the simulation when it reaches to max time limit
- initial
- begin
- #(SIM_MAX_TIME) $display("\nAURORA_TB : INFO : Reached max. simulation time limit\n");
- $finish;
- end
- endmodule
复制代码 5.3 仿真工程结构说明
①support模块(aurora_8b10b_0_support.v):核心,包含了对IP、GT等的例化处置处罚等一系列操作;后续在应用中此部分不必要修改。
②frame_gen( aurora_8b10b_0_FRAME_GEN.v):数据生成模块,接纳LFSR的方式生成伪随机序列;后续在我们的应用中此部分可更换成我们的数据输入模块(建议参加FIFO,这样代码的复用性更佳)。
③frame_check(aurora_8b10b_0_FRAME_CHECK.v):数据查验模块,对接受的数据进行查验以验证传输的正确性;后续在应用中此部分可更换成数据查抄模块或者删除。
④LL_AXI(aurora_8b10b_0_LL_TO_AXI_EXDES.v):LL总线转AXI总线(听说该例程原本的接口是LL接口,后面Xilinx为了推广AXI总线。
5.4 Aurora 8B/10B IP核 延迟开销
Aurora 8B/10B IP的延迟是由协议引擎(编解码、流水线处置处罚、)和GT收发器的管道延迟引起的。随着用户接口数据宽度的增长,协议引擎的延迟也会增长;GT收发器的延迟取决于所选收发器的功能和属性。在K7器件的仿真实行大约在34个User_clk周期,其他器件请另测试,手册给出V7系列最小37个周期。
5.5 发送和接收数据
1)channel_up信号
2)s_axi_tx_tdata用户发送数据
3)m_axi_rx_tdata用户接收数据
通过仿真当channel_up信号置位拉高时,意味着Aurora 8b/10b IP核乐成建立链路通道。s_axi_tx_tready和s_axi_tx_tvalid高有用时,用户发送数据有用,接收数据当m_axi_rx_tvalid有用时,接收端数据有用。在计划使用时必要注意:
①数据: 在用户发送每一帧数据的时候,Aurora8B10都会在数据的开始位置增长2byte的SCP和末尾增长2btye的EOF来表现数据帧的开始和结束标志(如果用户的数据btye数为奇数的话,会为其增长额外的一个PAD byte来使数据为偶数)。以是为了最大传输带宽,用户每次传输的数据byte数最好为偶数。
②时钟赔偿: 传输通道每10000 bytes必要进行一次时钟赔偿,每次时钟赔偿必要发送12 bytes的数据,必要消耗6个或者3个时钟周期开销。
③传输延时:从发送端发送第一个数据开始,到接收端接收到第一个数据结束所消耗的时间,最小的延时为37/41个用户时钟周期,如有对时延有要求。
6 总结
本文先容了高速接口Aurora8B/10B 协议,通过对协议的接口时序明白及握手机制及一些相关术语的学习,具体了解了高速接口Aurora8B/10B 协议的使用方法。通过FPGA仿真验证了该IP的使用方法和一些主要的关键信号。为使用高速串行接口计划提供底子。后续则继续总结分享FPGA中的一些技术应用,开辟不易爱惜每一分原创和劳动结果,同时注意平时开辟过程中的经验积累总结。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |