3. 链路层数据包格式
调试UCIe链路层,最基础的就是搞清楚数据包长什么样。我刚开始接触UCIe时,对着协议文档看了三天,还是一头雾水。后来在实验室里抓了一次波形,把每个字段和文档一一对应,才算真正理解。说白了,帧结构就是你从逻辑层往下扔东西,链路层给它套上一层层的外壳。
帧结构总览
一个完整的UCIe链路层数据包,从帧起始到帧结束,通常包含下面这些字段。注意,不是所有字段都是必须的,具体看配置。
核心观点: 链路层数据包 = 头部(控制信息)+ 数据负载 + 尾部(校验保护)。拆包时按顺序解析就行。
各字段详解
SOP / EOP(帧起始/结束定界符)
每个包由SOP开始,EOP结束。我在调试时发现,有时候链路层报CRC错误,根源却是EOP位置不对。你想想看,EOP被截断或丢失,整个包都会被当作无效。
- SOP:编码模式为
0xFB(K码),表示一个包开始。 - EOP:编码模式为
0xFD(K码),表示包结束。 - 这两个字段不参与CRC计算,但物理层必须正确识别。
小技巧: 用逻辑分析仪抓SOP/EOP时,注意K码抑制(Comma)的极性——我曾经因为差分线极性接反,导致SOP一直通不过,折腾了一整天。
保留字段(Rsv)
1字节,一般填0。但有些IP供应商会用它传递内部调试信息。如果你看到非零值,先查供应商文档。
Cycle Type + Virtual Network(CT+VN)
2字节,控制包的类型和所属的虚拟网络。CT决定包是 请求、响应 还是 数据,VN则用于隔离不同QoS流量。
| Cycle Type | 含义 | 典型长度 |
|---|---|---|
00 | Request(非投递) | 可变 |
01 | Request(投递) | 可变 |
10 | Response | 可变 |
11 | Data | 64B居多 |
Protocol(协议类型)
1字节,标识上层是什么协议。比如0x00表示流控(FC),0x01表示原始内存语义。嗯,这里要注意:这块定义和协议栈关系很大,不同厂家可能自定义。
Sequence Number(序列号)
1字节,从0累加,用于重排序和丢包检测。我曾在项目中看到序列号跳变3次后才触发链路层重传——后来发现是重传超时设得太长。
Vendor Define(厂商自定义)
1字节,留给芯片厂商放私有信息。调试时如果遇到不明白的包,先看这个字段。有时厂商会用它做debug Tag。
Payload(数据负载)
长度0~64字节。注意,如果是流控报文(FC),Payload为0。数据报文最大64B,超过的话需要切包。
CRC(循环冗余校验)
长度2~4字节,覆盖整个包(不含SOP/EOP)。我习惯先在仿真环境里故意篡改一位CRC,看看链路层能不能正确报告错误——这是一个不错的边界测试手段。
避坑指南: 有的SoC为了省功耗,把CRC改成2字节(CRC-16)。如果你抓取的包CRC长度是4字节,而期望是2字节,八成是配置不一致。我曾经在这个坑里浪费了一周,最后发现是寄存器没切到正确模式。
调试中的关键字段
平时看包,重点盯这几个位置:
- SOP/EOP——包完整性
- Sequence Number——丢包与乱序
- CRC——传输完整性
- CT+VN——包类型和QoS归属
举个例子:如果Sequence Number不连续,但CRC没错,那多半是中间某个包被链路层丢弃了(可能是流控反压导致溢出)。这时候要去查Credit机制。
格式对比:Standard vs Optional
UCIe 1.0定义了两种帧格式:Standard(标准)和Optional(可选)。区别主要在Vendor Define和保留字段的安排上。
| 特性 | Standard | Optional |
|---|---|---|
| 保留字段 | 固定1字节 | 可被复用为扩展ID |
| 自定义字段 | 有(1字节) | 有(1字节) |
| 最大负载 | 64B | 64B |
| 兼容性 | 所有设备必须支持 | 可选项,需双方约定 |
个人建议:初期调试全部用Standard格式,少踩兼容性的坑。等链路稳定了,再考虑用Optional格式压性能。