What a decoder does
A decoder reads a binary number and turns on exactly one of its output lines. Two input bits, A1 and A0, count from 0 to 3, so a 2-to-4 decoder has four outputs, Y0 to Y3.
The truth table lists every input and its outputs. In each row exactly one output is 1, a pattern called one-hot. Input 1 0 is the number 2, so Y2 is the hot line.
Inside: NOT and AND
Inside are only NOT and AND gates. A NOT gate flips each input, which gives four rails: A1, NOT A1, A0 and NOT A0. A rail is a long wire that many gates can tap.
Each output has an AND gate wired to one rail of each bit. Y2 taps A1 and NOT A0, so it gives 1 only for input 1 0. For any input, exactly one gate sees two 1s.
Decoders at work
Memory uses a decoder to choose a row. The address bits go in, and the one-hot output, called a word line, switches on a single row, so only that row is read or written.
A CPU decodes the bits of each instruction in the same way. Here a made-up 2-bit operation code picks one of four units: 00 add, 01 subtract, 10 AND, 11 OR. Only the chosen unit switches on.
A 7-segment display has seven bars, named a to g. A display decoder takes a 4-bit number from 0 to 9 and switches on the bars that draw that digit. For 2 it lights a, b, d, e and g.
Encoders
An encoder does the reverse: four input lines in, a 2-bit number out. With only I2 on, it outputs 1 0, the number 2. Inside it is just two OR gates.
If I1 and I2 are both on, a plain encoder outputs 1 1, which means 3: wrong. A priority encoder reports only the highest line that is on, so it outputs 1 0. The 74HC148 chip does this for eight lines.
Inside the step
;; step 1/9 · decoder-idea ;; about: Inputs A1 A0, Outputs Y0-Y3 2 inputs → 2² = 4 outputs A1 A0 number line on 0 0 0 Y0 0 1 1 Y1 1 0 2 Y2 1 1 3 Y3 A1 is the 2s bit, A0 the 1s bit.
A real part: Texas Instruments' SN74HC139 holds two 2-to-4 decoders. Its outputs are active low: the chosen line goes to 0 and the others stay at 1, the same idea with the levels flipped. In Python a decoder is [int(n == i) for i in range(4)], an encoder is y.index(1), and a priority encoder is max(i for i in range(4) if x[i]).