Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Reputation Activity

  1. Like
    ljepson74 reacted to Logger in randomize(argument) checks all constraints in scope   
    Bonus points for testing what happens when you change the constraint to the following:
    constraint c_1 { soft var1<100; }
  2. Like
    ljepson74 reacted to tudor.timi in FORK JOIN_NONE in UVM_SEQUENCE   
    You're using 'var' as a variable name, but this is an SV keyword. Try naming your variable something different:
    fork automatic int idx = i; // ! `uvm_do_on(eseq_inst[var], p_sequencer.master_sequencer[var]) join_none  
  3. Like
    ljepson74 reacted to tudor.timi in nested uvm_object class in uvm_sequence_item caused sv compiler to fail   
    The philosophy behind nested classes is that they have access to private members of the parent class. If you want to do scoping, you're better off using packages (though it's not possible to define a nice hierarchical structure of packages).
  4. Like
    ljepson74 reacted to David Black in fixed-size arrays : Do they not 'support' size()?   
    First, before I discuss the problems with SystemVerilog, I would like to point out that you are really missing a much simpler solution to your problem:
    module top; int farray[10]; //fixed array initial begin foreach (farray[jjj]) begin farray[jjj] = $urandom_range(121,0); end $display("******************************"); foreach (farray[jjj]) begin $display("%0d: %0d",jjj,farray[jjj]); end end endmodule : top  With respect to "how many elements does my container have?", try the following. Note that you may need to comment out a few lines since the EDA vendor simulators don't all agree on whether some of these should work, and to be fair, the standard is not entirely clear...
    module top;   byte   Fixed_array[3];   byte   Dynamic_array[] = {10, 20, 30};   string String = "abc";   byte   Queue[$] = {40,50,60};   byte   Assoc_array[string] = '{"a":70,"b":80,"c":90};   initial $display("Fixed_array size     is %0d", $size(Fixed_array)   );   initial $display("Dynamic_array size   is %0d", Dynamic_array.size() );   initial $display("String size          is %0d", String.len()         );   initial $display("Queue size           is %0d", Queue.size()         );   initial $display("Assoc_array size     is %0d", Assoc_array.num()    );   // Alternate approach   initial $display("$size(Fixed_array  ) is %0d", $size(Fixed_array)   );   initial $display("$size(Dynamic_array) is %0d", $size(Dynamic_array) );   initial $display("$size(String size  ) is %0d", $size(String)        ); // May not be legal   initial $display("$size(Queue size   ) is %0d", $size(Queue)         );   initial $display("$size(Assoc_array  ) is %0d", $size(Assoc_array)   );   // Yet another approach   initial $display("$bits(Fixed_array  ) is %0d", $bits(Fixed_array)   );   initial $display("$bits(Dynamic_array) is %0d", $bits(Dynamic_array) );   initial $display("$bits(String size  ) is %0d", $bits(String)        );   initial $display("$bits(Queue size   ) is %0d", $bits(Queue)         );   initial $display("$bits(Assoc_array  ) is %0d", $bits(Assoc_array)   ); // Strange result endmodule The standard attempts to rationalize away this inconsistency at the bottom of page 45 (85 in the PDF) in the IEEE 1800-2012 standard:[/size][/font][/color][/code]
    I for one don't entirely agree with this rationalization. The concepts are all closely related and should have been unified to make the coders job easier.
    Actually, $size() appears to work with most of them.
  5. Like
    ljepson74 reacted to imajeeth in Use of intersection in cross coverpoints   
    I was under the assumption that once bins are created, the coverage would be collected only for those bins and the remaining combinations would be ignored. However, I noticed this was not the case when using intersect.
    Intention: Assuming there are 3 banks (0,1,2) and 3 requestors(a,b,c). I wanted to write a coverpoint that covers the case where all 3 banks are active at the same time.
    Example 1: No bins for coverpoints and use intersect for cross coverpoint
    cp_bank_0_hit: coverpoint req_a_bank_id == 0 || req_b_bank_id == 0 || req_c_bank_id == 0;
    cp_bank_1_hit: coverpoint req_a_bank_id == 1 || req_b_bank_id == 1 || req_c_bank_id == 1;
    cp_bank_2_hit: coverpoint req_a_bank_id == 2 || req_b_bank_id == 2 || req_c_bank_id == 2;
    //cross coverpoint when all the banks (0,1,2) are being accessed at the same time. 
    ccp_all_banks_active: cross cp_bank_0_hit, cp_bank_1_hit, cp_bank_2_hit
    { bins all_hit = binsof(cp_bank_0_hit) intersect {1} &&
    binsof(cp_bank_1_hit) intersect {1} &&
    binsof(cp_bank_2_hit) intersect {1};
    Here I was expecting just one bin to be created for the cross coverpoint. However, I noticed other combinations(2^3=8) were generated.
    Example 2: Creating bins for coverpoints
    cp_bank_0_hit: coverpoint req_a_bank_id == 0 || req_b_bank_id == 0 || req_c_bank_id == 0 { bins hit = {1}; }
    cp_bank_1_hit: coverpoint req_a_bank_id == 1 || req_b_bank_id == 1 || req_c_bank_id == 1 { bins hit = {1}; }
    cp_bank_2_hit: coverpoint req_a_bank_id == 2 || req_b_bank_id == 2 || req_c_bank_id == 2 { bins hit = {1}; }
    //cross coverpoint when all the banks (0,1,2) are being accessed at the same time. 
    ccp_all_banks_active: cross cp_bank_0_hit, cp_bank_1_hit, cp_bank_2_hit
    { bins all_hit = binsof(cp_bank_0_hit.hit) &&
    binsof(cp_bank_1_hit.hit) &&
    binsof(cp_bank_2_hit.hit) ;
    The above code accomplishes the goal and only one bin was created, with other combinations not covered, as desired.
    Not sure why this change behavior, found it interesting nevertheless. I thought both should accomplish the same, maybe I was wrong.
    Feel free to comment.
  6. Like
    ljepson74 reacted to imajeeth in SVA for fairness of Round-Robin Arbiter   
    This is my solution. Not necessarily the best one. Suggestions for improvements are welcome. If any of you find any shortcomings with this method, please let me know. Open to constructive criticism!
    Assume there are 3 requestors namely: A,B and C with reqA, reqB and reqC being the requests
    and gntA, gntB and gntC being the grants. 
    Assumes the request and grant are on the same cycle
    Similar sequence and assertions need to be replicated for each requestor. Can concatenate the requests and grants 
    into a bit vector, in order to save some redundant code
    //Denotes there is request and grant for the requestor A. Does not care about other requestors 
    logic requestorA_req_and_gnt;
    //Denotes there is request and grant for requestor A and there is atleast one other requestor active
    logic requestorA_req_and_gnt_with_other_requestors_active;
    //There are requests other than requestor A
    logic other_req_except_requestorA;
    //There are grants other than requestor A
    logic other_gnt_except_requestorA;
    assign other_req_except_requestorA = reqB | reqC; //High when any one of the other requestor's are active
    assign other_gnt_except_requestorA = gntB | gntC;
    assign requestorA_req_and_gnt = reqA & gntA;
    assign requestorA_req_and_gnt_with_other_requestors_active = reqA && other_req_except_requestorA && gntA;
    // Covers the case where there is request and grant on one cycle for requestorA, followed by no other requests. And then few cycles later there 
    // are multiple requests(reqA and atleast one other request). In this case, requestorA should NOT be granted again
    sequence requestorA_req_and_gnt_followed_by_other_req_seq;
    requestorA_req_and_gnt ##0 (!other_req_except_requestorA)[*1:$] ##1 reqA && other_req_except_requestorA;
    //Covers the case where there are more than one requestor active(reqA and any one of the other requests) followed by cycles of no other request at all
    // and again followed by more than one requestor active. First time during multiple requests, reqA is granted, so, the second time when multiple
    // requests are active, gntA should not be asserted again, and one of the other requests should be granted
    sequence multiple_requests_with_requestorA_req_and_gnt_followed_by_other_req_seq;
    requestorA_req_and_gnt_with_other_requestors_active ##1 (!other_req_except_requestorA)[*0:$] ##1 reqA && other_req_except_requestorA;

    //Covers the case where there are multiple requestors active in one cycle and next cycle may or may not have reqA, but will have other requests. 
    // If reqA is granted in the previous cycle, it should not be granted again in the next cycle, rather other requestor should be granted
    sequence back_to_back_multiple_requests_active_with_requestorA_gnted_followed_by_other_req_seq;
    requestorA_req_and_gnt_with_other_requestors_active ##1 other_req_except_requestorA;
    //Assertion to check if reqA do not hog the round robin arbiter
    assert_fairness_wrt_requestorA: assert property( @(posedge clk) disable iff(!resetn) 
    (requestorA_req_and_gnt_followed_by_other_req_and_no_bts_seq or
    multiple_requests_with_requestorA_req_and_gnt_followed_by_other_req_and_no_bts_seq or
    ) |-> other_gnt_except_requestorA && !gntA
    `uvm_info("ARB_ASSERT",$sformatf("Requestor A was previously granted, and not granted again, round robin scheme followed!"),UVM_LOW) 
    `uvm_error("ARB_ASSERT_ERR",$sformatf("Requestor A was previously granted, and gets granted again, round robin scheme not followed"))
  7. Like
    ljepson74 reacted to mastrick in randomize() with inside syntax   
    Also, you might want to keep your randomize() call outside the assert().  Otherwise, simulators may not call the randomize at all if you disable assertions (e.g. to temporarily work around a problem).  You can assign the return from randomize() to a variable and then assert that variable.
  8. Like
    ljepson74 reacted to dave_59 in randomize() with inside syntax   
    The syntax is
    assert (         randomize(index) with { index inside { [1:5] } ;  }          ) else begin It's the same {} as if you wrote named constraint block. Each constraint within the {} needs to be terminated with a semi-colon
    constraint range_constraint                                { index inside { [1:5] } ;  }            
  9. Like
    ljepson74 reacted to joniale in randomize a string ?   
    Here a small example of code:   First, an example to create a byte dynamic array from a string. The dynamic array of bytes contains the ASCII CODE number representation of each character. The advantage is that this can be for example be randomized but strings cannot be randomized.   (created doing e.g.  for(i=0;i<stringvar.len(); i++) begin byte_din_array = {byte_din_array ,stringvar[i]}; //stringvar[i] will return empty byte if the index would be beyond the string length //The advantage of using stringvar[i] instead of stringvar.atoi(i) is that //the string can have all ASCII characters and not just numbers. //Disadvantage is that the byte contains the ASCII CODE "number" //representation of the character and that is not human readable end   ).   Here is the example to convert the dynamic array of bytes back in a concatenated string.  You may have used the previous dynamic array to be partly randomized (with constraints) inside an xfer or changed in post_randomize.   function string convert_byte_array2string(byte stringdescriptionholder[]); automatic string temp_str=""; automatic byte byte_temp; automatic string str_test; for ( int unsigned i = 0; i<stringdescriptionholder.size(); i++) begin i=i;//debug breakpoint byte_temp = stringdescriptionholder[i]; str_test = string'(byte_temp); //the "string cast" will convert the numeric ASCII representation in a string character temp_str = {temp_str,str_test}; end return temp_str; endfunction If you want more information about strings i recommend to read the section 3.7 of the Systemverilog LRM (2012) . It is about the string data types and explain the built-in methods used with string data types.
  10. Like
    ljepson74 reacted to tudor.timi in assertion to check for an array of channels   
    I'd start off with comments on your current assertion. You shouldn't use write_valid inside the disable iff block of the assertion. That's because it won't do what you probably think it does (at least not in SV 2012). The disable iff is for asynchronous resets, but I'm guessing that write_valid is a synchronous signal.
    What I think you want is:
    write_valid |-> !$isunknown(write_data) If for some reason you don't like the fact that this property accepts vacuous successes (i.e. it's true when write_valid is 0), then you can use disable iff to disable it in those case, but you need to make sure to use $sampled(...):
    disable iff (!$sampled(write_valid)) !$isunknown(write_data) This way you won't get any race conditions due to changing write_valid. You can read up more on the topic in section 16.2 Declaring properties of the SV2012 LRM, page 388.
  11. Like
    ljepson74 reacted to dave_59 in walk thru an enumeration   
    You can use a do-while loop:
    module top;    //typedef enum {alpha=0, beta=1, gamma=2, delta=3, epsilon=4} greek;  //to show default assignments    typedef enum {alpha, beta, gamma, delta, epsilon} greek;    greek letters;        initial begin       $display("****** Walk thru an enumeration example. ***********");       letters = letters.first;       do begin          $display(" %0d *** %0s", letters, letters.name);      letters = letters.next;       end       while (letters != letters.first);   end endmodule : top
  12. Like
    ljepson74 reacted to tudor.timi in overlapped implication vs logical AND. |-> vs. &&   
    I don't think it's just readability. When you cover stuff like this I'd assume you don't want to see vacuous hits (when A is false); you want to see that you had A and B high at the same time. In any case, they're not the same.
  13. Like
    ljepson74 reacted to apfitch in overlapped implication vs logical AND. |-> vs. &&   
      firstly that isn't a coverpoint, it's a cover property :-)
    The difference between A |-> B and A && B is that implication also evaluates to true if A is false, i.e.
    A |-> B is the same as (not A or (A and ) The standard says that the cover property statement will also report the number of vacuous passes (i.e. the case where  you cover A |-> B and A is false).
    I guess the other difference is that the implication operator applies to sequences (which doesn't really affect your example as A and B are just sequences of length 1 in a sense). Whereas && won't work on a sequence, you'd have to use "and" or "intersect".
    So I guess in this case of just testing logical values that have a sequence length of 1, && is more readable.
  14. Like
    ljepson74 reacted to sri.cvcblr in overlapped implication vs logical AND. |-> vs. &&   
    It is bad coding style and discouraged to use implication in cover property for the vacuity reason that Tudor has explained. This question often comes up and we now have it as part of our SV Quiz @ http://www.verifjobs.com 
    We discuss this in our SVA book in the coding guidelines chapter and we are adding it as a rule to our upcoming DVRules-SVA product too!
  15. Like
    ljepson74 reacted to sri.cvcblr in SystemVerilog checkers. simulator support. usage in a UVM environment   
    I  know that both VCS and Questa supports checker. Few quarters/years back even Aldec's Riviera-PRO added some basic support. For VCS there is a special flag needed to compile it though.
  16. Like
    ljepson74 reacted to uwes in When a phase completes, are any lingering processes terminated?   
    the answer is "it depends".
    - threads started inside or as a child-thread of  xyz_phase() are terminated before phase progression
    - threads started inside phase_started() are NOT terminated automatically and continue to run until normal end or explicit termination.
  17. Like
    ljepson74 reacted to ljepson74 in When a phase completes, are any lingering processes terminated?   
    Thanks a lot, /uwe.  That was very helpful.
    My notes, for when I encounter this again:
    1) from uvm_component.svh    (note: "Any threads spawned in this callback are not affected when the phase ends.")

      // Function: phase_started
      // Invoked at the start of each phase. The ~phase~ argument specifies
      // the phase being started. Any threads spawned in this callback are
      // not affected when the phase ends.

      extern virtual function void phase_started (uvm_phase phase);

    // phase_started
    // -------------
    // phase_started() and phase_ended() are extra callbacks called at the
    // beginning and end of each phase, respectively.  Since they are
    // called for all phases the phase is passed in as an argument so the
    // extender can decide what to do, if anything, for each phase.

    function void uvm_component::phase_started(uvm_phase phase);

    2) from uvm_task_phase.svh  (note:  "Once the phase completes, any remaining forked ...
    threads are forcibly and immediately killed.")

    // Class: uvm_task_phase
    // Base class for all task phases.
    // It forks a call to <uvm_phase::exec_task()>
    // for each component in the hierarchy.
    // The completion of the task does not imply, nor is it required for,
    // the end of phase. Once the phase completes, any remaining forked
    // <uvm_phase::exec_task()> threads are forcibly and immediately killed.
    // By default, the way for a task phase to extend over time is if there is
  18. Like
    ljepson74 reacted to c4brian in uvm_config_db and hierarchical access   
    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".
  19. Like
    ljepson74 got a reaction from c4brian in good technique to generate a random delay?   
    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.  

                   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
    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.)  

        //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

          ....  //here we set the req data to smthg meaningful (or just randomize it)
    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);

    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.
    all the best,
  20. Like
    ljepson74 reacted to tudor.timi in SystemVerilog checkers. simulator support. usage in a UVM environment   
    Not much has changed. I've tried to declare a checker in all 3 BigEDA simulators and all of them complained of syntax errors (granted, for some I didn't have the latest and greatest versions).
  21. Like
    ljepson74 reacted to dave_59 in assigning queue values from sequence   
    There certainly is a way around it.  Don't use `uvm_do_* and instead do
    req. tx_err_bytes.rand_mode(0);
    req. tx_err_bytes = {4,5,7};
    req.randomize() with   { tx_data_byte[0]=='h00;
                                         tx_data_byte[1]=='h11;                                      tx_data_byte[2]=='h00;                                      tx_data_byte[3]=='h99;                                      tx_data_byte[4]=='h55;                                      ///-----------------                                      tx_no_of_bytes_to_send ==20;
  22. Like
    ljepson74 got a reaction from c4brian in uvm_sequence_base kill on virtual sequence   
    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.)
  23. Like
    ljepson74 reacted to dave_59 in iff usage (as a mechanism for waiting)   
    The iff clause is an edge qualifier. It means wait for the edge to happen if and only if both the edge happens AND the expression is true.
    @(event iff (expression)); is equivalent to
    do @event; while (!expression) This becomes very handy when using clocking blocks. Once you start using clocking blocks, you want to make sure all your code that references the clocking block signals are synchronized with the clocking block event and no other events controls or wait statements. This eliminates all chances of race conditions that might add or miss a clocking block cycle.
  24. Like
    ljepson74 reacted to dave_59 in uvm sequence   
    The best method is not to use the macros at all. Learn the basics without the use of the macros. See http://verificationhorizons.verificationacademy.com/volume-7_issue-2/articles/stream/are-ovm-and-uvm-macros-evil-a-cost-benefit-analysis_vh-v7-i2.pdf
  25. Like
    ljepson74 reacted to ljepson74 in std::randomize( vs. randomize( vs. this.randomize( and scope   
    Dave, thanks a lot for this great answer.  I've just found myself Google-ing and returning to this answer 2+ times since I originally read it.  (I guess some things don't stick so well with me.)
  • Create New...