首页 > 其他分享 >SV学习(7)——包的使用

SV学习(7)——包的使用

时间:2022-10-04 23:33:39浏览次数:42  
标签:package int SV packet 学习 pkg 使用 import tb

1. 包的定义

  • SV提供了一种在多个module、interface和program中共享parameter、data、type、task、function、class等的方法,即利用package(包)的方法来实现。完整的验证环境会讲不同模块的类定义规整到不同的package中;
  • 讲一簇相关的类组织在了单一的命名空间(namespace)下,使得分属于不同模块验证环境的类来自于不同的package,这样可以通过package来解决类的归属问题;

2. 包的定义

package regs_pkg;
	`include "stimulator.sv";
	`include "monitor.sv";
	`include "chker.sv";
	`include "env.sv";
endpackage

package arb_pkg;
	`include "stimulator.sv";
	`include "monitor.sv";
	`include "chker.sv";
	`include "env.sv";
endpackage
  • 两个package中同名的类,内容是不相同的,实现的功能也是不同的;
  • 不同名的package中同名的类不会发生编译冲突:package是将命名空间分隔开了,当使用同名的类是,注明要使用哪一个package中的类
module test_tb;
	regs_pkg::monitor mon1 = new();
	arb_pkg::monitor mon2 = new();
endmodule

3. 包与库的区分

  • 上述代码例子,regs_pkg和arb_pkg中的存在着同名变量,可以通过域名索引"::"操作符 的方式显式地指出所引用地monitor类具体来自于哪一个package,这样可以通过不同命的package来管理同名的类,也就是package这个容易可以对类名做一个隔离的作用

  • package更多的意义在于将软件(类、类型、方法等)封装在不同的命名空间中,以此来与全局的命名空间进行隔离;

  • library是编译的产物,在没有介绍软件之前,硬件(module、interface、program)都会编译到库中。从容纳的类型来看,库既可以容纳硬件类型,也可以容纳软件类型

  • 若在顶层需要例化两个同名的模块,需要说明两个模块分别是从哪来的,config配置文件说明

  • Questa中,编译简单的module(.sv中只有module)后,模块的模型就会编译到默认库中,同样的还有interface、program

    在这里插入图片描述
    在这里插入图片描述

  • 当在Questa工程中再添加同名(不同路径)的module tb,再编译她,后编译的文件也会编译进默认work库中,就会顶掉之前编译的
    同名module不能编译到同一个库中,若在顶层需要例化两个同名的module,就需要说明两个模块分别是从哪来的,用config配置文件说明】 没这样用过,以后遇到补充

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 若Questa工程下有两个源文件package_import.sv有module tb,class_inheritance.sv也有module tb,里面都有tb模块,默认编译会把module添加到默认work库中,也可以在编译时指定编译库,相应跑仿真也就需要改动

    编译
    vlog -sv package_import.sv
    vlog -sv class_inheritance.sv -work.newlib

    仿真
    vsim -novopt -classdebug work.tb
    vsim -novopt -classdebug newlib.tb

    在这里插入图片描述

4. 包的命名规则

  • 定义的package名称独一无二,其内部定义的类也应该尽可能地独一无二,比如添加前缀,方便处理;
  • 如果不同package中定义的class名也不相同,在顶层的引用可以通过【import pkg_name :: 】的形式,来表示在module mcdf_tb中引用的类,如果在当前域(mcdf内部)中没有定义的话,会搜寻regs_pkg和arb_pkg的定义的类,又由于它们各自包含的类名不相同,因此无需担心下面的搜寻会遇到同名类发生冲突的问题
package regs_pkg;
	`include "regs_stm.sv";
	`include "regs_mon.sv";
	`include "regs_chk.sv";
	`include "regs_env.sv";
endpackage

package arb_pkg;
	`include "arb_stm.sv";
	`include "arb_mon.sv";
	`include "arb_chk.sv";
	`include "arb_env.sv";
endpackage

module test_tb;
	import regs_pkg::*;	// *代表全部类型
	import arb_pkg::*;
	regs_mon mon1 = new();
	arb_mon mon2 = new();
