My great aunt used to say that she had a great Forgettery. I think I inherited it. My Remembery is faulty.

I can remember really arcane and worthless trivia, like "CALL -151" enters the machine monitor on an Apple ][ and that the HERO-1 robot had a built-in speech synthesizer with the phrase "I don't do windows". Useful everyday stuff, like where my wife said the various knives belong in the knife drawer? Not a chance.

This works out pretty well for this project, though! I still remember enough of how to get around the Apple //. The assembly language looks familiar. I can poke at executables in memory. I can boot various kinds of DOS and transfer files between them. With ProDOS and Virtual ][, I can copy files back out to my Mac and use all of the tools I've got there, too. But I need a bit of a refresher - I haven't looked at the internals of the Apple //e since 1989. I don't remember what $C010 is, but I do remember that $C000 is the beginning of ROM. But it's a fast study: I quick remember zero-page memory, Applesoft BASIC tricks with magic values therein, and find references for various ROM entry points. The TMI disk is a DOS 3.3 disk; I use disk Copy to copy it to a ProDOS disk, boot to ProDOS, and then use Virtual ][ to copy it out to my Mac. Lovely.

Do I know where in memory this binary even loads, so that I can poke at it in the virtualizer? Nope. But a little poking around memory, and I find it at $1000.



Do I have a disassembler for 6502? Well, no. But several exist. I download a few and find them all lacking.

The 6502, being an 8-bit processor, has at most 256 opcodes. It can't be that hard to write a disassembler. When faced with the same problem for the PIC, I wrote pic-disassemble, a (wait for it) disassembler for (ahem) the PIC. (Bet you didn't see that coming.)

So an hour later, and I've got a perl script that disassembles. Just like all the other disassemblers that I found and didn't like. But from here, I can augment it to do anything I want!





I want it to be able to label memory points. I want it to be able to mark regions of memory as data, so they're not disassembled. But mostly I want it to be able to draw call flow graphs. Like perhaps this one!

(The full-size copy is here, on my web server, if you really want to look at it.)

From the call flow graph - which initially just had nameless labels, no descriptive ones like "MAINLOOP" - I was able to guess where the highlights are. MAINLOOP was my first target. Then I named ROM entry points in the assembly listing, followed by a lot of reset-to-monitor; call subroutine manually; see what happens.

Eventually I got tired of pure exploration and went in for the kill.

What does this program *do*?

0x1000 ORG 0x1000 0x1000 JSR ASKINIT 0x1003 L1003 JSR F8ROM:INIT 0x1006 JSR F8ROM:HOME 0x1009 JSR PRNTMENU 0x100C MAINLOOP LDA #$FF 0x100E STA CURSCR 0x1011 JSR PRNTTIME 0x1014 JSR RUNTILL 0x1017 CMP #$84 0x1019 BNE L1022 0x101B LDA #$2 0x101D STA $5B28 0x1020 BNE MAINLOOP

Well, there's the beginning of it. Simple enough. The ASKINIT function asks if you want to initialize the reactor core, and then returns. The F8ROM functions are part of the machine's rom - in this case, clearing the screen and returning the cursor to the top-left. The PRNTMENU function prints out the list of screens in the game. And so on. Boring.

I spent some time looking at code bits that read from the hardware KBD register, and that cleared the KBDSTROBE register (telling the machine that you're ready for the next keypress). Which lead me to this piece of the program:

0x543F GETKEY LDA KBD 0x5442 BMI L5446 0x5444 SEC 0x5445 RTS 0x5446 L5446 BIT KBDSTRB 0x5449 STA $18 0x544B CLC 0x544C RTS

Read from the keyboard; if the high bit isn't set, then there's no input, and we'll set the Carry flag and return. If the high bit *is* set, then we'll clear it, store the result in zero-page location 0x18, clear the carry, and return. Clearly this is a utility function to get a keypress and return (via the Carry flag)... Read more »