event
作为SV的关键词,表示事件,也用来同步多个并发的进程。比如:某个进程等待着事件,而另一个进程则触发这个事件。
1. event事件在线程中的通信
0. 最简单的例子:
program test;
event e1;
initial begin
$display("[%0t]Start simulation", $time);
fork
begin
$display("[%0t]Trigger the event e1", $time);
-> e1;
end
join
fork
begin
$display("[%0t]Received the event e1", $time);
@e1;
end
join
end
endprogram
仿真结果:
% vcs -R -sverilog -timescale=1ns/1ps basic_event_example.sv
[0]Start simulation
[0]Trigger the event e1
[0]Received the event e1
1. 在事件的边沿阻塞:在闪电出现的时候按下快门才有效
@和->必须同时发生。
如下面的例子:
program test;
event e1, e2;
initial begin
$display("@%0t: Thread 1: before trigger", $time);
-> e1;
@e2;
$display("@%0t: Thread 1: after trigger", $time);
end
initial begin
$display("@%0t: Thread 2: before trigger", $time);
-> e2;
@e1;
$display("@%0t: Thread 2: after trigger", $time);
end
endprogram
运行结果:
@0: Thread 1: before trigger
@0: Thread 2: before trigger
@0: Thread 1: after trigger
讲解:第一个初始化块启动,触发e1,
然后阻塞在了另一个事件上。第二个初始化块启动,触发e2,唤醒第一个块儿,然后阻塞在第一个事件上。但是因为第一个事件是一个零宽度的脉冲,所以第二个线程会因为错过第一个事件而被锁住。
1.1 补充:等待事件的触发
用电平敏感的wait(e1.triggered)来代替边沿敏感的阻塞语句@,如果时间在当前已经被触发过,则不会引起阻塞;否则还是要等到事件被触发为止。
rogram test;
event e1, e2;
initial begin
$display("[%0t]Start simulation", $time);
fork
begin
$display("[%0t]before the event e1", $time);
-> e1;
wait(e2.triggered);
$display("[%0t]after the event e1", $time);
end
join
end
initial begin
fork
begin
$display("[%0t]before the event e2", $time);
-> e2;
wait(e1.triggered);
$display("[%0t]after the event e2", $time);
end
join
end
endprogram
执行结果:
[0]Start simulation
[0]before the event e1
[0]before the event e2
[0]after the event e2
[0]after the event e1
$finish at simulation time 0
V C S S i m u l a t i o n R e p o r t
2. 传递事件:
SV中的event可以像被参数一样传递给子程序。如下:一个事件被generator用来作为其执行完毕的标识信号:
class Generator;
event done;
function new(event done);
this.done = done;
endfunction
task run();
fork
begin
// ... process
-> done;
$display("Generator triggered");
end
join_none
endtask
endclass
program automatic test;
event gen_done;
Generator gen;
initial begin
gen = new(gen_done);
gen.run();
wait(gen_done.triggered);
$display("Generator done");
end
endprogram
运行结果:
Generator triggered
Generator done
关于trigger:注意wait(event_name.triggered)中的triggered不是个方法,是属性,所以这里不能在triggered后加一对括号。
wait()括号中的参数不能是事件,即不能是wait(event_name),wait()括号中的参数需要是个表达式。
3. event可以被赋值
当一个event被赋值给其它事件,这样两个事件变量(句柄)会指向同一个同步化对象,触发任意一个变量就触发这个事件, 如下所示:
program e_event;
event event;
event tmp;
initial begin
tmp = eve;
#10 -> tmp;
end
initial begin
wait(event.triggered);
$display("@%0t : event trigger",$time);
end
endprogram
执行结果
@10 : event trigger
4. 使用wait fork等待多个线程
使用线程计数来等待多个线程
// TODO
5. Wait order
wait_order阻塞等待多个事件的触发,并且要求这多个事件按照用户决定顺序触发。wait_order可以和else一同使用,当多个事件按顺序触发时,执行wait_order后的语句,否则执行else后的语句。
module tb;
// Declare three events that can be triggered separately
event a, b, c;
// This block triggers each event one by one
initial begin
#10 -> a;
#10 -> b;
#10 -> c;
end
// This block waits until each event is triggered in the given order
initial begin
wait_order (a,b,c)
$display ("Events were executed in the correct order");
else
$display ("Events were NOT executed in the correct order !");
end
endmodule
6. 事件的合并
module tb;
// Declare three events that can be triggered separately
event a, b, c;
// This block triggers each event one by one
initial begin
#10 -> a;
#10 -> b;
#10 -> c;
end
// This block waits until each event is triggered in the given order
initial begin
wait_order (a,b,c)
$display ("Events were executed in the correct order");
else
$display ("Events were NOT executed in the correct order !");
end
endmodule
2. 旗语 semaphore
class car;
semaphore key; // declare a key
function new ();
this.key=new(1); // create one key
endfunction
task drive_car(string name);
$display("@%0t: %s wants to drive the car",$time,name);
key.get(); // get the key
#1ns;
$display("@%0t: %s gets the car key",$time,name);
#10ns;
endtask
task return_key(string name);
$display("@%0t: %s used the car",$time,name);
key.put(); // put back the key
#1ns;
$display("@%0t: %s returned the key.",$time,name);
endtask
endclass
program test;
car car_handle;
string name1="Alex";
string name2="Bob";
string name3="Calvin";
string name4="Denise";
initial begin
car_handle =new();
fork
begin
car_handle.drive_car(name1);
car_handle.return_key(name1);
end
begin
car_handle.drive_car(name2);
car_handle.return_key(name2);
end
begin
car_handle.drive_car(name3);
car_handle.return_key(name3);
end
begin
car_handle.drive_car(name4);
car_handle.return_key(name4);
end
join
end
endprogram
用VCS来执行:
vcs -R car.sv -sverilog -timescale=1ns/1ps
执行结果:
@0: Alex wants to drive the car
@0: Bob wants to drive the car
@0: Calvin wants to drive the car
@0: Denise wants to drive the car
@1000: Alex gets the car key
@11000: Alex used the car
@12000: Alex returned the key.
@12000: Bob gets the car key
@22000: Bob used the car
@23000: Bob returned the key.
@23000: Calvin gets the car key
@33000: Calvin used the car
@34000: Calvin returned the key.
@34000: Denise gets the car key
@44000: Denise used the car
@45000: Denise returned the key.