Jump to content

Recommended Posts

c4brian and I have messaged a bunch about ways to share data and access between elements in SV/UVM code.
I put common functions/tasks/constants into a package, which I think is standard.
I realize that absolute dot notation of accessing elements (i.e.  variable12 = smthgA.smthgB.smthgC.variableXYZ;) is frowned upon as it is not good for reuse.
So, the UVM presents the uvm_config_db to facilitate reuse and simplify connectivity across a hierarchy.**1
 
Many folks have (including c4brian, I believe) commented that they don't like how verbose it is to ::get from the config db and to check the return result.
   if (! uvm_config_db#(integer)::get(this,"hiccup","xyz_important_var", important_var) ) begin
     `uvm_fatal("ERROR,"important_var not found in config_db")
   end 
In a recent testbench, I've done the following. I probably need to review how the config component is supposed to be used.
I am curious what others think.
 
My setup:
1) Create an object to store common variables and handles.
//This should be a singleton and serve as a central point for others to access global connections. Likely not a good style.  Discuss.
class xyz_config extends uvm_component;
   `uvm_component_utils(xyz_config)

   static xyz_env          m_env;
   static id_state         m_id_state;
   static delay_ctl        m_delayctl;

   function new(string name="xyz_config", uvm_component parent=null);
      super.new(name, parent);
   endfunction

set_env_handle(input xyz_env handle);
   m_env=handle;
endfunction : set_env_handle

...
2) When something is created that other code might want to access, I set a handle to it in xyz_config.
ex1: In the test class constructor (which is declared inside top), create the env and set a handle to it in the xyz_config.  (Probably these actions should be done in the build_phase rather than the constructor.)
class test_base extends uvm_test;
   `uvm_component_utils(test_base)

   xyz_env env;

   function new(string name = "test_base", uvm_component parent = null);
      super.new(name, parent);
      env = xyz_env::type_id::create("env",this);
      xyz_config::set_env_handle(env);

ex2: In the env build_phase, I set handles to some objects which track data which is useful in many sequences and other code

function void xyz_env::build_phase(uvm_phase phase);
   super.build_phase(phase);
  ...

   // Create Helper Structures
   m_id_state = id_state::type_id::create("m_id_state",this);
   xyz_config::set_id_state_handle(m_id_state);
   m_delayctl = delay_ctl::type_id::create("m_delayctl",this);
   xyz_config::set_delayctl_handle(m_delayctl);
3) Now, in various parts of the tb (such as from sequences), I can access xyz_config as a singleton, and access its handles (using . "dot" notation) to whatever data structures it was given access to.  (I'm thinking now that those data structures should be in the scoreboard.)

The dot notation is much more concise than declaring a variable and then performing a uvm_config_db ::get and checking the return value. 

//in seq, id_state which tracks system-state used to set transaction variable
jhg_input_trans.state = xyz_config::m_id_state.get_jhg_state(.loopback(loopback), .fce_1(fce_1));
or
//in virtual seq, a call is made that turns off any internal stallers (special stallers to alter congestion in the dut)
xyz_config::m_env.turn_off_internal_stallers();
or
//in scoreboard, as monitors send in transactions, it adjusts state info which is used by sequences to make legal input
xyz_config::m_id_state.move_some_id(.note("fuf->xyz"), .syd(t.fuf_xyz_read_syd), .from_q(Q001), .to_q(Q111));

A benefit of this is that the user can more easily (from this line of code), see what is being accessed, rather than needing to rerun a test and dump config_db or grep thru a bunch of files to see who did the ::set.

With regards to reuse, it seems to me that as long as the new tb (that wants to benefit from reuse), sets the handles in the _config properly, it is just as reuse-able.

 

Probably, I am missing something.

 

 
I've have a vague notion and have heard soft feedback that this style (which I feel is unique to me) is not good.  Maybe I'm imagining this or exaggerating it in my mind.  I bring it up here, in the event anyone has feedback or a good scolding to give.
 
 
**1
  Conceptually I've been taught to think of uvm_config_db as a "string"-accessible associative array, or a group of associative arrays; something like 'one for each datatype'.
  I'm not poking into the uvm base class here, but just voicing my understanding out-loud for comments.  Conceptually, I think of uvm_config_db as operating as follows.
A user specifies the data type that they want to store or get - which 'conceptually' selects which associative array to access.
A user specifies a "string-name" which is the key into that associate array.
A user reads or writes that associative array as follows.
  To write, they use ::set,  specify a "string-name",  and provide a value.
  To read, they use ::get, specify a "string-name", and provide a variable, into which the value stored at "string-name" will be copied.
 
(Note: I've modified the code examples to shorten them, so may have introduced typos.)
Edited by ljepson74
fixed typo. For ex 1 in section 2), "rrc_config::set_env_handle(env);" should have been "xyz_config::set_env_handle(env);"
Link to comment
Share on other sites

My setup:
1) Create an object to store common variables and handles.

 

You create a uvm_component to store your configuration; I've never seen that, was it on purpose?

 

So basically you have a full STATIC configuration singleton (no automatic variables I assume).

 

I am mainly jealous because I'm having to fool around with...

1. NO config_db:   p_sequencer (no config_db, but I still have to remember to populate my "goodie" handles)

2. YES config_db: m_sequencer (using the config_db scope to snag agent configuration items, and then use methods there for hardware synchronization or whwatever)

3. NO config_db:   In the case of transient objects like sequence items, or sequences, assigning handles to configuration objects from a parent component (test-> virtual sequence, sequence) etc, for use in constraints, for example.

 

I digress.  Please weigh in on the singleton configuration approach.

Link to comment
Share on other sites

Yes.  And I suppose there is no reason it should be a uvm_component - I am not using phases or anything particular to uvm_components here.

I am probably muddying the waters by having "config" in the name, and will do some more reading today to understand normal UVM configurations.

 

"xyz_access_point".  Probably that is a better name for what I do here than xyz_config.   xyz is the module being tested in this case, and this singleton class below is used to provide a means to use the static operator, ::, to access elements from anywhere in the testbench.

 

ex:

xyz_config::m_id_state.move_some_id

 

Is it a "a full STATIC configuration singleton", you ask?  I'm not fully sure what that means, but see below.

// CLASS: xyz_config
//
//This should be a singleton and serve as a central point for others to access globally used objects.
//This is likely not a good style.  It is certainly not agreed upon.  Discuss.
//
class xyz_config extends uvm_component;
   `uvm_component_utils(xyz_config)

   static xyz_env     m_env;
   static id_state    m_id_state;
   static delay_ctl   m_delay_ctl;

   function new(string name="xyz_config", uvm_component parent=null);
      super.new(name, parent);
   endfunction

   extern static function void set_env_handle(input xyz_env handle);
   extern static function void set_id_state_handle(input id_state    handle);
   extern static function void set_delay_ctl_handle(input delay_ctl handle);
endclass : xyz_config

//--

// FUNCTION: set_*_handle
//
// These functions receive and set handles to their respective objects
//
function void xyz_config::set_env_handle(input xyz_env handle);
   m_env=handle;
endfunction : set_env_handle

function void xyz_config::set_id_state_handle(input id_state    handle);
   m_id_state=handle;
endfunction : set_id_state_handle

function void xyz_config::set_delay_ctl_handle(input delay_ctl handle);
   m_delay_ctl=handle;
endfunction : set_delay_ctl_handle

c4brian, you lost me on the jealous part.  What do the YES and NOs mean?  Those are uses for config objects (whether they use config_db or not) or smthg?

Link to comment
Share on other sites

  • 3 weeks later...

ah haha.. sorry that was confusing...

 

I meant YES = example using the config db, NO = example not using the config db.

 

Your new name makes a little more sense.  It could probably be a uvm_object unless you need it to have a hierarchical path, which it doesnt sound like.

I'll file this technique under "innocent until proven guilty".

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...