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结构中使用.