When you are programming in a conventional language, you frequently want to update the value of a variable by logically masking it with a bit vector, e.g., x = x & "00001111";, or by adding it with another variable or constant, e.g., x = x + 1. It is implicit in these expressions that x is stored in memory. The update is performed by reading the value of x from memory, doing the logical or arithmetic operation, and storing the result back into the same memory location, overwriting the original value. In VHDL, because we are modeling hardware, memory must explicitly be represented by a clocked process. If you forget this (and everyone does, sometime), modeling errors will result.
For example, consider this trivial unclocked process,
process(y)
begin
y <= not(y);
end process;
In a conventional language, this would simply flip the bit y. But not in VHDL. An event on y activates the process. The bit is flipped, from ’0’ to ’1’, say, and the process suspends. But the flipping of y reactivates the process, and the bit is flipped from ’1’ to ’0’. This event again reactivates the process, and the bit is flipped from ’0’ to ’1’, and...you get the picture. The bit will not flip just once, but will oscillate between ’0’ and ’1’. In hardware, this process models connecting the output of an inverter back to its input. The output will oscillate at a rate determined by the propagation delay of the gate.
This kind of modeling error, in which the output of a combinational element is fed directly back to the input, is called a combinational loop. In this course there is no good reason for a combinational loop. It will always lead to a bug, and must always be avoided.
The correct way to replace y with its complement is to store it in a flip-flop. The Q output of the flip-flop is passed through an inverter, placing the complement of the bit at the D input of the flip-flop. On the rising clock edge, the value at D is stored at Q. In VHDL,
process(clk)
begin
if rising_edge(clk) then
y <= not(y);
end if;
end process;
Often, your design tool will give you a warning when it encounters a combinational loop. It will not throw an error, because combinational loops are not forbidden by the language. Thus, it is incumbent on the designer (that’s you) to read and heed the warning messages. If you fail to do so (and everyone does, sometime), a real error may occur farther along, during implementation, or the final hardware will exhibit a bug during physical testing, which is a bad place to discover a modeling error.
Figure 13.2.1 shows a variety of combinational loops, and their VHDL models. These are examples to be avoided, not emulated! But it is instructive to study, even simulate, a few of them to observe how they behave. It may help you spot a hardware error in the future.
Logic diagrams and the corresponding VHDL, for a few combinational loops.
Figure13.2.1.Examples of combinational loops (left), and how they are repaired by inserting a storage element (right).
, the combinational loops in Figure 13.2.1. Note the addition of a propagation delay in the VHDL model, which makes the simulation more closely resemble what would be observed in hardware. Modify the model to simulate and compare the combinational loop and the loop with flip-flop.