VHDL
Strongly typed hardware design.
VHDL (VHSIC Hardware Description Language) describes digital circuits, like Verilog, but with a strict, Ada-like type system. It was created for the US Department of Defense and is widely used in Europe, aerospace, defence and FPGA design, including FPGA-based AI accelerators.
Why learn VHDL?
VHDL's strict typing catches mistakes early, which is why safety-critical hardware teams favour it.
- Strong types: the compiler rejects many wiring mistakes.
- Clear structure: separate entity (interface) and architecture (behaviour).
- FPGA AI: used to build custom inference pipelines on Xilinx/AMD and Intel FPGAs.
Set up and run your first program
Install GHDL, a free VHDL simulator, and GTKWave to view waveforms.
sudo apt install ghdl gtkwave
ghdl -a hello.vhd
ghdl -e hello
ghdl -r helloentity hello is
end entity;
architecture sim of hello is
begin
process
begin
report "Hello, AI! Welcome to VHDL.";
wait;
end process;
end architecture;--.Entities and architectures
An entity declares a block's ports; an architecture describes what it does. Concurrent signal assignments act like wires and gates.
library ieee;
use ieee.std_logic_1164.all;
entity half_adder is
port (a, b : in std_logic; sum, carry : out std_logic);
end entity;
architecture rtl of half_adder is
begin
sum <= a xor b;
carry <= a and b;
end architecture;Types and vectors
std_logic models a single wire; std_logic_vector a bus. Use numeric_std's signed and unsigned for arithmetic, with explicit conversions.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity mac8 is
port (a, b : in signed(7 downto 0);
acc_in : in signed(15 downto 0);
acc_out: out signed(15 downto 0));
end entity;
architecture rtl of mac8 is
begin
acc_out <= acc_in + (a * b); -- 8x8 -> 16-bit multiply-accumulate
end architecture;Processes and clocks
A process with rising_edge(clk) describes registers. Signals update at the end of the process; variables update immediately.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity counter is
port (clk, rst : in std_logic; count : out unsigned(7 downto 0));
end entity;
architecture rtl of counter is
signal c : unsigned(7 downto 0) := (others => '0');
begin
process (clk)
begin
if rising_edge(clk) then
if rst = '1' then c <= (others => '0');
else c <= c + 1;
end if;
end if;
end process;
count <= c;
end architecture;State machines with enums
Enumerated types make state machines readable and safe.
architecture rtl of loader is
type state_t is (IDLE, LOAD, COMPUTE);
signal state : state_t := IDLE;
begin
process (clk)
begin
if rising_edge(clk) then
case state is
when IDLE => if start = '1' then state <= LOAD; end if;
when LOAD => state <= COMPUTE;
when COMPUTE => if done = '1' then state <= IDLE; end if;
end case;
end if;
end process;
busy <= '0' when state = IDLE else '1';
end architecture;Testbenches
A testbench entity has no ports. It creates a clock, drives inputs and uses assert and report to check results.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity tb is end entity;
architecture sim of tb is
signal clk : std_logic := '0';
signal rst : std_logic := '1';
signal count : unsigned(7 downto 0);
begin
dut: entity work.counter port map (clk => clk, rst => rst, count => count);
clk <= not clk after 5 ns;
process begin
wait for 12 ns; rst <= '0';
wait for 100 ns;
report "count = " & integer'image(to_integer(count));
std.env.finish;
end process;
end architecture;
-- ghdl -a --std=08 counter.vhd tb.vhd && ghdl -r --std=08 tb --vcd=wave.vcdVHDL and AI hardware
FPGAs are used for low-latency AI inference in trading, telecom, cars and satellites. Designers build MAC arrays, quantised (INT8 or lower) neural network layers and streaming pipelines in VHDL or Verilog, or generate HDL from models with tools like hls4ml and AMD Vitis AI. Strong typing helps when every bit width matters.
The essential libraries
A quantised neuron
Four INT8 inputs times INT8 weights, plus bias, then ReLU, the building block of an FPGA neural network.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity neuron4 is
port (clk : in std_logic;
x0, x1, x2, x3 : in signed(7 downto 0);
y : out signed(19 downto 0));
end entity;
architecture rtl of neuron4 is
constant W0 : signed(7 downto 0) := to_signed(12, 8);
constant W1 : signed(7 downto 0) := to_signed(-7, 8);
constant W2 : signed(7 downto 0) := to_signed(25, 8);
constant W3 : signed(7 downto 0) := to_signed(3, 8);
constant B : signed(19 downto 0) := to_signed(-40, 20);
begin
process (clk)
variable s : signed(19 downto 0);
begin
if rising_edge(clk) then
s := resize(x0*W0, 20) + resize(x1*W1, 20) + resize(x2*W2, 20) + resize(x3*W3, 20) + B;
if s < 0 then y <= (others => '0'); else y <= s; end if; -- ReLU
end if;
end process;
end architecture;An agent that checks VHDL with GHDL
A local model can write or review VHDL more reliably when it can run the compiler and simulator. This agent gives it a GHDL tool.
import json, subprocess
from openai import OpenAI
def ghdl(files, top):
a = subprocess.run(["ghdl", "-a", "--std=08", *files], capture_output=True, text=True)
if a.returncode: return "Analysis error:\n" + a.stderr
r = subprocess.run(["ghdl", "-r", "--std=08", top], capture_output=True, text=True, timeout=30)
return r.stdout + r.stderr
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
tools = [{"type": "function", "function": {"name": "ghdl", "description": "Analyse and run a VHDL testbench",
"parameters": {"type": "object", "properties": {"files": {"type": "array", "items": {"type": "string"}},
"top": {"type": "string"}}, "required": ["files", "top"]}}}]
messages = [{"role": "user", "content": "Run the testbench tb with counter.vhd and tb.vhd and report the count."}]
for _ in range(5):
msg = client.chat.completions.create(model="llama3.1", messages=messages, tools=tools).choices[0].message
messages.append(msg)
if not msg.tool_calls:
print(msg.content); break
for c in msg.tool_calls:
messages.append({"role": "tool", "tool_call_id": c.id, "content": ghdl(**json.loads(c.function.arguments))})GHDL's report lines appear in the output, so the model can read the result directly.
ollama pull llama3.1, and keep it running. The code talks to its OpenAI-compatible API at http://localhost:11434/v1, so the same program also works with vLLM, llama.cpp server or a cloud API by changing the URL, model name and adding an API key.VHDL learning roadmap
Tick items off as you go. Your progress is saved in this browser.
Beginner
Intermediate
Advanced
Projects to build
VHDL cheat sheet
| Task | Syntax |
|---|---|
| Signal | signal s : std_logic; |
| Bus | std_logic_vector(7 downto 0) |
| Assign | y <= a and b; |
| Clocked | if rising_edge(clk) then ... end if; |
| Convert | to_integer(unsigned(v)) |
| Print (sim) | report "x = " & integer'image(x); |
Common mistakes
std_logic_vectorhas no arithmetic; convert tosignedorunsignedfirst.- Missing signals in a combinational process's sensitivity list cause simulation mismatches (use
process(all)in VHDL-2008). - Avoid the old
std_logic_arithlibrary; usenumeric_std.
Where to go next
- VHDLwhiz — tutorials
- GHDL — simulator docs
- Nandland VHDL — beginner guide
On TensorCore.si: Verilog volume, C volume.
Keyboard: [ previous language · ] next language · / search the library