Sensitivity Lists and Simulation


If you are unfamiliar with the VHDL hardware description language (HDL) and are interested in knowing things like the difference between a signal and a variable, or the difference between a function and a procedure, please stay tuned.

As a starter, I thought I would explain the importance of the sensitivity list, which is employed in a VHDL process. At some point, everyone developing VHDL will end up writing something similar to the following lines of code to implement a simple two-stage synchronizer:

In this case, the “sync” signal acts as the output from this process. The “ip” signal is an input. That signal would be declared in the entity associated with the process, but that’s a topic for another column.

The “(reset,clock)” portion of the process is referred to as the sensitivity list. It contains the signals that will cause a simulation tool (e.g., ModelSim) to execute the process and update the signals. This is required because all processes are executed concurrently, so the simulation tool needs to know which processes need updating as its simulation cycle progresses.

In the example above, events occurring on the “reset” or “clock” signals will result in the process being executed. The process will execute sequentially, updating the “sync” signal on the rising edge of the clock.

For clocked processes such as the one presented here, the sensitivity list requires only the “reset” and “clock” signals. Any other signals that appear on the righthand side of the assignment operator (<=) in a clocked process do not need to be included in the sensitivity list. Their states are effectively being sampled on the edge of the “clock.” You could include both the “sync” and “ip” signals in the sensitivity list of the above process, but neither would be used unless any changes on them occurred at the same time as they were being sampled by the rising edge of the “clock.”

By comparison, in the case of combinatorial processes, it is necessary for the sensitivity list to include all the input signals used within the process if you wish to avoid potential issues. Consider a simple 4:1 multiplexer, for example.

Note that, in this case, the “op” signal is the output from the process. Once again, this signal would be declared in the entity associated with the process.

As you can see, this process will be executed whenever a change occurs on the “select_ip” signal (which is a two-bit signal, by the way) or when the values on the “a,” “b,” “c,” or “d” data inputs are updated.

This is the really important point. If we were to include only the “select_ip” signal in our sensitivity list, then we would have a problem. The result would still be legal VHDL. However, the simulator would not respond to any of the changes on the multiplexer’s data inputs. Even worse, the resulting gate-level representation generated by the synthesis tool would be different, because the synthesis engine looks not only at the sensitivity list, but also at the code to extract the behavior of the process when implementing the logic. (This is often referred to as behavioral extraction.)

The result would be a mismatch between the simulation of the original RTL (register transfer level) representation and the simulation of the gate-level representation generated by the synthesis engine. For this reason, the synthesis engine normally reports any signals missing from the sensitivity list that may result in a simulation mismatch. These warnings, which will appear in the synthesis log file, should be investigated and corrected, but it’s a lot easier to create your code in a way that ensures the problem never arises in the first place.