Package 包的概念
SystemVerilog包提供了一种额外的机制,用于在多个SystemVerilog模块module、接口interface、程序program和检查器checker之间共享参数、数据、任务、函数、序列、属性和检查器等声明。
包是一种显式命名的作用域,出现在源文本的最外层(与顶级模块和原语处于同一级别),其实package里包的就是一些数据,而像interface,module是不能定义在package中的,不仅不能定义,甚至不能在package 中去include my_interface.sv、include my_module.sv。
Package 包的作用
1、把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
2、如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
3、包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。由于包创建了新的命名空间(namespace),所以不会跟其他包中的任何名字产生命名冲突。使用包这种机制,更容易实现访问控制,并且让定位相关类更加简单。
Package引用数据
1)用范围解析操作符::
直接引用;
2)将包中特定子项导入到模块或接口中,用import
导入;
3)用通配符*
导入包中的子项到模块或接口中;
注意这里导入后函数就是直接使用的,变量需要使用句柄加.的形式
举例实战
定义:
package definitions; //定义一个包
parameter VERSION = "1.1"; //定义包中一个参数
typedef enum{ADD, SUB, MUL} opcodes_t; //定义包中枚举opcodes_t
typedef struct {
logic [31:0] a, b;
opcodes_t opcode; //声明自定义类型变量
} instruction_t; //定义包中结构体instruction_t
function automatic [31:0] multiplier (input [31:0] a, b); //定义函数function,其中参数为a,b
return a * b; // 用户定义的function代码从这开始
endfunction //function定义结束
endpackage //包定义结束
使用范围解析操作符::直接引用
module ALU(
input definitions::instruction_t IW, //用范围解析操作符::引用definitions包中的instruction_t结构体,并对其命名为IW
input logic clock,
output logic [31:0] result
);
always_ff @(posedge clock) begin
case (IW.opcode)
definitions::ADD : result = IW.a + IW.b; //用范围解析操作符::引用definitions包中的枚举ADD
definitions::SUB : result = IW.a - IW.b;
definitions::MUL : result = definitions::
multiplier(IW.a, IW.b);
endcase
end
endmodule
导入package中的子项import
module ALU(
input definitions::instruction_t IW,
input logic clock,
output logic [31:0] result
);
import definitions::ADD; //用import导入definitions包中的枚举ADD
import definitions::SUB;
import definitions::MUL;
import definitions::multiplier;
always_comb begin
case (IW.opcode)
ADD : result = IW.a + IW.b; //前面导入包中特定子项后,该子项在模块/接口中可见,可直接使用
SUB : result = IW.a - IW.b;
MUL : result = multiplier(IW.a, IW.b);
endcase
end
endmodule
使用通配符*导入所有的定义名称import
module ALU(
input definitions::instruction_t IW,
input logic clock,
output logic [31:0] result
);
import definitions::*; // 通配符导入。实际上是将包添加到标识符搜索路径中
always_comb begin
case (IW.opcode)
ADD : result = IW.a + IW.b; //引用ADD时,在definitions包中查找该名称的定义
SUB : result = IW.a - IW.b;
MUL : result = multiplier(IW.a, IW.b);
endcase
end
endmodule
经验总结
1)在package里include 一个interface.sv文件,出错如下,所以在package里不能include 一个interface;
2)在package里直接import另一个package是找不到的,即使在前面已经include了这个package
3)package里`include另外一个package,是不允许的,编译报错。
4)include和import的区别
include 是把所有的文本内容原样插入到代码中;
import 不会把文本内容插入,其作用是把package的内容引入import 语句所在的作用域。
5) package中无法include另一个package,那么能否import 另外一个package的内容呢?
可以的,如果需要在a.pkg中import b.pkg,需要在include a.pkg之前include b.pkg,如下:
`include b.pkg
`include a.pkg
否则,会出现找不到package的情况。
6)如何在一个package 中import 另一个package?
如果在package a_pkg中import了package b_pkg::type_b,那么在module1中import a_pkg::*时,无法引用到type_b。因为a_pkg只是使得b_pkg::type_b在a_pkg域中可见并加以使用,并未定义在a_pkg中。所以,用户需要牢记一点的是,import操作使得类型可见的域只是调用该import时当前的域。例如下面的例子中,a_pkg中可见b_pkg::b_mon,但是module1则无法可见a_pkg::b_mon