我是一个基于断言的验证新手,试图了解它应该如何正确完成。我已经找到了很多关于systemverilog +断言的结构和技术细节的信息,但是我还没有找到一些" cookbook"关于事物在现实世界中如何真正完成的材料。
问题和限制:
下面是一个简单且有希望正确的时序图,其中包含频道ID:
那你怎么用最少量的代码来做这件事呢?很干净。以前我已经构建了虚拟verilog模块来驱动数据。但是肯定可以使用一些假设属性来限制通道ID,但是否则可以让正式工具自由地试图制动我的设计?
初学者的简单模板可能是:
data_in : assume property (
<data with some ID>[=3]
|=>
<data with the next id after any clk tick>
);
我想问题是上面的假设/断言倾向于触发每个数据样本并创建在时间上重叠的并行线程。
答案 0 :(得分:2)
相信你在谈论形式验证方法论。
对于形式验证,您无需构建任何驱动模块 刺激。但相反,刺激将由该工具驱动 本身,您可以使用假设属性来指导工具 产生法律刺激。
如果您不提供任何假设,那么工具可以驱动任何随机数据并评估断言,在这种情况下,您可能会得到错误的伪造。此方案称为“Under Constraint”。
同样,如果您提供了太多假设,那么您可能会错过一些合法的输入组合。此方案称为“Over Constraint”。
因此,提供准确的假设非常重要。
对于您的情况,您的假设可能有点像这样:
property channel_change;
// To check the next consecutive ID, after data transfer
@(posedge clk)
(id) throughout (valid [=3]) |=> valid && (id == $past(id) + 1)
endproperty
assume property (channel_change);
有关形式验证方法的更多详细信息,请访问我的博客:What is Formal Verification? [1/2]&amp; What is Formal Verification? [2/2]
答案 1 :(得分:1)
您提供的示例不重叠。在具有相同ID的三个样本之后,一旦具有下一个ID的另一个数据样本到来,结果将匹配并且整个属性将保持。
重叠尝试无论如何都是生活中的事实。工具总是在每个时钟周期中评估(声明或假设)属性,以确定是否可以匹配。如果它确定它是,那么它开始一个新的尝试;如果没有,它继续前进。没有办法说“当它已经被尝试时,不要试图考虑这个断言”,因为你永远不知道一次尝试是否会在比赛中结束。
当看到像你画的那样的波浪时,很明显你不需要在三个样本中评估属性,但这仅仅是因为你可以看到整个画面。这类似于能够展望未来的工具。
继续讨论你的具体问题,你的约束并没有说明整个故事。它仅表明,一旦具有相同ID的3个样本到来,下一个样本的ID应该递增。这里没有任何说明样本必须包含3个包。你需要这样的东西:
assume property (
sample_with_some_id_came |->
came_out_of_reset_and_no_samples_were_sent.triggered or
one_or_two_samples_with_same_id_sent_after_reset.triggered or
three_samples_with_the_previous_id_sent.triggered
);
我也不确定你的假设是否会导致某种“无休止”的行为,因为你说在具有相同ID的3个样本之后必须总是有下一个样本。
答案 2 :(得分:1)
我将定义三个sequence
以在下一个有效的same_id
)上检测相同的ID;检测下一个有效(id
)的change_id
更改;并检测有效数据包(packet_id
)。
然后我可以在四个valid
内监控一个属性,只有三种可能的情况:即
case1: (id, id, id, id+1) OR
case2: (id, id+1, id+1, id+1) OR
case3: (id, id, id+1, id+1)
请参阅下面的代码。我还没有测试过,这只是出于我的想法。希望它能奏效。
好的是property
只能持续4个时钟滴答,而且在每个时钟滴答中,只有一个线程。所以我们可以避免线程爆炸。
// To detect same id within two non-consecutive valid,
// (a,a)
sequence same_id;
int prev_id;
@(posedge clk)
valid, prev_id=id ##1 valid[=1] ##0 id==prev_id;
endsequence
// To detect valid packet
// (a,a,a)
sequence packet_id;
int prev_id;
@(posedge clk)
same_id, prev_id=id ##1 valid[=1] ##0 id==prev_id;
endsequence
// To detect any change of ID
// any (a,b)
sequence change_id;
int prev_id;
@(posedge clk)
valid, prev_id=id ##1 valid[=1] ##0 id==prev_id+1;
endsequence
// Put all together, in any four non-consecutive valid, there are only three cases: a,b,b,b OR b,b,b,c OR a,a,b,b
property next_id;
int prev_id;
@(posedge clk)
(change_id ##0 packet_id) or // a,b,b,b
(packet_id ##0 change_id) or // b,b,b,c
(same_id ##0 change_id ##0 same_id); // a,a,b,b
endproperty
答案 3 :(得分:0)
assume property (@ (posedge clk) disable iff (rst) ((valid[->2] ##0 id != $past(id,,valid)) or ($fell(rst) ##0 valid[->1])) |=> (valid[->1] ##0 id == $past(id,,valid))[*2] ##1 valid[->1] ##0 (id == $past(id,,valid) + 2'd1));
打破它: 隐含的先决条件是两次有效都发生了,并且当前id在时间段内有效完成两次变高([->]而不是[=]),与上一次有效变高的id不同:
((valid[->2] ##0 id != $past(id,,valid))
或有效值在第一笔交易后立即升高:
($fell(rst) ##0 valid[->1])
隐含的结果(在先行匹配| =>之后一个时钟开始)以有效的高电平两次匹配和id ==先前的id(有效有效)匹配开始。必须匹配两次[*]。
(valid[->1] ##0 id == $past(id,,valid))[*2]
并在下一个周期结束时,有效点在某个时候变高,并且当它这样做时,id必须等于先前的id(有效时为高)+1。
##1 valid[->1] ##0 (id == $past(id,,valid) + 2'd1))
这个假设允许id在有效值低时更改-但仍然要求id在3个有效高电平周期中都相同。
如果希望id在整个有效时间内保持稳定,则可以使用以下方法:
assume property (@ (posedge clk) disable iff (rst) ((valid[->2] ##0 id != $past(id,,valid)) or ($fell(rst) ##0 valid[->1])) |=> ($stable(id) throughout valid[->2]) ##1 valid[->1] ##0 (id == $past(id,,valid) + 2'd1));