ljepson74 Posted October 24, 2015 Report Share Posted October 24, 2015 (edited) 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 August 27, 2020 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);" Quote Link to comment Share on other sites More sharing options...
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.