aiie/README.md

340 lines
11 KiB
Markdown
Raw Normal View History

2017-02-19 18:46:13 +00:00
Aiie!
=====
Aiie! is an Apple //e emulator, written ground-up for the Teensy
3.6.
The name comes from a game I used to play on the Apple //e back
around 1986 - Ali Baba and the Forty Thieves, published by Quality
Software in 1981.
http://crpgaddict.blogspot.com/2013/07/game-103-ali-baba-and-forty-thieves-1981.html
When characters in the game did damage to each other, they exclaimed
something like "HAH! JUST A SCRATCH!" or "AAARGH!" or "OH MA, I THINK
ITS MY TIME" [sic]. One of these exclamations was "AIIYEEEEE!!"
Build log:
----------
https://hackaday.io/project/19925-aiie-an-embedded-apple-e-emulator
Getting the ROMs
================
As with many emulators, you have to go get the ROMs yourself. I've got
the ROMs that I dumped out of my Apple //e. You can probably get yours
a lot easier.
There are four files that you'll need:
2017-02-20 00:15:40 +00:00
* apple2e.rom -- a 32k dump of the entire Apple //e ROM
* disk.rom -- a 256 byte dump of the DiskII controller ROM (16-sector P5)
* parallel.rom -- a 256 byte dump of the Apple Parallel Card
* HDDRVR.BIN -- a 256 byte hard drive driver from AppleWin
(https://github.com/AppleWin/AppleWin/blob/master/firmware/HDD/HDDRVR.BIN)
2017-02-20 23:41:46 +00:00
The MD5 sums of those files are:
2017-02-20 00:15:40 +00:00
* 003a780b461c96ae3e72861ed0f4d3d9 apple2e.rom
* 2020aa1413ff77fe29353f3ee72dc295 disk.rom
2017-02-20 23:41:46 +00:00
* 5902996f16dc78fc013f6e1db14805b3 parallel.rom
* e91f379957d87aa0af0c7255f6ee6ba0 HDDRVR.BIN
2017-02-20 23:41:46 +00:00
From those, the appropriate headers will be automatically generated by
"make roms" (or any other target that relies on the ROMs).
2017-02-20 18:55:16 +00:00
Building (for the Teensy)
=========================
The directory 'teensy' contains 'teensy.ino' - the Arduino development
environment project file. You'll need to open that up and compile from
within.
However.
I built this on a Mac, and I used a lot of symlinks because of
limitations in the Arduino IDE. There's no reason that shouldn't work
under Linux, but I have absolutely no idea what Windows will make of
it. I would expect trouble. No, I won't accept pull requests that
remove the symlinks and replace them with the bare files. Sorry.
Also, you'll have to build the ROM headers (above) with 'make roms'
before you can build the Teensy .ino file.
If anyone knows how to make the Arduino development environment do any
form of scripting that could be used to generate those headers, I'd
gladly adopt that instead of forcing folks to run the Perl script via
Makefile. And if you have a better way of dealing with subfolders of
code, with the Teensy-specific code segregated as it is, I'm all ears...
I compile this with optimization set to "Faster" for the Teensy 3.6 at
180MHz. There's no need to overclock the CPU -- but it does give
2018-01-03 14:30:51 +00:00
better video performance, all the way up to 240MHz, but still not
perfect. Do as you see fit :)
2017-02-20 18:55:16 +00:00
Environment and Libraries
-------------------------
I built this with arduino 1.8.5 and TeensyDuino 1.40.
2017-02-20 18:55:16 +00:00
https://www.pjrc.com/teensy/td_download.html
These libraries I'm using right from Teensy's environment: TimerOne;
SPI; EEPROM; Time; Keypad.
I'm also using these libraries that don't come with TeensyDuino:
2018-01-07 10:08:29 +00:00
### SdFat ###
2017-02-20 18:55:16 +00:00
2018-01-07 10:08:29 +00:00
SD card support - accelerated for the Teensy, and with long filename support.
2017-02-20 18:55:16 +00:00
2018-01-07 10:08:29 +00:00
https://github.com/greiman/SdFat
2017-02-20 18:55:16 +00:00
Running (on the Teensy)
=======================
The reset/menu button brings up a BIOS menu:
Resume
Reset
Cold Reboot
Drop to Monitor
Display: RGB
Debug: off
Insert/Eject Disk 1
Insert/Eject Disk 2
2018-01-03 14:30:51 +00:00
Insert/Eject HD 1
Insert/Eject HD 2
2017-02-20 18:55:16 +00:00
Volume +
Volume -
2018-01-03 14:30:51 +00:00
Suspend
Restore
Prioritize Display/Audio
2017-02-20 18:55:16 +00:00
Reset
-----
This is the same as control-reset on the actual hardware. If you
want to execute the Apple //e self-test, then hold down the two
joystick buttons; hit the reset/menu key; and select "Reset".
Cold Reboot
-----------
This resets much of the hardware to a default state and forces a
reboot. (You can get the self-test using this, too.)
Drop to Monitor
---------------
"Drop to Monitor" tries fairly hard to get you back to a monitor
prompt. Useful for debugging, probably not for much else.
Display
-------
"Display" has four values, and they're only really implemented for
text and hi-res modes (not for lo-res modes). To describe them, I have
to talk about the details of the Apple II display system.
In hires modes, the Apple II can only display certain colors in
certain horizontal pixel columns. Because of how the composite video
out works, the color "carries over" from one pixel to its neighbor;
multiple pixels turned on in a row makes them all white. Which means
that, if you're trying to display a picture in hires mode, you get
color artifacts on the edges of white areas.
The Apple Color Composite Monitor had a button on it that turned on
"Monochrome" mode, with the finer resolution necessary to display the
pixels without the color cast. So its two display modes would be the
ones I call "NTSC-like" and "Black and White."
There are two other video modes. The "RGB" mode (the default, because
it's my preference) shows the color pixels as they're actually drawn
in to memory. That means there can't be a solid field of, for example,
orange; there can only be vertical stripes of orange with black
between them.
The last mode is "Monochrome" which looks like the original "Monitor
II", a black-and-green display.
Debug
-----
This has several settings:
off
Show FPS
Show mem free
Show paddles
Show PC
Show cycles
Show battery
Show time
... these are all fairly self-explanatory.
2018-01-03 14:30:51 +00:00
Insert/Eject Disk1/2 HD1/2
--------------------------
Fairly self-explanatory. Disks may be .dsk, .po, or .nib images
(although .nib images aren't very heavily tested, particularly for
write support). Hard drives are raw 32MB files, whose filenames must
end in .img.
Suspend and Restore
-------------------
The Teensy can be fully suspended and restored - including what disks
are inserted. It's a full VM hibernation. It currently writes to a
file named "suspend.vm" in the root of the MicroSD card. (I would like
to be able to select from multiple suspend/restore files
eventually. It wouldn't be terribly hard; it's just that the BIOS
interface is very limited.)
Prioritize Display/Audio
------------------------
Any Apple emulator needs real-time support for audio. The hardware is
very direct: when a particular memory location ($C030) is read from or
written to, the speaker's state is toggled. By doing this at specific
times, the Apple generates a square wave - and this is the basis of
the built-in audio. Obviously, then, the CPU has to be running at a
specific frequency and the updates to the speaker have to come at
exactly the right time.
The Mac version of AiiE runs the CPU a few cycles fast; and then while
it's waiting for the CPU to catch up, it's slowly toggling the speaker
at the right time. This works well because the actual computer it's
running on is so much faster than the CPU it's emulating.
The Teensy verison can't afford all that overhead. It runs the virtual
CPU in batches of 24-ish cycles, unless it updates the speaker; in
which case, the virtual CPU returns control to the main program
early. This was important while the Teensy code was queueing... but
the queueing has since been removed, and its virtual MMU directly
toggles the speaker as the virtual CPU is running. (This isn't quite
as accurate as the Mac verison but it's close enough; uses less RAM;
and uses less CPU.)
While all that's running, the display is also updating from the main
loop. The trobule is that it takes quite a lot of time to update the
display. Much longer than one CPU cycle. Much longer than hundreds of
CPU cycles. Which means that one of two bad things happens.
Either (a) the CPU can run and update the video while you're still
pushing that video to the screen - which means you can wind up with
(e.g.) half a cloud in Skyfox at the top of the screen, and nothing
immediately below it, because the video is "tearing" (getting partial
results that change over time as it scans down the screen); or (b) you
block the CPU from running while updating the display, which means the
CPU runs in fits and starts. Since the audio is directly coupled to
the CPU that also means the audio will be very messed up.
So this BIOS option lets you choose whether you want good audio or good video.
2017-02-20 18:55:16 +00:00
Building (on a Mac)
===================
While this isn't the purpose of the emulator, it is functional, and is
my first test target for most of the work. With MacOS 10.11.6 and
Homebrew, you can build and run it like this:
<pre>
2018-01-03 14:30:51 +00:00
$ make
$ ./aiie-sdl /path/to/disk.dsk
</pre>
2018-01-03 14:30:51 +00:00
As the name implies, this requires that SDL is installed and in
/usr/local/lib. I've done that with Homebrew like this
<pre>
2018-01-03 14:30:51 +00:00
$ brew install sdl2
</pre>
2017-02-24 15:15:17 +00:00
Mockingboard
============
Mockingboard support is slowly taking shape, based on the schematic in
the Apple II Documentation Project:
https://mirrors.apple2.org.za/Apple%20II%20Documentation%20Project/Interface%20Cards/Audio/Sweet%20Microsystems%20Mockingboard/Schematics/Mockingboard%20Schematic.gif
2018-01-03 14:30:51 +00:00
I'm not sure the Teensy 3.6 has enough horsepower to run this, so I'm
not sure it will ever come to be. It struggles to refresh the display
and run the speaker at full tilt; but maybe that's primarily a
function of the throughput to the display, and adding the Mockingboard
support won't require further sacrifice...
VM
==
The virtual machine architecture is broken in half - the virtual and
physical pieces. There's the root VM object (vm.h), which ties
together the MMU, virtual keyboard, and virtual display.
Then there are the physical interfaces, which aren't as well
organized. They exist as globals in globals.cpp:
<pre>
FileManager *g_filemanager = NULL;
PhysicalDisplay *g_display = NULL;
PhysicalKeyboard *g_keyboard = NULL;
PhysicalSpeaker *g_speaker = NULL;
PhysicalPaddles *g_paddles = NULL;
</pre>
There are the two globals that point to the VM and the virtual CPU:
<pre>
Cpu *g_cpu = NULL;
VM *g_vm = NULL;
</pre>
And there are two global configuration values that probably belong in
some sort of Prefs class:
<pre>
int16_t g_volume;
uint8_t g_displayType;
</pre>
2017-02-19 18:46:13 +00:00
CPU
===
The CPU is a 65C02, not quite complete; it supports all of the 65C02
documented opcodes but not the undocumented ones here:
http://www.oxyron.de/html/opcodes02.html
The timing of the CPU is also not quite correct. It's close, but
doesn't count cycles due to page boundary crossings during branch
instructions. (See the "cycle count footnotes" in cpu.cpp.)
The CPU passes the 6502 functional test from here:
https://github.com/Klaus2m5/6502_65C02_functional_tests
... which is included in binary form in the test harness (see the .h
files in util/ for notes).
testharness.basic should reach "test number 240", hang for a while,
and then exit.
testharness.verbose should show that it gets through 43 tests, test
240, and then loops repeatedly for a while (exiting at a somewhat
arbitrary point).
testharness.extended currently fails (hanging at 0x733) because I
haven't implemented the undocumented opcodes. It should get to address
0x24a8 and hang. Some day I'll finish implementing all of the
undocumented opcodes :)