Introduction
I recently (like a few months ago) stumbled onto an article about the Nibbler. It’s a 4-bit computer built out of discrete logic. There is no microprocessor, so this is lower level than slapping together a minimal system with a Z-80. Here’s the original article if you want to see what I’m attempting: Nibbler 4-bit CPU.
Before I dig into this subject, you might be wondering, “Why?” Why would anyone build a tiny computer like this? Well, first, it’s simple to build. There is still some wiring to do, and there are plenty of places where one could get tripped up by electronic problems (like noisy signals, unexpected signal delays, etc). This is about the simplest circuit you could start with to build a computer without using a microprocessor chip. There are a lot of computers out there built by hobbyists that are 8 and 16-bit computers. They’re pretty serious projects, and I don’t have enough free time to spend on such a project (maybe after I retire), so I’m going with something small.
On with the analysis…
So far, I’ve studied the schematic in the article and looked over his microprogramming ROM to see what he was doing. The microprogramming is super simple, and I laughed when I finally figured out how he got around the complexity of encoding the flags.
I downloaded the software he did in C# and added some code to it to dump a file of the microcode in binary. That’s when I started scratching my head that he was dumping some of the codes four times in a row. Between each command is a load instruction to load the next command to be decoded. Here’s an example of the Jump if Carry (JC):
1111100000110111 // load instruction 0011100000110111 // JC (NC,NZ) 1111100000110111 // load instruction 0011100000110111 // JC (NC,Z) 1111100000110111 // load instruction 1111100000110111 // JC (C,NZ) 1111100000110111 // load instruction 1111100000110111 // JC (C,Z)
As you can see above, there are 4 JC instructions. The schematic shows that the Carry flag and the Zero flag are fed into address 1 and address 2:
Address 0 is the phase, which is load, then decode. So the following occurs:
000 = 1111100000110111 // load instruction
001 = 0011100000110111 // JC (NC,NZ)
010 = 1111100000110111 // load instruction
011 = 0011100000110111 // JC (NC,Z)
100 = 1111100000110111 // load instruction
101 = 1111100000110111 // JC (C,NZ)
110 = 1111100000110111 // load instruction
111 = 1111100000110111 // JC (C,Z)
The first instruction above ends with 000, so it’s a load instruction (A0 is a zero). If the instruction coming in ends with 001, then there is no carry and no zero. If the instruction is 010, there is no carry and zero, but the JC doesn’t care about the zero flag, so it executes the same instruction for both (0011100000110111). For the next two instructions, the A2 pin is high (a carry input), so 101 and 111 will execute the same JC code. The instruction executed is the same for those two (1111100000110111).
Basically, it’s just memory-mapped logic. Since ROMs are cheap these days, it doesn’t matter that you have to chew up 8 memory cells for each instruction (every other cell for load and 4 cells for each combination of the carry and zero flags). I did an earlier blog post about using ROM to take the place of the 74181 ALU chip.
For the Nibbler, there are only 4 bits for the opcode. That means there are 16 total opcodes or instructions (some instructions have variations). The data output from the ROMs are the control wires used to activate different circuits and perform the operation. In the sample circuit, he uses the 2716 EPROM, which is a 16k memory. Those are not easy to find, but I substituted the 27256, which is cheap anyway. I can wire the upper address pins to zero to disable the rest of the memory.
Since I plan to blog about this project over time, I’m starting small and going to work up to the full circuit so I can get my head wrapped around every detail. How small? So far, I’ve set up a breadboard and started wiring up the output latches (74173) and the 2×16 display.
It took some digging around to find the full specs for the display, which I have here:
There is some complexity with this tiny display that I had not expected, especially with the modes. The Nibbler circuit hard-codes a few of the pins to ground (because they’re not needed) and makes it look simpler. One of the modes determines if the input data is 4-bits or 8-bits. The Nibbler uses 4 bits, so the software written for the Nibbler must take into account that you must output 2 words (4-bit words) to the display for each character.
Before I dig into all that, I’m setting up my breadboard to latch in 4 bits at a time to see if I can manually poke characters into the display. Once I get that figured out, then I’ll know how to program something to manipulate the display.
Stay tuned…