Verilog系列:package封装成员

moduleinterfaceprogram等结构中可以对类、变量、线网、任务、函数等多种成员进行声明,并且这些成员很多具有相同的声明定义形式,那么有没有一种方法将这些“同名同姓”的成员放在一个共享的地方呢?SystemVerilog借鉴了VHDL中的package结构,通过将共享的内容添加到package结构中实现了这些成员的共享,实现了代码的分割、共享和重用.

packagemoduleprograminterface等类似需要进行独立的声明,package中不能再定义其他的package,当然这几种结构彼此也不能在对方的定义中进行嵌套定义.但是package可以将其中的内容import到这些结构中.当然,与这些结构一样,package也有自己的格式如下:
package pkg_name;
    Net_declaration;
    Data_declaration;
    Task_declaration;
    Function_declaration;
    Checker_declaration;
    Dpi_import_export;
    Extern_constraint_declaration; 
    Class_declaration;
    Class_constructor_declaration;
    Localparameter_declaration;
    Parameter_declaration;
    Coverage_declaration;
    Overload_declaration;
    Assertion_iterm_declaration;
    Package_export_declaraton;
    Timeunits_declaration;
endpackage

注意,这里的parameter不能像module中那样在例化时指定(package是不能例化的),所以其中的parameterlocalparam是等同的.又因为package中的成员会被其他结构引用,所以package的编译必须先于使用该package的模块的编译.而一般情况下,package通过以下两种方式实现其中成员在其他模块中的引用.

  • 在设计代码中通过"::"作用域符号直接引用package中的元素;

  • 在设计代码中通过import使package中的元素可以被访问;


在设计代码中通过作用域符号引用package中的元素

【示例】
`timescale 1 ns /1 ps
`define DLY 1
package p1;
    typedef enum {ADD,SUB,MUL} opts_t;
    typedef enum {FALSE,TRUE} bool_t;
    logic [31:0] opt1,opt2;
    reg  imhere;
    wire im2here;
    function automatic [31:0] multx(input [31:0] d1,input [31:0] d2);
        return d1*d2;
    endfunction
endpackage    // p1

