SystemVerilog Functions

SystemVerilog函数具有与Verilog中相同的特征。

Functions

函数的主要目的是返回一个可以在表达式中使用且不会消耗仿真时间的值。
【1】函数不能使用@、#、fork join或wait等时间控制语句;
【2】函数不能启动任务,允许任务消耗模拟时间;

ANSI-C style declaration

module tb;
 
    // 有两种方法可以调用该函数:
    initial begin
      // 1. 调用函数并将值赋值给变量,然后使用变量
      int s = sum(3, 4);
      $display ("sum(3,4) = %0d", s);
 
      // 2. 调用函数并直接使用返回的值
      $display ("sum(5,9) = %0d", sum(5,9));
 
      $display ("mul(3,1) = %0d", mul(3,1));
    end
 
    // 该函数返回类型为“ byte”的值,并接受两个参数“ x”和“ y”。与函数同名的返回变量被隐式声明,因此可以直接赋值“ sum”,而不必声明单独的返回变量
  function byte sum (int x, int y);
    sum = x + y;
  endfunction
 
    // Instead of assigning to "mul", the computed value can be returned
    // using "return" keyword
    function byte mul (int x, y);
        return x * y;
    endfunction
endmodule
 
Simulation Log
ncsim> run
sum(3,4) = 7
sum(5,9) = 14
mul(3,1) = 3
ncsim: *W,RNQUIE: Simulation is complete.

使用声明和指示

尽管后来在Verilog中引入了ANSI-C样式声明,但是端口方向的旧样式声明仍然有效。 SystemVerilog函数可以将参数声明为输入和输出端口,如下例所示。

module tb;
  initial begin
        int res, s;
        s = sum(5,9);
      $display ("s = %0d", sum(5,9));
        $display ("sum(5,9) = %0d", sum(5,9));
        $display ("mul(3,1) = %0d", mul(3,1,res));
        $display ("res = %0d", res);
    end
 
  // 函数具有8位返回值,并接受两个输入,并通过其输出端口和返回val提供结果
    function bit [7:0] sum;
        input int x, y;
        output sum;
    sum = x + y;
  endfunction
 
    // 与上面相同,但是端口是内联的
    function byte mul (input int x, y, output int res);
      res = x*y + 1;
      return x * y;
    endfunction
endmodule  
 
Simulation Log
ncsim> run
s = 14
sum(5,9) = 14
mul(3,1) = 3
res = 4
ncsim: *W,RNQUIE: Simulation is complete.

如何通过值传递参数?

按值传递是将参数传递给子例程的默认机制。 每个自变量都将复制到子例程区域中,并且在子例程外部看不到对该子例程区域中的此局部变量所做的任何更改。

module tb;
 
  initial begin
    int a, res;
 
    // 1. 让我们从1到10中选择一个随机值,并将其分配给“ a”
    a = $urandom_range(1, 10);
 
    $display ("Before calling fn: a=%0d res=%0d", a, res);
 
    // 通过“按值传递”调用函数,这是默认模式
    res = fn(a);
 
    // 即使在函数内部更改了a的值,也不会在此处反映出来
    $display ("After calling fn: a=%0d res=%0d", a, res);
  end
 
  // 此函数在“按值传递”模式下接受参数,因此会将它获取的所有参数复制到称为“ a”的局部变量中。
  function int fn(int a);
 
    //对该局部变量的任何更改都不会反映在初始块中上面声明的主变量中
    a = a + 5;
 
    // 返回某个计算值
    return a * 10;
  endfunction
 
endmodule

从下面显示的日志中请注意,即使在函数内部定义的局部变量分配了不同的值,初始块内的a的值也未更改。

ncsim> run
Before calling fn: a=2 res=0
After calling fn: a=2 res=70
ncsim: *W,RNQUIE: Simulation is complete.

如何通过引用传递参数?

通过引用传递的参数不会复制到子例程区域中,而是将对原始参数的引用传递给子例程。 参数声明之前带有ref关键字。 对子例程内部变量的任何更改将反映在子例程外部的原始变量中。

  // 使用“ ref”使该函数通过引用接受参数
  // Also make the function automatic
  function automatic int fn(ref int a);
 
    // 对该局部变量的任何更改将反映在初始块中声明的主变量中
    a = a + 5;
 
    // Return some computed value
    return a * 10;
  endfunction
Simulation Log
ncsim> run
Before calling fn: a=2 res=0
After calling fn: a=7 res=70
ncsim: *W,RNQUIE: Simulation is complete.

参考文献:
【1】https://www.chipverify.com/systemverilog/systemverilog-functions

发布了124 篇原创文章 · 获赞 8 · 访问量 6712

猜你喜欢

转载自blog.csdn.net/qq_43042339/article/details/104467297