Jump to content

tudor.timi

Members
  • Content Count

    289
  • Joined

  • Last visited

  • Days Won

    33

Reputation Activity

  1. Like
    tudor.timi got a reaction from ljepson74 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  
  2. Like
    tudor.timi got a reaction from joniale in UVM reg model mask   
    Hijacking the thread for a bit.
     
     
    Is there a future bug fix release for UVM 1.1 planned? UVM 1.1e maybe for people who don't want to migrate to UVM 1.2 just yet?
  3. Like
    tudor.timi got a reaction from c4brian in block level verification in a system setting   
    It's not sufficient that all the blocks work properly, because it might be the case that they aren't properly connected to each other. Outputs from some block are left hanging and the corresponding inputs are tied to some values. Cascaded block level checks can't really find this, if your observation points for each block level environment are its corresponding design block. Example: A can start read or write transactions, but the direction signal doesn't get passed to B, where it's tied to read. The A or B env checks won't fail, but the whole system is buggy.
  4. Like
    tudor.timi got a reaction from ljepson74 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).
  5. Like
    tudor.timi got a reaction from c4brian in block level verification in a system setting   
    It's not sufficient that all the blocks work properly, because it might be the case that they aren't properly connected to each other. Outputs from some block are left hanging and the corresponding inputs are tied to some values. Cascaded block level checks can't really find this, if your observation points for each block level environment are its corresponding design block. Example: A can start read or write transactions, but the direction signal doesn't get passed to B, where it's tied to read. The A or B env checks won't fail, but the whole system is buggy.
  6. Like
    tudor.timi 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.
  7. Like
    tudor.timi got a reaction from nikunjhinsu in Selection of specific physical interface in default UVM register layer sequences   
    Not sure where you got the idea from that you can do this for uvm_reg_single_access_seq. First of all, there isn't any field called maps defined in the sequence. The only place I see any reference to any maps is in body(), where it's a local variable. Second, you can't constrain object handles like that, since only integral expressions are allowed by the LRM.
     
    Coming back to your question, you can't use these sequences to do what you want them to do. This is because they're poorly written. Instead of having one big loop inside the body() task of uvm_reg_single_access_seq, a better way would have been to write it like this:
    class uvm_reg_single_access_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item)); virtual task body(); uvm_reg_map maps[$]; // code that checks if register test is enabled // ... rg.get_maps(maps); foreach (maps[j]) begin if (skip_map(maps[j]) continue; verify(maps[j]); end endtask virtual function bit skip_map(uvm_reg_map map); // code that checks if reg only has RO or undef fields in map // ... endfunction virtual task verify(uvm_reg_map map); uvm_status_e status; uvm_reg_data_t v, exp; // code that was in the loop in the original file that does write and mirror endtask endclass This way, you could extend the skip_map(...) function to skip certain maps. You can still implement the code I showed you above in a sub-class of uvm_reg_single_access_seq that only handles a certain map:
    class my_reg_single_access_seq extends uvm_reg_single_access_seq; uvm_reg_map map_to_test; // ... same code for body() and verify(...) as above virtual function bit skip_map(uvm_reg_map map); if (map != map_to_test) return 1; return super.skip(map); endtask endclass You could propagate this map_to_test field to the other sequences as well. You could then use the factory to override uvm_reg_single_access_seq with my_reg_single_access_seq. Using mid_do, you could make sure that the map_to_test field gets passed down hierarchically:
    class my_reg_access_seq extends uvm_reg_access_seq; uvm_reg_map map_to_test; virtual function void mid_do (uvm_sequence_item this_item); my_reg_single_access_seq access_seq; if ($cast(access_seq, this_item) access_seq.map_to_test = this.map_to_test; endfunction task body(); uvm_reg_single_access_seq::type_id::set_inst_override( my_reg_single_access_seq::get_type(), get_full_name()); super.body(); // ideally you should remove the override now, but it's only possible // in UVM 1.2 (I think) endtask endclass You'd need to do the same for bit bash and reset.
     
    The code above might need some tweaks to get it to compile and really do what it's supposed to do, but it should be a good starting point for you.
  8. Like
    tudor.timi got a reaction from ljepson74 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.
  9. Like
    tudor.timi got a reaction from ljepson74 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.
  10. Like
    tudor.timi got a reaction from karandeep963 in uvm register implimentation for same register with different instances   
    You could still implement it as a callback, but just attach it to any of the registers' fields:
    class my_cb extends uvm_reg_cbs; `uvm_object_utils(my_cb) virtual task post_predict(input uvm_reg_field fld, ...); uvm_reg my_reg = fld.get_parent(); // everything else stays the same // ... endtask:post_predict endclass:my_cb ----------------------// IN REG BLOCK //--------------------- virtual function void build(); my_cb cb_reg = new(); // Now create all registers REG1 = REG_1::type_id::create("REG_1", , get_full_name()); REG_1.configure(this, null, ""); REG_1.build(); // Similar for REG_2/REG_3/REG_4 uvm_reg_field fields[$]; REG_1.get_fields(fields); uvm_reg_cb::add(fields[0], cb_reg); // Similar for REG_2/REG_3/REG_4 It doesn't matter on which field you add it. I chose the first one, but it could just as well be any of them. You just use the field to make sure post_predict(...) gets called and to get the register that was accessed.
  11. Like
    tudor.timi got a reaction from karandeep963 in uvm register implimentation for same register with different instances   
    I wouldn't use post_write(...) since that is only called when you call reg.write(...), i.e. when you are driving the registers. If you do any kind of vertical reuse, you might not be driving the registers from sequences, but other parts of the RTL will be doing this. Explicit prediction and post_predict(...) are the scalable way to go.
  12. Like
    tudor.timi got a reaction from karandeep963 in uvm register implimentation for same register with different instances   
    I don't think you can get any better than what you already plan to do. One note, you want to update the other registers using the mirrored value, i.e. the value returned by uvm_reg::get_mirrored_value().
  13. Like
    tudor.timi got a reaction from karandeep963 in uvm register implimentation for same register with different instances   
    From the quote above I take it you registered your callback with the register and not the fields. The problem is that there isn't any post_predict(...) hook defined for uvm_reg, just for uvm_reg_field. They both use the same callback class though (which is misleading). If you look at the BCL code you'll see that uvm_reg::do_predict(...) only calls predict(...) on each of the register's fields. You have to add the callback to each of these in a loop (as I've done in the example above). Here it is again:

    uvm_reg_field flds[$];
    some_reg.get_fields(flds);
    foreach (flds)
    uvm_reg_field_cb::add(flds, some_reg_cbs);


  14. Like
    tudor.timi got a reaction from karandeep963 in uvm register implimentation for same register with different instances   
    This is a pretty uncommon scenario, that you won't be able to implement without some extra code. This reminds me of a situation a colleague of mine faced, where different registers shared the same address, but they were differentiated based on some extra bits in the bus transaction objects. In your case, you differentiate using another register. It might be problematic to map multiple registers to the same address (you get warnings, but I'm not sure if nothing else gets busted).
     
    The first thing I can think of is that you can define your IP regs in a separate block (as you probably already have). You can instantiate them in your main block and not map them. At the same time you can add another instance of the IP regs block and map that one. This will serve as the gateway to the "real" registers:
    class dut_reg_block extends uvm_reg_block; rand control_reg CONTROL; rand ip_reg_block IP; ip_reg_block IPs[4]; virtual function void build(); // ... default_map.add_reg(CONTROL, 'h0); default_map.add_submap(IP.default_map, 'h10); foreach (IPs[i]) begin IPs[i].build(); // ... not mapped ... end endfunction // ... endclass The use model would be that when you call IP.DATA.write(...) or read(...), you would be accessing one of the register blocks in IPs, depending on the value set in CONTROL.MUX. You need to make this hookup. You can make it so that when IP.DATA gets written, the appropriate register gets updated, via a callback:
    class mux_regs_cbs extends uvm_reg_cbs; control_reg CONTROL; data_reg DATAs[4]; virtual function void post_predict(uvm_reg_field fld, uvm_reg_data_t previous, inout uvm_reg_data_t value, input uvm_predict_e kind, uvm_path_e path, uvm_reg_map map ); data_reg DATA = DATAs[CONTROL.MUX.get_mirrored_value()]; uvm_reg_field real_fld = DATA.get_field_by_name(fld.get_name()); if (kind == UVM_PREDICT_WRITE) real_fld.predict(value); // Won't work because 'predict(...)' is called after checking the read. //else if (kind == UVM_PREDICT_READ) // value = real_fld.get_mirrored_value(); endfunction endclass You also need to update the value of IP.DATA when reading, so that you can check what the DUT returns. You can't do this in the previous callback, since the post_predict(...) hook is called after the read data has already been checked and there isn't any pre_predict(...) hook. What you can do, however, is to update the value of IP.DATA whenever you're switching between registers (i.e. writing CONTROL):
    class mux_control_cbs extends uvm_reg_cbs; data_reg DATA; data_reg DATAs[4]; virtual function void post_predict(uvm_reg_field fld, uvm_reg_data_t previous, inout uvm_reg_data_t value, input uvm_predict_e kind, uvm_path_e path, uvm_reg_map map ); if (kind == UVM_PREDICT_WRITE) DATA.predict(DATAs[value].get_mirrored_value()); endfunction endclass You need to add the callbacks to the appropriate registers:
    protected function void connect_ips(); mux_regs_cbs regs_cbs = new(); mux_control_cbs control_cbs = new(); regs_cbs.CONTROL = CONTROL; foreach (regs_cbs.DATAs[i]) regs_cbs.DATAs[i] = IPs[i].DATA; control_cbs.DATA = IP.DATA; foreach (control_cbs.DATAs[i]) control_cbs.DATAs[i] = IPs[i].DATA; begin uvm_reg_field flds[$]; IP.DATA.get_fields(flds); foreach (flds[i]) uvm_reg_field_cb::add(flds[i], regs_cbs); end uvm_reg_field_cb::add(CONTROL.MUX, control_cbs); endfunction You can either do this in the register block itself or outside, if you're relying on generated code that you can't touch.
     
    The code I posted could be made more flexible, i.e. instead of hardcoding references to DATA, it could be made to loop over all registers of the IP reg block, etc. Maybe there are nicer ways of doing it as well. I'm most probably going to write a blog post on this in the future to detail this procedure and maybe investigate others, so stay tuned!
  15. Like
    tudor.timi got a reaction from karandeep963 in how to access verilog module internal signals in UVM testbench   
    Be aware that adding any kind of hierarchical path like that would make your driver and monitor non-reusable. It also only works with Verilog, since hierarchical paths aren't allowed in VHDL. If you want more flexibility you can go the long way of binding an interface inside the DUT and assigning that to your monitor and driver.
    interface whitebox_if( input logic some_signal, input logic some_other_signal ); endinterface // somewhere in your top level bind dut whitebox_if wb_if; initial uvm_config_db #(whitebox_if)::set(null, "*", dut.wb_if); This way you can reuse your components on different projects even if the path to the signal you want changes.
  16. Like
    tudor.timi got a reaction from c4brian in proper layering in an ethernet transaction class   
    Even if two classes reference each other, you just need to add a forward typedef:
    typedef class ip_packet; class igmp_packet; // ... ip_packet ip_pkt; endclass This tells the compiler, "whenever you see 'ip_packet' treat it as a class and I'll describe it later". This is the class prototype feature you were looking for.
  17. Like
    tudor.timi got a reaction from ljepson74 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).
  18. Like
    tudor.timi reacted to apfitch in how to display UVM_VERBOSITY   
    Just as an aside, you can also use the %p formatter to display enumerated types (and pretty well anything else), e.g.
     
    $display("Verbosity is %p", m_rh.get_verbosity_level() );
     
    The disadvantage of %p compared to Tudor's string is that %p tends to print things out more verbosely (ironic in this case!)
     
    regards
    Alan
     
    P.S. You might have to cast m_rh to the type of the verbosity level in that context.
  19. Like
    tudor.timi got a reaction from c4brian in I stink at writing test plans.   
    I don't really remember what the Verification Academy cookbook said (it's a long time since I've seen it). I can tell you how I've started writing my plans. For your small little feature, I'd structure it like this:
    ARP interface -- The DUT should reply to an ARP request addressed to it ---- <map some cover item where I show I did ARP requests to the DUT> -- The DUT should drop ARP requests not addressed to it ---- <map some cover item where I show I did ARP requests to some other device> -- The DUT should drop ARP replies ---- <map some cover item where I know I did ARP replies> The "--" notation above means that it's a child section. I'd have the one big section related to ARP processing, then split this into smaller sub-sections, one per requirement. I don't get what you mean by non-supported behavior. If you're referring to dropping replies and other requests, that's not non-supported behavior, just other requirements aside from the main one, that is should accept ARP requests addressed to it.
     
    I'd typically break down a specification like this to end up with a verification plan. That doesn't mean what I think of at that point is the final version. W.r.t. finding the bugs you aren't looking for, you're right, that's a big part of constrained random (the other being test automation). What I do when I find a bug in an area I wasn't expecting (i.e. I didn't have any coverage defined for) is to add some coverage in the general area to make sure I stress it enough and the bug doesn't reappear. Other times you just get ideas of more stuff you want to test out of the blue. A verification plan should be a living thing, like your testbench and tests.
  20. Like
    tudor.timi got a reaction from c4brian in bus monitoring : Using SVA to pass transactions to monitor?   
    I'd also advise against using assert for casts and randomization because when you disable such an assertion, your simulator might decide to not do the randomize or $cast at all (some sims do it, some don't, not sure if it's an LRM gray area). 
  21. Like
    tudor.timi got a reaction from Hongnhattl in UVM Monitor help!!!   
    I'm guessing your device can only be in one mode at a time and this is configured via some fields in some configuration registers. It doesn't make sense to start sending OCTA frames when the device is configured for DUAL mode operation, hence there's no point in having mode a field in your sequence/item. When you configure your device for a certain mode (via some register/bus sequence) you need to reach into the configuration for your SPI agent and update that with the appropriate value (e.g. write registers to configure the device for QUAD, set the config field in the SPI agent to QUAD as well).
  22. Like
    tudor.timi got a reaction from karandeep963 in Suggestion: Built in Register test for INVALID ADDRESS access   
    Checking for bus response is a very specific topic, as it is intimately tied to the protocol being used. I'd say a good first step is getting the infrastructure to stimulate accesses to unmapped areas and let users implement their own response checking.
  23. Like
    tudor.timi got a reaction from karandeep963 in Suggestion: Built in Register test for INVALID ADDRESS access   
    I've also recently run into this problem and I went the way of 'point 1', since UVM REG doesn't have anything like this built in. I'd also be in favor of such an addition.
  24. Like
    tudor.timi got a reaction from Hongnhattl in UVM Monitor help!!!   
    I'd rather suggest to have a configuration field that states in which mode you are (single, dual, quad, octa). This field could be part of a configuration object that is shared by both objects:
    typedef enum { SINGLE, DUAL, QUAD, OCTA } mode_t; class spi_config extends uvm_object; rand mode_t mode; // ... endclass class spi_driver extends uvm_driver #(...); spi_config cfg; // ... endclass class spi_monitor extends uvm_monitor #(...); spi_config cfg; // ... endclass class spi_agent extends uvm_agent; spi_config cfg; spi_driver driver; spi_monior monitor; virtual function void build_phase(...); // ... // create and randomize config // ... driver.cfg = cfg; monitor.cfg = cfg; endfunction
  25. Like
    tudor.timi reacted to karandeep963 in Suggestion: Built in Register test for INVALID ADDRESS access   
    Hi ,
     
    I would like to exchange the thoughts on built in sequences for register verification supports only accessing the valid registers.
     
    Why should we not also expect to put some transaction other than valid address so to verify that bus should not hang ?
     
    This is good thing and I think every verification engineer does himself in his verification setup. So I considered an important part this may be added to default UVM reg test seq library.
     
    As per my understanding this can be achieved in two ways:
     
    1. Adding dummy register for invalid address range. --> so in this case built-in reg_test sequences will pick them up for access
    2. Manually make the bus transaction by providing invalid address.
    3. Better way(Suggestion) --> In the register layer it should calculate the lowest and highest offset and if user enables the invalid address check (either from CONFIG_DB or CONFIG_FILE) it should create the transaction in the invalid range.
     
    For 1 & 2 I have made the setup which is basically user effort.
     
    For point 3. I expect your views to make efforts further.
     
    Please suggest any better way if figured out !!
     
    Great Many Thanks for your replies.
     
    Please correct me if my assumptions/expectations are incorrect.
     
    Thanks,
    Karandeep
     
     
×