Logic Circuits
On their own, the three
logic gates
— AND, OR and NOT — can't do very much. A single AND gate can only answer one tiny question:
"are both of my inputs on?" The real power comes when you wire gates together, so
that the output of one gate becomes an input to the next. Chain a few gates like
this and you have a logic circuit: a little machine that reads some
1s and 0s coming in and computes a brand-new
1 or 0 coming out.
This is exactly how the hardware inside a computer makes decisions. When the
CPU adds two numbers,
compares them, or decides which instruction to run next, it is really just a huge web of gates
wired into circuits — millions of them, all switching in step. Learn to read and build a
small circuit and you understand, in miniature, what a processor is doing billions of
times a second.
From gates to a circuit
A circuit diagram is read like a river flowing left to right. Inputs enter on the
left, wires carry signals through the gates, and the final answer leaves on the right. Every wire
carries a single value — 1 or 0 — and a wire
that leaves one gate can plug straight into another gate as its input.
Here is a circuit with three inputs, A, B and
C. Press play (or step through) to watch it being wired
up one gate at a time.
Trace it through: A and B feed an
AND gate, so that wire carries A \text{ AND } B. At the
same time C feeds a NOT gate, so that wire carries
\text{NOT } C. Finally those two wires feed an OR gate.
Following the wires from the output back to the inputs, the whole circuit computes:
Q = (A \text{ AND } B) \text{ OR } (\text{NOT } C)
That single expression is the circuit. The brackets are not decoration — they record the
wiring order: the AND and the NOT each happen first, and their outputs are what the OR gate joins
together.
Reading a circuit into an expression
To turn any circuit into its Boolean expression, work from the inputs forward,
labelling each wire as you go:
- Find the gates whose inputs are the circuit's own inputs — the "innermost" gates. Write down
what each one outputs (here: A \text{ AND } B, and
\text{NOT } C).
- Treat those outputs as new named signals and follow their wires to the next gate.
- Keep going until you reach the final output. Wrap each gate's inputs in brackets so the order
of operations is unambiguous.
Building a circuit from an expression is just the reverse: the outermost operation is the
last gate (nearest the output). In
Q = (A \text{ AND } B) \text{ OR } (\text{NOT } C) the outer operator is
OR, so an OR gate sits at the very end, fed by two smaller circuits.
A truth table for the whole circuit
Once you have the expression you can build a
truth table for the
entire circuit — one row for every combination of inputs. With three inputs there are
2^3 = 8 rows. The winning tactic is the same as for any combined
expression: give each intermediate wire its own column, fill the inner gates in
first, then combine them for the final output.
| A |
B |
C |
A \text{ AND } B |
\text{NOT } C |
Q |
| 0 | 0 | 0 | 0 | 1 | 1 |
| 0 | 0 | 1 | 0 | 0 | 0 |
| 0 | 1 | 0 | 0 | 1 | 1 |
| 0 | 1 | 1 | 0 | 0 | 0 |
| 1 | 0 | 0 | 0 | 1 | 1 |
| 1 | 0 | 1 | 0 | 0 | 0 |
| 1 | 1 | 0 | 1 | 1 | 1 |
| 1 | 1 | 1 | 1 | 0 | 1 |
The two shaded ideas at work: the A \text{ AND } B column is
1 only on the last two rows (where both are on); the
\text{NOT } C column is simply C flipped. The
final Q column ORs those two together, so it is
1 unless both of them are 0 — which
only happens when C = 1 and A and
B are not both on.
Let a program run the circuit
A circuit is just a rule, so we can write it in code. Each gate becomes one line, and — crucially —
we compute the inner gates first and feed their results into the next gate, exactly
as the wires do. Press Run and check every row against the table above.
// The circuit Q = (A AND B) OR (NOT C), one line per gate.
const circuit = (A: number, B: number, C: number): number => {
const andAB: number = A && B ? 1 : 0; // AND gate: inner gate, done first
const notC: number = C ? 0 : 1; // NOT gate: inner gate, done first
return andAB || notC ? 1 : 0; // OR gate: combines the two wires → Q
};
console.log("A B C | Q");
console.log("------+----");
for (let A = 0; A <= 1; A++) {
for (let B = 0; B <= 1; B++) {
for (let C = 0; C <= 1; C++) {
console.log(A + " " + B + " " + C + " | " + circuit(A, B, C));
}
}
}
Change the last line of circuit to andAB && notC ? 1 : 0 and you've
rewired the OR gate into an AND gate — a whole new circuit, and a whole new truth table. That is all
"designing hardware" really is: choosing which gates to wire to which.
The two mistakes that wreck circuit questions are both about order and wiring:
-
Work through the circuit in order — inner gates first. Don't try to leap
straight from A, B, C to Q in your head.
Evaluate each innermost gate, write its 1 or
0 onto that wire, then feed those results forward into the next gate.
A multi-gate circuit is easy when it's a chain of tiny steps and a nightmare when you rush the
final column.
-
Match every wire to the right input. A single wire connected to the wrong gate
input — swapping which signal goes where, or forgetting the little bubble that makes a gate a
NOT — silently changes the output for some rows. The gates can all be "correct" and the circuit
still wrong, because a circuit is defined as much by its wiring as by its gates. When
you build one, trace each wire end-to-end before you trust the table.
Adding 1 + 1 in binary gives 10 — a
sum bit of 0 and a carry bit of
1. A tiny circuit called a half adder produces exactly
that from two input bits: the carry is just A \text{ AND } B, and the
sum is A XOR B (on when the bits differ).
Wire a chain of these together — a full
adder per column — and you can add any two binary numbers. The arithmetic unit inside
every CPU is built from precisely this idea: numbers in, gates switch, a number comes out. No
multiplication tables memorised, no counting — just wired-up AND, OR and NOT.