task形参类型 inout 和 ref 的区别

task形参类型 inout 和 ref 的区别

原文链接 https://stackoverflow.com/q/31017629/13685812

通常来说,task或者function的形参声明为input时,input类型的形参仅仅是得到了一份拷贝

当task或者function的形参声明为output时,output类型的形参会在return的时候将此形参的拷贝复制给接收对象

而inout类型的形参,则会在被调用时得到一份拷贝,并在return的时候将形参的拷贝复制给接收对象。

==》 以上都是涉及到把形参拿过来拷贝

对于ref类型的形参,则传入的是引用,而不是一份拷贝。因此,ref类型的形参,具有更严格的数据类型要求。由于传入的是引用当task或者function对这个参数进行修改时,外部是可见的

特别注意:
对于一个需要消耗时间的task来讲,inout和ref的形参,具有很大的区别。在task运行期间,ref类型的参数,外部一直是可见,并且外部对这个引用所指向的内存空间的值的修改,task也是可见的。而对于inout类型的形参,task中仅仅是得到的一份拷贝,因此,在task运行期间,尽管这个参数对应的外部值发生变化,task中也是不可见的。当然,task中对这个值进行修改时,外部也是不可见的。当task结束时,才会将这个参数的拷贝传递给外部,这时,外部才能得到这个值

module ref_inout;

	logic [3:0] a,b;
	
	task automatic mytask(inout logic [3:0] arg1, ref logic [3:0] arg2);
		#0 $display("%m %t arg1 %h arg2 %h", $time, arg1, arg2);
		#5 $display("%m %t arg1 %h arg2 %h", $time, arg1, arg2);
		#0 arg1 = 1; arg2 = 2;				// task 中途改了,inout参数是看不到的。但是ref参数却可以实时看到。
		#5 $display("%m %t arg1 %h arg2 %h", $time, arg1, arg2);
	endtask
	
	initial begin
		#0 mytask(a,b);
	end
	
	initial begin
		a = 'z; b = 'z;
		#2
		a = 0; b = 0;
		#5 $display("%m %t arg1 %h arg2 %h", $time, a, b);
		#5 $display("%m %t arg1 %h arg2 %h", $time, a, b);
	end


endmodule 

/* 打印
//======================================================
									  inout    ref
# ref_inout.mytask                   0 arg1 z arg2 z
# ref_inout.mytask                   5 arg1 z arg2 0
# ref_inout                    		 7 arg1 0 arg2 2   --> 7ns 外部打印是看不出inout参数变化的,但是却可以实时看到ref传进去的参数变化。
# ref_inout.mytask                  10 arg1 1 arg2 2   --> inout 只有当task结束了,才可以看到其变化。
# ref_inout                   		12 arg1 1 arg2 2
//====================================================== 
*/

上例可以清楚看到inout 和 ref 的区别:

1,在0ns,启动两个initial块;初始化a b为z;

2,在0ns,调用my_task;line4打印 arg1 =z arg2 =z;

3,在1ns,对a b分别赋值为0;

4,在5ns,打印arg1 =z arg2 =0;(b的值此时为0,准确的说,在2ns时,arg2已经可见b的值0)

5,在6ns,打印a = 0,b=1;(arg2为1,对外部可见,故B为1。准确的说,在6ns时,使b已得到值1)

6,在10ns,打印arg1 =1 arg2 =1;(task退出,arg1的拷贝传递给了a)

7,在12ns,打印a = 1,b=1;(arg1为1,传递给a)

==》 可以看到,即使task的参数 中途改了,inout参数只能看到进去之前和出去之后的值。但是ref参数却可以实时看到。当task出现耗时的时候,差异特别明显。

//=================================
还有一个需要注意:
需要特别注意的一点是,如果形参是一个class类型的,那么这时候传进来的是一个句柄。也就是说,task中对这个class进行修改时,其实是在修改这个句柄所指向的对象那么外部也是看见的,这可能并不是所期望的,很容易与ref混淆,(我明明没有申明ref类型,为什么我改的task内部,却还是会影响到外部?),应当特别小心。同时需要说明,如果想要在task或者function中,对类句柄进行修改(如new一块新的内存空间),那么,应该把这个形参声明为ref。

  class reg_trans;
	xxxx;
  endclass
  
 task reg_write(input reg_trans t); //这里传进来的是input,但是下面t.data = xxx;竟然可以传出去!!! ==> 因为传进来的形参是句柄!!!注意,是句柄,你直接去修改对象里的值了。
      @(posedge intf.clk iff intf.rstn);
      case(t.cmd)
        `READ:  begin 
                  intf.drv_ck.cmd_addr <= t.addr; 
                  intf.drv_ck.cmd <= t.cmd; 
                  repeat(2) @(negedge intf.clk);	//第一个下降沿在当前拍,第2个下降沿在下一拍数据中间
                  t.data = intf.cmd_data_s2m; 		//这个是直接改t句柄指向的对象中的数值。
                end
        `IDLE:  begin 
                  this.reg_idle(); 
                end
        default: $error("command %b is illegal", t.cmd);
      endcase
      $display("%0t reg driver [%s] sent addr %2x, cmd %2b, data %8x", $time, name, t.addr, t.cmd, t.data);
    endtask

//=================================
最后,如果需要传递一个特别大的参数给task或者function,使用ref类型是一个很好的选择,可以节省内存资源。

为什么?
因为只有ref是直接引用,其他的都是拷贝后使用。

  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ethan_WC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值