SystemVerilog Constraint Gotcha
I found another one (I guess I still need to order that book). In using the UVM, I have some sequences randomizing other sub sequences. I really want it to work like this (simplified, non-UVM) example:
class Foo; rand int bar; function void display(); $display("bar: %0d", bar); endfunction endclass class Bar; int bar; function void body(); Foo foo = new(); bar = 3; foo.display(); assert(foo.randomize() with {bar == this.bar;}); foo.display(); endfunction endclass module top; Bar bar; initial begin bar = new(); bar.body(); end endmodule
See the problem there? Here's what prints out when you run the above:
bar: 0 bar: -1647275392
foo.bar is not constrained to be 3 like you might expect. That's because this.bar refers to bar that is a member of class Foo, not bar that's a member of class Bar. As far as I can tell, there is no way to refer to bar that is a member of Bar in the constraint. I guess Foo could have a reference back up to Bar, but that's really awkward. Has anyone else run into this? How do you deal with it?
UPDATE: Thank you to Mihai Oncica for pointing out that the local keyword with the scope resolution operator can be used to solve this problem. Here is the now working code example:
class Foo; rand int bar; function void display(); $display("bar: %0d", bar); endfunction endclass class Bar; int bar; function void body(); Foo foo = new(); bar = 3; foo.display(); assert(foo.randomize() with {bar == local::bar;}); foo.display(); endfunction endclass module top; Bar bar; initial begin bar = new(); bar.body(); end endmodule
And here is the result:
bar: 0 bar: 3
Comments
I stumbled your blog when I was trying to refresh my memory about disable fork/block_name. You showed some good examples.
Now regarding your question, a simple fix is to use local:: namespace.
For example:
assert(foo.randomize() with {bar == local::bar;});
The 'local' resolution was a recent hack/fix for that issue in the SV spec.
I assumed you meant Bar::bar, so I removed the int bar declaration and created a simple function:
function int bar();
return 3;
endfuction
And then changed the randomize to:
assert(foo.randomize() with {bar == local::bar();});
And it worked the same as when bar was an int. Is that what you were talking about?