Systemverilog thread and communication between threads (2)

 
 

1. Semaphore

If the process execution is regarded as the behavior of "driving", a key is required for driving, and the semaphore is similar to "key". A thread must first apply for a key (semaphore) to execute. If there is only one key (semaphore) and it is applied for by other threads, then this thread is blocked. When that thread finishes executing, the key (semaphore) is returned, and the blocked thread can apply for the key (semaphore) again.

Semaphores can be used when multiple processes share resources.

  1. The new method creates one or more semaphores

  2. get gets one or more semaphores, if the get fails to block

  3. put returns one or more semaphores

  4. try_get() tries to get the semaphore, but does not block. A return of 1 indicates that there are enough semaphores, and a return of 0 indicates that there are not enough semaphores.

program automatic test; 
    semaphore sem; //create a semaphore 
    initial begin 
        sem = new(1); //allocate a key 
        run(); 
    end 
    task run(); 
        sem.get(1); //apply for a key ; At this time, if other processes apply for the key of this semaphore, they will be blocked. 
        .... // Use resource 
        sem.put(1); // Execution ends, return key 
    endtask 
endprogram

2. Mailbox mailbox

Mailboxes are used to pass transactions between multiple threads, such as between generators and drivers.

The mailbox is similar to a FIFO, first in first out.

Adding an object to a fixed-capacity full mailbox will block; fetching an object from an empty mailbox will also block.

A letterbox is an object and needs to be instantiated.

get, put, peak (peek takes a copy of the object's data, but does not delete it).

It is best to put only one type of data in the mailbox. (Although it is not wrong to put different data syntax).

The mailbox is actually a parameter class, which can specify the type of data in the mailbox.

The handle (pointer) is stored in the mailbox. If only one object is new, but it is randomized many times, then the object stored in the mailbox is one.

initial begin
    mailbox mlb#(Transaction); //指定类型
    Transaction tr,tmp;
    repeat(10) begin
        tr = new(); // 在循环内创建对象
        assert(tr.randomize());
        mlb.put(tr); //存入mlb
    end
    repeat(10) begin
        mlb.get(tmp); //从mlb取
        tmp.show();
    end
end

2.1 Synchronize using fixed-volume mailboxes

class Transaction;
  rand bit[7:0] data;
  rand bit[7:0] addr;
endclass
class Generator;
  mailbox mlb;
  Transaction tr;
  function new(mailbox m);
    this.mlb= m;
  endfunction
  task run();
    repeat(5) begin   
      tr=new();
      assert(tr.randomize());
      mlb.put(tr);
      $display("@ %0t [gen] put a tr",$time);
    end 
  endtask
endclass
​
class Driver;
  mailbox mlb;
  Transaction tr;
  function new(mailbox m);
    this.mlb= m;
  endfunction
  task run();
  forever begin
      #10; //每延迟10ns,driver取一个数据,也可以同步到时钟沿@(posedge clk);
    mlb.get(tr);
    $display("@ %0t [drv] get a tr",$time);
    end
  endtask
endclass
​
program automatic tb;
Generator gen;
Driver drv;
mailbox mlb;
initial begin
    mlb=new(1);//定容信箱,容量1,如果参数为空,则mailbox不限容量
  gen=new(mlb);
  drv=new(mlb);
  fork // 并发执行
    gen.run();
    drv.run();
  join
end
endprogram 
// output 
@ 0 [gen] put a tr
@ 10 [drv] get a tr
@ 10 [gen] put a tr
@ 20 [drv] get a tr
@ 20 [gen] put a tr
@ 30 [drv] get a tr
@ 30 [gen] put a tr
@ 40 [drv] get a tr
@ 40 [gen] put a tr
@ 50 [drv] get a tr

As can be seen from the output, put a tr, block the put operation, then get a tr, and then put and so on.

2.2 Using Mailboxes and Events to Synchronize

program automatic tb;
event handshake; // 事件
mailbox mlb;
class Generator;
  ...
  task run();
    repeat(5) begin   
      ...
      mlb.put(tr);
      $display("@ %0t [gen] put a tr",$time);
      @handshake;  //生成完一个tr后阻塞。
    end 
  endtask
endclass
​
class Driver;
  ...
  task run();
  forever begin
    #10;
    mlb.get(tr);
    $display("@ %0t [drv] get a tr",$time);
  ->handshake; //获取完一个tr后触发事件
    end
  endtask
​
endclass
​
Generator gen;
Driver drv;
initial begin
    mlb=new(); //无限容量
  gen=new(mlb);
  drv=new(mlb);
  fork ... join_none
end
endprogram 
@ 0 [gen] put a tr
@ 10 [drv] get a tr
@ 10 [gen] put a tr
@ 20 [drv] get a tr
@ 20 [gen] put a tr
@ 30 [drv] get a tr
@ 30 [gen] put a tr
@ 40 [drv] get a tr
@ 40 [gen] put a tr
@ 50 [drv] get a tr

2.3 Synchronize using two mailboxes

program automatic tb;
mailbox#(Transaction) mlb;
    mailbox#(int) m;  // 定义两个信箱
class Generator;
  Transaction tr;
  int i;
  task run();
    repeat(5) begin
      tr=new();
      assert(tr.randomize());
      mlb.put(tr);
      $display("@ %0t [gen] put a tr",$time);
        m.get(i); //m为空,阻塞
    end 
  endtask
endclass
​
class Driver;
  Transaction tr;
  int i;
  task run();
  forever begin
#10;
    mlb.get(tr);
    $display("@ %0t [drv] get a tr",$time);
      m.put(i); // m不为空,触发了Generator中的语句。
    end
  endtask
endclass
​
Generator gen;
Driver drv;
initial begin
  mlb=new();
    m=new(); //新建信箱
  gen=new();
  drv=new();
  fork
    gen.run();
    drv.run();
  join
end
endprogram 
@ 0 [gen] put a tr
@ 10 [drv] get a tr
@ 10 [gen] put a tr
@ 20 [drv] get a tr
@ 20 [gen] put a tr
@ 30 [drv] get a tr
@ 30 [gen] put a tr
@ 40 [drv] get a tr
@ 40 [gen] put a tr
@ 50 [drv] get a tr

Guess you like

Origin blog.csdn.net/m0_38037810/article/details/125022272