System Verilog : Mailbox

Synchronization and communication mechanisms are essential in our design, to control the interactions between processes or with a reactive testbench. This can be easily handled in System Verilog using semaphores, mailboxes and named events.

Mailboxes are a message-based process synchronization and communication mechanism provided in SV. It allows messages to be exchanged between processes. Conceptually, mailboxes behave like real mailboxes with delivery and retrieval of messages. In this, data can be sent to mailbox by one process and retrieved by another.

Example of creating a mailboxes are

mailbox mbx1 = new; 
mailbox mbx2 = new(5); 

Bounded and Unbounded Mailboxes
If maximum capapcity of the mailbox is specified along with the constructor, it is called bounded mailbox. If you do not pass a value to constructor, it would be an unbounded mailbox. A bounded mailbox becomes full when it reaches the maximum number of messages. But unbounded mailbox can never be full, as it has unlimited capacity.

Mailboxes can be created using bounded or unbounded queue size as per your requirement. In the above case, mbx1 is an unbounded mailbox and mbx2 is a bounded mailbox.

Following built-in methods are available to do communication using mailboxes.

  • new() : Create a mailbox
  • put() : Place a message in a mailbox
  • try_put() : Try to place a message in a mailbox without blocking
  • get() : Retrieve a message from a mailbox
  • try_get() : Try to retrieve a message from a mailbox without blocking
  • peek() : Copy a message from a mailbox without removing
  • try_peek() : Try to copy a message from a mailbox without blocking & removing
  • num() : Retrieve the number of messages in the mailbox

Following code shows how to use new(), num(), get() and put() built-in methods for mailbox.

///////////////////////////////////////////////////////////////////////
program mailbox_check;

mailbox mbx = new();
int msg,num;

initial begin
  for(int i=0; i<5; i++) #10 send_to_mbx(i*100);
  
  num = mbx.num();
  $display($time,"Number of packets in the Mailbox : %0d",num);

  for(int i=0; i<5; i++) #20 retrive_from_mbx(msg);
 
  #20 send_to_mbx(500);
  #10 retrive_from_mbx(msg);

  send_to_mbx(700);
  send_to_mbx(900);
  
  retrive_from_mbx(msg);
  copy_from_mbx(msg);
  retrive_from_mbx(msg);
  
  #500 $finish;
end

task send_to_mbx(int i);
 $display($time,"Sending message to Mailbox : %0d", i);
 mbx.put(i);
endtask

task retrive_from_mbx(int msg);
 mbx.get(msg); 
 $display($time,"Retrieved message using get : %0d", msg); 
endtask

task copy_from_mbx(int msgt);
 mbx.peek(msg); 
 $display($time,"Copied message using peek : %0d", msg); 
endtask

endprogram
/*
ncsim> source /opt/cadence/incisive_11.10.011/tools/inca/files/ncsimrc
ncsim> run
                  10Sending message to Mailbox : 0
                  20Sending message to Mailbox : 100
                  30Sending message to Mailbox : 200
                  40Sending message to Mailbox : 300
                  50Sending message to Mailbox : 400
                  50Number of packets in the Mailbox : 5
                  70Retrieved message using get : 0
                  90Retrieved message using get : 100
                 110Retrieved message using get : 200
                 130Retrieved message using get : 300
                 150Retrieved message using get : 400
                 170Sending message to Mailbox : 500
                 180Retrieved message using get : 500
                 180Sending message to Mailbox : 700
                 180Sending message to Mailbox : 900
                 180Retrieved message using get : 700
                 180Copied message using peek : 900
                 180Retrieved message using get : 900
Simulation complete via $finish(1) at time 680 NS + 1
*/

The new() method returns the mailbox handle. If the bound argument is 0, then the mailbox is unbounded. Here mbx is an unbounded mailbox. If bound is nonzero, it represents the size of the mailbox queue.

The number of messages in a mailbox can be obtained via the num() method. It returns the number of messages currently in the mailbox. In the above case, 5 messsages are there in the mailbox mbx at time 50. So the method returns 5.

The put() method places a message in a mailbox. This is a blocking method and stores the message in the mailbox in strict FIFO order. If the mailbox was created with a bounded queue, the process shall be suspended until there is enough room in the queue. In the above code, from time 10 to 50, 5 messages are placed in the mbx using put() method.

The get() method retrieves a message from a mailbox and also removes it from the mailbox queue. If the mailbox is empty, then the current process is blocked until a message is placed in the mailbox. If the type of the message variable and the type of the message in the mailbox are different, a run-time error is generated.

The peek() method copies a message from a mailbox without removing the message from the queue.If the mailbox is empty, then the current process blocks until a message is placed in the mailbox. If type of the message variable and the type of the message in the mailbox are different, a run-time error is generated.

From time 70 to 150 all 5 messages are retrieved and removed from queue. Again two more messages are sent to mailbox. At time 180, get() method retrieves “700” and the message left in the mailbox is “900”. The method peek() just copies that and when we do get() again, 900 will be retrived and mbox will be emptied.

Here we can see that peek() will not retrieve & remove the messages from the queue; instead it just copies. But get() method removes the message from the mailbox after retrieval.

Below code shows how to use try_get and try_peek methods.

///////////////////////////////////////////////////////////////////////
program mailbox_try_check;

