I have a problem with super.func() call in SV.
I have three main classes:
class_C extends class_B;
class_B extends class_A;
class_A;
And I have three configuration (aggregate) classes:
inner_C extends inner_B;
inner_B extends inner_A;
inner_A;
When I call function chain from clacc_C that prints self pointer and pointer to the corresponding inner class I receive normal self pointer and null for inner_B and inner_A.
Why am I getting such behavior from SV? How to workaround this problem?
simulator - Questa 2021.1 This is a code sample for problem illustration:
package test_pkg;
// base config
class inner_A;
int val_0_min;
int val_0_max;
function new();
endfunction : new
endclass : inner_A
// base class
class class_A;
inner_A in_A_h;
rand int val_0;
constraint constr_0 {
val_0 inside {[in_A_h.val_0_min : in_A_h.val_0_max]};
}
function void print();
$display("val_0 = %0d", val_0);
// next string give an error: Fatal: (SIGSEGV) Bad handle or reference.
//$display("val_0_min = %0d, val_0_max = %0d",
// in_A_h.val_0_min, in_A_h.val_0_max);
$display("pointer_0 this %m = ", this);
$display("pointer_0 in_A_h %m = ", in_A_h);
endfunction : print
function new();
endfunction : new
endclass : class_A
// first inheritance
class inner_B extends inner_A;
int val_1_min;
int val_1_max;
function new();
super.new();
endfunction : new
endclass : inner_B
class class_B extends class_A;
inner_B in_B_h;
rand int val_1;
constraint constr_1 {
val_1 inside {[in_B_h.val_1_min : in_B_h.val_1_max]};
}
function void print();
super.print();
$display("val_1 = %0d", val_1);
// next string give an error: Fatal: (SIGSEGV) Bad handle or reference.
//$display("val_1_min = %0d, val_1_max = %0d, val_0_min = %0d, val_0_max = %0d",
// in_B_h.val_1_min, in_B_h.val_1_max, in_B_h.val_0_min, in_B_h.val_0_max);
$display("pointer_1 this %m = ", this);
$display("pointer_1 in_B_h %m = ", in_B_h);
endfunction : print
function new();
super.new();
endfunction : new
endclass : class_B
// second inheritance
class inner_C extends inner_B;
int val_2_min;
int val_2_max;
function new();
super.new();
endfunction : new
endclass : inner_C
class class_C extends class_B;
inner_C in_C_h;
rand int val_2;
constraint constr_2 {
val_2 inside {[in_C_h.val_2_min : in_C_h.val_2_max]};
}
function void print();
super.print();
$display("val_2 = %0d", val_2);
$display("val_2_min = %0d, val_2_max = %0d, val_1_min = %0d, val_1_max = %0d, val_0_min = %0d, val_0_max = %0d",
in_C_h.val_2_min, in_C_h.val_2_max, in_C_h.val_1_min, in_C_h.val_1_max, in_C_h.val_0_min, in_C_h.val_0_max);
$display("pointer_2 this %m = ", this);
$display("pointer_2 in_C_h %m = ", in_C_h);
endfunction : print
function new();
super.new();
endfunction : new
endclass : class_C
endpackage : test_pkg
module DUT
import test_pkg::*;
();
inner_C in_C_h;
class_C C_h;
class_B B_h;
class_A A_h;
initial begin
in_C_h = new();
in_C_h.val_2_min = 20;
in_C_h.val_2_max = 30;
in_C_h.val_1_min = 10;
in_C_h.val_1_max = 20;
in_C_h.val_0_min = 1;
in_C_h.val_0_max = 10;
B_h = new();
A_h = new();
C_h = new();
C_h.in_C_h = in_C_h;
if (!C_h.randomize()) begin
$error("randomization failed"); // $fatal();
end
// print all data by the print() chain
$display("\n\tprint from C");
C_h.print();
// cast to parent and print only parent content
$display("\n\tprint from B");
if (!$cast(B_h, C_h)) begin
$fatal();
end
B_h.print();
$display("\n\tprint from A");
if (!$cast(A_h, B_h)) begin
$fatal();
end
A_h.print();
end
endmodule : DUT
The answer to the problem is simple. The problem is that the child class creates the parent class it doesn't pass the reference to the inner class.
In other words:
C_h >> B_h >> A_h
| | |
in_C in_B in_A
| |
in_B in_A
|
in_A
Then we pass a reference to in_C inside C_h we pass it only for the topmost child class, not for the parent classes! The child class has its own inner classes chain and the parent class has its own and these chains is different chains, not the same.
To do what I want I need to pass reference to the parent class from the child class. It can't be done with direct link pass. To do this I need to write a function that will get an inner object, cast it and pass to the child class config function and so on.
Rewritten code:
// base config
class inner_A;
int val_0_min;
int val_0_max;
function new();
endfunction : new
function void print();
$display("pointer self %m = ", this);
$display("val_0_min = %0d, val_0_max = %0d", val_0_min, val_0_max);
endfunction : print
endclass : inner_A
// base class
class class_A;
protected inner_A in_A_h;
rand int val_0;
constraint constr_0 {
val_0 inside {[in_A_h.val_0_min : in_A_h.val_0_max]};
}
function void print();
$display("val_0 = %0d", val_0);
$display("val_0_min = %0d, val_0_max = %0d",
in_A_h.val_0_min, in_A_h.val_0_max);
$display("pointer_0 this %m = ", this);
$display("pointer_0 in_A_h %m = ", in_A_h);
endfunction : print
function void set_config(ref inner_A conf_in);
in_A_h = conf_in;
endfunction : set_config
function new();
endfunction : new
endclass : class_A
// first inheritance
class inner_B extends inner_A;
int val_1_min;
int val_1_max;
function new();
super.new();
endfunction : new
function void print();
super.print();
$display("pointer self %m = ", this);
$display("val_1_min = %0d, val_1_max = %0d", val_1_min, val_1_max);
endfunction : print
endclass : inner_B
class class_B extends class_A;
protected inner_B in_B_h;
rand int val_1;
constraint constr_1 {
val_1 inside {[in_B_h.val_1_min : in_B_h.val_1_max]};
}
function void print();
super.print();
$display("val_1 = %0d", val_1);
$display("val_1_min = %0d, val_1_max = %0d, val_0_min = %0d, val_0_max = %0d",
in_B_h.val_1_min, in_B_h.val_1_max, in_B_h.val_0_min, in_B_h.val_0_max);
$display("pointer_1 this %m = ", this);
$display("pointer_1 in_B_h %m = ", in_B_h);
endfunction : print
function void set_config(ref inner_B conf_in);
inner_A in_A_h;
in_B_h = conf_in;
if (!$cast(in_A_h, this.in_B_h)) begin
$fatal();
end
super.set_config(in_A_h);
endfunction : set_config
function new();
super.new();
endfunction : new
endclass : class_B
// second inheritance
class inner_C extends inner_B;
int val_2_min;
int val_2_max;
function new();
super.new();
endfunction : new
function void print();
super.print();
$display("pointer self %m = ", this);
$display("val_2_min = %0d, val_2_max = %0d", val_2_min, val_2_max);
endfunction : print
endclass : inner_C
class class_C extends class_B;
protected inner_C in_C_h;
rand int val_2;
constraint constr_2 {
val_2 inside {[in_C_h.val_2_min : in_C_h.val_2_max]};
}
function void print();
super.print();
$display("val_2 = %0d", val_2);
$display("val_2_min = %0d, val_2_max = %0d, val_1_min = %0d, val_1_max = %0d, val_0_min = %0d, val_0_max = %0d",
in_C_h.val_2_min, in_C_h.val_2_max, in_C_h.val_1_min, in_C_h.val_1_max, in_C_h.val_0_min, in_C_h.val_0_max);
$display("pointer_2 this %m = ", this);
$display("pointer_2 in_C_h %m = ", in_C_h);
endfunction : print
function void set_config(ref inner_C conf_in);
inner_B in_B_h;
in_C_h = conf_in;
if (!$cast(in_B_h, this.in_C_h)) begin
$fatal();
end
super.set_config(in_B_h);
endfunction : set_config
function new();
super.new();
endfunction : new
endclass : class_C
endpackage : test_pkg
module DUT
import test_pkg::*;
();
inner_C in_C_h;
class_C C_h;
class_B B_h;
class_A A_h;
initial begin
in_C_h = new();
in_C_h.val_2_min = 20;
in_C_h.val_2_max = 30;
in_C_h.val_1_min = 10;
in_C_h.val_1_max = 20;
in_C_h.val_0_min = 1;
in_C_h.val_0_max = 10;
C_h = new();
C_h.set_config(in_C_h); // C_h.in_C_h = in_C_h;
if (!C_h.randomize()) begin
$error("randomization failed");
end
// print all data by the print() chain
$display("\n\tprint from C");
C_h.print();
$display("\n\tprint from inner_C");
in_C_h.print();
// cast to parent and print only parent content
$display("\n\tprint from B");
if (!$cast(B_h, C_h)) begin
$fatal();
end
B_h.print();
$display("\n\tprint from A");
if (!$cast(A_h, B_h)) begin
$fatal();
end
A_h.print();
end
endmodule : DUT