Code
Although computers today are more complex than the computers of 25 years or 50 years ago, they are still fundamentally the same.
Charles Petzold
Code: The Hidden Language of Computer Hardware and Software
Code is an approachable book that succeeds at an absurdly ambitious goal: to guide a motivated reader from “what is binary?” all the way to “design a microprocessor out of Radio Shack components” without skipping any steps in between.
The book is remarkably self-contained and uses old tech to illustrate timeless principles, so it still holds up 20+ years after it was written.
Marginalia
Here are some interesting things I learned from the book.
Relays
A relay is an electrical component in which copies the on/off state of one wire to another, e.g. by having an electromagnet flip a switch.
You can build logic gates out of relays; of course, modern computers use transistors instead, but relays are easier to understand.
Memory
I was already aware that every Boolean function can be realized by an acyclic network of logic gates, but wasn’t sure how to get there to a programmable computer. The key step is to design (non-acyclic) circuits that admit multiple stable states for a given set of inputs — these can be used as volatile memory.

(The output Q “remembers” the state of A at the time C was most recently set.)
Such a circuit can be used to build a memory array to store data — including “instructions” that can be read conditionally to execute other circuits.
How to subtract
Computers subtract by using bitwise operations to convert the subtrahend to “two’s complement” form and then adding. The same trick could be used in base ten to subtract without borrowing.
If is less than a million, then (the “ten’s complement”) can be done with “digit-wise” operations. Then it’s just a matter of addition and ignoring the leading one.