Monday, February 29, 2016

Virtual sequence and virtual seqeuencer

Why we need to use virtual sequence as well virtual sequencer.

Lets take an hypothetical example.

If in your system you want to drive USB and AHB transaction together (parallel) as your DUT support both interface.

From test you will start a virtual sequence (here virtual means not a virtual class like of polymorphism)

This virtual sequence will in turn start USB and AHB sequence in its body.
Now USB sequence will need usb_sequencer and ABH will need AHB_sequencer.

So n virtual sequence we will take handle of both sequencer and assign the handle with respective sequencer in test case like

virtual_seq.usb_sequencer = env.usb_agent.usb_sequencer
virtual_seq.ahb_sequencer = env.ahb_agent.ahb_sequencer

We will start virtual sequence as below
virtual_seq.start( .sequencer(null))

This start task will call body of virtual sequence and it will call start for USB and AHB sequence.

Here virtual sequence is not started on any sequencer. Because we are not going to connect any sequencer for virtual sequence to driver. As we do not need it. Alternatively we can start it on virtual_sequencer and that virtual_sequencer will have handle of usb_sequencer and ahb_sequencer, but it will add up with more code unnecessarily.

So better not to use virtual_sequencer.

Sunday, February 14, 2016

type_id::create simplified.

With UVM we use type_id::create to create object of any class. We do not use new. It is because we can override that class without changing single line of your code by help of uvm_factory.

How type_id::create works, that I will try to show you by very simple example.

class u_object; // Think of it as uvm_object
endclass
class u_registry #(type T=u_object); // Think of it as uvm_object_registry #(type T=uvm_object, string Tname="<unknown>")
  static function T create();
    u_object obj;
    u_registry#(T) me;
    me = new();
    obj = me.create_object();
    $cast(create,obj);
  endfunction
  function u_object create_object();
    T obj;
    obj = new();
    return obj;
  endfunction
endclass
class transaction extends u_object;
  int i;
  typedef u_registry #(transaction) type_id; // Assume this line will be added when we write `uvm_object_utils(transaction)
  virtual function display();
    i = 25;
    $display("i is %0d",i);
  endfunction
endclass
module test();
transaction pkt;
initial
begin
  pkt = transaction::type_id::create(); // transaction::type_id is 
                                        // u_registry #(transaction)
                                        // u_registry #(transaction)::create()
                                        // so we called static function create which will
                                        // return object of type transaction.
  pkt.display();
end
endmodule
Output :
i is 25 (run here)

1. pkt = transaction::type_id::create() will do pkt=u_registry #(transaction)::create()
2. create is a static method. In this method we have created object of own class type "me"
3. "me.create_object" will return handle of "transaction" object of type u_object
4. As return type of create_object is u_object, we will downcast it with "transaction" type by $cast in "create" method.
5. Retrun type of "create" is T ("transaction"), so finally object of type "transaction" returned to "pkt"

Now, how can we override transaction class with another class (say transaction_1) by factory.

UVM Factory method is
transaction::type_id::set_type_override(transaction_1::get_type());

Without going in to the details of factory, I will just give an essence that how factory will override pkt to contain handle of transaction_1 instead of transaction.

Check out below code. I have just changed (keeping rest of the code same)
pkt = transaction::type_id::create(); to
pkt = transaction_1::type_id::create();
(Above change will be done by factory when we call set_type_override, 
 this change is just for explanation purpose)

class u_object;
endclass
class u_registry #(type T=u_object);
  static function T create();
    u_object obj;
    u_registry#(T) me;
    me = new();
    obj = me.create_object();
 //create = me.create_object();
 $cast(create,obj);
  endfunction
  function u_object create_object();
 T obj;
    obj = new();
    return obj;
  endfunction
endclass
class transaction extends u_object;
  int i;
  typedef u_registry #(transaction) type_id;
  virtual function display();
    i = 25;
    $display("i is %0d",i);
  endfunction
endclass
class transaction_1 extends transaction; // derived transaction class
  typedef u_registry #(transaction_1) type_id;
  function display();
    i = 50;
    $display("i is %0d",i);
  endfunction
endclass
module test();
transaction pkt;
initial
begin
  pkt = transaction_1::type_id::create(); // Check this change
  pkt.display();
end
endmodule
Output
i is 50 (run here) 
Now create will return object of type transaction_1 instead of transaction.
Check the output.