endmodule

5. 包的使用

  • 在包中可以定义类、静态方法和静态变量
  • 如果将类封装在某一个包中,那么它就不应该在其他地方编译,这么做的好处在于之后对类的引用更加方便
  • 一个完整模块的验证环境组件类,应该是由一个对应的模块包来封装
  • 使用’include关键字完成类在包中的封装,要注意编译的前后顺序来放置各个‘include的类文件
  • 编一个包的背后实际是将各个类文件用纯文本替换,按照顺序完成包和各个类的有序编译
  • 使用“import”可以将包中所以类或者某一个类导入

补充:包的编译和代码示例

  • 在library中编译module的时候,默认会查找所有的library
  • 在modle中声明类(类在package中),编译时只能查找到library中有package,不会进一步往下找(package内部),相当于package - endpackage关键字把里面的内容包进了一个盒子,除非主动告诉要到某一个盒子中找类型
package pkg_a;
	class packet_a;
	endclass
	typedef struct {
		int data;
		int command;
	} struct_a;
	int va = 1;
endpackage

package pkg_b;
	class  packet_b;
	endclass
	typedef struct {
		int data;
		int command;
	} struct_b;
	int vb = 2;
endpackage

module mod_a;
endmodule

module mod_b;
endmodule

module tb;
	class packet_tb;
	endclass
	typedef struct {
		int data;
		int command;
	} struct_tb;
	
	mod_a ma();
	mod_b mb();
	
//	import pkg_a::packet_a;
//	import pkg_b::packet_b;
//	import pkg_a::va;
//	import pkg_b::vb;

	import pkg_a::*;
	import pkg_b::*;
	
	initial begin
		//-- packet_a  pta = new();	// err
		//-- packet_b  ptb = new();	// err
		packet_a  pa = new();
		packet_b  pb = new();
		packet_tb ptb = new();
		$display("pkg_a::va = %0d, pkg_b::vb = %0d", va, vb);
	end
endmodule
	class packet_a;
		int tb_a;
	endclass
	class packet_b;
		int tb_b;
	endclass
	
	mod_a ma();
	mod_b mb();
	
	import pkg_a::packet_a;	// err: 'packet_a' already declared in this scope 模块内有重名类
	import pkg_b::packet_b;
//	import pkg_a::va;
//	import pkg_b::vb;

//	import pkg_a::*;	// 如果在当前域中没找到的话,会搜寻包内部,重名不会报错
//	import pkg_b::*;
	
	initial begin
		//-- packet_a  pta = new();	// err
		//-- packet_b  ptb = new();	// err
		packet_a  pa = new();
		packet_b  pb = new();
		packet_tb ptb = new();
		$display("pkg_a::va = %0d, pkg_b::vb = %0d", va, vb);
	end
  • 用import::package_name::*导入更安全,这样先在当前域中找,没找到在进包中找,如果当前域和包中有重名的也不会报错
package pkg_a;
	class packet_a;
		int pkg_a;
	endclass
	typedef struct {
		int data;
		int command;
	} struct_a;
	int va = 1;
	int shared = 10;
endpackage

package pkg_b;
	class  packet_b;
		int pkg_b;
	endclass
	typedef struct {
		int data;
		int command;
	} struct_b;
	int vb = 2;
	int shared = 20;
endpackage

module mod_a;
endmodule

module mod_b;
endmodule

module tb;
	class packet_tb;
	endclass
	typedef struct {
		int data;
		int command;
	} struct_tb;
	
	class packet_a;
		int tb_a;
	endclass
	class packet_b;
		int tb_b;
	endclass
	
	mod_a ma();
	mod_b mb();
	
//	import pkg_a::packet_a;	// err: 'packet_a' already declared in this scope 模块内有重名类
//	import pkg_b::packet_b;
//	import pkg_a::va;
//	import pkg_b::vb;

	import pkg_a::*;	// 如果在当前域中没找到的话,会搜寻包内部,重名不会报错
	import pkg_b::*;
	
	initial begin
		//-- packet_a  pta = new();	// err
		//-- packet_b  ptb = new();	// err
		packet_a  pa = new();
		packet_b  pb = new();
		packet_tb ptb = new();
		$display("pkg_a::va = %0d, pkg_b::vb = %0d", va, vb);
		$display("shared = %0d", shared);	// err: Identifier 'shared' is not directly visible 不直接可见
	end
