System Verilog : Mailbox

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.