One of the loyal jelly-bean customers reported that his gift box had repeated flavors. After the investigation, we found a potential issue with the gift_boxed_jelly_bean_sequence
created in Transactions and Sequences. Here is the original code snippet.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class gift_boxed_jelly_bean_sequence extends uvm_sequence#( jelly_bean_transaction ); task body(); same_flavored_jelly_bean_sequence jb_seq; repeat ( num_jelly_bean_flavors ) begin jb_seq = same_flavored_jelly_bean_sequence::type_id::create( .name( "jb_seq" ) ); assert( jb_seq.randomize() ); `uvm_info( get_name(), jb_seq.convert2string(), UVM_NONE ) jb_seq.start( m_sequencer ); end endtask: body // ... endclass: gift_boxed_jelly_bean_sequence |
The gift box is supposed to have num_jelly_bean_flavors
of mutually different flavors. However, there is a chance that we get repeated flavors. This is because we created a new same_flavored_jelly_bean_sequence
in the loop (line 7) and randomized it without taking care of the duplicated flavor (line 8). Let’s fix it using randc
.
Jelly Bean Transaction
Firstly, we are going to replace the rand
modifier of the flavor
with randc
so that it will cycle through all the flavors (line 4).
1 2 3 4 5 6 7 8 9 10 | class jelly_bean_transaction extends uvm_sequence_item; `uvm_object_utils( jelly_bean_transaction ) randc flavor_e flavor; rand color_e color; rand bit sugar_free; rand bit sour; taste_e taste; // ... endclass: jelly_bean_transaction |
Unfortunately, merely changing the modifier won’t achieve our goal. Here is why.
Same-Flavored Jelly Beans
As you see below, the same_flavored_jelly_bean_sequence
creates a new jelly_bean_transaction
every time the body
task is called (line 16). Because of this, the flavor
will never cycle through.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | class same_flavored_jelly_bean_sequence extends uvm_sequence#( jelly_bean_transaction ); `uvm_object_utils( same_flavored_jelly_bean_sequence ) rand int unsigned num_jelly_beans; // knob constraint num_jelly_beans_con { num_jelly_beans inside { [2:4] }; } function new( string name = "" ); super.new( name ); endfunction: new task body(); jelly_bean_transaction jb_tx; flavor_e jb_flavor; jb_tx = jelly_bean_transaction::type_id::create( .name( "jb_tx" ) ); assert( jb_tx.randomize() ); jb_flavor = jb_tx.flavor; repeat ( num_jelly_beans ) begin jb_tx = jelly_bean_transaction::type_id::create( .name( "jb_tx" ) ); start_item( jb_tx ); assert( jb_tx.randomize() with { jb_tx.flavor == jb_flavor; } ); finish_item( jb_tx ); end endtask: body // ... endclass: same_flavored_jelly_bean_sequence |
Instead of creating a new object in the body
task, let’s create a class property (lines 5 and 11) so that we can reuse the jelly bean (flavor_setter
) between the body
calls. See the highlighted lines for the other changes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | class same_flavored_jelly_bean_sequence extends uvm_sequence#( jelly_bean_transaction ); `uvm_object_utils( same_flavored_jelly_bean_sequence ) rand int unsigned num_jelly_beans; // knob rand jelly_bean_transaction flavor_setter; constraint num_jelly_beans_con { num_jelly_beans inside { [2:4] }; } function new( string name = "" ); super.new( name ); flavor_setter = jelly_bean_transaction::type_id::create( .name( "flavor_setter" ) ); endfunction: new task body(); jelly_bean_transaction jb_tx; /* no longer used flavor_e jb_flavor; jb_tx = jelly_bean_transaction::type_id::create( .name( "jb_tx" ) ); assert( jb_tx.randomize() ); jb_flavor = jb_tx.flavor;*/ repeat ( num_jelly_beans ) begin jb_tx = jelly_bean_transaction::type_id::create( .name( "jb_tx" ) ); start_item( jb_tx ); assert( jb_tx.randomize() with { jb_tx.flavor == flavor_setter.flavor; } ); finish_item( jb_tx ); end endtask: body // ... endclass: same_flavored_jelly_bean_sequence |
Gift-Boxed Jelly Beans
Similarly, create the same_flavored_jelly_bean_sequence
outside of the loop only once (line 6) rather than creating it in the loop (line 8).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class gift_boxed_jelly_bean_sequence extends uvm_sequence#( jelly_bean_transaction ); task body(); same_flavored_jelly_bean_sequence jb_seq; jb_seq = same_flavored_jelly_bean_sequence::type_id::create( .name( "jb_seq" ) ); repeat ( num_jelly_bean_flavors ) begin // jb_seq = same_flavored_jelly_bean_sequence::type_id::create( .name( "jb_seq" ) ); assert( jb_seq.randomize() ); `uvm_info( get_name(), jb_seq.convert2string(), UVM_NONE ) jb_seq.start( m_sequencer ); end endtask: body // ... endclass: gift_boxed_jelly_bean_sequence |
This is just one of the many ways to avoid the repeated flavor. The diagram below shows how the flavor is randomized in the sequences.
You can view and run the code on EDA Playground.
Thanks a lot….very useful for quick code &functional coverage instead of long, multiple runs!!
Thanks for the detailed explanation. As you said, there are multiple ways to achieve this. I prefer to create the transaction only once and randomize it repeatedly. But, before sending it, I clone it. This way, the randc modifier works properly. Thanks.