Last Updated: March 26, 2016 (added the link to EDA Playground)
Did you know the mix of two lemon and two coconut jelly beans will create the flavor of lemon meringue pie? And the mix of two strawberry and two vanilla jelly beans will create the flavor of strawberry shortcake? This post will provide an explanation on the virtual sequence to create these new jelly-bean recipes.
Overview
The first figure shows the relationship of the verification components used in this post. The jelly_bean_taster
(DUT) from the previous posts was “enhanced” to take two jelly-bean flavors at the same time through two jelly_bean_if
s. This new DUT is referred to as the jelly_bean_taster_subsystem
. To drive the two interfaces, two instances of jelly_bean_agent
are used. The jelly_bean_recipe_virtual_sequence
orchestrates the creation of jelly-bean flavors in order to make a new flavor. The second figure at the bottom of the page shows the verification components in a class diagram, and the third figure shows the verification objects in a class diagram.
Virtual Sequence
The virtual sequence defines three new jelly-bean recipes (LEMON_MERINGUE_PIE
, STRAWBERRY_SHORTCAKE
, and CANDY_APPLE
) on the second line. Each recipe requires two jelly-bean flavors. For example, to create the LEMON_MERINGUE_PIE
recipe, two LEMON
jelly beans and two COCONUT
jelly beans are necessary. Two sub-sequences (same_flavored_jelly_beans_sequence
) are created (line 19) to generate two flavors. The case
statement on the line 21 prepares two jelly-bean flavors based on the recipe. At the end of the body
task, the two sub-sequences are started in parallel (line 42).
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | class jelly_bean_recipe_virtual_sequence extends uvm_sequence#( uvm_sequence_item ); typedef enum bit[1:0] { LEMON_MERINGUE_PIE, // 2 LEMON + 2 COCONUT STRAWBERRY_SHORTCAKE, // 2 STRAWBERRY + 2 VANILLA CANDY_APPLE // 2 APPLE + 1 CINNAMON } recipe_e; rand recipe_e recipe; jelly_bean_sequencer jb_seqr1; jelly_bean_sequencer jb_seqr2; same_flavored_jelly_beans_sequence jb_seq1; same_flavored_jelly_beans_sequence jb_seq2; function new( string name = "" ); super.new( name ); endfunction: new task body(); jb_seq1 = same_flavored_jelly_beans_sequence::type_id::create( .name( "jb_seq1" ), .contxt( get_full_name() ) ); jb_seq2 = same_flavored_jelly_beans_sequence::type_id::create( .name( "jb_seq2" ), .contxt( get_full_name() ) ); case ( recipe ) LEMON_MERINGUE_PIE: begin jb_seq1.flavor = jelly_bean_transaction::LEMON; jb_seq2.flavor = jelly_bean_transaction::COCONUT; jb_seq1.num_jelly_beans = 2; jb_seq2.num_jelly_beans = 2; end STRAWBERRY_SHORTCAKE: begin jb_seq1.flavor = jelly_bean_transaction::STRAWBERRY; jb_seq2.flavor = jelly_bean_transaction::VANILLA; jb_seq1.num_jelly_beans = 2; jb_seq2.num_jelly_beans = 2; end CANDY_APPLE: begin jb_seq1.flavor = jelly_bean_transaction::APPLE; jb_seq2.flavor = jelly_bean_transaction::CINNAMON; jb_seq1.num_jelly_beans = 2; jb_seq2.num_jelly_beans = 1; end endcase // case ( recipe ) `uvm_info( get_name(), { "\n", this.sprint() }, UVM_LOW ) fork jb_seq1.start( .sequencer( jb_seqr1 ), .parent_sequence( this ) ); jb_seq2.start( .sequencer( jb_seqr2 ), .parent_sequence( this ) ); join endtask: body `uvm_object_utils_begin( jelly_bean_recipe_virtual_sequence ) `uvm_field_enum ( recipe_e, recipe, UVM_ALL_ON ) `uvm_field_object( jb_seq1, UVM_ALL_ON ) `uvm_field_object( jb_seq2, UVM_ALL_ON ) `uvm_object_utils_end endclass: jelly_bean_recipe_virtual_sequence |
Test
The jelly_bean_recipe_test
class creates the above mentioned virtual sequence. Firstly, the test assigns two jelly_bean_sequencer
s to the virtual sequence (line 13 and 14). By doing this, the sub-sequence, jb_seq1
, will run on the sequencer in the agent #1, and the sub-sequence, jb_seq2
, will run on the sequencer in the agent #2. The test randomizes the virtual sequence and starts the sequence on the line 15 and 16. Note that the sequencer
argument of the start
task takes null
since there is no sequencer associated with the virtual sequence.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class jelly_bean_recipe_test extends jelly_bean_base_test; `uvm_component_utils( jelly_bean_recipe_test ) function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new task main_phase( uvm_phase phase ); jelly_bean_recipe_virtual_sequence jb_vseq; phase.raise_objection( .obj( this ) ); jb_vseq = jelly_bean_recipe_virtual_sequence::type_id::create( .name( "jb_vseq" ), .contxt( get_full_name() ) ); jb_vseq.jb_seqr1 = jb_env.jb_agent1.jb_seqr; jb_vseq.jb_seqr2 = jb_env.jb_agent2.jb_seqr; assert( jb_vseq.randomize() ); jb_vseq.start( .sequencer( null ) ); #100ns ; phase.drop_objection( .obj( this ) ); endtask: main_phase endclass: jelly_bean_recipe_test |
Simulation
Let’s run a simulation to see what flavors the virtual sequence generates. In my case, the sequence generated a CANDY_APPLE
recipe. It in turn made the first sequence (jb_seq1
) generate two APPLE
jelly beans, and made the second sequence (jb_seq2
) generate one CINNAMON
jelly bean.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | UVM_INFO jb.sv(266) @ 0: reporter@@jb_vseq [jb_vseq] ------------------------------------------------------------------------------------ Name Type Size Value ------------------------------------------------------------------------------------ jb_vseq jelly_bean_recipe_virtual_sequence - @1196 recipe recipe_e 2 CANDY_APPLE jb_seq1 same_flavored_jelly_beans_sequence - @1200 num_jelly_beans integral 32 'h2 flavor jelly_bean_transaction::flavor_e 3 APPLE req object - rsp object - jb_seq2 same_flavored_jelly_beans_sequence - @1204 num_jelly_beans integral 32 'h1 flavor jelly_bean_transaction::flavor_e 3 CINNAMON req object - rsp object - depth int 32 'd1 parent sequence (name) string 0 "" parent sequence (full name) string 0 "" sequencer string 0 "" req object - rsp object - ------------------------------------------------------------------------------------ |
I hope this tutorial helped you understand the virtual sequence. Oh, for those of you who are interested in more jelly-bean recipes, consult this site 🙂
You can view and run the code on EDA Playground.
Hi,
I have a basic doubt related to raising an objection.
In many examples i found the objection is raised from inside the sequences, or may be some other components.
Here, in this example, the objection is raised from the testcase.
How to decide on the point of raising an objection? What all factors incfluence that? Does it make any difference if i raise an objection from a sequence or from a testcase?
An objection should be raised if a component or a sequence does not want to move on to the next phase. For example, the
jelly_bean_recipe_test
wanted to run for 100 ns, so it raised an objection. If a test pushes 100 requests to a request queue, but the test does not know when these requests finish, the request queue should also raise an objection as long as there is a request in the queue. A scoreboard is another candidate to raise an objection.Hi Keisuke,
I found the post is very helpful for me to understand the uvm. I wonder what is the reason that seq1.start needs to provide parent_sequence, but the gift_box example, sequence of sequences does not need parent_sequence.
Thanks.
The
jb_seq1
andjb_seq2
are children of thejelly_bean_recipe_virtual_sequence
. If theparent_sequence
is provided, theparent_sequence
‘spre_do
,mid_do
, andpost_do
methods will be called during the execution of thejb_seq1
andjb_seq2
.Similarly the
gift_boxed_jelly_beans_sequence
should have provided theparent_sequence
when it calledjb_seq.start()
. I have corrected the example (the line 15 ofgift_boxed_jelly_beans_sequence
of this article). Thank you for pointing this out.Hi Keisuke,
Thanks for your update and explanation. It helps me a lot.
I am glad to hear that it is useful.
Hi Keisuke,
I am new to virtual_seq. In line 1,
class jelly_bean_recipe_virtual_sequence extends uvm_sequence#( uvm_sequence_item );
Since virtual_seq does not work with a driver, why do we need uvm_sequence_item? Is it ok to leave it out.
class jelly_bean_recipe_virtual_sequence extends uvm_sequence;
Many thanks.
Hi Loren,
As you mentioned, the type parameter of the
uvm_sequence#
class is not important here. Since the default type isuvm_sequence_item
, you can omit the type.Hi Keisuke,
I have a few questions related to sequence. Can you give me some pointer?
1. This is the problem. I want to test multiplexer interface in DUT. Each output is connection to a 4 deep FIFO. I don’t want to interface to be idle when any of the FIFO is full. The driver will drive 2bit control bit, and 8-bit data. (this is my sequence item) So I want to use 4 sema to keep track of each fifo assuming the I can put token back to sema when I drain out 1 entry from the fifo.
1. should I pass the sema to a sequence, and In the body(), I try_put sema to randomize the 2bit control bit?
2. should I use the sema info in the driver?
What is the most practical way to implement this?
2. When I compare the syntax of seq, and virtual seq, they are very similar except:
a. virtual seq is not associated with a user-defined sequence_item.
b. virtual seq has sequencer for each of the sub-seq.
Are these the only different?
Many thanks.
Hi Loren,
1. I’m afraid I might not understand your DUT well, but I would probably put control bit info in a transaction so that I can fully control the driver behavior.
2. Yes, a virtual sequence is nothing but a sequence. The only difference is that it co-ordinates multiple sequences on different sequencers.
Mr. Shimizu,
Thanks for the wonderful explanation. Could also explain about Virtual Sequencers ? As per your explanation, I understood that Virtual Sequences co-ordinates multiple sequences on different sequencers. how does it differ from Virtual Sequencer.
Thanks.
A virtual sequencer also has the handles to the coordinated sequencers, and you can create a virtual sequence that runs on the virtual sequencer. However, this approach adds an unnecessary component (virtual sequencer) to the verification environment and it negatively affects the reusability of the environment. I would recommend not to use the virtual sequencer.
Hi,
I youe code you have not used virtual sequencer my question is
Why do we need virtual sequencer when the same can be done with the above example.
What are the disadvantage of using the above example.
A virtual sequencer is not needed. Please see my comment above.
I’m new to UVM, and maybe not catch the idea really well. I have a basic question. What’s the benefit of using the virtual sequence? We can do pretty much do the same thing in the test, right? Is it just to group the sequences? Thanks, Cate
There are a couple of benefits using the virtual sequence over doing the same in a test.
Hi Keisuke san,
I tried to read more the the sequencer arbitration, but I couldn’t find anything that can explain clearly to me how the SEQ_ARB_FIFO, SEQ_ARB_RANDOM work. Can you give an example to illustrate.
For example, when I forked
I know that start will not return until seq’s body is completed. Let’s say it takes 10 time unit.
I can see the seq thread should be
@1 seqA
@2 seqA, seqB
@3 seqC
@11 seqA finished. Then it is the only one that can request again. I can’t figure it out.
Many thanks.
Loren
Sorry for the slow response. I have written a new article about Sequence Arbitration. I hope it helps.
Hi Keisuke San,
Can you explain how to parameterize a uvm_sequence_item? For example, I have a interface, and I want to have the address and data width parametrizable.
I think I can write the base class like.
class bus_item#( ADDR_WIDTH = 8, DATA_WIDTH=8) extends uvm_sequence_item
`uvm_object_utils( bus_item#(ADDR_WIDTH, DATA_WIDTH))
…
So when I create a derive class. Should it be?
class d_bus_item extends bus_item#(ADDR_WIDTH, DATA_WIDTH)
`uvm_object_utils( d_bus_item)
Also when I use the class my_seq extends uvm_sequence#(packet), is the packet the parameter in uvm_sequence?
These are my confusion.
1. I am not sure where to place the parameter in the derived class. For example, `uvm_object_utils( d_bus_item#(ADDR_WIDTH, DATA_WIDTH)).
2. If my base class is not parameterized, can I derived a class and parameterize it?
Many thanks.
A parameterized class needs to be specialized (meaning you need to specify the parameter values) before use. Your code won’t compile because the
ADDR_WIDTH
and theDATA_WIDTH
are not specified.You can either make the
d_bus_item
parameterized:and specialize the
d_bus_item
when you instantiate it:Or, specialize the
bus_item
:Since the
bus_item
class has the default parameter values, you can also write:Similarly, when you did:
you specialized the
uvm_sequence
class with thepacket
type.You can add new parameters to the derived class, too.
Thanks Keisuke san. You explained the usage very well.
If I understand it correctly, can I summarize it this way?
For a derived class also can change the parameters, I need to declare it this way.
class A_item#(int a) extends B_item#(int a)
`uvm_object_param_utils(A_item#(int a)) <– I used the param_utils, and I included the param.
If my drived class will use a fixed parameter like 8, I need declare it this way.
class A_item extends B_item#(8) <– I used the fix parameter
`uvm_object_utils(A_item) <– this is not parameterized class
Many thanks.
Loren
You are right.
Hi shimizu,
In some pdfs like uvm_user_guide, i have seen people using virtual sequences contain only sub-sequences and virtual sequencers contain the subsequencers
In the env, they set the virtual_sequecer.sub_seqr = agent.sequencer
Then in test, they define the default_sequence of the virtual sequencer to be the virtual sequence using config_db
Here you keep the sequencers in virtual sequence
Which approach you would suggest
Thanks
Sasi
I would suggest not to use a virtual sequencer as it is not needed. Please see my old comment.
Hi, I am just eager how a sequence will be run if sequencer handle is not passed.
Say, if vir_seq.start(null) is called , please explain how does it start() method works.
Basically the
start
method executes thebody
task of thevir_seq
, but no sequencer is involved when thesequencer
argument isnull
.How I set a value to variable in the sequence, when i start the sequence with `uvm_do_* macro? Because I don’t need to create the sequence when I use uvm_do. I tried setting the variable as rand type and tried to use uvm_do_with, but it doesn’t work.
If you could paste how did you call the
`uvm_do_with
, I might be able to help.Thanks, I was able to make it work with `uvm_do_with. But my requirement is that I don’t want to set the variable always, but only on certain occasions. Making it as rand type randomizes it always(even when I just use `uvm_do).
How about disabling random variables with
rand_mode
likeyour_variable.rand_mode(0)
?HI KEISUKE,
1) I recently came across an interview question regarding Virtual sequencer.I know the application of virtual sequencer.
Interview Question : What is virtual sequencer? Is it possible to drive two different sequences with out using virtual sequences/sequencers on different agents?
– If Yes,Then what is the purpose of virtual sequences/sequencers?
– If No,what makes the advantage using it.
can you let me know with some scenario ?
-Raja.
You can start sequences on multiple sequencers without using a virtual sequence. But if you do, you can extend it, reuse it, and create hierarchical sequences with it.
Hello Shimizu-san,
Thank you very for your great tutorial.
I have a question: can we start a virtual sequence in another virtual sequence (like in no3 I see sequence of sequences by using m_sequencer ). Can we do similar things with two (or more) virtual sequences. If possible could you please recommend the way ?
Thank you.
Yes, you can. This is a virtual sequence (
gift_boxed_jelly_beans_virtual_sequence
) that runs another virtual sequence (jelly_bean_recipe_virtual_sequence
).And this is a test that runs the above virtual sequence.
Dear Shimizu-san,
Thank you very much for your help. It works well.
You are welcome.
Hi, If I create a virtual_seq with only one sequence and start this virtual_seq in my test with actual sequencer (instead of null), then will that be considered as normal sequence? If yes, then only way simulator knows it is a virtual sequence is by the way start is called?
I would say your sequence is a non-virtual sequence, not because you started the sequence on a (non-
null
) sequencer, but because it is a sequence of another sequence.You can start a virtual sequence on a (non-
null
) sequencer. For example, the virtual sequence can send sequence items to the sequencer while it starts other sequences on their sequencers. My definition of virtual sequence is that it starts sub-sequences on multiple sequencers.Hi Keisuke,
Can we run a sequence on multiple sequencers in parallel, can you please explain.
You cannot start the same sequence on multiple sequencers in parallel unless you clone it because the sequence keeps track of its sequence state (once a sequence is started, it cannot be started again until it is finished or stopped).
hi Mr. Shimizu,
virtual sequencer and physical sequencer exit from main phase prematurely before test completes. have you seen this? if so, how to resolve it? Thank you.
Ed
Sorry for the very slow reply. It’s most likely objections are dropped prematurely. You could use
+UVM_OBJECTION_TRACE
command-line argument to trace objection activity.Hi Keisuke: The definition of your “same_flavored_jelly_beans_sequence” class does not have a member called “flavor”. How were you able to assign some values inside your “jelly_bean_recipe_virtual_sequence” class for the “jb_seq1” and “jb_seq2” sequences?
Actually, I slightly modified the original
same_flavored_jelly_beans_sequence
to have theflavor
property for this tutorial. Sorry for the confusion.Hi Keisuke,
What’s the difference between “this” and “self” in the line jb_tx.randomize() with {} above.
Thanks a lot for this great tutorial. Really learned a lot.
Hulin
In the line below:
this
refers to thejb_tx
object (not the current instance ofsame_flavored_jelly_beans_sequence
), whereasself
refers to the current instance ofsame_flavored_jelly_beans_sequence
.Hi Keisuke,
/////////////////////
In the virtual sequence, we do not create sequencer, but create sequence. jb_seq1, jb_seq2.
//////////////////
//////////////////////
In the test, we create the virtual sequence jb_vseq.
//////////////////////
I have some questions here
1. When should we do create? From the code, it seems like we do not need to create sequencer. My understanding is that we do not need to do type override for sequencer so that we do not need to create it in the sequence? Please correct me.
2. In the test, I think it only pass the handle of jb_env.jb_agent1.jb_seqr to jb_vseq.jb_seqr1? Am i correct? When could we just pass the handle?
3. if we have, for example, 4 sequences in one virtual sequence: vseq , if we want to set the default sequence, we could use virtual sequencer in the test to control it together. Is that one of the usage for virtual sequencer? If we do not have virtual sequencer and the sequencer for virtual sequence is null
(jb_vseq.start( .sequencer( null )) , does that mean we need to set default sequence one by one in the virtual sequence. Or for virtual sequence we should only do .start, but not default sequence to start a sequence.
Thank you very much
Thanks Keisuke for your reply, I got it.
Best,
Hi Keisuke,
For virtual sequence reused by different tests, should we put the virtual sequence in env? Is that a good way? Otherwise is there any better way to handle the virtual sequence?
Thank you very much
Best,
I would create a package for the virtual sequence and let the test import it.
Hi KEISUKE,
Will please explain the difference between import a package and include a file with a good example?
The
`include
is a compiler directive used to insert a file as if it is copy & pasted.On the other hand, the
import
declaration DOES NOT insert the contents of the package. It just provides direct visibility of identifiers within a package. For example, unless you import the package, you need to use the package name qualifier when you use thejelly_bean_transaction
declared in thejelly_bean_pkg
.With the
import
declaration, you can use thejelly_bean_transaction
without the package name qualifier.I have written an env with 3 agents like apb agent and 2 other agents.
For this,I have used virtual sequencer using m_sequencer method.(normal uvm_sequencer which holds the handles to different sequences. )
When it calls UVM_TEST= test_name from command line ,All pre-run phases are working absolutely correct.But it is stuck at run phase.
It is stuck at below :
m_vseq.start(v_seqr.apb_seqr);
It is not going ahead.
Can somebody help me to solve this?
Check the
body
task ofm_vseq
and thebody
task of the sequences thatm_vseq
starts. Ism_vseq
a virtual sequence? Then, do you want to start it onapb_seqr
?