4、并发断言基础:并发断言语法、并发断言与时钟的关系、并发断言与复位的关系

4.1 并发断言到底是什么?

好,咱们来聊聊并发断言。说实话,刚接触验证那会儿,我对并发断言和即时断言的区别一直有点模糊。后来在项目里踩了坑才真正搞明白。

并发断言,说白了就是基于时钟周期的断言。它不像即时断言那样,在代码执行到那一行就立刻检查。并发断言是跟着时钟沿走的,在每个时钟沿上采样信号,然后判断序列是否成立。

我个人习惯把并发断言想象成一个“时钟驱动的监视器”。它不关心你代码里哪一行在跑,它只关心在每个时钟上升沿,信号之间的关系对不对。

核心区别一句话:

  • 即时断言:执行到就检查,像交警临时拦车
  • 并发断言:时钟沿才检查,像电子眼定时抓拍

4.2 并发断言的基本语法

并发断言用 propertyassert 来定义。我给你看个最简单的例子:

// 定义一个属性:当req拉高后,两个时钟内ack必须拉高
property p_req_ack;
  @(posedge clk) req |=> ##[1:2] ack;
endproperty

// 断言这个属性
a_req_ack: assert property(p_req_ack);

这里有几个关键点,我一个个说:

  • @(posedge clk):指定时钟,并发断言必须有时钟
  • |=>:这叫“重叠蕴含”,意思是前件成立后,下一个时钟沿检查后件
  • ##[1:2]:延迟1到2个时钟周期

嗯,这里要注意,|=>|-> 不一样。前者是“下一个时钟沿”,后者是“当前时钟沿”。我在项目中见过有人搞混这两个,结果仿真结果完全对不上。

4.3 并发断言与时钟的关系

时钟是并发断言的心脏。没有时钟,并发断言就没法工作。

为什么会这样?因为并发断言需要靠时钟来采样信号、推进时间。你想想看,如果没有时钟沿,那“下一个周期”这个概念就不存在了。

我的经验:

我曾经在一个多时钟域的项目里,把两个不同时钟域的断言写在一起。结果仿真跑出来一堆假失败。后来才发现,是时钟域没分开。从那以后,我每个时钟域都单独写property,绝不混用。

时钟在并发断言中的使用方式:

写法 含义 适用场景
@(posedge clk) 时钟上升沿采样 最常用,同步设计
@(negedge clk) 时钟下降沿采样 双沿采样或DDR接口
@(edge clk) 双边沿采样 较少用,特殊场景

我个人习惯统一用 @(posedge clk),除非有特殊要求。这样整个验证环境风格一致,别人看代码也舒服。

4.4 并发断言与复位的关系

复位这块,说实话,是很多新手容易忽略的地方。

并发断言在复位期间该不该检查?答案很明确:不应该。复位期间信号都是不确定的,你这时候去检查,肯定一堆假失败。

那怎么处理?有两种主流做法:

  1. 用disable iff:这是最推荐的方式
  2. 在property里加条件:不推荐,容易漏掉

看个例子:

// 带复位的并发断言
property p_req_ack_with_rst;
  @(posedge clk) 
  disable iff (!rst_n)  // 复位期间不检查
  req |=> ##[1:2] ack;
endproperty

a_req_ack_rst: assert property(p_req_ack_with_rst);

避坑指南:

我曾经在一个项目里,忘了加 disable iff。结果复位期间仿真报了上千个断言失败。排查了半天才发现是复位的问题。从那以后,我写每个并发断言的第一件事,就是先把 disable iff 加上。

关于复位,还有几个要点:

  • 异步复位:用 disable iff (!rst_n) 处理
  • 同步复位:可以在property里加条件判断
  • 复位释放后的第一个时钟沿:要小心,信号可能还没稳定

4.5 实战中的小技巧

最后分享几个我常用的技巧:

技巧一:命名规范

我习惯用 p_ 开头命名property,用 a_ 开头命名assert。这样一眼就能看出哪个是定义,哪个是调用。

技巧二:时钟和复位写在property里

不要把时钟和复位写在assert那一行。虽然语法允许,但可读性差。我见过有人这么写:

// 不推荐
a_bad: assert property(@(posedge clk) disable iff (!rst_n) req |=> ack);

这样写,别人看代码得猜半天。还是分开写清楚。

技巧三:仿真时打开断言报告

很多仿真工具默认不打印断言信息。记得在仿真脚本里加上 +define+ASSERT_ON 之类的选项。不然你写了断言,仿真跑完啥也没看到,白忙活。

好了,并发断言的基础就这些。说白了就是三件事:时钟驱动、复位屏蔽、语法正确。把这三点记住,写并发断言就不会出大问题。