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:
fires an error if the FSM is to be launched and its state is S_UNDEFINED, or
the transition from when others is encoded to go into S_IDLE.
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:
any of valid FSM states.
an invalid state depending on how FSM is encoded by synthesizer.
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:
As is now, the default behavior
Random init
Enum types are initialized to a run-time decided random value. An exception is std_logic family of types that initializes to either 0 or 1.
Integer types initialize to a random value within its valid range.
Fixed init (init_param = 0 or 1)
If init_param=0, all enum types are initialized to type'left. If init_param=1, all enum types are initialized to type'right. Exception is std_logic family of types that initialize to 0 or 1 based on init_param
Integer types initialize to type'low or to type'high based on init_param.
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.
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.
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 toS_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 toS_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 toS_IDLE
. A state decoder will hide theS_UNDEFINED
underwhen others =>
clause and either:S_UNDEFINED
, orwhen others
is encoded to go intoS_IDLE
.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, thewhen 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
std_logic
family of types that initializes to either0
or1
.Fixed init (init_param = 0 or 1)
init_param=0
, all enum types are initialized totype'left
. Ifinit_param=1
, all enum types are initialized totype'right
. Exception isstd_logic
family of types that initialize to0
or1
based oninit_param
type'low
or totype'high
based oninit_param
.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.