erc an emulator for retro computers

Small changes, large effects

The most interesting thing, programming erc, is that small mistakes in understanding can have large, difficult-to-debug effects. To set the stage, I have been able to load software from the disk drive abstraction built into the emulator, and I can “boot” that software the way an Apple II would do; but I had not been able to read any other data. Or, rather, I should say the software was trying to, but managed to catch itself in an infinite loop inside the RWTS method that reads data from the disk. Clearly, that shouldn’t be happening, so what did I miss?

In these cases, I tend to go back over the implementation of the assembly codes for the processor. Something I’m doing isn’t right; and, it turns out, that was so: subtraction (via the SBC instruction) was removing more than it should be when carry was set, and less when it wasn’t. Oops.

And, suddenly, the infinite loop ended. But now I had a different problem; it seemed like I could read data from track 0, but couldn’t move to any other track. My tests showed that I could move the disk drive head using the right motor phases, but the software was never activating the motor phases in the right way to do so.

So now what? I began poring over the code each instruction executes; it occurred to me that status flag changes, which were handled with the mos6502_modify_status() function, were communicating the results of operations with an int. This was the Right Thing to see if carry should be set, because in many cases, carry is set if the result would require a value greater than a byte can hold.1

But it was the Wrong Thing to properly measure other conditions. Things that, in a real MOS CPU chip, would overflow 8 bits and wrap around, were not always doing so in the way expected. Suppose you had $01 in the A register, and you do SBC #$02. In an int variable, you would get -1, but aligned to 32 bits. Even if you took that result and masked it to just a byte (e.g. result & 0xff), you wouldn’t see the sign bit set. With an 8bit type, you would see the value go from $01 to $FF, which is what software written for the Apple II would expect.

So I spent some time last evening to change that throughout the app, and voilá: my software that I’m loading is actually moving the head to track 1 and to track 2.

Slowly but surely, we’re getting there.

  1. Carry is an unusual property in the MOS 6502 chip family. Different instructions imply different carry conditions; carry is set in ADC if the result is greater than $FF, but it is set in CMP if the A register is greater than DATA (for whatever you are comparing); in LSR, carry is set of bit 0 is set; in ASL, carry is set of bit 7 is set; context matters, and it’s hard to codify the meaning of that bit in a neutral function. 

A debugger for the Apple II

Lately, I have been testing erc with different ROMs to see what it’s doing—mostly, to see what it’s doing wrong. erc is able to disassemble machine code, and following along with that has been very helpful, but I decided what I really wanted was a debugger: something to stop execution, look at the machine state, and make changes to it.

So, I wrote a debugger:

FA62:D8                        CLD
erc> h
break          b    <addr>         Add breakpoint at <addr>
help           h                   Print out this list of commands
jump           j    <addr>         Jump to <addr> for next execution
printaddr      pa   <addr>         Print the value at <addr>
printstate     ps                  Print the machine and CPU state
quit           q                   Quit the emulator
resume         r                   Resume execution
step           s                   Execute just one opcode
unbreak        u    <addr>         Remove breakpoint at <addr>
writeaddr      wa   <addr> <byte>  Write <byte> at <addr>
writestate     ws   <reg> <byte>   Write <byte> into <reg>
FA62:D8                        CLD
erc> s
FA63:20 84 FE                  JSR   $FE84
erc> s
FE84:A0 FF                     LDY   #$FF
erc> ps
CPU:  A:00 X:00 Y:00 P:c7 S:fd PC:fe84
MACH: BS:00 CM:03 DM:04 MM:40 STROBE:00
FE84:A0 FF                     LDY   #$FF
erc> ws x d8
FE84:A0 FF                     LDY   #$FF
erc> ps
CPU:  A:00 X:d8 Y:00 P:c7 S:fd PC:fe84
MACH: BS:00 CM:03 DM:04 MM:40 STROBE:00
FE84:A0 FF                     LDY   #$FF

The debugger resembles gdb in spirit, if not in practice. I’m hoping to add a backtrace command so you can see what the previous JMPs and JSRs (jumps-to-subroutine) were; it’s not quite straightforward, as software can—and does, quite often!—use the stack for more than just managing function calls.

Finally, hello! This is the first post of the erc blog. I figured I’d put something together, if only to let people know how it’s going. (It’s going!)