digiwleeaLearn
Open the lab →

Processes and rising_edge

Describing logic that remembers

5 min read

A VHDL process is a block of statements that re-evaluates when a signal in its sensitivity list changes, and the pattern 'if rising_edge(clk)' inside it describes edge-triggered sequential logic, synthesising to a D flip-flop or register.

Build it in the lab →
A concurrent assignment describes combinational logic: output follows input, no memory. But a computer must remember, and from the D flip-flop you know memory comes from capturing a value on the clock edge. VHDL describes that with a process and the rising_edge test. This is how you write anything sequential: registers, counters, the accumulator of your CPU.

What a process is

A process is a block (process ... begin ... end process) that wakes up and re-evaluates whenever a signal in its sensitivity list (the names in process(clk)) changes. Inside the process, statements read top to bottom like software, which is why processes feel familiar, but the process as a whole is still one piece of hardware. For a clocked storage element, the only signal we care about is the clock, so the list is just process(clk).

rising_edge: capturing on the clock

Inside the process, if rising_edge(clk) then ... end if; is the magic phrase. rising_edge(clk) is true only at the instant clk goes from '0' to '1', the rising edge, exactly the one moment a D flip-flop samples. Any signal assigned inside that if is captured at the edge and held until the next one. This single pattern is the universal template for edge-triggered storage; synthesis turns it into actual flip-flops.
library ieee;
use ieee.std_logic_1164.all;

entity dff is
  port (
    clk : in std_logic;
    D : in std_logic;
    Q : out std_logic
  );
end entity;

architecture rtl of dff is
  signal q_r : std_logic := '0';
begin
  process(clk)
  begin
    if rising_edge(clk) then
      q_r <= D;
    end if;
  end process;
  Q <= q_r;
end architecture;
A D flip-flop as a clocked process. The internal signal q_r is the stored bit; it captures D on each rising edge and is then assigned out to the port Q. This is a template skeleton: digiwleea generates the entity and the process shell, and the body (q_r <= D) is the logic you fill in.
Read the architecture as hardware. The internal signal q_r is the flip-flop's stored bit (initialised to '0'). The process says: on every rising clock edge, load q_r with whatever D is at that instant. Outside the process, the concurrent line Q <= q_r wires the stored bit to the output port continuously. That mix is normal: the process is the sequential part, the final assignment is plain combinational wiring.
Why assign to an internal q_r and then to Q, instead of straight to Q? Because in classic VHDL an out port cannot be read back, and a flip-flop's next value sometimes depends on its current one (a counter does q_r <= q_r + 1). Keeping the state in a readable internal signal, then driving the port from it, is the standard, safe pattern. It mirrors the register bit holding its own value.

Why the if has no else

Notice there is no else. When clk is not rising, the if simply does not fire, so q_r keeps its old value, it remembers. In a process, a signal that is not reassigned holds its previous value, and that held value is exactly what makes it storage. An else branch here would describe combinational logic instead and break the flip-flop.
The classic beginner trap: writing if rising_edge(clk) then ... else ... end if; or testing a level (if clk = '1') instead of the edge. A level test describes a transparent latch (the D latch problem you already saw), not an edge-triggered flip-flop, and adding an else to a clocked process tends to create unintended latches the synthesis tool will warn about. For a register, use rising_edge(clk) with no else, and let the no-fire case hold state.
Why this matters: if rising_edge(clk) is the single most-used pattern in real VHDL, because every register, counter, and state machine in a synchronous design is built on it. The register, the program counter (counter), and the instruction register of your CPU are all this template, widened to many bits. Master it and you can describe any sequential circuit you built by hand.
The flip-flop the process describes. Open it in the lab and pulse the clock: Q captures D only on the rising edge, the hardware behind if rising_edge(clk).
Try it
Inside if rising_edge(clk) then q_r <= D; end if;, suppose clk is currently high and steady (no new edge) while D flips from 0 to 1. Does q_r change? Why?

Frequently asked

What is a process in VHDL?

A process is a block of statements that re-evaluates whenever a signal in its sensitivity list changes. Statements inside read top to bottom, but the process as a whole is one piece of hardware. It is how VHDL describes sequential (clocked) logic, as opposed to concurrent assignments which describe combinational logic.

What does rising_edge(clk) do in VHDL?

rising_edge(clk) is true only at the instant the clock goes from '0' to '1'. Used as 'if rising_edge(clk) then ...', it captures the assigned signals at that edge and holds them until the next rising edge, which is exactly a D flip-flop's behavior. Synthesis turns the pattern into real flip-flops.

Why is there no else in a clocked VHDL process?

When the clock is not rising, the if simply does not fire, so the signal keeps its previous value, which is what makes it storage. Adding an else would describe combinational logic and can create unintended latches, so a register uses 'if rising_edge(clk)' with no else.

How do you describe a D flip-flop in VHDL?

Put 'if rising_edge(clk) then q_r <= D; end if;' inside a process(clk), keep the state in an internal signal q_r, and drive the output port from it with a concurrent 'Q <= q_r'. That is the standard, synthesisable D flip-flop template.

You've got the theory. Now build it from scratch and watch it work.

Build it in the lab →
Found this useful? Share itShare on X