FPGA实战(51):FPGA高速串行通信:双通道Aurora 8B/10B工程实例

📅 2026/7/18 13:08:19
FPGA实战(51):FPGA高速串行通信:双通道Aurora 8B/10B工程实例
一、概述Aurora 8B/10B是Xilinx提供的一种轻量级、可扩展的链路层协议,专为FPGA间或FPGA与ASIC之间的高速串行通信而设计。该协议基于GT(Gigabit Transceiver)收发器实现物理层,通过8B/10B编码保证DC平衡,并提供帧起始/结束符插入、空闲字符生成、多通道绑定等链路层服务。本工程基于Xilinx Zynq-7000系列(XC7Z035)器件,实现了两个独立Aurora 8B/10B通信通道,线速率6.25Gbps,用户接口位宽32bit,采用AXI4-Stream协议,包含完整的时钟管理、复位逻辑、GT资源共享和仿真验证环境。二、IP核内部架构Aurora 8B/10B IP核由四个核心逻辑单元构成:通道逻辑:负责8B/10B编解码、逗号检测与字节对齐、K码插入与识别。全局逻辑:多通道时通过FIFO补偿skew,实现通道绑定;管理空闲序列生成和错误监测。用户接口:标准AXI4-Stream,含tdata、tkeep、tlast、tvalid、tready。收发器封装:将GTX/GTH原语封装为统一接口。数据流:用户数据 → 协议封装 → 可选扰码/CRC → 8B/10B编码 → GT串行化输出;接收端为逆过程。三、四个时钟域时钟域来源用途GT Refclk外部差分晶振156.25MHz驱动GT内部QPLLINIT CLK板载100MHz初始化与复位逻辑DRP CLK接地(本工程未使用)动态重配置USER CLKGT的tx_out_clk经BUFG用户逻辑与IP核主时钟USER_CLK计算公式:线速率 × 0.8 / 接口位宽,本工程为6.25G×0.8/32=156.25MHz。多核共享GT Refclk和INIT CLK,但USER_CLK各核独立。四、复位序列IP核提供两个复位输入:reset(协议层复位):最小脉宽6个USER_CLK周期。gt_reset生效前须保持高电平至少128个USER_CLK周期。gt_reset(物理层复位):复位GT收发器,须在INIT CLK域去抖(4级移位寄存器)并展宽至≥6周期。工程中通过SUPPORT_RESET_LOGIC模块实现外部复位信号去抖和CDC同步。五、GT资源共享CPLL:1.6~3.3GHz,单Lane私有。QPLL:5.93~12.5GHz,整个Quad共享。本工程线速率6.25Gbps,使用QPLL。GTXE2_COMMON原语配置QPLL,输出gt_qpllclk_quad3和gt_qpllrefclk_quad3同时供给两个通道。多核场景须将Shared Logic置于外部,避免资源浪费。六、用户数据接口与环回发送端产生递增数据流,便于接收端比对校验。tlast在包尾倒数第二拍置位,确保与最后一个数据同时有效。仿真中设置loopback=3'b010(近端PCS环回),发送差分对短接到接收端,实现全内部验证。七、CDC同步器工程包含参数化CDC模块,支持三种模式:脉冲同步:源域异或翻转,目的域多级同步后检测边沿异或。电平同步:目的域多级打拍输出(本工程用于复位信号传递,5级同步)。带应答同步:增加握手确认。关键属性:(* ASYNC_REG = "true" *)强制使用触发器,(* shift_extract = "{no}" *)防止综合为SRL。XDC约束:set_false_path -to [get_pins -hier *cdc_to*/D]。八、工程文件列表文件名功能XC7Z035_TOP.v顶层模块aurora_module.v双通道管理、GT参考时钟缓冲、QPLL共享aurora_channel.v单通道封装(时钟+复位+IP核)aurora_8b10b_0_CLOCK_MODULE.v用户时钟生成aurora_8b10b_0_SUPPORT_RESET_LOGIC.v复位去抖与CDC同步aurora_8b10b_0_gt_common_wrapper.vQPLL共享逻辑aurora_8b10b_0_cdc_sync_exdes.v参数化CDC同步器user_data_gen.v用户数据产生与校验rst_gen_module.v上电复位产生器tb.v仿真测试平台九、仿真与验证测试平台特点:生成100MHz和156.25MHz差分时钟。发送差分对短接到接收端实现物理环回。以收到10个完整数据包作为仿真结束条件,总耗时约50μs。自动比对收发数据并输出PASS/FAIL。完整源代码1. XC7Z035_TOP.v`timescale 1ns / 1ps module XC7Z035_TOP( input i_gtref_clk_p , input i_gtref_clk_n , input i_clk_100M_p , input i_clk_100M_n , output [1 :0] gt_txp , output [1 :0] gt_txn , input [1 :0] gt_rxp , input [1 :0] gt_rxn , output [1 :0] o_sfp_dis ); wire w_clk_100M ; wire w_clk_100M_rst ; wire w_c0_user_clk ; wire w_c0_user_rst ; wire w_c1_user_clk ; wire w_c1_user_rst ; (* MARK_DEBUG = "TRUE" *)wire [31:0] m_c0_axi_tx_tdata ; (* MARK_DEBUG = "TRUE" *)wire [3 :0] m_c0_axi_tx_tkeep ; (* MARK_DEBUG = "TRUE" *)wire m_c0_axi_tx_tlast ; (* MARK_DEBUG = "TRUE" *)wire m_c0_axi_tx_tvalid ; (* MARK_DEBUG = "TRUE" *)wire m_c0_axi_tx_tready ; (* MARK_DEBUG = "TRUE" *)wire [31:0] s_c0_axi_rx_tdata ; (* MARK_DEBUG = "TRUE" *)wire [3 :0] s_c0_axi_rx_tkeep ; (* MARK_DEBUG = "TRUE" *)wire s_c0_axi_rx_tlast ; (* MARK_DEBUG = "TRUE" *)wire s_c0_axi_rx_tvalid ; (* MARK_DEBUG = "TRUE" *)wire [31:0] m_c1_axi_tx_tdata ; (* MARK_DEBUG = "TRUE" *)wire [3 :0] m_c1_axi_tx_tkeep ; (* MARK_DEBUG = "TRUE" *)wire m_c1_axi_tx_tlast ; (* MARK_DEBUG = "TRUE" *)wire m_c1_axi_tx_tvalid ; (* MARK_DEBUG = "TRUE" *)wire m_c1_axi_tx_tready ; (* MARK_DEBUG = "TRUE" *)wire [31:0] s_c1_axi_rx_tdata ; (* MARK_DEBUG = "TRUE" *)wire [3 :0] s_c1_axi_rx_tkeep ; (* MARK_DEBUG = "TRUE" *)wire s_c1_axi_rx_tlast ; (* MARK_DEBUG = "TRUE" *)wire s_c1_axi_rx_tvalid ; (* MARK_DEBUG = "TRUE" *)wire w_c0_hard_err ; (* MARK_DEBUG = "TRUE" *)wire w_c0_soft_err ; (* MARK_DEBUG = "TRUE" *)wire w_c0_frame_err ; (* MARK_DEBUG = "TRUE" *)wire w_c0_channel_up ; (* MARK_DEBUG = "TRUE" *)wire w_c0_lane_up ; (* MARK_DEBUG = "TRUE" *)wire [2 :0] w_c0_loopback ; (* MARK_DEBUG = "TRUE" *)wire w_c1_hard_err ; (* MARK_DEBUG = "TRUE" *)wire w_c1_soft_err ; (* MARK_DEBUG = "TRUE" *)wire w_c1_frame_err ; (* MARK_DEBUG = "TRUE" *)wire w_c1_channel_up ; (* MARK_DEBUG = "TRUE" *)wire w_c1_lane_up ; (* MARK_DEBUG = "TRUE" *)wire [2 :0] w_c1_loopback ; assign w_c0_loopback = 3'b010; assign w_c1_loopback = 3'b010; assign o_sfp_dis = 2'b00 ; IBUFDS #( .DIFF_TERM ("TRUE" ), .IBUF_LOW_PWR ("TRUE" ), .IOSTANDARD ("DEFAULT" ) )IBUFDS_inst( .O (w_clk_100M ), .I (i_clk_100M_p ), .IB (i_clk_100M_n ) ); rst_gen_module#( .P_RST_CYCLE (10 ) ) rst_gen_module_U0 ( .i_clk (w_clk_100M ), .o_rst (w_clk_100M_rst ) ); user_data_gen user_data_gen_u0( .i_clk (w_c0_user_clk ), .i_rst (w_c0_user_rst ), .m_axi_tx_tdata (m_c0_axi_tx_tdata ), .m_axi_tx_tkeep (m_c0_axi_tx_tkeep ), .m_axi_tx_tlast (m_c0_axi_tx_tlast ), .m_axi_tx_tvalid (m_c0_axi_tx_tvalid ), .m_axi_tx_tready (m_c0_axi_tx_tready ), .s_axi_rx_tdata (s_c0_axi_rx_tdata ), .s_axi_rx_tkeep (s_c0_axi_rx_tkeep ), .s_axi_rx_tlast (s_c0_axi_rx_tlast ), .s_axi_rx_tvalid (s_c0_axi_rx_tvalid ) ); user_data_gen user_data_gen_u1( .i_clk (w_c1_user_clk ), .i_rst (w_c1_user_rst ), .m_axi_tx_tdata (m_c1_axi_tx_tdata ), .m_axi_tx_tkeep (m_c1_axi_tx_tkeep ), .m_axi_tx_tlast (m_c1_axi_tx_tlast ), .m_axi_tx_tvalid (m_c1_axi_tx_tvalid ), .m_axi_tx_tready (m_c1_axi_tx_tready ), .s_axi_rx_tdata (s_c1_axi_rx_tdata ), .s_axi_rx_tkeep (s_c1_axi_rx_tkeep ), .s_axi_rx_tlast (s_c1_axi_rx_tlast ), .s_axi_rx_tvalid (s_c1_axi_rx_tvalid ) ); aurora_module aurora_module_u0( .i_gtref_clk_p (i_gtref_clk_p ), .i_gtref_clk_n (i_gtref_clk_n ), .i_clk_100M (w_clk_100M ), .i_rst (w_clk_100M_rst ), .gt_txp (gt_txp ), .gt_txn (gt_txn ), .gt_rxp (gt_rxp ), .gt_rxn (gt_rxn ), .s_axi_c0_tx_tdata (m_c0_axi_tx_tdata ), .s_axi_c0_tx_tkeep (m_c0_axi_tx_tkeep ), .s_axi_c0_tx_tlast (m_c0_axi_tx_tlast ), .s_axi_c0_tx_tvalid (m_c0_axi_tx_tvalid ), .s_axi_c0_tx_tready (m_c0_axi_tx_tready ), .m_axi_c0_rx_tdata (s_c0_axi_rx_tdata ), .m_axi_c0_rx_tkeep (s_c0_axi_rx_tkeep ), .m_axi_c0_rx_tlast (s_c0_axi_rx_tlast ), .m_axi_c0_rx_tvalid (s_c0_axi_rx_tvalid ), .s_axi_c1_tx_tdata (m_c1_axi_tx_tdata ), .s_axi_c1_tx_tkeep (m_c1_axi_tx_tkeep ), .s_axi_c1_tx_tlast (m_c1_axi_tx_tlast ), .s_axi_c1_tx_tvalid (m_c1_axi_tx_tvalid ), .s_axi_c1_tx_tready (m_c1_axi_tx_tready ), .m_axi_c1_rx_tdata (s_c1_axi_rx_tdata ), .m_axi_c1_rx_tkeep (s_c1_axi_rx_tkeep ), .m_axi_c1_rx_tlast (s_c1_axi_rx_tlast ), .m_axi_c1_rx_tvalid (s_c1_axi_rx_tvalid ), .o_c0_hard_err (w_c0_hard_err ), .o_c0_soft_err (w_c0_soft_err ), .o_c0_frame_err (w_c0_frame_err ), .o_c0_channel_up (w_c0_channel_up ), .o_c0_lane_up (w_c0_lane_up ), .i_c0_loopback (w_c0_loopback ), .o_c1_hard_err (w_c1_hard_err ), .o_c1_soft_err (w_c1_soft_err ), .o_c