Tip of the day, #35
Debugging. Part I. Hardware. You can use some very simple tools to debug your new home-made computer without expensive
logic analyzers, emulators, simulators, or debuggers. Starting with a longish routine to actually do something useful
will usually disappoint, as it probably won't run the first time and you won't have the means to debug it yet. Start
with a very simple routine to just toggle an output bit, for example. If the computer doesn't do anything at all, first
use your oscilloscope to see if you get a good reset. (See the Reset section.) Then
make sure you have a clean Φ2 toggling at the expected frequency. (Use the scope probes' x10 setting for all but
the lowest frequency work.) Are address and data lines toggling? If they sometimes don't go as high or as low
as expected, maybe there's bus contention (meaning two things are trying to output data on the bus at the same time). If
an IC's output voltage never gets very close to power or ground, did you forget to hook one of these up to it? Is IRQ
or NMI going down unexpectedly? Is the power supply current approximately what you expected? Don't forget also the
single-cycler clock source shown about 3/4 of the way down the clock-generation
page. If the hardware seems fine, move on to software. (continued)
Tip of the day, #36
Debugging. Part II. Software. A simple effective debugging tool is a piezoelectric beeper, the kind that's .010"-.020" thick and needs an AC signal in order to sound.
The one at the top is in a black plastic housing that's about 3/8" thick and improves the volume if there's no sounding board. The small one is 3/4" diameter and .012" thick. The bigger one that's tarnished from skin oils and soldering at four points around the edge (but would still work perfectly fine) is 1-3/8" diameter and about .020" thick.
They can be taped or soldered onto the breaboard, so the entire breadboard acts as a sounding board. I've even used scissors to cut them down to fit a tight space, like this one on the back of a mostly analog breadboard with a microcontroller on it:
Very simple beep and delay routines should run on the first try. Write about 3 beep routines of different frequencies and maybe different durations so you can tell them apart. These should save the processor registers like an ISR does. Once these work, call them at appropriate places in your next routine. Put delays between the beeps to make them easier to separate when you hear them. Does it make it to point A before crashing? How about point B? Does the loop that point C is in get run the right number of times? Keep re-assembling and trying your code, each time narrowing down the problem area. LEDs can also be used to monitor the progress; but the software-driven beeper's sound "signature" assures you that the output is not a random effect of a crash. As code development advances, you might incorporate other debugging routines; but in the absence of expensive debugging tools, the lowly beep is indispensable as a "crash-finder."
Without a digital-storage oscilloscope (DSO), you can still study a pulse train output by making the software repeat in
a loop for an analog 'scope. For real-time, things that cannot be slowed down to deliver a beep can be watched on the scope
with probes on various I/O lines. Sometimes it can be a challenge to get the triggering and sweep rate just right, but it's
usually doable. Added 11/29/21: See my post here
about using as little as a single I/O pin to output a set of status bytes to view on an oscilloscope for troubleshooting.
Tip of the day, #37
Debugging. Part III. An ounce of prevention... Take a building-block approach. Start with the really simple stuff, then use those things as components to build or debug more advanced components, and so on. The job is only complicated if you don't break it down into manageable chunks, conquer them, and then put them together in steps. Working for small, low-budget outfits (which I enjoy), I have found that the lack of expensive debugging tools actually teaches you to write better code. (Many of the development tools are free today, but it wasn't always that way.) You can't have the attitude that "I'll whip out this code in record time and debug it later." Out of necessity, I've become more structured and neat in my programming, documenting everything thoroughly, making the code as readable as I know how, and proofreading.
And speaking of structure, after you get a little experience, I would like to encourage you to make good use of your assembler's macro capabilities. Around 2012 I started using macros to make program structures like high-level languages have, like FOR...NEXT, the CASE structure, IF...ELSE...ENDIF, BEGIN...WHILE...REPEAT, etc.. In most cases there is absolutely zero penalty in assembled program size or run speed, because the macros are assembling exactly what I would do by hand, just without showing the ugly internal details every time. I have an article about it here, and a couple of my best examples of usage are shown near the end of my article on simple methods of multitasking without a multitasking OS.
Large companies have been starting to see the value in the proofreading, and the industry magazines started publishing articles around the year 2000 on code inspection and having committees of the programmers' peers proofread the code. I sometimes catch bugs when further commenting code that's already working but not exhaustively tested yet. I comment as if trying to explain it to someone else who hasn't been following my train of thought on it. (If I come back to change it a year later, I'll need the comments anyway.) As a result of this madness, no user has ever found a software bug in any product or automated test equipment I programmed. The projects have had from 700 to 10,500 lines of code.
BTW, using a lines-of-code-per-day benchmark of programming performance is a sure way to end up with inefficient, buggy code that's hard to figure out and fix or modify later. I once worked with a programmer who typed non-stop. I always wondered what he was typing. After he left the company, I had to fix a 4-page routine he wrote. When I was done, it was down to a half page, bug-free, clearer, faster, and did more with less memory. (Eventually most of what he wrote had to be redone.)
Here's a debugging tip that doesn't seem to fit anywhere else: Mind your number bases! You can waste a lot of time
debugging problems caused by specifying for example 56 when you meant $56.
Tip #40 is not directly related to debugging, but gives a way to recover more quickly from crashes during development.
It is common for the beginner to want all the fancy tools too soon, and these tools insulate him too much from really learning what goes on at the heart of the machine, giving him a disadvantage that takes much longer to overcome. A sure result down the road is more bugs, some of which he won't be aware of until after the bugs have been a secret cause of a lot of inconvenience, equipment damage, or worse. It's kind of like giving young kids a calculator to multiply and divide with before they really have an understanding of what these procedures even are. The appropriate thing is to get them well acquainted with, and practiced at, doing it with paper and pencil, before moving on. A very smart engineer I work with marvels at how I can quickly calculate logarithms (for decibels) in my head. He's just slightly too young to have used a slide rule, having started with calculators. Same kind of thing.
The last half of section 17 (on general steps for a successful project) is about how to more effectively get help on the 6502.org forum if you need it.
Program-writing <--Previous | Next--> Programming tips
last updated Dec 24, 2021