mailbox mbx = new();
int msg,ret;
string str;

initial begin
  
  //As there is no message in the mbox, try_get returns 0
  ret = mbx.try_get(msg); 
  $display("  Empty Mailbox - Return %0d", ret); 
  
  //send a message to mbox
  send_to_mbx(555);
 
  //As type is different, try_get returns a negative number
  ret = mbx.try_get(str); 
  $display("  try_get fails due to type mismatch - Return %0d", ret);
 
  //send another message to mbox
  send_to_mbx(666);
  
  //try_peek
  ret = mbx.try_peek(msg); 
  $display("  try_peek() Message copied  - Return %0d : Message = %0d", ret, msg); 
 
  //try_get 
  ret = mbx.try_get(msg); 
  $display("  try_get() Message retrieved - Return %0d : Message = %0d", ret, msg); 
 
  //try_peek
  ret = mbx.try_peek(msg); 
  $display("  try_peek() Message copied  - Return %0d : Message = %0d", ret, msg); 
 
  //try_get 
  ret = mbx.try_get(msg); 
  $display("  try_get() Message retrieved - Return %0d : Message = %0d", ret, msg); 
 
  #50 $finish;
end

task send_to_mbx(int i);
 $display("  Sending Packet to Mailbox - put() : %0d", i);
 mbx.put(i);
endtask

endprogram 
///////////////////////////////////////////////////////////////////////
/*
ncsim> run
  Empty Mailbox - Return 0
  Sending Packet to Mailbox - put() : 555
  try_get fails due to type mismatch - Return -1
  Sending Packet to Mailbox - put() : 666
  try_peek() Message copied  - Return 1 : Message = 555
  try_get() Message retrieved - Return 1 : Message = 555
  try_peek() Message copied  - Return 1 : Message = 666
  try_get() Message retrieved - Return 1 : Message = 666
Simulation complete via $finish(1) at time 50 NS + 1
./b.sv:40    #50 $finish;
ncsim> exit
*/

The try_get() method attempts to retrieve a message from a mailbox without blocking.If the mailbox is empty, then the method returns 0. This can be found in the above code.

If the type of the message variable and the type of the message in the mailbox are different, the method returns a negative integer. Here string is passed with try_get (inplace of int) and it returns -1.

The try_peek() method attempts to copy a message from a mailbox without blocking & without removing from mailbox queue.If the mailbox is empty, then the method returns 0. If there is a type mismatch the method returns a negative integer.

///////////////////////////////////////////////////////////////////////

program mailbox_bounded_check;

mailbox mbx = new(4);
int msg,ret;
string str;

initial begin
  
  for(int i=0; i<7; i++) #10 try_put_to_mbx(i*100);
  for(int i=0; i<5; i++) #20 try_get_from_mbx(msg);

  #50 $finish;
end

task try_put_to_mbx(int i);
 int  ok;
 ok = mbx.try_put(i);
 if(ok > 0) $display(" Sent message to Mailbox - try_put() : %0d  Return : %0d", i, ok);
 else  $display(" Fails sending message to Mailbox - try_put() : %0d  Return : %0d", i, ok);
endtask

task try_get_from_mbx(int msg);
 int ok;
 ok = mbx.try_get(msg); 
 if(ok > 0) $display(" Retrieved message from Mailbox - try_get() : %0d  Return : %0d", msg, ok);
 else  $display(" Fails retrieving message from Mailbox - try_get() : %0d  Return : %0d", msg, ok);
endtask

endprogram 

/*
ncsim> run
 Sent message to Mailbox - try_put() : 0  Return : 1
 Sent message to Mailbox - try_put() : 100  Return : 1
 Sent message to Mailbox - try_put() : 200  Return : 1
 Sent message to Mailbox - try_put() : 300  Return : 1
 Fails sending message to Mailbox - try_put() : 400  Return : 0
 Fails sending message to Mailbox - try_put() : 500  Return : 0
 Fails sending message to Mailbox - try_put() : 600  Return : 0
 Retrieved message from Mailbox - try_get() : 0  Return : 1
 Retrieved message from Mailbox - try_get() : 100  Return : 1
 Retrieved message from Mailbox - try_get() : 200  Return : 1
 Retrieved message from Mailbox - try_get() : 300  Return : 1
 Fails retrieving message from Mailbox - try_get() : 0  Return : 0
Simulation complete via $finish(1) at time 220 NS + 1
*/

Here mbx is an bounded mailbox with size 5. The try_put() method attempts to place a message in a mailbox. It stores a message in the mailbox in strict FIFO order. This method is meaningful only for bounded mailboxes. If the mailbox is not full, then the specified message is placed in the mailbox, and the function returns a positive integer. If the mailbox is full, the method returns 0. In the above code, try_put on messages “400”, “500” & “600” fail as mbx is full.

5 comments on “System Verilog : Mailbox

  1. praveen

    is it legal to write put() and peek()/get() method in same task to see what has been put into the mailbox…

    eg.

    task send_to_mbx(int i);
    int j;
    $display(” Sending Packet to Mailbox – put() : %0d”, i);
    mbx.put(i);
    mbx.get(j); //or mbx.peek(j);
    $display(” Sent Packet to Mailbox – get() : %0d”, j);
    endtask

    if its not then could you please explain why?

    ps: very helpful and very well explained.. thanks alot..

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *