FPGA教程系列-Vivado Aurora 8B/10B 例程解读

FPGA教程系列-Vivado Aurora 8B/10B 例程解读

1. 核心支撑层 (最重要,以后要抄作业的部分)

对应层级: aurora_module_i : aurora_8b10b_0_support

这是整个工程的心脏。如果你要在自己的项目里使用 Aurora,不要直接例化那个 .xci文件 ,而是建议把这个 support 模块作为一个整体移植过去。

  • aurora_8b10b_0_i (xci) :

    这是在 GUI 界面配置生成的 IP 核本体(黑盒子)。它负责协议层的编解码、8B/10B 转换等。

  • clock_module_i:

    非常关键 。它负责把 GT 输出的时钟(tx_out_clk)通过 BUFG 缓冲,生成 user_clk​ 和 sync_clk

    如果自己手动例化 IP,很容易把时钟搞错,用这个模块能省很多事。

  • gt_common_support:

    这里面包含了 GT_COMMON 原语(也就是 QPLL)。

    还记得在 "Shared Logic" 那一页选了 "Example Design" 吗?所以这个公共逻辑出现在了这里,而不是在 .xci 里面。

  • support_reset_logic_i:

    GT 的复位序列非常复杂(要先复位 PLL,等锁定了再复位 TX/RX,还要处理去抖)。这个模块帮你把这些麻烦事全干了。


2. 流量产生与测试层 (测试用,以后要替换的部分)

对应层级: traffic... 开头的模块

这部分逻辑就是为了演示 IP 核是活的。在正式开发时,这部分要被删除,替换成自己的数据源(比如 ADC 数据、视频流等)。

  • traffic.frame_gen_i (高亮选中的部分):

    产生伪随机数(LFSR),使用的是旧版的 LocalLink 接口(SRC_RDY / DST_RDY)。

  • traffic.frame_gen_ll_to_axi_pdu_i:

    适配器 。因为 frame_gen​ 用的是旧接口,而 Aurora IP 用的是新接口(AXI4-Stream),所以 Xilinx 加了这个模块把 LocalLink 信号转换成 AXI 信号 (tvalid​, tdata​, tlast)。

  • traffic.frame_check_i:

    接收端的检查器。它在收到数据后,用同样的算法算一遍,看收到的数对不对。如果不对,它会报错(通常连接到板子上的 LED 灯)。


3. 调试与仿真层

对应层级: vio​, ila​, Simulation Sources

  • VIO / ILA:

    vio​ (Virtual IO):电脑上通过 Vivado 面板控制复位、查看 channel_up 状态。

    ila (Integrated Logic Analyzer):内置逻辑分析仪,用来抓取波形。

  • Simulation Sources (aurora_8b10b_0_TB) :

    仿真文件 (Testbench)。实例化了 两个 exdes​ (example_design_1_i​ 和 _2_i​)。仿真环境模拟了 两块板子互联 的场景。板子 A 发给板子 B,板子 B 发给板子 A,形成一个闭环测试。

对应了各个文件,在这里例子里其实有点冗余的设计,traffic.frame_gen_ll_to_axi_pdu_i文件只是一个接口转换的功能,现在大部分都是AXI接口,没有必要进行这个转换,以后使用的时候可能也用不到,所以。。。后续的工作就把这部分替换掉,那么就得引入什么是AXI。稍后再学习,这部分留下一个问题。

整个例子是在做一个回环实验。如下图所示:​

数据生成模块

完整代码就不再粘贴了,生成的官方例子里都有,逐个拆解,看一下内部:

主要功能是产生伪随机数据帧,用于测试 Aurora 通信链路的连通性和稳定性。通过一个简单的流量生成机制,在链路建立后向发送端接口发送数据。

1. 模块接口 (Interface)

该模块连接了两个主要接口:

用户接口 (User Interface / LocalLink 风格):

  • TX_D [0:15]: 发送的数据总线(16位)。
  • TX_SRC_RDY_N: 源端就绪信号(低电平有效)。表示 TX_D 上的数据有效。
  • TX_DST_RDY_N: 目的端就绪信号(低电平有效)。这是输入信号,表示下游(Aurora Core)是否准备好接收数据。

系统接口 (System Interface):

  • USER_CLK: 用户时钟,所有逻辑以此为基准。
  • RESET: 复位信号。
  • CHANNEL_UP: 链路状态信号,高电平表示 Aurora 通道已建立并准备好工作。

接口对比:

映射表

