VHDL · Chapter 10.4 · Packages and Reuse
Libraries, work, and Compilation Order
VHDL does not just compile files, it analyses design units into libraries, and the order matters. Your own units land in the work library by default, the ieee library holds the standard packages every file imports, and tool vendors provide their own. The iron rule is dependency order: a unit must be analysed before anything that references it, so a package comes before the modules that use it, an entity comes before the architecture that instantiates it, and a package declaration comes before any code that needs it. Get the order wrong and you hit the classic used-before-analysed error. This lesson explains what libraries are, why compilation order is really a dependency graph you walk from leaves to roots, and how to organise a project so it builds cleanly every time.
Foundation13 min readVHDLLibrariesworkCompilation OrderAnalysisProject
1. Engineering intuition — you cannot use what is not yet known
Compiling VHDL is like reading a book where every reference must point to something already written. When the
analyser reaches a module that says use work.bus_pkg.all, that package must already be in the library — if it
has not been analysed yet, the reference dangles and analysis fails. So the order in which you analyse units is
not arbitrary: each unit must come after everything it depends on. Think of it as a dependency graph that you
must walk from the leaves (no dependencies) up to the roots (the top level) — packages first, then the modules
that use them, then the things that instantiate those.
2. Formal explanation — libraries and the order rules
-- LIBRARIES:
-- work : your current design's units land here by default (no 'library work;' needed to compile into it).
-- ieee : standard packages — std_logic_1164, numeric_std (you 'library ieee; use ieee....').
-- vendor : tool/FPGA primitive libraries (e.g. unisim), referenced as needed.
--
-- COMPILATION (ANALYSIS) ORDER — each unit AFTER what it depends on:
-- 1. packages (declarations) before any unit that uses them
-- 2. a package body after its package declaration (and before users needing its subprograms)
-- 3. an entity before the architecture(s) of it
-- 4. an entity before any unit that instantiates it
-- 5. lower-level modules before the top level that instantiates themUnits are analysed into a library (yours into work, standards from ieee). The order is governed by
dependencies: analyse a unit only after everything it references. Packages come first (everyone uses them),
then leaf modules, then higher-level modules, then the top — a topological order of the design's dependency
graph. (Build tools and make/project files automate this, but the rule is what they are enforcing.)
3. Production usage — a correctly-ordered build
-- A clean analysis order for a small design:
-- 1. cfg_pkg (package: constants/types) ← leaf, no dependencies
-- 2. cfg_pkg body (if it has subprograms)
-- 3. adder.vhd (entity + arch, uses cfg_pkg)
-- 4. fifo.vhd (entity + arch, uses cfg_pkg)
-- 5. datapath.vhd (instantiates adder, fifo)
-- 6. top.vhd (instantiates datapath)
-- Each line depends only on lines ABOVE it, so analysis never references an un-analysed unit.What hardware does this become? Compilation order is a build concern, not hardware — it does not change the synthesised result, only whether analysis succeeds. But it is essential: the same source set fails or succeeds depending on order. Organising files so dependencies are analysed first (packages, then leaves, then roots) is what makes a project build reliably.
4. Structural interpretation — the dependency graph
5. Why this is structural, not timing
Compilation order has no run-time behaviour — it is purely about analysing source units into libraries in dependency order, so a dependency diagram (above), not a waveform, is the right picture. The only observable effect is binary: with the correct order, analysis succeeds and you proceed to elaboration and simulation; with the wrong order, analysis stops at the first unresolved reference. Get the order right once (or let a build tool derive it from dependencies) and it disappears as a concern.
6. Debugging example — used before analysed
Expected: the design compiles. Observed: analysis fails with an error that a package, entity, or
declaration is unknown / not found / used before analysed, even though the source for it exists. Root
cause: the referenced unit was not analysed before the unit that uses it — the package was compiled after a
module that imports it, an entity after its instantiation, or a package body in the wrong place. Fix:
analyse units in dependency order — packages first, then leaf modules, then higher levels, then the top — or use
a project/make file that derives the order from dependencies. Engineering takeaway: a not-found error for a
unit whose source exists is almost always a compilation-order problem; analyse dependencies first.
-- BUG: analysing 'adder.vhd' (which uses cfg_pkg) BEFORE cfg_pkg → cfg_pkg unknown.
-- FIX: analyse cfg_pkg first, then adder.vhd.
-- analyze cfg_pkg.vhd # package first
-- analyze adder.vhd # then its user7. Common mistakes & what to watch for
- Analysing a user before its package/entity. The classic used-before-analysed error; analyse dependencies first.
- Wrong library reference.
use work.pkg.allfor your own packages;library ieee; use ieee....for standards — a wrong library means not found. - Forgetting
library ieee;beforeuse ieee..... You must name the library before using its packages (exceptstd/work, which are implicit). - Package body missing or misordered. A package with subprograms needs its body analysed too, after the package declaration.
- Hand-maintaining order for large projects. Use a build tool/project file to derive order from dependencies; manual ordering does not scale.
8. Engineering insight & continuity
Libraries and compilation order are the build discipline behind reuse: units are analysed into libraries
(work, ieee, vendor) in dependency order, packages first and the top level last, so every reference resolves
to something already analysed. It changes no hardware, but it is the difference between a project that builds and
one that fails at the first unresolved name — and it is why packages, which everyone depends on, are always
compiled early. With sharing (constants, types) and the build order understood, the next lesson looks at the
packages you already rely on every day — The Standard IEEE Packages (std_logic_1164, numeric_std, and
their place in the library) — before the module closes with an overall Reuse Strategy.