Of course, now that I've said that, something will go horribly wrong (but let's pretend it won't).
- 8-bit ripple-carry
- Supports addition, subtraction, AND, OR, and NOT
- Exports Zero, Negative, Overflow, and Carry condition codes
- 41 7400-series logic chips:
- 21 Quad NAND (7400)
- 2 Quad NOR (7402)
- 2 Hex NOT (7404)
- 4 Dual 4-1 Mux (74153)
- 7 Quad 2-1 Mux (74157)
- 2 Quad Buffer (74125)
- 3 Octal Buffer (74541)
- All the processing power (actually less) of a pair of 74183s, at several times the cost!
Here's a picture:
The blindingly-white breadboard on the left is the core of the ALU. The buffer chips live on the middle breadboard. The PCB on the right is the Front Panel I described earlier. Briefly, the Front Panel allows me to control the ALU from my computer. First, this allows me to implement the UI in software rather than switches and LEDs. Second, I can perform automated regression tests by simply running a script.
With the exception of the rainbow-colored ribbon cables, I wired the entire circuit in red and black. Why? I was told that blue and yellow wires are slower than red and black ones. Or Radio Shack only stocks red and black in the big rolls. You choose.
The ribbon cables are Adafruit "Premium" Jumper Wires electrical-taped together. I really wanted an 8-conductor cable, but Adafruit only carries 6-conductor cables (six???). The only other choice seemed to be ordering housings, crimp terminals, and wire separately from Mouser and building them myself. Compared to that, taping together cables seemed easier (not to mention cheaper).
Everyone loves video, so here's a video. It's a flyover of the breadboarded circuit followed by a wonderfully-shaky look at the GUI I use to control the ALU interactively.
Now to the guts of the circuit. First, the schematic:
Next, the board layout. It's easily the most complicated board I've designed (n=2), and it just barely fits in the routing space allowed by Eagle Hobbyist. Unless I'd been willing to cut the circuit in half (or maybe smaller), I quite simply wouldn't have been able to do it in free Eagle. Had space not been so tight, I might've (ok, would've) ditched the buffer chips in favor of back-to-back NOTs. Maybe if I get really really bored, I'll make daughterboards which plug into the buffer sockets and use NOTs to implement the buffers.
The first page shows the board layout without the back-side ground fill. The second page shows the fill (the individual wires are a mite difficult to see through the rivers of purple).
Just routing this board was an adventure. When I first laid it out, I naively let the autorouter do the whole thing. It routed every trace, which was great, but it picked some mindbendingly roundabout paths for some of the signals. I knew I'd go insane if I tried to route the whole thing, so instead I hand-routed the traces I cared about (primarily the A0-7, B0-7, R0-7, and control lines) and let the auto-router take care of the rest. Eagle doesn't seem to go quite so crazy when you only give it short wires to route. Unfortunately, it wasn't able to route the entire board -- there's one signal left, so I'll have to solder a jumper wire to complete the circuit.
When I made the Front Panel, I was a little conservative with the silkscreening. This time, I went in the other direction. Waaaay too far in the other direction. I added silkscreen labels to everything that wasn't moving, and also labeled some things that were just moving slowly. The chips that calculate the individual bits are labeled. The control bits are labeled. The pads on the edge connector are labeled. Every IC has a label which will be (gasp) still visible when the socket is installed (I learned this the hard way with the Front Panel). I'm sure there's something I forgot to label, but I should be in much better shape with this board.
At the suggestion of a coworker, I made some space in the bottom right of the board for a single 16-pin DIP just in case. Just in case what, I don't know yet, but I'm sure it'll be nice to have a place to put a chip if I need it.
Why is there an edge connector on the board? This board will be but one component of my microprocessor. The control logic will live on a backplane board, and individual subsystem boards will plug into it via ISA sockets. I'm not using the ISA bus -- just the physical sockets. There won't be any bus at all, as a matter of fact. I'm simply breaking the microprocessor up into several boards so that a) I can develop them separately and b) I can work with them in Eagle without having to shell out $1600 for the professional version.
The Front Panel as originally designed has 27 output pins (numbered 0-26) and 8 input pins (numbered 100-107). Output pins 0-23 use 74595 serial-to-parallel latches (which are in turn connected to the Front Panel's microcontroller), while pins 24-26 are connected directly to the microcontroller. Input pins 100-107 connect to the microcontroller via a 74165 parallel-to-serial latch. This configuration worked when I was testing ALU bits 0-7, but came up short when I added the four condition codes (zero, negative, overflow, and carry). Negative is the same as R7, so I needed to find three extra input pins.
I solved that problem by changing the Front Panel software to allow pins 24-26 to function as input pins (numbered 124-126) on demand. Very happy with myself for coming up with this solution, I wired the whole thing up and watched as my current consumption skyrocketed from a normal 20mA to 120mA. Some very exciting(?) debugging ensued. It turns out that the newly-minted input pins 124-126 sink about 30mA each. Maybe I don't have them configured correctly in the microcontroller -- who knows. Bottom line, they were sinking power in a way pins 100-107 weren't. They differ from 100-107 in that 124-126 carry condition codes, which means the weird power behavior only exhibited itself when those codes were active, and of course the power consumption changed depending on how many were active. Only condition code zero? +30mA. Zero, Overflow, and Carry? +90mA. Very exciting. Eventually I figured out what was happening, added some series resistors, and all is well. I need to double-check that I'm initializing the pins correctly in the Front Panel microcontroller, as it's possible the microcontroller could take care of this for me, ridding me of the need to use the series resistors.
I also learned, the hard way, that thou shalt always ground thy unused inputs. I don't have many unused gates in this design (3 NAND, 3 NOR, and 4 NOT), but I had initially left their inputs floating. I was seeing some truly bizarre behavior from the chips containing those unused gates. I haven't tried to reproduce since then, but I swear the unused gates were influencing the output of the active ones. That is, use gate A on a 7400, leave B-D floating, and watch A behave very strangely. I'm far too burned out on this circuit at the moment to go investigate further, but I think that's what I saw. Anyway, I haven't seen anymore weirdness since I grounded the inputs for every unused gate.
Labels and diagrams are very important. Every ribbon cable now has a label on it which says which wires are which signals. Almost every IC has a sticker on it with its U number. I even created a map of the breadboard in Inkscape which shows the position of every IC and the signals for every header pin. These diagrams saved much time.
Now that I have the circuit working in breadboarded form, I'm going to have PCBs made by DorkbotPDX. They did an awesome job with the Front Panel, so I'm very happy to have them make this board too. I had to use 6mil traces for everything (except power), so hopefully that'll turn out OK. Once the PCBs come in, I'll populate one, test it out, and then gleefully reclaim my breadboards. The ALU has consumed almost all of my breadboard space, leaving me with one dinky Radio Shack 63-row breadboard to play with. It'll be nice to have the big breadboard back.
Once I'm satisfied with the ALU, I think it'll be time to tackle the register file. Perhaps I should start designing it. I also have to think about the control circuitry for the whole processor, what the instruction set will look like, and all that. While I had initially planned to implement the microprocessor in CODE, I may have decided to just do my own thing instead. We'll see.
A friend asked how many boards I'd get from Dorkbot (3), and promptly suggested that I could populate all of them, chain them together, and get a 24-bit adder. Then I could build a 24-bit machine! Um, no. Eight bits is enough for me until I work on microprocessor v2, which will be done with a CPLD. Well, eight bits is enough for me for the datapath. The address path will be at least 24 bits, if not 32. But that's a story for another day.
Last but not least
Here's the output from the verifier running its regression tests over the breadboarded ALU. It's music to my ... eyes.
Testing ADD ADD case 1/7 ADD case 2/7 ADD case 3/7 ADD case 4/7 ADD case 5/7 ADD case 6/7 ADD case 7/7 Testing SUB SUB case 1/7 SUB case 2/7 SUB case 3/7 SUB case 4/7 SUB case 5/7 SUB case 6/7 SUB case 7/7 Testing NOT NOT case 1/3 NOT case 2/3 NOT case 3/3 Testing OR OR case 1/9 OR case 2/9 OR case 3/9 OR case 4/9 OR case 5/9 OR case 6/9 OR case 7/9 OR case 8/9 OR case 9/9 Testing AND AND case 1/9 AND case 2/9 AND case 3/9 AND case 4/9 AND case 5/9 AND case 6/9 AND case 7/9 AND case 8/9 AND case 9/9 Success