systemverilog-线程通信

目录

1.线程通信的意义

2.线程的使用

3.线程的控制

4.线程间的通信

4.1 event

4.2 semaphore

4.3 mailbox


1.线程通信的意义

在测试平台中,需要通过控制和模拟事务之间的调度,来控制整个测试平台的运行。例如何时开始发送激励,监测到信号时,触发另一些事件,或者是通过mailBox充当FIFO,来存放句柄。通过这些线程之间的通信,可以控制和搭建更完整的验证平台。

2.线程的使用

线程的使用主要包括begin…… end 的顺序执行语句块以及fork …… join, fork……join_none,fork …… join_any等的并行执行语句块。

fork……join:全部子线程执行完再进入下一阶段。

fork …… join_any:有一个子线程完成即进入下一阶段。

fork……join_none:直接进入下一阶段。

示例:

 //一直监听复位信号而不阻塞其他进程的运行
virtual protected task reset_listener();
    `uvm_info(get_type_name(), "reset_listener ...", UVM_HIGH)
    fork
      forever begin
        @(negedge vif.hresetn); // 等待复位信号
        _do_drive_idle();       //  复位
      end
    join_none
  endtask

3.线程的控制

线程可以通过wait fork来等待fork块中所有线程执行完毕再退出initial块,也可以通过disable来禁止某个线程的进行。

示例:

initial begin::wait_fork
    fork
        wait_fork_1();
        wait_fork_2();
    join_none
    
    wait fork;        //等待线程结束
end


initial begin::disable_fork
    fork:d
        fork:d_1
           dis_fork_1();
        join

        fork:d_2
           dis_fork_2();   //100ns后 禁止
        join

        fork:d_3
          #100ns;
          disalbe d_1;            //100ns 后终止进程d_1
        join      
    join
end

4.线程间的通信

 线程之间需要通过同步并交换数据,另一个线程可能需要等待一个线程的触发后才会运行,以及多个线程之间可以需要共享一个资源。这些线程之间的数据交换和同步被成为是线程之间的通信。线程之间的通信方法主要包括event、semaphore、mailBox

4.1 event

在Verilog中可以通过->来触发事件,同时通过@来等待事件,而在systemVerilog中新添加了wait(event.triggered())。

@是边沿敏感的阻塞语句,而wait(event.triggered())是电平敏感的。但需要对一个事件重复触发时,需要用@,因为event没有方法能够清除wait(event.triggered())的状态。

wait(event.triggered())无法捕捉已经被触发,但后续才等待的事件,若没有采样到事件就会一直阻塞。

示例:

event e1,e2;

initial begin
    $display( "1: before trigger");
    -> e1;
    wait(e2.triggered());             //等待e2触发才会继续执行
    $display("1: after trigger");
end

initial begin
    $display( "2: before trigger");
    -> e2;
     wait(e1.triggered());            //等待e1触发才会继续执行
    $display("2: after trigger");
end

4.2 semaphore

semaphore(旗语)用于对同一资源的访问,一般用于多资源访问请求时但只允许由单一驱动时(只有一把车钥匙,多个人都想开车,但同一时间只有一个人能开上车)。

示例:

program automatic test()

semaphore sem;        //声明

initial begin
   sem = new(1);     //分配1个钥匙
   fork
    sem_1();
    sem_2();
   join
end

task sem_1();
   sem.get(1);    //获取钥匙 
   #100ns;
   sem.put(1);   //放回钥匙
endtask

task sem_2();
   #10ns;
   sem.get(1);    //100ns等sem_1返回钥匙后才能拿到钥匙
   #100ns;
   sem.put(1);   
endtask

endprogram

4.3 mailBox

mailBox可以用于传递线程之间的信息,用于充当SV中的FIFO。

mailBox和队列类似,但mailBox需要通过new()来例化,若不指定size,则其容量为无限大。

mailBox方法

put() : 可以把数据放入mailBox里。(阻塞,如果mailBox为满,则方法会阻塞)

get() : 从mailBox中移除数据。(阻塞,如果mailBox为空,则方法会阻塞)

peek() : 获得mailBox的信箱的数据拷贝而不移除,多用于线程之间的同步。可以将数据处理完后,再把数据删除。(阻塞)

以及try_put() 、try_get() 和try_peek()等非阻塞方法

示例:

program automatic bounded;
mailBox mbx;   //声明
initial begin
    mbx = new(l); //例化 指定大小
    fork 
    // Producer线程
    for (int i=1; i<4; i++) begin
    $display("Producer: before put(%0d)", i);   
    mbx.put(i);                                 //放入数据                           
    $display("Producer: after put(%0d)", i);
    end 
    // Consumer线程
    repeat(4) begin
    int j;
    #lns mbx.get(j);                            //拿出数据
    $display("Consumer:after get(%0d)", j);
    end
    join
end
endprogram

mailBox和队列的区别

  • mailBox需要例化,而队列不用。
  • mailBox中可以同时储存不同数据类型的数据(不建议),而队列不行。
  • 队列中push_back和pop_front()为非阻塞,再取数时要保证队列大小大于0(queue.size() > 0),而mailBox既有阻塞又又非阻塞。
  • mailBox传递形式参数时,传递拷贝的是它的指针,而对于queue若不声明为ref(认为input),那么传递数组时会对数组进行拷贝而不是影响原来的数组。

相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...
win11本地账户怎么改名?win11很多操作都变了样,用户如果想要...