Skip to content

VHDL · Chapter 1.4 · Foundation

VHDL Design Units

A design unit is the smallest piece of VHDL the compiler analyses on its own. There are five of them, the entity, architecture, package, package body, and configuration, and understanding them is what turns writing a single file into structuring a real design. This lesson separates the source file, a text file on disk, from the design units inside it, which are the compile-time building blocks the language actually cares about. It shows how those units land in a library called work, explains the primary and secondary unit relationship that decides compile order, and makes clear why this structure drives organisation and reuse across a project.

Foundation13 min readVHDLDesign Unitswork libraryPackagesCompilation

1. Intuition — files vs building blocks

You write VHDL into a file (counter.vhd). But the VHDL language does not care about files — it cares about design units. A file is just a container; the compiler reaches inside and analyses each design unit it finds.

A useful analogy: a .vhd file is a shipping box, and the design units are the labelled parts inside it. You can put one part per box or several parts in one box — the factory (the compiler) unpacks them and files each part on a shelf in a library. From then on, the rest of the design refers to parts on shelves, not to boxes.

2. The five design units

Design unitWhat it isPrimary / secondary
entityThe external interface of a block (its ports and generics).Primary
architectureAn implementation of an entity — the logic inside.Secondary (belongs to an entity)
packageA shared header: types, constants, and subprogram declarations.Primary
package bodyThe implementations for a package's subprograms.Secondary (belongs to a package)
configurationA unit that binds an entity to a specific architecture.Primary

Primary units stand alone. Secondary units depend on a primary one: an architecture cannot exist without its entity, and a package body cannot exist without its package. That dependency is the whole reason compile order matters (§4).

3. What each looks like

Compact skeletons — just enough to recognise each unit by shape. (Packages get their own full lesson later; here we only need their silhouette.)

design-units.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
library ieee;
use ieee.std_logic_1164.all;
 
-- PRIMARY: entity — the interface
entity reg8 is
  port (
    clk : in  std_logic;
    d   : in  std_logic_vector(7 downto 0);
    q   : out std_logic_vector(7 downto 0)
  );
end entity reg8;
 
-- SECONDARY: architecture — an implementation OF reg8
architecture rtl of reg8 is
begin
  process (clk)
  begin
    if rising_edge(clk) then
      q <= d;
    end if;
  end process;
end architecture rtl;
types_pkg.vhd
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-- PRIMARY: package — shared declarations (the "header")
package types_pkg is
  constant WORD_W : integer := 8;
  function parity (v : std_logic_vector) return std_logic;
end package types_pkg;
 
-- SECONDARY: package body — the implementations (the "source")
package body types_pkg is
  function parity (v : std_logic_vector) return std_logic is
    variable r : std_logic := '0';
  begin
    for i in v'range loop
      r := r xor v(i);
    end loop;
    return r;
  end function;
end package body types_pkg;

A configuration (the fifth unit) names which architecture an entity should use when more than one exists. It is rare in everyday RTL, so we only name it here and return to it when it earns its place.

4. How units relate — file, library, and binding

Here is the relationship that actually matters in practice: a source file contains design units; the compiler analyses each unit into a library (the default one is called work); an architecture binds to its entity; and any unit can pull in a package with a use clause.

Source file contains design units that compile into the work library.vhd source filea containerentityinterfacearchitecturebinds → entitypackage (+ body)shared declswork librarycompiled units12
A .vhd source file holds one or more design units. Analysis compiles each unit into the work library. An architecture is bound to its entity (it implements that interface), and a package body is bound to its package. Other units reach shared declarations by importing the package with a `use` clause. The file is just a container — the library is what the rest of the design actually references.

That work library is why you write use work.types_pkg.all; to reach your own package, and use ieee.std_logic_1164.all; to reach the standard one: ieee and work are just two libraries, one provided, one yours.

5. Why no waveform here — a compile-time flow instead

Design units are a compile-time, structural concept. They have no signal values and no timing — there is literally nothing for a waveform to plot, because a waveform shows how signals change over simulated time, and design units exist before simulation even begins. Forcing a waveform onto this topic would teach nothing.

The artifact that does illuminate design units is the build flow — the order in which the tool processes them:

Analyse then elaborate then run — design units are processed before simulationAnalyseunits → work libraryElaboratebind entity+arch, resolvegenericsSimulate / Synthesizesignals & timing exist here12
Design units live on the compile-time side of the flow, not the run-time side. ANALYSE checks each unit's syntax and stores it in the work library (this is where primary-before-secondary order is enforced). ELABORATE walks the hierarchy, binds each entity to an architecture, and resolves generics into a concrete design. Only AFTER elaboration does a simulator or synthesizer run — which is the first point at which signals and timing (and therefore waveforms) exist.

6. Why design units matter

  • Organisation — splitting a chip into entities (one job each) keeps every unit small and testable.
  • Reuse — a package compiled once into a library is shared by every design that imports it; a verified entity is dropped into many designs.
  • Separate compilation — change one architecture and only its unit (and its dependents) need re-analysing, not the whole project.
  • Clear contracts — the entity/package declaration is the public face; the architecture/package body is the private implementation behind it.

7. Common mistakes & what to watch for

  • Confusing files with units. "It's in the file" is not the same as "it's compiled into the library." Tools track units, not filenames.
  • Compile order. A secondary unit cannot be analysed before its primary: compile the entity before its architecture, the package before its body, and a package before anything that uses it. Out-of-order analysis is a classic first-day error.
  • Forgetting the package body. A package that declares a function but has no body will compile yet fail to elaborate — the implementation is missing.
  • Trying to put an entity + architecture inside a package. A package holds declarations (constants, types, subprograms, component declarations) — not whole design entities.

8. Summary & next step

A design unit is the smallest thing VHDL compiles on its own. There are five — entity, architecture, package, package body, configuration — split into primary units and the secondary units that depend on them. Source files merely contain units; the compiler files them into a library (work), and compile order follows the primary-before-secondary rule. Because all of this is compile-time and structural, the right artifact is a build flow, not a waveform.

The most important pair of units is the entity and its architecture. The next lesson opens them fully: interface versus implementation, ports and their directions, and how one entity can have more than one architecture.