PAYATHON 2026

为什么 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:

  1. import P1::*; 使 a、b 成为 P2 中的候选导入名称。
  2. P2 内没有使用这两个名称,也没有显式导入它们。
  3. export P1::*; 因此没有将 a、b 重新导出。
  4. 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。

题目没有提供编译器版本和具体错误信息,无法判断是否还存在工具配置或实现问题。就给出的代码而言,候选导入和实际导入的区别足以解释这两种表现。

备注:内容仅供参考。