4. PRBS 生成器的硬件实现(LFSR)
讲 PRBS 的硬件实现,绕不开线性反馈移位寄存器。说白了,LFSR 就是一堆触发器串成链,再通过异或门把某些抽头反馈回去。我刚开始接触这玩意儿时,总觉得它就是个高级计数器,后来发现没那么简单——计数器的状态是固定的,LFSR 的状态却像随机游走,这才是伪随机序列的根源。
4.1 LFSR 的核心结构
一个标准的 LFSR 由三部分组成:
- 移位寄存器链 — N 个 D 触发器级联,每个时钟上升沿向右移动一位
- 抽头位置 — 根据本原多项式选择哪些级参与反馈
- 异或网络 — 将抽头输出异或后馈送到第一级输入
举个例子你就明白了。PRBS7 的生成多项式是 x⁷ + x⁶ + 1,意思就是第 7 级和第 6 级的输出做异或,结果反馈到第 1 级。为什么是这两级?因为这是个本原多项式,能保证最大周期 2⁷ - 1 = 127 位。我建议初学时先拿 PRBS7 练手,周期短,仿真快,波形一眼就能看出规律。
4.2 常用 PRBS 阶数与多项式
不同测试场景用不同阶数。下表列出我项目中常用的几种:
| 名称 | 级数 (N) | 本原多项式 | 序列长度 | 典型应用 |
|---|---|---|---|---|
| PRBS7 | 7 | x⁷ + x⁶ + 1 | 127 | 8B/10B 编码链路,低速 SerDes |
| PRBS15 | 15 | x¹⁵ + x¹⁴ + 1 | 32767 | PCIe 3.0/4.0,10G 以太网 |
| PRBS23 | 23 | x²³ + x¹⁸ + 1 | 8388607 | 光纤通道,25G 速率 |
| PRBS31 | 31 | x³¹ + x²⁸ + 1 | 2147483647 | 100G/400G 以太网,高速背板 |
选阶数时有个原则:序列长度要远大于码间干扰的持续时间。你想想看,如果被测链路的记忆效应只有几个 UI,用 PRBS7 就够了;但要测 CDR 抖动跟踪能力,PRBS31 更合适。我记得有一次项目里用 PRBS7 测 25G 链路,眼图很干净,换 PRBS31 立马发现低频抖动超标——说白了,短序列自相关太好,掩盖了问题。
4.3 硬件实现 —— 串行与并行
最直接的方式就是串行 LFSR。下图是一个 PRBS7 串行生成器的典型结构:
串行实现很简单:每个时钟移一位,输出就是序列。但速率一高(比如 28Gbps),单周期时间不到 36ps,这时串行 LFSR 的异或门传播延时就会成为瓶颈。我曾在 32G NRZ 设计里吃过亏,仿真能过,流片回来发现高频段序列质量变差。后来改成并行 N 路结构,每路同时计算多个位的反馈,才把问题解决。
4.4 Verilog 代码实现
下面是一个 PRBS7 的串行生成模块。我个人习惯用 always_ff + always_comb 分开写,更直观。
module prbs7_gen (
input wire clk,
input wire rst_n,
input wire en,
output wire prbs_out
);
reg [6:0] shift_reg;
// 反馈逻辑:x^7 + x^6 + 1
wire feedback = shift_reg[6] ^ shift_reg[5];
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n)
shift_reg <= 7'b1; // 避免全0
else if (en)
shift_reg <= {shift_reg[5:0], feedback};
end
assign prbs_out = shift_reg[6];
endmodule
4.5 并行 LFSR 设计思路
当数据路径宽度为 M 位时,需要在一个时钟内计算出 M 个新的序列位。做法是先把串行反馈逻辑展开 M 拍。举个例子,PRBS7 每拍输出 8 位:
// 伪代码:每个周期同时产生 8 个 bit
always_comb begin
next_reg[0] = shift_reg[6] ^ shift_reg[5];
next_reg[1] = shift_reg[5] ^ shift_reg[4];
// ... 展开 8 步
next_reg[7] = ... ;
end
展开时要注意抽头位置随着移位而改变。你可以用数学归纳法推导,也可以用 Python 脚本自动生成展开后的逻辑。我个人推荐写个脚本,手动展开容易漏项。
4.6 硬件实现中的避坑指南
- 初始状态:上电时要保证至少一个寄存器为 1。我曾经用全 0 复位,仿真死得悄无声息。
- 扇出过大:高位数的 PRBS(比如 PRBS31)反馈网络有 31 级异或门,组合逻辑路径很长。建议拆成两级异或树。
- 跨时钟域:如果 LFSR 工作在高速时钟域,输出到低速域采样时要加同步器,否则亚稳态会破坏序列相位。
- 自同步问题:某些接收端需要 LFSR 与发射端对齐。发送端的初始相位必须可配置,不能写死。我习惯把 seed 值做成寄存器,方便调试。
经验总结: 串行 LFSR 适合速率低于 10Gbps 的场景;高于 10Gbps 必须用并行结构。并行结构的关键是正确展开反馈多项式,并用综合工具检查最大频率是否达标。
4.7 测试与验证要点
写完了代码怎么确认它是对的?我的做法是三步:
- 周期检查:用 testbench 跑满一个周期(PRBS7 跑 127 拍),看序列是否重复。如果提前重复,说明多项式写错了。
- 自相关检验:计算序列的自相关函数,除了 0 偏移处为 1,其余位置应该接近 0。这个用 Python 算很方便。
- 眼图测试:把生成的 PRBS 信号灌入实际通道,用示波器捕获眼图。如果眼图轮廓有固定的“眼线”而不是均匀的噪声,说明序列中长连 0 / 长连 1 太多——可能是抽头没选对。
好了,这一章的核心就是 LFSR 的硬件实现。说白了,结构不难,细节却不少。你要是也打算在 FPGA 里拉一条 PRBS 链路,建议先从 PRBS7 串行开始,把仿真跑通,再挑战并行和更高阶数。