LFSR/PRBS SystemVerilog模板:Galois 与 Fibonacci 两种结构及最长序列验证
更新时间:2026-11-10。这是一篇「拿来即用」的模板文:线性反馈移位寄存器(LFSR,Linear Feedback Shift Register)是伪随机二进制序列(PRBS)、CRC 反馈、扰码与测试图案发生器共同的硬件骨架。本篇给出 Galois(内反馈型)与 Fibonacci(抽头型)两份完整 SystemVerilog 实现,讲清多项式怎么变成抽头掩码、种子为什么不能是全零、最长序列周期怎么验证。LFSR 与 CRC 共用移位异或结构,CRC 侧的工程形态在 CRC8 SystemVerilog 模板 与 CRC16 SystemVerilog 模板,移位寄存器与时序基础可回看 计数器与移位寄存器。
本文要回答的问题
- LFSR 靠什么产生看起来随机、实则确定的比特流?
- Galois 和 Fibonacci 两种结构的反馈接线差在哪,什么时候选哪个?
- 一个多项式(如 x⁷+x⁶+1)怎么翻译成代码里的抽头掩码?
- 为什么种子全零会让发生器彻底锁死,工程上怎么自启动?
- 「最长序列周期 2ⁿ−1」是写在纸上的结论,还是能在仿真里量出来?
先把两种结构的关键差异摆在一起:
读这张卡抓一条主线:两种结构描述的是同一个多项式的两种硬件排法,在选用本原多项式、种子相同的前提下,它们都能跑出长度为 2ⁿ−1 的最长序列(m 序列),区别只在异或门放在级间还是集中在反馈端。
一、LFSR 的工作原理与多项式
一个 n 位 LFSR 就是一排寄存器加一条反馈组合路径:每来一个时钟,寄存器整体移一位,被移出的端头补上「某些抽头位异或」的结果。抽头位置由一个 GF(2) 多项式规定,本篇的 PRBS7 用 x⁷+x⁶+1,PRBS15 用 x¹⁵+x¹⁴+1。当多项式取本原多项式时,发生器在回到种子之前会遍历除全零以外的所有 2ⁿ−1 个状态,这个状态序列就是 m 序列,从最低位逐拍取出的比特流就是 PRBS。
这张图是两种结构共同的数据流:种子决定起点,多项式决定抽头,反馈决定下一个状态,输出端逐拍吐出比特流。它和 CRC 反馈移位寄存器的区别只在用途——CRC 让数据流穿过寄存器取最终余数,LFSR 让寄存器自由运转、把移位过程本身当输出,二者的移位异或内核是同一个。
二、Galois 结构:异或嵌在级间
Galois(又称内反馈型、MISR)把异或门分散到寄存器级之间。右移口径下,每拍先看最低位 state[0]:它为 1 时,寄存器右移一位再整体异或抽头掩码 TAPS;为 0 时只右移。输出直接取最低位。
// Galois LFSR:右移,state[0]=1 时移位并异或 TAPS
module lfsr_galois #(
parameter int WIDTH = 7,
parameter logic [WIDTH-1:0] TAPS = 8'hC1
)(
input wire clk,
input wire rst_n,
input wire enable,
input wire [WIDTH-1:0] seed,
input wire load,
output logic [WIDTH-1:0] state,
output wire bit_out
);
assign bit_out = state[0];
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n)
state <= '0;
else if (load)
state <= seed;
else if (enable) begin
if (state[0])
state <= (state >> 1) ^ TAPS; // 反馈位为 1:移位 + 掩码异或
else
state <= (state >> 1);
end
end
endmodulePRBS7 实例化时传 WIDTH=7, TAPS=7'h41。这个掩码来自多项式 x⁷+x⁶+1 在右移口径下的位映射——反馈涉及的次幂对应到掩码里的相应位。Galois 的好处是异或分散在各级、关键路径短,综合频率高,这也是 CRC 余数单元普遍采用同款结构的原因。
三、Fibonacci 结构:抽头异或后统一反馈
Fibonacci(抽头型)把所有抽头位先做一次异或归约,得到单个反馈位,再把它补进右移后空出的最高位,结构更贴近教科书上的多项式图示。
// Fibonacci LFSR:抽头位异或归约,反馈补进最高位
module lfsr_fibonacci #(
parameter int WIDTH = 7,
parameter logic [WIDTH-1:0] TAP_MASK = 7'h03
)(
input wire clk,
input wire rst_n,
input wire enable,
input wire [WIDTH-1:0] seed,
input wire load,
output logic [WIDTH-1:0] state,
output wire bit_out
);
logic feedback;
assign bit_out = state[0];
assign feedback = ^(state & TAP_MASK); // 抽头位奇偶异或
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n)
state <= '0;
else if (load)
state <= seed;
else if (enable) begin
state <= {feedback, state[WIDTH-1:1]}; // 右移,反馈补最高位
end
end
endmodule注意右移口径下同一个多项式 x⁷+x⁶+1 的抽头掩码是 7'h03,和 Galois 的 7'h41 并不相同——两种结构对多项式的位映射方向相反,照抄掩码会得到非最长周期。调试时这里确实栽过一次:初版反馈方向接反,Fibonacci 只走出 8 个状态就重复,改成「抽头异或补最高位」的标准右移形式后周期恢复到 127。^(state & TAP_MASK) 是 SystemVerilog 的一元归约异或,先屏蔽非抽头位再求奇偶。
两个掩码为什么差这么多,可以从移位方向推。Fibonacci 右移时,反馈补进的是最高位 bit6,多项式 x⁷+x⁶+1 里真正参与异或的是移出端附近的两个低次项,对应到状态位就是 bit0 和 bit1,于是掩码是二进制 0000011 即 7'h03。Galois 内反馈的异或点散布在级间,同一多项式在它的位映射下落到 bit6 和 bit0,掩码成了 01000001 即 7'h41。结论是:换一个多项式时,两种结构的掩码要分别按各自的位映射重新算,不能只改一个再互相复制。
种子的选择也有讲究。任何非零种子都能让本原 LFSR 跑满完整的 2ⁿ−1 周期,区别只是相位——同一个 LFSR 装不同非零种子,产生的是同一条 m 序列的不同起点,序列的统计性质完全一致。所以工程上挑种子主要看两点:一是复位后能否快速进入有效状态,常用全 1(如 PRBS7 用 7'h7F)省去额外逻辑;二是若多个同源发生器需要相位错开(例如收发两端的扰码与解扰),就让它们装载不同种子,再配合一次已知的对齐序列重新同步。唯一的硬约束仍是避开全零;只要种子非零,发生器上电后就能自动进入完整的状态环,不需要额外的对齐或预热周期。
两种结构的接线与适用场景对照如下:
| 维度 | Galois 内反馈 | Fibonacci 抽头型 |
|---|---|---|
| 异或位置 | 分散在寄存器级间 | 集中在反馈端一处 |
| 反馈控制 | 最低位决定是否异或掩码 | 抽头归约后补最高位 |
| PRBS7 掩码 | TAPS=7'h41 | TAP_MASK=7'h03 |
| 关键路径 | 短,易跑高频 | 抽头多时异或链较长 |
| 可读性 | 掩码需按结构换算 | 掩码直观对应多项式 |
| 典型用途 | CRC/MISR、高速 PRBS | 教学、传统 PRBS 文档 |
四、波形与全零陷阱
下面的波形给出 Galois PRBS7 从装载种子到连续输出的节奏:load 拉高那拍装入非零种子,随后 enable 期间每拍右移一次,bit_out 逐拍给出确定但看似无规律的比特。
读这张波形要联系 m 序列的统计性质:单个比特看起来在 0、1 间跳变,但把一个完整周期的 bit_out 数下来,1 的个数恰好比 0 多一个——7 位 m 序列一个周期 127 拍里有 64 个 1、63 个 0,这种近似平衡正是它能当测试图案和扰码源的原因。
全零陷阱是 LFSR 工程化必须处理的点:若种子是全零,移位后还是零、反馈异或也还是零,发生器永久锁死在零状态,永远进不了 2ⁿ−1 的状态环。换句话说,n 位寄存器本可以表示 2ⁿ 个状态,LFSR 只用了其中 2ⁿ−1 个,唯一被排除的就是全零——这也是最长周期为什么是 2ⁿ−1 而不是 2ⁿ 的直接原因。测试平台专门验证了这一点——装载全零种子后连续 20 拍,状态与输出始终保持 0。实际芯片里通常加「状态检测到全零则强制注入一个 1」的自启动逻辑,或在复位后装载固定非零种子(本模板即采用后者,load 一个非零 seed)。
五、验证:把最长周期量出来
验证不停留在「能振荡」,而是直接测量周期与状态覆盖。测试平台用 load 装入种子后使能运转,记录回到种子所需拍数(周期)、经过的独立状态数,以及输出 1 的个数;PRBS7 同时对 Galois 和 Fibonacci 两种结构测量,再补一个 PRBS15 的长周期用例和全零陷阱用例。
实录里几个理论值全部被仿真量出来:PRBS7 无论 Galois 还是 Fibonacci,周期都是 127、独立状态 127,且 Galois 一个周期输出 64 个 1;全零种子 20/20 拍保持锁死;PRBS15 周期 32767,正是 2¹⁵−1。7 条断言全部通过。
=== LFSR/PRBS 自校验 ===
[INFO] PRBS7 Galois: period=127 distinct=127 ones=64 (期望 127/127/64)
[PASS] PRBS7 Galois 周期 2^7-1=127
[PASS] PRBS7 Galois 独立状态 127
[PASS] m 序列一个周期含 64 个 1
[INFO] PRBS7 Fibonacci: period=127 distinct=127 (期望 127/127)
[PASS] PRBS7 Fibonacci 周期 127
[PASS] PRBS7 Fibonacci 独立状态 127
[INFO] 全零种子 Galois:20/20 拍保持 0 输出(期望 20,全零陷阱)
[PASS] 全零种子锁死,无法自启动
[INFO] PRBS15 Galois: period=32767 (期望 32767)
[PASS] PRBS15 周期 2^15-1=32767
=== 汇总: PASS=7 FAIL=0 ===
RESULT: ALL PASS下图是这次自校验在终端中的完整输出,可以逐条核对周期、独立状态数与全零陷阱的实测值。

读图时把三组数字连起来看:两种结构在同一多项式下都走到 127 个独立状态,证明结构差异不改变最长序列性质;ones=64 对应 m 序列的 1/0 平衡;PRBS15 的 32767 说明同一套参数化代码只改 WIDTH 和 TAPS 就能扩展到位宽更大的发生器,周期随位宽指数增长。
六、本原多项式怎么选,PRBS 用在哪里
周期能达到 2ⁿ−1 的前提是多项式本原。随便挑几个抽头位拼出来的多项式不一定本原,可能只走出一个很短的状态环就回到种子,这正是选型不能靠拍脑袋的原因。工程上不必自己证明本原性,通信标准已经把各档 PRBS 的本原多项式固定下来,直接照表取用即可。
| 名称 | 本原多项式 | 位宽 n | 周期 2ⁿ−1 | 典型用途 |
|---|---|---|---|---|
| PRBS7 | x⁷+x⁶+1 | 7 | 127 | 低速链路、传感器测试、本篇实验 |
| PRBS15 | x¹⁵+x¹⁴+1 | 15 | 32767 | 千兆以太网、传统 SDH 误码测试 |
| PRBS23 | x²³+x¹⁸+1 | 23 | 8388607 | 长周期数据通信误码率测量 |
| PRBS31 | x³¹+x²⁸+1 | 31 | 2147483647 | PCIe/SATA/SerDes 抖动与眼图测试 |
表里两个规律值得记住。其一,周期随位宽指数增长,PRBS31 跑完一个完整周期需要二十多亿拍,在常见时钟下要数秒甚至更久,所以仿真验证一般只用 PRBS7/PRBS15 量周期,PRBS31 靠代码审查与局部断言保证,不全周期跑。其二,标准多项式的抽头都很稀疏(只有三项),这让异或归约网络极小,无论 Galois 还是 Fibonacci 都能跑到很高频率。
m 序列除了周期长,还有两条让它适合做测试与扰码的统计性质。第一条是平衡:一个完整周期里 1 比 0 恰好多一个,n=7 时就是 64 个 1、63 个 0,和实测对得上,因此序列的直流分量极低,不会在链路上引入基线漂移。第二条是游程分布确定:连续相同比特的游程长度有固定比例,长连 0、长连 1 都会出现但占比很小,这恰好能压测时钟恢复电路在最差跳变密度下的表现。
工程落点主要有三类。SerDes 和高速收发器的误码率测试用 PRBS 做已知激励,接收端用一个同源 LFSR 还原出期望比特流、逐拍比对统计误码;数字逻辑的内建自测试(BIST,Built-In Self-Test)用 LFSR 产生伪随机测试向量、用 MISR(多输入签名寄存器,本质就是 Galois 结构)压缩响应成一个签名;数据扰码(scrambler)在发送端把 payload 与 PRBS 异或、接收端再异或一次还原,用来打散长连 0/1、摊平频谱。这三类应用的内核都是本篇两个模块,区别只在反馈是否与外部数据混合——纯运转是 PRBS,让数据穿过反馈环就是扰码器和 CRC。
自启动设计也顺带交代清楚。靠复位装载非零种子的方案在复位可靠时足够,但某些场景要求「哪怕误入全零也能自己爬出来」,做法是加一级全零检测:当 state == '0 时,下一次移位强制把最低位(或任一固定位)注入 1。综合上这只是一个 n 输入或门加一路复用选择,面积代价很小,却能彻底消除全零锁死这个唯一的卡死状态。
实验环境
- 机器/系统:Mac mini M4 / macOS 15
- 工具版本:Icarus Verilog 13.0(
iverilog -V输出Icarus Verilog version 13.0 (stable) (v13_0)),编译选项-g2012 - 日期:2026-11-10
- 完整命令:
make run(Makefile 内部依次执行iverilog -g2012 -o lfsr.vvp lfsr.sv tb_lfsr.sv与vvp lfsr.vvp)
代码获取
本文全部代码(Galois 与 Fibonacci 两份 LFSR 模板、周期与全零陷阱自校验测试平台与 Makefile)已同步到公开仓库 geek-doc.cn/experiments/tpl-lfsr-prbs-sv,克隆后在该目录执行 make run 即可复现 PRBS7/PRBS15 周期与全零陷阱输出。
这一篇在知识体系里的位置
本篇是芯片设计入门簇中「时序与随机源」节点的 LFSR 模板页:移位寄存器与时序基础见 计数器与移位寄存器,同一移位异或内核用于数据校验的工程形态见 CRC8 SystemVerilog 模板 与 CRC16 SystemVerilog 模板,一位异或奇偶的起点见 比较器与奇偶校验电路。把这四篇连起来,能看清「寄存器移位 + GF(2) 异或」这一个硬件内核如何同时支撑校验、伪随机与扰码三类功能。
总结
LFSR 用一排寄存器加一条 GF(2) 反馈路径产生确定却近似随机的比特流,选用本原多项式时可遍历除全零外的全部 2ⁿ−1 个状态、输出 m 序列。Galois 把异或嵌在级间、时序更优,Fibonacci 把抽头异或后统一反馈、抽头直观,两者同多项式同种子下周期相同,但右移口径的掩码不同(PRBS7 分别为 7'h41 与 7'h03),不可照抄。全零种子会让发生器永久锁死,工程上靠复位装载非零种子或全零检测自启动解决。模板已实测 PRBS7 周期 127、PRBS15 周期 32767、单周期 64 个 1 与全零陷阱,改位宽只需换 WIDTH 与对应掩码。