模块参数初始化难题:通用参数初始化函数的仿真兼容问题
问题:参数化类静态函数作为模块参数的跨工具兼容性问题
我需要一个通用函数,用于使用不同参数初始化同一个模块,其中一个参数是大小依赖于另一个参数的打包数组。尝试了如下代码:
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
该代码在Vivado综合工具中可正常构建,但在Questa Sim中无法仿真,报错信息如下:
** Error: ../../../..TEST.sv(54): External function '<class-spec#1>::GetRand' may not be used in a constant expression. ** Error: ../../../../TEST.sv(54): The expression for a parameter actual associated with the parameter name ('myParam') for the module instance ('i_myModule') must be constant.
请问是否有解决该问题的方法?另外,不带参数的类的代码可正常仿真,但会失去函数的通用性。
解决方法
- 改用参数化函数或包替代参数化类
SystemVerilog标准中,类的静态函数在常量表达式中的支持度存在工具差异。可以将逻辑迁移到参数化函数(或参数化包)中,这类结构在多数仿真工具中被认可为合法的常量表达式来源:
package my_pkg; // 带输入参数的普通函数 function int GetRand(int seed = 0); return seed + 10; endfunction // 编译时参数化函数(更贴合原需求的通用型) function int GetRandParam #(int seed = 0)(); return seed + 10; endfunction 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::GetRand(5))) i_myModule1 (); // 使用编译时参数化函数 myModule #(.myParam(my_pkg::GetRandParam#(5)())) i_myModule2 (); endmodule : test_class
- 尝试用localparam提前计算常量
如果必须保留类的结构,可以在父模块中用localparam提前计算出目标值,再传递给子模块。部分工具可能会接受这种方式(但Questa Sim仍可能限制,需测试):
module test_class; localparam int calc_param = my_pkg::helper#(.seed(5))::GetRand(); myModule #(.myParam(calc_param)) i_myModule (); endmodule : test_class
- 工具兼容性说明
Vivado对类静态函数作为常量表达式的支持更为宽松,但Questa Sim严格遵循SystemVerilog标准——类成员函数默认不属于常量表达式范畴。因此优先选择非类的参数化逻辑实现,能保证跨工具的兼容性,同时保留函数的通用性。
内容的提问来源于stack exchange,提问作者Don Rumata
相关产品推荐
相关产品推荐

