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

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中声明的变量是静态的、全局的;
  • 2
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值