If you want to really understand something, you must go straight to the source. Led Zepplin. The Beatles. Ernest Hemmingway. Shakespeare. The original works in any area may not be the most polished - but they are the ones you will learn the most from. Good ideas have a way of gathering extraneous junk over time - it's as if every original concept is a potential katarami damacy ball, absorbing more cruft with each reincarnation. Eventually it reaches a point that the quality without a name that made the idea good in the first place is completely obscured.
It's easy to see why this happens. Original ideas are rare, and original people are scary. Sometimes they smell bad, too. It's much easier find a person who'll take an original idea and adapt it. There are three ways to adapt an old idea - you can remove part of it, or you can substitute part of it with something else, or you can tack on unnecessary crap. Of these ways, the first two require some understanding of what you are doing. I don't look down on them. Everything is created in the larger context of the culture and technology that spawned it, and I suspect what we call original ideas, are mostly made of other original ideas by simplifying them or substituting parts of another idea.
The third way of co-opting an idea, however, is a form of pollution. It's easy to take a good idea and add something that doesn't change it, because it doesn't break what was already there. Anyone can do it. That's the problem. Look, it's not just a dog, it's a dog with a flower on it's head! It's original! Dog 2.0. The noosphere is littered with junk like this.
The best way to avoid exposure to junk is to go back in time far enough to reach a point before the cruft took over. So when I wanted to understand computer architecture better, I set out to build a homemade system based around one of the oldest 8-bit classics: the 6502 microprocessor. To those of you who may ask why I would want to design my own computer, I refer you to my previous blog entry.
There are all manner of shortcuts that could be taken in such a project. For instance, I could have just used a 6502 emulator on a PC - but I don't want to pretend I have a 6502 computer, I want to have a real 6502 that I can hold in my hands. One shortcut I do think is reasonable is that I am using a powerful modern microcontroller, the Propeller from Parallax, to manage all the I/O and control logic for the circuit. It will allow me to use software to replace a whole handful of support chips. The Propeller is over a hundred times more powerful than the 6502 CPU it will be supporting, but the point is not to make a powerful computer, but to gain a better insight into computer architecture. The Von Neumann architecture, which most computers today are based on, remains remarkably unchanged whether you're looking at a 6502 or a modern Pentium.
(Incidently, the Propeller chip itself is also an example of an original work, the first of its own class.)
My 6502-computer remains a work in progress. I've run NOPs and simple loops on it using its single-cycle facility, but it's temporarily offline while I make some changes. I figured out a way to eliminate even more chips from the circuit, using software on the Propeller to do their jobs, but the computer will not be operational again until I finish writing that firmware.
Even so, I've already uncovered a wealth of fascinating things, which I would never have suspected. Building actual projects provides you with these wonderful Zen moments where your whole plan of action is suddenly brought up short by something unexpected. You find there's a gap in your reasoning and there's nothing in your plans for connecting it. Getting stuck is a wonderful thing because it means you're about to learn something that will change your perspective.
Some of the interesting problems I've overcome so far:
Problem: The hardest part of the whole project is... wiring. If you've never tried to build a microprocessor circuit, you might think that the chips and the signals are what's important. For the most part, those will sort themselves out as you improve your design. But your schematic doesn't give you any hint how to keep hundreds of wires from turning into a horrible rats nest. Bad wiring is the perpetrator of electrical gremlins, and wiring is by far the most time consuming aspect of building a homebrew computer.
Solution: Ribbon cables to keep the mess manageable, and patience.
Problem: The 6502 doesn't always behave the same way every time you reset it. Sometimes it produces junk for six machine cycles before jumping to its reset vector, and sometimes it is seven or eight. This is a problem because my theoretical design depended upon carefully counting the number of machine cycles so that I would know when the 6502 is looking for its reset vector, so that I can substitute another number.
Solution: In my original design, I didn't give the Propeller any connections to the 6502's address lines. I was relying on counting machine cycles to predict what the address should be. I had to change my design, because I needed it to measure actual addresses instead. Plus, you really do need to know the machine addresses for debugging. Guessing doesn't cut the mustard.
Problem: The 6502 I'm using is rated for a 2 MHz clock. I would like to run the 6502 at a slower-than-normal clock speed while I'm debugging it, because certain electrical problems are mitigated by running the circuit more slowly. However, the 6502 uses dynamic RAM for its registers, which have to be refreshed. There is a minimum safe clock speed that will still keep the registers refreshed on time - but what is it?
Solution: It seems no one knows what the real minimum clock speed is. However, everyone agrees that 500 KHz is fast enough. In my own experiments, I found that some operations (like resets and interrupts) would still work at speeds as slow as 10 KHz, but others did not. I've taken to running the processor at 500 KHz normally, and 50 KHz for specific tests.
Problem: The 6502 lacks many "essential" bus control signals. When I first evaluated the chip, I thought, wow, this is really simple. It doesn't have all the confusing extra pin functions that other microprocessors have. Then I went to actually implement the thing and realized there were signals I needed which the 6502 doesn't provide.
Solution: The 6502 has a clock input, as you would expect, but it also has two clock outputs, for no obvious reason. When I first looked at the datasheets, I ignored these because I didn't understand what they did. You can't ignore them. The reason the 6502 appears to be simpler in its bus control pins is that other microprocessors include bus-decoding logic on the chip, but the 6502 makes you use the two clock-phase outputs to synthesize your own bus logic. I first used NAND gates to combine the signals in the way I needed, but my new design will use firmware on the Propeller to decode it on the fly.
Problem: The 6502 single-step feature is very poorly documented, and poses a complex logic design problem. It is also very easy to lock up the 6502 if the single-step pin is asserted at an inconvenient time. (I think they tried to gloss over that in the official docs.)
Solution: I found a schematic of the 6502 single-step circuit that the man himself, Steve Wozniak, used on the Apple II. It was a brilliantly designed state machine using a pair of D-flipflops in a 7474 chip. I'm proud to report that I independently came up with the same idea of using a 7474, and had something already that looked remarkably like Woz's circuit - except for the small detail that mine locked up the 6502, but Woz's actually worked. I analyzed his circuit and realized that the clock-phase outputs (mentioned above) were the piece of the puzzle that I had been missing. Using a flipflop configuration inspired by Woz's, I at last got single-stepping to work, but no sooner had I gotten it working than I realized I could do it in software on the Propeller, without any additional chips.