SystemVerilog inheritance, aggregated classes and parent function call

91 Views Asked by At

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
2

There are 2 best solutions below

0
Андрей Ефимов On BEST ANSWER

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 parrent and print only parrent 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
0
Parth Pandya On

you need to assign in_A_h and in_B_h with in_C_h.
Below modification solves the issue.

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;
        C_h.in_B_h = in_C_h;
        C_h.in_A_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