Apple ][ notes

Upon purchasing the Virtual ][ emulator for OS X, I decided to experiment with the original Apple ][. Here are my notes from those endeavours.

Note: throughout I use the caret (^) to denote a control character, eg “^P” means “Control-P”, as I find the Apple manual method of subscripts to be counterintuitive, and writing out “Control” to be tedious.

word size:           

System boot / mode selection

At system boot, you are in the Monitor, indicated with an asterisk prompt (*). From here, you can enter Integer BASIC, boot from floppy, execute the mini-assembler, and so on.

Entering BASIC

(BASIC manual, pp. 11–16 [PDF pp. 10–13]; Redbook, pp. 28/72, 87 [PDF pp. 33/77, 92])
*^B
*FEB0G
*E000G
Enter Integer BASIC
“Cold” launch; erases any loaded program
*^C
*FEB3G
*E003G
Enter Integer BASIC
“Warm” launch (continue); preserves program state
*3D0GEnter Integer BASIC
via DOS call vector (requires DOS to be loaded)
Where do these numbers come from?

Brilliantly, the Apple ][ ROM comes with a complete listing, which is invaluable for looking up constants like these. The relevant section looks like this:

FEB0: 4C 00 E0  XBASIC   JMP   BASIC      TO BASIC WITH SCRATCH
FEB3: 4C 03 E0  BASCONT  JMP   BASIC2     CONTINUE BASIC

And indeed if you disassemble that part of the Monitor, you get:

*FEB0L

FEB0-   4C 00 E0    JMP   $E000
FEB3-   4C 03 E0    JMP   $E003

Returning to the Monitor

(comp.sys.apple2.programmer FAQ #004, also Redbook p. 88 [PDF p. 93])

There are three useful entry points for returning to the Monitor:

hex    dec
$FF59  -167  ENTER MONITOR RESET, TEXT mode, "COLD START" 
$FF65  -155  ENTER MONITOR, ring BELL, "WARM START" 
$FF69  -151  Go to MONITOR

The source listing labels these three RESET, MON, and MONZ, respectively. In BASIC, use the CALL statement, eg:

>CALL -151

Entering & exiting the mini-assembler

(Redbook, p. 69 [PDF p. 74])

The entry point for the mini-assembler is $F666. So to enter the mini-assembler from the Monitor:

*F666G

And from BASIC:

>CALL -2458

Of course, you can use the RESET button to return to the Monitor. Perhaps a more elegant way would be to use one of the Monitor’s entry points, eg:

!$FF69G

Booting from floppy

(Wikipedia: Apple DOS)
*n^P

where n is the desired slot number. On Virtual ][ it’s slot 6 by default, thus:

*6^P

Strangely the Redbook (p. 71 [PDF p. 76]) says that ^P:

Sets printer output to I/O slot number (X).

which seems a bit nonsensical. But it seems that the ^P command executes whatever is in $Cn00, thus one could do, eg using slot 6 ($C600):

*C600G

Or, from BASIC, eg one of:

>CALL -14848
>PR#6

Monitor commands

(Redbook, pp. 68–71 [PDF pp. 73–76])

These are only the most common commands:

[address1][.address2]*1024.1048
*.4096
*C0F2
*
Examines memory.
If address1 is omitted, displays data starting at current position to address2.
If .address2 is omitted, displays a single byte at address1.
Pressing RETURN on a blank line displays the next 8 bytes.
[address]: data [data …]*A256:EF 20 43
*:F0 A2 12
Changes memory.
If address is omitted, starting position is the next byte after the last one previously written.
[address]G*300GGo (execute) from specified address.
Can also continue execution without specifying address, eg after pressing RESET during a trace or step.
[address]T*800TTrace execution from specified address until a breakpoint (BRK instruction) is reached.
[address]S*C050SStep execution from specified address.
Use S for each successive step.
[address]L*C800LDisassemble (the next) 20 instructions.
address1.address2R*300.4FFRReads cassette data into memory.
The address length must match the amount of data read.
address1.address2W*800.9FFWWrites memory to cassette data.

Mini-assembler commands

(Redbook, pp. 69–70 [PDF pp. 74–75])
[address:] instruction [operand …]!C010:STA 23FF
! STA 01FF
Assemble a mnemonic 6502 instruction into machine code.
Omitting the address: places the instruction in the next address.
Note the space preceding the instruction is required regardless of whether the address: is specified.
$monitor-command!$C800LExecutes a monitor command, then returns control to the mini-assembler.
After such a command, it’s a good idea to explicitly restate the desired assembly address.

DOS 3.3

Formatting disks

(DOS Quick Reference Guide)

Boot into the desired DOS version using some known working DOS boot disk. If you have a program you’d like to execute at boot, LOAD it now, eg:

>LOAD FUNIONS

Otherwise, create a dummy BASIC program so you don’t get an error at boot, eg:

>NEW
>10 END

Initialise the disk:

>INIT HELLO

(HELLO appears to be the canonical choice, though you can use whatever you like.) This saves the current program to the disk with the name HELLO, which will be executed at boot.

By default, this creates a “slave diskette” (1970s–80s terminology!) suitable for booting on machines with your current memory configuration. If you want a relocatable DOS boot disk, you’ll now want to use MASTER CREATE, eg one of:

>BRUN MASTER CREATE
]RUN MASTER

Executing DOS commands from Integer BASIC

(Apple kb article TA30047)

Looking at the HELLO startup file on my custom Integer-BASIC-only S-C Macro Assembler disk, you’ll see lines like:

>LIST 80,100
   80 CALL -936: PRINT "CATALOG":
       PRINT "INT"
  100 PRINT "BLOAD S-C.ASM.MACRO.1000.
      2.0": CALL 4096

There are actually invisible ^D characters there which cause those PRINT statements to effectively execute DOS commands. If you could see them, they’d look like:

>LIST 80,100
   80 CALL -936: PRINT "CATALOG":
       PRINT "INT"
  100 PRINT "BLOAD S-C.ASM.MACRO.1000.
      2.0": CALL 4096

It’s important that these be inside the quote marks.

Solid cursor

One of my “pet peeves” about the Apple ][ is that blinking cursor. Its blink rate is very fast to my eyes, and distracting when I have several programs open (besides the Virtual ][ emulator). My preference is a solid cursor, like the NetBSD default.

Apple published an Applesoft BASIC program to accomplish this, but it has bugs, and didn’t seem to play nice with the version of DOS I was using.

The original snippet from Apple

(Apple kb article TA40710)
 10 FOR A = 935 TO 941
 20 READ B
 30 POKE A,B
 40 NEXT A
 50 POKE 56,167
 60 POKE 57,3
 70 CALL 1002
 80 END
100 DATA 72,41,63,145,40,104,76,27,253

At first glance, this appears to write some data to $3A7 (935), then a 16-bit word $3A7 to address $38. But there’s 9 bytes of DATA – and only 7 locations (935 through 941) to put it in. So that 941 should really be 943 (or the 935 should be 933) so that all of the bytes are written.

That DATA is machine code, which looks like this when disassembled:

*3A7:48 29 3F 91 28 68 4C 1B FD

*3A7L

03A7-   48          PHA
03A8-   29 3F       AND   #$3F
03AA-   91 28       STA   ($28),Y
03AC-   68          PLA
03AD-   4C 1B FD    JMP   $FD1B

At system boot, the contents of $38 are:

*38.39

0038- 1B FD

Hey, that address looks familiar! From this it appears that address $38 is being patched to execute the above code at $3A7 before it jumps to its original location, $FD1B. This works just fine, provided that DOS isn’t loaded.

DOS I/O interception

(Apple II Textfiles: the DOS 3.3 Anatomy)

After booting DOS, the situation changes slightly. Now $38 points to a DOS I/O handler at $9E81. Not only that, there are protection routines that prevent you from changing this, eg:

*38.39

0038- 81 9E
*38:1B FD

*38.39

0038- 81 9E

This is because DOS is intercepting all I/O requests – including those from the Monitor. After much digging, I was able to locate the address in DOS, $AA55, which points to the original I/O handler ($FD1B). When DOS boots, it copies $38 (labelled KSW) to $AA55 (labelled KSWTRUE), then patches $38 to its own I/O handler at $9E81. With DOS loaded, this works:

*3A7:48 29 3F 91 28 68 4C 1B FD

*AA55:A7 3

After a RESET, $38 will be reset back to $FD1B. I’ve found it best to change $38 before reconnecting the DOS I/O hooks so that it will save $3A7 to $AA55, eg:

*38:A7 3

*3EAG

*38.39

0038- 81 9E
*AA55.AA56

AA55- A7 03

In fact, this is the same procedure that the Applesoft snippet tried to use (]CALL 1002 is *3EAG); it failed due to the DOS I/O interception protection.

