写在前面:欢迎您,有缘人!
1.内部线程通信
线程之间需要通信,实现对执行序列的控制
主要有三种:Event based、Resource sharing、Data passing
内部线程通信机制:Verilog event
在Verilog中,@操作符是边沿敏感的,它总是阻塞着,等待着事件的变化。其他的线程可以通过->操作符来触发事件。
Verilog event
- Verilog语言中使用 event同步线程
-
触发事件的操作符:->
◆不会阻塞线程的执行
- 等待事件被触发@
◆边沿敏感,总会阻塞线程执行
◆只有当事件发生变化时,线程才会继续执行
- 当阻塞线程之前发生触发线程时,可能引起竞争现象
内部线程通信机制:SV event
SystemVerilog引入了triggered()函数,可用于查询某个事件是否已经被触发,包括在当前时刻。线程可以等待这个函数的结果,而不用在@操作符上阻塞。
Systemverilog event
- 同步线程
- event是一个同步对象的句柄,可以当做参数传递给子程序
不需要声明为全局变量,就可以将 event作为共享资源使用
- 触发一个事件的操作符:->和->>
- 等待一个事件被触发的操作符:@和wait()
- triggered函数用于检查一个事件是否被触发过,返回值是一个状态
- wait(event.triggered)
如果在当前的仿真时间范围内,事件曾触发过,语句不会被阻塞
否则, wait(event.triggered)语包会一直等待事件被触发
2.内部线程通信机制:旗语
旗语有三种基本操作。可以将旗语看成是一把钥匙,谁拥有钥匙谁就对资源具有使用的权利。旗语可被视为一个互斥体,用于实现对同一资源的访问控制。使用new方法可以创建一个带单个或多个钥匙的旗语,使用get可以获取一个或多个钥匙,而put则可以返回一个或多个钥匙。如果你试图获取一个旗语而不希望被阻塞,可以使用try_get函数。它返回1表示有足够多的钥匙,而返回0则表示要是不够。
实例:用旗语实现对硬件资源的访问控制
//SV绿皮书
//用旗语实现对硬件资源的访问控制
program automatic test(bus_ifc.TB bus)
semaphore sem;//创建一个旗语
initial begin
sem = new(1);//分配一个钥匙
fork
sequencer();//产生两个总线事务线程
sequencer();
join
end
task sequencer;
repeat($urandom%10)//随机等待0-9个周期
@bus.cb;
sendTrans();//执行总线任务
endtask;
task sendTrans;
sem.get(1);//获取总线钥匙
@bus.cb;//把信号驱动到总线上
bus.cb,addr <=t.addr;
...
sem.put(1);//;处理完成时把钥匙返回
endtask
endprogram
如上面实例,旗语重要的几行代码如下:
semaphore sem;创建一个旗语
sem = new(1);分配一把钥匙
sem.get(1);获取一把钥匙
sem.put(1);返回一把钥匙
try_get();获得钥匙而不被阻塞,返回1表示有足够多的钥匙,返回0则表示钥匙不够
实例:semphore应用实例
//systemverilog与功能验证(钟文枫)
//源代码3-6 semaphore应用实例
//Chapter3 semaphore_example.sv
module semaphore_example();
semaphore s1=new(1);
task t1();
for(int i=0;i<3;i++) begin
s1.get(1);
#5;
$display("t1 owns semaphore");
s1.put(1);
#5;
end
endtask
task t2();
for(int i=0;i<3;i++)begin
s1.get(1);
#5;
$display("t2 owns semaphore");
s1.put(1);
#5;
end
endtask
initial begin
fork
t1();
t2();
join
end
endmodule
仿真结果:
Compiler version I-2014.03; Runtime version I-2014.03; Aug 17 13:13 2020
t1 owns semaphore
t2 owns semaphore
t1 owns semaphore
t2 owns semaphore
t1 owns semaphore
t2 owns semaphore
V C S S i m u l a t i o n R e p o r t
实例:semaphore_ex.sv
//e课网
//semaphore_ex.sv
program semaphore_ex;
semaphore semBus = new(1);
initial begin
fork
agent("Agent 0",5);
agent("AGENT 1",20);
join
end
task automatic agent(string name,integer nwait);
integer i=0;
for(i=0;i<4;i++)begin
semBus.get(1);
$display("[%0d] Lock semBus for %s",$time,name);
#(nwait);
$display("[%0d] Release semBus for %s",$time,name);
semBus.put(1);
#(nwait);
end
endtask
endprogram
仿真结果:
Compiler version I-2014.03; Runtime version I-2014.03; Aug 17 13:32 2020
[0] Lock semBus for Agent 0
[5] Release semBus for Agent 0
[5] Lock semBus for AGENT 1
[25] Release semBus for AGENT 1
[25] Lock semBus for Agent 0
[30] Release semBus for Agent 0
[35] Lock semBus for Agent 0
[40] Release semBus for Agent 0
[45] Lock semBus for AGENT 1
[65] Release semBus for AGENT 1
[65] Lock semBus for Agent 0
[70] Release semBus for Agent 0
[85] Lock semBus for AGENT 1
[105] Release semBus for AGENT 1
[125] Lock semBus for AGENT 1
[145] Release semBus for AGENT 1
$finish at simulation time 165
V C S S i m u l a t i o n R e p o r t
实例:semaphore_ex_0.sv
//e课网
//semaphore_ex_0.sv
program semaphore_ex_0;
semaphore semBus = new(1);
initial begin
fork
agent("Agent 0",5);
agent("AGENT 1",20);
join
end
task automatic agent(string name,integer nwait);
integer i=0;
for(i=0;i<4;i++)begin
//semBus.get(1);
$display("[%0d] Lock semBus for %s",$time,name);
#(nwait);
$display("[%0d] Release semBus for %s",$time,name);
//semBus.put(1);
#(nwait);
end
endtask
endprogram
仿真结果:
Compiler version I-2014.03; Runtime version I-2014.03; Aug 17 13:37 2020
[0] Lock semBus for Agent 0
[0] Lock semBus for AGENT 1
[5] Release semBus for Agent 0
[10] Lock semBus for Agent 0
[15] Release semBus for Agent 0
[20] Release semBus for AGENT 1
[20] Lock semBus for Agent 0
[25] Release semBus for Agent 0
[30] Lock semBus for Agent 0
[35] Release semBus for Agent 0
[40] Lock semBus for AGENT 1
[60] Release semBus for AGENT 1
[80] Lock semBus for AGENT 1
[100] Release semBus for AGENT 1
[120] Lock semBus for AGENT 1
[140] Release semBus for AGENT 1
$finish at simulation time 160
V C S S i m u l a t i o n R e p o r t
注意对照上面两个实例, 明显观看到:
- Semaphore通常用于对共享资源的分配和同步
- 在内存中创建 semaphore时,类似于创建一个篮子( bucket),篮子中包含一定数量的钥匙(keys)
- 进程在执行之前必须获取一个钥匙
- 当一个特定的进程需要钥匙时,只有一定数量的进程在同时运行
3.内部线程通信机制:信箱
- Mailbox是SV中不同进程间的通信方式,通过 mailbox可以在不同的进程之间传递信息
- 将一个进程中的数据,通过 mailbox传递给另外一个进程:当 mailbox中没有数据时,线程将等待
- Mailbox类似于一个FIFO,可以设置一定的深度queue size
当邮箱中的信息数量达到邮箱的深度时,邮箱为满
如果邮箱已经为满。进程就不能再往邮箱中存放信息,直到邮箱中的信息被取走,邮箱不再为满
- Mailbox是SV内建的类,提供以下方法:
创建邮箱:new()
将信息放入邮箱:put()
非阻塞性将信试着放入邮箱: try_put()
从邮箱中取出信息:get()或peek()
非阳塞性从邮箱中取出信息:try_get()或 try_peek()
获取邮箱中的信息的数量:num()
写在最后:冲冲冲