Reputation: 11
I want to have universal function to initialize same module with different parameters. One of them is packed array with size depends on another parameter.
I've tried something like this:
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
Vivado synthesis tool builds it without any errors, but Questa Sim doesn't allow to simulate this code. I'm getting following errors:
\*\* Error: External function '\<class-spec#1\>::GetRand' may not be used in a constant expression.
May be some one could advice some workaround for this trouble?
Same code with class without any parameters simulates with no problems. But function stops be universal...
Upvotes: 0
Views: 54
Reputation: 12384
Unfortunately, in system verilog you can only use locally (or globally) defined functions in constant expressions like that. Because it depends on module parameters, it should be defined locally within the module as in the following example:
module myModule #(
parameter p_WIDTH = 16,
parameter p_COUNT = 2,
parameter [p_COUNT - 1 : 0] [p_WIDTH - 1 : 0] p_INIT = '{default: 0}
)();
endmodule : myModule
module test_class#();
localparam p_WIDTH = 16;
localparam p_COUNT = 2;
localparam p_STEP = 6;
typedef logic [p_COUNT - 1 : 0] [p_WIDTH - 1 : 0] ret_t;
function automatic ret_t GetRand(int value);
automatic ret_t result;
for (int i = 0; i < p_COUNT; ++i) begin
result[i] = value * i;
end
endfunction
myModule #(
.p_WIDTH(p_WIDTH ),
.p_COUNT(p_COUNT ),
.p_INIT (GetRand(p_STEP))
) i_myModule ();
endmodule : test_class
There are a couple of ways to make this function reusable.
`define GetRand(p_COUNT, p_WIDTH) \
typedef logic [p_COUNT - 1 : 0] [p_WIDTH - 1 : 0] ret_t;\
function automatic ret_t GetRand(int value);\
automatic ret_t result;\
for (int i = 0; i < p_COUNT; ++i) begin\
result[i] = value * i;\
end\
endfunction
module test_class#();
...
`GetRand(p_COUNT, p_WIDTH) // define it within the module by instantiating the macro
myModule #(
...
.p_INIT (GetRand(p_STEP))
) i_myModule ();
Upvotes: 0