UVM Tutorial for Candy Lovers – 32. Using randc
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.
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).
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.
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.
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).
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.
上一篇: 【LCA】【模板】最近公共祖先