📦 Mailboxes in SystemVerilog#
Mailboxes are built-in classes in SystemVerilog that provide a powerful and convenient mechanism for interprocess communication and data exchange between concurrent processes. They’re commonly used to implement producer-consumer architectures in testbenches and simulation environments.
🗂️ What is a Mailbox?#
A mailbox acts as a FIFO queue that stores messages (data) between processes:
- A producer process puts data into the mailbox.
- A consumer process gets data from the mailbox.
Mailboxes support both bounded and unbounded queue sizes:
- Unbounded mailboxes (default) never block on a put operation.
- Bounded mailboxes suspend the producer if the queue is full, ensuring safe data flow.
🛠️ Creating a Mailbox#
Mailboxes are created using the built-in mailbox
class and the new()
constructor.
mailbox mbx;
// Create an unbounded mailbox
initial begin
mbx = new();
end
// Create a bounded mailbox with a size of 10
initial begin
mbx = new(10);
end
🚦 Using a Mailbox#
📤 Putting Data into a Mailbox#
Use the put()
task to store a message in the mailbox.
mbx.put(data); // blocks if mailbox is full (bounded mailbox)
For non-blocking insertion, use try_put()
:
if (mbx.try_put(data)) begin
// Data added successfully
end else begin
// Mailbox is full
end
📥 Getting Data from a Mailbox#
Use the get()
task to retrieve a message from the mailbox.
mbx.get(data); // blocks if mailbox is empty
For non-blocking retrieval, use try_get()
:
if (mbx.try_get(data)) begin
// Data retrieved
end else begin
// Mailbox is empty
end
👀 Peeking at Data#
Use the peek()
task to copy a message without removing it from the queue.
mbx.peek(data); // blocks if mailbox is empty
For non-blocking peek, use try_peek()
:
if (mbx.try_peek(data)) begin
// Data peeked
end else begin
// Mailbox is empty
end
🔍 Summary of Key Methods#
Method | Description |
---|---|
new() | Creates the mailbox (bounded or unbounded). |
put() | Places a message in the mailbox (blocks if full). |
try_put() | Non-blocking attempt to place a message. |
get() | Retrieves a message from the mailbox (blocks if empty). |
try_get() | Non-blocking attempt to retrieve a message. |
peek() | Copies a message without removing it (blocks). |
try_peek() | Non-blocking attempt to copy a message. |
num() | Returns the number of messages currently stored. |
🛡️ Common Uses#
- Producer-Consumer Communication: Send transactions from drivers to monitors.
- Scoreboard Communication: Transfer data between different testbench components.
- Flow Control: Manage data throughput using bounded queues.
💡 Best Practices#
✅ Use try_put()
and try_get()
when implementing non-blocking data flow.
✅ Always match put()
calls with corresponding get()
calls to avoid indefinite growth of unbounded mailboxes.
✅ For type safety, consider using parameterized mailboxes when exchanging specific data types.
✅ Document mailbox usage clearly in the testbench architecture.
📖 Conclusion#
Mailboxes are a versatile mechanism for data exchange and synchronization in SystemVerilog verification environments. When used effectively, they simplify communication between concurrent processes, ensuring safe and reliable simulation results.
module tb_mailbox_demo;
mailbox mbx; // Define mailbox
// Clock generation
logic clk = 0;
always #5 clk = ~clk;
// Producer process: sends data into mailbox
initial begin
mbx = new(); // Create an unbounded mailbox
repeat (5) begin
automatic int data = $urandom_range(0, 255);
mbx.put(data); // Put data into mailbox (blocking)
$display("[Producer] Sent: %0d at time %0t", data, $time);
#10;
end
end
// Consumer process: receives data from mailbox
initial begin
int received;
repeat (5) begin
mbx.get(received); // Get data from mailbox (blocking)
$display("[Consumer] Received: %0d at time %0t", received, $time);
#15;
end
end
// Simulation end
initial begin
#100;
$finish;
end
endmodule