A compatible solution

Integer BASIC

Tape operation

(BASIC manual, pp. 13–14, 17, 76 [PDF pp. 11–13, 43])
>LOAD
>SAVE

Doesn’t get much easier than that, does it?

LISTing output one page at a time

(The Apple Gazette: List Apple Integer Basic Programs One Page at a Time)

GRaphics mode

(BASIC manual, pp. 30–35 [PDF pp. 20–22])
>GR>GREnters Graphics mode.
GR mode is a 40×40 graphics area, with a 40-column, 4-line text area below.
>TEXT>TEXTEnters Text mode.
TEXT mode is a 40-column, 24-line text area.
>COLOR=color>COLOR=12Changes the plotting color.
color must be 0 ≤ x ≤ 15.
>PLOT col,row>PLOT 12,34Plots a square at the specified location.
col must be 0 ≤ x ≤ 39.
row must be 0 ≤ y ≤ 47 (but y > 39 starts clobbering the text area).
Locations are specified left-to-right, top-to-bottom.
>HLIN col1,col2 AT row>HLIN 0,39 AT 20Plots a horizontal line from col1 to col2 on the specified row.
>VLIN row1,row2 AT col>VLIN 11,32 AT 7Plots a vertical line from row1 to row2 on the specified col.

S-C Macro Assembler

