SystemVerilog中的参数传递

以下均为个人理解,能力有限,如有差错还望指正。

  1. SystemVerilog中的ref、input、ouput、inout
    sv中传递值一般只有两种规则:
    ①.地址传递,函数内部修改可以改变函数调用的值。
    ②.值传递,将整片空间复制一份,函数内部修改不会改变函数调用的值。

下面具体来看下ref、input、ouput、inout这4种关键字

  • 1.1 当函数参数类型为input
    1.1.1 基本数据类型作为参数(如 int)
module test;
int num_t = 1;

function void input_t(input int num);
  $display("here is function input_t:");
  num += 1;
  $display("num = %0d", num);
endfunction

function void print_t();
  $display("here is function print_t:");
  $display("num_t = %0d", num_t);
endfunction

initial begin: test_input
  print_t();
  input_t(num_t);
  print_t();
end

endmodule

输出结果为:

here is module test:
num_t = 1
here is function input_t:
num = 2
here is module test:
num_t = 1

1.1.2 类作为参数

module test;

class packet;
  int num_p;
  function void print_p();
    $display("here is class packet, function print_p:");
    $display("num_p = %0d", num_p);
    print_point(this);
  endfunction
endclass

function void input_t(input packet pc);
  $display("here is function input_t:");
  pc.num_p = 1;
  $display("pc.num_p = %0d", pc.num_p);
  print_point(pc);
endfunction

function void print_point(input packet pc);
  $display("here is function print_point:");
  $display("pc = %0d", pc);
endfunction

initial begin: test_input
  packet p = new();
  p.print_p();
  input_t(p);
  p.print_p();
end
endmodule

输出结果为:

here is class packet, function print_p:
num_p = 0
here is function print_point:
pc = 46912654205056
here is function input_t:
pc.num_p = 1
here is function print_point:
pc = 46912654205056
here is class packet, function print_p:
num_p = 1
here is function print_point:
pc = 46912654205056

1.1.3结论:
①基本数据类型作为参数类型(如 int)
函数调用之前,内存里只有变量num_t的空间;
函数调用之后,会将num_t拷贝一份到函数内部的变量num,函数内部使用的是num的地址空间;
函数返回之后,函数内部num的地址空间被释放,所以函数外部的num_t并没有被修改。
input是标准的值传递。
②类作为参数类型
函数调用时进行句柄的传递,本质上传递的是句柄指向的对象,可以认为在函数开头就进行句柄的传递。也可以理解为调用函数input_t时,执行了packet pc = p。函数外部和函数内部的句柄指向同一个对象,即函数内部的packet句柄指向的对象地址空间和函数外部的packet类指向的对象地址空间是同一个。假如我们在调用input_t(p)之前,没有对p分配对象空间(即没有执行new),此时是空句柄,当执行到input_t函数的赋值语句时,pc.num_p = 1,会报空句柄的错误。

  • 1.2 当函数参数类型为output
    1.2.1 基本数据类型作为参数(如 int)
module test;
int num_t = 1;

function void output_t(input int num);
  $display("here is function output_t:");
  num = 2;
  $display("num = %0d", num);
endfunction

function void print_t();
  $display("here is function print_t:");
  $display("num_t = %0d", num_t);
endfunction

initial begin: test_input
  print_t();
  output_t(num_t);
  print_t();
end
endmodule

输出结果为:

here is module test:
num_t = 1
here is function output_t:
num = 2
here is module test:
num_t = 2

1.2.2 类作为参数

module test;

class packet;
  int num_p;
  function void print_p();
    $display("here is class packet, function print_p:");
    $display("num_p = %0d", num_p);
    print_point(this);
  endfunction
endclass

function void output_t(input packet pc);
  $display("here is function input_t:");
  pc.num_p = 1;
  $display("pc.num_p = %0d", pc.num_p);
  print_point(pc);
endfunction

function void print_point(input packet pc);
  $display("here is function print_point:");
  $display("pc = %0d", pc);
endfunction

initial begin: test_output
  packet p = new();
  p.print_p();
  output_t(p);
  p.print_p();
end
endmodule

输出结果为:

here is class packet, function print_p:
num_p = 0
here is function print_point:
pc = 46912654205056
here is function output_t:
pc.num_p = 1
here is function print_point:
pc = 46912654205056
here is class packet, function print_p:
num_p = 1
here is function print_point:
pc = 46912654205056

1.2.3 结论:
①基本数据类型作为参数类型(如 int)
函数调用之前,内存里只有num_t的空间;
函数调用之后,会新建一个变量num,函数内部使用的是num的地址空间,赋值后,修改的是num这个地址空间;
函数返回之后,会将num_t指向函数内部的num的地址空间,而原来的num_t空间会被释放掉,所以函数外部的num_t的值被修改了。
output是地址传递,并且是函数传递了新地址给外部变量。
②类作为参数类型
函数调用时进行句柄的传递,本质上传递的是句柄指向的对象,可以认为在函数开头就进行句柄的传递。也可以理解为调用函数output_t时,执行了packet pc = p。看输出结果是执行函数开始时,句柄指向的对象空间进行了传递,而非在函数执行的最后进行传递。这点可能比较让人容易混淆。和Verilog也不太一样:“在子程序的开头把input和inout的值复制给本地变量,在子程序退出时则复制output和inout的值。”

  • 1.3 当函数参数类型为ref
    1.3.1 基本数据类型作为参数(如 int)
