Module's parameter initialization troubles

Good day! English is not my native language so first of all sorry for mistakes.

I have the following code:

package my_pkg;

    class helper #(
        parameter seed = 0
    );
        
    static function int GetRand();
        return seed + 10;
    endfunction

    endclass : helper

endpackage : my_pkg

module myModule #(
    parameter myParam = 0
);

    initial begin
        $display("My value = %d", myParam);
    end

endmodule : myModule

module test_class #(
);

    myModule #(
        .myParam(my_pkg::helper #(.seed(5))::GetRand())
    ) i_myModule ();

endmodule : test_class

Real task is simplified to this short example. While launching simulation with QuestaSim 2019.2 i’m getting following errors:
** Error: …/…/…/…/bpl_test_debug.srcs/sources_1/new/TEST.sv(54): External function ‘<class-spec#1>::GetRand’ may not be used in a constant expression.
** Error: …/…/…/…/bpl_test_debug.srcs/sources_1/new/TEST.sv(54): The expression for a parameter actual associated with the parameter name (‘myParam’) for the module instance (‘i_myModule’) must be constant.

It works if i use class without parameters, but actually i have to pass at least one to be able to return from static function array with parametrized length.

May be someone can suggest any workaround?

In reply to DonRumata:

Without knowing how you plan to use myParam and why it needs to be a parameter, it is difficult to suggest a workaround.

I believe this code should be legal, but many tools do not support it. This Mentor/Siemens EDA sponsored public forum is not for discussing tool specific usage or issues. Please read your tool’s user manual or contact your tool vendor directly for support.

In reply to dave_59:

Thank you for fast reply!

I’m going to pass myParam to initialize registers array inside module. It’s simplified version, but in a real case it should have type logic [REG_NUM * REG_WIDTH - 1 : 0] and i want to get it from function which filling it.

Got it, i’ll check

In reply to DonRumata:

The code you wrote could easily be rewritten as

package my_pkg;
function int GetRand(int seed);
  return seed + 10;
endfunction 
endpackage : my_pkg
 
module myModule #(
    parameter myParam = 0
);
    logic [myParam:0] data;
    initial begin
        $display("My value = %d", myParam);
    end
 
endmodule : myModule
 
module test_class #(
);
 
    myModule #(
      .myParam(my_pkg::GetRand(5))
    ) i_myModule ();
 
endmodule : test_class

In reply to dave_59:

That’s it. But this example is just too simplified

package my_pkg;

    class helper #(
        parameter p_WIDTH = 16,
        parameter p_COUNT = 2
    );

    typedef logic [p_COUNT - 1 : 0] [p_WIDTH - 1 : 0] ret_t;

    static function ret_t GetRand(int value);
        automatic ret_t result;

        for (int i = 0; i < p_COUNT; ++i) begin
            result[i] = value * i;
        end
    endfunction

    endclass : helper

endpackage : my_pkg

module myModule #(
    parameter                                     p_WIDTH = 16,
    parameter                                     p_COUNT = 2,
    parameter [p_COUNT - 1 : 0] [p_WIDTH - 1 : 0] p_INIT  = '{default: 0}
);

    // other module i can't edit
    otherModule #(
        ......
        .p_INIT(p_INIT),
        ......
    ) (
      .....
    )

endmodule : myModule

module test_class
    import my_pkg::*;
#();

    localparam p_WIDTH = 16;
    localparam p_COUNT = 2;
    localparam p_STEP  = 6;

    typedef helper#(.p_WIDTH(p_WIDTH), .p_COUNT(p_COUNT)) helper_t;

    myModule #(
        .p_WIDTH(p_WIDTH                  ),
        .p_COUNT(p_COUNT                  ),
        .p_INIT (helper_t::GetRand(p_STEP))
    ) i_myModule (
        .....
    );

endmodule : test_class

In real case i need something like this