UVM Tutorial for Candy Lovers – 6. Tasting

Last Updated: September 1, 2014

The anticipated culmination of the UVM for Candy Lovers series is revealed in this post. Using the created verification components and writing out a test class, the actual simulation is prepared to run.

Test

This particular example will show you how to develop a variety of sugar-free jelly beans in the form of a gift box. The test class is described below.

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
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);
      begin
         jelly_bean_configuration jb_cfg;
 
         jb_cfg = new;
         assert(jb_cfg.randomize());
         uvm_config_db#(jelly_bean_configuration)::set           (.cntxt(this), .inst_name("*"), .field_name("config"), .value(jb_cfg));         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));      end
   endfunction: build_phase
 
   task run_phase(uvm_phase phase);
      gift_boxed_jelly_beans_sequence jb_seq;
 
      phase.raise_objection(.obj(this));
      jb_seq = gift_boxed_jelly_beans_sequence::type_id::create(.name("jb_seq"), .contxt(get_full_name()));      assert(jb_seq.randomize());      `uvm_info("jelly_bean_test", { "\n", jb_seq.sprint() }, UVM_LOW)      jb_seq.start(jb_env.jb_agent.jb_seqr);      #10ns ;
      phase.drop_objection(.obj(this));
   endtask: run_phase
endclass: jelly_bean_test

The build_phase executes three actions:

  1. the registration of the configuration of the simulation into the database (line 17)
  2. the direction on the usage of the sugar_free_jelly_bean transaction rather than the jelly_bean_transaction (line 19)
  3. the creation of the jelly_bean_env (line 20)

Lines 13 to 18 were provided for future configuration uses, and were added as placeholders. An explanation of the configuration was omitted from this series due to the lack of configuration needs. Please see Configurations if you are interested in this topic.

In the run_phase, the created gift_boxed_jelly_beans_sequence is ready to run.

Configuration

For reference, the source code for the jelly_bean_configuration class is inserted below.

1
2
3
4
5
6
7
class jelly_bean_configuration extends uvm_object;
   `uvm_object_utils(jelly_bean_configuration)
 
   function new(string name = "");
      super.new(name);
   endfunction: new
endclass: jelly_bean_configuration

Top

Before proceeding with the simulation, there is a need to write the top module, which instantiates the DUT module, registers the jelly_bean_if in the resource database, and runs the test. The top module is responsible for clock generation as well.

Update (April 2, 2014): In this tutorial, we used uvm_resource_db to store the jelly_bean_if (lines 15 and 16). UVM recommends using uvm_config_db instead of uvm_resource_db as the former is more robust. You can replace the lines 15 and 16 with:

uvm_config_db#( virtual jelly_bean_if )::set( .cntxt( null ), .inst_name( "uvm_test_top.*" ),
   .field_name( "jelly_bean_if" ), .value( jb_slave_if ) );

For more information about the configuration database, please see Configuration Database and Configuration Database Revisited.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module top;
   import uvm_pkg::*;
 
   reg clk;
   jelly_bean_if     jb_slave_if(clk);
   jelly_bean_taster jb_taster(jb_slave_if);
 
   initial begin // clock generation
      clk = 0;
      #5ns ;
      forever #5ns clk = ! clk;
   end
 
   initial begin
      uvm_resource_db#(virtual jelly_bean_if)::set
        (.scope("ifs"), .name("jelly_bean_if"), .val(jb_slave_if));
      run_test();
   end
endmodule: top

Simulation

It is now time to compile and run the simulation, as part of the finale. Posted below are the results for the simulation.

UVM_INFO @ 0: reporter [RNTST] Running test jelly_bean_test...
UVM_INFO jb.sv(481) @ 0: uvm_test_top [jelly_bean_test]
-----------------------------------------------------------------------
Name                      Type                             Size  Value
-----------------------------------------------------------------------
jb_seq                    gift_boxed_jelly_beans_sequence  -     @772
  num_jelly_bean_flavors  integral                         32    'h2
  req                     object                           -
  rsp                     object                           -
-----------------------------------------------------------------------
 
UVM_INFO jb.sv(406) @ 40: uvm_test_top.jb_env.jb_sb [jelly_bean_scoreboard] You have a good sense of taste.
----------------------------------------------------------------
Name          Type                               Size  Value
----------------------------------------------------------------
jb_tx         sugar_free_jelly_bean_transaction  -     @818
  flavor      flavor_e                           3     CHOCOLATE
  color       color_e                            2     RED
  sugar_free  integral                           1     'h1
  sour        integral                           1     'h1
  taste       taste_e                            2     YUCKY
----------------------------------------------------------------
 
