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),那么传递数组时会对数组进行拷贝而不是影响原来的数组。

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...