10GBASE-R中的PCS层

IEEE Std 802.3-2022 在 49章,介绍了10GBASE-R的PCS(Physical Coding Sublayer,物理编码子层)64b/66b原理。

下面这几个 10G 以太网物理层变种均使用该同步头:

  • 10GBASE-SR(多模光纤,短距离)

  • 10GBASE-LR(单模光纤,中距离)

  • 10GBASE-ER(单模光纤,长距离)

  • 10GBASE-LRM(老的多模光纤)

  • 10GBASE-KR(背板铜缆,数据中心内部)

10GBASE-T 是 IEEE 802.3 标准中定义的 10 Gbit/s 以太网通过双绞铜缆(即普通网线)传输 的物理层规范,简单说就是“10G 铜缆以太网”。

项目

10GBASE-T

10GBASE-R(SR/LR/KR 等)

标准条款

Clause 55

Clause 49(PCS)

传输介质

双绞铜缆(RJ45 网线)

光纤或背板铜

最大距离

Cat6:55 m Cat6a/Cat7:100 m

取决于光模块(300 m 到 40 km)

支持的网线等级

Cat6(55 m) Cat6a 或更高(100 m)

不需要网线

编码方式

64B/65B + LDPC + PAM16(非常复杂)

64B/66B(简单)

功耗

早期芯片很高(约 10 W/端口),现在降到 2~4 W

光模块通常 1~3 W

延迟

比光纤版高约 2~3 μs

更低

发布年份

2006 年标准完成,2010 年后才真正普及

2002~2006 年就已成熟

PCS在Tx方向将用户数据进行加扰,添加同步头后送往PMA,在Rx方向接收PMA的数据,进行同步并去掉同步头,然后解扰恢复出并行数据送给MAC层,数据流向如下:

GEAR BOX可以理解为“变速箱”,用来做速率匹配。因为输入数据是64bit,输出数据为66bit,每隔32clk就会多出一拍数据。

PCS中的数据在PMA中做并串和串并转换,低bit先发送:

前面说到,PCS将用户数据(如XGMII)从32/64bit位宽转换成66bit。为什么是 66 位?因为前 2 位是“同步头”(sync header),后面 64 位是实际负载,所以叫 64B/66B。前 2 位的同步头用于快速锁定边界,这些数据块只在 PCS 内部存在,外面完全看不到(不感知这个同步头),具体怎么转全看 49.2.4 的编码表。这就是为什么 10GBASE-R能做到极低的编码开销(66/64 = 1.03125,仅 3.125% 开销),远比 1000BASE-X 的 8B/10B(25% 开销)高效得多。

1.1 64B/66B编码的作用

64B/66B编码要做到:

  • 编码必须保证比特流里有很多 0↔1 的跳变(high transition density)。

为什么?因为接收端没有单独的时钟线,全靠从数据里自己“抠”出时钟(Clock Data Recovery, CDR)。跳变得少,CDR 就漂移、失锁。

  • 有限连 0/连 1 长度(run-length-limited):

最长连续 0 或 1 不会超过某个值(64B/66B 加上扰码后,最长跑长大概 66 左右),避免基线漂移(DC wander)和电磁干扰问题。

  • 快速同步

每个 66 位块前 2 位的同步头,让接收端能在几百比特之内就找到“块边界在哪里”,这叫 Block Lock。 找到边界之后,后面的解码、解扰、错误检查就全都能对齐了。

编码规则如下图:

  • 一个 66-bit 块 = 连续两个 XGMII 周期的 8 个字符 XGMII 是双 32-bit(4 字节 × 2 路),两个周期正好 8 字节 → 打包成一个 66-bit 块。

  • 8 个字符的编号规则

    • D0 D1 D2 D3 D4 D5 D6 D7 → 纯数据八字节

    • C0–C7 → 普通控制字符(比如 Idle、Error)

    • S0 或 S4 → Start(帧起始),只能出现在第 1 或第 5 个位置(对应 XGMII 的 lane 0)

    • T0–T7 → Terminate(帧结束),可以出现在任意位置

    • O0 或 O4 → Ordered_set(比如 /LPI/、/LF/、/RF/),也只能出现在第 1 或第 5 个位置

    下标 0~3 属于第一个 XGMII 周期,4~7 属于第二个周期。

  • 块格式只有两大类

    • 同步头 = 01 → 纯数据块:01 + 8 个 D0~D7

    • 同步头 = 10 → 控制块:10 + 8-bit 块类型字段(block type field)+ 若干控制字符/数据混合

