UVM Tutorial for Candy Lovers – 5. Environment

Last Updated: April 4, 2014

This post will provide a continued explanation on the rest of the verification components.

Subscribers

Functional Coverage

The functional coverage subscriber (jelly_bean_fc_sucbscriber) identifies the generated jelly beans to take a total tally. The jelly_bean_transaction sent from the monitor is sampled by the write function on the line 21, and takes the cross coverage of the flavor, color, and other characteristics of the 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
class jelly_bean_fc_subscriber extends uvm_subscriber#(jelly_bean_transaction);
   `uvm_component_utils(jelly_bean_fc_subscriber)
 
   jelly_bean_transaction jb_tx;
 
   covergroup jelly_bean_cg;      flavor_cp:     coverpoint jb_tx.flavor;      color_cp:      coverpoint jb_tx.color;      sugar_free_cp: coverpoint jb_tx.sugar_free;      sour_cp:       coverpoint jb_tx.sour;      cross flavor_cp, color_cp, sugar_free_cp, sour_cp;   endgroup: jelly_bean_cg 
   function new(string name, uvm_component parent);
      super.new(name, parent);
      jelly_bean_cg = new;
   endfunction: new
 
   function void write(jelly_bean_transaction t);      jb_tx = t;      jelly_bean_cg.sample();   endfunction: writeendclass: jelly_bean_fc_subscriber

Scoreboard

In the functional coverage subscriber, the jelly_bean_transaction was sampled in the write function. Similar to the functional coverage subscriber, focus on the write function is the key. The scoreboard subscriber uses the write function to call the check_jelly_bean_taste function in the parent component (jelly_bean_scoreboard). This check_jelly_bean_taste function compares the DUT response against the expected response.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
typedef class jelly_bean_scoreboard;
 
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);      jelly_bean_scoreboard jb_sb;       $cast( jb_sb, m_parent );      jb_sb.check_jelly_bean_taste(t);   endfunction: writeendclass: jelly_bean_sb_subscriber

The check_jelly_bean_taste function expects the DUT module to “respond negatively to the sour chocolate-flavor jelly bean, while reacting positively to the other combinations.” When the DUT responds properly, the jelly-bean flavor and color are printed. When the DUT is not functioning correctly, the function will print an error message.

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
class jelly_bean_scoreboard extends uvm_scoreboard;
   `uvm_component_utils(jelly_bean_scoreboard)
 
   uvm_analysis_export#(jelly_bean_transaction) jb_analysis_export;
   local jelly_bean_sb_subscriber jb_sb_sub;
 
   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_analysis_export = new( .name("jb_analysis_export"), .parent(this));
      jb_sb_sub = jelly_bean_sb_subscriber::type_id::create(.name("jb_sb_sub"), .parent(this));
   endfunction: build_phase
 
   function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);
      jb_analysis_export.connect(jb_sb_sub.analysis_export);
   endfunction: connect_phase
 
   virtual function void check_jelly_bean_taste(jelly_bean_transaction jb_tx);      uvm_table_printer p = new;      if (jb_tx.flavor == jelly_bean_transaction::CHOCOLATE && jb_tx.sour) begin         if (jb_tx.taste == jelly_bean_transaction::YUCKY) begin            `uvm_info("jelly_bean_scoreboard",                       { "You have a good sense of taste.\n", jb_tx.sprint(p) }, UVM_LOW);         end else begin            `uvm_error("jelly_bean_scoreboard",                        { "You lost sense of taste!\n", jb_tx.sprint(p) });         end      end else begin         if (jb_tx.taste == jelly_bean_transaction::YUMMY) begin            `uvm_info("jelly_bean_scoreboard",                       { "You have a good sense of taste.\n", jb_tx.sprint(p) }, UVM_LOW);         end else begin            `uvm_error("jelly_bean_scoreboard",                        { "You lost sense of taste!\n", jb_tx.sprint(p) });         end      end   endfunction: check_jelly_bean_tasteendclass: jelly_bean_scoreboard

