Mailboxes in SystemVerilog

Mailboxes are FIFO queues for passing data between processes. They're the primary way to send transactions from generators to drivers in verification.

What Is a Mailbox?

Think of a mailbox like a real post box. One process puts letters in, another takes them out. The letters are kept in order (FIFO - First In, First Out).

Basic Mailbox
mailbox mbx;

initial begin
    mbx = new();  // Create unbounded mailbox
    
    fork
        // Producer
        begin
            for (int i = 0; i < 5; i++) begin
                mbx.put(i);  // Put data in mailbox
                $display("[%0t] Put: %0d", $time, i);
                #5;
            end
        end
        
        // Consumer
        begin
            int data;
            repeat(5) begin
                mbx.get(data);  // Get data from mailbox
                $display("[%0t] Got: %0d", $time, data);
            end
        end
    join
end

Bounded vs Unbounded Mailboxes

Creating Mailboxes
mailbox mbx_unbounded = new();    // Unlimited capacity
mailbox mbx_bounded = new(5);     // Max 5 items

// Bounded mailbox blocks producer when full!
for (int i = 0; i < 10; i++) begin
    mbx_bounded.put(i);  // Blocks after 5th item!
    $display("Put %0d", i);
end

Mailbox Methods

put() - Blocking Put

Puts item in mailbox. Blocks if bounded mailbox is full:

put() Method
mbx.put(data);  // Blocks if bounded and full

try_put() - Non-blocking Put

Tries to put. Returns 1 if success, 0 if mailbox full:

try_put() Method
if (mbx.try_put(data)) begin
    $display("Data sent!");
end else begin
    $display("Mailbox full!");
end

get() - Blocking Get

Gets item from mailbox. Blocks if empty:

get() Method
int data;
mbx.get(data);  // Blocks until data available

try_get() - Non-blocking Get

Tries to get. Returns 1 if success, 0 if empty:

try_get() Method
int data;
if (mbx.try_get(data)) begin
    $display("Got: %0d", data);
end else begin
    $display("Mailbox empty!");
end

peek() - Look Without Removing

Gets a copy without removing from mailbox:

peek() Method
int data;
mbx.peek(data);  // Look at front item, don't remove

num() - Check Count

Returns number of items in mailbox:

num() Method
$display("Items in mailbox: %0d", mbx.num());

Parameterized Mailboxes

You can specify the data type for type safety:

Typed Mailbox
class Transaction;
    int addr;
    int data;
endclass

// Typed mailbox - only accepts Transaction objects
mailbox #(Transaction) txn_mbx = new();

Transaction txn = new();
txn.addr = 32'h1000;
txn.data = 32'hCAFE;

txn_mbx.put(txn);  // Put Transaction

Transaction received;
txn_mbx.get(received);  // Get Transaction
$display("Addr: %h, Data: %h", received.addr, received.data);

Practical Example: Generator-Driver

UVM-Style Pattern
class Transaction;
    rand bit [31:0] addr;
    rand bit [31:0] data;
    rand bit write;
endclass

class Generator;
    mailbox #(Transaction) gen2drv;
    
    function new(mailbox #(Transaction) mbx);
        this.gen2drv = mbx;
    endfunction
    
    task run();
        Transaction txn;
        repeat(10) begin
            txn = new();
            assert(txn.randomize());
            gen2drv.put(txn);
            $display("[GEN] Sent txn: addr=%h", txn.addr);
        end
    endtask
endclass

class Driver;
    mailbox #(Transaction) gen2drv;
    
    function new(mailbox #(Transaction) mbx);
        this.gen2drv = mbx;
    endfunction
    
    task run();
        Transaction txn;
        forever begin
            gen2drv.get(txn);
            $display("[DRV] Driving: addr=%h, data=%h", 
                     txn.addr, txn.data);
            #10;  // Drive to DUT
        end
    endtask
endclass

// Testbench
module tb;
    initial begin
        mailbox #(Transaction) mbx = new();
        Generator gen = new(mbx);
        Driver drv = new(mbx);
        
        fork
            gen.run();
            drv.run();
        join_any
        
        disable fork;
        $display("Test complete!");
    end
endmodule

Quick Summary

  • mailbox - FIFO queue for inter-process communication
  • new() - Unbounded, new(n) - Bounded to n items
  • put() - Blocking put
  • try_put() - Non-blocking put
  • get() - Blocking get
  • try_get() - Non-blocking get
  • peek() - Look without removing
  • num() - Count items
  • Use mailbox #(Type) for type safety