4、序列组合:and、or、intersect、within、throughout

好,咱们接着聊序列组合。说白了,就是怎么把多个小序列拼成一个大序列,或者检查它们之间的时序关系。

我在项目里见过不少新人,写单个序列挺溜,一到组合就懵了。其实没那么复杂,掌握五个关键词就够了:and、or、intersect、within、throughout。

4.1 and:两个序列都成功

and 的意思是:两个序列都匹配上,才算成功。注意,它不要求同时结束,只要求都成功就行。

sequence s1;
  a ##1 b;
endsequence

sequence s2;
  c ##1 d;
endsequence

sequence s_and;
  s1 and s2;
endsequence

这个例子中,只要 a ##1 b 和 c ##1 d 都发生了,s_and 就成功。谁先谁后无所谓。

我的习惯:用 and 时,我一般会加上时间窗口约束,不然两个序列隔得太远,验证意义不大。

4.2 or:任一成功即可

or 就更好理解了——两个序列里,只要有一个成功,就算通过。

sequence s_or;
  s1 or s2;
endsequence

嗯,这里要注意:如果两个序列都成功了,那也算一次成功,不会重复计数。

避坑指南:我曾经在项目中用 or 组合了两个很长的序列,结果仿真跑得巨慢。后来发现,其中一个序列其实可以用更简单的表达式替代。所以,能用简单逻辑就别用复杂序列。

4.3 intersect:同时开始,同时结束

intersect 比 and 严格得多。它要求两个序列不仅都要成功,而且必须从同一个时钟周期开始,在同一个时钟周期结束。

sequence s_intersect;
  s1 intersect s2;
endsequence

你想想看,这相当于两个序列的「时间窗口」完全重叠。我在做总线协议验证时经常用这个,比如检查读写操作是否在同一个时钟周期内完成。

注意:如果两个序列长度不一样,intersect 会取较短的那个作为结束点。比如 s1 长 5 拍,s2 长 3 拍,那 intersect 在第 3 拍就结束了。

4.4 within:一个序列在另一个内部完成

within 检查的是「包含关系」。语法是 seq1 within seq2,意思是 seq1 必须在 seq2 的开始和结束之间完成。

sequence s_within;
  s1 within s2;
endsequence

举个例子:s2 从第 2 拍开始,第 10 拍结束。s1 只要在第 2 拍到第 10 拍之间完成,就算成功。s1 可以比 s2 早开始吗?不行,必须晚于或等于 s2 的开始时间。

我个人习惯:用 within 时,我会把外层序列 s2 写得稍微宽松一点,给内层序列留足余量。不然稍微有点抖动就失败了,调试起来很头疼。

4.5 throughout:持续保持某个条件

throughout 的意思是:在整个序列执行期间,某个信号必须一直保持为真。

sequence s_throughout;
  (a && b) throughout (c ##1 d ##1 e);
endsequence

这个例子中,从 c 开始到 e 结束,a && b 必须一直为高。中间哪怕掉了一拍,整个序列就失败。

为什么会这样?因为 throughout 本质上是在序列的每个时钟周期都插入了一个检查点。我在做握手协议验证时特别喜欢用这个,比如检查 valid 信号在整个数据传输过程中不能拉低。

核心总结:
  • and:都成功就行,不要求同时
  • or:任一成功即可
  • intersect:同时开始,同时结束
  • within:一个在另一个内部完成
  • throughout:整个过程中条件一直保持

知识体系图

序列组合操作符知识体系 序列组合操作符 and:都成功 不要求同时结束 or:任一成功 只要一个匹配即可 intersect:同时 同时开始,同时结束 within:包含 一个在另一个内部 throughout:持续 条件全程保持 五个操作符覆盖了序列组合的常见场景 实际项目中常混合使用,注意优先级和括号

实际项目中的组合使用

说实话,上面这些操作符很少单独用。我在一个 PCIe 验证项目中,就同时用了 within 和 throughout:

sequence pcie_valid_transfer;
  // 在整个传输过程中,power_good 必须一直为高
  power_good throughout 
    // 数据包必须在帧开始和帧结束之间完成
    (data_packet within (frame_start ##[1:$] frame_end));
endsequence

你看,这样组合起来,一个序列就能检查多个条件。比写一堆分散的断言要清晰得多。

注意优先级:这些操作符的优先级从高到低是:throughout > within > intersect > and / or。我建议你拿不准的时候,直接用括号把优先级写清楚,别省那点功夫。

好了,序列组合就这些内容。记住一个原则:能用简单组合解决的问题,别搞复杂嵌套。验证代码也是代码,可读性很重要。