I am finding it hard to understand how handle passing in function arguments works. I have written 3 codes. The last one is giving a bad handle error.
First I would like to know if I am right in thinking the function call s1.copy(s2); passes the handle s2
to s
in the copy
method (it is pass by reference)?
For code 1, I think the handle s2
is passed to s
and hence s
refers to the same object and the code works fine.
I am skeptical about code 2 working. s2
has null handle so how s1.copy(s2); works? Is it like s2
is output argument so on calling copy
method the statement s=new(); will provide handle to s
and same handle is passed to s2
. So s
and s2
refer same object and after function call s
is destroyed but s2
is still there pointing to the same object?
The code 3 gives error stating "bad handle". In the module I have done s2=new(); so won't the s2
handle be passed to s
on the function call s1.copy(s2);? Is it something related to the argument being declared as output?
code1
class sample;
rand bit[3:0] a;
rand bit b;
function void copy(sample s);
s.a=this.a;
s.b=this.b;
endfunction
endclass
module tb;
sample s1,s2;
initial begin
s1=new();
s2=new();
s1.randomize();
$display("s1_a=%0d,s1_b=%b",s1.a,s1.b);
s1.copy(s2);// copying s1 fields to s2
$display("s2_a=%0d,s2_b=%b",s2.a,s2.b);
end
endmodule
code 2
class sample;
rand bit[3:0] a;
rand bit b;
function void copy(output sample s);
s=new();
s.a=this.a;
s.b=this.b;
endfunction
endclass
module tb;
sample s1,s2;
initial begin
s1=new();
s1.randomize();
$display("s1_a=%0d,s1_b=%b",s1.a,s1.b);
s1.copy(s2);// copying s1 fields to s2
$display("s2_a=%0d,s2_b=%b",s2.a,s2.b);
end
endmodule
code 3
class sample;
rand bit[3:0] a;
rand bit b;
function void copy(output sample s);
s.a=this.a;
s.b=this.b;
endfunction
endclass
module tb;
sample s1,s2;
initial begin
s1=new();
s2=new();
s1.randomize();
$display("s1_a=%0d,s1_b=%b",s1.a,s1.b);
s1.copy(s2);// copying s1 fields to s2
$display("s2_a=%0d,s2_b=%b",s2.a,s2.b);
end
endmodule
-
\$\begingroup\$ code 2 is really clone, not copy. \$\endgroup\$dave_59– dave_592024年11月21日 20:43:38 +00:00Commented Nov 21, 2024 at 20:43
2 Answers 2
First I would like to know if I am right in thinking the function call
s1.copy(s2);
passes the handles2
tos
in thecopy
method (it is pass by reference)?
It depends on how you declared the copy
function. Refer to IEEE Std 1800-2023 section 13.4 Functions:
Functions can have the same formal arguments as tasks.
Function argument directions are as follows:
input // copy value in at beginning
output // copy value out at end
inout // copy in at beginning and out at end
ref // pass reference (see 13.5.2)
Function declarations default to the formal direction input if no
direction has been specified.
You do not pass the argument as a reference in any of your code examples; that requires the ref
keyword.
In the first code example, you pass the argument as an input
since you did not explicitly use a direction. This works as you expected it to. The handle was copied into the function, and the object was already constructed before calling the function.
In the 2nd code example, s
is null, but the first thing you do inside the function is to construct the object with new
. This is why you do not get an error.
In the 3rd code example, s2
is constructed before the function call, but the s
object inside the function is null because it is declared as an output
. The s2
object was not copied at the start of the function. You did not construct s
inside the function, but you tried to access its contents with this line:
s.a=this.a;
That is why you got an error.
-
\$\begingroup\$ So can this be concluded this? In code 1 the function argument is input so handle s2 is passed to s in copy method. But in case of codes 2 and 3 the function argument is output so vice-versa(handle s passed to s2) will happen? That is why in code 3 despite of s2 pointing to an object before function call, s is null as s2 won't be passed to s. If s = new(); is done s is no more a null handle and at the end of the function handle s is passed to s2. So now s2 refers to some other object which was referred by s. \$\endgroup\$Kartikey– Kartikey2024年11月21日 14:17:37 +00:00Commented Nov 21, 2024 at 14:17
-
\$\begingroup\$ @Kartikey: yes, I think your understanding is correct. \$\endgroup\$toolic– toolic2024年11月21日 14:24:43 +00:00Commented Nov 21, 2024 at 14:24
It would help to first understand that class variables hold references (handles) to class objects. When making an assignment from one class variable to another class variable, you are copying the reference to the object, not the the object itself. input
arguments to functions/tasks are assignments upon entry, and output
arguments are assignments upon exit from the function/task.
The copy()
method of a class is designed to copy all the properties of a class from one object to another object. Both source and destination objects must be constructed before calling the copy method. That is what your code 1 does. It copies the class handle stored in s1
to the s
argument of the copy method, then proceeds to copy the individual class properties.
The copy()
method in code 2 is more like what is referred to as a clone method. That is class construction followed by copy. It's usually written as a separate clone()
method that calls copy(), and returns a handle to the new object instead of passing the handle out as an output argument.
class sample;
rand bit[3:0] a;
rand bit b;
function void copy(sample rhs); // rhs is right-hand-side of the assignment
this.a=rhs.a;
this.b=rhs.b;
endfunction
function sample clone();
sample lhs = new();
lhs.copy(this);
return lhs;
endfunction
endclass
module tb;
sample s1,s2;
initial begin
s1=new();
assert(s1.randomize());
$display("s1_a=%0d,s1_b=%b",s1.a,s1.b);
s2 = s1.clone();// copying s1 fields to s2
$display("s2_a=%0d,s2_b=%b",s2.a,s2.b);
end
endmodule
Your code 3 is almost the same as code 1, except you reversed the implicit input direction to an output, so the the s
argument never gets the handle that was stored in s2, so s
remains null inside the function. If it weren't for the fatal error, the null value of s
would have been copied as an output to s2
, making it null.