SystemVerilog中的参数传递
以下均为个人理解,能力有限,如有差错还望指正。
- 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
浙公网安备 33010602011771号