XGMII接口66B编码举例:

场景一:纯数据传输 (Data Block)

  • XGMII 状态: 正在传输一个大文件的中间部分。

  • 输入: 8 个字节全是数据,XGMII 的控制位(TXC)全是 0。

    • 数据内容:11 22 33 44 55 66 77 88 (16进制)

  • 查表: 对应表格第一行 D0 D1 D2 D3 D4 D5 D6 D7。

  • 编码结果:

    • Sync: 01

    • Payload: 直接就是 11 22 33 44 55 66 77 88

    • 最终 66B: 01 11 22 33 44 55 66 77 88

场景二:数据包开始 (Start of Packet)

以太网规定,数据包必须从第 0 通道 或第 4 通道 开始。

  • XGMII 状态: 开始发送一个新包。

  • 输入: 第 1 个字节是 /S/ (Start),后面 7 个字节是前导码/SFD/MAC地址数据。

    • XGMII 数据: FB 55 55 55 55 55 55 D5 (FB 是 Start 的控制码)

    • XGMII 控制位: 1 0 0 0 0 0 0 0 (只有第1个字节是控制符)

  • 查表: 找到以S_0 开头的那一行 -> S0 D1 D2 D3 D4 D5 D6 D7。

  • 编码结果:

    • Sync: 10 (因为有控制符)

    • Block Type Field: 0x78 (看表格中间那列,对应S_0 行)

    • Payload: 扔掉S_0 (因为 Type Field 0x78 已经隐含了“第一个字节是 Start”的意思),只保留后面 7 个数据字节。

    • 最终 66B: 10 78 55 55 55 55 55 55 D5

这种机制极其巧妙地把 8 bit 的控制开销压缩到了 2 bit (Sync) + 偶尔出现的 8 bit (Type Field) 中。

不过个人觉得上述的控制码表没那么重要,主要是和XGMII接口配合使用,当我们不关心接口,只把PCS+PMA用来传输数据的时候,我们只需要考虑把数据正确恢复出来即可。给我32个32bit数据,我就恢复出对应的32个32bit数据就完事了,不用考虑XGMII 64bit数据,还有8bit控制符这些。

1.2 Scramble(加扰)

上面介绍PCS提到,编码必须保证比特流里有很多 0↔1 的跳变,保证不出现连续的0或者1,那么在添加同步头之前,还需要进行加扰。

上面这张图体现了同步头和加扰以及原始数据之间的关系:根据原始数据可以确定同步头是01还是10,然后按照低位优先的顺序把数据送入加扰模块,得到输出数据后再添加上同步头,得到完整的66b数据,最后送入Gearbox做速率匹配,保证输出的还是64/32/16bit位宽。

加扰通常使用一个本原多项式,可以用线性反馈移位寄存器(LFSR)实现,通过这个移位寄存器可以将所有非连续0的序列变成具有伪随机特征的序列,PCS里面使用的多项式为:

G(x) = 1 + x^{39} + x^{58}

该过程可以表示如下:

对于不使用FEC的编码,数据加扰之后可以直接再加上同步头,形成66B数据,再经过GearBox变成64/32bit码流输出给PMA,PMA将并行数据转换成串行数据后发送到对端,接收端PMA首先需要进行串并转换。串并转换之后数据并不能直接使用,还需要先做块同步,也就是把数据恢复成发送的原始并行数据。例如PAM发送数据为16个0和16个1交替的串行数据,对端PMA恢复出来的并行数据并不是{16'h0,16'hffff},而是{16'h0,16'hffff,16'h0,16'hffff}这个串行码流中的任意一个连续的32bit数据,但是显然我们后级模块是无法处理这种数据的。

1.3 Block Sync (块同步)

接收端的处理流程如图49-6所示,首先做块同步,这个步骤会去除同步头并将PMA的数据恢复成原始的并行数据,然后对数据进行解扰。其状态机流程如下图所示:

