Exercise: VHDL Counter and Testbench
This exercise makes VHDL feel real: write a small hardware block, then write a testbench that proves the reset, enable, count, and wrap behavior.
Learning Objectives
You will practice:
- writing synthesizable VHDL;
- building a clocked counter;
- using assertions in a testbench;
- running a simulation before hardware.
Task
Create counter4.vhd:
- inputs:
clk,rst,en; - output:
count : std_logic_vector(3 downto 0); - synchronous reset;
- count increments only when
en = '1'; - wraps naturally from 15 to 0.
Design Code
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity counter4 is
port (
clk : in std_logic;
rst : in std_logic;
en : in std_logic;
count : out std_logic_vector(3 downto 0)
);
end entity;
architecture rtl of counter4 is
signal count_r : unsigned(3 downto 0);
begin
process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
count_r <= (others => '0');
elsif en = '1' then
count_r <= count_r + 1;
end if;
end if;
end process;
count <= std_logic_vector(count_r);
end architecture;
Testbench Sketch
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity counter4_tb is
end entity;
architecture tb of counter4_tb is
signal clk : std_logic := '0';
signal rst : std_logic := '1';
signal en : std_logic := '0';
signal count : std_logic_vector(3 downto 0);
begin
clk <= not clk after 5 ns;
dut : entity work.counter4
port map (
clk => clk,
rst => rst,
en => en,
count => count
);
process
begin
wait for 20 ns;
rst <= '0';
en <= '1';
wait for 10 ns;
assert count = "0001" report "counter did not increment" severity error;
wait for 150 ns;
assert count = "0000" report "counter did not wrap as expected" severity error;
assert false report "test complete" severity note;
wait;
end process;
end architecture;
Suggested GHDL Commands
ghdl -a counter4.vhd
ghdl -a counter4_tb.vhd
ghdl -e counter4_tb
ghdl -r counter4_tb --vcd=counter4.vcd
gtkwave counter4.vcd
Verification Checklist
- Reset holds count at zero.
- Enable low holds the previous value.
- Enable high increments once per rising edge.
- Count wraps from
1111to0000. - Testbench fails if the design is wrong.
Extension Challenge
Add a terminal_count output that is high when count equals 15. Decide whether it should be combinational or registered, then explain the tradeoff.
Common Mistakes
- Checking output before the next rising clock edge.
- Forgetting that signal updates happen after the process suspends.
- Using arithmetic without
numeric_std. - Writing a testbench that only generates waveforms but checks nothing.
Summary
This exercise reinforces the VHDL loop: write synthesizable RTL, analyze it, elaborate the testbench, run the simulation, inspect waveforms, and use assertions to catch errors.
Next: Packages, numeric_std, and Project Structure.
Further Reading
- GHDL quick start
- GTKWave manual
- VHDL assertion examples
Mind Map
mindmap
root((VHDL Counter Exercise))
Core concept
Counter increments
Testbench checks sequence
Reset then count
Applications
Applications
Clocked verification
Reusable counter
Checks
Design checks
Expected count
Wrap behavior
Common mistakes
Wrong range
Common mistakes
No wait for edge