SystemVerilog Interprocess Communication

测试平台中的组件通常需要相互通信以交换数据并检查设计的输出值。 下表显示了一些允许组件或线程影响数据控制流的机制。

Events事件 不同的线程通过测试台中的事件句柄彼此同步
Semaphores 旗语 不同的线程可能需要访问相同的资源,他们通过使用旗语
Mailbox邮箱 线程/组件需要彼此交换数据;数据放入邮箱并发送

什么是事件?

事件是同步两个或多个不同进程的方法。一个进程等待事件发生,而另一个进程触发事件。当事件被触发时,等待事件的进程将继续执行。

  1. 使用event创建event
event   eventA;    // 创建一个名为“ eventA”的事件

2.使用->运算符触发事件

 ->eventA;     // 任何有权访问“ eventA”的进程都可以触发该事件

3.等待事件发生

 @eventA;             // Use "@" operator to wait for an event
  wait (eventA.triggered);    // Or use the wait statement with "eventA.triggered" 

4.将事件作为参数传递给函数

module tb_top;
  event eventA;     //声明一个名为“ eventA”的事件句柄
 
  initial begin     
    fork 
      waitForTrigger (eventA);    // 任务等待eventA发生
      #5 ->eventA;                //触发 eventA
    join
  end
 
  //该事件将作为参数传递给此任务。它只是等待事件被触发
  task waitForTrigger (event eventA);
    $display ("[%0t] Waiting for EventA to be triggered", $time);
    wait (eventA.triggered);
    $display ("[%0t] EventA has triggered", $time);
  endtask
endmodule
 
Simulation Log
[20] Waiting for EventA to be triggered
[25] EventA has triggered
ncsim: *W,RNQUIE: Simulation is complete.

什么是旗语?

假设您想在图书馆租一个房间几个小时。 管理台将为您提供在您请求访问时间使用房间的钥匙。 完成工作后,您将把密钥退还给管理员,管理员将被分配给想要使用同一房间的其他人。 这样一来,两个人将无法同时使用房间。 在这种情况下,关键是一个旗语。

旗语用于控制对资源的访问,并称为互斥(互斥),因为一次只能有一个实体具有该旗语。

module tb_top;
   semaphore key;         // 创建一个名为“ key”的旗语
 
   initial begin 
      key = new (1);       //仅创建一个密钥;也可以使用多个键
      fork
         personA ();       // personA tries to get the room and puts it back after work
         personB ();       // personB also tries to get the room and puts it back after work
         #25 personA ();     // personA tries to get the room a second time
      join_none
   end
 
   task getRoom (bit [1:0] id);
      $display ("[%0t] Trying to get a room for id[%0d] ...", $time, id);
      key.get (1);
      $display ("[%0t] Room Key retrieved for id[%0d]", $time, id);
   endtask
 
   task putRoom (bit [1:0] id);
      $display ("[%0t] Leaving room id[%0d] ...", $time, id);
      key.put (1);
      $display ("[%0t] Room Key put back id[%0d]", $time, id);
   endtask
 
   // 此人尝试立即获得房间,并在20个时间单位后将其放回房间
   task personA ();       
      getRoom (1);
      #20 putRoom (1);
   endtask
 
  // This person tries to get the room after 5 time units and puts it back after
  // 10 time units
   task personB ();
      #5  getRoom (2);
      #10 putRoom (2);
   endtask
endmodule
 
Simulation Log
[0] Trying to get a room for id[1] ...
[0] Room Key retrieved for id[1]
[5] Trying to get a room for id[2] ...
[20] Leaving room id[1] ...
[20] Room Key put back id[1]
[20] Room Key retrieved for id[2]
[25] Trying to get a room for id[1] ...
[30] Leaving room id[2] ...
[30] Room Key put back id[2]
[30] Room Key retrieved for id[1]
[50] Leaving room id[1] ...
[50] Room Key put back id[1]

注意以下有关旗语的信息。
【1】旗语对象键是使用new()函数声明和创建的。 new()的参数定义键的数量;
【2】您可以使用get()关键字来获取密钥,该关键字将等到密钥可用;
【3】您使用put()关键字放回密钥;

什么是信箱?

信箱就像建立用于在两个组件之间发送数据的专用通道。

例如,可以创建信箱,并将句柄传递给数据生成器和驱动程序。 生成器可以将数据对象推入信箱,驱动程序将能够检索数据包并将信号驱动到总线上。

// Data packet in this environment
class transaction;
   rand bit [7:0] data;
 
   function display ();
      $display ("[%0t] Data = 0x%0h", $time, data);
   endfunction
endclass
 
// Generator class - Generate a transaction object and put into mailbox
class generator;
   mailbox mbx;
 
   function new (mailbox mbx);
      this.mbx = mbx;
   endfunction
 
   task genData ();
      transaction trns = new ();
      trns.randomize ();
      trns.display ();
      $display ("[%0t] [Generator] Going to put data packet into mailbox", $time);
      mbx.put (trns);
      $display ("[%0t] [Generator] Data put into mailbox", $time);
   endtask
endclass
 
// Driver class - Get the transaction object from Generator
class driver;
   mailbox mbx;
 
   function new (mailbox mbx);
      this.mbx = mbx;
   endfunction
 
   task drvData ();
      transaction drvTrns = new ();
      $display ("[%0t] [Driver] Waiting for available data", $time);
      mbx.get (drvTrns);
      $display ("[%0t] [Driver] Data received from Mailbox", $time);
      drvTrns.display ();
   endtask
endclass
 
// Top Level environment that will connect Gen and Drv with a mailbox
module tb_top;
   mailbox   mbx;
   generator Gen;
   driver    Drv;
 
   initial begin
      mbx = new ();
      Gen = new (mbx);
      Drv = new (mbx);
 
      fork 
         #10 Gen.genData ();
         Drv.drvData ();
      join_none
   end
endmodule
 
Simulation Log
[0] [Driver] Waiting for available data
[10] Data = 0x9d
[10] [Generator] Put data packet into mailbox
[10] [Generator] Data put into mailbox
[10] [Driver] Data received from Mailbox
[10] Data = 0x9d
ncsim: *W,RNQUIE: Simulation is complete.

参考文献:
【1】https://www.chipverify.com/systemverilog/systemverilog-interprocess-communication

SystemVerilog Interprocess CommunicationSystemVerilog Interprocess Communication 菜鸟-求指导 发布了69 篇原创文章 · 获赞 8 · 访问量 6856 私信 关注
上一篇:ROS学习笔记------ROS基础-----基础编程 day 3 2019/1/22 工程源码文件夹


下一篇:C++-POJ1018-Communication System