'quiet attributes are predefined in the VHDL standard and work on signal objects. We can use these special features in simulation to check that a signal’s value remains untouched for a given period.
Here’s the syntax for using ‘stable and ‘quiet:
Both attributes require a
time type value as an argument and return a
They will return a derived signal with the value
true if the base signal has remained quiet or stable for the given period before the current simulation time. Otherwise, the attributes return
The difference between the two is that stable only considers changes to the signal’s value, while quiet, on the other hand, senses all assignments, also when it doesn’t result in a new signal value.
When called sequentially, the attributes work like functions. We can, for example, print the instantaneous evaluation of
'stable by using the
report statement like this:
report "stable: " & boolean'image(sig'stable(50 ns));
If you are using ModelSim, the output to the simulator console will be:
# ** Note: stable: true # Time: 0 ps Iteration: 0 Instance: /stable_quiet_tb
Stable and quiet as derived signals
As we have seen, you can use these attributes like regular impure function calls, and they will appear to return a
boolean value. But in reality, they are producing a derived signal and not an instantaneous value.
When we type
sig'stable(50 ns), this whole expression is like a new signal of
boolean type, continuously updated with the result of the called attribute.
To demonstrate this, I’ve created a testbench with a
std_logic signal named
sig and two
architecture sim of stable_quiet_tb is signal sig : std_logic := '0'; signal stable_50_ns : boolean; signal quiet_50_ns : boolean; begin stable_50_ns <= sig'stable(50 ns); quiet_50_ns <= sig'quiet(50 ns);
Then, using two concurrent processes (shown above), we assign to the two
boolean signals using the
'quiet attributes. For both attributes, we use 50 nanoseconds as the stable/quiet time.
Furthermore, we’ll use a regular process to create some events on
sig to trigger changes in the two derived signals named
The initial value of
'0', but after 100 nanoseconds, we change it to
'1', as shown below. Then, after 100 more, we set it to
'1' again. But the signal’s value won’t change because it’s already
'1' at this point. And finally, we change
sig back to
'0' before pausing the process indefinitely.
process begin wait for 100 ns; sig <= '1'; wait for 100 ns; sig <= '1'; -- Assign the same value again wait for 100 ns; sig <= '0'; wait for 100 ns; wait; end process;
When we simulate the code above in ModelSim, it will produce this waveform:
The first event on
sig happens at 100 ns when it changes from
'1'. The two derived signals change from
false on the rising edge of the base signal because it’s no longer stable nor quiet. As we can see from the marked waveform section below, they remain
false for 50 ns before transitioning to
When the value of the base signal changes,
'quiet behave identically, but
'quiet can sense assignments that we cannot observe in the waveform.
For example, at the 200 ns mark shown below. We can’t see any change on
quiet_50_ns goes to
false. That’s because, in the code, we assigned the same value of
'1' once again to the signal. While
'stable ignores that,
'quiet senses the assignment and becomes
false for 50 ns.
Finally, we make
sig change from
'1' back to
'0', and we can see both attributes reacting:
Using the attributes within assert statements
Another way to use
'stable is within VHDL
assert statements. Typical use cases would be to verify pulse widths or setup and hold times. Check out my tutorial video below to see how we can use
'stable to check some assumptions about the timing on asynchronous interfaces!
In the tutorial video, I used a simplified verification component to spy on the device under test (DUT). You can see the two signals of interest coming in through the entity of this simulation module below.
entity spi_verification is port ( cs : in std_logic; sclk : in std_logic ); end spi_verification;
The first thing I checked was that the falling edge of
sclk wasn’t too close to the prior falling edge of
cs. This timing requirement comes from the datasheet of the analog-to-digital converter (ADC) I used in the SPI master VHDLwhiz Membership tutorial mentioned in the video.
It’s easy to check if a signal remained stable before a different one changed. Simply wait for the edge of the triggering signal and then run the assert on the other one, as shown in the process below.
process begin wait falling_edge(sclk); assert cs'stable(10 ns) report "Falling SCLK too close to falling Chip Select" severity failure; end process;
But we can’t use this method to check the pulse width of a discrete signal. That’s because if we wait for an event on signal A before checking,
A'stable(T) will always return
false. The signal is changing at that delta cycle and, thus, has remained stable for zero time.
A workaround is to create an additional helper signal delayed by one delta cycle from the signal of interest, as shown below. The concurrent assignment from
cs_delta copies the value in zero simulation time but creates an additional delta cycle delay on the copy. That’s just what we need!
architecture sim of spi_verification is signal cs_delta : std_logic; begin cs_delta <= cs;
Finally, we can create the pulse width checker process, which triggers on the falling edge of
cs. But instead of calling
cs itself, we use
cs_delta to check that the pulse width requirement is honored:
process begin wait until falling_edge(cs); assert cs_delta'stable(10 ns) report "Chip Select pulse too short" severity failure; end process;
The two signals are identical concerning simulation time, but
cs by one delta cycle. Therefore, it will still not have changed when the program executes the assertion line, and we can use it to verify the stability of the original
'stable to be one of the most helpful signal attributes for testbenches, and I often use it to verify interfaces’ timing. When dealing with complex hardware protocols, I usually move the checking code to a separate module like the verification component in this article.
On the other hand, I hardly ever use the
'quiet attribute. I feel that I’m making too many assumptions about the implementation of the DUT by using it. It doesn’t matter how many times you assign the same value to a signal in an RTL module. After synthesis, there are no signal assignments anyway, just logic.
Feel free to comment below if you know a good use case for