VHDL · Chapter 2.13 · Data Types
Physical Types and time
Most VHDL types are pure numbers, but a physical type is a number with a unit attached. The one you use constantly is time, expressed as values like ten nanoseconds or five picoseconds, and it is the type behind every after delay, every wait for, and every clock period in a testbench. This lesson shows how a physical type is built from a base unit plus scaled secondary units, how time schedules a value into the future, and the rule that keeps designs honest. Time and after are simulation constructs that synthesis ignores, so they belong in testbenches and as generic and constant parameters, never as the timing of synthesizable logic. Writing after delays in synthesizable code is a classic simulation-versus-synthesis trap.
Foundation13 min readVHDLPhysical TypestimeafterSimulationGenerics
1. Intuition — a number with a unit
A scalar like integer is just a value. A physical type binds a value to a unit so the
quantity is self-describing: 10 ns is not the bare number 10, it is ten nanoseconds. VHDL
predefines exactly one physical type you will use everywhere — time — and lets you declare
your own for any measured quantity (resistance, capacitance, distance).
constant CLK_PERIOD : time := 10 ns; -- a value (10) and a unit (ns)
constant SETUP : time := 200 ps; -- another time, different unit, same type
-- CLK_PERIOD and SETUP are both `time`; the units interoperate by scale.The point of the unit is that the compiler tracks it: you cannot accidentally add a time to
an integer, and the simulator knows that 1 ns is 1000 ps.
2. How a physical type is built — base unit plus secondary units
A physical type declares one base unit (the smallest, indivisible step) and any number of
secondary units defined as integer multiples of it. time's base unit is fs, and every
larger unit is a scale of it:
You can declare your own physical type the same way — a base unit and scaled secondaries:
type resistance is range 0 to 2_000_000_000
units
ohm; -- base unit
kohm = 1000 ohm; -- secondary units, integer multiples of the base
Mohm = 1000 kohm;
end units;
constant R_PULLUP : resistance := 10 kohm; -- self-documenting quantity3. time in action — after schedules a value into the future
The reason time matters is the after clause: a signal assignment with after t does not
take effect now — it schedules the new value to appear t later. This is the foundation of
delay modelling and of every wait for in a testbench:
y <= x after 5 ns — the new value is scheduled, then appears 5 ns later
8 cyclesy <= x after 5 ns; -- model a 5 ns propagation delay
clk <= not clk after CLK_PERIOD / 2; -- a free-running clock in a testbench
wait for 100 ns; -- advance simulation time by 100 ns4. Hardware interpretation — time is for simulation, not synthesis
This is the rule that separates a working design from a sim-only artifact: time and after
are not synthesizable. Synthesis builds logic from behaviour, not from wall-clock delays —
it has no way to realise "5 ns later" as gates. So after delays are simply ignored (or
rejected) by synthesis, and a time signal cannot become hardware.
Where physical types do belong in real RTL is as parameters — generics and constants that configure a design or its testbench without ever becoming logic:
entity baud_gen is
generic ( CLK_PERIOD : time := 10 ns; -- a configuration value, not logic
BAUD : integer := 115200 );
port ( clk : in std_logic; tick : out std_logic );
end entity;
-- Inside, the DIVISOR is computed as an integer (numeric_std arithmetic);
-- CLK_PERIOD documents the intended clock but is not itself synthesised.5. Debugging example — the after that "did nothing" in synthesis
A frequent bring-up surprise: a delay that works perfectly in simulation vanishes in hardware.
-- Intended (wrongly) as a real hold: works in sim, ignored by synthesis.
q <= d after 3 ns;
-- Simulation: q follows d 3 ns late, looks correct on the waveform.
-- Synthesis: the 'after 3 ns' is dropped — q <= d becomes a plain wire/assignment,
-- so the 3 ns never exists in silicon. The gate-level behaviour differs from RTL sim.The fix is conceptual: never use after to create timing in synthesizable logic. Real timing
comes from clocked registers and the place-and-route delays, not from after. Reserve after
for testbench stimulus and for delay modelling in non-synthesizable models, and confirm RTL
intent with a zero-delay or gate-level simulation rather than RTL after delays.
6. Common mistakes & what to watch for
- Putting
afterdelays in synthesizable RTL. They are simulation-only; synthesis ignores them, creating an RTL-vs-gate mismatch. Use clocked logic for real timing. - Assuming
timecan be a hardware signal. It cannot be synthesised; keep it in testbenches, generics, and constants. - Delays below the simulator's resolution.
timeis an integer count offs(or the set resolution); a delay finer than the resolution rounds to zero and silently disappears. - Mixing a physical type with a plain number.
CLK_PERIOD + 5does not compile — add atimeto atime(CLK_PERIOD + 5 ns); convert deliberately when you need an integer count. - Reaching for
min/hrin hardware contexts. They exist for completeness; real designs live inps/ns.
7. Engineering insight
Physical types make quantities self-documenting and type-safe: a CLK_PERIOD : time := 10 ns
says what it means and cannot be confused with an integer, which is exactly what you want for
testbench timing and configuration. The discipline is to keep them on the simulation/parameter
side of the line. Synthesizable hardware expresses timing structurally — through clocks,
registers, and the physical delays the tools compute — never through after. Knowing that
after schedules a future transaction (rather than storing a value now) is also the bridge
to the next module: signals update by scheduling, and time is just the explicit-delay form of
the same mechanism.
8. Summary & next step
A physical type is a number plus a unit, built from a base unit and integer-scaled secondary
units. time (fs…hr) is the predefined one, and after/wait for use it to schedule values
into the future — the basis of delay modelling and testbench clocks. Crucially, time and
after are simulation constructs: synthesis ignores them, so in real RTL physical types live
as generics and constants, while timing comes from clocked logic.
That closes the Data Types module — you can now describe logic values, numbers,
enumerations, composites, subtypes, and physical quantities. The next module steps from what
values exist to how values move: the signal, VHDL's model of a real wire, including the
scheduled, delta-delayed update behaviour that after just previewed — starting with the most
important distinction in the language, signals vs variables.