SV-- event(二)

本文探讨了Verilog中的线程间通信,重点讲解了event和triggered()的概念,以及如何使用它们确保线程间的同步和数据交换。通过实例展示了事件触发和电平敏感等待在控制线程协调中的作用,以及如何用event解决汽车启动与移动的同步问题。
摘要由CSDN通过智能技术生成

2线程间的通信

2.1概述

•    测试平台中的所有线程都需要同步并交换数据。

•    一个线程需要等待另一个。

•    多个线程可能同时访问同一个资源。

•    线程之间可能需要交换数据。
•    所有这些数据交换和同步称之为线程间的通信(IPC, Interprocess Communication)。

2.2 event 

 Verilog中,一个线程总要等待一个带@操作符的事件,这个操作符是边沿触发的,所以它总是阻塞的、等待事件的发生。

其它线程可以通过->操作符来触发事件,结束对第一个线程的阻塞。

event el, e2; 
initial begin
$display("@%0t: 1: before trigger", $time); 
-> el; //触发事件e1
@  e2;  //等待事件e2 
$display("@%0t: 1: after trigger", $time);
end 
initial begin
$display ("@%0t: 2: before trigger", $time);
-> e2; //触发事件e2
@  el; //等待事件e1
$display ("@%0t: 2: after trigger", $time); 
end

代码结果:

@0: 1: before trigger  //第一个初始化块启动, 触发e1事件, 然后阻塞在e2上。

@0: 2: before trigger  //第二个初始化块启动, 触发e2事件, 然后阻塞在e1上。

@0: 1: after trigger   

//el和e2在同—个时刻被触发, 但由于delta cycle的时间差使得两个初始化块可能同时无法等到el或者e2。

所以, 更安全的方式可以使用event的方法triggered() 。

 triggered()应用:

event el, e2; 
initial begin
$display("@%0t: 1: before trigger", $time); 
-> el; //触发事件e1
wait(e2. triggered());  //等待事件e2 
$display("@%0t: 1: after trigger", $time);
end 
initial begin
$display ("@%0t: 2: before trigger", $time);
-> e2; //触发事件e2
wait(e1. triggered()); //等待事件e1
$display ("@%0t: 2: after trigger", $time); 
end

@0: 1: before trigger

@0: 2: before trigger

@0: 1: after trigger

@0: 2: after trigger 

可以使用电平敏感的wait(e1, triggered ())来替代边沿敏感的阻塞语句@e1。

如果事件在当前时刻已经被触发, 则不会引起阻塞。 否则, 会一直等到事件被触发为止。

这个方法比起@而言, 更有能力保证, 只要event被触发过, 就可以防止引起阻塞。

实例 

不同的线程之间,有时会相互告知需求,比如,我们要开一辆车,在踩油门行驶之前,首先要看看汽车有没有发动,设计代码如下:

class car;
bit start=0;
task launch();
start = 1;
$display("car is launched");
endtask

task move();
wait(start=1);
$display("car is moving");
endtask

task drive();
  fork
    this.launch();
	this.move();
  join
endtask
endclass

module road;
initial begin
automatic car byd =new();
byd.drive();
end
endmodule

代码结果:

# car is launched 
 # car is moving 

我们发现,car::drive()同时启动线程car::move和car::launch,然而car::move是通过wait语句完成线程launch通知线程move

见上述代码改成event触发也可以实现一样的功能。

class car;
event start_e;
task launch();
->start_e;
$display("car is launched");
endtask

task move();
wait(start_e.triggered);
$display("car is moved");
endtask

task drive();
  fork
    this.launch();
	this.move();
  join
endtask
endclass

module road;
initial begin
automatic car byd =new();
byd.drive();
end
endmodule

 汽车要加速的时候,速度仪表信息又是如何显示的呢?
 

class car;
event e_start; 
event e_speedup; 
int speed= O;

...

task speedup() ;
# 10ns;
-> e_speedup; 
endtask 

task display() ;
forever begin
@ e_speedup; 
speed++; 
$display("speed is %0d", speed);
end 
endtask

task drive() ;
fork
this.launch(); 
this.move(); 
this.display() ; 
join_none 
endtask 
endclass

module road; 
initial begin 
automatic car byd = new(); 
byd.drive(); 
byd.speedup(); 
byd.speedup(); 
byd.speedup();  

从这个汽车加速的例子来看,如果你要一直踩着油门不放的话,这个加速的event必定会被不断触发,而当线程A要给线程B传递超过一次的事件时,利用公共变量就不再是个好的选择。

上边的例子依然可以通过event触发,来多次通知另外一个线程。注意,对于线程多次通知的需求,应该使用“@”,而无法使用wait(event,triggered()),这是由于,当一个event被触发时,它的状态会使得event.triggered一直保持true,不过,event没有方法可以清除event.triggered的状态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

创芯人

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

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

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

打赏作者

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

抵扣说明:

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

余额充值