Wednesday, 27 August 2014

Best method to force a signal in UVM environment across packages

Add an interface class to your package
interface class abstract_forces;
// this could be parameterized and accept arguments.
  pure virtual function void apply_forces;
endclass

Create a module that has the functions that do the forces to the DUT, and inside that module, construct a concrete class that could can add via the config_db and call from your test.
module DUT_forces;
import uvm_pkg::*;
import test_pkg::*;
 
function void forceset1;
  force $root.a.b.c = 0;
  force $root.d.e.f = 0;
endfunction
 
class concrete_set1 implements abstract_forces;
  virtual function void apply_forces;
    forceset1;
  endfunction
endclass
concrete_set1 h1 = new();
initial uvm_config_db#(DUT_api)::set(null,"*","set1",h1);
 
function void forceset2;
  force $root.g.h.i = 0;
  force $root.j.k.l = 0;
endfunction
 
class concrete_set2 implements abstract_forces;
  virtual function void apply_forces;
    forceset1;
  endfunction
endclass
concrete_set2 h2 = new();
initial uvm_config_db#(abstract)::set(null,"*,"set2",h2);
endmodule

Then in your test class, you get the concrete class object and call the forces() method
class test extends uvm_test;
 
abstract_forces f_h;
 
function void build_phase(uvm_phase);
 
 if( !uvm_config_db #(abstract_forces)::get( this , "" , "set1" , f_h; ) ) begin
      `uvm_error(...)
    end
endfunction
task run_phase(uvm_phase phase);
 
  f_h.apply_forces;
endtask
 
endclass :test

Tuesday, 12 August 2014

How to stop the simulation on `UVM_ERROR

Below is a good article which shows how to control simulation flow with different types of errors.

The default behavior of `uvm_error is to continue the simulation once the message is reported. Although one can argue over Accelera’s default choice, there are ways to stop the simulation on `uvm_error. I’ve tested them with UVM 1.1d and UVM 1.2 releases.

Using Simulator Arguments

Major simulators support the +uvm_set_action command-line argument to set a custom action for report messages:
+uvm_set_action=<comp>,<id>,<severity>,<action>
For example, to stop the simulation on `uvm_error(“MY_ERROR”, “message”), use the following argument when invoking the simulator:
+uvm_set_action="uvm_test_top.*,MY_ERROR,UVM_ERROR,UVM_STOP"
You can use _ALL_ instead of MY_ERROR to set the action for all errors, regardless of their id.

Using the uvm_component API

Call uvm_component.set_report_id_action_hier (string id,uvm_action action), for example after elaboration:
class basic_test extends uvm_test;
    function void end_of_elaboration_phase(uvm_phase phase);
        super.end_of_elaboration_phase(phase);
        set_report_id_action_hier("MY_ERROR", UVM_STOP);
    endfunction
endclass

Pay Attention: objects vs. components vs. sequence items

To my surprise, the above configuration does not apply to `uvm_error calls from within an uvm_object, for example for config objects, even if created under the “uvm_test_top.*” or “basic_test” hierarchy…
For `uvm_error calls from within an uvm_sequence_item, the message is delegated to the enclosing sequencer, hence it is not behaving like an uvm_object. The component path is enhanced with the enclosing sequencer and the sequence hierarchy path.
My recommendation is to use a generous star path pattern (“*”) when working with simulator arguments:
+uvm_set_action="*,MY_ERROR,UVM_ERROR,UVM_STOP"

or use the uvm_root component when working with the uvm_component API:
class basic_test extends uvm_test;
    function void end_of_elaboration_phase(uvm_phase phase);
        uvm_root top = uvm_root::get();
        super.end_of_elaboration_phase(phase);
        top.set_report_id_action_hier("MY_ERROR", UVM_STOP);
    endfunction
endclass

Underground Details for the Curious

The `uvm_error macro is defined as:
`define uvm_error(ID,MSG) \
   begin \
     if (uvm_report_enabled(UVM_NONE,UVM_ERROR,ID)) \
       uvm_report_error (ID, MSG, UVM_NONE, `uvm_file, `uvm_line); \
   end

That is the macro call is delegated to a uvm_report_error() function call. The function that is actually called depends on the context where the macro is used.
There are three relevant uvm_report_error() function definitions in the UVM library:
  1. uvm_report_object.uvm_report_error(). An uvm_component inherits from uvm_report_object.
  2. Global uvm_report_error() which delegates the call to uvm_root.uvm_report_error()
  3. uvm_sequence_item.uvm_report_error() which delegates the call to its sequencer, if it exists or to uvm_root.

Monday, 23 June 2014

How to insert delays in a TB - part 2

This is an update to previous post. If you want to wait for no of clocks in TB/sequence rather than giving delay, which can be done by events as shown below, but not recommended. Recommended solution is given below that.

we can use the same uvm_event.
  we can get the event with the help of uvm_event_pool, the sharing of the event happens with respect to the name with which you have set your clock event.
Please find the code snippet below.
example:
class my_sequence extends uvm_sequence;
//factory registration 
//other stuff
 
  uvm_event_pool my_event_pool;
  uvm_event clk_event;
  .
  .
  .
  clk_event = new();
  my_event_pool =  uvm_event_pool::get_global_pool();
  `uvm_info(get_full_name(),my_event_pool.get_type_name(),UVM_HIGH);
 
  task body();
      clk_event = my_event_pool.get("CLOCK EVENT");//this clock event will be triggered and set in the event pool with the same name in some other place where you have the access to the virtual interface handle.
      .
      .
      .
      clk_event.wait_trigger;
      .
      .
  endtask
endclass
 
 
You can use the same uvm_event which you have mentioned .

You can get the event with the help of uvm_event_pool, the sharing of 
the event happens with respect to the name with which you have set your 
clock event.

Please find the code snippet below.

example:
class my_sequence extends uvm_sequence;
//factory registration 
//other stuff
 
  uvm_event_pool my_event_pool;
  uvm_event clk_event;
  .
  .
  .
  clk_event = new();
  my_event_pool =  uvm_event_pool::get_global_pool();
  `uvm_info(get_full_name(),my_event_pool.get_type_name(),UVM_HIGH);
 
  task body();
      clk_event = my_event_pool.get("CLOCK EVENT");//this clock event will be triggered and set in the event pool with the same name in some other place where you have the access to the virtual interface handle.
      .
      .
      .
      clk_event.wait_trigger;
      .
      .
  endtask
endclass
 
 
 
Better solution is: 


Using a uvm_event_pool is not recommended as it results in an environment that is very co-dependent on other components and isn't very portable.
Our recommendation it to create an agent which can be used for time/clock advancement. It would have an interface connected to a system clock and have a sequence which would complete when a specified number of clocks have passed.
This technique is recommended since it removes all timing from the HVL testbench and is portable to both simulation and emulation.

-courtesy cgales
 

Thursday, 19 June 2014

How to insert delays in a TB - part 1

It is not recommended to insert hard coded delays in your TB. If TB is a part of SOC, there always exists an ambiguity on which delay simulator takes, since there are many blocks which uses different timescales.

As mentioned below, a global task can be created and used it all through the TB to insert delays. Problem of having different timescale units in different files can be solved by normalizing the amount of delay you want before applying it.

can go through below example, to understand it.
Go through below link for complete information.

http://tenthousandfailures.com/blog/2014/4/6/the-delayps-task


// `timescale 1ps/1ps
 `timescale 1fs/1fs

 package shared;

 class helper;

     static task delay_ps(real delay);
         real t0, t1;
         t0 = $realtime;
        
         $printtimescale;
         $display("delay_ps(%g)", delay);        
         #(delay*1ps);

         t1 = $realtime;
         if (t0 == t1) $error("%m timescale not precise enough"); 
  endtask // delay_ps

 endclass // helper   
    
 endpackage // shared

 `timescale 1ps/1ps
 // `timescale 1fs/1fs
    
 module tb ();

     task print_time();
         $display("\n%f is tb time\n", $realtime);
     endtask
    
     initial begin

         $display("\n");
         $printtimescale;
         $display("\n");

         print_time();
         #2ps; $display("delay 2ps"); print_time();
         shared::helper::delay_ps(2); print_time();
shared::helper::delay_ps(2ps/1ps); print_time();
         shared::helper::delay_ps(0.002ns/1ps); print_time();
         shared::helper::delay_ps(0.000002us/1ps); print_time();
         #2fs; $display("delay 2fs"); print_time();
            
         $finish();
        
     end
    
 endmodule 

Wednesday, 28 May 2014

base class - derived class dilemma example

Below example helps to understand parent-child relationship better. many things to look at.

module constraint_test();
        class parent;
          rand int unsigned a;
          constraint c1{
            (a < 10);

          }
        endclass

        class child extends parent;

          rand int unsigned a;
          constraint c2{
            (a > 10);
          }
        endclass

        parent parent_handle = new();
        child child_handle = new();

        initial
        begin
          parent_handle = child_handle;
          parent_handle.randomize();

          $display("a = %d",parent_handle.a);
          $display("a = %d",child_handle.a);
        end

endmodule

case 1:

If there is no handle assignment in above example, first display statement will display value less than 10 and second display statement will display "0", since child_handle.randomize() is not given.  If there is handle assignment, first will display less than 10 and second will display greater than 10. reason is before assignment, 'a' will have different location, after assignment 'a' will point to child class location. so, when parent_handle.randomize() is called, it randomizes child part variables also even though it doesn't have access to child class properties.

case 2:

Assume, no handle assignment in above example, if constraint names are given same in base class and derived class, if you do child_handle.randomize, since constraints are mutually exclusive, it should give error, but instead it wont throw error, it simply dosen't randomize the value and puts default value in it. randomize() function returns 0. If want to throw the error, capture return value of randomize() function. use assert(child_handle.randomize()), it throws error.

case 3:

we can give initial values to variables declared as rand/randc, if we call randomize() function, it overwrites that value.


Thursday, 22 May 2014

How to declare and use Nested classes in system verilog

At first instance, I couldn't get how to declare an object of a class which in nested in another class. Below example clears that

*****************************************************************************
module inheritance1;
   class c1;
      static int i = 10;
      int j = 20;
      static int k = 50;

      function void my_print();
         $display("i=%0d",i);
         $display("j=%0d",j);
      endfunction


      class c2;
         int i = 30;
     int j = 40;


     function void my_print(c1 h1);
        $display("i = %0d", i);
        $display("h1.i = %0d", h1.i);
        $display("j = %0d", j);
        $display("h1.j = %0d", h1.j);
        $display("k = %0d", k);
     endfunction
      endclass
   endclass

   c1 o1 = new;
   c1::c2 o2 = new;

   initial
   begin
      o1.my_print();
      o2.my_print(o1);
   end
endmodule

****************************************************************************
output:

 i=10
# j=20
# i = 30
# h1.i = 10
# j = 40
# h1.j = 20
# k = 50
*****************************************************************************

Tuesday, 20 May 2014

How to Write Action blocks in Assertions

Usual tendency is to write display statements in action blocks(report blocks) to display the error and values. since, the way assertions are executed is a bit different, please go through below example to understand how to write action blocks using $sampled.
***********************************************************************************
This quiz shows a subtle "gotcha" with SystemVerilog Assertions.  The example comes from a real problem encountered at a commpany, though the code has been simplified to focus on the "gotcha" in the assertion.
The assertion verifies that the value of a parity bit is set correctly for the value of data for every clock cycle.  An assertion failure indicates something is wrong with either data or the parity generator logic. 
Assertion Code
property p_parity_check;
  @(posedge clk)
  disable iff (!rstN)  // no checking during active-low reset
  parity == ^data;
endproperty

pcheck: assert property (p_parity_check)
else $error("PARITY ERROR at %0d ns: data = %h, even parity = %b (expected %b)\n",
            $realtime, data, parity, ^data);
This assertion has a subtle "gotcha" when there is an assertion failure.  To illustrate the problem, the design under test for this example always generates a 1 for the parity, which is occasionally an incorrect parity value.  The assertion appears to work most of the time, but sometimes reports an error even though the values printed out in the error message indicate that the data and parity values are correct.  In the following simulation output, the first assertion failure is a real failure, but the second error seems to be incorrect — the value of parity is the right value for the value of data.
Simulation Output
# At 15: Requesting data
# ** Error: PARITY ERROR at 15 ns: data = 00, even parity = 1 (expected 0)
# ** Error: PARITY ERROR at 25 ns: data = 01, even parity = 1 (expected 1)
# At 45: Requesting data
# At 75: Requesting data
Waveform
pcheck             P    F    F    P    P    P    P    P

         +----+    +----+    +----+    +----+    +----+
clk      |    |    |    |    |    |    |    |    |    |
     ----+    +----+    +----+    +----+    +----+    +----

     +        +--------------------------------------------
RSTn |        |
     +--------+

     ------------------------+-------------------+---------
data    00 (hex)             | 01 (hex)          | 02 (hex)
     ------------------------+-------------------+---------

              +--------------------------------------------
parity        |
     ---------+
Why did the assertion show a second failure when the printed values are correct at that time?
Answer
The "gotcha" in this assertion has to do with the order in which simulators evaluate assertions, print messages, and change design signal values.  The IEEE SystemVerilog defines a specific order for processing events on a clock edge.
  1. Any signals to be evaluated by a concurrent assertion are "sampled" in a "Preponed event region" of a clock edge.  This is a stable point, before any signal changes that might occur as a result of the clock edge have been processed.
  2. Next, design modules process signal changes in the "Active event region" and the "NBA Update event region".
  3. After the design changes for that clock edge are processed, assertions error messages are printed in a "Reactive event region".
This delta between sampling values and the assertion results from processing those values represents register-based hardware clock-to-Q behavior, and is as it should be.  It does mean, however, that, by the time the pass/fail statements are executed, RTL code can, and probably will, be changing signal values due to the clock edge.
In the assertion in the example above, it appears that the second failure message should not have happened -- the value or parity appears to be correct, and yet the assertion failed.  The real problem, though, is that the assertion error message is showing the value of data after the assertion has sampled data.  The sampled value wass not the same as the printed value.  The assertion failure was correct, but the error message was misleading.  Gotcha!.
SVA has a simple solution for this "gotcha".  If a pass/fail statement needs to print the values of signals that are used by the assertion, then the message should print the Preponed value — the same value used by the assertion — by using the $sampled() function.  $sampled() returns the Preponed value of a signal for the current moment in simulation time.  the correctly written assertion for this example is:
property p_parity_check;
  @(posedge clk)
  disable iff (!rstN)  // no checking during active-low reset
  parity == ^data;
endproperty

pcheck: assert property (p_parity_check)
else $error("PARITY ERROR at %0d ns: data = %h, even parity = %b (expected %b)\n",
            $realtime, $sampled(data), $sampled(parity), ^($sampled(data))); 
 
********************************************************************************************