A mailbox provides a synchronized communication channel between two concurrent processes — typically a Generator and a Driver in a SystemVerilog testbench.
🧩 Concept Overview
- The Generator creates and sends transactions.
- The Driver receives and processes those transactions.
- A mailbox connects them, allowing asynchronous and decoupled communication.
This pattern models a realistic testbench environment where different verification components operate at their own pace.
Exchanging Objects Using a Mailbox
program mailbox_example(bus_if.TB bus, ...);
// -----------------------
// Generator Class
// -----------------------
class Generator;
Transaction tr;
mailbox mbx;
function new(mailbox mbx);
this.mbx = mbx;
endfunction
task run;
repeat (10) begin
tr = new;
assert(tr.randomize);
mbx.put(tr); // Send transaction to mailbox
end
endtask
endclass
// -----------------------
// Driver Class
// -----------------------
class Driver;
Transaction tr;
mailbox mbx;
function new(mailbox mbx);
this.mbx = mbx;
endfunction
task run;
repeat (10) begin
mbx.get(tr); // Receive transaction from mailbox
@(posedge busif.cb.ack);
bus.cb.kind <= tr.kind;
...
end
endtask
endclass
// -----------------------
// Testbench Setup
// -----------------------
mailbox mbx; // Shared mailbox between generator & driver
Generator gen;
Driver drv;
initial begin
mbx = new; // Create the mailbox
gen = new(mbx); // Pass mailbox handle to generator
drv = new(mbx); // Pass mailbox handle to driver
fork
gen.run(); // Spawn generator thread
drv.run(); // Spawn driver thread
join
end
endprogram
🧠 Explanation
| Component | Role | Behavior |
|---|---|---|
| Generator | Produces transactions | Randomizes and sends each transaction via mbx.put(tr) |
Mailbox (mbx) |
Communication channel | Holds transactions until the driver retrieves them |
| Driver | Consumes transactions | Calls mbx.get(tr) to fetch the next transaction and drives it to the bus |
-
The mailbox synchronizes the flow of data:
- The generator may be faster — it blocks if the mailbox is full.
- The driver may be slower — it blocks if the mailbox is empty.
-
This ensures that both components run asynchronously but safely without data loss.
🔄 Data Flow Summary
Generator ── put(tr) ─▶ [ Mailbox FIFO ] ── get(tr) ─▶ Driver
- put() inserts a transaction (blocks if full)
- get() retrieves a transaction (blocks if empty)
Both operations automatically handle synchronization between threads.
🧱 Key Takeaways
- Mailboxes provide a simple and safe way to exchange data between concurrent processes.
- They decouple components — neither side needs to know the other’s hierarchy or timing.
- The mailbox acts as a FIFO buffer between producer (Generator) and consumer (Driver).
- This pattern forms the foundation of transaction-level communication in testbench design.