]CATALOG
 
DISK VOLUME 254
 
 A 002 HELLO

]

Apple II emulator in C

Here is the source for the Apple II emulator in C that I wrote with Tom Markson back in 1990. This was done on an Amiga 2500 running Unix; the speed of the emulator was about 1/5th of a real Apple II.

These days a typical PC has no problem running Apple II programs at speed or faster. There are also better emulators available now (mine didn't do graphics, although someone sent me some code to extend the emulator to use X that I never folded back in).

Apple II disk images:

Design notes on the emulator: (from notes.txt)


Speed is everything in the emulator.  I use macros instead of functions;
autoincrement wherever I can; suitably sized variables to take advantage
of wraparound so I don't have to & 0xFF or & 0xFFFF.  These things are done
for speed, not safety, although they should work on most machines.  Hopefully
the safety_check() routine will assert fail if at least some of these
assumptions are not true.

The main loop of the cpu is handled by a big switch statement.  There
are no function calls since they incur a large overhead.  I count on
your compiler generating an efficient jump table for the switch.

The Apple's memory is represented by a 64K array of bytes (unsigned char).
All memory references, with the exception of special locataions in the
C000-CFFF range, come unintercepted from the mem array.

References in the C000-CFFF range are taken from the mem_map() function.
It implements things such as the keyboard read & strobe locations and
the bank switching toggles.  If mem_map() doesn't have a special hook
for a Cxxx location, it will return the mem[] value associated with
the location.  Thus you can load device PROM images there and you will
be able to reference them.

Memory stores may be caught on a per-page basis.  For example, stores to
the C0xx range are caught by store_c0().  Besides the Cxxx functions,
store catching routines are used for the memory mapped video from $400-7FF
also for the language card.

Certain PC values are intercepted and dealt with by C routines.  The 64K
array jmp_tbl[] determines whether a location is "caught"; if zero, nothing
will happen.  If non-zero, the value is passed to jump().  Pc's are only
intercepted on JMP and JSR instructions (so that we don't pay a speed
penalty for every instruction fetch).  This imposes obvious limitations
on what code can be caught.

Intercepted routines include the ROM routines to handle scrolling, the
ROM wait and bell calls, and some Cxxx calls.  Scrolling must be caught
and done separately or it looks horrible.  RWTS and Prodos are also
caught at the block read/write level to speed up disk access.

Note that none of the jump intercepts are necessary.  They speed up
scrolling and disk access (for Prodos & DOS 3.3) quite a bit, but you
can turn them all off and the emulator will still run.  The memory map
support is enough.

The Pc catches ignore whether the language card is active or not; instead,
they look for key values to see if they routines they're supposed to sit
on top of really are there.  If not, they let the real code execute.
If we just caught ROM calls, and didn't catch calls that executed when
the RAM card was active, then copying the ROM into the language card and
switching to it would cause us to lose all of our interception.

Beware when adding intercepts for the ROM or other functions: there's
always some piece of code that depends on a side effect of a function.

The blocks in the disk image are ordered in DOS 3.3 layout.  The prodos
code uses a mapping table.  Thus, one Prodos block consists of two non-
contiguous 256 byte blocks in a disk image.

I only have the old Disk II boot prom from $C600.  Jump.c patches it to
look something like a Prodos device controller, so that Prodos has high-
level disk intercept support.  I don't know if a prom image from a newer
disk controller will work or not.

The emulator supports raw access to the disk controller by nibble
encoding sector images as they're fed in through the shift data register.
A routine decodes the motion of the disk head based on references to
the stepper magnets.