SystemVerilog中的包提供对许多不同数据类型、包括nets、variable、task、function、assertion sequences、property和checker声明的封装。封装再包内的数据可以在多个module、interface、program和checkers之间共享。它们有明确命名的范围(或通配符范围——访问范围的所有成员),允许引用该范围内的数据。它提供了一种整洁的可重用方法。包也是一个顶级对象——也就是说,它不能在模块、程序、类或其他包中声明。
看一个例子:
package myPack;
typedef struct {
int i;
int j;
} cStruct;
function cStruct add (cStruct a , b);
add.i = a.i + b.i;
add.j = a.j + b.j;
endfunction
endpackage
module top (
//referencing package item 'cStruct' of myPack
output myPack::cStruct cout,
input myPack::cStruct a , b
);
//referencing 'add' function of myPack
assign cout = myPack::add(a , b);
endmodule
在这个例子中,我们声明了一个包“myPack”,它有一个结构体声明“cStruct”和一个函数“add”,它们被封装在“myPack”包中。在模块“top”中,我们使用“myPack”中的“cStruct”作为模块“top”的 I/O。请注意,我们没有明确导入包“myPack”。相反,我们使用以下语法显式引用“myPack”:
myPack::cStruct
这是从包中引用函数、任务、结构体等的一种方式。另一种方法是简单地在模块中导入包,然后允许访问包数据而无需显式引用包。下面是有“导入”包的示例:
package myPack;
typedef struct {
int i;
int j;
} cStruct;
function cStruct add (cStruct a , b);
add.i = a.i + b.i;
add.j = a.j + b.j;
endfunction
endpackage
//importing selective entity from 'myPack'
//import myPack::cStruct;
//import myPack::add;
import myPack::*; //importing entire myPack
module top (
output cStruct cout,
input cStruct a , b
);
//'add' is visible ... no need for mypack::add(a, b);
assign cout = add(a , b);
endmodule
在此示例中,我们可以从“myPack”导入单个结构体和函数,如下所示:
//importing selective entity from 'myPack'
import myPack::cStruct;
import myPack::add;
我们也可以导入整个包,而不需要单独的实体导入,如下所示:
import myPack::*; //importing entire myPack
请注意,无论以哪种方式导入包,包中包含的结构体和函数在模块“top”中直接可见。因此,我们有“assign cout = add(a, b);”
无需显式调用“assign cout = myPack::add(a, b);”。
package p;
typedef enum { FALSE, TRUE } bool;
endpackage
package q;
typedef enum { ORIGINAL, FALSE } hair;
endpackage
module top1 ;
import p::*;
import q::hair;
hair myhair;
initial begin
myhair = q:: FALSE; // OK:
//myhair = FALSE;
// ERROR: Direct reference to FALSE refers to the
// FALSE enumeration literal imported from p
end
endmodule
module top2 ;
import p::*;
import q::hair, q::ORIGINAL, q::FALSE;
//import q::*; //will not work.. need above import
hair myhair;
initial begin
myhair = FALSE;
// OK: Direct reference to FALSE refers to the
// FALSE enumeration literal imported from q
end
endmodule
在这个例子中,我们声明了两个包“p”和“q”。请注意,枚举变量 FALSE 存在于两个包中。在模块“top1”中,我们导入整个包 p(import p::*)并显式导入枚举类型“hair”(import q::hair)。并声明“myhair”为“hair”类型。
现在,当我们尝试将 FALSE(来自包“q”)直接分配给 myhair(myhair = FALSE;)时,它会报错,因为编译器认为你正在从包 p 中分配 FALSE。你不能这样做,因为“myhair”属于“hair”类型,并且只能(应该)接受包 q 中的 FALSE。因此,myhair = FALSE 将给出如下所示的编译时错误(Synopsys – VCS):
Error-[ENUMASSIGNTYPE] Different enum types in assignment
testbench.sv, 20
Different enum types in assignment statement
Cannot assign a value of type 'p::bool' to a variable of type 'q::hair'
Source info: myhair = FALSE;
为了避免这种情况,在模块“top2”中,我们显式导入以下内容:
import q::hair, q::ORIGINAL, q::FALSE;
这使得“q”中的 FALSE 在导入的范围内可用。所以,现在当我们执行 myhair = FALSE 时,它会起作用。
请注意,在模块“top2”中,如果你只是执行“import q::*”,它仍然无法正常工作。如果你只是在模块“top2”中执行以下操作:
module top2 ;
import p::*;
import q::*;
hair myhair;
initial begin
myhair = FALSE;
end
endmodule
将收到以下错误(Synopsys – VCS):
Error-[SV-LCM-MWD] Multiple wildcard definition
testbench.sv, 32
top2, "FALSE" Identifier 'FALSE' getting imported from more than one package
p::* [testbench.sv:25] (Owner Package: p)
and q::* ["testbench.sv", 27] (Owner Package: q)
Make explicit import with the package from where the definition should be picked.
现在看看在包中导入包的工作原理以及在分层导入的包中声明变量的可见性。示例:
package P1;
int a = 1;
endpackage : P1
package P2;
import P1 :: *;
int b = 2;
endpackage : P2
module TRY1( );
import P2 :: *;
initial begin
$display("top : P1::a = %0d", a);
$display("top : P2::b = %0d", b);
end
endmodule : TRY
VCS报错:
Simulation log (Synopsys – VCS):
Error-[IND] Identifier not declared
testbench.sv, 14
Identifier 'a' has not been declared yet. If this error is not expected,
please check if you have set `default_nettype to none.
在这个例子中,我们声明了两个包“P1”和“P2”。 “P1”具有变量“a”,“P2”具有在其中声明的变量“b”。然后我们将 P1::* 导入到包“P2”中。这意味着变量“a”在包“P2”中可见。
然后在模块“TRY1”中,我们导入 P2::*(但我们不导入 P1::*)。我们尝试从模块“TRY1”访问“a”和“b”。现在,你可能会认为,由于“P2”导入“P1”,“P1”中声明的变量将在“TRY1”模块中可见。但事实并非如此。变量“a”仅在包“P2”中可见,因为P2中才是 import P1::* 发生的地方。换句话说,变量“a”仅在其包被导入的地方(模块或包)可见,而不在另一个模块(或包)中可见。你需要了解将一个包导入另一个包的含义。
让我们看同样的例子,但这里我们在模块 TRY1 中同时导入“P1”和“P2”。让我们看看变量“a”现在在模块 TRY1 中是否可见。
package P1;
int a = 1;
endpackage : P1
package P2;
import P1 :: *;
int b = 2;
endpackage : P2
module TRY1( );
import P1 :: *;
import P2 :: *;
initial begin
$display("TRY1 : P1::a = %0d", a);
$display("TRY1 : P2::b = %0d", b);
end
endmodule : TRY1
这两个示例之间的唯一区别在于,在示例 2 中我们同时导入了 P1 和 P2。由于 P1 在模块 TRY1 中显式导入,因此(包 P1 的)变量“a”现在在模块 TRY1 中可见。仿真结果:
Compiler version S-2021.09; Runtime version S-2021.09; Aug 24 08:26 2022
TRY1 : P1::a = 1
TRY1 : P2::b = 2
V C S S i m u l a t i o n R e p o r t
现在,你可能想知道为什么要导入一个包,为什么我不能只将文件包含在我的模块中。它不会以同样的方式工作吗?答案是否定的。这与 SystemVerilog 的类型系统有关。 (Rich, Dave) 提供了一个很好的解释,在这里尝试总结一下。
假设你有两个类“A”和“B”,定义如下:
class A;
int i;
endclass : A
class B;
int i;
endclass : B
SystemVerilog 将这两个类定义视为不相等的类型,因为它们具有不同的名称(“A”和“B)”,即使两个类的内容相同。这是因为类的名称不仅仅是简单的名称“A”和“B”。它们的名称还包括声明定义的范围。因此,当你在包中声明一个类时,包名将成为类名的前缀。
现在我们定义两个包含“A”类定义的包:
package P;
class A;
int i;
endclass : A
A a1;
endpackage : P
//另一个包 Q 中“A”的类定义与包 P 中相同:
package Q;
class A;
int i;
endclass : A
A a1;
endpackage : Q
请注意,和之前一样,“A”类有两种定义。添加包前缀后,它们是 P::A 和 Q::A,变量 P::a1 和 Q::a1 仍然是类型不兼容的,因为它们引用了两个不同的类“A”。
如果用ìnclude重写上面的代码,没有什么实质的改变,因为`include 只是在你使用 `include 的文件的剪切/粘贴文本的快捷方式。所以,这里有与上面相同的包,但是使用了`include。
package P;
`include "A.sv"
A a1;
endpackage : P
package Q;
`include "A.sv"
A a1;
endpackage : Q
P::a1 和 Q::a1 之间的类型仍然不兼容。
现在,让我们使用 import 而不是 `include。首先,声明定义类“A”的包“P”:
package P;
class A;
int i;
endclass : A
endpackage : P
package R;
import P::A;
A a1;
endpackage : R
package S;
import P::A;
A a1;
endpackage : S
首先要注意的是,类“A”只有一个定义(在包“P”中)。在前面的示例中,我们对“A”类有两个定义,每个包中都有一个。有了这个前提,变量 R::a1 和 S::a1 是类型兼容的,因为它们都是 P::A 类型。
这就是使用“包含”与使用“导入”之间的主要区别。使用“import”解决了类型兼容性问题。
关于导入枚举类型的最后一点说明。请注意,导入枚举类型定义不会导入其枚举标签。你必须显式导入枚举类型的所有标签(或使用通配符导入)。例如,
package enumP;
typedef enum logic [1:0] {SLOW, FAST, MEDIUM} speed;
endpackage
module top;
import enumP::speed;
speed s1;
always @(posedge clk)
…
s1 <= FAST; //ERROR
…
endmodule
在模块“top”中,导入枚举“speed”并尝试访问枚举标签“FAST”。但这是不可能的。枚举名称已导入,但枚举标签未导入。 “FAST”是枚举“speed”中的枚举标签,并未导入。
为了解决这个问题,必须显式地导入枚举标签。必须执行以下操作:
import enumP::speed;
import enumP::SLOW;
import enumP::FAST;
import enumP::MEDIUM;
解决问题的另一种方法是使用通配符导入:
import enumP::*;
这将导入枚举类型及其所有标签。
标签:P1,FALSE,Package,package,SV,导入,myPack,import From: https://www.cnblogs.com/fuqiangblog/p/16621366.html