(Paul Schlyter – Apple 2 stuff)

Versions, memory, etc.

Which version? I suggest the S-C Macro Assembler 2.0, not the S-C Assembler II 4.0; despite having a higher version number, it’s four years older!

$1000 or $D000? $1000. On the original Apple ][ with the Programmer’s Aid routines, $D000 is already used for the high-resolution graphics system.

Building a working disk

(SCMASM2, p. 1)

The documentation helpfully suggests:

You will probably wish to move the version of the assembler you
usually use, with your favorite driver and EXEC loader, to your
working disks. Do it!
This seems like an excellent idea, especially for the original Apple ][, which can’t run the Applesoft BASIC HELLO program on the S-C disk. (In any case, the S-C disk doesn’t boot DOS properly, which is annoying enough on its own to merit building a working disk.)

The overall procedure looks like:

  1. Create a new bootable DOS disk using the INIT / MASTER CREATE commands (see Formatting disks above).
  2. Copy the desired assembler version, eg S-C.ASM.MACRO.1000.2.0, to that new disk.
    This could be done with the COPY (Integer BASIC) or COPYA (Applesoft BASIC) programs, or an external utility like Copy II Plus.
  3. Edit the HELLO BASIC program to execute the assembler upon boot. At minimum, it would need to include a line like:
    10 PRINT "BLOAD S-C.ASM.MACRO.1000.2.0"
    20 CALL 4096
    Note that the character is invisible.

80-column support

(SCMASM2, pp. 2–4)

S-C Macro Assembler 2.0 supports three different 80-column cards:

Quick start

(SCMASM10)

Programmer’s Aid #1

Floating-point math

High-resolution graphics

SWEET-16

References

  1. Apple ][ “Redbook” Reference Manual (January 1978) – 30th Anniversary Edition
  2. Apple ][ BASIC Programming Manual
  3. Programmer’s Aid #1: Installation and Operating Manual
  4. [Apple] DOS Quick Reference Card
  5. Beneath Apple DOS

Feel free to contact me with any questions, comments, or feedback.