UVM_INFO jb.sv(406) @ 60: uvm_test_top.jb_env.jb_sb [jelly_bean_scoreboard] You have a good sense of taste.
----------------------------------------------------------------
Name          Type                               Size  Value
----------------------------------------------------------------
jb_tx         sugar_free_jelly_bean_transaction  -     @834
  flavor      flavor_e                           3     CHOCOLATE
  color       color_e                            2     GREEN
  sugar_free  integral                           1     'h1
  sour        integral                           1     'h0
  taste       taste_e                            2     YUMMY
----------------------------------------------------------------
 
UVM_INFO jb.sv(406) @ 80: uvm_test_top.jb_env.jb_sb [jelly_bean_scoreboard] You have a good sense of taste.
------------------------------------------------------------
Name          Type                               Size  Value
------------------------------------------------------------
jb_tx         sugar_free_jelly_bean_transaction  -     @842
  flavor      flavor_e                           3     APPLE
  color       color_e                            2     GREEN
  sugar_free  integral                           1     'h1
  sour        integral                           1     'h1
  taste       taste_e                            2     YUMMY
------------------------------------------------------------
 
UVM_INFO jb.sv(406) @ 100: uvm_test_top.jb_env.jb_sb [jelly_bean_scoreboard] You have a good sense of taste.
------------------------------------------------------------
Name          Type                               Size  Value
------------------------------------------------------------
jb_tx         sugar_free_jelly_bean_transaction  -     @850
  flavor      flavor_e                           3     APPLE
  color       color_e                            2     RED
  sugar_free  integral                           1     'h1
  sour        integral                           1     'h0
  taste       taste_e                            2     YUMMY
------------------------------------------------------------

With these six posts, the basic UVM tutorial is complete. While this jelly-bean machine is hypothetical, it has the ability of being rephrased with other DUT. In the next possible opportunity, I would like to review other topics omitted from these posts, such as Virtual Sequence. I hope this tutorial assisted in your further understanding on UVM.

Get source code

