nickg / nvc

VHDL compiler and simulator
https://www.nickg.me.uk/nvc/
GNU General Public License v3.0
635 stars 80 forks source link

Random initialization #1042

Open Blebowski opened 2 weeks ago

Blebowski commented 2 weeks ago

A VHDL simulation initializes value of signal to type'left. This may sometimes hide bugs on RTL, that later pop-out on GLS.

An example is FSM coded with enum type and first state being S_IDLE. VHDL simulation initializes a state register to S_IDLE. If state register is not reset, the RTL simulation will work correctly because FSM starts from correct state. On GLS or on real device, there is no guarantee that the FSM state vector will initialize to S_IDLE encoding.

This pops out in UPF flow simulations, where if a power domain with such FSM is disabled, the FSM will immediately become S_IDLE. Missing reset after re-enabling the domain will not be recognized.

What can be done on coding style level, is to define first state in enum type to something like S_UNDEFINED. Such state will be default power-up state. Only upon reset, the state vector will be initialized to S_IDLE. A state decoder will hide the S_UNDEFINED under when others => clause and either:

This approach helps, but it does not solve the problem. S_UNDEFINED is just a proxy state for RTL, that will be encoded into a state vector value by the synthesizer. So, the when others clause may not execute in real device. In real device, a post power-up value of a state register may be:

If it is valid state, the logic will behave as if the FSM was in that state. Likely, waiting for some "done signal" it will stay stuck forever.

If it is an invalid state, it can be protected by the when others => s_next <= S_IDLE coding approach.

This may sound like virtual issue, but I have seen it in reality and consequences were not nice.

On simulator level, what can be done, is to initialize signals randomly depending on some simulator settings (.e.g --init-signals=(lrm|random|0|1). I would propose following ways:

LRM compliant:

Random init

Fixed init (init_param = 0 or 1)

Any random initialization should be reproducible by means of --seed runtime argument. This guarantees reproducibility.

Verilator does similar thing since it does not support X.

nickg commented 2 weeks ago

I don't want to add and support too many non-standard features. You should be able to do this through a VHPI plugin, which would also have the advantage of being portable across different simulators.