SystemVerilog $unit 编译单元介绍

SV $unit 编译单元

SV中增加了编译单元的概念,就是SV源文件编译的时候,一起编译的所有源文件

1. 编译单元域搜索规则

编译单元域在搜索顺序中排第三位

举个栗子

package a_dpk;  //创建一个名为a_dpk的包
    function print();
        $display("	 This is in a_dpk!");
    endfunction
endpackage

package b_dpk;  //创建一个名为b_dpk的包
    function print();
        $display("	 This is in b_dpk!");
    endfunction
endpackage

import b_dpk:: *; //导入$unit编译单元域

module test_tb;
    
    import a_dpk:: *; //通配符导入

    function print();
        $display("	 This is in module!");
    endfunction

    initial begin
        $display("	**********************");
        print;
        $display("	***********End*********");
    end
endmodule

这里我们创建了两个包(a_dpk和b_dpk),两个包中的都只有一个打印函数,同时module中也有一个打印函数,(打印函数用于指示所在位置)

打印结果如下:

SystemVerilog $unit 编译单元介绍

image-20211216201944989

从打印结果可以看出,当三者都存在时,打印的是module中声明的函数

那么如果把module中声明的函数注释掉会打印哪个函数呢?

package a_dpk;  //创建一个名为a_dpk的包
    function print();
        $display("	 This is in a_dpk!");
    endfunction
endpackage

package b_dpk;  //创建一个名为b_dpk的包
    function print();
        $display("	 This is in b_dpk!");
    endfunction
endpackage

import b_dpk:: *; //导入$unit编译单元域

module test_tb;
    
    import a_dpk:: *; //通配符导入

    //function print();
    //    $display("	 This is in module!");
    //endfunction

    initial begin
        $display("	**********************");
        print;
        $display("	***********End*********");
    end
endmodule

运行结果如下:

SystemVerilog $unit 编译单元介绍

可以看到此时打印的是在module中导入的包

那么接下来我们把在module中导入的包注释掉,即把import a_dpk::*;注释掉

package a_dpk;  //创建一个名为a_dpk的包
    function print();
        $display("	 This is in a_dpk!");
    endfunction
endpackage

package b_dpk;  //创建一个名为b_dpk的包
    function print();
        $display("	 This is in b_dpk!");
    endfunction
endpackage

import b_dpk:: *; //导入$unit编译单元域

module test_tb;
    
   // import a_dpk:: *; //通配符导入

    //function print();
    //    $display("	 This is in module!");
    //endfunction

    initial begin
        $display("	**********************");
        print;
        $display("	***********End*********");
    end
endmodule

下面运行结果:

SystemVerilog $unit 编译单元介绍

此时终于把导入$unit编译单元域的内容打印出来了

通过这个过程不难发现,在运行过程中,先从module内部找有没有声明,如果没有声明再从module内部import的包找,如果还是没有才会在module外部import的包中找

这也就是为什么 编译单元域在搜索规则中排第三

那么为什么编译单元域叫$unit呢?我们可以再把代码更改一下

package a_dpk;  //创建一个名为a_dpk的包
    function print();
        $display("	 This is in a_dpk!");
    endfunction
endpackage

//package b_dpk;  //创建一个名为b_dpk的包
//    function print();
//        $display("	 This is in b_dpk!");
//    endfunction
//endpackage

import b_dpk:: *; //导入$unit编译单元域

module test_tb;
    
   // import a_dpk:: *; //通配符导入

    //function print();
    //    $display("	 This is in module!");
    //endfunction

    initial begin
        $display("	**********************");
        print;
        $display("	***********End*********");
    end
endmodule

我们把b_dpk注释掉,但依旧将其导入,看看运行结果

SystemVerilog $unit 编译单元介绍

这里直接显示错误在 $unit,或许$unit只是一个名称,就好像上例中module命名为test_tb一样

2. 单独编译将包导入到$unit中(条件编译)

格式为:

`ifndef xxx
 `define xxx
`endif

这是C语言中常用的技巧,如果第一次遇到导入语句将其编译到$unit中,再次出现则不会编译

下面我们将上篇笔记中的包用这种方式仿真一下,先给出上篇笔记中包的内容

package definitions;
    parameter version = "1.1";
    
    typedef enum {ADD, SUB, MUL} opcodes_t;

    typedef struct {
        logic [31:0] a, b;
        opcodes_t opcode; //声明的opcode中包含 ADD, SUB和MUL
    } instruction_t;
    
    function automatic [31:0] multiplier (input [31:0] a, b);
        return a * b;
    endfunction
endpackage 

我们将文件名命名为definitions.dpk,其中后缀.dpk是随便起的

`ifndef PACK
 `define PACK
 package definitions;
        parameter version = "1.1";
        
        typedef enum {ADD, SUB, MUL} opcodes_t;
        
        typedef struct {
            logic [31:0] a, b;
            opcodes_t opcode; //声明的opcode中包含 ADD, SUB和MUL
             } instruction_t;
        
        function automatic [31:0] multiplier (input [31:0] a, b);
            return a * b;
        endfunction
    endpackage

 import definitions:: *; //将包导入到$unit中
`endif

下面是源码和测试文件

`include "definitions.dpk" //编译包文件

module ALU (
 input instruction_t IW,
    input logic clk,
    output logic [31:0] result
);
    always @ (posedge clk) 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
`include "definitions.dpk" //编译包文件

module ALUtb;
    instruction_t IW;
    logic    clk = 1;
 logic [31:0] result;
    
    always #10 clk = ~clk; //生成时钟,周期为20ns
    
    initial begin
        IW.a = 'd10;
        IW.b = 'd5;
        IW.opcode = ADD;

        repeat(2)  @(negedge clk);
         IW.a = 'd3;
         IW.b = 'd7;
         IW.opcode = MUL;
    
        repeat(2) @(negedge clk);
         IW.a = 'd5;
         IW.b = 'd1;
         IW.opcode = SUB;
        
        repeat(3) @(negedge clk);
         $finish; 
    end
    
    initial begin
        $monitor ($time, ,"a->%d, b->%d, opcode->%s, result->%d",IW.a, IW.b, IW.opcode, result);
    end

    ALU tb(.IW(IW), .result(result), .clk(clk));    //例化
endmodule

运行结果如下

SystemVerilog $unit 编译单元介绍


本文主要参考

  1. 《SystemVerilog硬件设计及建模》
  2. 人人都会用到,但是大部分人不清楚是什么的“神秘空间” (baidu.com)
展开阅读全文

页面更新:2024-05-12

标签:单元   通配符   源文件   注释   函数   声明   规则   两个   文件   笔记

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top