module test;
int num_t = 1;

function void ref_t(ref int num);
  $display("here is function ref_t:");
  num += 1;
  $display("num = %0d", num);
endfunction

function void print_t();
  $display("here is function print_t:");
  $display("num_t = %0d", num_t);
endfunction

initial begin: test_input
  print_t();
  ref_t(num_t);
  print_t();
end
endmodule

输出结果为:

here is module test:
num_t = 1
here is function ref_t:
num = 2
here is module test:
num_t = 2

1.3.2 类作为参数

module test;

class packet;
  int num_p;
  function void print_p();
    $display("here is class packet, function print_p:");
    $display("num_p = %0d", num_p);
    print_point(this);
  endfunction
endclass

function void ref_t(ref packet pc);
  $display("here is function ref_t:");
  pc.num_p = 1;
  $display("pc.num_p = %0d", pc.num_p);
  print_point(pc);
endfunction

function void print_point(input packet pc);
  $display("here is function print_point:");
  $display("pc = %0d", pc);
endfunction

initial begin: test_output
  packet p = new();
  p.print_p();
  ref_t(p);
  p.print_p();
end
endmodule

输出结果为:

here is class packet, function print_p:
num_p = 0
here is function print_point:
pc = 46912654205056
here is function output_t:
pc.num_p = 1
here is function print_point:
pc = 46912654205056
here is class packet, function print_p:
num_p = 1
here is function print_point:
pc = 46912654205056

1.3.3 结论:
①基本数据类型作为参数类型(如 int)
函数调用之前,内存里只有num_t的空间;
函数调用之后,会将num指向num_t所在的空间,函数内部使用的是num和num_t指向的同一个空间,函数修改的是同一个空间的数值;
函数返回之后,num_t被修改。
ref是地址传递。
②类作为参数类型
函数调用时进行句柄的传递,本质上传递的是句柄指向的对象,可以认为在函数开头就进行句柄的传递。

  • 1.4 当函数参数类型为inout
    1.4.1 基本数据类型作为参数(如 int)
module test;
int num_t = 1;

function void inout_t(inout int num);
  $display("here is function inout_t:");
  num += 1;
  $display("num = %0d", num);
endfunction

function void print_t();
  $display("here is function print_t:");
  $display("num_t = %0d", num_t);
endfunction

initial begin: test_input
  print_t();
  inout_t(num_t);
  print_t();
end
endmodule

输出结果为:

here is module test:
num_t = 1
here is function inout_t:
num = 2
here is module test:
num_t = 2

1.4.2 类作为参数

module test;

class packet;
  int num_p;
  function void print_p();
    $display("here is class packet, function print_p:");
    $display("num_p = %0d", num_p);
    print_point(this);
  endfunction
endclass

function void inout_t(inout packet pc);
  $display("here is function inout_t:");
  pc.num_p = 1;
  $display("pc.num_p = %0d", pc.num_p);
  print_point(pc);
endfunction

function void print_point(input packet pc);
  $display("here is function print_point:");
  $display("pc = %0d", pc);
endfunction

initial begin: test_output
  packet p = new();
  p.print_p();
  inout_t(p);
  p.print_p();
end
endmodule

输出结果为:

here is class packet, function print_p:
num_p = 0
here is function print_point:
pc = 46912654205056
here is function output_t:
pc.num_p = 1
here is function print_point:
pc = 46912654205056
here is class packet, function print_p:
num_p = 1
here is function print_point:
pc = 46912654205056

1.4.3 结论:
①基本数据类型作为参数类型(如 int)
函数调用之前,内存里只有num_t的空间;
函数调用时,函数内部会新建一个num的空间,并将num_t的值传递给函数内部的num,函数内部使用的是num的空间;
函数返回时,函数会将内部num的值传递给外部num_t,故外部num_t的值发生改变
函数返回之后,num_t的值被修改。
inout是值传递,并且是函数调用时和函数返回时发生了2次值传递。
②类作为参数类型
函数调用时进行句柄的传递,本质上传递的是句柄指向的对象,可以认为在函数开头就进行句柄的传递。

  • 1.5 解释
    在SystemVerilog中:
    1.5.1 如果是基本数变量作为函数参数,input只是把变量传递进函数内部,函数外部变量不受影响;output是地址传递,并且是把函数内部的变量地址传递给了给外部变量;ref是标准的地址传递;inout是值传递,并且是在函数开头时和函数结束时发生了2次值传递。
    1.5.2 如果是类句柄作为函数参数,根据测试来看,input、output、ref、inout类型本质上传递的是对象空间地址,并且均在函数开头是进行传递。

  • 1.6 参考
    https://blog.csdn.net/qq_41467882/article/details/121684326

posted @ 2024-05-06 10:51  李黑黑  阅读(449)  评论(0)    收藏  举报