How to pass time in SystemVerilog while waiting for data on a socket in DPI

We have a verification architecture that relies on sockets to communicate with a test application. This allows us to simulate with the same C++ hardware abstraction layer that we use in our product, significantly reducing integration time and bugs.

My question is this: Is it possible to pass simulation time while waiting on a socket in DPI? There is an obvious workaround (repeatedly making the imported DPI function call to query the state of the socket, then waiting for some time), but this has overhead and feels like a hack.

Starting a new thread that polls on the socket and then calls an exported DPI function to trigger an event would seem like a clean approach, but the new thread runs out of context and thus cannot make DPI calls.

Also, there does not seem to be a way to interact with a socket file descriptor directly in SystemVerilog.

Is there a clean way to achieve this, or do we need to settle for the above mentioned hack?

In reply to jwhatley:

The SystemVerilog DPI has nothing built-in for OS thread-safe event triggering. Even if it did, it’s unlikely to be any more efficient than the polling method you came up with, just a little more convenient.

If you are already using C++, you may want to consider using SystemC’s async_request_update() method, but that might be overkill for your needs.

In reply to jwhatley:

Hi jwhatley,

Would you be able to provide a sample code for the obvious workaround you talk of ?(repeatedly making the imported DPI function call to query the state of the socket, then waiting for some time)

I am trying to get multiple socket clients connected to a socket server linked to the simulator and I face issues like running out of context in a thread.

In reply to Madhusudhan:

Hi Madhusudhan,

On the SystemVerilog side, do something like this (in a separate thread for each socket):

do begin
int dpiResult = DpiReadFromSocket(fd_, rawTxn_, maxSize_, rawSize);
if (!dpiResult) #1000;
end while (!dpiResult && !stop_);

Then, in the C function DpiReadFromSocket(), just read from your socket and return your result. When you start your socket, you should have a DPI call from SystemVerilog that advertises a name or something to facilitate client connections and returns a file descriptor (int) that you can pass back in subsequent calls.

Also, the above waits 1000 time units, but it is arguably better to wait for clock edges instead.

Depending on how you run your tests, you may need to set your fd in C to non-blocking so you don’t hang the simulator waiting for socket activity:

fcntl(data_fd, F_SETFL, fcntl(data_fd, F_GETFL) | O_NONBLOCK);

I hope that helps!