Skip to content
Volume V · The TensorCore.si Library

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.

Prologue

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.
Prologue

Set up and run your first program

Install GHDL, a free VHDL simulator, and GTKWave to view waveforms.

terminal
sudo apt install ghdl gtkwave
ghdl -a hello.vhd
ghdl -e hello
ghdl -r hello
hello.vhd
entity hello is
end entity;

architecture sim of hello is
begin
  process
  begin
    report "Hello, AI! Welcome to VHDL.";
    wait;
  end process;
end architecture;
TipVHDL is not case-sensitive. Comments start with --.
Chapter 1

Entities and architectures

An entity declares a block's ports; an architecture describes what it does. Concurrent signal assignments act like wires and gates.

half_adder.vhd
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;
Chapter 2

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.

mac8.vhd
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;
Chapter 3

Processes and clocks

A process with rising_edge(clk) describes registers. Signals update at the end of the process; variables update immediately.

counter.vhd
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;
Chapter 4

State machines with enums

Enumerated types make state machines readable and safe.

loader.vhd
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;
Chapter 5

Testbenches

A testbench entity has no ports. It creates a clock, drives inputs and uses assert and report to check results.

tb.vhd
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.vcd
Part II · AI with VHDL

VHDL 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

GHDLFree VHDL simulator.
cocotbPython testbenches for VHDL and Verilog.
hls4mlNeural networks to FPGA firmware.
AMD Vitis AIAI inference on AMD/Xilinx FPGAs.

A quantised neuron

Four INT8 inputs times INT8 weights, plus bias, then ReLU, the building block of an FPGA neural network.

neuron4.vhd
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;
Part III · Build an AI agent

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.

Your goal→Model plans→Tool call→Your code runs the tool→Result back to model→Final answer
agent.py
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.

Run it locallyInstall Ollama, run 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.
Part IV · Your path

VHDL learning roadmap

Tick items off as you go. Your progress is saved in this browser.

Beginner

Intermediate

Advanced

Part IV · Your path

Projects to build

Seven-segment counterShow a counter on an FPGA board display.
PWM controllerControl LED brightness or a motor.
FPGA neuronA small INT8 neural layer with a testbench.
Reference

VHDL cheat sheet

TaskSyntax
Signalsignal s : std_logic;
Busstd_logic_vector(7 downto 0)
Assigny <= a and b;
Clockedif rising_edge(clk) then ... end if;
Convertto_integer(unsigned(v))
Print (sim)report "x = " & integer'image(x);
Reference

Common mistakes

  • std_logic_vector has no arithmetic; convert to signed or unsigned first.
  • Missing signals in a combinational process's sensitivity list cause simulation mismatches (use process(all) in VHDL-2008).
  • Avoid the old std_logic_arith library; use numeric_std.
Reference

Where to go next

On TensorCore.si: Verilog volume, C volume.

Keyboard: [ previous language · ] next language · / search the library