The vast majority of VHDL designs uses clocked logic, also known as synchronous logic or sequential logic. A clocked process is triggered only by a master clock signal, not when any of the other input signals change.
The basic building block of clocked logic is a component called the flip-flop. There are different variants of it, and in this tutorial we are going to focus on the positive-edge-triggered flip-flop with negative reset:
The flip-flop is a sample-and-hold circuit, meaning that it copies the value from the input to the output when the rising edge of the clock signal arrives. The output is then held stable at the sampled value until the next rising edge of the clock, or until the reset signal is pulsed.
This blog post is part of the Basic VHDL Tutorials series.
All clocked processes are triggered simultaneously and will read their inputs at once. At the same time, they will output the results from the last iteration. The clock signal effectively creates timesteps in the data flow. This makes it manageable for the designer to create complex, deep logic. He or she can break down the actions of the algorithm into events that happen on the clock cycles.
Flip-flops or arrays of flip-flops are sometimes referred to as registers, it is the same thing.
The sensitivity list for clocked processes usually contains only the clock signal. This is because a clocked process is triggered only by a flank on the clock signal, the other input signals won’t cause it to wake up at all.
This is a template for creating a clocked process with synchronous reset:
if rising_edge(Clk) then
if nRst = '0' then
<reset all output signals here>
<main logic here>
In this video tutorial we will learn how to create a clocked process in VHDL:
The final code for flip-flop testbench:
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T17_ClockedProcessTb is end entity; architecture sim of T17_ClockedProcessTb is constant ClockFrequency : integer := 100e6; -- 100 MHz constant ClockPeriod : time := 1000 ms / ClockFrequency; signal Clk : std_logic := '1'; signal nRst : std_logic := '0'; signal Input : std_logic := '0'; signal Output : std_logic; begin -- The Device Under Test (DUT) i_FlipFlop : entity work.T17_FlipFlop(rtl) port map( Clk => Clk, nRst => nRst, Input => Input, Output => Output); -- Process for generating the clock Clk <= not Clk after ClockPeriod / 2; -- Testbench sequence process is begin -- Take the DUT out of reset nRst <= '1'; wait for 20 ns; Input <= '1'; wait for 22 ns; Input <= '0'; wait for 6 ns; Input <= '1'; wait for 20 ns; -- Reset the DUT nRst <= '0'; wait; end process; end architecture;
The final code for the flip-flop module:
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity T17_FlipFlop is port( Clk : in std_logic; nRst : in std_logic; -- Negative reset Input : in std_logic; Output : out std_logic); end entity; architecture rtl of T17_FlipFlop is begin -- Flip-flop with synchronized reset process(Clk) is begin if rising_edge(Clk) then if nRst = '0' then Output <= '0'; else Output <= Input; end if; end if; end process; end architecture;
The waveform window in ModelSim after we pressed run, and zoomed in on the timeline:
We can see from the waveform that the output signal is only updated on each rising edge of the clock signal. The input signal is sampled only when the clock signal changes from ‘0’ to ‘1’. The negative dip of the input signal starting at about 45 ns is completely lost. It’s not copied to the output because it’s in between two rising edges of the clock, and therefore it is ignored.
This animation illustrates how the output reacts to the changing input and clock signals:
The vertical lines indicate how the input signal is relative to the rising edges of the clock.
Pay special attention to the one positive pulse on the input signal starting at 20 ns. It’s synchronous to the clock and exactly one clock period long. The output doesn’t react instantaneously, it’s delayed by one clock period.
When I was learning VHDL I found this particularly hard to understand. The rising edge of the clock is synchronous with the input’s rising edge, so how can the flip-flop choose one value or the other?
The simulator uses timesteps to model events in a predictable way, and signals propagate in zero time. Because the flip-flop reads the input in the exact same timestep as it updates the output, it sees the old value of the input and copies it to the output.
I should add to this answer that this isn’t really how it works. In the physical world, a signal needs time to propagate, we don’t know exactly when it arrives at the flip-flop. These propagation delays are estimated automatically for us by the software process (place and route) which converts the VHDL code into a netlist.
In reality, the input must be held stable for a few nanoseconds before and after the rising clock edge:
These critical time periods are known as setup and hold time. Fortunately, this is not something you normally have to take into consideration. When working purely with clocked logic, these problems are handled by the software which turns the VHDL code into a netlist.
- Clocked processes with synchronized reset only have the clock signal on the sensitivity list
if rising_edge(Clk)ensures that the process only wakes up on rising edges of the clock
- In a synchronous design, stuff only happens at active the clock edge