# Testbenches: simulating a design

*Driving inputs and checking outputs*

A VHDL testbench is a separate, non-synthesisable design that instantiates the circuit under test, applies a sequence of input stimuli over time, and uses assert statements to check the outputs, the textual equivalent of sweeping inputs and reading the waveform in a simulator.

Group: HDL
URL: https://digiwleea.wleeaf.dev/learn/vhdl-testbench/

You can now describe combinational logic with [concurrent assignments](https://digiwleea.wleeaf.dev/learn/vhdl-concurrent/) and sequential logic with a [clocked process](https://digiwleea.wleeaf.dev/learn/vhdl-process/). But how do you know your description is correct before committing it to a chip? The same way you check a circuit in the lab: drive the inputs and watch the outputs. In VHDL, the harness that does this is a **testbench**.

## What a testbench is

A **testbench** is itself a VHDL design, but a special one: it has an entity with **no ports** (nothing connects to the outside, it is a closed experiment) and it is **not synthesised**, it only runs in a simulator. Inside, it does three jobs: instantiate the design under test (your [entity](https://digiwleea.wleeaf.dev/learn/vhdl-entity/)), drive that design's inputs with a planned sequence of values over time (the **stimulus**), and check the outputs against what you expect.

> **TIP:** An analogy: the design is a component on a test bench in an electronics lab; the testbench is the signal generator wired to its inputs plus the meter watching its outputs. The component does not know it is being tested, exactly as your circuit on the canvas does not change when you sweep its inputs to read the truth table. The testbench is the lab bench, not part of the product.

## Stimulus and assert

A testbench uses two tools you have not met yet. The `wait for` statement advances simulated time (`wait for 10 ns;`), letting you set an input, wait, then check, which is how a static description gets a sense of "before and after". The `assert` statement checks a condition and complains if it fails: `assert F = '1' report "AND of 1,1 should be 1" severity error;`. If the output is wrong, the simulator prints your message, the textual version of a probe reading the wrong value.

```vhdl
library ieee;
use ieee.std_logic_1164.all;

entity and_gate_tb is
end entity;                         -- testbench has no ports

architecture sim of and_gate_tb is
  signal A, B, F : std_logic := '0';
begin
  -- instantiate the design under test
  dut : entity work.and_gate
    port map (A => A, B => B, F => F);

  -- drive inputs over time and check outputs
  process
  begin
    A <= '0'; B <= '0';
    wait for 10 ns;
    assert F = '0' report "0 and 0 should be 0" severity error;

    A <= '1'; B <= '1';
    wait for 10 ns;
    assert F = '1' report "1 and 1 should be 1" severity error;

    wait;                           -- stop: no more stimulus
  end process;
end architecture;
```

_A small testbench for the AND gate: it instantiates the design as dut (device under test), drives A/B through a couple of input combinations, waits, and asserts the expected output each time. Note the empty port list and that it is simulation-only, never synthesised._

The `port map (A => A, ...)` line wires the testbench's signals to the design's ports, the textual form of dropping the part on the canvas and connecting wires to its pins. The final bare `wait;` (no `for`) parks the process forever so the simulation stops after the last check instead of looping.

## Reading the result as a waveform

Run a testbench and the simulator produces a **waveform**: each signal drawn as a line over time, going high and low as your stimulus drives it, exactly the timing diagram you get from the lab's Waveform view. For combinational logic you are really just sweeping the [truth table](https://digiwleea.wleeaf.dev/learn/truth-tables/) over time; for a clocked design you watch the output change on each [rising edge](https://digiwleea.wleeaf.dev/learn/vhdl-process/), the same way you pulse a clock and read a flip-flop in the lab. The `assert`s turn that visual check into an automatic pass/fail.

> **WARN:** Do not try to synthesise a testbench, and do not put `wait for` or fixed time delays in the design you intend to build. `wait for 10 ns` and bare `wait` are **simulation-only**: they model the passage of time on the bench, but a real chip has no such delays to map onto. Keep stimulus and timing in the testbench; keep the synthesisable [entity](https://digiwleea.wleeaf.dev/learn/vhdl-entity/) free of them.

> **KEY:** Why this matters: in real hardware design you verify in simulation before you ever program a chip, because a bug found in a waveform costs minutes while a bug found in fabricated silicon costs a respin. The testbench is where that verification lives, and it is the same discipline you have used all along: drive the inputs, read the output, confirm it matches the truth table. You have been writing testbenches by hand on the canvas this whole time.

**Q (Check yourself):** Why does a testbench entity have an empty port list, while the design it tests (like `and_gate`) has ports?

**A:** The design under test is a reusable block, so it exposes ports to connect to the rest of a larger circuit. A testbench is a **self-contained experiment**: it generates its own input stimulus internally and checks the outputs internally, so nothing needs to cross its boundary. With no connections to the outside world, its entity needs no ports. It also is never synthesised, it only runs in the simulator.

### FAQ

**Q:** What is a testbench in VHDL?

**A:** A testbench is a VHDL design that verifies another design in simulation. It instantiates the design under test, drives its inputs with a planned sequence of values over time, and checks the outputs with assert statements. Its entity has no ports and it is never synthesised onto a chip.

**Q:** What does the assert statement do in a VHDL testbench?

**A:** assert checks a condition and, if it is false, prints a message with a severity level (note, warning, error, failure). For example 'assert F = '1' report "should be 1" severity error;' flags it when the output does not match the expected value, turning a manual waveform check into an automatic pass/fail.

**Q:** Why is a testbench not synthesisable?

**A:** A testbench uses simulation-only constructs like 'wait for 10 ns' to model the passage of time and to sequence stimulus. A real chip has no such delays to implement, so the testbench runs only in a simulator; only the design under test is synthesised onto hardware.

**Q:** How does a testbench relate to a waveform?

**A:** Running a testbench produces a waveform: each signal drawn over time as the stimulus drives it. It is the same timing diagram you read in a lab simulator, sweeping a combinational truth table over time or watching a clocked output change on each rising edge, with assert statements automating the pass/fail check.
