UVM Config DB

UVM driver passes an integer variable through configDb. When the monitor tries to get the variable, the value is always 0.

Here is the driver code:



  int REQ_NUM_WORDS;

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    uvm_config_db#(int)::set(null, "*", "driver_int", REQ_NUM_WORDS);
  endfunction: build_phase

And the monitor is:


  int REQ_NUM_WORDS;
  virtual task run_phase(uvm_phase phase);
    super.run_phase(phase);      
    if(!uvm_config_db#(int)::get(this, "", "driver_int", REQ_NUM_WORDS))
       `uvm_fatal("NO_NUM_WORDS",{"uvm event must be set for: ",get_full_name(),".driver_int"});   
    :
    :
    :
  endtask

I have printed REQ_NUM_WORDS, both in driver and monitor. Though the the value changes to 803, 900 in driver, values printed in monitor is always 0.

I enabled +UVM_CONFIG_DB_TRACE switch and ran the test. I see below [CFGDB/SET].

UVM_INFO verilog_src/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration ‘*.driver_int’ (type int) set by = (int) 0

I believe the last part should be “set by = (int) {REQ_NUM_WORDS}” to reflect the value of REQ_NUM_WORDS.
I did check configDb set and not able to find the issue.

Any idea, what am i missilng?

In reply to uvmsd:

The uvm_config_db is pass by value. What you need to do is create an object

class cfg;
  int REQ_NUM_WORDS;
  // add other variables you want to share
endclass

Then construct this object in your driver and set it.

In your monitor, you can get a handle to this object and retrieve it from the config_db.

In reply to dave_59:

Thanks Dave!
I understand that, using configuration makes things more reusable friendly.
Can’t we do it without configuration? Like, directly setting an integer in the driver and retrieving it in monitor. I have done that for an uvm_event and things look good.

I set an uvm_event in driver and retrieve it in the monitor.

 
 class my_driver extends uvm_driver(my_seq_item);
    uvm_event DELAY_DONE;
   :
   :
   function void build_phase(uvm_phase phase);
     super.build_phase(phase);
     uvm_config_db#(uvm_event)::set(null, "*", "driver_event", DELAY_DONE);
   endfunction: build_phase
   :
   
   virtual task drive();  
    :
    :
    DELAY_DONE.trigger;
   endtask

 endclass

Its retrieved in Monitor:


class my_monitor extends uvm_monitor;
  uvm_event DELAY_DONE;
     :
     :
  virtual task run_phase(uvm_phase phase);
      super.run_phase(phase);      
      if(!uvm_config_db#(uvm_event)::get(this, "", "driver_event", DELAY_DONE))
        `uvm_fatal("NO_UVM_EVENT",{"uvm event must be set for: ",get_full_name(),".driver_event"}); 
    :
    :
    DELAY_DONE.wait_trigger();
    :
    :
   endtask
endclass

AM i missing something here?

You don’t have to use a configuration object.

Though the the value changes to 803, 900 in driver, values printed in monitor is always 0.

How and when are you setting REQ_NUM_WORDS to 803,900 in your driver? You don’t show it.

UVM_INFO verilog_src/uvm-1.2/src/base/uvm_resource_db.svh(121) @ 0: reporter [CFGDB/SET] Configuration ‘*.driver_int’ (type int) set by = (int) 0

According to your log, at the time your driver calls set() REQ_NUM_WORDS is 0. You must be changing the value after that.

But before you try to fix that, you really shouldn’t have a component setting a value in a sibling component, it’s not good encapsulation. In other words, REQ_NUM_WORDS should be a field in your agent, and it should propagate it down to both the driver and monitor. This is fine if you have a single value like this, but if you have more than a couple, a configuration class makes more sense.

In reply to uvmsd:
You did not mention in your original question the intent behind what you wanted to share.

The uvm_config_db can be used to configure many kinds of things. Usually one thinks of a configuration object as a set once, and get one or more times. If you need a uvm_event, you can put the through the uvm_config_db as well. In that case, you are configuring the handle to a shared uvm_event. It is usable friendly that way because the driver needs no knowledge of the components that contains it.

In reply to warnerrs:

You don’t have to use a configuration object.
How and when are you setting REQ_NUM_WORDS to 803,900 in your driver? You don’t show it.
According to your log, at the time your driver calls set() REQ_NUM_WORDS is 0. You must be changing the value after that.
But before you try to fix that, you really shouldn’t have a component setting a value in a sibling component, it’s not good encapsulation. In other words, REQ_NUM_WORDS should be a field in your agent, and it should propagate it down to both the driver and monitor. This is fine if you have a single value like this, but if you have more than a couple, a configuration class makes more sense.

Sorry, i have not yet completed the coding part. Below is the intent.

REQ_NUM_WORDS represents packet size. I want to send faulty packets(sending the packets with less or more than the standard size). The packet size is set by the sequence and i have added a field in the seq_item. Using this field REQ_NUM_WORDS(packet size), the driver generates cs(chip_select) accordingly.
And i wanted this info to be passed onto monitor too so that the monitor would take appropriate action.

Yes, REQ_NUM_WORDS might change dynamically throughout the test.

Will try the option mentioned by you,. Thank you!

In reply to dave_59:

In reply to uvmsd:
You did not mention in your original question the intent behind what you wanted to share.

Below is the intent.

REQ_NUM_WORDS represents packet size. I want to send faulty packets(sending the packets with less or more than the standard size). The packet size is set by the sequence and i have added a field in the seq_item. Using this field REQ_NUM_WORDS(packet size), the driver generates cs(chip_select) accordingly.
And i wanted this info to be passed onto monitor too so that the monitor would take appropriate action on those packets.

And REQ_NUM_WORDS might change dynamically(packet boundaries) throughout the test.

If you need a uvm_event, you can put the through the uvm_config_db as well. In that case, you are configuring the handle to a shared uvm_event. It is usable friendly that way because the driver needs no knowledge of the components that contains it.

Sorry, I didn’t get what you said about uvm_event above.

BTW, I have passed uvm_event(not the global pool) through config_db in the driver and retrieved it in the monitor. It did work. It didn’t have to go through agent.

  1. An uvm_event is created and triggered in driver. It triggered based on certain delays. And this uvm_event is set in build_phase of driver.
  2. I did ‘get’ to this uvm_event in build_phase of monitor. Monitor waits for uvm_event to be triggered and then starts writing into TLM fifo(that’s the requirement)

Ok, my understanding is that, once you do a set to uvm_config_db to any variable, and if you have retrieved it in other component, it should reflect all the subsequent changes occurring on that variable, right?
Of course, we have to make sure that, the get doesn’t occur before the set.

Please let me know.

In reply to uvmsd:

You need to distinguish between the handle of the object that you set/get through the uvm_config_db, which never changes, and changing the members of the object. Maybe we are saying the same thing, but you may want to look at my short class on classes.

In reply to dave_59:

In reply to uvmsd:
You need to distinguish between the handle of the object that you set/get through the uvm_config_db, which never changes, and changing the members of the object. Maybe we are saying the same thing, but you may want to look at my short class on classes.

Thanks Dave for the link!
My bad, how I forgot that the uvm_event is a class, not a construct.
I was wondering how did it work.
And now I am convinced about having a configuration class. And things are working fine.

Thanks for your time and patience!

In reply to uvmsd:

REQ_NUM_WORDS represents packet size. I want to send faulty packets(sending the packets with less or more than the standard size). The packet size is set by the sequence and i have added a field in the seq_item. Using this field REQ_NUM_WORDS(packet size), the driver generates cs(chip_select) accordingly.

Why can’t your monitor infer the packet size based on the cs signal? No need to tell the monitor anything.

In reply to warnerrs:

In reply to uvmsd:
Why can’t your monitor infer the packet size based on the cs signal? No need to tell the monitor anything.

oh! yes.you are correct. That is one way. I did think of it. Since, packets are coming in bit by bit, packet size calculation results in some lines of code(thats how Driver generates cs). Monitor already has so much of logic with fork-join constructs. I just thought to keep it simple uaing configDb. But ended up adding configuration.

Thanks for your genuine inputs.

In reply to uvmsd:

Monitor already has so much of logic with fork-join constructs.

Monitors shouldn’t rely on anything from the driver. By making the monitor dependent on the driver, you eliminate the possibility of using this as a passive agent. This sounds like an external interface, so it’s more likely that you can live with that limitation. But consider if you wanted to replace your driver with a model from a vendor, or to create a multi-chip simulation, then you’d still want to be able to put this agent into passive mode.

Best of luck.

In reply to warnerrs:

In reply to uvmsd:
Monitors shouldn’t rely on anything from the driver. By making the monitor dependent on the driver, you eliminate the possibility of using this as a passive agent. This sounds like an external interface, so it’s more likely that you can live with that limitation. But consider if you wanted to replace your driver with a model from a vendor, or to create a multi-chip simulation, then you’d still want to be able to put this agent into passive mode.
Best of luck.

Good point! I didn’t think about it. Definitely will keep that in my mind and will see if i can revisit my monitor. Thanks you!

In reply to dave_59:

The uvm_config_db is pass by value. What you need to do is create an object

can you please explain more here