35 thoughts on “UVM Tutorial for Candy Lovers – 6. Tasting”

    1. Hi Arun,

      The jb_seq is an object of gift_boxed_jelly_beans_sequence class. The gift_boxed_jelly_beans_sequence class has one rand property, called num_jelly_bean_flavors. The jb_seq.randomize() randomizes this num_jelly_bean_flavors.

  1. Hi ,
    Really nice article..
    but have doubt like why have u randomised gift_box_jelly_bean sequence because it is getting randmised in the same sequence class.
    And one more thing.can u please explain the concept of config db and resource db and the syntax direction to use it.
    Thanks

    1. The gift_boxed_jelly_beans_sequence is randomized in order to randomize its knob (num_jelly_bean_flavors). Regarding the configuration database, I have written a new article. Let me know if you have further questions. The uvm_config_db provides a convenience interface to the uvm_resource_db. You don’t need to use the uvm_resource_db.

  2. Hi Keisuke,

    Do you have any good idea for a chip level pin automation configuration in UVM verification environment? For example, we always have some pin config to put the chip into some specific working mode, such as Normal Function mode, Function Test mode, Scan mode, etc. we could use pullup/pulldown as well as register configuration setting to implement this function in module based testbench. But how do I do it in class based testbench UVM?

    Thx,
    Tong

    1. Hi Tong,

      If you need to drive these primary pins from a class-based object, I would probably create an interface that includes these pins and pass it to the testbench using a uvm_config_db.

      // your interface
      interface pin_interface;
        logic test_mode;
        logic scan_mode;
      ...
       
      // your top-level module
      module top;
        pin_interface pin_if();
       
        // your DUT
        DUT dut( .test_mode( pin_if.test_mode ),
                 .scan_mode( pin_if.scan_mode ),
      ...
        initial begin
          uvm_config_db#( virtual pin_interface )::set( .cntxt( null ), 
            .inst_name( "uvm_test_top*" ), .field_name( "pin_if" ), .value( pin_if ) );
        end
      ...

      The UVM-side gets the interface via the uvm_config_db and stores it as a virtual interface and drives it as needed.

      // your UVM driver
      class your_driver extends uvm_driver#(your_transaction);
        virtual pin_interface pin_if;
       
        virtual function void build_phase( uvm_phase phase );
          super.build_phase( phase );
          assert( uvm_config_db#( virtual pin_interface )::get( .cntxt( this ), .inst_name( "" ), 
            .field_name( "pin_if" ), .value( pin_if ) ) );
        endfunction
       
        virtual task main_phase( uvm_phase phase );
          pin_if.test_mode <= 1;
          pin_if.scan_mode <= 0;
      ...

      Having said that, I guess the test mode and the scan mode might not use the normal tests that the UVM testbench provides. If that is the case, you can assign the test mode and the scan mode using the parameters of your testbench, instead of driving them from the UVM testbench.

      // your top-level module
      module top;
        parameter TEST_MODE = 0;
        parameter SCAN_MODE = 0;
       
        // your DUT
        DUT dut( .test_mode( TEST_MODE ),
                 .scan_mode( SCAN_MODE ),
      ...

      When you run a simulation, you can set the TEST_MODE and SCAN_MODE by defparam top.TEST_MODE=1, etc.

  3. Hi Keisuke,

    In the above jelly_bean_test, if I am calling a C function in the task and assign the return value to some local variable or jelly_bean_test property, then how do I print that value ?

    EX:

    class jelly_bean_test extends uvm_test:
    
    logic [10:0] p;
    real q;
    int r;
    
    function new ();
    q = 1.0;
    r = 10;
    endfunction
    
    task run_phase(uvm_phase phase);
          gift_boxed_jelly_beans_sequence jb_seq;
     
          p = c_function(q,r);
    
            *****How do I print this P value here to verify the returned value*****
          
       endtask: run_phase
    
  4. Hello Keisuke,

    Could you please tell me what role dose jelly_bean_configuration play here? In general how is it useful in testbench?

      1. Keisuke,

        How to decide what string to use for “.inst_name” argument in the uvm_config_db’s set function? Can we use any arbitrary string for this argument?

        1. You can use an arbitrary string for the inst_name as long as the object who gets the field (getter) also knows the inst_name. But typically we use the instance name of the getter (often with a wildcard, *, if you want multiple objects to get the field) to avoid unnecessary dependency.

  5. Hello Keisuke,

    Thanks for all your answers. I have an issue while i try to run the jelly bean example in this tutorial. The exact error is

    UVM_ERROR @ 50: run [TEST_DONE_NOHIER] A non-hierarchical object, ‘common.run’ () was used in a call to uvm_test_done.drop_objection(). For this objection, a sequence or component is required.
    UVM_FATAL @ 50: run [OBJTN_ZERO] Object “common.run” attempted to drop objection ‘run’ count below zero

    I know that without looking at the code it will be difficult to say what is going wrong but any idea on what could be going wrong? I don’t know where to start looking for to fix this. Also how do we debug a uvm test bench, specifically is there a switch which will enable printing of the sequence of task call like a call stack in other languages?

      1. Thanks Keisuke. I had make a mistake in the drop_objection argument. I had given “phase” as the argument instead of the the test object

  6. Hi Keisuke,
    Thanks for this awesome tutorial.
    I’ve download the source code tutorial_1_to_6.sv and try to re-run it in EDA playground.
    After fixing some syntax errors, I ran into an error which says “segmentation fault (core dumped)” thatI have not any clues.

    Could you help me to take a look?
    Here is the link:

    http://www.edaplayground.com/x/BUb

    1. Thank you for porting the code to EDA Playground. I found a couple of problems in your code. Please do the followings:

      • Select “UVM 1.1d” instead of “UVM 1.2” from the UVM / OVM menu on the left.
      • Fix the typo +UVM_TEST_NAME to +UVM_TESTNAME in the Compile & Run Options field on the left.
      • Change "jelly_bean_if" to "jb_if" on line 22 of agent.sv.
      • Change uvm_resource_db on line 60 of agent.sv to uvm_config_db like you did for the jelly_bean_driver.
      1. Hi Keisuke,
        Thanks for your time to help fix it.
        I found if I fix all the errors in the code, except for changing the UVM lib from 1.2 to 1.1d, I still got “segmentation fault (core dumped)” error.
        But if I change to 1.1d library, the code works.

        Could you explain a little bit why change from UVM1.2 to UVM1.1d can resolve the problem?

        Thanks in advance.

        Best Regards,
        Rui Huang

  7. Hi Keisuke,

    1. In module top , Is test instantiation not required ?? , if so why ??
    2. What does run_test() do ?

    1. The run_test() task calls the run_test() task of the uvm_root class. It executes all the phases including the build_phase() that dynamically creates a test-bench. So, you don’t need to instantiate the test-bench in the top-module.

      1. Hi Keisuke,

        Can you Please clarify about the difference when we call seq in run_phase (seq.start()) and specifying the default sequence in build phase. Can you Please explain.

        1. If you have a default sequence, it is executed automatically at the beginning of the specified phase (such as the main_phase). If you use start(), you can fully control its execution (timing, conditional execution, and the number of executions, etc.).

  8. Hi Keisuke,

    Thanks for the nice article.
    I have a test say “class test_x extends base_test”
    And i have few random variables declared inside test_x.

    Now if I write few constraints as part test_x, will those be randomized by default?
    Because we are not explicitly calling test_x.randomize() anywhere.

Leave a Reply