01
线程控制
1.概述
线程,即独立运行的程序;
线程需要被触发执行,可以结束或者不结束;
在module中的initial和always,都可以看作独立的线程,他们在仿真0时刻开始,而选择结束或者不结束;
在硬件模块中都是always语句块,所以可以看成是独立运行的线程,而且会一直占用仿真资源,因为他们不会结束;
验证环境需要initial语句块,在仿真过程中,验证环境中的对象可以创建和销毁,故验证环境的资源是动态的;
验证环境中的initial语句块有两种方式:begin……end或者fork……join;
Begin……end中语句顺序执行,而fork……join中语句并发执行;
与fork……join类似的并行语句有fork……join_any、fork……join_none;
线程的执行轨迹是呈树状结构,即任何线程都应该有父线程;
父线程可以开辟若干子线程,父线程可以暂停或者终止子线程;
当子线程终止时,父线程可以继续执行;
当父线程终止时,其子线程都终止执行;
2.并行线程
fork……join需要所有并行线程都结束才会继续执行;
fork……join_any其中任意一个线程结束就继续执行;
fork……join_none不等待子线程,直接继续执行;
注意:
Fork……join_any和fork……join_none继续执行后,其一些未完成的子线程仍将继续在后台执行;
如果要等待或者停止这些子线程,可使用wait fork 或者disable fork;
task do_test; fork …… join_any fork …… join_none wait fork;//等待所有子线程结束endtask
task get_first(output ubt adr); fork …… join_any disable fork;endtask
3.时序控制
SV可以通过延迟控制或者事件(event)等待来完成时序控制;
延迟控制即通过#来完成;
#100 clk2=clk1;
事件(event)控制即通过@来完成;
@a clk1=clk2; //等待事件
@(posedge clk)a=b;//边沿触发
Wait语句可以与事件或者表达式结合使用;
Real AOR[];
Initial wait(AOR,size()>0) //wait语句完成电平触发
02
线程同步
1.概述
测试平台所有线程都需要同步并进行交换数据;
一个线程等待另一个线程;
2.事件event
通过event声明一个event变量,并且触发;
event变量可以由一端去触发,再由另一端完成阻塞式的等待,即可以用来控制多个线程之间的同步;
通过->来触发事件;
其他等待该事件的线程可以通过@操作符或者wait()来检查事件触发状态来完成等待事件;
event done,blast; //声明两个独立的事件event done_too=done; //事件done赋值给done_tootask trigger(event ev); ->ev; //触发ev事件endtask……fork @done_too; //等待done_too #1 trigger(done); //触发done事件joinfork ->blast; //触发blast事件 wait(blast.triggered); //电平触发等待join
wait_order() 可使得线程保持等待,直到在参数列表中的事件event按照顺序从左往右依次完成;
wait_order(a,b,c);
3.旗语(semaphore)
旗语是一个互斥体,使用旗语可以实现对同一资源的访问控制;
在创建旗语时,会为其分配固定的钥匙数量;
使用旗语的进程必须先获得钥匙,才可访问资源;
旗语的钥匙数量可以有多个,等待旗语的进程也可以有多个;
旗语的等待队列是先进先出(FIFO),即先排队等待旗语的将优先得到钥匙;
旗语操作
创建旗语
semaphore sm;//创建一个旗语
sm=new(1); //分配一个钥匙
创建一个固定钥匙数量的旗语:new
从旗语获取一个或多个钥匙(阻塞型):get
返回一个或多个钥匙:put
获取一个或多个钥匙而不被阻塞:try_get
task send; sem.get(1) ///获取钥匙 …… sem.put(1); //处理完成时把钥匙返回endtask
03
线程通信
1.信箱
用于收发信息,SV中信箱可以存放任何数据类型,也可以从信箱中读取这些数据,
创建信箱:new()
将信息写入信箱:put()
写入信箱但不会阻塞:try_put()
获取信息:get() 获取信息并取出数据:
peek()获取信息不会取出数据
从信箱获取数据但不会阻塞:try_get()/try_peek()
获取信箱信息数目:num()
2.信箱和队列区别
信箱必须通过new()例化,队列只需要声明
信箱的存取方法put()和get()是阻塞方法,不一定会立即返回;队列的存取方法push_back和pop_front()是非阻塞方法,会立即返回;
传递形式参数时,如果是input方向,则信箱类型传递的是句柄,队列类型完成的是队列内容的拷贝;
3.总结
event:最小信息量的触发,即单一的通知单元,用来做事件的触发,也可多个事件组合起来作线程之间的同步;
semaphore:共享资源安全,用于多线程间需要对某一公共资源做访问;
mailbpx:SV类似FIFO,在线程之间做数据通信或者内部数据缓存;
END
往期相关(?猛戳可查看)
SystemVerilog
SystemVerilog两态数据类型
SystemVerilog自定义、枚举、结构体类型
SystemVerilog数组操作
SystemVerilog数组类型
SystemVerilog函数和任务
SystemVerilog覆盖率
$display("点个在看吧!")