Loading header...

Introduction to VHDL

VHDL is a hardware description language used to describe digital hardware for FPGAs and ASICs. It is common in aerospace, industrial, medical, defense, telecom, and other long-lifecycle systems where reviewability matters as much as quick coding.

The most important beginner shift is this: VHDL is not a programming language that runs line by line on the FPGA. Synthesizable VHDL describes registers, lookup-table logic, memories, muxes, and connections that the FPGA tools build as hardware.

Learning Objectives

By the end of this lesson, you should be able to:

  • explain what VHDL is used for in an FPGA flow;
  • identify the entity, architecture, signal, process, and concurrent-assignment parts of a design;
  • distinguish synthesizable RTL from simulation-only testbench code;
  • explain why VHDL's strong typing catches real hardware mistakes;
  • read a small VHDL module and predict the hardware it creates.

Where VHDL Fits in the FPGA Flow

flowchart LR REQ["Requirement"] --> RTL["VHDL RTL"] RTL --> SIM["Simulation"] SIM --> SYN["Synthesis"] SYN --> PAR["Place and route"] PAR --> BIT["Bitstream"] BIT --> FPGA["Configured FPGA"] RTL --> TB["VHDL testbench"] TB --> SIM SYN --> RPT["Timing and resource reports"] PAR --> RPT

VHDL source is only one part of the design. A usable FPGA project also needs constraints, testbenches, timing review, pin planning, and board-level checks.

First Synthesizable Example

library ieee;
use ieee.std_logic_1164.all;

entity and_gate is
    port (
        a : in  std_logic;
        b : in  std_logic;
        y : out std_logic
    );
end entity and_gate;

architecture rtl of and_gate is
begin
    y <= a and b;
end architecture rtl;

The entity is the boundary of the hardware block: it lists the ports visible to the outside. The architecture is the implementation: it describes what hardware exists inside the boundary.

The assignment y <= a and b; is a concurrent assignment. It is active all the time, like a small piece of combinational logic wired between a, b, and y.

VHDL Building Blocks

VHDL part Hardware meaning Review question
entity block boundary and port directions Are the names, widths, and directions correct?
architecture implementation of that block Is it RTL, behavioral simulation, or structural wiring?
signal internal wire or registered value Is it driven by exactly the intended logic?
concurrent assignment continuously active combinational logic Does every input path produce the intended output?
clocked process flip-flops or registers Is the clock, reset, and enable structure clean?
package shared types, constants, and functions Is reuse explicit and version controlled?

Strong Typing Is a Hardware Safety Feature

VHDL makes you say what a signal means. A bus of bits is not automatically a number. For arithmetic, use unsigned or signed from ieee.numeric_std.

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

signal raw_count : std_logic_vector(7 downto 0);
signal count_u   : unsigned(7 downto 0);
signal next_u    : unsigned(7 downto 0);

count_u <= unsigned(raw_count);
next_u  <= count_u + 1;

The conversion looks verbose, but it prevents accidental arithmetic on a bus that might actually be an address, control field, or packed status word.

Synthesizable Code vs Testbench Code

Construct Typical purpose Synthesizes into FPGA hardware?
combinational assignment LUT logic, muxes, decoders yes
if rising_edge(clk) process flip-flops and registers yes
wait for 10 ns simulation delay no
assert ... report ... simulation and verification checks usually no
file I/O in a testbench stimulus and logging no
unconstrained time delays simulation model behavior no

Simulation-only code is not bad; it is essential for verification. The mistake is expecting simulation delays or testbench tasks to become physical FPGA timing.

Worked Example: Active-Low Button to LED

Many FPGA boards wire push buttons as active-low signals: unpressed reads 1, pressed reads 0. The following logic turns the LED on when the button is pressed.

library ieee;
use ieee.std_logic_1164.all;

entity button_led is
    port (
        button_n : in  std_logic;
        led      : out std_logic
    );
end entity button_led;

architecture rtl of button_led is
begin
    led <= not button_n;
end architecture rtl;

This describes one inverter. It does not wait, poll, or execute instructions. When button_n changes, the combinational path to led changes after real propagation delay.

Timing Mental Model

title "Combinational response, idealized"
time start=0 end=20 unit=ns divisions=10

BUTTON: square label="button_n" low=0 high=1 duty=45 cycles=1 unit=logic color=#2563eb
LED: square label="led = not button_n" low=1 high=0 duty=45 cycles=1 phase=0 unit=logic color=#dc2626

marker PRESS at=9 label="press"

This waveform is explanatory, not a measured simulation. Real boards add switch bounce, synchronizers, clocking, and electrical delay.

Exercise

Write a VHDL entity and architecture named two_switch_led.

Requirements:

  • inputs: sw0, sw1;
  • output: led;
  • behavior: led turns on only when both switches are on;
  • use std_logic ports;
  • write the Boolean expression in plain English.

Expected hardware: one two-input AND function implemented in FPGA LUT fabric.

Explained Solution

library ieee;
use ieee.std_logic_1164.all;

entity two_switch_led is
    port (
        sw0 : in  std_logic;
        sw1 : in  std_logic;
        led : out std_logic
    );
end entity two_switch_led;

architecture rtl of two_switch_led is
begin
    led <= sw0 and sw1;
end architecture rtl;

Plain English: the LED is on when switch 0 is on and switch 1 is on. If either input is off, the LED is off.

Common Mistakes

  • Treating VHDL statements as software instructions instead of hardware descriptions.
  • Using nonstandard arithmetic packages such as std_logic_unsigned instead of numeric_std.
  • Expecting wait for 10 ns to create a hardware delay.
  • Forgetting library ieee; use ieee.std_logic_1164.all;.
  • Mixing std_logic_vector, unsigned, and signed without explicit conversion.
  • Ignoring warnings about latches, multiple drivers, or width mismatch.

Summary

VHDL describes hardware structure and behavior for FPGA tools. Start with the entity and architecture split, use std_logic_1164 and numeric_std, and keep simulation-only constructs out of synthesizable RTL. VHDL feels strict because it makes hardware intent explicit.

Next: Entities, Architectures, Signals, and Types.

Further Reading

Mind Map

mindmap root((VHDL Intro)) Core concept Describes hardware Entity is boundary Architecture is logic RTL becomes FPGA fabric Applications FPGA control logic Industrial systems Aerospace designs Verification testbenches Design rules Use std_logic_1164 Use numeric_std Name ports clearly Separate RTL and testbench Practical checks Compile with simulator Review synthesis warnings Check port directions Confirm no testbench code in RTL Common mistakes Software mental model wait for in RTL Nonstandard packages Missing type conversions