这里有一个例子:
class constraint_container;
rand int unsigned a, b, c;
function int unsigned get_a();
return a;
endfunction
function int unsigned value_of(int unsigned value);
return value;
endfunction
constraint a_constraint {
a == 5;
// I expect "b" to be equal to "a", but, surprise, surprise...
b == get_a();
// I expect "c" will be equal to "a"
c == value_of(a);
}
endclass
module top;
initial begin
automatic constraint_container cc_inst = new();
void'(cc_inst.randomize());
$display($sformatf("a: %0d, b: %0d, c: %0d", cc_inst.a, cc_inst.b, cc_inst.c));
end
endmodule
乍看之下,人们会猜测,所有三个字段都是5,但是实际上会得到如下输出:
OUTPUT:
a: 5, b: 0, c: 5
陷阱:不管种子是多少,b总是等于0!
它看起来像get_a()在RNG生成之前被执行,也就是说当a为0时就执行了。
我能找到的最接近的解释是SystemVerilog IEEE 1800-2012标准,“18.5.12约束中的函数”一章:
函数应该在求解约束之前被调用,并且它们的返回值应该被视为状态变量(state variables)。
处于激活状态的约束中的函数调用以未指定的次序执行未指定的次数(至少一次)。
结论是,约束所使用的函数应该仅基于函数的参数计算结果,而不是基于类成员。