为什么 SystemVerilog package 通配符 export 没有导出变量?
数据小许
结论
两段代码的差异来自 SystemVerilog 的 package 导入和导出规则。import P1::*; 只让 a、b 成为候选导入名称。代码 1 中,P2 没有实际导入这两个名称,因此 export P1::*; 不会将它们提供给 TRY1。
代码 2 通过 export P1::a; 和 export P1::b; 明确指定了名称。显式 export 可以触发候选名称的实际导入并将其导出,所以使用方能够访问这两个变量。
通配符为什么没有把变量全部导出?
IEEE Std 1800-2017 第 26.6 节规定,export package_name::*; 只导出当前 package 中已经从指定 package 实际导入的声明,未实际导入的候选名称不会被导出。显式的 export package_name::name; 可以引用候选名称并触发导入。参见 SystemVerilog 标准第 26.6 节。
对应到代码 1:
import P1::*;使a、b成为P2中的候选导入名称。P2内没有使用这两个名称,也没有显式导入它们。export P1::*;因此没有将a、b重新导出。TRY1中的import P2::*;无法通过P2找到它们。
c 是 P2 自己声明的变量,使用方可以通过导入 P2 使用它。
如何修改代码?
原来的代码 2 已经是一种正确写法。如果希望保留通配符 export,可以在 P2 中显式导入需要公开的名称:
package P2;
import P1::a;
import P1::b;
export P1::*;
int c = 2;
endpackage : P2
这样,a、b 已经实际导入 P2,通配符 export 就能将它们重新导出。P1 和 TRY1 可以保持原样。
也可以使用代码 2 的方式,直接列出需要公开的名称:
package P2;
import P1::*;
export P1::a;
export P1::b;
int c = 2;
endpackage : P2
如果使用方不需要通过 P2 访问这些变量,也可以直接使用包限定名:
$display("top : P1::a = %0d", P1::a);
$display("top : P1::b = %0d", P1::b);
$display("top : P2::c = %0d", P2::c);
这种方式不依赖 P2 对 a、b 的重新导出。
排查时需要注意什么?
- 将
export P1::*;换成export *::*;仍然受“实际导入”的限制,不能强制导出所有候选名称。 $display字符串里的P1::a只是输出标签。原代码真正访问的表达式是逗号后的裸名称a,字符串不会触发名称导入。- 使用 SystemVerilog 编译模式,并确保编译依赖顺序为
P1、P2、TRY1。
题目没有提供编译器版本和具体错误信息,无法判断是否还存在工具配置或实现问题。就给出的代码而言,候选导入和实际导入的区别足以解释这两种表现。
备注:内容仅供参考。
