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:整个过程中条件一直保持
知识体系图
实际项目中的组合使用
说实话,上面这些操作符很少单独用。我在一个 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。我建议你拿不准的时候,直接用括号把优先级写清楚,别省那点功夫。
好了,序列组合就这些内容。记住一个原则:能用简单组合解决的问题,别搞复杂嵌套。验证代码也是代码,可读性很重要。