Many consider it a hassle to create a separate scoreboard class. In our case, it may be more straightforward to check expected response in the jelly_bean_sb_subscriber, because the expected response is created from the inside. Yet, there are times when two analysis ports are necessary, one for expected data and the other for actual data. The write function of a subscriber does not support multiple analysis ports. One solution to this problem is to develop a scoreboard class with two subscribers. Thinking about the extendability in the future, creating two layers like our scoreboard might be a good idea.

Environment

To provide a conclusion, this section will explain the verification environment that contains all the verification components. Simply stated, the environment connects the previously explained agent and the subscribers. Taking a look at the first post of the series will help better understand this concept.

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_sub;
   jelly_bean_scoreboard    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_sub = jelly_bean_fc_subscriber::type_id::create(.name("jb_fc_sub"), .parent(this));
      jb_sb     = jelly_bean_scoreboard::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_sub.analysis_export);      jb_agent.jb_ap.connect(jb_sb.jb_analysis_export);   endfunction: connect_phaseendclass: jelly_bean_env

The next post will show the anticipated test using these components.

Get source code

26 thoughts on “UVM Tutorial for Candy Lovers – 5. Environment”

  1. There are a few points I am confused on here.
    What is the need for the scoreboard subscriber? You don’t create a handle to it in the env, the scoreboard already has an analysis export…..
    Is it because a scoreboard class doesn’t have a built in write() method?

    Also in the fc subscriber you don’t create a handle to an analysis export, nor do you reference it in the connect and build phases (the same goes for the scoreboard subscriber) is that because these are extended uvm_subscribers and have this analysis export by default ( called analysis_export)? I.e from the uvm base class

    Thanks
    Steve

    1. The jelly_bean_scoreboard instantiates the local jelly_bean_sb_subscriber. For this tutorial, the jelly_bean_scoreboard class is not indispensable. I could have used the jelly_bean_sb_subscriber only and moved the check_jelly_bean_taste function from the jelly_bean_scoreboard to the jelly_bean_sb_subscriber. As you mentioned, the reason I had a subscriber was I wanted the write method in the scoreboard. I also wanted expandability of the scoreboard so that I could add another subscriber in case I needed the second write. Another approach to have the second write would be using `uvm_analysis_imp_decl macro.

      Regarding the analysis_export, the uvm_subscriber class (the base class of the fc and sb subscribers) has the analysis export called analysis_export.

      1. a small correction to the last line … uvm_subscriber class has analysis import called analysis export.

        uvm_analysis_imp #(T, class_name) analysis_export.

  2. Hi Keisuke,

    Can you please add some sort comments whereever required in the piece of code you provide so that it is easy to grab the content.

    Also, can you give me a brief idea why we reuiqre a subscriber ? or waht is its significance ?
    Is it a gateway between the components in agent and outside ??

    Thanks in Advance..!
    -surya

    1. A subscriber is a component typically used with a monitor. It “subscribes” the transactions the monitor sends via an analysis_port. Every time a transaction is sent by the monitor, the write function of the subscriber is executed. You can use the write function to collect functional coverage or check the validity of the transaction, for example.

  3. Hi Keisuke,

    Can you please explain, why are you casting with m_parent at line no 13 in jelly_bean_sb_subscriber and also could you please explain the significance of m_parent there.

    Thanks
    Dheeraj

    1. Each uvm_component has a property called m_parent, which points to the parent component that created the component. In this example, the m_parent of jelly_bean_sb_subscriber points to the jelly_bean_scoreboard. Please see the line 14 of jelly_bean_scoreboard.
      The $cast is required because the type of m_parent is uvm_component, which does not know anything about the check_jelly_bean_taste function.

  4. Hello Keisuke,

    In the scoreboard class uvm analysis export object is declared “uvm_analysis_export#(jelly_bean_transaction) jb_analysis_export” . Why cannot it be a uvm_analysis_imp type object since “imp” class serves as termination for the analysis port.

    1. If you look at the Verification Components figure in Overview, you will find the jelly_bean_sb_subscriber serves as the termination point, not the jelly_bean_scoreboard. That’s why the scoreboard uses a uvm_analysis_export instead of a uvm_analysis_imp.

  5. Hey Keisuke,
    my question is regarding the $cast.
    in the write function of jelly_bean_sb_subscriber, the jelly_bean_scoreboard is already defined.
    hence the jb_sb would be aware of check_jelly_bean_taste task. then why is the cast needed.

    plus when a castis done as $cast(jb_sb,m_parent). the m_parent which point to component class,will start pointing to a extended class which would be a error ,right ?

    Also, thanks for the brilliant blog, its very useful. Thanks.

    –Vin

    1. The jb_sb is declared as the jelly_bean_scoreboard type on the line 11, but the value of jb_sb is null because we did not assign any value yet. On the line 13, we attempted to assign the value of jb_sb to be m_parent so that jb_sb (object handle) points to the m_parent object. Since the type of m_parent is uvm_component, not jelly_bean_scorebord, we needed to use the $cast. This casting won’t cause any errors as long as the m_parent is a handle to a jelly_bean_scoreboard object.

  6. Hi keisuke,
    I have one small doubt, In jelly_bean_fc_subscriber we are having handle jb_tx of type jelly_bean_transaction, So why we are not using create/new method to that handle.

    1. The jb_tx is an object handle that points to the same object passed by the write function (see the line 20 of the jelly_bean_fc_subscriber). Since we do not create a new object, we call neither new nor create.

  7. I somehow remembered only the uvm_analysis_imp can provide the write method, but looks here the subscriber’s analysis_export is hooked up to the scoreboard. Could you please explain why the write method is used with analysis_export?

    Another thing I’m not clear is that in subscriber, the scoreboard is declared in “write” function, in scoreboard, the subscriber is declared as local and further created in the build_phase. Is there any problem with the double referencing to each other?

    Thanks in advance!

      • The type of the analysis_export of the uvm_subscriber is actually uvm_analysis_imp.
      • As you mentioned, the jelly_bean_sb_subscriber and the jelly_bean_scoreboard each need a handle to the other. The typedef (the first line) of the jelly_bean_sb_subscriber provides a forward declaration for the jelly_bean_scoreboard. The typedef lets the compiler know the actual class definition of the jelly_bean_scoreboard will follow.
  8. I have a confusion. I cannot see anywhere the write function of scoreboard_subscriber being called, like the functional coverage subscriber write was called in monitor. Then how is that write implemented?

    1. The jb_ap.write(jb_tx) on the line 31 of the jelly_bean_monitor class (see Agent) executes every write() function connected to the jb_ap. In other words, the line 31 executes the write() function of the jelly_bean_sb_subscriber as well as the write() function of the jelly_bean_fc_subscriber.

  9. Hey Kiesuke,

    I have the same question as Ella, the scoreboard is declared in “write” function, in scoreboard, the subscriber is declared as local and further created in the build_phase. Is there any problem with the double referencing to each other?

    Can you be more specific about the answer you gave to ella.

    Thanks.

    1. typedef class jelly_bean_scoreboard declares jelly_bean_scoreboard is to be of type class. This allows compiler to compile jelly_bean_sb_subscriber when it encounters jelly_bean_scoreboard in the write function even though it is not defined yet.

  10. When having a scoreboard with a prediction port and a measurement port that are not generating transactions at the same rate, how would you handle that?

    This is actually a typical use case for an ADC where the rate of input signals is faster than the sampling rate of the ADC.

  11. Hi Keisuke,
    Thanks for the nice blog. I have one question.
    Let us say, in jelly_bean_scoreboard, if we have overridden any function from uvm_scoreboard. In this case, we should be able to access that overridden function in sb_subscriber just by using m_parent without casting right?

Leave a Reply

Your email address will not be published. Required fields are marked *