引言:当形式验证遇上数据包协议
传统的形式验证(Formal Verification)在控制逻辑和接口协议验证中表现出色,但面对数据路径时却常被认为"不可能"。原因很简单:一个以太网巨型帧(jumbo frame)可能携带超过9000字节的数据,其潜在状态空间高达(2^72288)种组合,直接验证如同大海捞针。
但问题核心并非数据本身,而是控制逻辑的可靠性。例如:数据包解析是否正确?协议字段是否合法?如果绕开"无意义"的随机数据,仅关注关键控制字段,状态空间将大幅缩减。本文将以CAN总线协议为例,拆解如何通过七步法,让形式验证轻松应对复杂数据包协议。

一、拆解数据包:以小搏大的关键
数据包协议的核心是结构化字段。以CAN总线帧为例,其结构包含:
- 起始帧(SOF):1位
- 仲裁段(Arbitration):11位ID + 控制位
- 数据段(Data):0-8字节
- CRC校验:15位
- 确认段(ACK)等
虽然数据段可能长达64位,但其内容对协议逻辑无影响,可直接交给形式工具随机填充。真正需要约束的是固定格式字段(如ID、CRC)。通过将数据包拆分为8位或16位的结构体(struct),状态空间从指数级爆炸降至可控范围。
代码示例:定义CAN帧结构体
go
typedef struct packed {
bit [10:3] id_high;
bit [2:0] id_low;
bit rtr;
} arbitration_t;
二、建模控制逻辑:从握手信号到状态机
数据包的传输依赖控制信号(如Start-of-Frame, End-of-Frame)。以CAN总线为例,虽然没有显式握手信号,但可通过建模实现类似逻辑:
go
bit in_progress; // 传输进行中标志
always @(posedge clk) begin
if (rst) in_progress <= 0;
else if (pkt_eof) in_progress <= 0;
else if (pkt_sof) in_progress <= 1;
end
通过约束pkt_sof
和pkt_eof
的时序关系,确保形式工具生成的波形符合协议要求。例如:
go
// 假设:传输开始时,valid信号持续到结束
assume property (pkt_sof |-> pkt_valid throughout (##[1:$] pkt_eof));
三、约束定义:精准控制合法值
每个字段的合法值需通过断言(assertion)和假设(assumption)约束。例如,CAN的仲裁段ID为11位,但实际应用中可能只有少数几个有效值(如0x123、0x456)。通过约束ID范围,进一步缩小搜索空间。
go
// 约束ID为预定义的几个值
bit [10:0] valid_ids[] = '{11'h123, 11'h456};
assume property (arbitration.id inside {valid_ids});
// 约束CRC校验计算
assume property (crc == calculate_crc(packet_data));
技巧:将数据段设为"自由变量"(free variable),允许形式工具自由填充,避免无效计算。
四、驱动逻辑:从结构体到比特流
数据包的发送需要将结构体转换为比特流,并处理协议细节(如CAN的位填充)。核心是通过指针遍历结构体数组,逐比特驱动输出:
go
bit [3:0] p; // 数据包结构体索引
bit [2:0] n; // 当前结构体的比特位置
always @(posedge clk) begin
if (pkt_valid) begin
tx_out <= packet[p].qbits[n];
if (n == 0) begin
p <= p + 1;
n <= 7; // 重置为下一个结构体的最高位
end else begin
n <= n - 1;
end
end
end
注意:位填充逻辑需额外处理连续5个相同比特,此处可借助计数器实现。
五、结果验证:从覆盖点到反例挖掘
形式验证的核心目标是证明协议逻辑的完备性。通过定义覆盖点(cover property)和断言(assert),可同时验证合法包和非法包的处理:
go
// 覆盖合法包的完整传输
cover property (pkt_sof ##1 pkt_valid[*] ##1 pkt_eof);
// 断言:非法包必须触发错误标志
assert property (
illegal_packet |-> ##[1:10] error_flag
);
实际案例中,作者曾用此方法验证以太网巨型帧解析器,仅需3-6分钟即可生成完整覆盖,无需编写海量测试用例。
六、经验总结:七步法实战口诀
- 控制逻辑建模------明确握手信号与状态机。
- 结构体拆分------8/16位分段,化整为零。
- 字段约束------合法值、CRC计算一个不漏。
- 约束应用------用假设(assume)绑定结构体。
- 驱动实现------比特流转换与协议细节处理。
- 数据包生成------自由变量+合法约束双管齐下。
- 断言覆盖------合法/非法包两手抓。
结语:让"不可能"成为可能
形式验证并非万能,但在数据包协议验证中,通过结构化拆解和精准约束,可大幅降低复杂度。无论是CAN总线还是以太网,关键在于聚焦控制逻辑,放过随机数据。这种方法不仅节省数月测试开发时间,还能捕获传统仿真难以触达的极端场景。
正如作者在文中所说:"没有不可能,只有未尝试。" ------ 或许,下一次当你面对海量数据路径时,形式验证会成为你的秘密武器。
参考文章:
Doing the Impossible:
Using Formal Verification on
Packet Based Data Paths
「数字芯片设计【不定期更新文件】」链接:https://pan.quark.cn/s/27331927a18e