首页 > 其他分享 >SV中的包(Package)

SV中的包(Package)

时间:2022-08-24 21:02:37浏览次数:37  
标签:P1 FALSE Package package SV 导入 myPack import

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

相关文章

  • windows10-msys2-msvc编译ffmpeg4.4.2
    下载msys2在msys2安装目录下创建文件msys2_ffmpeg.batcall"D:\ProgramFiles\MicrosoftVisualStudio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"setMSY......
  • C#下载csv代码总结(解决中文乱码问题)
    ///<summary>///下载///</summary>///<paramname="startTime"></param>///<paramname="endTime"></param>publicvoidDownload(DateTime?startTime,D......
  • svg学习
    svg学习基础知识参考资料https://baike.baidu.com/item/SVG格式/3463453?fr=aladdinSVG指可伸缩矢量图形(ScalableVectorGraphics)SVG用来定义用于网络的基于......
  • package.json和package-lock.json的区别(转载)
    package.json记录当前项目所依赖模块的版本信息,更新模块时锁定模块的大版本号(版本号的第一位),不能锁定后面的小版本,package-lock.jsonpackage-lock.json是在`npminst......
  • 一天一个知识点-----vue项目简单引入svg
    项目背景:vue3.0+elementPlus注意项目结构,主要涉及的几个文件及文件夹---直接上代码----1.最开始是要下载包npminstallsvg-sprite-loader2.配置项目的配置文件vu......
  • package.json 与 package-lock.json 的关系
    模块化开发在前端越来越流行,使用node和npm可以很方便的下载管理项目所需的依赖模块。package.json用来描述项目及项目所依赖的模块信息。那 package-lock.json 和......
  • csv
    importcsv#withopen('write.csv','r')asf:#打开#text=csv.reader(f)#读取##print(text)#forrowintext:#必须这样才可以读取出数据#......
  • svn客户端检出的工程导入eclipse后不显示SVN信息
    1、首先确定原因:是由于SVN客户端与SVN插件版本不对应导致的,因此需要更换SVN插件版本1.1、SVN插件与SVN客户端版本对应关系插件svn1.4.x对应TortoiseSvn1.5.x插件svn1.6......
  • 2022年8月21日周六总结(maven install和package的区别未完成)
    最近做了nexus的配置,突然发现maven也很重要,我们平时会在idea用到clear、install、package等,package毫无疑问就是打包jar包了(在maven中定义了),这个打包会把 最近:这里记录......
  • 日常学习(2)sv赋值、寻址方式、正则
    sv赋值方式sv的赋值方式可以采用.形参(参数)的方式,更清晰功能https://gitee.com/bai-mengwei/my_uart_tb/blob/11126a220e740ea070c128f1949078daaaf5cad7/uvm_tb/registe......