128B/130B 编码
我们来对 128B/130B 编码 进行一次详细而深入的探讨。这是一种在现代高速串行通信中至关重要的编码方案,尤其以在 PCI Express 4.0/5.0/6.0 和 USB4 等标准中的应用而闻名。
我们将从“为什么需要它”开始,逐步深入到其核心原理、工作机制、优缺点,并与其他编码进行对比。
1. 背景与要解决的问题
在深入128B/130B本身之前,我们必须理解它所要解决的根本问题。
高速串行通信面临几个核心挑战:
直流平衡:信道和接收器通常希望传输的“0”和“1”数量大致相等。如果数据流中长期是“0”多或“1”多,会导致信号基线漂移,影响接收器正确判断信号电平,从而增加误码率。
时钟恢复:接收器需要从数据流本身提取时钟信号,而不是依赖单独的时钟线。如果数据流中出现长串连续的“0”或“1”(称为“游程”),接收器的锁相环可能因为缺乏电平跳变而失去同步,导致时钟漂移。
控制字符嵌入:物理层需要一种方法来区分“数据”和“控制信息”(例如,数据包的开始、结束、空闲状态等)。
传输效率:早期编码方案(如 8B/10B)通过增加额外开销(25%)来解决上述问题,但在追求极高数据速率(如每秒数十吉比特)时,这个开销变得不可接受。
128B/130B 编码就是为了在极高的数据速率下,以更低的开销有效地解决上述问题而设计的。
2. 核心思想与工作原理
2.1 基本概念
“128B”: 将 128 位 的原始数据作为一个块。
“130B”: 在 128 位数据前加上 2 位 的同步头,形成一个 130 位 的传输块。
开销: 。这远低于 8B/10B 的 25% 开销。
(130 - 128) / 128 = 1.5625%
2.2 同步头 – 核心中的核心
这 2 位的同步头是整个编码方案的灵魂,它有两个作用:
块类型识别: 告诉接收器后面的 128 位数据是如何组织的。
提供直流平衡信息: 同步头本身的取值,直接决定了整个 130B 块是否需要进行直流平衡补偿。
同步头只有两种可能的值:
: 表示这是一个 数据块。后面的 128 位全部是有效载荷数据。
01
******: 表示这是一个 有序集块。有序集是用于链路管理的控制命令,例如电气空闲、流量控制、训练序列等。此时,128 位中的前 8 位(16 位有序集)或更多位被用来定义具体的命令,其余位可能被填充。
10
注意: 和
00 是无效的同步头,用于错误检测。
11
2.3 加扰 – 实现直流平衡的关键
128B/130B 编码 本身并不保证 130 位传输块内的直流平衡!这是一个关键点,与 8B/10B 完全不同。
那么它是如何解决直流平衡和长游程问题的呢?答案是:加扰。
加扰器: 在编码器之前,发送端使用一个已知的、线性的反馈移位寄存器对原始的 128 位数据流进行加扰。这本质上是一个伪随机序列与数据进行的异或操作。
作用:
打破规律性: 将可能出现的重复性数据模式(如全0、全1)随机化。
减少游程: 极大地降低了出现长串连续0或1的概率。
实现统计上的直流平衡: 虽然单个 130B 块可能不平衡,但经过加扰后,在足够长的时间窗口内,数据流中的 0 和 1 在统计上是趋于平衡的。
接收端 有一个完全相同的解扰器,在接收到数据后,用同样的伪随机序列进行异或操作,即可恢复出原始数据。
2.4 完整的流程:发送与接收
发送端:
组块: 将发送数据组成 128 位的块。
判断块类型: 确定该块是数据块还是有序集块。
加扰: 仅对数据块 进行加扰。有序集块不加扰,因为控制信息必须是接收端可以立即识别的确定模式。
添加同步头:
如果是数据块,添加 同步头。
01
如果是有序集块,添加 同步头。
10
发送: 将完整的 130 位块通过串行器发送出去。
接收端:
时钟恢复与对齐: 从数据流中恢复时钟,并找到 130 位块的边界。
读取同步头: 读取每个块的 2 位同步头。
判断与处理:
如果同步头是 ,则将后面的 128 位送入解扰器,然后作为数据处理。
01
如果同步头是 ,则后面的 128 位被直接解释为有序集(控制命令),无需解扰。
10
如果同步头是 或
00,则标记为错误。
11
处理有序集: 执行相应的链路管理操作。
3. 与 8B/10B 编码的深度对比
| 特性 | 8B/10B 编码 | 128B/130B 编码 |
|---|---|---|
| 基本单元 | 8 位数据 -> 10 位码 | 128 位数据 -> 130 位块 |
| 开销 | 25% | ~1.56% |
| 直流平衡 | 基于规则的字符级保证。每个10B字符都强制满足“不均等性”不超过1。 | 基于加扰的流级统计保证。不保证单个块的平衡,但保证长期统计平衡。 |
| 游程控制 | 严格保证。游程长度被限制在5个相同比特以内。 | 统计上控制。通过加扰使长游程概率极低,但理论上仍可能出现。 |
| 控制字符 | 使用特殊的 K-字符,可以嵌入到数据流中任何位置。 | 使用 有序集块,占用整个130B块的资源。 |
| 复杂度 | 编码/解码逻辑相对简单,但需要查表或组合逻辑。 | 编码/解码逻辑更简单(主要是加扰/解扰),但对同步和块对齐要求极高。 |
| 适用场景 | PCIe 1.0/2.0, SATA, USB 3.0, Gigabit Ethernet | PCIe 4.0+, USB4 等超高速标准 |
为什么在高速率下转向 128B/130B?
在 25 Gbps 及以上的速率下,8B/10B 25% 的开销意味着你每发送 4 个比特,就有 1 个是无效的。要达到同样的有效带宽,你需要更高的物理层速率,这会急剧增加功耗、设计复杂性和信号完整性挑战。128B/130B 以极低的开换实现了相似的目标,是技术演进的自然选择。
4. 优势与劣势
优势:
极高的编码效率: 1.56% 的开销是其最大优点,为提升有效带宽立下汗马功劳。
简化逻辑: 编码和解码逻辑比 8B/10B 更简单,主要依赖于加扰器,这在高速硬件设计中至关重要。
强大的随机化: 加扰能有效消除数据的频谱尖峰,减少电磁干扰。
劣势/挑战:
块对齐敏感性: 接收器必须精确找到 130 位块的起始位置。一旦失步,恢复过程比 8B/10B 更复杂,通常需要依赖训练序列或特定的对齐流程。
无绝对游程保证: 虽然概率极低,但理论上仍有可能出现较长的游程,对接收器的时钟恢复能力提出了更高要求。
控制开销较大: 发送一个小的控制命令(如 16 位有序集)也需要占用整个 128 位的块,效率较低。但这在高速链路中是可以接受的,因为控制信息相对于数据流量占比很小。
5. 实际应用:PCI Express 的例子
在 PCIe 链路训练和初始化过程中,会发送大量的训练有序集(TS1, TS2),这些就是使用 同步头的有序集块。一旦链路建立,大部分时间传输的都是带有
10 同步头的、经过加扰的数据块。
01
当链路进入节能状态(如 L0s)后恢复时,会发送一个特殊的“电气空闲退出有序集”,接收端通过检测这个确定的、未加扰的模式来快速重新同步并恢复通信。
总结
128B/130B 编码是一种为超高速串行通信设计的、以“加扰”为核心、以“低开销块传输”为形式的高效编码方案。
它通过:
2位同步头 来区分数据与控制。
大块传输(128B) 来显著降低开销。
流加扰 来统计性地解决直流平衡和游程问题。
它代表了从“字符级、确定性编码”(8B/10B)到“块级、统计性编码”的技术范式转变,是支撑当今数据中心、高性能计算和消费电子设备中每秒数十吉比特数据传输速率的关键基石技术之一。
场景设定
假设我们要通过一条使用 128B/130B 编码的链路(比如 PCIe 总线)发送两部分信息:
一段很短的数据,内容是 (16位)。
0x1234
一个链路控制命令:电气空闲有序集。
由于 128B/130B 以 128 位 为一个块,我们的数据需要先被组装和填充成一个完整的块。
例子 1:发送一个数据块
第1步:组块与填充
原始数据: (十六进制),二进制表示为
0x1234(16位)。
0001 0010 0011 0100
一个数据块需要 128 位。我们的数据远不足 128 位。因此,发送端逻辑会将它填充到一个 128 位的块中。为了简化例子,我们假设填充后,这个 128 位块的前 16 位是我们的数据,后面 112 位全是 。
0
我们定义的 128位数据块 (Block) 如下(为了可读性,分组显示):
原始数据: 00010010 00110100 填充数据: 00000000 ... (112个0)
整个块可以简化为: (共128位)
000100100011010000000000...0
第2步:加扰
关键:数据块在发送前需要被加扰。
加扰器使用一个已知的伪随机二进制序列(PRBS)。这个序列由发送端和接收端共享的线性反馈移位寄存器(LFSR)产生。
假设在处理这个块时,LFSR产生的 128位加扰序列 (Scrambler Sequence) 是:
(一个真实的伪随机序列,这里我们用简化的
10101100... 模式示意)。
10101100...
加扰操作:将数据块与加扰序列进行逐位异或(XOR)。
数据块 (Block): 00010010 00110100 00000000...
加扰序列 (Scrambler): 10101100 11010011 01010101... (示例序列)
↓↓↓↓↓↓↓↓ ↓↓↓↓↓↓↓↓ ↓↓↓↓↓↓↓↓
加扰后数据 (Scrambled): 10111110 11100111 01010101...
异或规则:相同为0,不同为1。
现在,我们得到了 加扰后的128位数据。注意,即使原始数据中有大段的 ,加扰后的数据也变得看起来是随机的,充满了
0 和
0 的跳变。
1
第3步:添加同步头
因为这是一个数据块,我们添加同步头 。
01
最终的 130位传输块 (Transmission Block) 如下:
同步头 加扰后的128位数据 01 10111110 11100111 01010101...
第4步:发送
这个 130 位的块被串行化(变成一长串 和
0)并通过物理链路发送出去。
1
接收端过程:
接收器从数据流中恢复时钟,并正确地对齐到 130 位块的边界。
它读取前 2 位,发现是 ,于是知道这是一个数据块,后面的 128 位需要被解扰。
01
接收端使用一个与发送端完全相同的、同步的 LFSR,生成了完全相同的加扰序列。
接收端对接收到的加扰数据进行解扰(同样是逐位异或操作):
接收到的加扰数据: 10111110 11100111 01010101...
本地加扰序列: 10101100 11010011 01010101... (与发送端相同)
↓↓↓↓↓↓↓↓ ↓↓↓↓↓↓↓↓ ↓↓↓↓↓↓↓↓
解扰后数据 (Descrambled): 00010010 00110100 00000000...
瞧!原始数据 (即
00010010 00110100... 加上填充) 被完美恢复。上层的逻辑会忽略掉填充位,提取出有效的
0x1234 数据。
0x1234
例子 2:发送一个有序集块(控制命令)
现在,假设链路需要进入低功耗状态,需要发送一个 电气空闲有序集(Electrical Idle Ordered Set)。
第1步:定义有序集
在 PCIe 中,一个电气空闲有序集是一个16位的特定编码模式。我们假设它的值是 (注意:这是一个简化的假设值,实际值是协议预定义的)。
0x1234
和数据块一样,我们需要将它放入一个 128 位的块中。通常,一个有序集块会包含多个相同的有序集副本以增强可靠性,或者与其它控制信息一起填充。我们简化为:前16位是有序集,后面112位是特定填充模式(比如全0)。
我们定义的 128位有序集块 如下:
有序集: 00010010 00110100 填充: 00000000 ... (112个0)
第2步:加扰?不!
关键区别:有序集块绝不加扰。因为控制命令必须是接收端能够立即识别出的确定无疑的、预定义的模式。如果被加扰,它就变得随机而无法识别了。
所以,这 128 位保持原样。
第3步:添加同步头
因为这是一个有序集块,我们添加同步头 。
10
最终的 130位传输块 如下:
同步头 未加扰的128位有序集数据 10 00010010 00110100 00000000...
第4步:发送
这个 130 位的块被发送出去。
接收端过程:
同样,接收器对齐块边界。
它读取前 2 位,发现是 ,于是知道这是一个有序集块,后面的 128 位不需要解扰,应直接送往有序集解析器。
10
解析器读取这 128 位,识别出前 16 位是 ,它查表得知这是一个“电气空闲”命令。
0x1234
接收端电路随即执行相应的动作,比如让接收电路进入低功耗状态。
总结与对比
通过这两个例子,我们可以清晰地看到:
| 特性 | 数据块 | 有序集块 |
|---|---|---|
| 内容 | 用户数据 | 控制命令(如电气空闲、流量控制) |
| 加扰 | 必须,为了随机化数据 | 绝不,为了保持可识别性 |
| 同步头 | |
|
| 接收端动作 | 解扰 -> 提交给数据处理层 | 直接提交给有序集解析器 |
这个简单的例子揭示了 128B/130B 编码的精妙之处:它通过一个极其简单的 2 位标签(同步头),优雅地管理了高速链路中数据流和控制流的混合传输,同时通过流加扰以极低的开销(仅1.56%)解决了直流平衡和时钟恢复问题。