功能 Verilog 代码信号 (LocalLink) 图片接口信号 (AXI4-Stream) 备注
发送数据 TX_D s_axi_tx_data 方向一致
数据有效 TX_SRC_RDY_N s_axi_tx_tvalid 极性相反 (0有效 vs 1有效)
接收准备好 TX_DST_RDY_N s_axi_tx_tready 极性相反 (0有效 vs 1有效)
时钟 USER_CLK user_clk -
复位 RESET reset -

2. 核心逻辑分析

代码逻辑可以分为三个主要部分:通道延迟启动、复位控制、数据生成(LFSR)。

A. 通道延迟启动 (Channel Up Delay Counter)
verilog 复制代码
always @ (posedge USER_CLK)
begin
  if(RESET)
      channel_up_cnt <= `DLY 5'd0;
  else if(CHANNEL_UP)
    if(&channel_up_cnt) // 如果计数器全为1 (即等于31)
      channel_up_cnt <= `DLY channel_up_cnt; // 保持最大值
    else 
      channel_up_cnt <= `DLY channel_up_cnt + 1'b1; // 计数+1
  else
    channel_up_cnt <= `DLY 5'd0; // 如果Channel断开,重置计数器
end

这是一个 5 位的饱和计数器。当 CHANNEL_UP​ 信号拉高(链路建立)后,模块不会立即发送数据,而是等待 channel_up_cnt​ 计数满(31个时钟周期)。提供了一个"热身"或"稳定"时间,确保链路真正稳定后再开始数据传输。dly_data_xfer 信号在计数器满时变高。

B. 内部复位逻辑 (Internal Reset Generation)
verilog 复制代码
assign reset_c = RESET || !dly_data_xfer;

生成内部控制用的复位信号 reset_c​。只要外部 RESET​ 有效,或者 延迟计数器还没数满(即 dly_data_xfer 为低),数据生成逻辑就一直处于复位状态。这意味着只有在链路建立并稳定约 32 个周期后,数据生成才会开始。

C. 数据生成与流控 (LFSR Data Generation & Flow Control)

这是模块的核心部分,使用线性反馈移位寄存器 (LFSR) 生成伪随机数。

verilog 复制代码
always @(posedge USER_CLK)
    if(reset_c)
    begin
        data_lfsr_r      <=  `DLY    16'hABCD;  // 初始种子 (Seed)
        TX_SRC_RDY_N     <=  `DLY    1'b1;      // 复位时,源端未就绪 (高电平)
    end
    else if(!TX_DST_RDY_N) // 只有当目的端 (Aurora Core) 准备好接收时
    begin
        // XNOR 反馈逻辑,生成下一个伪随机数
        data_lfsr_r      <=  `DLY    {!{data_lfsr_r[3]^data_lfsr_r[12]^data_lfsr_r[14]^data_lfsr_r[15]},
                            data_lfsr_r[0:14]};
        TX_SRC_RDY_N     <=  `DLY    1'b0;      // 拉低信号,表示正在发送有效数据
    end

LFSR 算法 :使用了 XNOR 反馈。新的最高位(bit 0)由 !(bit3 ^ bit12 ^ bit14 ^ bit15)​ 计算得出,其余位右移(data_lfsr_r[0:14] 移到低位)。这种特定的抽头(Taps)选择用于生成具有特定周期长度的伪随机序列。

握手协议 (Handshake)

  • 遵循 LocalLink/AXI-Stream 风格的反压机制。
  • if(!TX_DST_RDY_N) 判断极其重要:只有当下游设备准备好接收时,LFSR 才会更新数值 。如果下游忙 (TX_DST_RDY_N 为高),data_lfsr_r 保持不变,TX_D 数据保持在总线上等待,直到下游读走。

TX_SRC_RDY_N:只要不在复位状态,它就被拉低(有效),意味着这个模块是一个"始终有数据要发"的贪婪发生器 (greedy generator),只要对方敢收,我就敢发。

数据接收

aurora_8b10b_0_FRAME_CHECK:主要功能是接收数据并进行校验。它在接收端(RX)运行与发送端(TX)完全相同的伪随机数生成算法(LFSR),将计算出的"期望数据"与实际接收到的数据进行比对。如果两者不一致,就增加错误计数器。

1. 与 AXI4-Stream 接口图的对应关系

模块信号 (LocalLink) 极性/方向 图片接口信号 (AXI4-Stream) 说明
RX_D Input m_axi_rx_tdata 接收到的数据。数据从 IP 核流向此模块。
RX_SRC_RDY_N Input (低有效) m_axi_rx_tvalid 表示 IP 核输出了有效数据。代码中通过 !RX_SRC_RDY_N 转换为高有效。
(无) - m_axi_rx_tready 注意:此模块没有输出流控信号。这意味着它假设自己永远能跟上接收速度(Always Ready),或者测试逻辑通过忽略流控来简化设计。
USER_CLK Input user_clk 同步时钟。
RESET Input reset 复位信号。

