Using 'ref' with variables in interface

I was trying to write a generic task that takes ref clk, ref data, ref en
and calling this task from multiple places by passing in distint clk, data, en.
In doing this, I could not send my interface (used as virtual interface)
signals as input to the task and I get the error
"“Invalid ref argument usage as the actual argument is not a variable”

Has anyone seen this and how to get around with it?

PS : I preferably do not want to have any interface related code in my task as I want to
make it generic and also do not want to send the virtual interface name as argument to
task input …

Thanks,
Babu

Hi Babu,

You should explain your preferences and how “generic” you expect this task to be. In reality you are only asking that the names of your interface signals be generic; the functional of the signal must be the same. Can you explain with an example of what functionality you are trying to model?
The purpose of a virtual interface is to make your code generic enough that it does not refer to a specific interface instance, but the names the the virtual interface must match.

An alternative to all this is to use an abstract class with pure virtual methods. I’ll wait for your reply before explaining more.

Dave

In reply to dave_59:

Hi Dave,

Thanks for the quick response.

This is what Im doing :

The generic task code just takes the data @ clk whenever en is available
and dumps it to the file ‘filename’ and also sends to scoreboard.

It looks like this
task task_fileio (ref clk, ref data, ref en, ref filename);

and it is called from outside as

fork
task_fileio (output_intf.clk1x, output_intf.data1, output_intf.en1, filename1);
task_fileio (output_intf.clk2x, output_intf.data2, output_intf.en2, filename2);
task_fileio (output_intf.clk3x, output_intf.data3, output_intf.en3, filename3);
join

If I send local signals in the class and connect to ref variables in the task_fileio,
that works. ie. task_fileio (local_signal) works.

The problem only occurs, when I try to connect it to an interface signal

i.e task_fileio (output_intf.data1) gives an error message
“Invalid ref argument usage as the actual argument is not a variable”

In reply to Babu Raghunathan:

When you say “Called from outside” where is that? A class method? or top-level module? How does task_fileio send data to the scoreboard?

Instead of a task, could you make fileio another interface that is bound into your interface? The ports of that interface would be inputs and you could have an initial block execute the procedural code you had in the task.

Dave

In reply to dave_59:

When I say ‘called from outside’, I mean it is called from a class method.
task_fileio sends data to scoreboard through a queue which is unloaded in scoreboard
class.

I do not want to use anything other than task in order to reuse the task.
So, my question is, why cannot I connect an interface variable to a task ref value?

In reply to Babu Raghunathan:

In order to pass an argument by reference to a task, the data types of the formal and actual must match. If you have

task task_fileio (ref clk, ref data, ref en, ref filename);

that is understood to be the same as

task task_fileio (ref logic clk, ref logic data, ref logic en, ref logic filename);

The data types of clk1, data1, etc. inside the interface must also be logic (or reg).

Agreed. But my problem is, if I declare a signal as logic abcd in an interface
and try to use that as argument to task like

task task_fileio(intf.abcd)

I get the error message “Invalid ref argument usage as the actual argument is not a variable”

So, this does not look to like a datatype mismatch problem.

In reply to Babu Raghunathan:

You are going to need to show more code. this works for me

interface itf;
   logic A,B;
endinterface
module top;
   itf i();
class C;
virtual itf vitf;
   task t(ref logic arg, input string s);
      forever @arg $display(s,,arg,,$time);
   endtask // t
   task run;
      fork 
	 t(vitf.A,"A");
	 t(vitf.B,"B");
      join_none
   endtask // run
endclass // C
   C c;
   
   initial begin
      c = new();
      c.vitf = i;
      c.run();
      #1 i.A = 1;
      #1 i.A = 0;
      #1 i.A = 1;
      #1 i.B = 1;
      #1 i.B = 0;
      #1 i.B = 1;
      end
      
endmodule

In reply to dave_59:

Hi Dave,

I copy pasted and simulated the above code and I get the same error
message “Invalid ref argument usage as the actual argument is not a variable”
on both vitf.A and vitf.B.

Which simulator did you use? I’m using ncsim (ver 10.2),
I’m not sure if this is a simulator issue???

Thanks for your quick responses,
Babu

In reply to Babu Raghunathan:

I guess it is a simulator issue then. You’ll need to contact Cadence.

BTW, I work for Mentor, so I use Questa.

Dave

In reply to dave_59:

Hi Dave, yes this is a simulator issue. I resourced to my
new version of ncsim and it works.

Thanks a lot for your replies,
Babu

In reply to Babu Raghunathan:
Hi Dave,

I am trying to write generic task that take different interface signal as ref and do some calculation. I getting following error with Questa tool - this is in UVM environment.

//----------------
vsim.log(428): # ** Error: (vsim-8462) Illegal use of a net actual with ref port ‘signal_ref’ of task ‘cal_duty_cycle’.
vsim.log(430): # ** Error: (vsim-8462) Illegal use of a net actual with ref port ‘signal_ref’ of task ‘cal_duty_cycle’.
vsim.log(466): # ** Error: (vsim-8462) Illegal use of a net actual with ref port ‘signal_ref’ of task ‘cal_duty_cycle’.
vsim.log(468): # ** Error: (vsim-8462) Illegal use of a net actual with ref port ‘signal_ref’ of task ‘cal_duty_cycle’.
vsim.log(491): # Error loading design
vsim.log(492): Error loading design
//-------------------

below is brief description about what I am trying to achieve:

// Calling duty cycle task passing different signals in arguments in fork.. join
fork
begin cal_duty_cycle(tb_top.axi4_mst1_if.ARREADY, total_nooftxn); end
begin cal_duty_cycle(tb_top.mtr_isp__mtr_top_u0.arready_m1, total_nooftxn); end
join_none
 
//below is definition of duty_cycle task
task automatic decomp_base_mvc_seq::cal_duty_cycle(ref logic signal_ref, int total_no_txns);
    while (1) begin
        $display("In duty cycle : signal_ref = %d", signal_ref); // added simple display msg for debug purpose. have a logic to calculate duty cycle and working fine if I am directly using interface signal in the task itself. 
    End
endtask
//----------------------

Thanks
Krupa

In reply to krupahalani1:
You cannot pass a net(wire) by reference to a task/function.

In reply to dave_59:

Hi Dave,

Thanks. In QVIP -AXI4, are these signals declared as wire not logic?

Is there any other better way to achieve this?

Thanks
Krupa

In reply to krupahalani1:

Better way depends on what you ultimately need to do.

You could declare another variable, and make a continuous assignment to it from the wire. Then pass the variable to the task.