SV -- Interprocess Communication (IPC 线程间通信)

SV -- Interprocess Communication (IPC 线程间通信)

@(SV)

1. Semaphore 旗语

  • 旗语是sv内置的方法,可以用来做线程间的同步。
  • 旗语就像一个桶,里面有很多键。使用旗语的进程必须首先从桶中获取一个密钥,然后才能继续执行,所有其他进程必须等待,直到向桶中返回足够数量的密钥。
  • 设想这样一种情况:两个进程试图访问一个共享内存区域。其中一个进程试图写入,而另一个进程试图读取相同的内存位置。这导致了一个意想不到的结果。可以使用旗语来克服这种情况。

语法:semaphore semaphore_name;
方法:

  • new(); 生成一定数量的keys
  • get(); 从桶中获取一定数量的keys
  • put(); 返回一定数量的keys到桶中
  • try_get(); 尝试获取一个或多个keys,不会让线程阻塞

其中get和try_get的区别在于:

  • get是在keys可获取时返回并且线程继续执行,而keys不可获取时线程被阻塞。
  • try_get则不管keys是否可获取,线程都会继续执行,只是keys可获取时返回1,不可获取返回0。

实例:并行进程之间通过旗语顺序执行

module semaphore_ex;
  semaphore sema; //declaring semaphore sema
 
  initial begin
    sema=new(4); //creating sema with '4' keys
    fork
      display(); //process-1
      display(); //process-2
      display(); //process-3
    join
  end
 
  //display method
  task automatic display();
    sema.get(2); //getting '2' keys from sema
    $display($time,"	Current Simulation Time");
    #30;
    sema.put(2); //putting '2' keys to sema
  endtask
endmodule

上面例子输出:
0 Current Simulation Time
0 Current Simulation Time
30 Current Simulation Time

第三个进程需要等待前两个中一个归还了keys之后才能执行。
下面是有多个keys存取的情况:

module semaphore_ex;
  semaphore sema; //declaring semaphore sema
 
  initial begin
    sema=new(4); //creating sema with '4' keys
    fork
      display(2); //process-1
      display(3); //process-2
      display(2); //process-3
      display(1); //process-4
    join
  end
 
  //display method
  task automatic display(int key);
    sema.get(key); //getting 'key' number of keys from sema
    $display($time,"	Current Simulation Time, Got %0d keys",key);
    #30;
    sema.put(key); //putting 'key' number of keys to sema
  endtask
endmodule

桶内只有四个键,会先依次取,第一个进程取了两个,第二个取三个不够,第三个可以取,此时进程1和3先执行,执行完后进程4和2再执行。

2. Mailbox 信箱

邮箱是一种通信机制,它允许在进程之间交换消息。希望与另一个进程通信的进程将消息发送到邮箱,邮箱将消息临时存储在系统定义的内存对象中,以便将消息传递给所需的进程。
mailbox按size分可以分为两种:

  • bounded mailbox
  • unbounded mailbox

有界邮箱的大小已定义。邮箱在存储有限数量的消息时变为满的。试图将消息放入完整邮箱的进程将被挂起,直到邮箱队列中有足够的空间可用为止。
无界邮箱的大小无限。

按照类型也可分为两种:

  • Generic Mailbox (type-less mailbox) 通用邮箱 mailbox mailbox_name;
  • Parameterized mailbox (mailbox with particular type) 参数化邮箱 mailbox#(type) mailbox_name;

跟旗语类似,信箱也有如下几种方法:

new();           - Create a mailbox
put();           - Place a message in a mailbox
try_put();       - Try to place a message in a mailbox without blocking
get(); or peek();- Retrieve a message from a mailbox
num();           - Returns the number of messages in the mailbox
try_get(); or try_peek();  - Try to retrieve a message from a mailbox without blocking

案例:
mailbox负责在generator和driver之间传输数据:

//-------------------------------------------------------------------------
// Packet
//-------------------------------------------------------------------------
class packet;
  rand bit [7:0] addr;
  rand bit [7:0] data;
 
  //Displaying randomized values
  function void post_randomize();
    $display("Packet::Packet Generated");
    $display("Packet::Addr=%0d,Data=%0d",addr,data);
  endfunction
endclass
 
//-------------------------------------------------------------------------
//Generator - Generates the transaction packet and send to driver
//-------------------------------------------------------------------------
class generator;
  packet pkt;
  mailbox m_box;
  //constructor, getting mailbox handle
  function new(mailbox m_box);
    this.m_box = m_box;
  endfunction
  task run;
    repeat(2) begin
      pkt = new();
      pkt.randomize(); //generating packet
      m_box.put(pkt);  //putting packet into mailbox
      $display("Generator::Packet Put into Mailbox");
      #5;
    end
  endtask
endclass
 
