Jump to content


  • Posts

  • Joined

  • Last visited

Profile Information

  • Gender
    Not Telling

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

Logger's Achievements

Advanced Member

Advanced Member (2/2)



  1. You should use a register model with multiple uvm_reg_maps. One per interface. Assuming you're generating your register model using some sort of tool (rather than by hand), you need to find out how your tool supports that.
  2. You need to provide more detail. Like, why do you currently have to select one at compilation time? What exactly do you mean by parallel access? Do you have 3 separate physical interfaces which can simultaneously access the same register? Or as often the case, do you have 3 masters which can all access the same registers via a fabric and a single physical interface to the registers? What are you using for your register model? RAL ( uvm_reg ) ?
  3. Looking for suggestions on the best approach to modeling something akin the following. value1 and value0 are implemented as value_reg[31:0] in RTL. The value actually stored in this register is always whatever you wrote to it. However, what you read back, and what HW sees when it looks at this register depends on the value of value_mode. When value_mode == DIRECT, you'll read back the whatever value is physically stored in value_reg[15:0] as value0 and value_reg[31:16] as value1. When value_mode == MULT, you'll read back a computed value instead. Let quotient == value_reg[15:0] * value_reg[31:16]. Then you'll read back quotient[15:0] as value0 and quotient[31:16] as value1. Right now I've just added tasks write_value( bit [15:0] a, bit [15:0 b ), read_value( output bit [31:0] quotient ) to the register model, which look at value_mode before accessing value_reg. In both cases, write_value() just writes parameters a and b to value0 and value1 using the register model. When value_mode == DIRECT, read_value() reads value0 and value1 multiplies them and returns the result. When value_mode == MULT, read_value() reads value0 and value1, concats them and returns the result. I'm contemplating adding some kind of virtual register to the register model instead of the tasks. Then, implement the logic using either callbacks or a custom front door. It also needs to preserve support for multiple address maps. The goal is to prevent multiple scoreboards and coverage classes which are referencing these registers from having to implement the same computation. The idea of a virtual register is to provide the same uvm_reg API to the user as other registers. A side benefit is the user only makes a single call to read the 32 bit value, rather than making two calls. Cheers.
  4. The short answer is yes. However, from the way you worded your question, I'm immediately inclined to use the PLI/VPI instead of the DPI. There are a lot of ways to skin this cat. If you want more guidance, you'll need to give more details about what you're trying to accomplish.
  5. Seen quite a few posts on various forums like this. Moving your register model to UVM-1.2 yields a bunch of warnings like this. [uVM/RSRC/NOREGEX] a resource with meta characters in the field name has been created As far as I can tell this is a bug in uvm_reg_block::configure(). If special regex characters are not allowed in the call to uvm_resource_db#(uvm_reg_block)::set(), then this function needs to sanitize the return value from get_full_name before passing it to set. get_full_name() is return hierarchical paths with dots in them, as it is supposed to, but those are regex characters with ::set() complains about. function void uvm_reg_block::configure(uvm_reg_block parent=null, string hdl_path=""); this.parent = parent; if (parent != null) this.parent.add_block(this); add_hdl_path(hdl_path); uvm_resource_db#(uvm_reg_block)::set("uvm_reg::*", get_full_name(), this); endfunction I am not alone: https://goo.gl/REafnv -Ryan
  6. This section of the LRM is vague. 18.11 In-line random variable control What is the expected behavior for the following code? class child; rand int a; rand int b; constraint cb { a inside {[0:100]}; b inside {[0:(2*a)]}; } endclass class parent; //Uncomment to force desired behavior: rand int a; rand child c; constraint cb { //Uncomment to force desired behavior: a == c.a; c.b >= c.a; } //Uncomment to force desired behavior: function void pre_randomize(); //Uncomment to force desired behavior: a = c.a; //Uncomment to force desired behavior: endfunction endclass module top; initial begin parent p = new; child c = new; c.a = 10; p.c = c; void'( p.randomize( c.b ) ); $write( "c.a == %0d ( expecting 10 )\nc.b == %0d\n\n", c.a, c.b ); c = new; c.a = 50; p.c = c; void'( p.randomize( c.b ) ); $write( "c.a == %0d ( expecting 50 )\nc.b == %0d\n\n", c.a, c.b ); $finish; end endmodule In my simulator I get:
  7. Bonus points for testing what happens when you change the constraint to the following: constraint c_1 { soft var1<100; }
  8. What am I missing here? Say you model an APB transaction that includes a cycles_before_delay member. The driver will have to implement that like this: seq_item_port.get_next_item( item ); // stall for item.cycles_before_delay; // do transaction seq_item_port.item_done( ); During that stall, no other transaction will be able to execute on that driver. Now there was the suggestion of forking this, but you can't call get_next_item() again, until you first call item_done(). Calling item_done() before the transaction is actually completed, is a non-blocking completion model, as the sequence will return from finish_item() immediately.
  9. So in the scenario where the spec says write register A, then wait 40 cycles before writing register B. You propose modeling that 40 cycle delay at the end of A, or the beginning of B. I know that is how a lot of models do it, but that doesn't make it right. In the case of APB, I'd like to allow other sequences to write to other registers during that delay. Which implies I now need to implement what otherwise would have been a simple in order atomic driver, as a non-blocking driver, so it can fork threads and return immediately. In addition to that, the sequence using the APB transaction can no longer assume that the item is done after calling finish_item(), so it now also has to check the end_event. Furthermore, by default, the sequencer automatically triggers begin_event and end_event unless you define UVM_DISABLE_AUTO_ITEM_RECORDING. Which affects all sequencers not just the sequencer in question. That will change with UVM 1.2, but for the time being this flow is broken.
  10. Good points. I've been real lazy about directly referring to m_sequencer rather than using get_sequencer(). You point out a good reason to stop that. I concur. I don't like this approach for two reasons: First and foremost, the delay before or after a transaction is not part of that transaction (mixing abstractions agains), but it is part of the sequence containing that transaction. Hence, the sequence needs some mechanism to perform delays. And time based delays doesn't cut it, so it needs to be cycle delays. Second, it requires you use a non-blocking completion model in your driver. For an in-order atomic interface, the driver should not have to implement a non-blocking completion model to support interleaving of sequences. This makes me think uvm_sequence_base should have a wait_cycles() task, and probably several other standard utility methods. I agree the driver should be handling the actual implementation of these tasks, so somehow the library needs to connect the sequences wait_cycles() task to a corresponding one on the driver.
  11. I kind of have a gripe against directly referring to the interface from a sequence for these common use case scenarios. Different sequences on different interfaces can be doing the same thing, but implement it differently and it looks different. m_sequencer is the window/proxy by which a sequence knows which interface it is operating on. I was just meaning to say a virtual wait_cycles() method in the uvm_sequencer_base, would make it possible for all sequences to call m_sequencer.wait_cycles(x) without having to refer directly to the interface. That of course adds the burden of having to extend the base sequencer if you want to use that functionality. This would not create a strong type association. Also it would be so nice if a sequence could call, m_sequencer.get_interface(), but because interfaces lack polymorphism that API is not possible. I wish interfaces had some limited form of polymorphism.
  12. I have made it a standard practice to add a wait_cycles() task to all my sequencers to abstract this. Then in my sequences I can simply write: p_sequencer.wait_cycles(x); This requires you use the `uvm_declare_p_sequencer() macro in your sequence. Too bad that's not built into uvm_sequencer. -Ryan
  13. But that's the problem, this "standard operating procedure" is not a documented procedure, nor is it a single procedure. No two people do it the same way, and good luck finding an example when you google or search the UVM forums. You'll mostly likely come across someone raising the question, but it's never answered. So is there no canned solution, because we haven't yet agreed on how this should be implemented in the general case? Or is it just one of those things that UVM hasn't gotten around to yet?
  14. It would be really nice to be able to receive TLM messages in some sequences for the purposes of coordinating stimulus with monitored events. I have a solution which gets the job done, but it's not as clean as it should be, and this missing feature feels like a gaping hole in the methodology. I think a very nice solution would be to have uvm_analysis_imp#() class either implement the get() method, or maybe more clearly have a new method called wait_for_write( T t ). You could then extend your sequencer to have a uvm_analysis_imp#(), and use `uvm_declare_p_sequencer() in your sequence to provide access to the analysis port. Here's a partial example of what the user code would look like: class ItemSqr extends uvm_sequencer#( Item ); uvm_analysis_imp#( OtherItem ) other_item_analysis_export; // .. rest of class definition endclass class TestSeq extends uvm_sequence#( Item ); `uvm_object_utils( TestSeq ) `uvm_declare_p_sequencer( ItemSqr ) // .... virtual task body( ); OtherItem t; // .. do some transactions p_sequencer.other_item_analysis_export.wait_for_write( t ); // .. do some more transactions endtask endclass I basically implement this now, but UVM should do it for me. -Ryan
  • Create New...