system Verilog——线程控制

什么是线程
       在SV中,可以认为 线程即独立运行的程序。 线程需要被触发,可以结束或者不结束。

举例: 

        在硬件module中的initial和always,都可以看做独立的线程,它们会在仿真0时刻开始,而选择结束或者不结束。

硬件模型的线程的特点

        硬件模型中由于都是always语句块,所以可以看成是多个独立运行的线程,而这些线程会一直占用仿真资源,因为它们并不会结束。

验证环境中线程的特点

         initial语句中例化的各个验证环境、验证对象,以及整个验证平台,可以在仿真过程中动态的创建或者销毁,因此验证环境的资源是动态的利用过程。

验证环境中的initial块有两种执行方式:

begin. ..end语句(以顺序方式执行)
fork. . .join语句(以并发方式执行)
并行方式语句有:

fork. . . join(可以开辟多个子线程,即触发多个程序的执行,这些被触发的程序可以被看做fork join语句的子线程)
fork.. . join_any
ork. . . join_none
线程的概念
        线程的执行轨迹是呈树状结构的,即任何的线程都应该有父线程。

子线程和父线程的关系:

        父线程可以开辟若干个子线程,父线程可以暂停或者终止子线程。
        当子线程终止时,父线程可以继续执行。
        当父线程终止时,其所开辟的所有子线程都应当会终止。
并行线程
Verilog中的创建线程

顺序线程begin. . .end
并行线程fork.. . join(所有并行的线程都结束以后才会继续执行接下来的程序)
SV引入了两种新的创建线程的方法:(并行线程)

fork...join_any(等到任何一个线程结束以后就继续执行接下来的程序)
fork. .. join_none(不会等待其子线程而继续执行接下来的程序)


fork join语句 

        在进入fork 以后可以触发多个子线程运行, fork join需要等待所有并行的子线程都结束以后才会继续执行。

fork...join_any

        在进入fork 以后可以触发多个子线程运行,fork...join_any等到其中一个最短的子线程结束以后就继续执行接下来的程序

 fork. .. join_none

        在进入fork 以后可以触发多个子线程运行,不会等待其子线程而继续执行接下来的程序。

注意:

          fork.. .join_any和fork.. .join_none语句不需要等待全部子线程执行结束,但是在执行  fork.. .join_any和fork.. .join_none语句的同时,之前已经被触发的子线程,依然会在后台执行,直到它们执行结束。

fork join语句的示例: 

fork
    begin
        $display( "First Block\n”);
        # 20ns;
    end
    begin
        $display ("Second Block\n”);
        @eventA;
    end
join
#fork join开辟了两个begin end子线程,这两个线程分别需要等待20ns和事件A被触发以后,才能分别结束
#从而,fork join语句块才能退出,执行下面的程序


 

initial begin
    $display ("@%0t: start fork.. .join example",$time);
    #10 $display("@%0t: sequential after #10",$time);
//fork join触发了四个子线程,需要不同的时间点完成打印操作
//最慢的时间为50ns。在fork join语句退出时,已经经历了10ns+50ns=60ns的仿真时间
//程序结束时。经历了60ns+80ns=140ns的仿真时间
    fork
        $display("@%0t: parallel start", $time) ;
        #50 $display("@%0t: parallel after #50",$time);
        #10 $display("@%Ot: parallel after #10", $time) ;
        begin
            #30 $display("@%0t: sequential after #30",$time);
            #10 $display("@%0t: sequential after #10",$time) ;
        end
    join
 
    $display("@%0t: after join", $time) ;
    #80 $display("@%0t: finish after #80",$time);
end

wait fork或者disable fork

        fork.. .join_any和fork.. .join_none语句结束后继续执行下面的程序,其一些未完成的子线程怎么处理。可以使用

wait fork:等待这些子程序全部完成
disable fork:停止这些子线程
 

task do_test;
    fork
        exec1) ;
        exec2() ;
    join_any
    fork
        exec3() ;
        exec4();
    join_none
 
    wait fork; //等待所有子线程结束
   // 在任务退出前,保证四个子线程都完成后,才退出任务。
endtask
task get_first( output int adr ) ;
//fork  join_any分别触发了三个同名的子线程。
//每个子线程完成时间不一样,都会给adr参数赋值。
//任务是只要其中一个线程完成,就可以退出任务
    fork
        wait_device( 1. adr ) ;
        wait_device( 7. adr ) ;
        wait_device( 13, adr ) ;
    join_any
//如果没有 disable fork,任务也可以退出,并且可以获得 wait_device( 1. adr )返回的变量
//后台的两个子线程有可能还在执行,甚至处于阻塞状态。
//这种还在等待的却已经不需要的子线程属于资源浪费
//在退出任务之前,通过 disable fork停止还在后台运行的不需要的子线程,
//保证退出任务时,资源被清理干净。
    disable fork;
endtask

时序控制
SV可以用来实现阻塞的时序控制的方式:

延迟控制(#)
事件(event)等待或者完成边沿触发(@)
电平触发式赋值(wait)
1、延迟控制即通过#来完成。

#10 rega = regb;
2、事件(event)控制,完成边沿触发方式即通过@来完成。

@r rega = regb;
@(posedge clock) rega = regb;
3、wait语句也可以与事件或者表达式结合来完成。

real AOR[];
initial wait(AOR.size() > 0) ....;
 

你可能感兴趣的:(fpga开发)