×

Data Protection Policy

At LogikHaus, we take your privacy seriously. We are fully committed to protecting your personal information in compliance with Singapore's Personal Data Protection Act (PDPA) 2012.

How we handle your data:

For more information on your rights under Singapore Law, please visit:

→ Singapore Statutes Online (PDPA 2012) → DLA Piper Global Data Protection Guide (Singapore)

Guide

VHDL Design: A Practical Guide with Examples

How a VHDL design is structured, how to write VHDL that synthesises into the hardware you intended, how to verify it with a self-checking testbench, and the mistakes that trip up even experienced engineers.

What is VHDL design?

VHDL (VHSIC Hardware Description Language) is a language for describing digital hardware. It was developed for the US Department of Defense in the 1980s and is standardised as IEEE 1076, most recently revised in 2019. VHDL design means writing that description, verifying it in simulation, and synthesising it into real logic on an FPGA or ASIC.

The most important thing to understand is that VHDL is not a programming language in the usual sense. You are not writing instructions that run one after another; you are describing a circuit. Every concurrent statement is a piece of hardware that exists and operates at the same time as all the others. Good VHDL design starts from a picture of the hardware you want, then writes the code that describes it.

VHDL design is one part of the wider FPGA design flow, alongside architecture, synthesis, timing closure and bring-up. Our FPGA design guide covers that full flow; this guide focuses on the VHDL itself.

Anatomy of a VHDL design

Every VHDL design unit has the same basic structure:

  • Library and use clauses bring in standard types, most importantly ieee.std_logic_1164 for std_logic and ieee.numeric_std for arithmetic.
  • The entity is the block's interface: its generics (parameters) and ports (inputs and outputs). It is the equivalent of a chip's pinout.
  • The architecture is what the block does. It contains signal declarations and concurrent statements: processes, signal assignments and instances of other entities.

Inside an architecture, statements are concurrent: order does not matter, because they all describe hardware operating at once. Inside a process, statements are sequential and read top to bottom, but the process as a whole is still one piece of hardware running in parallel with everything else.

Signals vs variables

This is the concept that causes the most confusion for engineers coming from software.

  • Signals represent wires and registers. An assignment inside a process (<=) does not take effect immediately; the new value is scheduled and becomes visible only after the process suspends.
  • Variables exist only inside a process. An assignment (:=) takes effect immediately, like a software variable.
process (clk)
  variable v : unsigned(7 downto 0);
begin
  if rising_edge(clk) then
    a <= a + 1;   -- signal: new value visible on the next clock
    b <= a;       -- b gets the OLD value of a, so b lags a by one cycle
    v := x + 1;   -- variable: updated immediately
    c <= v;       -- c gets x + 1 on this clock edge
  end if;
end process;
a and b become two registers in a chain. The variable v is just an intermediate value inside the logic feeding c.

A practical rule: use signals for anything that is a register or crosses between processes, and use variables sparingly for intermediate calculations inside a single process.

Writing synthesisable VHDL

Only a subset of VHDL can be turned into hardware. Synthesis tools recognise specific coding patterns and map them to flip-flops, look-up tables, block RAM and DSP slices. Code that does not follow those patterns either fails to synthesise or, worse, synthesises into something different from what you simulated.

  • Use one clocked process template. A process sensitive only to the clock, with everything inside if rising_edge(clk) then, produces registers predictably.
  • Use numeric_std for arithmetic. Declare values as unsigned or signed. Avoid the non-standard std_logic_arith and std_logic_unsigned packages.
  • Assign every output on every path in combinational logic. Missing an assignment infers a latch.
  • Keep simulation-only constructs out of RTL. wait for 10 ns, after delays, file I/O and report statements are for testbenches. Synthesis ignores or rejects them.
  • Be deliberate about initial values. Most FPGAs honour signal initial values at configuration; ASICs do not. If the design may move to an ASIC, use an explicit reset.

State machines in VHDL

Finite state machines control almost every non-trivial design: protocol handlers, sequencers, and the control logic around datapaths. VHDL's enumerated types make them readable:

library ieee;
use ieee.std_logic_1164.all;

entity pulse_ctrl is
  port (
    clk   : in  std_logic;
    rst   : in  std_logic;
    start : in  std_logic;
    done  : in  std_logic;
    busy  : out std_logic
  );
end entity pulse_ctrl;

architecture rtl of pulse_ctrl is
  type state_t is (IDLE, RUN, FINISH);
  signal state : state_t := IDLE;
begin
  process (clk)
  begin
    if rising_edge(clk) then
      if rst = '1' then
        state <= IDLE;
      else
        case state is
          when IDLE   => if start = '1' then state <= RUN; end if;
          when RUN    => if done = '1' then state <= FINISH; end if;
          when FINISH => state <= IDLE;
        end case;
      end if;
    end if;
  end process;

  busy <= '1' when state = RUN else '0';
end architecture rtl;
A single-process state machine with an enumerated state type. The synthesis tool chooses the state encoding, and the output is decoded outside the process.

Verifying VHDL with a self-checking testbench

A testbench is VHDL that is never synthesised. It generates a clock, drives inputs into the design under test (DUT), and checks the outputs automatically. The example below tests the parameterised counter from our FPGA design guide:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity counter_tb is
end entity counter_tb;

