为何在SystemVerilog函数/任务内初始化变量会报错?
维基百科相关描述
在任务或函数内部声明且未指定类型的变量会被视为自动(automatic)变量。若要指定变量为静态(static),需在类型前添加"static"关键字,例如
static int x;。"automatic"关键字的用法同理。
报错代码示例
module MouduleName (); function int getNumberDivisableValue(int divisibleNumber); int number_divisable_value = 0; // 未显式声明为automatic // automatic int number_divisable_value = 0; // 显式声明为automatic时可正常工作 while (!number_divisable_value) begin number_divisable_value = $urandom_range(URANDOM_MIN_RANGE, URANDOM_MAX_RANGE); if (number_divisable_value % divisibleNumber == 0) begin return number_divisable_value; end else begin number_divisable_value = 0; end end endfunction initial begin // 函数调用 end endmodule
报错信息
可抑制错误:array_manipulation.sv(18): (qverilog-2244) 变量'number_divisable_value'是隐式静态变量。您必须显式将其声明为static或automatic,或者移除变量声明中的初始化操作。
疑问1解答
维基百科的描述有个关键前提:未指定类型的变量默认才是automatic。而你代码里的int number_divisable_value = 0;已经指定了int类型,此时SystemVerilog的规则是:未标记为automatic的任务/函数中,带类型的变量默认是static。
QuestaSim报错的核心原因就在这:你的函数没加automatic属性,变量也没显式声明automatic,所以这个带类型的变量默认是静态变量。静态变量的初始化是仿真启动时执行一次,之后每次调用函数都不会重新初始化,但你的逻辑需要每次调用时变量都回到0,这就和静态变量的特性冲突了,工具因此抛出错误。当你给变量显式加上automatic关键字后,它变成了自动变量,每次函数调用都会重新分配内存并执行初始化,符合你的逻辑,所以不再报错。
额外说明:如果想让函数内所有变量默认是automatic,直接给函数加上automatic属性即可,比如function automatic int getNumberDivisableValue(int divisibleNumber);,这样里面的带类型变量都会默认是自动变量,无需单独加关键字。
疑问2解答
早期的SystemVerilog标准里,自动变量在声明时初始化的写法是不被允许的——因为自动变量的内存是在任务/函数调用时才分配的,早期标准对这种初始化的执行时机和语义定义不够明确。不过后续的标准(比如IEEE 1800-2012及之后版本)已经支持这种写法,但像QuestaSim这类工具为了兼容旧代码,默认开启了严格语法检查,会把这种写法标记为错误。
而Java这类编程语言从设计之初就明确了局部变量的生命周期:每次进入方法时分配内存并执行初始化,语义清晰无歧义,所以天然支持这种写法。你可以通过调整QuestaSim的编译选项关闭这个可抑制错误的检查,或者升级工具版本来适配新的SystemVerilog标准特性。
内容的提问来源于stack exchange,提问作者NIVESH D

