To make co-simulation work, a specific type of PLI callback is
needed. The callback should be run when all pending events have been
processed, while allowing the creation of new events in the current
time step (e.g. by the MyHDL simulator). In some Verilog
simulators, the cbReadWriteSync callback does exactly
that. However, in others, including Icarus, it does not. The
callback's behavior is not fully standardized; some simulators run the
callback before non-blocking assignment events have been processed.
Consequently, I had to look for a workaround. One half of the solution
is to use the cbReadOnlySync callback. This callback runs
after all pending events have been processed. However, it does not
permit to create new events in the current time step. The second half
of the solution is to map MyHDL delta cycles onto real Verilog time
steps. Note that fortunately I had some freedom here because of the
restriction that only passive HDL code can be co-simulated.
I chose to make the time granularity in the Verilog simulator a 1000 times finer than in the MyHDL simulator. For each MyHDL time step, 1000 Verilog time steps are available for MyHDL delta cycles. In practice, only a few delta cycles per time step should be needed. Exceeding this limit almost certainly indicates a design error; the limit is checked at run-time. The factor 1000 also makes it easy to distinguish ``real'' time from delta cycle time when printing out the Verilog time.
About this document