[SystemVerilog][Verification] Mailboxes

2024-05-21


Mailboxes is used to pass information between threads. Generator can pass information to driver by mailboxes and no need to call driver's task. Mailboxes can be seen as a FIFO with limited or unlimited size.
Mailboxes methods:

1. function new(int bound = 0);
bound = 0 means unlimited size.

2. function int num();
Return the number of messages currently in the mailbox.

3. task put(data_type message);
Places a message in mailbox. If mailbox is bounded and full, the process should be suspended until there's enough room.

4. function int try_put(data_type message);
The try_put() method stores a message in the mailbox in strict FIFO order. 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.

5. task get(ref data_type message);
The get() method retrieves one message from the mailbox, that is, removes one message from the mailbox queue. If the mailbox is empty, then the current process blocks until a message is placed in the mailbox.

6. function int try_get(ref data_type message);
The try_get() method attempts to retrieves a message from a mailbox without blocking. The try_get() method tries to retrieve one message from the mailbox. If the mailbox is empty, then the method returns 0. If the type of the message variable is not equivalent to the type of the message in the mailbox, the method returns a negative integer. If a message is available and the message type is equivalent to the type of the message variable, the message is retrieved, and the method returns a positive integer.

7. task peek(ref data_type message);
The peek() method copies one message from the mailbox without removing the message from the mailbox queue. If the mailbox is empty, then the current process blocks until a message is placed in the mailbox.

8. function int try_peek(ref data_type message);
The try_peek() method tries to copy one message from the mailbox without removing the message from the mailbox queue. If the mailbox is empty, then the method returns 0. If the type of the message variable is not equivalent to the type of the message in the mailbox, the method returns a negative integer. If a message is available and its type is equivalent to the type of the message variable, the message is copied, and the method returns a positive integer.

Note that mailbox only store the handler(pointer) of the object. get task and try_get function use ref variable because mailbox will copy the handler(pointer) to the ref variable, meaning modifying the variable directly.
Also note that noparameterized mailboxes are typeless, that is, a single mailbox can send and receive different types of data. Thus, in addition to the data being sent (i.e., the message queue), a mailbox implementation shall maintain the message data type placed by put(). This is required in order to enable the run-time type checking. It's also recommended that use parameterized mailbox and each date type has different mailbox, which also enable run-time type checking.

mailbox Handler(pointer) stored in mailbox.

Example:


task generator_good(
	input int n,
	input mailbox #(Transaction) mbx
);

Transaction tr;
repeat (n) begin
	tr = new();          // Create a new transaction
	`SV_RAND_CHECK(tr.randomize());
	$display("GEN: Sending addr=%h", tr.addr);
	mbx.put(tr);         // Send transaction to driver
end

task driver(input mailbox #(Transaction) mbx);
	Transaction tr;
	forever begin
		mbx.get(tr);     // Get transaction from mailbox
		$display("DRV: Received addr=%h", tr.addr);
		// Drive transaction into DUT
	end
endtask

End