I’ve done a bunch of work on this blog with 6502-based systems, but there’s been a pretty glaring omission so far: the Apple II series. This has mostly been because it’s very hard to get modern tools to produce artifacts that Apple II emulators are willing to read.
The reason for that has a lot to do with the smarts for I/O living in the CPU and not on the disk drive, which means that we won’t get anything done without a proper disk image, really. And the best tools for Apple interoperability were not merely proprietary but commercial until quite recently.
That’s changed, and this time when I went to try to run some code on a simulated Apple IIe, I actually succeeded. It’s still a bit complicated, though. Here’s how I did it.
The emulator I used was AppleWin. Accurate, easy to use, handles a goodly number of disk formats, but is unfortunately Windows-only. I haven’t found any other IIe emulators I actually like, though. Open to suggestions.
To work with disk images, I used CiderPress. This recently got a heavy rewrite and the disk utilities can in principle be compiled to a standalone library that works anywhere, but CiderPress itself is still Windows-only.
Making a disk image
CiderPress makes this trivial. I click “create a new image”, select DOS 3.3, give it a volume number, and specify a filename. AppleWin will boot the resulting image, albeit straight into Applesoft BASIC.
Writing a binary program
Unlike the C64 and its PRG format, information about a program’s load address is part of its file attributes on Apple disks. That means that we can write our Hello World program with no metadata whatsoever:
.org $1900 ldy #$00 lp: lda msg, y beq done ora #$80 jsr $fded iny bne lp done: jmp $03d0 msg: .byte 13,"HELLO, APPLE WORLD!",13,0
When we assemble this program, we need to give it a name like
HELLO.WORLD#061900.BIN. The HELLO.WORLD is the filename on disk, the 06 is the file type (binary), the 1900 is the load address, and the .BIN is also the file type, just to make sure. Open your disk image in CiderPress, add it as a file, and make sure that “use file attribute tags and guess file type from extension” is set. You can now enter the command
BRUN HELLO.WORLD and see the program run!
Quirks of that program, aka Welcome To The Apple II
- We can’t name the program
HELLObecause that’s the default autoboot program and under normal circumstances it must be a BASIC program.
- We have to set the high bits on our characters on the way to the character-out routine at
$FDEDbecause that’s where normal characters live. The first 128 characters are inverse-video and flashing variants.
- Instead of returning with
RTSwe must return with
JMP $03D0, which is much like the C64’s
JMP ($A002)—a jump to the BASIC warm-start vector. This is necessary because if you try to BRUN a program that calls the character-out routine, the system ends up in a state where it will hang on a return-from-subroutine. Machine language routines invoked via the CALL statement (equivalent to CBM BASIC’s SYS) do not have this problem.
Writing a hybrid program
This is a little unusual—it’s far more typical to BRUN your target program or have the BASIC program BLOAD it into place and then call it itself—but it’s still totally possible to wrote BASIC loader stubs for the Apple II the way we did for the C64. The exact token values are a little different, but the structure is extremely similar; both Applesoft BASIC and Commodore BASIC were developed off of Microsoft’s base. They even use an identical base address:
.org $0801 .word next, 10 .byte $8c, " 2062", 0 next: .word 0 ldy #$00 lp: lda msg, y beq done ora #$80 jsr $fded iny bne lp done: rts msg: .byte 13,"HELLO, APPLE WORLD!",13,0
When you assemble this program, give it a filename like
HELLO.WORLD.BAS. CiderPress will identify it as a BASIC program and set attributes accordingly. You will probably want to rename away the .BAS from the filename on the disk, but the resulting program can be LOADed and RUN like any other BASIC program.
That’s great, but so what?
A fair question, really. Except for having access to more memory and different peripherals, the Apple IIe was really a generation behind the C64, and it’s somewhat obnoxious to work with as a result. Still, I’m sure we’ll find a few fun things to make it do.