Testbench remains in HDL (Verilog or VHDL). Synchronization is performed at every signal event between the testbench and the DUT in ZeBu.

Typical result: 50 kHz (100X RTL simulation)
Sample Verilog code:
always @(posedge clk) begin
if (!ce && !we) begin
mem[add] <= data;
$displayPixel(add, data);
end end
Testbench is written in C++, SystemC or SystemVerilog. Packets of data are exchanged between the testbench and the DUT. Encoding and decoding of packets into signals for the DUT is performed in hardware, at very high speed (faster than the DUT, typically at 50 MHz). In the example, each packet corresponds to a valid pixel.

Typical result: speed in the tens of MHz range
Sample C++ code:
Port *rcv_port;
unsigned int *msg;
while(1) {
while(!rcvPort->isPossibleToReceive()) ;
msg = rcvPort->receiveMessage();
*add = msg[1] & 0x1fff;
*data = msg[0];
displayPixel(add, data);
}
Testbench is written in C++. Signals are synchronized at clock boundaries. Clocks advance under the control of the C++ testbench.

Typical result: speed in the 200 kHz range
Sample C++ code:
Signal &ce = *(top->ce);
Signal &we = *(top->we);
Signal &add = *(top->add);
Signal &data = *(top->data);
while(1) {
if(!ce && !we) {
mem[add] = data;
displayPixel(add, data);
}
top->run(1);
}
This sample design is a graphics rendering engine, computing a fractal image called Mandelbrot. The same design is used in different modes of operation to illustrate the impact of various testbench choices..
The design generates pixels by writing them on a video bus (signals CE, WE, ADD, DATA). Depending on how the decoding of this bus is performed (by an HDL simulator, in C++ or directly in hardware via a transactor), the same image gets generated at widely different speeds.