SV基础:task和function

概述

 类似于C语言,函数(function)和任务(task)可以提高代码的复用性和整洁度。

它们的目的都在于将大型的过程块切分为更细小的片段,而便于阅读代码维护

函数与任务之间有相同点和不同点。

函数function

函数的首要目的在于为运算表达式提供返回值,这样既便于简化原有的代码,也便于大型代码的维护。

SV的函数定义与使用与C类似:

  1. 函数可以指定输入变量和输出变量
  2. 函数可以返回数值,也可以不返回数值(不返回数值用void函数)


可以声明的函数的参数方向

  1. input(默认值)
  2. output
  3. inout
  4. ref

声明参数列表方式:

1、将参数和方向在参数列表中声明
2、 将参数和方向在函数体中声明
试例:

function logic [15:0] myfunc1(int x, int y);
    ...
endfunction
 
function logic [15:0] myfunc2;
    input int x;
    input int y;
    ...
endfunction

SV的函数返回的方式      同C一致

  1. 使用return直接返回值(return会立即返回)
  2. 将值赋给与函数同名的变量(赋值给函数同名变量后将继续执行后续代码)

函数可以调用函数,但是必须立即返回。即不能发生阻塞等待的行为。  

示例:

//myfunc1,返回值经过计算,赋予了与函数同名的变量
function [15:0] myfunc1 (input [7:0] x, y) ;
    myfunc1 = x *y - 1;
endfunction
 
//myfunc2,将计算的返回值,通过return返回,并且立即退出函数
function [15:0] myfunc2 (input [7:0] x, y);
    return x *y - 1;
endfunction

 void函数

void函数不会返回数值。 

如果调用具有返回值的函数,但是又不使用该返回值时,我们建议为其添加void’()进行类型转换。【这一步骤可以消除在编译时带来的警告信息】

任务task

与函数类似,任务也有参数列表 。但是任务没有返回值。

任务的定义可以指定声明参数

  • input
  • output
  • inout
  • ref

任务声明参数方式(和函数一样) 

  1.  将参数和方向在参数列表中声明
  2.  将参数和方向在任务体中声明

示例:  

task mytask1 (output int x, input logic y);
    ...
endtask
 
task mytask2;
    output x;
    input y;
    int x;
    logic y;
    ...
endtask

任务可以消耗仿真时间。可以内置一些阻塞语句。(与函数不同)

任务可以调用其它任务或者函数。

虽然task不会返回值,但是我们依然可以利用return来使task结束。

示例: 

在任务light,需要先获取参数,再来决定需要等待多少个时钟周期,继而将clock置为off。

light内置了阻塞任务,要封装这样的操作,只能通过任务,而不是函数。

任务light,在always过程块中被调用,将其最终的结果赋值给red 

logic red;
parameter red_tics = 100;
always begin //控制灯光
    red = on; //打开红灯
    light(red,red_tics) ; //等待end
//等待‘tics’时钟上升沿的任务
//在关掉‘color’灯之前
task light (output color,input [31:0] tics) ;
    repeat (tics)@ (posedge clock);
    color = off;//关灯
endtask: light

任务和函数的区别

  1.  函数不会消耗仿真时间,而任务则可能会消耗仿真时间。(最大的区别)
  2. 函数无法调用任务,而任务可以调用函数。(函数需要立即返回,无法内置阻塞语句或者可能带有阻塞行为的任务,因此函数只能调用函数,无法调用任务。反过来,任务可以调用函数,任务也可以调用任务,因为任务是可以内置阻塞语句的)
  3. 一个函数只能返回一个数值,而任务不会返回数值。(如果一个函数具备返回值,而不是void返回类型时,函数调用后的结果可以做为一个表达式中的操作数
  4.  函数可以作为一个表达式中的操作数,而该操作数的值即函数的返回值

参数传递

参数类型 
1、 input参数

 input参数方向在方法调用时,属于值传递。

 即传递的过程中,外部变量的值会经过拷贝,赋值给输入参数。

2、output、inout 参数

与input参数类似,output、inout也会在传入或者传出的时候发生值传递的过程。

 值传递的过程只发生在方法的调用时和返回时。

3、ref参数

 与前面三个参数不同。 

 ref参数在传递时不会发生值拷贝,而是将变量指针传递到方法中,在方法内部对该参数的操作将会同时影响外部变量。

如果为了避免外部传入的ref参数会被方法修改,则可以添加const修饰符,来表示变量是只读变量。

 传递参数的方式

  1. 由参数位置在调用方法时传递参数
  2. 由参数名字映射的方式来传递参数。(SV允许类似于模块例化)

遵循参数位置传递参数 

指定参数的默认值

SV允许方法声明输入参数时指定参数的默认值。

        带有参数默认值的方法被调用时,如果这些参数没有被传递值,那么编译器将会为这些参数传入对应的默认值。

示例:  

调用read()函数,传递的参数方式有很多种。简单概括:

两个输入参数可以使用缺省值,在调用时,至少要传递 1个参数值,还应遵循三个参数前后位置进行传递。

//没有指定方向的情况下,参数都是输入方向
//为参数j 、data指定了默认值
task read(int j = 0, int k, int data = 1 );
    ...
endtask
 
read( , 5 );//等同于read ( 0,5,1 );
read ( 2,5 );//等同于read( 2,5,1 );
read( , 5,);//等同于read ( 0,5,1 );
read( , 5,7 );//等同于read( 0,5,7 );
read( 1,5,2 );//等同于read( 1,5,2 );
read ( );//错误;k没有默认值
read( 1,, 7 );//错误;k没有默认值

由参数名字映射的方式来传递参数

        SV允许类似于模块例化,可由参数位置在调用方法时传递参数,也可以由参数名字映射的方式来传递参数。

示例:  

function int fun( int j = 1,string s = "no”);
    ...
endfunction
fun( .j(2),.s("yes") ) ; //fun( 2,"yes");
fun( .s("yes") ); //fun( 1,"yes" );
fun( , "yes" );  //fun( 1,"yes" ) ;
fun( . j(2) );  //fun( 2,“no”);
fun( .s("yes"),.j(2));  // fun( 2, "yes");
fun( .s(),.j() );  // fun( 1, "no”);
fun( 2 ); //fun( 2, "no”);
fun( );  //fun


版权声明:本文为CSDN博主「桐桐花」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_41788560/article/details/124057717

猜你喜欢

转载自blog.csdn.net/Arvin_ing/article/details/127224779