UVM Tutorial for Candy Lovers – 23. Jelly Bean Taster in UVM 1.2

Last Updated: February 21, 2015

My first series of UVM tutorials (#1 to #6) was posted more than three years ago. Since then, UVM (and my knowledge about it) has evolved and I always wanted to update my articles and code. But it was not easy because my article and code were tightly coupled and some comments from the readers even referred to the specific lines of code.

UVM 1.2

About two months ago, Accellera released new UVM 1.2 and it motivated me to update my jelly bean taster. I thought it’s time to overhaul. Interestingly though, my code required almost no modifications. The only change I made was taking advantage of new automatic phase objection of the uvm_sequence_base class. The set_automatic_phase_objection function automatically raises the objection prior to executing the sequence, and drops the objection after ending the sequence (line 25).

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 jelly_bean_test extends uvm_test;
  `uvm_component_utils( jelly_bean_test )
 
  jelly_bean_env jb_env;
 
  function new( string name, uvm_component parent );
    super.new( name, parent );
  endfunction: new
 
  function void build_phase( uvm_phase phase );
    super.build_phase( phase );
 
    jelly_bean_transaction::type_id::set_type_override( 
      sugar_free_jelly_bean_transaction::get_type() );
    jb_env = jelly_bean_env::type_id::create( .name( "jb_env" ), .parent( this ) );
  endfunction: build_phase
 
  task main_phase( uvm_phase phase );
    gift_boxed_jelly_bean_sequence jb_seq;
 
    jb_seq = gift_boxed_jelly_bean_sequence::type_id::create( .name( "jb_seq" ) );
    assert( jb_seq.randomize() );
    `uvm_info( "jb_seq", jb_seq.convert2string(), UVM_NONE )
    jb_seq.set_starting_phase( phase );
    jb_seq.set_automatic_phase_objection( .value( 1 ) );    jb_seq.start( jb_env.jb_agent.jb_seqr );
  endtask: main_phase
endclass: jelly_bean_test

Taking this opportunity, I also simplified the scoreboard as the layered scoreboard used in Environment always confused the newbies. Here is the simplified hierarchy of the verification components. Note that the wrapper around the jelly_bean_sb_subscriber has been removed. You can compare this figure with the figure in Overview if you are interested.

Simplified Scoreboard Hierarchy
Simplified Scoreboard Hierarchy
The jelly_bean_sb_subscriber has been simplified accordingly. The write function checks if the taste has expected value or not by itself.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class jelly_bean_sb_subscriber extends uvm_subscriber#( jelly_bean_transaction );
  `uvm_component_utils( jelly_bean_sb_subscriber )
 
  function new( string name, uvm_component parent );
    super.new( name, parent );
  endfunction: new
 
  function void write( jelly_bean_transaction t );    if (     t.flavor == CHOCOLATE && t.sour   && t.taste == YUMMY ||         ! ( t.flavor == CHOCOLATE && t.sour ) && t.taste == YUCKY ) begin      `uvm_error( get_name(), { "You lost sense of taste!", t.convert2string() } )    end else begin      `uvm_info( get_name(), { "You have a good sense of taste.", t.convert2string() }, UVM_LOW )    end  endfunction: write  endclass: jelly_bean_sb_subscriber

The jelly_bean_env directly instantiates the jelly_bean_sb_subscriber without a wrapper (line 16).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class jelly_bean_env extends uvm_env;
  `uvm_component_utils( jelly_bean_env )
 
  jelly_bean_agent         jb_agent;
  jelly_bean_fc_subscriber jb_fc;
  jelly_bean_sb_subscriber jb_sb;
 
  function new( string name, uvm_component parent );
    super.new( name, parent );
  endfunction: new
 
  function void build_phase( uvm_phase phase );
    super.build_phase( phase );
    jb_agent = jelly_bean_agent        ::type_id::create( .name( "jb_agent" ), .parent( this ) );
    jb_fc    = jelly_bean_fc_subscriber::type_id::create( .name( "jb_fc"    ), .parent( this ) );
    jb_sb    = jelly_bean_sb_subscriber::type_id::create( .name( "jb_sb"    ), .parent( this ) );  endfunction: build_phase
 
  function void connect_phase( uvm_phase phase );
    super.connect_phase( phase );
    jb_agent.jb_ap.connect( jb_fc.analysis_export );
    jb_agent.jb_ap.connect( jb_sb.analysis_export );
  endfunction: connect_phase  
endclass: jelly_bean_env

EDA Playground

You can view and run the new code on EDA Playground now! For those of you who do not know EDA Playground, it is a web-based simulator developed by Victor EDA, Inc. About two weeks ago, they added Aldec’s Riviera-PRO EDU simulator, which enabled us to use full features of SystemVerilog including randomization, SVA, and functional coverage. How wonderful! Thank you, Victor EDA and Aldec!

10 thoughts on “UVM Tutorial for Candy Lovers – 23. Jelly Bean Taster in UVM 1.2”

  1. Hi Keisuke san,

    When I compare the tasting example, I noticed that at line 24 ” jb_seq.set_starting_phase( phase );” is added. What is this for? How come we don’t need it in previous example. Many thanks.

    Loren

    1. The set_starting_phase function is new addition to UVM 1.2. The set_automatic_phase_objection function (line 25) uses the starting_phase set by this set_starting_phase function to raise and drop the objection. Please see the diagram below how the automatic phase objection works (you probably don’t have to know about it, though).
      How automatic phase objection works

  2. Hi Keisuke,
    I noticed in this jelly_bean_test you use main_phase instead of run_phase of previous jelly_bean_test.
    Can you talk a little about the difference?

    Thanks,
    Rui

      1. Hi Keisuke san,

        When I first learn UVM, I still use program to initial the run_test. However, in your examples, you initial the run_test inside module. What is the different? Many thanks.

        Loren

  3. Given you use set_starting_phase( phase ) in the test component, do we still need starting_phase.raise/drop_objection in the sequence ?

    1. If you call set_automatic_phase_objection, then you don’t need to manually raise/drop the objection in the sequence. However, I think a better approach would be not using the set_automatic_phase_objection at all (I was too excited about the new feature of UVM 1.2 ;). Instead, I should have coded the main_phase simply like this:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      
      task main_phase( uvm_phase phase );
        gift_boxed_jelly_bean_sequence jb_seq;
       
        phase.raise_objection( this );
        jb_seq = gift_boxed_jelly_bean_sequence::type_id::create( .name( "jb_seq" ) );
        assert( jb_seq.randomize() );
        `uvm_info( "jb_seq", jb_seq.convert2string(), UVM_NONE )
        jb_seq.start( jb_env.jb_agent.jb_seqr );
        phase.drop_objection( this );
      endtask: main_phase
  4. jb_seq.set_starting_phase( phase );
    jb_seq.set_automatic_phase_objection( .value( 1 ) );

    even after removing above two lines code is running as per expected instead it should come out from the simulation in zero time, because no where else in code raise and drop objection mention.

Leave a Reply