任务Task和函数Function

类似于c语言中的函数

Task

  • task 含有input\output\inout语句
  • task消耗仿真时间

task中可以写延迟:#20 延迟20个仿真时间单位
时钟周期 @(posedge Clk) 等待下一个时钟周期上升沿
事件 @event 等待某一个事件被触发

task task_name;
  begin
    paramters
    input
    output
    reg
    ...
  end
endtask

function

  • function是不消耗仿真时间的,其中没有等待和延迟
  • function中不能有控制仿真时间的语句:@和#
  • function是不能调用task的,因为function不能控制时间
  • void function空函数,没有返回值
function [range] function_name;
  begin
    parameters;    //range范围表示function返回值的
    input;
    reg;
  end
endfunction
  • SV中task和function中不需要使用begin end
task reset();
  reset_l = 1'b0;
  #100
  reset_l = 1'b1; // 电平什么时候拉高和什么时候拉低需要有时间单位
endtask

function add2(int n);
  n+2;
endfunction

传递参数

通过名字传递参数

  • verilog通过形式参数的名字传递参数,减少错误
  • 参数的顺序不受限制
  • 传递参数的语法与verilog端口连接的方式相同
functon int divide(input int numerator,denominator);
  if(denominator == 0) begin
    return 0;
  end
  else 
    return numerator/denominator;
endfunction

always_ff@(posedge Clk) begin
  result <= divide(b,a);  //传递参数的顺序与定义的参数顺序相同
end
  • 这种传递参数的方式,如果参数校多,就会分不清楚实参和形参的对应关系
  • 采用 .形参名(实参) 的形式进行传参
always_ff @(posedge Clk)
  result <= divide(.denominator(b),.numerator(a));  
  • 这种传递参数的方式可以与定义参数的顺序不同

形式参数的默认方向和类型

  • 每个形式参数可以给一个默认值
  • 调用task和function时不传递参数就会使用默认值
function int increment(int count=0,step=1);
  increment = count+step;
 endfunction

always_ff @(posedge clock)
  result = increment(data_bus);//只传入一个参数,第二个使用默认参数

参数的传递方式

常见任务task和函数function传递参数值的方法时复制,传递参数的时候,是将实参复制一份传递给形参,两者指向不同内存存储的变量,函数体内进行操作的时候,不会影响原有的实参

  • 参数传递默认情况下跟左侧的参数类型保持一致
function int increment(int count=0,step=1);  //step的数据类型与count一致都是int,默认与左边一致
  • input-- 默认情况下,在开始的时候复制实参给形参
  • output--结束的时候,将输出的值复制一份给返回位置
  • inout--开始输入的时候,在结束时输出,一份复制的数值

task和function阻塞情况

  • task是没有返回值的
  • function会将执行结果返回到调用位置
// 使用递归的方式计算n的阶乘
task print_sum(integer a[],input start=0);
  automatic int sum = 0;
  for(int j = start;j<a.size();j++)
    sum += a[j];
  $display("sum of the array is %0d",sum);//%0d的意思是将变量的数值,以前面不含0的十进制数的形式打印
endtask

print_sum(my_array)
function int factorial(int n);
  int share_value = 0;
  if(n=2) return (1);
  else return (n*factorial(n-1));
endfunction
Result = factorial(my_value)
  • Task消耗时间,可以阻塞
  • Functions不能阻塞

参数传递是具有粘连性的

输入参数的数据类型与左边的保持一致

Verilog系统函数

系统函数都是以$符号开头的

  1. $random
    可以使用$random或者使用$random(seed)
int a;
initial begin
    a = $random(20);//随机种子默认值为0,可以更改为别的数
    $display("a = %d",a)
end
  • $urandom()产生32bit的无符号数
int a;
initial begin
    a = $urandom(20);// a定义的int是有符号数,虽然随机数产生的是无符号数,但是赋值之后a仍然为有符号数
    $display("a = %d",a)
end

$urandom_range(min,max) 产生一定范围内的无符号随机数

代码的生命周期

代码是有生命周期的

function int adder;
  int a;    // 函数内部定义的a 和在module定义的a所占用的内存空间是不同的,函数执行结束后会自动销毁
  a = a+1;  
endfunction

int a;
initial begin
  a = adder();
  $display("a = %d",a);
end
  • 当遇到endfunction,endtask,return的时候,会结束task和function,销毁其中的变量
  • 循环语句遇到end或者break的时候,结束循环