Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by ljepson74

  1. When used in a coverpoint, what is the difference between overlapped implication and logical AND? |-> vs. && cp_test : cover property ( @(posedge clk) disable iff (!resetn) A |-> B ); cp_test : cover property ( @(posedge clk) disable iff (!resetn) A && B ); ? A colleague asked me. It seems to me they are the same and the logical AND is more readable.
  2. Nhat, Can you provide more details in your question? You want a monitor and scoreboard to be able to check that suspend and resume operations occur correctly for a flash memory design. Correct? I would guess that few people on this forum are familiar with flash memory controller design and with those operations. I am not familiar with them. How about if you separate the application specific part (flash controller) of your question from the UVM/SV part? I think the flash part of the question confuses and deters people from responding. Your question was very short and provided little information. Look at other questions on this forum. Read this posting about asking good questions: https://www.biostars.org/p/75548/. We're all in a rush somtimes and then ask questions quickly and with little information. I certainly do. And sometimes we can review and review and add more and more information to a question (gold-plating it, people say - making it perfect), and the people that ultimately respond to it only needed a small part of that, and a lot of time is wasted. I certainly can take forever to compose a question/response, sometimes. It's tough sometimes to know how much time and detail to put into a question. I think that in this case more detail in the question would have gotten you an answer, already. More information helps others determine the experience level of the person asking the question - resulting in a more appropriate answer. Would it be correct to rephrase your question like this? *I am new to UVM. *I must verify that two types of multi-cycle operations occur correctly, but am unsure of how to best do it. *The operations are i) suspend of either a program or erase command ii) resume of either a program or erase command. *Can someone help me determine how to verify this? Or, maybe you are not new to UVM. If so, share what you have already tried. Let's make the problem smaller. If we only wanted to verify that a bus changes from 0x04 to 0x44, using a monitor and scoreboard, can you do that? Or should we start earlier in an explanation?
  3. 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?
  4. 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); rrc_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.)
  5. Regarding c4brian comment: You summed it up very well. All of the 'pulling' would happen in one centralized file. I'll start a new thread about this so as not to change the topic here, where I think you might add other comments and thoughts from our side discussion. (new thread: http://forums.accellera.org/topic/5234-uvm-config-db-and-hierarchical-access/ ) --- "tudor has mentioned this before, but "singleton" just means... there's 1, right?" Yup.** (There could be some code inside the class to restrict instantiation of the class to one object (as I recall), but I just instantiate it once.) --- Regarding bhunter1972 comment: I've heard (and read, I think) that sequences should not have any concept of time. This is smthg I need to explore more. --- I've totally mixed you two Brians up in the past on this forum. It's nice to have this thread appear as a way to straighten things out in my mind. **Tudor also got me thinking about composition vs. inheritance more.
  6. My favorite technique... 1) delay_gen: a class that can provide delay. We'll create one of these for each channel/interface that needs delays. next - function that returns an int, which can be used for delay set_mode - function used to select one of multiple constraints in delay_gen, to indicate the values/flavor of ints that next should return 2) delay_gen_container: a class that holds many delay_gens add_controller - function with string input which is name of the delay_gen to create. adds a delay_gen to an associate array, accessible by the string name next - function with string input (name of delay_gen), used to access associate array and calls next function of the specified delay_gen other - other functions to set delays for all members of the delay_gen associative array. ex: set all to max-throughput mode, where all next calls return 0, so we don't have any delays 3) env: the environment in the build_phase creates delay_gen_container, then calls add_controller for each channel that will need delays. ex: m_dg = delay_gen_container::type_id::create("m_dg",this); my_config::set_dg_handle(m_dg); //set handle in config so others (such as sequences) can access it m_dg.add_controller("channel1"); m_dg.add_controller("channel2"); m_dg.add_controller("channel3"); 4) seq: Whenever a sequence needs a delay, it calls next for the channel it refers to. (If you have an array of the same channel, that string name just has a number suffix to refer to the specific channel.) ex: //Inside a sequence **1 virtual task body(); int gap; gap = my_config::m_dg.next("channel2"); //call next to get delay for channel2 **2 tick(gap); //wait gap clk cycles `uvm_create(req) start_item(req); .... //here we set the req data to smthg meaningful (or just randomize it) finish_item(req); endtask : body 5) tick(n) is just a task in the package for the environment that anyone uses to access 'time'. It uses a vif as you do in your #1. task tick(input int number); repeat (number) @(my_config::m_env.m_abcdef_agent.m_vif.smp_cb); endtask I don't like to clutter my code with calls to uvm_config_db and checks for return values, so try to minimize them or restrict them to locations where they don't distract too much from the main code. I try to reduce this as much as possible by using the the scope resolution operator, ::, with my_config (singleton), my_config::blahblahblah, to get what I want. I am pretty sure this is verboten in reuse methodology. But, I am not sure why, as it would just mean that the calls to uvm_config_db could/would be in the my_config. (That said, I need to learn more about the suggested use of configuration objects.) I'd love some feedback here about this technique, but don't want to hi-jack this thread. Aside: I typically like to perform the wait before selecting the data/transaction that will be sent. I think this is system-specific, but for the last few modules I worked on, when a transaction's data is set, it is set with the current system state in mind. If 100 clk cycles elapse before it is input to the DUT, the state may/will have changed and it may be illegal or not-useful. Even if this is not the case, I try to stick to this ordering 1) perform delay 2) set transaction data 3) send transaction , versus swapping 1 and 2. (Certainly, some info about the transaction might need to be decided before a wait range is selected.) I realize this all depends on the type of DUT. If you're local to Si Valley, come by here sometime. I believe we shared thoughts on this a few months ago in a meeting. http://www.meetup.com/SystemVerilog-Social-Club-Silicon-Valley all the best,
  7. I am trying to run the uvm builtin register sequences. I seem to have broken our usage of them in porting code from a previous project. Q1: In the past, we've started them as default sequences. Is there any way to have an error/warning appear if a 'set', such as the below, is never utilized (or 'get'-ed)? uvm_config_db#(uvm_object_wrapper)::set(this, "*.m_reg_agent.m_seq_reg.main_phase", "default_sequence", uvm_builtin_reg_test_seq::type_id::get()); I've added uvm_top.print_topology(); and uvm_config_db::dump(); and it seems the ::set should be working, but nothing is starting. Q2: Are builtin (base class) sequences automatically "::created" somehow/somewhere? (Creation/new-ing is still necessary when you setup a default sequence, right? Or is there some magic singleton-ness that happens?) Q3: My error of the moment is as follows. Your thoughts are appreciated. UVM_FATAL @ 39990: reporter@@seq [SEQ] neither the item's sequencer nor dedicated sequencer has been supplied to start item in seq always@(posedge clk), ljepson74
  8. 2+ years later ... Does anyone have new information on checker support and/or best practices for usage?
  9. How do I display the name string of the UVM_VERBOSITY? I have been using this to report the verbosity level, but it returns an int. m_rh.get_verbosity_level() How would you display the enumerated name as opposed to the enumerated value? I'm looking at section "6.19 Enumerations" of the LRM (1800-2012.pdf) and close, but not there yet, so I punt this question out into the ether. .name() seems like it should be in there somewhere.
  10. I learned .... uvm_sequencer has the following two functions: function void kill_sequence ( uvm_sequence_base sequence_ptr) virtual function void stop_sequences () Tells the sequencer to kill all sequences and child sequences currently operating on the sequencer, and remove all requests, locks and responses that are currently queued. This essentially resets the sequencer to an idle state. Stop_sequences While this is different from my original post, and I have not tried either yet, these look useful for what I was doing and will probably allow me to replace the function I added to the virtual sequence, so that it can terminate its child sequences. What I was doing was trying to kill all activity in/from testbench, so that I can reset at a random time in the middle of a test. (I am specifically avoiding phase jumping.) (I learned this from interviewing a candidate today and doing some follow-up research. It's great to learn something in an interview.)
  11. We hacked around with this tonight @ http://www.meetup.com/SystemVerilog-Social-Club-Silicon-Valley Here is the code. I think the uvm added to some confusion for me. Maybe tomorrow I'll replace the interface I used. // From SVSC meetup, 2015 July 20 // Some code we hacked around with. // Trying to get event to trigger between module and class. // Play: // Swap A1 and A2. // Switch the locations of the initial blocks, so order compiler // encounters them differs. // Comment out/in B1, to adjust the triggering of the event class event_holder; event class_e; function new(); $display(" pre trigger."); ->$root.top.top_e; //or even just ->top.top_e; $display(" post trigger."); endfunction endclass : event_holder module top; event top_e; initial begin event_holder m_event_holder; $display(" Start ** ** **."); #1; //B1 m_event_holder=new(); #55; //->top_e; end initial begin $display(" pre event."); @top_e; //A1 //wait(top_e.triggered); //A2 $display(" post event."); end endmodule
  12. We (as an industry) normally use virtual interfaces to communicate between the module 'world' and the class 'world' of SystemVerilog. Right?** Can anyone comment on the use of events (named events) for class<-->module communication? Good? Bad? Gothchas? Scenario: A test wants to send a signal (trigger) to the top (where the DUT is instantiated). Creating a 1b interface to transmit this trigger seems like overkill, but that is what I did. I had some trouble triggering on an event between module and class. Hierarchy problems. I did not try passing the event thru the config_db - if that even makes sense (is possible). **Correct me if I'm wrong, but that's the way I see it. I'm sure the UVM base class has a sea of code that I don't understand.
  13. When using uvm_sequence_base's kill on a virtual sequence, will it kill child sequences? It seems to me that it will not, but I am unsure and have not explored this much, yet. Looking briefly at the UVM base class, I'm guessing that a virtual sequence should have its own function to terminate child sequences. ----- update: I added a function in the virtual sequence to terminate child sequences and everything is working fine.
  14. Praneeth, Try something like this in the sequence: virtual my_if m_my_vif; if (! uvm_config_db#(virtual my_if)::get(uvm_root::get(),"*","somestring",m_my_vif)) `uvm_fatal("config_db"," vif connect failed") Elsewhere, you'd need to have added the handle to the config_db, like so: my_if m_my_if; uvm_config_db#(virtual my_if)::set(uvm_root::get(),"*", "somestring", m_my_if); I haven't compiled this to check for typos. Feedback from gurus welcome. Particularly, I'd like to hear thoughts on having a clock in a sequence.
  15. Thanks a lot, Dave. Aside: For non-English speakers, my above usage of the word "tine" (a prong or sharp point, such as that on a fork) was an attempt at some fork humor.
  16. I found that even if the condition is true from the start, as it is here... int count=10; ... @(posedge clk iff (count>=10)); a single posedge clk will be waited for.
  17. I happened across the following code. @(m_vif.smp_cb iff (m_vif.smp_cb.xyz_enable) ); To get to the crux of my question, let's consider it to be the below code. I don't think I've dropped anything relevant with this change (but I post both, b/c I have dropped important info with my edits in the past). @(posedge clk iff (xyz_enable) ); Q) How should the above line behave? How would you read that line aloud? 1) "Wait for a posedge of clk, if and only if xyz_enable is true." //That's how I read it, but that is incorrect. 2) "Wait for posedges of clk until xyz_enable is true." //This is correct. My thought was that when xyz_enable==0, it would just 'fall through' and there would be no wait for a posedge of clk. i.e. if(xyz_enable) @(posedge clk); Can someone help me read that line as a descriptive sentence? Here is some test code: module top; logic clk; int count=0; initial clk=0; always #1 clk = ~clk; initial begin $display($time," ************* START"); repeat (10) @(posedge clk); fork begin repeat(33) begin $display($time," Tine1: waiting for posedge clk. count=%0d",count); @(posedge clk); count++; end end begin $display($time," Tine2: waiting for count=10"); @(posedge clk iff (count==10)); $display($time," Tine2: waited for count=10. count=%0d",count); end join_any $display($time," ************* END"); $finish; end endmodule Results: 0 ************* START 19 Tine1: waiting for posedge clk. count=0 19 Tine2: waiting for count=10 21 Tine1: waiting for posedge clk. count=1 23 Tine1: waiting for posedge clk. count=2 25 Tine1: waiting for posedge clk. count=3 27 Tine1: waiting for posedge clk. count=4 29 Tine1: waiting for posedge clk. count=5 31 Tine1: waiting for posedge clk. count=6 33 Tine1: waiting for posedge clk. count=7 35 Tine1: waiting for posedge clk. count=8 37 Tine1: waiting for posedge clk. count=9 39 Tine1: waiting for posedge clk. count=10 39 Tine2: waited for count=10. count=10 39 ************* END Thanks, for any feedback.
  18. SystemVerilog Social Club (SVSC) meetup in Santa Clara. May 12th @7pm. It looks like we may have a guest star at our SVSC meetup next Tuesday. Cliff Cummings. Bring some good questions/problems. If anyone out there wants to join our very informal group which kicks around small SV and UVM examples, stop by. http://www.meetup.com/SystemVerilog-Social-Club-Silicon-Valley/events/222163018/
  19. By "best", I believe you mean the "best method for someone who is new to UVM". As someone who has been using UVM for a few years, but is still pretty green with it, here are my thoughts. Avoid the `uvm_do macros until you can comfortably work without them. (And in my case, I still don't use them. In my early UVM days, they just led to a lot of confusion for me, as I looked at examples of the different ways to do things.) I found that sticking with the following got me going when I was floundering in the assorted examples online showing different ways to send sequences. `uvm_create(item) start_item(item); // randomize item and/or assign to it here. finish_item(item); I strongly agree with the following. "The [‘uvm_do] macros also obscure a very simple interface for executing sequences and sequence items. Although 18 in number, they are inflexible and provide a small subset of the possible ways of executing. If none of the [‘uvm_do] macro flavors provide the functionality you need, you will need to learn how to execute sequences without the macros. And once you’ve learned that, you might as well code smartly and avoid them all together. " -from Adam Erickson whitepaper -http://events.dvcon.org/2011/proceedings/papers/09_1.pdf
  20. Does an abstract class (virtual class ....), which extends from uvm_object, benefit from using uvm utility macros (`uvm_component_utils, `uvm_object_utils)? As I understand, `uvm_component_utils and `uvm_object_utils are used to register a class w/ the factory so objects of that class can be overridden. But, because an abstract class cannot be instantiated, it cannot be overridden. Is that assessment correct? Are those utils macros doing smthg else besides allowing for 'overriding' capability? (Although I have looked at them, I know I don't fully understand all they're used for.) thanks, From uvm_object_defines.svh: //------------------------------------------------------------------------------ // // Title: Utility and Field Macros for Components and Objects // // Group: Utility Macros // // The ~utils~ macros define the infrastructure needed to enable the // object/component for correct factory operation. See <`uvm_object_utils> and // <`uvm_component_utils> for details. // // A ~utils~ macro should be used inside ~every~ user-defined class that extends // <uvm_object> directly or indirectly, including <uvm_sequence_item> and // <uvm_component>. // // Below is an example usage of the ~utils~ macro for a user-defined object. // //| class mydata extends uvm_object; //| //| `uvm_object_utils(mydata) //| //| // declare data properties
  21. *, Is one of these ways to have a sequence wait on an event preferred? If so, why? The following are code snippets from inside a sequence. 1) Create transaction and engage w/ driver, then wait for event. `uvm_create(req) start_item(req); m_state.wait_on_smthg(); // <--- wait here 2) Wait for event, then proceed m_state.wait_on_smthg(); // <--- wait here `uvm_create(req) start_item(req); In this case, the event being waited for is that data of a certain type is available.
  22. Thanks a lot for that clear explanation, Dave. It looks like that's the way we're going (handle==create's string name). Does anyone see any reason or case when this doesn't make sense?
  23. CodingStyle: handle name vs create's string name. To match or not to match? What pros, cons, or team rules can you share about whether the string name passed into create should match the handle? i.e. //1) object declared, with handle name m_xyz_agent xyz_agent m_xyz_agent; //2) object created. what-string-name will you pass in to ::create? m_xyz_agent or smthg else? m_xyz_agent = xyz_agent::type_id::create("what-string-name",this); When I first started with uvm, I was tripped up a bunch in situations where I confused the handle and the string. A prime example is in the place of what-string-name below. uvm_config_db#(uvm_object_wrapper)::set(this,"*.what-string-name.asdf.main_phase", "default_sequence",xyz_seq::type_id::get()); When different developers use different styles, it can be a headache. So, besides suggesting 'just be consistent', which I fully agree with, what are your preferences, and why? thanks, Most examples I find have the string name passed to create and the handle match. (Having them differ does help a newbie understand what is going on a bit better, I believe.)
  24. Thanks a lot. I didn't realize that an objection to ending a phase meant extending the time only. I thought the lack of an objection might mean that the phase could end anytime, even between delta cycles at the same time. (I'm not sure if delta cycle is the proper term there.) So, all functions that are called at the start of one of the uvm run phases (before any time consuming events) will be guaranteed to complete. And any uvm run phase which has no time consuming elements needs no objections. Right? (I'm not saying I have a reason for such measures. I am just checking.) thanks again for spelling it out for me Perhaps it's just me, but I don't think the uvm_users_guide_1.1.pdf is clear enough about this. "each phase" to me means "every phase". (see below) Also, I didn't read "activity" below as meaning something that consumes time. snippet from uvm_users_guide_1.1.pdf: 3.11 Managing End of Test UVM provides an objection mechanism to allow hierarchical status communication among components. There is a built-in objection for each phase, which provides a way for components and objects to synchronize their testing activity and indicate when it is safe to end the phase and, ultimately, the test. In general, the process is for a component or sequence to raise a phase objection at the beginning of an activity that must be completed before the phase stops and to drop the objection at the end of that activity. Once all of the raised objections are dropped, the phase terminates.
  25. T or F: Objections should not be used in the uvm phases which are functions (i.e. build_phase, connect_phase, check_phase, ...). If True, why?
  • Create New...