2. 核心逻辑详细分析

该模块的代码逻辑可以分为四个主要阶段:输入打拍(Pipeline)、预期数据生成、比对检查、错误计数。

A. 输入打拍 (Slack Registers)
verilog 复制代码
always @ (posedge USER_CLK)
begin
  RX_D_SLACK          <= `DLY RX_D;
  RX_SRC_RDY_N_SLACK  <= `DLY RX_SRC_RDY_N;
end
assign  data_valid_c    =   !RX_SRC_RDY_N_SLACK;

为了改善时序(Timing Closure),代码没有直接使用输入端口的信号进行逻辑运算,而是先用寄存器(_SLACK)锁存了一拍。

data_valid_c ​:将低电平有效的 Ready 信号转换为高电平有效的 Valid 信号,表示当前 RX_D_SLACK 中的数据是有效的。

B. 预期数据生成 (LFSR)
verilog 复制代码
always @(posedge USER_CLK)
    if(reset_c)
        data_lfsr_r <= `DLY 16'hD5E6; // 初始种子
    else if(CHANNEL_UP)
    begin
      if(data_valid_c) // 每收到一个有效数据,LFSR 就推演一次
       data_lfsr_r <= `DLY {!{data_lfsr_r[3]^data_lfsr_r[12]^data_lfsr_r[14]^data_lfsr_r[15]},
                            data_lfsr_r[0:14]};
    end

这与 FRAME_GEN 模块使用的是完全相同的 XNOR 反馈多项式。

同步机制 :只有当 data_valid_c 为高(即真的收到数据)时,LFSR 才会更新到下一个状态。这保证了 checker 产生的序列速度与 incoming 数据流的速度完全一致。

C. 错误检测 (Error Detection)
verilog 复制代码
assign data_err_detected_c = (data_valid_c && (RX_D_SLACK != data_lfsr_concat_w));

逻辑 :如果当前数据有效(data_valid_c​ 为 1),并且 接收到的数据(RX_D_SLACK​)不等于 本地计算的预期数据(data_lfsr_concat_w),则判定为误码。

D. 错误计数器 (Error Counter)
verilog 复制代码
always @(posedge USER_CLK)
    // ...
    if(&err_count_r) // 如果计数器满 (所有位为1)
        err_count_r <= `DLY err_count_r; // 保持最大值 (饱和计数)
    else if(data_err_detected_r)
        err_count_r <= `DLY err_count_r + 1; // 发现错误,计数+1

饱和机制:计数器增加到最大值(511, 9位全1)后就会停止增加。这防止了计数器溢出回绕成0,那样会误导测试人员以为没有错误。

输出assign ERR_COUNT = err_count_r[1:8];

  • 模块输出的是计数器的低 8 位。配合饱和逻辑,如果外部读到 255 (0xFF),通常意味着错误已经"爆表"了。

仿真

说明正常了。

例子的仿真与解读就先到这里,其实有个小问题,gen和check的随机种子并不一致,暂时不清楚为什么这样,猜测可能是时序上的原因。后续补充这部分。

相关推荐
世冠科技17 小时前
建模仿真技术成为汽车产教融合新引擎,世冠科技董事长李京燕发表主题报告
仿真·国产软件
Wishell20153 天前
FPGA教程系列-Vivado Aurora 8B/10B IP核设置
仿真
Wishell20154 天前
FPGA教程系列-Vivado Aurora 8B/10B IP核接口解析
仿真
Wishell20154 天前
FPGA教程系列-Vivado Aurora 8B/10B 协议解析
仿真
Altair澳汰尔7 天前
成功案例丨仿真+AI技术为快消包装行业赋能提速:基于 AI 的轻量化设计节省数十亿美元
人工智能·ai·仿真·cae·消费品·hyperworks·轻量化设计
十五年专注C++开发10 天前
fmilib: 一个FMI 标准的 C 语言实现库
c语言·仿真·fmi·fmu
Wishell201511 天前
FPGA教程系列-Vivado实现低延时除法器与generate用法
仿真
Wishell201512 天前
FPGA教程系列-番外篇Model Composer之滤波器优化设计仿真
仿真
Wishell201513 天前
FPGA教程系列-番外篇Model Composer之HDL滤波器仿真
仿真