D-Flip-Flops (DFF) and latches
Remarks#
D-Flip-Flops (DFF) and latches are memory elements. A DFF samples its input on one or the other edge of its clock (not both) while a latch is transparent on one level of its enable and memorizing on the other. The following figure illustrates the difference:
Modelling DFFs or latches in VHDL is easy but there are a few important aspects that must be taken into account:
-
The differences between VHDL models of DFFs and latches.
-
How to describe the edges of a signal.
-
How to describe synchronous or asynchronous set or resets.
D-Flip-Flops (DFF)
In all examples:
clkis the clock,dis the input,qis the output,srstis an active high synchronous reset,srstnis an active low synchronous reset,arstis an active high asynchronous reset,arstnis an active low asynchronous reset,ssetis an active high synchronous set,ssetnis an active low synchronous set,asetis an active high asynchronous set,asetnis an active low asynchronous set
All signals are of type ieee.std_logic_1164.std_ulogic. The syntax used is the one that leads to correct synthesis results with all logic synthesizers. Please see the Clock edge detection example for a discussion about alternate syntax.
Rising edge clock
process(clk)
begin
if rising_edge(clk) then
q <= d;
end if;
end process;Falling edge clock
process(clk)
begin
if falling_edge(clk) then
q <= d;
end if;
end process;Rising edge clock, synchronous active high reset
process(clk)
begin
if rising_edge(clk) then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;Rising edge clock, asynchronous active high reset
process(clk, arst)
begin
if arst = '1' then
q <= '0';
elsif rising_edge(clk) then
q <= d;
end if;
end process;Falling edge clock, asynchronous active low reset, synchronous active high set
process(clk, arstn)
begin
if arstn = '0' then
q <= '0';
elsif falling_edge(clk) then
if sset = '1' then
q <= '1';
else
q <= d;
end if;
end if;
end process;Rising edge clock, asynchronous active high reset, asynchronous active low set
Note: set has higher priority than reset
process(clk, arst, asetn)
begin
if asetn = '0' then
q <= '1';
elsif arst = '1' then
q <= '0';
elsif rising_edge(clk) then
q <= d;
end if;
end process;Latches
In all examples:
enis the enable signal,dis the input,qis the output,srstis an active high synchronous reset,srstnis an active low synchronous reset,arstis an active high asynchronous reset,arstnis an active low asynchronous reset,ssetis an active high synchronous set,ssetnis an active low synchronous set,asetis an active high asynchronous set,asetnis an active low asynchronous set
All signals are of type ieee.std_logic_1164.std_ulogic. The syntax used is the one that leads to correct synthesis results with all logic synthesizers. Please see the Clock edge detection example for a discussion about alternate syntax.
Active high enable
process(en, d)
begin
if en = '1' then
q <= d;
end if;
end process;Active low enable
process(en, d)
begin
if en = '0' then
q <= d;
end if;
end process;Active high enable, synchronous active high reset
process(en, d)
begin
if en = '1' then
if srst = '1' then
q <= '0';
else
q <= d;
end if;
end if;
end process;Active high enable, asynchronous active high reset
process(en, d, arst)
begin
if arst = '1' then
q <= '0';
elsif en = '1' then
q <= d;
end if;
end process;Active low enable, asynchronous active low reset, synchronous active high set
process(en, d, arstn)
begin
if arstn = '0' then
q <= '0';
elsif en = '0' then
if sset = '1' then
q <= '1';
else
q <= d;
end if;
end if;
end process;Active high enable, asynchronous active high reset, asynchronous active low set
Note: set has higher priority than reset
process(en, d, arst, asetn)
begin
if asetn = '0' then
q <= '1';
elsif arst = '1' then
q <= '0';
elsif en = '1' then
q <= d;
end if;
end process;Clock edge detection
The short story
Whith VHDL 2008 and if the type of the clock is bit, boolean, ieee.std_logic_1164.std_ulogic or ieee.std_logic_1164.std_logic, a clock edge detection can be coded for rising edge
if rising_edge(clock) thenif clock'event and clock = '1' then -- type bit, std_ulogic or std_logicif clock'event and clock then -- type boolean
and for falling edge
if falling_edge(clock) thenif clock'event and clock = '0' then -- type bit, std_ulogic or std_logicif clock'event and not clock then -- type boolean
This will behave as expected, both for simulation and synthesis.
Note: the definition of a rising edge on a signal of type
std_ulogicis a bit more complex than the simpleif clock'event and clock = '1' then. The standardrising_edgefunction, for instance, has a different definition. Even if it will probably make no difference for synthesis, it could make one for simulation.
The use of the rising_edge and falling_edge standard functions is strongly encouraged. With previous versions of VHDL the use of these functions may require to explicitly declare the use of standard packages (e.g. ieee.numeric_bit for type bit) or even to define them in a custom package.
Note: do not use the
rising_edgeandfalling_edgestandard functions to detect edges of non-clock signals. Some synthesizers could conclude that the signal is a clock. Hint: detecting an edge on a non-clock signal can frequently be done by sampling the signal in a shift register and comparing the sampled values at different stages of the shift register.
The long story
Properly describing the detection of the edges of a clock signal is essential when modelling D-Flip-Flops (DFF). An edge is, by definition, a transition from one particular value to another. For instance, we can defined the rising edge of a signal of type bit (the standard VHDL enumerated type that takes two values: '0' and '1') as the transition from '0' to '1'. For type boolean we can define it as a transition from false to true.
Frequently, more complex types are used. The ieee.std_logic_1164.std_ulogic type, for instance, is also an enumerated type, just like bit or boolean, but it has 9 values instead of 2:
| Value | Meaning |
|---|---|
'U' |
Uninitialized |
'X' |
Forcing unknown |
'0' |
Forcing low level |
'1' |
Forcing high level |
'Z' |
High impedance |
'W' |
Weak unknown |
'L' |
Weak low level |
'H' |
Weak high level |
'-' |
Don’t care |
Defining a rising edge on such a type is a bit more complex than for bit or boolean. We can, for instance, decide that it is a transition from '0' to '1'. But we can also decide that it is a transition from '0' or 'L' to '1' or 'H'.
Note: it is this second definition that the standard uses for the
rising_edge(signal s: std_ulogic)function defined inieee.std_logic_1164.
When discussing the various ways to detect edges, it is thus important to consider the type of the signal. It is also important to take the modeling goal into account: simulation only or logic synthesis? Let us illustrate this on a few examples:
Rising edge DFF with type bit
signal clock, d, q: bit;
...
P1: process(clock)
begin
if clock = '1' then
q <= d;
end if;
end process P1;Technically, on a pure simulation semantics point of view, process P1 models a rising edge triggered DFF. Indeed, the q <= d assignment is executed if and only if:
clockchanged (this is what the sensitivity list expresses) and- the current value of
clockis'1'.
As clock is of type bit and type bit has only values '0' and '1', this is exactly what we defined as a rising edge of a signal of type bit. Any simulator will handle this model as we expect.
Note: For logic synthesizers, things are a bit more complex, as we will see later.
Rising edge DFF with asynchronous active high reset and type bit
In order to add an asynchronous active high reset to our DFF, one could try something like:
signal clock, reset, d, q: bit;
...
P2_BOGUS: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif clock = '1' then
q <= d;
end if;
end process P2_BOGUS;But this does not work. The condition for the q <= d assignment to be executed should be: a rising edge of clock while reset = '0'. But what we modeled is:
clockorresetor both changed andreset = '0'andclock = '1'
Which is not the same: if reset changes from '1' to '0' while clock = '1' the assignment will be executed while it is not a rising edge of clock.
In fact, there is no way to model this in VHDL without the help of a signal attribute:
P2_OK: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif clock = '1' and clock'event then
q <= d;
end if;
end process P2_OK;The clock'event is the signal attribute event applied to signal clock. It evaluates as a boolean and it is true if and only if signal clock changed during the signal update phase that just preceded the current execution phase. Thanks to this, process P2_OK now perfectly models what we want in simulation (and synthesis).
Synthesis semantics
Many logic synthesizers identify signal edge detections based on syntactic patterns, not on the semantics of the VHDL model. In other words, they consider what the VHDL code looks like, not what behavior it models. One of the patterns they all recognize is:
if clock = '1' and clock'event thenSo, even in the example of process P1 we should use it if we want our model to be synthesizable by all logic synthesizers:
signal clock, d, q: bit;
...
P1_OK: process(clock)
begin
if clock = '1' and clock'event then
q <= d;
end if;
end process P1_OK;The and clock'event part of the condition is completely redundant with the sensitivity list but as some synthesizers need it…
Rising edge DFF with asynchronous active high reset and type std_ulogic
In this case, expressing the rising edge of the clock and the reset condition can become complicated. If we retain the definition of a rising edge that we proposed above and if we consider that the reset is active if it is '1' or 'H', the model becomes:
library ieee;
use ieee.std_logic_1164.all;
...
signal clock, reset, d, q: std_ulogic;
...
P4: process(clock, reset)
begin
if reset = '1' or reset = 'H' then
q <= '0';
elsif clock'event and
(clock'last_value = '0' or clock'last_value = 'L') and
(clock = '1' or clock = 'H') then
q <= d;
end if;
end process P4;Note:
'last_valueis another signal attribute that returns the value the signal had before the last value change.
Helper functions
The VHDL 2008 standard offers several helper functions to simplify the detection of signal edges, especially with multi-valued enumerated types like std_ulogic. The std.standard package defines the rising_edge and falling_edge functions on types bit and boolean and the ieee.std_logic_1164 package defines them on types std_ulogic and std_logic.
Note: with previous versions of VHDL the use of these functions may require to explicitly declare the use of standard packages (e.g. ieee.numeric_bit for type bit) or even to define them in a user package.
Let us revisit the previous examples and use the helper functions:
signal clock, d, q: bit;
...
P1_OK_NEW: process(clock)
begin
if rising_edge(clock) then
q <= d;
end if;
end process P1_OK_NEW;signal clock, d, q: bit;
...
P2_OK_NEW: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif rising_edge(clock) then
q <= d;
end if;
end process P2_OK_NEW;library ieee;
use ieee.std_logic_1164.all;
...
signal clock, reset, d, q: std_ulogic;
...
P4_NEW: process(clock, reset)
begin
if reset = '1' then
q <= '0';
elsif rising_edge(clock) then
q <= d;
end if;
end process P4_NEW;Note: in this last example we also simplified the test on the reset. Floating, high impedance, resets are quite rare and, in most cases, this simplified version works for simulation and synthesis.