module disp(input logic bt);
always @(bt)
begin
    if (bt == 1'b1) begin
        $display("===============================");
        $display("Opt1 is %h and Opt2 is %h!",p1::opt1,p1::opt2);
    end
    if (bt == 1'b0)
        $display("===============================");     
end
endmodule

module top_tb;
p1::opts_t opts;
p1::bool_t blt;
logic [31:0] result;
logic bt;
initial begin
      p1::opt1 = 32'h12;
      p1::opt2 = 32'h34;
    #`DLY opts = p1::SUB;
           blt = p1::TRUE;
    #`DLY opts = p1::ADD;
           blt = p1::FALSE;
    #`DLY opts = p1::MUL;                      
end

always @(opts)
begin
    case(opts)
        p1::ADD : result = p1::opt1 + p1::opt2;
        p1::SUB : result = p1::opt1 + p1::opt2;
        p1::MUL : result = p1::multx(p1::opt1,p1::opt2);
    endcase
    $display("The option result is %h",result);
end

always @(blt)
begin
    if (blt == p1::TRUE)
        bt = 1'b1;
    if (blt == p1::FALSE)
        bt = 1'b0;        
end
disp u_dut(bt);
endmodule
【仿真结果】
# The option result is 0000000f
# ===============================
# Opt1 is 00000012 and Opt2 is 00000003!
# The option result is 00000015
# ===============================
# The option result is 00000036

示例中32行和33行通过作用域符好实现了对package中成员的引用,即完成了对opt1opt2的赋值操作.在模块disp中调用了p1中的opt1opt2,通过仿真可以观测到,top_tb中对p1中的opt1opt2的修改会影响到所有调用p1opt1opt2的模块,所以对于一般可综合的结构不建议在package中声明全局变量(线网)或者静态的函数或任务.

上例中package元素比较少还可以使用作用域符号实现对package中元素的引用,那么当package中被引用的成员很多时,如果还是用上例通过作用域符号引用的方式代码将会变得很冗繁,而且还特别容易出错.为此,可以使用下属的import方式对package中元素的引用.常用的import方式有两种,如下:

  • import package_name::var_name;;指定特定元素;

  • import package_name::*;使package中所有元素在被import结构中可见(这里需要注意具体哪些元素可见,取决于当前范围引用了package中的哪些元素);

通过import导入package中的元素

【示例】

`timescale 1 ns /1 ps
`define DLY 1
package p1;
    typedef enum {ADD,SUB,MUL} opts_t;
    typedef enum {FALSE,TRUE} bool_t;
    logic [31:0] opt1,opt2;
    reg  imhere;
    wire im2here;
    function automatic [31:0] multx(input [31:0] d1,input [31:0] d2);
        return d1*d2;
    endfunction
endpackage    // p1

module disp(input logic bt);
always @(bt)
begin
    if (bt == 1'b1) begin
        $display("===============================");
        $display("Opt1 is %h and Opt2 is %h!",p1::opt1,p1::opt2);
    end
    if (bt == 1'b0)
        $display("===============================");     
end
endmodule

module top_tb;
// below explicitly imported
import p1::ADD;
import p1::SUB;
import p1::MUL;
import p1::FALSE;
import p1::TRUE;
import p1::opt1;
import p1::opt2;
import p1::multx;
import p1::opts_t;
import p1::bool_t;
// end explicitly imported
opts_t opts;
bool_t blt;
logic [31:0] result;
logic bt;
initial begin
      p1::opt1 = 32'h12;
      p1::opt2 = 32'h3;
    #`DLY opts = SUB;
           blt = TRUE;
    #`DLY opts = ADD;
           blt = FALSE;
    #`DLY opts = MUL;                      
end

always @(opts)
begin
    case(opts)
        ADD : result = opt1 + opt2;
        SUB : result = opt1 - opt2;
        MUL : result = multx(opt1,opt2);
    endcase
    $display("The option result is %h",result);
end

always @(blt)
begin
    if (blt == TRUE)
        bt = 1'b1;
    if (blt == FALSE)
        bt = 1'b0;        
end
disp u_dut(bt);
endmodule
【仿真结果】
# The option result is 0000000f
# ===============================
# Opt1 is 00000012 and Opt2 is 00000003!
# The option result is 00000015
# ===============================
# The option result is 00000036

通过import导入p1中指定元素后,该元素对于当前模块可见,可以不用再使用作用域符号进行引用.但是这里需要注意,在对枚举类型进行引用时,不止要import定义的类型,还要import其中定义的符号,如示例中28-32,如果不对这些枚举类型中的符号进行import,那么在当前模块不能直接引用这些符号.可见,相较之前的示例,本例中使用import可以简化代码,但是,如果package中需要引用的元素非常多时,这样这个通过import指定元素同样是一件非常繁重的体力劳动.为此SystemVerilog中提供了另一种方式,使对package中元素的引用更加简洁使用.

【示例】

`timescale 1 ns /1 ps
`define DLY 1
package p1;
    typedef enum {ADD,SUB,MUL} opts_t;
    typedef enum {FALSE,TRUE} bool_t;
    logic [31:0] opt1,opt2,opt3;
    reg  imhere;
    wire im2here;
    function automatic [31:0] multx(input [31:0] d1,input [31:0] d2);
        return d1*d2;
    endfunction
endpackage    // p1

module disp(input logic bt);
always @(bt)
begin
    if (bt == 1'b1) begin
        $display("===============================");
        $display("Opt1 is %h and Opt2 is %h!",p1::opt1,p1::opt2);
    end
    if (bt == 1'b0)
        $display("===============================");     
end
endmodule

module top_tb;
import p1::*;
opts_t opts;
bool_t blt;
logic [31:0] result;
logic bt;
initial begin
      p1::opt1 = 32'h12;
      p1::opt2 = 32'h3;
    #`DLY opts = SUB;
           blt = TRUE;
    #`DLY opts = ADD;
           blt = FALSE;
    #`DLY opts = MUL;                      
end

always @(opts)
begin
    case(opts)
        ADD : result = opt1 + opt2;
        SUB : result = opt1 - opt2;
        MUL : result = multx(opt1,opt2);
    endcase
    $display("The option result is %h",result);
end

always @(blt)
begin
    if (blt == TRUE)
        bt = 1'b1;
    if (blt == FALSE)
        bt = 1'b0;        
end
disp u_dut(bt);
endmodule
【仿真结果】
# The option result is 0000000f
# ===============================
# Opt1 is 00000012 and Opt2 is 00000003!
# The option result is 00000015
# ===============================
# The option result is 00000036

可见,使用import::*的方式,可以仅将被使用到package的元素可见范围拓展到当前作用域,比使用import p1::item逐个的指定特定元素的方式更加简洁.但是注意这种方式并不是将package中的所有元素都可以导入到当前范围,而是仅限于被当前作用范围使用到的package中的元素.示例中p1的opt3在module中未被使用,所以在module中并不可见.

通过上面几个例子,在具体使用package的过程中可以总结如下例:









全部评论

相关推荐

神哥不得了:首先我就是在成都,成都的互联网格外的卷,如果是凭现在的简历的话很难找到大厂,建议再添加一个高质量的项目上去,另外专业技能的话最好是超过每一条的一半
点赞 评论 收藏
分享
2024-12-21 10:42
已编辑
江西软件职业技术大学 Java
新宿站不停:该提升学历就提升学历,菜了就多练。没事找牛马公司虐自己是吧? 谁没事说自己“经验少”,这不自己把自己塞剎鼻hr嘴里找🐴吗
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务