VHDL · Chapter 6.6 · Combinational Logic Design
Decoders and Encoders
If the multiplexer routes one of many, decoders and encoders translate between encodings. A decoder takes an n-bit binary value and activates exactly one of its many outputs, a one-hot pattern that is the basis of address decode, chip selects, and demultiplexing. An encoder does the reverse, compressing a one-hot input back to binary, and a priority encoder returns the index of the highest-priority set bit, which is used for interrupts and arbitration. This lesson shows the clean way to model each in VHDL, using a selected assignment or a shift for decoders and an if ladder or a for loop for priority encoders. It maps them to the hardware they build and keeps every output complete and latch-free.
Foundation14 min readVHDLDecoderEncoderPriority EncoderOne-hotRTL
1. Engineering intuition — expand and compress
A decoder expands: it turns a compact binary index into a one-hot signal where exactly one line is active — "select line number 5" becomes "line 5 high, all others low." An encoder compresses: it turns a one-hot (or, for a priority encoder, any pattern) back into the binary index of the active line. These are the translation primitives between the two ways hardware names a choice: by binary value and by one-hot position. Address decode, chip-select generation, interrupt prioritisation, and demultiplexing are all decoders and encoders.
2. Formal explanation — decoder, encoder, priority encoder
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
-- DECODER: n-bit binary → one-hot (2^n). Two clean styles:
with sel select -- explicit one-hot
onehot <= "0001" when "00", "0010" when "01",
"0100" when "10", "1000" when others;
-- or by shifting a single '1' to the selected position:
onehot2 <= std_logic_vector(shift_left(to_unsigned(1, 4), to_integer(unsigned(sel))));
-- PRIORITY ENCODER: highest set bit → its index (+ a 'valid' flag).
prio : process (all)
begin
index <= (others => '0'); valid <= '0'; -- defaults → latch-free
for i in req'range loop -- low to high: last match (highest i) wins
if req(i) = '1' then
index <= std_logic_vector(to_unsigned(i, index'length));
valid <= '1';
end if;
end loop;
end process;A decoder maps a binary value to a one-hot output (via with/select or a shift). An encoder
reverses it. A priority encoder scans the input and returns the index of the highest-priority set
bit plus a valid flag; a for loop scanning low-to-high naturally lets the highest index win
(last-assignment-wins, lesson 5.9), or an if ladder encodes the priority explicitly.
3. Production RTL — address decode and interrupt priority
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
-- (A) Chip-select decoder: activate one peripheral select from the address high bits.
cs <= std_logic_vector(shift_left(to_unsigned(1, NUM_DEV), to_integer(unsigned(addr_hi))));
-- (B) Interrupt priority encoder: highest pending IRQ wins.
irq_enc : process (all)
begin
irq_num <= (others => '0'); irq_any <= '0';
for i in irq'range loop
if irq(i) = '1' then
irq_num <= std_logic_vector(to_unsigned(i, irq_num'length));
irq_any <= '1';
end if;
end loop;
end process;What hardware does this become? (A) a binary-to-one-hot decoder driving one chip-select line per
device; (B) a priority encoder whose unrolled for loop becomes a network that outputs the index of
the highest-numbered asserted interrupt, with irq_any indicating any request. Defaults keep both
latch-free.
4. Hardware interpretation — one-hot fan-out and priority compress
5. Simulation interpretation — one-hot tracks input; encoder picks highest
Decoder one-hot output, and a priority encoder picking the highest set bit
8 cycles6. Debugging example — the priority encoder that picked the wrong bit (or latched)
Expected: the highest-priority set bit's index. Observed: the lowest index was returned, or
the output latched when no bit was set. Root cause: for "highest wins," a for loop scanning low
to high relies on last-assignment-wins so the top index overwrites — scanning the wrong direction (or
using an if/elsif in the wrong order) returns the lowest; and without a default index/valid, the
no-request case leaves them unassigned → latch. Fix: scan low-to-high for highest-wins (or order
the if ladder by priority) and default index/valid at the top. Engineering takeaway: a
priority encoder's correctness is scan direction + last-assignment-wins (or explicit if ordering),
and its safety is defaulting the index and valid for the empty input.
-- Defaults make the no-request case safe; low-to-high scan makes the HIGHEST index win.
process (all) begin
index <= (others => '0'); valid <= '0'; -- default: no request
for i in req'low to req'high loop
if req(i) = '1' then
index <= std_logic_vector(to_unsigned(i, index'length)); -- higher i overwrites lower
valid <= '1';
end if;
end loop;
end process;7. Common mistakes & what to watch for
- No default on encoder outputs. The empty-input case leaves
index/validunassigned → latch. Default them at the top. - Wrong scan direction / priority order. Decide highest- vs lowest-priority and make the loop
direction (or
iforder) match. - Incomplete decoder coverage. A
with/selectdecoder needswhen others; a process-style decoder needs a default. - Index width too small.
to_unsigned(i, index'length)must fit the largest index; sizeindexforreq'high. - Confusing a decoder with a demux. A decoder gives one-hot selects; a demux routes a data input to one of N outputs (a decoder enabling the data) — keep the intent clear.
8. Engineering insight & continuity
Decoders and encoders are the translators between the two ways hardware names choices — binary index and
one-hot position — and they appear everywhere selection logic lives: address maps, chip selects,
interrupts, arbiters. Model them with the patterns you now know: with/select or a shift for the clean
decoder, a defaulted for/if for the priority encoder, always complete and latch-free. With routing
(muxes) and encoding translation (decoders/encoders) covered, the module turns to computation: the next
lesson, Arithmetic Circuits, builds adders, subtractors, comparators, and more on numeric_std,
before Combinational Loops closes the module on the one structure to never build.
Standards & specifications
- Governing standard
- IEEE Std 1076 (VHDL)(opens IEEE in a new tab)
Defines the VHDL language — types, the simulation cycle, and the semantics a conforming analyser and simulator must implement. Synthesis restrictions and vendor coding rules are tool behaviour, not language rules.
This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.
Where this fits
Part of the VHDL curriculum.
