带参数类静态函数初始化Verilog模块参数的仿真兼容问题
问题背景
需要实现通用函数,用于对同一模块使用不同参数进行初始化,其中一个模块参数为依赖其他参数的打包数组。尝试编写的代码可通过Vivado综合工具编译,但在Questa Sim仿真时触发错误。
尝试代码
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
仿真报错信息
** Error: External function '<class-spec#1>::GetRand' may not be used in a constant expression.
注:使用无参数类时仿真可正常运行,但函数会失去通用性。
解决办法
方案1:用包内参数化函数替代参数化类
将类中的静态函数迁移到包的参数化函数中,SystemVerilog标准对包内函数在常量表达式中的支持更广泛,能兼容多数仿真器:
package my_pkg; // 带默认参数的通用函数 function automatic [p_COUNT-1:0][p_WIDTH-1:0] GetRand( int value, int p_WIDTH=16, int p_COUNT=2 ); automatic [p_COUNT-1:0][p_WIDTH-1:0] result; for (int i=0; i<p_COUNT; i++) begin result[i] = value * i; end return result; endfunction endpackage : my_pkg
在test_class中调用时传递参数:
myModule #( .p_WIDTH(p_WIDTH), .p_COUNT(p_COUNT), .p_INIT (my_pkg::GetRand(p_STEP, p_WIDTH, p_COUNT)) ) i_myModule ( // ...端口连接 );
方案2:通过局部参数中转计算结果
部分仿真器对直接在模块参数中调用类静态函数限制严格,但允许在局部参数中计算后传递。修改test_class:
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; // 先计算出初始化值存到局部参数 localparam [p_COUNT-1:0][p_WIDTH-1:0] INIT_VAL = helper_t::GetRand(p_STEP); myModule #( .p_WIDTH(p_WIDTH), .p_COUNT(p_COUNT), .p_INIT (INIT_VAL) ) i_myModule ( // ...端口连接 ); endmodule : test_class
方案3:使用参数化包替代参数化类
利用SystemVerilog的参数化包特性,将辅助逻辑封装到参数化包中,其函数在常量表达式中的兼容性优于参数化类:
package my_pkg #( parameter p_WIDTH = 16, parameter p_COUNT = 2 ); 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 return result; endfunction endpackage : my_pkg
在test_class中导入参数化包并使用:
module test_class#(); localparam p_WIDTH = 16; localparam p_COUNT = 2; localparam p_STEP = 6; // 导入指定参数化版本的包 import my_pkg#(.p_WIDTH(p_WIDTH), .p_COUNT(p_COUNT))::*; localparam ret_t INIT_VAL = GetRand(p_STEP); myModule #( .p_WIDTH(p_WIDTH), .p_COUNT(p_COUNT), .p_INIT (INIT_VAL) ) i_myModule ( // ...端口连接 ); endmodule : test_class
内容的提问来源于stack exchange,提问作者Don Rumata
相关产品推荐
相关产品推荐

