Can we use interface in object in uvm?

In reply to chr_sue:

This is my driver run task code


    task get_and_drive();
        basic_seq_item     req;
	drv_vif.intf_a = 0;drv_vif.intf_b = 0;drv_vif.intf_c = 0;drv_vif.intf_start = 0;
        forever begin
	    @(posedge drv_vif.intf_clk);
	    seq_item_port.get_next_item(req);
	    drv_vif.intf_a = req.seq_item_a;
	    drv_vif.intf_b = req.seq_item_b;
	    drv_vif.intf_start = req.seq_item_start;
            `uvm_do_callbacks(alu_driver, alu_drv_cb, corrupt_data())
	    drv_ap.write(req);
	    //`uvm_info(get_type_name, $sformatf("Driver transaction %s", req.sprint()), UVM_LOW)
	    seq_item_port.item_done();
	end 
    endtask : get_and_drive

Here is the callback I want to implement, the idea is the callback generates junk output values which would be caught in the scoreboard.


class alu_drv_cb extends uvm_callback;

    function new(string name = "alu_drv_cb");
        super.new(name);
    endfunction : new

    virtual task corrupt_data();
    // Drive random data on interface output, something along the lines of
    // intf_handle.intf_c = 'h1234_5678;
    endtask : corrupt_data

endclass : alu_drv_cb

In reply to JDoe:
This does not have much to do with the original question. It would have helped to start a new one.

You can call uvm_config_db::get from a class derived from uvm_object. It would just take some work to get the context. A much better OOP approach is not using callbacks and extending alu_driver with the corrupt_data virtual method.

class alu_driver;
`uvm_component_utils(alu_driver)
...
 task get_and_drive();
        basic_seq_item     req;
	drv_vif.intf_a = 0;drv_vif.intf_b = 0;drv_vif.intf_c = 0;drv_vif.intf_start = 0;
        forever begin
	    @(posedge drv_vif.intf_clk);
	    seq_item_port.get_next_item(req);
	    drv_vif.intf_a = req.seq_item_a;
	    drv_vif.intf_b = req.seq_item_b;
	    drv_vif.intf_start = req.seq_item_start;
            corrupt_data())
	    drv_ap.write(req);
	    //`uvm_info(get_type_name, $sformatf("Driver transaction %s", req.sprint()), UVM_LOW)
	    seq_item_port.item_done();
	end 
    endtask : get_and_drive 
    virtual task corrupt_data;
    endtask
endclass

endclass
class corrupted_alu_driver extends alu_driver;
`uvm_component_utils(corrupted_alu_driver)
 
    virtual task corrupt_data();
    // has access to everything in alu_driver
    // Drive random data on interface output, something along the lines of
    // intf_handle.intf_c = 'h1234_5678;
    endtask : corrupt_data
 
endclass

Now, instead of your test registering the callback, you factory override alu_driver with corrupted_alu_driver.

In reply to dave_59:

Hi Dave,
What if we have to use callbacks and get the interface into the callback object? What could be the approach for that?
I tried creating the callback inside the agent and assigning the interface manually into the object but it’s giving an error that interface is uninitialized inside the callback object.

In reply to Srinadh:

It is hard to help without seeing any code. Are you sure the handle is not null when you do the manual assignment?

Hi Dave,
Here’s the sample code:


//sorry that I'm unable to add the indentation here

class callback extends uvm_callback;
   virtual interface vif;

   //constructor

   virtual task drive_data();
   endtask

endclass

class child_callback extends callback;
   virtual task drive_data();
      @(vif.cb); //error at this line: unintialized virtual interface object
      vif.cb.data <= 1'b1;
   endtask
endclass

//inside agent's build phase
   //get the config_h object using config db
   callback_h = callback::type_id::create("callback_h");
   callback_h.vif = config_h.vif;

//inside test we override the callback with child_callback
//call uvm_do_callback inside driver's run phase

In reply to Srinadh:

Are you sure config_h.vif is not null inside the agent’s build phase when making the assigment?

In reply to dave_59:

Yes, conifg_h.vif is not null. I’m also able to print interface variables through callback_h.vif.data inside agent.

In reply to Srinadh:

Did you register your callback with the driver using

`uvm_register_cb(...)

In reply to chr_sue:

Yes, I’ve done that too.

In reply to Srinadh:

OK, I made a very simple example and found some strange behavior.
See here

It works fine, but adding any time dependence like #… or @(posedge vif.clk) the call back does not get executed.
In the reference manual I did not see any limitstion like this.

In reply to chr_sue:

Thanks for your response. But I think the way you used callbacks is not entirely correct. We need to add the callback inside test and also we need to call them inside driver through `uvm_do_callback. Correct me if I am wrong.

In reply to Srinadh:

You might be right. I have never used callbacks so far. Do you have some instructions for me how to employ them?

In reply to chr_sue:

I had a closer look the callback approach. My understanding is this approach is focussing on modification of seq_items/data packets instead of modifying pinlevel signals. I consider this as useful. In your case you had to implement the pinlevel protocol twice which is not good.

In reply to chr_sue:

Thanks for effort to provide a response. Now that seems the only way when we are not able to get the interface into the callback object, but I have few doubts following that approach.

  1. I don’t want to modify my driver, I don’t want to create a new sequence for doing this, I want to reuse already existing sequences basically one sequence inside other sequence through callback.
  2. If I start a new sequence inside callback onto the driver it will not take it untill it comes out of the current task but I want the driver to drive some signals when it is inside certain task. Can we start two sequences onto driver once? I don’t think so
    Any thoughts on this?

In reply to Srinadh:

I`m not sure if your conclusion is correct. You do not have to use a seperate sequencer. You can simply modify data packets recveived in the driver using the callback.
Do you know this link:

In reply to chr_sue:

Hi,
Actually, it is very much possible to get the interface into callback and modify the pin level signals. I was only not able to get the interface through manual assignment inside agent, so I was trying to get the interface by setting inside agent and getting into the callback object through uvm_config_db. I have a problem with this approach as shown below.
//inside agent
uvm_config_db #(virtual vif)::set(this, “callback_h”, “Interface”, uvc_if);
//inside callback
uvc_config_db #(virtual vif):get(null, “uvm_test_top.env_h.agent_h.callback_h”, “Interface”, uvc_if);
Now the above approach is working fine but is not reusable since we’ve given the entire path which changes from project to project. I’ve also tried various other arguments by keeping the identifier same(“Interface”) as shown below but I am only able to get a null interface which is useless.
uvm_config_db #(virtual vif)::set(null, “*”, “Interface”, uvc_if);
//inside callback
uvc_config_db #(virtual vif):get(null, “”, “Interface”, uvc_if);

uvm_config_db #(virtual vif)::set(this, “callback_h”, “Interface”, uvc_if);
//inside callback
uvc_config_db #(virtual vif)::get(null, “callback_h”, “Interface”, uvc_if);

Can you please tell me why the above approaches are not working and help me with a better solution compared to the working one given above.
Thanks

In reply to Srinadh:

Sounds good t me.
I believe you do have the right understand when using the arguments of the config_db command.
If the 1st argument is null this indicates you are using an absolute path which requires the whole hierarchy path in the 2nd argument whan using the get.
Using as 1st argument ‘this’ it is indicating a relative path.

uvm_config_db #(virtual vif):get(this, "", "Interface", uvc_if);

This command means you want to see the entry in the component where you have called it.

In reply to Srinadh:

An analogy to the uvm_config_db is the Linux file system. The DB is made of name-value pairs while Linux has file-contents. The first two arguments to uvm_config_db form a scope, which is like a Linux directory. The first must be a uvm_component handle, usually this, or null. The handle this is like the current directory, while null is like Linux root or /. A callback class is not derived from uvm_component, so it can’t pass this as the first argument.

When your agent makes the following call, it is using the scope uvm_test_top.env_h.agent_h.callback_h

// In agent
uvm_config_db #(virtual vif)::set(this, "callback_h", "Interface", uvc_if);

That is like the Linux file /uvm_test_top/callback_h/Interface with the contents uvc_if.
[br]
The problem is that a callback is not a component. In your code, callback_h seems to be a property under the agent or driver. So you should use a global scope. If you start the scope with null, that is like the Linux root.

// In test class
uvm_config_db#(virtual vif)::set(null, "Callback", "Interface", uvc_if);

This is like the Linux file /Callback/Interface Then get the value in the callback class with the matching call.

// In callback
uvm_config_db#(virtual vif)::get(null, "Callback", "Interface", uvc_if);

[br]
This works great if every agent has the same callback. If you need different callbacks for different agents … see what you can uniquify that second argument.

In reply to chr_sue:

Hi chr_sue,
Faced an issue regarding using virtual interface in the object.
If I set the interface provided with the inst_name hierarchy path and try to access the virtual interface in sequence then I use to get error.
uvm_config_db #(virtual intf)::set(null,“uvm_test_top.env.agt”,“vif_intf”,vif);

but if inst_name is simply provided with Asterisk it works fine
uvm_config_db #(virtual intf)::set(null,“*”,“vif_intf”,vif);

So may I know why virtual interface works for sequence only if the inst_name is provided with Asterisk (in my case).

In reply to Yeptho:

The answer is very simple. The agent belongs to the topology of your UVM environment because it is extended from uvm_component.
Sequences do not belong to the topology. They are transient objects and they are extended from uvm_object. Using the wildcard ‘*’ does not point to a component “uvm_test_top.env.agt”.
BTW you should never use a virtual interface in a sequence.
You are loosing the reusability slow-down your simulation.