steveicarus / iverilog

Icarus Verilog
https://steveicarus.github.io/iverilog/
GNU General Public License v2.0
2.81k stars 522 forks source link

VPI: vpi_put_value() to a WIRE is not sticky. #1041

Closed gatk555 closed 8 months ago

gatk555 commented 9 months ago

By sticky, I mean the behaviour described in the standard (I only have 2001, section 27.32 describes the function):

When vpi_put_value() is called for an object of type vpiNet or vpiNetBit, and with modes of vpiInertialDelay, vpiTransportDelay, vpiPureTransportDelay, or vpiNoDelay, the value supplied overrides the resolved value of the net. This value shall remain in effect until one of the drivers of the net changes value. When this occurs, the net shall be re-evaluated using the normal resolution algorithm

That does not happen. A minimal test case (attached) has an undriven wire whose value is copied to a register on a clock edge. The wire is set to 1 from VPI at the start of simulation, so my interpretation of the above is that the register value should become 1. It is z.

If vpiNoDelay is replaced by vpiForceFlag it works as expected. But that is no good if there are drivers on the wire. In my application it may be the avatar of an inout port of the top module (described here).

I tried to find out why this happens, but ran aground around line 1077 in net_vvp.h. Too much C++++++ for me!

test_case.zip

martinwhitaker commented 9 months ago

I agree, this does appear to be incorrect behaviour.

martinwhitaker commented 8 months ago

This happens because the start of simulation callbacks are being executed before the simulator performs its initial constant propagation. An undriven wire is connected to a constant Z, and that Z value gets propagated after the callbacks, replacing the value set by vpi_put_value(). I have a fix for this, but it is causing 3 failures in the test suite which I need to investigate.

gatk555 commented 8 months ago

Thank you for looking at it. Today, I tried digging a bit deeper and came to much the same conclusion, although I have not understood what is happening in schedule.cc. What I have found is that changing cbStartOfSimulation to cbNextSimTime fixes the problem in my demonstration code. I shall try that in my application code.

After looking at the documents I have, I am no longer convinced this is a bug. The timing of these callbacks relative to both initial blocks and implicit initialisations seems undefined. Perhaps later specifications are better at that.

martinwhitaker commented 8 months ago

The SystemVerilog simulation reference algorithm in IEEE 1800-2017 section 4.5 does indicate that all nets and variables are initialised before any events are executed, and in section 4.3 it does state that VPI callbacks are evaluation events.

It is different for an explicit initialisation (e.g. wire w = 1'b0 or assign w = 1'b0). Section 4.9.1 states that a continuous assignment process is also evaluated at time zero in order to propagate constant values. So there I think the execution order is non-deterministic.

Just to add to the complexity, there are different rules for nets with user-defined data types in section 6.7.3 . They are required to be initialised before any initial or always processes are started.

gatk555 commented 8 months ago

Verified with my reproduction cases and application. Many Thanks!

martinwhitaker commented 8 months ago

Closing as fixed by PR #1065.