文章目录 一、mgdmy、fork..join类型2.1 fork..join2.2 fork...join_any来同步线程2.3 fork...join_none来产生线程 三、线程通信3.1event事件3.2mailbox3.3 semaphore旗语
一、简介
要了解什么是线程之前,我们要了解什么叫进程。进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。线程是指进程中的一个执行流程,一个进程中可以运行多个线程。
在实际硬件中,时序逻辑通过触发器和时钟来激活,组合逻辑通过输入变化而变化。在Verilog中也是通过initial和always、连续赋值语句等进行模拟。但是对于我们的验证环境来说,我们会使用许多并发执行的线程,这要求sv能够控制和不断选择下一个要运行的线程。
二、fork…join类型 2.1 fork…join必须等内部所有语句执行完成才能继续块内后续的线程。
module test();initial begin $display("%t : AAAA",$time); #10 $display("%t : BBBB",$time); fork $display("%t : CCCC",%time); #50 $display("%t :DDDD",$time); #10 $display("%t :EEEE",$time); begin #30 $display("%t :FFFF",$time); #10 $display("%t :GGGG",$time); end join $display("%t:HHHH",$time); #80 $display("%t :IIII",$time); endendmodule
代码说明:
对块内语句进行调度,当第一个语句完成后,父线继续执行
module test();initial begin $display("%t : AAAA",$time); #10 $display("%t : BBBB",$time); fork $display("%t : CCCC",%time); #50 $display("%t :DDDD",$time); #10 $display("%t :EEEE",$time); begin #30 $display("%t :FFFF",$time); #10 $display("%t :GGGG",$time); end join_any $display("%t:HHHH",$time); #80 $display("%t :IIII",$time); endendmodule
注意:
在调度其块内语句时,父线继续执行。
module test();initial begin $display("%t : AAAA",$time); #10 $display("%t : BBBB",$time); fork $display("%t : CCCC",%time); #50 $display("%t :DDDD",$time); #10 $display("%t :EEEE",$time); begin #30 $display("%t :FFFF",$time); #10 $display("%t :GGGG",$time); end join_none $display("%t:HHHH",$time); #80 $display("%t :IIII",$time); endendmodule注意:线程H先于fork里面的语句执行
@和wait的qu区别
解释
写的挺好的IPC 3.2mailbox
可以这么理解:virtual interface 是TB和dut之间连接,然后mailbox是类之间的连接。官方的说法是mailbox是进程之间交换消息的机制,数据可以通过一个进程发送到mailbox,然后由另一个进程获取。其中数据可以是任何有效的systemVerilog数据类型。
Methoddescriptionnew()creat a mailboxput()place a message in a mailboxtry_put()try to place a message in a mailbox without blockingget()/peek()retrieve a message from a mailboxnum()returns the number of messages in the mailboxtry_get()/try_peek()try to retrieve a message from a mailbox without blockingmailbox分类
有界邮箱(bounded mailbox):邮箱的大小是指定的,如果邮箱满了,那么对邮箱的写入操作就会被挂起,直到邮箱再次有空间;无界邮箱:没有大小限制;根据存放数据类型划分:通用型:可以放任何数据类型,mailbox mailbox_name;;参数型:可以存放指定数据类型mailbox#(type) mailbox_name;; class transcation;rand bit valid;rand bit [7:0]data;endclassclass generator;mailbox #(transcation) gen2drv;transcation tr;function new(input mailbox #(transcation)gen2drv); this.gen2drv = gen2drv;endfunctiontask gen(input int num); for(int i = 1;i < num;i++)begin tr = new(); assert(tr.randomize) gen2drv.put(tr); $display("trans valid = %d",tr.valid); $display("trans data = %d",tr.data); #1ns; endendtaskendclassclass driver;mailbox #(transcation)gen2drv;transcation tr;function new(input mailbox #(transcation) gen2drv); this.gen2drv = gen2drv;endfunctiontask run;tr = new();while(1)begin gen2drv.get(tr); $display("trans valid = %d",tr.valid); $display("trans data = %d",tr.data);endendtaskendclassprogram test;mailbox #(transcation) gen2drv;driver drv;generator gen;initial begin gen2drv = new(); drv = new(gen2drv); gen = new(gen2drv); fork gen.gen(5); drv.run; join_any end endprogram
di
generator是不断的产生新的tr然后放到mailbox里面,然后driver去取mailbox的值。在top_tb里面是先定义不同类的句柄,然后传递mailbox进去,之后在每个类构造中都放进去mailbox。最后在进行task。 3.3 semaphore旗语设想一下,家里只有一台车,然后车也只有一把钥匙。如果家里人都会开车,那么假如爸爸出门要上班开车,并且把这把钥匙取走后,妈妈假如出门买菜,只能等爸爸把车钥匙换回来才能出门买菜。semaphore也是,semaphore主要用于对共享资源进行管理,通常共享资源在不同的进程中使互斥使用的,在内存中创建semaphore时,类似于创建了一个篮子(bucket),篮子中包含了一定数量的钥匙(keys),要获取共享的资源,必须从篮子中获取一把或多把钥匙,在获取完资源后必须将钥匙放回到篮子中;如果此时另一个线程试图获取篮子中的资源,必须等到桶中有足够多的钥匙的时候才能进行,否则会一直阻塞在这里.。
Methoddescriptionnew()creat a semaphore with a specified number of keysget()obtain one or more keys from the bucketput()obtain one or more keys from the buckettry_get()try to obtain one or more keys without blockingclass bridge;semaphore key;function new(); this.key = new(1);endfunctiontask go_on(string name); $display("@%0t : %s wants to go trough the bridge",$time,name); key.get(); #1ns; $display("@%0t : %s gets permission to go trough the bridge",$time,name); #10ns;endtasktask go_off(string name); $display("@%0t : %s wants to go off the bridge",$time,name); key.put(); #1ns; $display("@%0t : %s return the key",$time,name);endtaskendclassmodule top_tb;bridge brg;string name1 = "xhdnp";string name2 = "Bob";string name3 = "Calvin";string name4 = "kldwl";initial beginbrg = new();fork begin brg.go_on(name1); brg.go_off(name1);end begin brg.go_on(name2); brg.go_off(name2);end begin brg.go_on(name3); brg.go_off(name3);end begin brg.go_on(name4); brg.go_off(name4);endjoinendendmodule