endmodule
  • 在两个包中添加同名变量shared,需要显式指明哪个包里的
package pkg_a;
	...
	int shared = 10;
endpackage

package pkg_b;
	...
	int shared = 20;
endpackage

... ... 
	
module tb;
	...
	
	import pkg_a::*;	// 如果在当前域中没找到的话,会搜寻包内部,重名不会报错
	import pkg_b::*;
	
	initial begin
		packet_a  pa = new();
		packet_b  pb = new();
		packet_tb ptb = new();
		$display("pkg_a::va = %0d, pkg_b::vb = %0d", va, vb);
//		$display("shared = %0d", shared);	// err: Identifier 'shared' is not directly visible 不直接可见
		$display("shared = %0d", pkg_a::shared);
	end
endmodule
  • package名一定不能重,建议内部的变量、类也最好不要重

3.16 补充

  • 全局变量和局部变量是从变量的作用域的角度划分;
  • 静态变量和动态变量是从变量的内存分配的角度划分;
  • package中声明的变量是静态的、全局的;

标签:package,int,SV,packet,学习,pkg,使用,import,tb
From: https://www.cnblogs.com/amxiang/p/16754831.html

相关文章

  • 【服务器管理】禁止指定用户使用密码登录服务器
    前言登录服务器通常会采用“用户名-密码”和“ssh密钥”这两种方案中的一种,而在调研到的大多数观点中,都认为密钥比密码更加安全。在管理服务器时,强制服务器用户均使用密......
  • 【生信学习第三天】论文分区和影响因子 If 查询
    一、什么是影响因子影响因子(英文:Impactfactor,缩写:IF),又译作影响指数或影响系数,指某一期刊的文章在特定年份或时期被引用的频率,是衡量学术期刊影响力的一个重要指标,由美国......
  • XX学Python·运算符的使用
    算数运算符加减乘除//取商%取余(取模)**幂次运算()小括号用来提高运算优先级float1=10.2int1=4int2=11#数值型数据(float,int,bool)间可以进行算数运算#......
  • 补档--【THM】Subdomain Enumeration(子域名枚举)-学习
    简介子域名枚举是为一个域查找有效子域的过程,在本节中我们将学习发现子域的各种方法,我们这样做是为了扩大我们的攻击面,试图发现更多潜在的漏洞点。我们将探讨三种不同的......
  • 【微信小程序】button和image组件的基本使用
    ......
  • 【ECharts学习】—实现中国地图
    【ECharts学习】—实现中国地图使用Echarts进行地图绘制展示的时候,需要china.js的引入,我把它放在百度网盘里了,需要的自取​​点我跳转到百度网盘​​提取码:clby<!DOCTYPE......
  • Pandas 学习笔记
    一、用Pandas创建Excel文件importpandasaspddf=pd.DataFrame({'ID':[1,2,3],'Name':['liujun','daifen','duanziqian']})#创建一个数据集df=df.set_index('ID'......
  • python中类与对象的命名空间(静态属性的陷阱)、__dict__ 和 dir() 在继承中使用说明
    1.面向对象的概念1)类是一类抽象的事物,对象是一个具体的事物;用类创建对象的过程,称为实例化。2)类就是一个模子,只知道在这个模子里有什么属性、什么方法,但是不知道......
  • java学习前
    java后台运行机制编译指令:javaca.java-dx.classa.java--->x.class运行指令:javax.classx.class是都可以直接运行的机器指令,一份java代码可以再多平台使用,原......
  • 学习记录-Python的局部变量和全局变量
    目录1定义2作用域的重要性2.1全局作用域中的代码不能使用任何局部变量2.2局部作用域中的代码可以访问全局变量2.3不同局部作用域中的变量不能相互调用2.4在不同的作......