本节主要介绍了SystemVerilog中线程控制与相关通信的方法
线程的控制
fork……join
需要所有并行线程都结束才会继续执行fork……join_any
其中任意一个线程结束就继续执行fork……join_none
不等待子线程,直接继续执行- 在Fork/Join结构之后,加一句
wait fork
,会阻塞后续语句,直到fork出来的进程都执行完;如果加一句disable fork
,则是直接结束掉fork出来的进程,后续语句往下执行。
线程的通信
1.事件event
使用
@
操作符或者wait()
等待事件被触发使用-
>
操作符触发事件- 使用@等待某个事件发生时产生竞争的情况
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16`timescale 1ns/10fs
module event_test();
event a; //使用关键字event来声明一个事件a
initial begin
#50ns;
->a;
end
initial begin
#50ns;
@a; //第一个进程在50ns后触发了事件a,第二个进程在50ns的时候等待a,有可能等的到,有可能等不到,产生竞争
end
endmodule- 使用wait(event_a.triggered) 等待event:Systemverilog 引入了triggered()函数,用于检测某个事件是否已被触发过,包括正在触发
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29module event_test();
event a; //使用关键字event来声明一个事件a
initial begin
#50;
->a;
$display("Event a is being triggered!");
end
initial begin
#20;
wait(a.triggered); //使用wait来等待事件a,这种方式是一定可以等到a的
$display("#20 a.triggered!");
end
initial begin
#50;
wait(a.triggered); //使用wait来等待事件a,这种方式是一定可以等到a的,这是和使用@来等待的区别
$display("#50 a.triggered!");
end
initial begin
#60;
wait(a.triggered); //使用wait来等待事件a,a會被trigger一次,並且並且發生在wait之前,永遠等不到
$display("#60 a.triggered!"); //不會被打印
end
endmodule
2.旗语semaphore
使用旗语可以实现对同一资源的访问控制
旗语有三种基本操作:
- new:可以创建一个带单个或者多个钥匙的旗语
- get:可以获取一个或多个钥匙
- put:可以返回一个或多个钥匙
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24program automatic test(bus_ifc.TB bus);
semaphore sem; //创建一个旗语
initial
begin
sem = new(1); //分配一个钥匙
fork
sequencer();
sequencer();
join
end
task sequencer;
repeat($urandom()%10) @bus.cb; //等待0~9个周期
sendTrans(); //执行总线事务
endtask
task sendTrans;
sem.get(1); //获取总线钥匙
@bus.cb;
bus.cb.addr <= t.addr;
...
sem.put(1); //返回总线钥匙
endtask
endprogram
3.信箱mailbox
mailbox是一种对象,因此也需要使用new()来例化
使用
put()
可以把数据放入mailbox,使用get()
可从信箱移除数据如果信箱为满,则put()会阻塞;如果信箱为空,则get()会阻塞
maibox的存取方法put()和get()是阻塞方法,即使用时方法不一定立即返回
peek()
可以获取对信箱里数据的拷贝而不移除它mailbox只能够用作FIFO
在线程之间做数据通信或者内部数据缓存时可以考虑使用此方式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31program automatic bounded;
mailbox mbx;
initial begin
mbx=new(1); //容量为1
fork
//Producer线程
for(inti=1; i<4; i++) begin
$display("Producer: before put(%0d)", i);
mbx.put(i);
$display("Producer: after put(%0d)", i);
end
//consumer线程
repeat(3) begin
int j;
#1ns mbx.get(j);
$display("Consumer: after get(%0d)", j);
end
join
end
endprogram
//测试结果
// Producer: before put(1)
// Producer: after put(1)
// Producer: before put(2)
// Consumer: after get(1)
// Producer: after put(2)
// Producer: before put(3)
// Consumer: after get(2)
// Producer: after put(3)
// Consumer: after get(3)