Priority Encoder Explained: 4-to-2 and 8-to-3
TL;DR: A priority encoder is a combinational circuit that takes N input lines and outputs a -bit binary code identifying the highest-priority active input. Unlike a plain encoder (which assumes exactly one input is high), a priority encoder behaves correctly when several inputs are simultaneously active, resolving the ambiguity by picking the one with the highest assigned priority.
The priority encoder is the answer to a question every interrupt controller, keyboard scanner, and resource arbiter has to answer: “multiple things just asked for attention — which one wins?” A plain encoder fails this question because it assumes only one input is ever asserted. A priority encoder is the workhorse upgrade that makes the same chip useful in real systems where requests collide.
What is a priority encoder?
A priority encoder is a combinational circuit with N input lines and output lines (plus a “valid” output). When at least one input is high, the output is the binary index of the highest-priority active input. When no input is high, the output index is undefined and the valid output is 0.
Two design choices set up the rest of the truth table:
- Priority direction. Conventionally the highest-numbered input has highest priority. The 74148 IC uses this convention with active-low inputs and outputs.
- Valid signal. A separate output (often called V, EO, or GS) indicates whether at least one input is asserted, distinguishing “input 0 is active” from “no input is active” — both of which would otherwise produce the all-zeros output code.
For the broader category — including non-priority encoders that fail when more than one input is high — see Decoders and Encoders: Driving a 7-Segment Display.
Encoder vs priority encoder
A plain 4-to-2 encoder has the truth table:
| I3 | I2 | I1 | I0 | O1 | O0 |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 1 | 0 | 0 |
| 0 | 0 | 1 | 0 | 0 | 1 |
| 0 | 1 | 0 | 0 | 1 | 0 |
| 1 | 0 | 0 | 0 | 1 | 1 |
This works only when exactly one input is high. If I1 and I2 are both 1, the OR-gate implementation produces O1=1, O0=1 — the code for I3, which is wrong. A priority encoder handles all 16 input combinations:
| I3 | I2 | I1 | I0 | O1 | O0 | V |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | x | x | 0 |
| 0 | 0 | 0 | 1 | 0 | 0 | 1 |
| 0 | 0 | 1 | x | 0 | 1 | 1 |
| 0 | 1 | x | x | 1 | 0 | 1 |
| 1 | x | x | x | 1 | 1 | 1 |
The “x” in I0..I2 columns means “don’t care because a higher-priority input is asserted.” The “x” in O1..O0 when V = 0 means the output code is meaningless when no input is asserted.
Building a 4-to-2 priority encoder from gates
Reading the truth table:
- — a single 4-input OR.
- — high whenever input 2 or 3 is asserted (the upper half of the input range).
- — high when input 3 is asserted, or when input 1 is asserted and input 2 is not.
The equation is the line that distinguishes a priority encoder from a plain encoder: the second term is gated by , ensuring that when I2 is asserted alongside I1, the I2 path wins. That is the priority logic in literally one inversion plus one AND.
Ready-made 4-to-2 priority encoders are at /docs/ENCODER and as the /template/4-to-2-priority-encoder.
The 8-to-3 priority encoder
Scaling up to 8 inputs and 3 outputs, the equations become:
The pattern is consistent: each output bit is a sum of products where higher-priority inputs disable lower-priority terms via inverted gating. The 74148 IC implements exactly this function with active-low conventions, plus extra cascading inputs (EI, EO) that let two 74148s combine into a 16-to-4 priority encoder. See /docs/ENCODER_8TO3 for the standalone block, and /template/8-to-3-priority-encoder for the simulator model with togglable inputs.
This priority pattern — higher inputs disable lower terms via inverted gates — is fundamentally an OR-with-priority. For the OR primitive that anchors it, see The OR Gate: Understanding Digital Logic’s Democratic Decision-Maker.
Use case 1: interrupt controllers
The single most common use of the priority encoder is in an interrupt controller. A CPU has many sources of interrupts — timers, UARTs, GPIO pins, DMA channels — and only one program counter. When multiple interrupt requests fire in the same cycle, the interrupt controller must pick exactly one to service first.
The 8259A Programmable Interrupt Controller, used in every IBM PC compatible from 1981 to the early 2000s, was at its core an 8-input priority encoder with a programmable priority mask. Eight IRQ lines came in, eight bits of mask register said which were currently enabled, and a priority encoder produced the 3-bit index of the winning request. That index drove the interrupt vector lookup.
Modern interrupt controllers (ARM’s GIC, x86’s APIC) extend the same idea with hundreds of inputs, programmable priority levels, per-CPU routing, and message-signaled interrupts — but the kernel logic is still “find the highest-priority asserted line and output its index.”
Use case 2: keyboard scanning
A matrix-scanned keyboard organizes keys into rows and columns. The scanner energizes one row at a time and reads back the column lines. A priority encoder on the column lines turns the bit pattern into the index of the lowest-numbered pressed key (or the highest, depending on priority direction). This is faster than a microcontroller scan loop and was the standard approach for keyboard controllers from the 1980s through early USB.
When a user presses two keys simultaneously, the priority encoder picks one — software sees the higher-priority key only and is unaware of the second. This N-key rollover limitation is distinct from the more dramatic “ghosting” effect (where missing diodes in the matrix cause sneak paths to assert phantom keys that were never pressed); both effects can occur in the same keyboard. Modern gaming keyboards add a diode per key to eliminate ghosting and use full bit-matrix scanning instead of priority encoding to support arbitrary simultaneous presses.
Use case 3: address decoding and resource arbitration
A bus arbiter receiving multiple device requests can use a priority encoder to pick the winner. The encoder output drives a one-hot decoder that asserts exactly one grant line. The compactness is appealing — N requesters, priority encoder outputs, then grant outputs from the matched decoder.
This is also how leading-zero count (LZC) and find-first-set (FFS) hardware is built. CPUs that include a CLZ/FFS instruction (every modern ARM core, x86 with BMI1, RISC-V with Zbb) implement it as a priority encoder over the bits of the input word. The output is the bit index of the highest-set or lowest-set bit, computed in one cycle.
The MUX is the dual operation — given an index, route one of N inputs to a single output. For the symmetric pair, see Multiplexers Demystified: The Data Traffic Controller. A priority encoder in front of a MUX implements a “fetch from the highest-priority active source” pattern, common in scoreboard logic inside out-of-order CPUs.
Cascading priority encoders
Two 4-to-2 priority encoders can combine into an 8-to-3 unit. The high-half encoder sees inputs 4-7. The low-half encoder sees inputs 0-3. The high-half’s V output is the high bit of the combined output; it also forces the low-half’s output to be ignored (via gating) whenever any high-half input is active. The combined logic:
| High V | High O1 | High O0 | Low V | Low O1 | Low O0 | Final O2 | Final O1 | Final O0 | Final V |
|---|---|---|---|---|---|---|---|---|---|
| 1 | a | b | x | x | x | 1 | a | b | 1 |
| 0 | x | x | 1 | a | b | 0 | a | b | 1 |
| 0 | x | x | 0 | x | x | x | x | x | 0 |
The 74148 supports this cascade natively via its EI/EO pins.
Build the 8-to-3 and watch priority resolve
Priority resolution is one of those concepts that clicks instantly the moment it is wired up. Open the 8-to-3 Priority Encoder and start asserting inputs from the bottom up — the output index climbs each time a higher-priority input fires, and snaps back the moment that input is released. Once the priority pattern is intuitive, the next stop is the CPU flags register, where a similar select-and-latch structure captures ALU status bits. Combined, the priority encoder and flags register show how a CPU answers the two questions every cycle asks: what just happened, and what should be serviced first?