It is better to fix x's in the simulation or in the design?

I have a question about how to deal with x's in Verilog netlist simulations. I have a disagreement with another engineer (who is a bit more senior than I am) about what the right approach is. Although this question might seem opinion based, I do think there is a right answer even if the views are divided.

I do development for mixed-signal ASICs. I'm doing netlist simulations of a microprocessor which doesn't have it's program registers reset (it's an ARM Cortex-M3, there is an option to not have the registers reset during synthesis).

We have a ROM which the processor starts executing from after reset. During that program execution, one program register (R6) has x's in it because it wasn't reset. At a point in the simulation, x's from that register spread like wildfire through the rest of the design, and breaks the simulation. We don't see this issue in RTL simulations.

I would prefer to make a design change to cause the registers to be reset or to have the ROM program write zeros to those registers first thing. My college is very resistant to making any design change to clear out these x's, and he would prefer to mask them in the simulation somehow.

His contention is that the "x's aren't real because x's don't exist in real hardware". He therefore concludes that the x's in the simulation aren't real, and that any design changes based on these is not a good thing, or at lest, way too extreme of a response.

My contention is that although it is undoubtedly true that x's don't exist in hardware, they represent unknown or unpredictable values. I believe the gate library models x's to propagate pessimistically. Therefore, if x's are propagating to kill the simulation, it suggests there could be a combination of bits that would cause a problem. Since that is a possibility, I don't see making a design change to clear the x's as being too extreme, even if I can't prove they are absolutely real. (I suppose I could try a search for the bad combination of bits, but that would be a lot of work.)

Now, I can imagine an answer that the right approach depends on the type of quality that is being developed here. But, I think that the design changes I've suggested (adding in the resets or clearing them in the program) cost very little (especially modifying the ROM program). I think that going through the process of masking the bits in the simulation would be much more labor intensive.

What could I be misunderstanding from his point-of-view? What is the best approach? Is it really so bad to make a design change for a problem you can't prove is absolutely real?

• The time wasted debugging x's in gate simulations is real. "Design For Verification" should be a consideration. Fix it in the design now, and you need not waste the time again on the next product which reuses the design (and the next, and the next...) – toolic Nov 24 '15 at 0:24

I suppose it depends on where the x's are in the design.

Take an example communication scheme within the chip. You may want to pass data around between two components, but lets say not on every clock cycle. You might decide then to have a data bus and a valid signal. The valid signal says when the data is valid. Because of this, whenever the valid signal is low, the value of the data signal doesn't matter (because it is ignored).

In this example as long as the valid signal is never a don't-care, the design will never do anything unexpected. The data signal can be don't-care, it doesn't really matter, because you always know that there will be valid data (whatever it is) when the valid signal is high.

If the valid signal was ever don't-care, then you do have a problem. Why? because it means you have some scenario where you have no idea what will happen. This may or may not cause an issue, but boy is it a nightmare to track down.

So, with that in mind, it is my opinion that:

If you come across x's in a data bus, it isn't the end of the world, in reality you don't know what the data will be at any given time anyway.

If they appear in control signals it may or may not be bad, you don't know. In this situation you should run your simulation twice, once making sure that the don't care is forced to be 0, and a second time making sure it is a 1. This way you know what will happen in both cases.

If you cannot be certain (i.e. from the code you have written) that a don't care wont cause issues, then you should not ignore it, x is an unknown potential disaster. If you know that the value at any given point doesn't matter, then x is perfectly valid.

Also, all control registers, whatever they are for, should be initialised to a value at reset. An uninitialised control register at power on could be disastrous. Imagine you make a control system for launching nuclear weapons and didn't initialise the 'launch' register to 0. For all you know when you turn the power on you could start WW3.

There are many different causes for the X state in a simulation but unfortunately they are all represented by one state in Verilog. VHDL has the U state to represent an uninitialized value. That may not have a physical representation in hardware, but is certainly a real property of a hardware design in addition to the voltage level of signal.

Accurate propagation of the X state is a difficult in dynamic simulation for any RTL or netlist. You may want to look at formal tools for this purpose - especially for reset checking. They are well suited for this application for exhaustively proving all combinations.

As far as the cost associated with adding reset logic, designs are always at some sort of limit in their specification; power, area, features. So you certainly don't want to add unnecessary logic to to make your net list simulation work. Some simulators allow you to randomly initialize logic, so you can at least get some level of confidence before you try to mask out the X's.

If you're running code generated by a 'C' compiler (rather than raw assembler) on an ARM core, you're likely to have problems with netlist simulations unless you start by initialising the register bank. Depending on how aggressive the compiler has been, you might need to initialise all state (and this then starts getting risky).

The most obvious problem is that flag-setting operations on in-initialised registers will move a fairly harmless data-path X into the control path in a way that isn't always harmless. This isn't something that should happen in sensibly hand-written code, but the 'C' compiler is (I think) at liberty to re-order operations and sometimes do things where it will ignore the result. The RTL will behave consistently if it's given arbitrary numeric input, but sometimes reacts badly if it's given X as a data value.

As soon as you have prefetch logic which is exposed to X data, it's not hard to imagine that more control logic can generate an X result instead of a fast/slow type of performance behaviour.

RTL is frequently written to be X-pessimistic, so any X values (that represent don't know values) will be passed through a design.

If your tests run without initialising the register bank to 0 in your init code, keep it like that. You're more likely to detect a problem this way (like running off the code image into executing data). Don't despair if you have to initialise some registers in software just to run on a netlist though.

If you find your netlist needs all flops initialised at reset, you need to check the core documentation (Integration manual) and follow up with support if necessary.

To support this view, look in the boot code provided with the execution testbench. If there are some zero-initialisations there, you'll need them for netlist simulation (but probably not in real silicon).