A Very Simple 6502 Accessory That can Catch Very Complex bugs.
Debugging is hard.
Anyone who programs computers knows how hard it is to get stuff working reliably. Tiny oversights can lead to massive problems, often in ways that aren’t obvious. Patches get churned out on a daily basis.
Hardware engineers have it much, much worse. Unlike software, hardware can’t usually be patched. When you end up with hardware bugs, you usually have to live with them- possibly forever. Getting things right the first time becomes imperative.
Just like software debugging, hardware debugging requires specialized tools. Unlike software these will be actual, physical tools- very expensive tools.
I don’t want to spend too much on overspecialized equipment. My logic analyzer is already a bit of a fancy paperweight, and I “only” spent 250 bucks on it. Instead there is a cheap, simple debug tool you can make from scrap you probably already have. It won’t catch every problem, but if it catches just one it will pay for itself.
Hardware Debugging
One of the troubles with hardware debugging is producing the stimulus to reproduce a bug. You can slap all the monitoring equipment on a board you want; it’s worthless if you can’t figure out how to trigger the bug.
Case in point: my 6502 development board. I had a hard time getting it to work at all, much less find all the hardware bugs (there were a lot). Many of my initial assumptions no longer hold true. Like, I know my address decoder isn’t working the way I intended. But I don’t have a good way to “scan” the address bus to find what’s where.
The easiest solution to this problem is to wire the CPU so it always executes a NOP. With no other modifications this will cause the CPU to enter an endless loop that performs a read operation on every single memory location. This can be done by replacing the ROM with a custom NOP generator.
The NOPerator
This circuit is not an original work. It’s a more or less direct copy of this mini-project from 6502.org. I decided to put a few extras in and slap a catchy name on it.
My first modification is to give each data pin it’s own resistor. This is so any potential shorts or contention can be spotted. The diodes can be removed because I only want a 28 pin version.
I chose to break out the pins for easy access. This won’t cover all the interesting stuff, but it is a good way to check if the ROM is wired correctly. Unlike RAM, ROM can’t tolerate addresses being out of order.
Finally I threw a power LED on. No real reason, I just think it looks nice.
Building it was straightforward. I chose to swap the 1K resistors for 4K7 ones because I didn’t have enough 1K resistors. Everything else proceeded as planned.
Total cost is unknown; I’ve had this stuff lying around for years. If you had to buy new parts, I estimate a cost of around 2USD.
My chosen headers are slightly thinner than the standard square ones. Ideally you’d use turned-pin type headers. The standard size header is too big to fit most IC sockets. You can easily tap the signals off the exposed pins on the top.
I spent an hour or so building it, most of which was spent getting stuff together. For unknown reasons I had trouble getting the solder to wet the protoboard. Apparently I left them in storage too long. Flux helped, but did not solve the underlying issue.
Using the NOPerator
First pull the I/O, RAM, and ROM. The only things on the board should be the CPU support circuitry and address decoding. Plug the NOPerator into the ROM socket.
I had to pull the UM245R, RAM, ROM, and the HC125. Everything else can stay.
Power up the board, and the 6502 should start endlessly scanning the address lines.
Probe the address system however you please. I’m interested in how the UM245R and it’s flags get accessed.
One very long session with the logic analyzer later:
CLK actually corresponds to the UM245R read signal. It’s clear ADR10 controls the UM245R.
As above, but now CLK is connected to the HC125 that controls access to the UM245R flags. A11 is in control.
This little test setup confirmed the location of the UM245R ports. Adding in the state of the entire address bus (omitted for clarity) puts the data port at CBFF with flags at C7FF. This is simply decoded, so anytime the upper address is at C and ADDR10/11 is low the port is accessed.
Looking at my development notes (what few I have) this is correct. I think I got a little confused with binary-to-hexadecimal conversion and put the wrong value in my test software. I hacked in a value of C000 to get around this. Obviously this little hack only works when there is one port on the bus.
Finishing Up
This 6502 board just keeps giving me trouble. I’m pretty sure the number of hardware bugs I’ve caught is well into double digits now. With the NOPerator in my arsenal, I have a better way to tell if the problem is with my spaghetti code or just my spaghetti wiring.
The NOPerator only works for read cycles. The suggested way to test write cycles is to lift the R/W pin and hotwire it to always write. It would appear this is the only way to do this; there is no NOP-equivalent for write cycles.
Using the NOPerator I found another hardware bug. Turns out the resonator running the main clock is prone to getting knocked out of it’s socket. I didn’t need the NOPerator to tell me that, but it did eliminate a lot of potential false leads.
While 6502 focused, this basic idea can work with any other CPU. You may have to get a bit creative for more complex CPUs, but as long as there is a NOP- or NOP-like- instruction it can be done. It’s something I’ll keep in mind for other computer projects.
Computers are hard, and the NOPerator makes things a little easier. I’m not sure how long it would take me to track down address problems without it. Since my intention is to add onto my development board, I’m definitely going to run into more trouble down the line.
I can get back to working on the serial interface, which is the first step towards a fully interactive 6502 system. That’ll be a while off yet- though perhaps not as long as you’d think.
Have a question? Comment? Insight? Post below!