VHDL Cheat Guide for Beginners: Essential Tips and Examples
What VHDL is — quickly
VHDL (VHSIC Hardware Description Language) models digital hardware at multiple abstraction levels. It describes structure and behavior so synthesis tools can map designs to FPGAs/ASICs. Think of it as code that defines circuits rather than sequential programs.
File and basic structure
- Entity: External interface (ports).
- Architecture: Internal implementation (behavior/structure).
- Library/use: Include standard packages (e.g., IEEE). Minimal template:
vhdl
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity my_module is port ( clk : in std_logic; rst_n : in std_logic; a : in std_logic_vector(7 downto 0); y : out std_logic_vector(7 downto 0) ); end my_module; architecture rtl of my_module is begin – implementation end rtl;
Common types
- std_logic — single-valued digital signal (0,1,Z,X,…).
- std_logic_vector(N downto 0) — bus of bits.
- signed / unsigned — arithmetic vectors (from IEEE.NUMERIC_STD).
- integer, boolean — for simulation and synthesis-limited uses.
Always prefer IEEE.NUMERICSTD for arithmetic:
vhdl
use IEEE.NUMERIC_STD.ALL; signal asigned : signed(7 downto 0);
Combinational vs. sequential coding
- Combinational: outputs update whenever inputs change. Use concurrent assignment or combinational process with all signals in sensitivity list.
vhdl
– concurrent y <= a and b; – combinational process process(a, b) begin if a = ‘1’ then y <= b; else y <= ‘0’; end if; end process;
- Sequential (clocked): state changes on clock edge. Use risingedge(clk) or clk’event and clk = ‘1’.
vhdl
process(clk, rst_n) begin if rst_n = ‘0’ then q <= (others => ‘0’); elsif rising_edge(clk) then q <= d; end if; end process;
Reset styles
- Synchronous reset: checked inside clock edge.
- Asynchronous reset: checked before edge in process sensitivity. Prefer one style consistently per design and follow target FPGA vendor recommendations.
Vectors and slicing
- Concatenate: x <= a & b;
- Slice: part <= vec(7 downto 4);
- Resize/convert with numericstd:
vhdl
c <= std_logic_vector(resize(a_signed, 16));
Arithmetic tips
- Convert std_logicvector ↔ signed/unsigned for math:
vhdl
signal a, b : std_logic_vector(7 downto 0); signal sum : std_logic_vector(8 downto 0); sum <= std_logic_vector(unsigned(a) + unsigned(b));
- Avoid arithmetic on std_logicvector directly.
State machines
- Use enumerated types for states.
- Two-process FSM (one for state register, one for next-state/outputs) is clear and synthesis-friendly. Example:
vhdl
type state_t is (IDLE, LOAD, RUN); signal state, next_state : state_t; – state register process(clk, rst_n) begin if rst_n = ‘0’ then state <= IDLE; elsif rising_edge(clk) then state <= next_state; end if; end process; – next-state logic process(state, start) begin case state is when IDLE => if start = ‘1’ then next_state <= LOAD; else next_state <= IDLE; end if; when others => next_state <= IDLE; end case; end process;
Clock domain crossing (CDC) basics
- Avoid direct transfers between different clock domains.
- Use synchronizer flip-flops for single-bit signals.
- Use FIFOs for multibit data crossing domains.
Testbenches and simulation
- Testbench has no ports; instantiate DUT and drive stimuli.
- Use assert statements for checks; use wait for and process timing. Simple testbench skeleton: “`vhdl entity tb_my_module is end tb_my_module;
architecture sim of tb_my_module is signal clk : std_logic := ‘0’; begin clk_gen: process begin