Good news! I tracked down my checksum bug last night, and just in the nick of time, everything is working. I can both LOAD and SAVE from EhBASIC, and my little SBC is happy. Finally, a Retrochallenge that I’ve completed successfully!
For the technically minded who are interested in the gory details, I’ll explain exactly what was going wrong. BASIC programs are stored in tape files that contain two records.
Each record starts with a 770Hz tone as a header, followed by a short sync bit, then the record data, and finally a checksum. The checksum is just a running-XOR of the data.
The first record is just two bytes, it specifies the length of the data in the second record (little endian, which is, as we all know, the only true endianness).
The second record is the BASIC program data. The bug I was seeing on Sunday was that the checksum failed, but only on the DATA record, never on the LENGTH record. I could not for the life of me figure out what was happening. I went so far as to capture the tape data on my oscilloscope and walk over it bit by bit, by hand, and calculate a checksum. The checksum on the tape was correct, it should have read correctly. And of course the checksum of the LENGTH record was matching correctly.
Then I had a breakthrough, one of those things that should have been painfully obvious but was not. I discovered it by walking through the data that was loaded into memory off the tape. EhBASIC puts the program at $0301, so I dumped page 3 to see what was in it. It all looked correct, until I noticed that the checksum itself was being loaded as data. I had a simple, very stupid off-by-one error in my arithmetic, so I was slurping in the checksum as part of the program data by mistake. It was then reading garbage (random tape hiss noise) from just after the record and treating that as the checksum, which of course never matched. Aha!
I fixed my arithmetic, burned a new EPROM, and now, at last, I can SAVE and LOAD just like it’s 1977 all over again.
Tomorrow I’ll post a quick video, and a final Retrochallenge wrap-up.