//-------------------------------------------------------------------------
// Driver - Gets the packet from generator and display's the packet items
//-------------------------------------------------------------------------
class driver;
  packet pkt;
  mailbox m_box;
 
  //constructor, getting mailbox handle
  function new(mailbox m_box);
    this.m_box = m_box;
  endfunction
 
  task run;
    repeat(2) begin
      m_box.get(pkt); //getting packet from mailbox
      $display("Driver::Packet Recived");
      $display("Driver::Addr=%0d,Data=%0d
",pkt.addr,pkt.data);
    end
  endtask
endclass
 
//-------------------------------------------------------------------------
//     tbench_top 
//-------------------------------------------------------------------------
module mailbox_ex;
  generator gen;
  driver    dri;
  mailbox m_box; //declaring mailbox m_box
 
  initial begin
    //Creating the mailbox, Passing the same handle to generator and driver, 
    //because same mailbox should be shared in-order to communicate.
    m_box = new(); //creating mailbox
 
    gen = new(m_box); //creating generator and passing mailbox handle
    dri = new(m_box); //creating driver and passing mailbox handle
    $display("------------------------------------------");
    fork
      gen.run(); //Process-1
      dri.run(); //Process-2
    join
    $display("------------------------------------------");
  end
endmodule

输出:
Packet::Packet Generated
Packet::Addr=3,Data=38
Generator::Packet Put into Mailbox
Driver::Packet Recived
Driver::Addr=3,Data=38

Packet::Packet Generated
Packet::Addr=118,Data=92
Generator::Packet Put into Mailbox
Driver::Packet Recived
Driver::Addr=118,Data=92

3. Event 事件

事件是对流程之间的同步非常有用的静态对象。事件操作是两个分阶段的流程,其中一个流程将触发事件,另一个流程将等待触发事件。

  • 事件使用->操作符或->>操作符触发
    • -> : 触发一个事件时解除当前等待该事件的所有进程的阻塞。
    • ->> : 非阻塞事件使用->>操作符触发
  • 使用@操作符或wait()来等待触发事件
    • @: 对于使用一个使用触发来解除等待事件的进程的阻塞,等待进程必须在触发进程执行触发器操作符->之前执行@语句
    • wait(): 如果带有@操作符的事件触发和等待事件触发同时发生,@操作符可能会错过检测事件触发。wait(event_name.triggered);
    • wait_order(): 构造将阻塞该进程,直到按照给定的顺序(从左到右)触发所有指定的事件。无序的事件触发器将不会解除对进程的阻塞。wait_order(a,b,c); 还可以这么写:wait_order( a, b, c ) success = 1; else success = 0; 表示当触发顺序不是abc时,会显示错误。

示例:@ .triggered

module events_ex;
  event ev_1; //declaring event ev_1
 
  initial begin
    fork
      //process-1, triggers the event
      begin
        #40;
        $display($time,"	Triggering The Event");
        ->ev_1;
      end
     
      //process-2, wait for the event to trigger
      begin
        $display($time,"	Waiting for the Event to trigger");
        @(ev_1.triggered);
        $display($time,"	Event triggered");
      end
    join
  end
endmodule

输出:
0 Waiting for the Event to trigger
40 Triggering The Event
40 Event triggered

上面的例子中,->ev_1需要发生在triggered之后,即使同一时间发生也不会识别到。

示例:wait(.triggered)

module events_ex;
  event ev_1; //declaring event ev_1
 
  initial begin
    fork
      //process-1, triggers the event
      begin
         $display($time,"	Triggering The Event");
        ->ev_1;
      end
    
      //process-2, wait for the event to trigger
      begin
        $display($time,"	Waiting for the Event to trigger");
        wait(ev_1.triggered);
        $display($time,"	Event triggered");
      end
    join
  end
endmodule

输出:
0 Triggering The Event
0 Waiting for the Event to trigger
0 Event triggered

上面的例子中,->ev_1可以和wait同一时间发生。

示例: wait_order()

module events_ex;
  event ev_1; //declaring event ev_1
  event ev_2; //declaring event ev_2
  event ev_3; //declaring event ev_3
 
  initial begin
    fork
      //process-1, triggers the event ev_1
      begin
        #6;
        $display($time,"	Triggering The Event ev_1");
        ->ev_1;
      end
 
      //process-2, triggers the event ev_2
      begin
        #2;
        $display($time,"	Triggering The Event ev_2");
        ->ev_2;
      end
 
      //process-3, triggers the event ev_3
      begin
        #1;
        $display($time,"	Triggering The Event ev_3");
        ->ev_3;
      end
      //process-4, wait for the events to trigger in order of ev_2,ev_1 and ev_3
      begin
        $display($time,"	Waiting for the Event's to trigger");
        wait_order(ev_2,ev_1,ev_3)
          $display($time,"	Event's triggered Inorder");
        else
          $display($time,"	Event's triggered Out-Of-Order");
      end
    join
  end
endmodule

输出:
0 Waiting for the Event's to trigger
1 Triggering The Event ev_3
1 Event's triggered Out-Of-Order
2 Triggering The Event ev_2
6 Triggering The Event ev_1

原文地址:https://www.cnblogs.com/lyc-seu/p/12797089.html