Skip to content

Writing Testbenches

A testbench drives stimulus into your design and lets you observe the results. It’s a VHDL entity with no ports — it’s self-contained.

library ieee;
use ieee.std_logic_1164.all;
entity my_tb is
end my_tb;
architecture testbench of my_tb is
-- 1. Declare signals to wire up to the design
signal clk_tb : std_logic := '0';
signal data_tb : std_logic_vector(7 downto 0);
begin
-- 2. Instantiate the design under test
uut: entity work.my_design
port map (
clk => clk_tb,
data => data_tb
);
-- 3. Drive stimulus
process
begin
data_tb <= x"00";
wait for 10 ns;
data_tb <= x"FF";
wait for 10 ns;
wait; -- end simulation
end process;
end testbench;

A bare wait; (no time argument) stops the process forever. Without it, the process restarts from the top and loops infinitely.

process
begin
-- stimulus here...
wait; -- required!
end process;

Map each port explicitly by name:

port map (
input_a => sig_a,
input_b => sig_b,
output => sig_out
);

Signals default to 'U' (uninitialized) unless you provide a value. Set defaults to avoid unexpected behavior:

signal sel_tb : std_logic := '0';
signal bus_tb : std_logic_vector(7 downto 0) := x"00";

Use wait for to advance simulation time between stimulus steps:

process
begin
sel <= '0';
wait for 10 ns; -- hold sel='0' for 10 ns
sel <= '1';
wait for 10 ns; -- hold sel='1' for 10 ns
wait;
end process;

Set your CLI --run-time or web app run time to at least the sum of all your wait for durations.

If your design uses sub-components, pass all files to nexsim. Order doesn’t matter.

Terminal window
nexsim sub_module.vhd top.vhd top_tb.vhd --top top_tb --run-time 5000

In the web app, load all the files before selecting the top entity.

  • Name your testbench signals with a _tb suffix to distinguish them from the DUT’s ports
  • Test edge cases: all zeros, all ones, boundary conditions
  • Use systematic test patterns — step through all input combinations for small designs
  • Check the Examples page for complete working testbenches