It's the early 90s, and a younger version of me is soldering chips to a board in my high school industrial class.
I had been looking forward to this part of the class. Having some self-taught experience with electronics, I took the opportunity to try something really ambitious. Instead of a blinky-light kit, motor, amplifier or radio, I decided to build a computer from chips. I had convinced my Dad to invest the money in an Elenco Micro Master Computer Training kit. This single-board machine has an 8084 CPU -- the grandfather of the x86 series -- and a modest amount of RAM and ROM. Instead of running an Windows or any operating system, it was designed to allow you to learn the hard physical realities of computer hardware. Programs are entered painstakingly by flipping 8 switches to enter an address, pressing a memory latch button, flipping 8 switches again to enter data, and pressing the write button. Using a magnetic needle and a steady hand to write to a hard drive would be only slightly more difficult.
Due to a soldering mistake, I trashed both the ROM and the power regulator for the kit. Thankfully, Elenco was nice enough to mail me tested replacements gratis. While I did get the kit to light up, and execute simple programs from the book, the realities of computer hardware were still lost on me. I kept the kit, pulling it out occasionally to try understand what it was trying to teach me. Inevitably, I became lost again and never quite figured it out.
I still have that assembled kit today. When I plugged it in recently, not only did it not light up, but it didn't seem to function at all. If I had an oscilloscope or a logic analyzer, maybe I could bring it back to life. Even if I did, I know I would get stuck in the same place in the book, unable to make the conceptual leap necessary to understand what concepts it tried to reveal.
Today, one would think that CPU design would only appeal to those working at a large semiconductor fabricator. In reality, there's a lot of people like me that still want to understand how a physical constellation of doped silicon and wires can become a computer. While Elenco still sells the Micro Master kit, I'm certain that it continues to suffer the problem of teaching from complexity. The 8086 architecture is simply too well developed to present to a learner as a first experience. One can become mired in complications very, very quickly. Combine this with the simple fact that the CPU is integrated -- all the components on one die -- it makes explaining how CPUs actually work an easily neglected topic. It'd be much better if you take a bunch of basic logic chips and make a CPU out of that.
A number of hobbyists have done exactly that. Many, however, create architectures that are designed for ease of programming, features, or performance. Few have actually tried to design a CPU from basic logic gates with the following attributes:
- Foremost, it should be a teaching tool.
- It should be built with cheap, simple, off-the-shelf components.
- It should have a minimum of chips, yet still be clear in design.
Only today did I find such a design. The Nibbler is a 4-bit CPU that fits just those specifications. The name comes from the fact that a byte is 8 bits, and 4 bits is called a "nibble". While you can't do much with 4 bits, it's more than enough to teach the basics. While I wanted to spend the day reading up on Symfony for future Drupal 8 work, this was simply too enticing for me to put down until things finally clicked.
The basic idea behind any CPU is that it reads memory for instructions and data, operates on that data, and writes the results back to memory. You can think of memory like an ice cube tray. A typical ice cube tray is 8 cubes wide and two cubes long. In this example, our tray is still 8 cubes wide, but it's an arbitrary number of cubes long. Each cube can either have a cube in it, or be empty. The CPU is like a little robot that operates on only one row of 8 cubes at a time. It rides along the tray, detects the presence of lack thereof of cubes. Based on that, the robot looks at a table of rules that applies to that combination of cubes and empties. While each rule is different in details, they all instruct the robot to go and replace the contents of an 8-cube wide row with another combination of cubes and empties. While it can be the same row, it typically is another row in the tray, or a completely separate tray.
The part that I always got stuck on is how does the little robot know what to do? How does one translate those rules into a piece of hardware? In a real CPU, a special device called a Program Counter keeps track of where we are in memory. It starts at zero -- the first row in our ice cube tray -- and then goes on to the next. To keep everything in sync, we have a clock that emits a pulse according to a set interval. Each pulse of the clock, the program counter goes up by one, moving our robot to the next row in the tray. Each tick of the clock also has a corresponding tock. On the tick, we move the robot and read that row of the tray. In other words, the CPU reads that address of memory and places it into a temporary spot called a fetch register. On the tock, the robot looks up the rule and then performs it.
Now wait a minute, I said that the Nibbler is 4-bit CPU, why are we reading rows of 8 cubes wide? Each row is actually divided into two parts. The do-something half called the opcode, and the something-you're-doing-on part called the operand. Our opcode is only four cubes/binary numbers/bits long. In the CPU, this opcode is carried by four wires that need to tell the rest of the chips what to do on the next tock. Somehow, those four wires need to turn into an entry in our table of rules. Complicating this is that many CPUs, like The Nibbler, need additional flags that modify the result of the opcode. This allows previous instructions to affect later instructions performed by the CPU.
It was always at this point that I stalled, never quite understanding how the CPU did what it needed to do based on the opcode. The rest of the chips in The Nibbler don't understand opcodes, only specific control signals of on or off (1 or 0) at specific terminals. The key goes back to our example. The robot is reading a table of rules. It turns out that each opcode and the current flags are decoded into CPU-internal microcodes. A microcode is best thought of not as a number that has an absolute meaning, but a series of on-and-off control signals piped to the other chips. If the opcode means "read the memory at the location in the operand", the microcode would turn on the RAM chip. The RAM chip just happens to be connected to the operand half of the fetch register so it knows where to read. The Nibbler uses two ROM chips that translate opcodes into microcodes. In older computers, a large bank of switches called a plugboard was often used for this purpose.
The rest is just careful selection of what chips so that they all do just what they need to do on tick, what control signals it needs, and what to do on tock. From this, you get the complexity that is a computer.