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) then
if clock'event and clock = '1' then -- type bit, std_ulogic or std_logic
if clock'event and clock then -- type boolean
and for falling edge
if falling_edge(clock) then
if clock'event and clock = '0' then -- type bit, std_ulogic or std_logic
if 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_ulogic
is a bit more complex than the simpleif clock'event and clock = '1' then
. The standardrising_edge
function, 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_edge
andfalling_edge
standard 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.
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:
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:
clock
changed (this is what the sensitivity list expresses) andclock
is '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.
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:
clock
or reset
or 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).
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 then
So, 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...
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_value
is another signal attribute that returns the value the signal had before the last value change.
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.