SystemVerilog----任务(task)和函数(function)

目录

1.概述

2.任务和函数的区别

3.  任务和函数中的参数传递(值传递和引用传递)

4.任务函数返回值

5、program块和module模块的区别


1.概述

  • 类似于C语言,函数(function)和任务(task)可以提高代码的复用性整洁度
  • 它们的目的都在于将大型的过程块切分为更细小的片段,而便于阅读代码维护。
  • 相比于大家更为熟悉的函数,SV引入了任务的概念。function与task之间有相同点和不同点。

2.任务和函数的区别

 

函数function    任务task
执行与消耗 不会消耗仿真时间 ,不能含有控制仿真时间的语句 可能会消耗仿真时间,可以包含仿真时间控制语句,如#100,时钟周期@(),wait()以及事件event等语句
形参变量   函数中至少包含一个输入变量进行传参  任务中可以没有输入、输出变量
调用方式 function无法调用task,只能调用function 而task可以调用task,也可以调用function
返回值 一个可以返回数据的function只能返回一个单一数值 而任务或者void function不会返回数值,一般通过output信号直接输出。
返回方式 函数的返回可以通过调用return语句实现,当不需要返回值时可以将函数定义为void类型 任务没有返回值,但是也可以用return来结束task

        如果调用具有返回值的函数,但是又不使用该返回值时,我们建议为其添加void'()进行转换。
void' (some_function() ;一个可以返回数据的function可以作为一个表达式中的操作数,而该操作数的值即function的返回值。

3.  任务和函数中的参数传递(值传递和引用传递

任务的定义可以指定参数,input、output、inout及ref皆可。inout在开始的时候复制,在结束的时候输出;ref传递引用(句柄或者指针);input: 在开始的时候复制值;output:在开始的时候复制值

  •  input参数方向在方法调用时,属于值传递。即传递的过程中,外部变量的值会经过拷贝,赋值于形式参数。
  • 同样地,output、inout也会在传入或者传出的时候发生值传递的过程。
  • 值传递的过程只发生在方法的调用时和返回时。
  • ref参数在传递时不会发生值拷贝,而是将变量"指针”传递到方法中,在方法内部对该参数的操作将会同时影响外部变量。
  • 如果为了避免外部传入的ref参数会被方法修改,则可以添加const修饰符,来表示变量是只读变量。

SV中,子程序中的begin…end语句是可选的,但是在Veriliog1995中,除了单个语句外,这是必须的。在SystemVerilog中多条语句可以在task和function中使用,这些语句是顺序的执行

值传递:常见的向任务与函数传递值的方法是复制;需要关键字input、output,这种传递方式实际上是将实参内容复制到形参中,原来的实参与形参存放在不同的内存空间中。
引用传递(相当于指针):用到关键字ref(取代了原来的input/output),同时需要将任务和函数声明为automatic型。在通过引用传递的方式将实参传递给形参引用时,引用型的形参变量实际上相当于实参变量的句柄或指针,也就是变量的入口地址,两者具有相同的内存空间。

SystemVerilog通过值传递的方式来传递参数,实参将被整体复制,这将消耗一定的内存和操作时间。而使用引用传递(ref),只是获取实参的入口地址(句柄或者指针),操作速度快,减少内存的使用。除此之外,在子程序修改ref参数变量的时候,其变化对于外部是立即可见的,这一点很有用。

typedef struct{logic        valid;
               logic[7:0]   check;
               logic[63]    data;       //最后一个变量后也需加分号
              }packet_t;
              
packet_t           data_packet;         //结构体变量
logic[7:0]         raw_data[0:7];

always@(posedge clk)
  if(data_ready)
    fill_packet(.data_in(raw_data), .data_out(data_packet));


function automactic void fill_packet(ref logic[7:0]     data_in[7:0], 
                                     ref packet_t       data_out);
  for(int i=0; i<=7; i++)begin
    data_out.data[(8*i)+:8] = data_in[i];
  end
endfunction

4.任务函数返回值

SystemVerilog中可以将函数声明为void类型它没有返回值。这是相对于verilog的改进,其他函数同Verilog一样可以通过函数名赋值来返回一个值,或者使用return语句实现。

当返回值的个数为1个return返回;当返回值的个数为多个时,通过output返回各种数值;

function logic[15:0] func(input [7:0] x,y);
  return x*y-1;                   //2. 通过函数名返回
endfunction

a = func(.x(5), .y(6));      // 名字映射
a = func(5, 6);            // 位置映射

1.  函数或任务中通过return关键字返回时,为非void类型;
2.  函数或任务中通过output返回时(或无返回值),须将其定义为**void类型**

5、program块和module模块的区别

为什么在程序(program)中不能使用always块?

SV中,可以在程序中使用initial块,不能使用具有连续执行性质的always块。当程序中initial块结束时,仿真实际上也默认结束了,像执行了$finish,加了always永远不会结束,不得不用$exit结束。

SV中动态存储和静态存储的概念
automactic:自动存储(相当于局部变量)             static:静态存储(相当于全局变量)
   类class中定义的任务和函数总是自动automatic的。 自动任务中声明的所有项都为每次调用动态分配。 所有形式参数和局部变量都存储在堆栈上。

   在module、interface、program、package中定义的任务和函数默认为静态static的,所有声明的变量都是静态分配的。 如果一个程序是静态的,那么所有的子程序只能共享一个内存空间。子程序的每次执行都会覆盖之前子程序运行产生的结果。

强烈建议:将program声明为automatic类型
1. 任务定义为自动存储automatic可以采用以下两种方式:

        显式声明:使用关键字automatic作为任务和函数声明的一部分;
        隐式声明:通过将任务和函数定义在被定义为automatic类型的module, interface, program,            or package中;
2. Program的优势:

       将Testbench与DUT分开;
       program可用于执行测试案例(testcase);        —module不可
       program可用于封装与测试案例相关的数据变量;    —module不可

3. Program的功能:

       program可以在顶层文件中进行例化,以实现TB与DUT的连接;
      可以像module一样使用interface和端口进行连接;
      可以有initial、task、function代码块,但是不能存在always代码块;
      program中的initial语句块执行到结束时,隐式执行$finish语句;


参考原文链接:https://blog.csdn.net/weixin_46022434/article/details/106869354

       
  

你可能感兴趣的:(System,verilog,systemverilog,开发语言)