状态机的各个状态含义如下:

LOCK_INIT

初始化状态,系统复位后进入此状态。

RESET_CNT

重置计数器,准备开始检测同步头。

TEST_SH

检测当前是否接收到有效的同步头(SH)。

VALID_SH

接收到有效同步头,计数器递增。

INVALID_SH

接收到无效同步头,计数器和错误计数器均递增。

64_GOOD

成功锁定块同步,表示连续 64 个有效同步头被检测到。

SLIP

发生滑动(slip),尝试重新同步,丢弃部分数据

图中的信号含义如下:

sh_cnt

有效同步头计数(累计值)

sh_invalid_cnt

无效同步头计数(错误次数)

rx_block_lock

是否已锁定块同步(输出信号)

test_sh

是否正在测试同步头(控制信号)

slip_done

滑动操作完成标志

PCS 接收来自 PMA 的数据流后,首先进入初始化状态并清零计数器,随后开始逐块检测同步头(Sync Header)。若连续 64 个块均检测到有效同步头且无错误,则判定为同步成功,置位 rx_block_lock 信号,进入锁定状态;若在同步建立前累计出现 16 次无效同步头,则判定为失锁,触发滑动(Slip)操作——即丢弃当前对齐位置并重新调整块边界,之后返回初始状态重新尝试同步。一旦已锁定状态下再次频繁检测到无效同步头,也可能触发滑动以恢复同步。如果在锁定下出现一个非法同步头,并不会直接失锁,会重新跳转到TEST_SH,直到超过阈值(这里是16)才会跳转到SLIP 状态。

1.4 Descramble(解扰)

前面使用的扰码是一种自同步扰码,也就是说,经过加扰后的数据,再通过一个完全相同的本原多项式,等待一段时间后会自动恢复成原始未加扰的数据,这个是其本身的性质,可以参考其他文章。解扰的流处理过程如下图所示:

以 IEEE 802.3 常用的 1 + x²⁵ + x⁵⁷ 为例:

  • 扰码多项式:G(x) = 1 + x^{25} + x^{57}

  • 发送端扰码公式:

    s(n) = d(n) \oplus s(n - 25) \oplus s(n - 57)

    其中 d(n) 是原始数据,s(n) 是扰码后输出。

  • 接收端解扰公式:

    \hat{d}(n) = r(n) \oplus r(n - 25) \oplus r(n - 57)

    其中 r(n) 是接收到的数据(理想情况下 r(n)=s(n)),代入后可以得到\hat{d}(n) = {d}(n)

注意:解扰器只依赖接收到的 r(n),不依赖原始数据或初始状态!这是因为即使接收端 LFSR 初始状态错误,经过最多 N 比特(N = 最大抽头延迟,如 57)后,内部状态会自动“被正确数据覆盖”而收敛到正确状态。

以一个简单的多项式 1+x^3为例:

扰码公式(发送端):

s(n) = d(n) \oplus s(n - 3)

解扰公式(接收端):

\hat{d}(n) = r(n) \oplus r(n - 3)

假设接收端初始寄存器为 [?, ?, ?](未知),但一旦开始接收 r(0),r(1),r(2),…,从第 3 个比特起:

\hat{d}(3)=r(3)⊕r(0)=[d(3)⊕s(0)]⊕s(0)=d(3)

即使 r(0) 被错误地用于反馈,但从 n=3 开始,所有用于反馈的 r(n−k) 都是真实的扰码输出,因此解扰结果立即正确!即只要连续接收到 N+1 个正确的扰码比特(N 为最大延迟),解扰器就能自动输出正确的原始数据,无需知道初始状态。

总结

本文介绍了IEEE Std 802.3-2022 Clause49的内容,该章节没有对PCS层中的FEC模块做过多描述,事实上当Serdes速率超过10G后,不可避免会出现误码,而上面所提到的加扰又会放大这种错误,因为错1bit,会影响到前后57bit的数据,导致连锁反应。因此还需要额外增加一些纠错手段,能够将少量错误恢复出来,这就是Forward Error Correction (FEC),即前向纠错编码。