Verilog系列:package多层导入
前面已经了解了package是如何导入到其他结构(module\interface\program等)中("Verilog系列:package封装成员"),除此之外,package也可以导入到其他的package中,然后再通过其他的package导入到其他的结构中.可能会有人文为什么要这样做?对于一个巨大的项目,很有可能出现不同的设计人员,他们使用各自定义的package,当最后要将整个设计进行整合时就需要整合这些package,为此,SystemVerilog提供了package之间相互导入的功能,本文将以示例说明.
`timescale 1 ns / 1 ps
package p1;
typedef enum {FALSE,TRUE} bool_t;
bool_t b = FALSE;
bool_t c = TRUE;
int d = 3;
int e = 4;
endpackage // p1
package p2;
import p1::*;
int c =d;
endpackage // p2
module top_tb;
import p2::*;
logic [31:0] tmp1,tmp2;
initial begin
tmp1 = c;
// tmp2 = d; // illegal
$display("tmp1 is %h",tmp1);
end
endmodule 【仿真结果】 # tmp1 is 00000003
第11行通过p1::*使p1中的成员在p2中可见,在p2中声明c同时使用p1中的d对其进行初始化.在15行开始的module中通过p2::*,使其中的成员在module中可见,但是此时需要注意,虽然p1中的成员在p2中可见,但是其在module中并不可见.例如示例中的d,在module中并不可见,所以直接将d赋给tmp2会报找不到d的错误.也就是说一个package中的成员import到另一个package中后,其中的成员并不会随着另一个package导入到其他结构中.那么如何实现一个package中的成员导入到另一个package后还能够随着另一个package导入到其他架构中呢?请看下例.
`timescale 1 ns / 1 ps
package p1;
typedef enum {FALSE,TRUE} bool_t;
bool_t b = FALSE;
bool_t c = TRUE;
int d = 3;
int e = 4;
endpackage // p1
package p2;
import p1::*;
export p1::*;
int c = d;
endpackage // p2
module top_tb;
import p2::*;
logic [31:0] tmp1,tmp2;
initial begin
tmp1 = c;
tmp2 = d;
$display("tmp1 is %h,tmp2 is %h",tmp1,tmp2);
end
endmodule 【仿真结果】 # tmp1 is 00000003,tmp2 is 00000003
示例中通过在第12行增加p1的export声明后,p1中的元素不仅在p2中可见,而且也可以随着p2导入到其他的结构中.但是这里有一点需要注意,采用通配符导入方式仅仅表示只是p1中的内容在p2中可见,具体p1中哪个成员导入到p2中取决于p2中使用了p1中的哪个成员.如下例.
`timescale 1 ns / 1 ps
package p1;
typedef enum {FALSE,TRUE} bool_t;
bool_t b = FALSE;
bool_t c = TRUE;
int d = 3;
int e = 4;
endpackage // p1
package p2;
import p1::*;
export p1::*;
int c = d;
endpackage // p2
module top_tb;
import p2::*;
logic [31:0] tmp1,tmp2,tmp3;
initial begin
tmp1 = c;
tmp2 = d;
tmp3 = e; // illegal!
$display("tmp1 is %h,tmp2 is %h,tmp3 is %h",tmp1,tmp2,tmp3);
end
endmodule 【仿真结果】
编译错误!
虽然11行和12行采用了通配符使p1中的元素在p2中可见,但是实际上可以被访问的只有p2中使用的d.那么p2采用通配符模式导入module中时,p2中并没有使用e,所以此时e并不存在于p2中也就对于module不可见.如果在p2中没有对d的引用,那么在module中d也是不可见的.
`timescale 1 ns / 1 ps
package p1;
typedef enum {FALSE,TRUE} bool_t;
bool_t b = FALSE;
bool_t c = TRUE;
int d = 3;
int e = 4;
endpackage // p1
package p2;
import p1::d;
export p1::*;
int c = d;
// int f = e; // illegal
endpackage // p2
module top_tb;
import p2::*;
logic [31:0] tmp1,tmp2;
initial begin
tmp1 = c;
tmp2 = d;
$display("tmp1 is %h,tmp2 is %h",tmp1,tmp2);
end
endmodule 【仿真结果】 # tmp1 is 00000003,tmp2 is 00000003
【示例】
`timescale 1 ns / 1 ps
package p1;
typedef enum {FALSE,TRUE} bool_t;
bool_t b = FALSE;
bool_t c = TRUE;
int d = 3;
int e = 4;
endpackage // p1
package p2;
import p1::*;
export p1::d;
int c = d;
int f = e;
endpackage // p2
module top_tb;
import p2::*;
logic [31:0] tmp1,tmp2,tmp3;
initial begin
tmp1 = c;
tmp2 = d;
// tmp3 = e; // illegal
tmp3 = f;
$display("tmp1 is %h,tmp2 is %h,tmp3 is %h",tmp1,tmp2,tmp3);
end
endmodule 【仿真结果】# tmp1 is 00000003,tmp2 is 00000003,tmp3 is 00000004
12行允许p2在导出时其中的d对外可见,注意此处并没有显式的说明e对外可见,所以在22行可以访问到p1中的d,但是23行并不能访问到e.
为了更好地总结,这里我们假设p1要导入到p2中,然后p2再导入到其他结构中,通过上述几种示例及仿真结果可以总结如下:
| 场景 | 说明 |
| package p2; import p1::*; export p1::*; endpackage | 如果p1中的成员在p2中被访问了,那么该被访问的成员在p2导入到其他结构时对其它结构可见 |
| package p2; import p1::var_n; export p1::*; endpackage | 仅var_n在p2导入到其他结构时对其它结构可见,p1中的其他成员对于p2可见 |
| package p2; import p1::*; export p1::var_n; endpackage | 同上 |
可见,import表征了package中哪些成员对外可见,而export则表征了哪些成员在当前package导出时可被访问.同时这里还需要注意,export只能在package结构中使用.
查看10道真题和解析