14 ms·
Once, while writing a new program-loader-and-debugger/"bios" for a Z80 clone, I had a particularly nasty heisenbug. The problem was my new code "usually" worke
by pdkl95 13y ago
Once, while writing a new program-loader-and-debugger/"bios" for a Z80 clone, I had a particularly nasty heisenbug.
The problem was my new code "usually" worked. About 25% of the time it would simply fail to do anything (it worked perfectly the other 75% - "umm... aren't computers supposed to be deterministic?") Of course, every single time I did anything to try extract any useful information from the device, it would work 100% of the time. Even tossing a quick 2-byte sequence to flip an I/O pin made the problem completely go away.
The problem was, of course, that the hardware wasn't quote done rebooting, and needed to be left alone a tiny bit longer after hitting the RST pin. About 8 cycles longer than when the hardware engineers assured me it would be "completely safe". Any time I added debug code, it simply worked as the needed delay, and was solved by a very carefully documented sequence of NOOPs.
What made this particularly infuriating, though, was it's seemingly arbitrary sensitivity to when the real code was started. Depending on how much you padded with NOOPs, several behaviors were observed.
#NOOP | Behavior
---------------
0 | original 75/25 ok/fail split
1 | always failed
2 | always worked
3 | always worked
4 | worked ~95% of the time
5 | ~80/20 ok/fail split
6 | ~50/50 ok/fail split (not a lot of data)
7 | *almost* always worked (I think I saw it fail once)
8+ | always worked
Of course, the various stuff I would add for debugging tended to line up with the cases when it DID work.
sigh
I miss working with that chip. Z80 assembly is kind of fun. Well, except for when my boss told me my new loader had to work on our slowest 4Mhz part. Receiving a program over a 115kbaud serial line, verifying CRC-8, and writing it to flash is pretty hard when you have to do it less than ~100 clocks/byte....
- userbinator 13y agoOn some x86 PC BIOS, there is a do-nothing delay loop (I've seen 20K and 64K cycles) not far from the reset vector, and I had figured that it was there because of this exact same reason; to give the system some more time to reach a stable state. If the voltages haven't completely settled, or there are still some undefined levels somewhere, then the CPU might be able to execute some if not most instructions correctly, but behave incorrectly for others --- overclockers are probably quite familiar with this "analogue" failure characteristic.
- SpikedCola 13y agoReminds me of the Read-Modify-Write procedure on a lot of PIC devices. Our teacher taught us to randomly place NOP instructions until it worked; we all thought he was crazy until we realized what he was working around. (The actual solution was to write to the LATx registers instead of PORTx)