architecture sim of counter_tb is
  signal clk   : std_logic := '0';
  signal rst   : std_logic := '1';
  signal en    : std_logic := '0';
  signal count : unsigned(7 downto 0);
begin
  clk <= not clk after 5 ns;  -- 100 MHz clock

  dut : entity work.counter
    generic map (WIDTH => 8)
    port map (clk => clk, rst => rst, en => en, count => count);

  stimulus : process
  begin
    wait until rising_edge(clk);
    rst <= '0';
    en  <= '1';
    for i in 1 to 10 loop
      wait until rising_edge(clk);
    end loop;
    en <= '0';
    wait until rising_edge(clk);

    assert count = 10
      report "Counter mismatch: expected 10, got " & integer'image(to_integer(count))
      severity error;

    report "Test finished";
    std.env.stop;  -- VHDL-2008
  end process;
end architecture sim;
The testbench releases reset, counts for ten clock cycles, then checks the result with an assert. It passes or fails on its own, with no waveform inspection needed.

For larger designs, hand-written checks quickly become unmanageable. OSVVM, a free, open-source VHDL verification library, adds transaction-level models, scoreboards, constrained-random stimulus and functional coverage, so VHDL teams get the same verification power that SystemVerilog teams get from UVM. Our own communications IP work relies on it.

VHDL-2008 features worth using

VHDL-2008 removed many of the language's old frustrations and is supported by current FPGA tools. Features that make everyday VHDL design easier:

  • process (all) builds the sensitivity list automatically, eliminating a whole class of simulation/synthesis mismatches in combinational logic.
  • Reading output ports is allowed, so you no longer need an internal copy of every output just to read it back.
  • Conditional assignments inside processes (x <= a when sel = '1' else b;) make sequential code more compact.
  • ieee.fixed_pkg provides synthesisable fixed-point types, which is valuable for DSP.
  • std.env.stop ends a simulation cleanly from the testbench.

Check your synthesis tool's settings: some default to an older VHDL standard until VHDL-2008 is enabled.

Common VHDL mistakes

  1. Incomplete sensitivity lists. Simulation and synthesis disagree: the simulator only re-evaluates on listed signals, while synthesis builds the logic regardless. Use process (all) for combinational processes.
  2. Unintended latches. A combinational process that does not assign a signal on every path infers a latch. Assign defaults at the top of the process.
  3. Multiple drivers. Assigning the same signal from two processes creates conflicting drivers. Each signal should be driven from one place.
  4. Mixing arithmetic packages. Using std_logic_arith alongside numeric_std causes ambiguous types and subtle errors. Use numeric_std only.
  5. Doing arithmetic on std_logic_vector. A vector has no numeric meaning on its own. Convert to unsigned or signed so the intent is explicit.
  6. Expecting after delays in RTL to mean anything. Synthesis ignores them. Timing comes from registers and constraints, not delay statements.
  7. Treating variables like registers. A variable read before it is written in a clocked process can infer a register unintentionally; one written before it is read cannot. Be deliberate about which you mean.

VHDL or Verilog?

Both describe the same hardware and every major FPGA toolchain supports both. VHDL's strong typing catches many mistakes at compile time that Verilog accepts silently, at the cost of more verbose code. In practice the right choice is usually the language your team, customer or existing codebase already uses. We compare them in more detail in our FPGA design guide.

Learn VHDL design, or have it done for you

Learn it: VHDL courses

LogikHaus Academy teaches VHDL hands-on, from VHDL for synthesis and simulations and testbenches to VHDL subprograms, with classes in Penang and Kuala Lumpur.

Browse VHDL courses

Hire it: VHDL design services

Our VHDL experts design and verify FPGA and ASIC hardware for video processing, DSP, communications and cryptography, with OSVVM and UVM verification built in.

Discuss your VHDL project

Frequently asked questions

What is VHDL design used for?

VHDL design is used to describe digital hardware such as FPGA designs, ASICs and IP cores. The VHDL description is simulated to verify it, then synthesised into real logic. It is common in video and signal processing, communications, and aerospace, defence and industrial systems.

Is VHDL hard to learn?

The syntax is verbose but learnable in a short time. The harder part is thinking in hardware: understanding that statements run in parallel, that signals update at the end of a process, and that every line describes a circuit. Hands-on practice with simulation and a real FPGA is the fastest way to build that intuition.

Is VHDL still used?

Yes. VHDL is an actively maintained IEEE standard, most recently revised as IEEE 1076-2019, and is supported by every major FPGA toolchain. It remains widely used in FPGA design, in Europe, and in aerospace, defence and safety-related industries.

What software do I need to write and simulate VHDL?

You need a simulator and, to target hardware, an FPGA vendor toolchain. GHDL is a free open-source VHDL simulator; vendor tools such as AMD Vivado, Altera Quartus Prime, Microchip Libero SoC and Gowin EDA include their own simulators and synthesis.

About the author. Daniel Kho is Founder and CTO of LogikHaus, with over 24 years in VHDL, FPGA and ASIC design. He builds LogikHaus's OSVVM and UVM verification frameworks and teaches the company's VHDL and FPGA courses.