My name is Dave and I'm a software developer.
I both create and fix defects in code that I've written. Hopefully I find the bugs quickly, but sometimes they linger for weeks, months, years, before being discovered or reproduced.
My story is not unique. It is difficult or impossible to write software without introducing defects. Computers are complex systems, but very obedient. They do exactly as they are told if you know how to speak their language, precisely, without misunderstanding or any inaccuracies. Problems can crop up if the developer didn't understand the system requirements in the first place (design/requirements issues), didn't thoroughly test all inputs and code paths, didn't understand concurrency issues, made assumptions, or makes the simplest of mistakes. As humans, we learn to overlook some inconsistencies, mistakes of others, so as to not disrupt the social norm. But with most of the languages we use with computers (Assembly, C, C++, C#, Java, etc.) many of these don't allow for the slightest of change. Some scripting languages (HTML, JavaScript, CSS, etc.) allow for some variance, but still are expecting a valid input.
Am I making an excuse for my mistakes? No, but explaining that they will exist. I wrote a limited Commodore/6502 emulator a while back and have ported it to various platforms with demonstrable results. I can run Commodore 64 and related systems at the BASIC prompt and it appears to mostly function normally.
Then I ported to Vic-20 including adding full-screen editing support and conversion from Commodore 64 key scans to Vic-20 key scans. And it did not work. But I swore up and down that I did everything correctly (ha!). Then dove in deeper to see what was different. Turned out the ROL ABS and ASL ABS instructions were doing the value shift but not storing the result in memory. A normal 6502 knows how to do this just fine, but the emulator needed to accurately replicate this behavior to be correct. The fix was to store the result at the absolute 16-bit address.
My first mistake was that I never performed a formal test of the instruction set of the emulated 6502. I knew they existed, but when bringing up the C64 I only spot checked a few instructions, and even compared traces between Vice and my emulator to note differences, and correct the emulation in a few places. (There's a reason my trace looks exactly like that from Vice -- so the comparison would be easy!) But once the system appeared to function correctly, I stopped testing.
Fast forward over 3 years later, and I know that some of my systems are not 100% correct. The effort I had brushed away came back to nag me. I really should test better. I have a saying that if it's not tested, it's not working. And I had ignored that saying. But I buckled down and did the effort of running a 6502 test suite against my emulator. And sure enough there were problems.
And since I have multiple emulator instances, the problems were slightly different, as I hadn't applied fixes consistently between all of them (still have missed a few at date of this article! STM32, mbed, TypeScript still have known bugs). [update 2023-11-05: TypeScript emulator updated with fixes]
Here are the instructions and features of the 6502 that required fixes in my emulator:
ROL (absolute address)
LSR (absolute address)
PHP (B flag)
PLP (B flag)
IRQ (push processor state without B flag)
(zp,X) indirect zero page indexed by X addressing not truncated to byte address when overlap page, affecting both load value and store value
SBC resulting in a negative result when in decimal mode
Many changes are now checked in for C++, C#, Arduino, M5, Teensy and related projects.
There are remaining bugs in emulation, probably closer to individual system systems outside the 6502 emulation. A few issues can be reproduced on demand, so I can tackle those next.
But the 6502 emulation should be good, at least as much as it has been tested.
Thanks to Klaus Dormann for these 6502 tests.
Reference: 6502_65C02_functional_tests