Apple /// Reset Logic & Apple II Emulation Flaws
I recently ported software from the Apple II to Apple III and encountered an interesting topic. It's a corner case, but in my opinion a typical example. It shows how the Apple III design was sometimes (maybe unnecessarily) complicated. And how features introduced Apple II compatibility issues.
I had implemented a firmware update utility for the DAN][ Controller card on the Apple II. This utility uses Apple II's "warm start handler" feature. It's an option to execute a custom handler whenever the user presses RESET.
I needed this feature for my firmware update utility as a method of triggering a hardware reset of the interface card. This would cause the card's microcontroller to reset and execute its bootloader. And I needed the warm start handler in order for the 6502 to then very quickly talk to the microcontroller, before a timeout expired and it left its bootloader to launch the normal application from flash memory.
Using RESET & bootloader for firmware updates is actually a very common approach - since it provides a failsafe update mechanism. It even keeps working when a microcontroller's normal application in flash was "bricked".
My utility was working great on the Apple II. So, I was looking on properly porting it for the Apple III...
Warm start RESET on the Apple II
Here's what happens on an Apple II when a warm start RESET is triggered:
- The user presses RESET.
- A full system reset is triggered. This affects the entire mainboard, all I/O slots (and interface cards) and the 6502 CPU itself.
- Once the RESET button is released, all I/O resumes operation - and with the following clock cycle, the 6502 fetches the address from its RESET vector ($FFFC/$FFFD) and starts executing.
- The Apple II executes the ROM's RESET routine. It quickly determines whether a warm start or normal system reset was requested (Apple-CTRL-RESET), and if a warm start handler was previously registered by software.
- Eventually the ROM calls the registered warm start handler - just a few microseconds after RESET was released.
Easy. A simple feature really. Works great on the Apple II...
Apple /// warm start vs NMI
So, I was considering how to implement the same for the Apple III. But, oh dear! The Apple III has no such feature. The Apple III ROM was hardcoded to always boot from floppy. It doesn't care to distinguish between warm start and normal system RESETs.
It does have an option, however, to trigger an NMI interrupt when the RESET button was pressed individually (rather than Control-RESET). But that's not the same. And it doesn't help with my application. It does not trigger an I/O hardware reset, like on the Apple II.
So, too bad? Nothing we can do? Well, wait, there's more...
The Apple III has an "Apple II Emulation Mode". And to be Apple II compatible this does support a warm start RESET routine.
Well yes, but...
Apple /// Reset & Apple II Emulation Mode
The Apple III supports a warm start RESET, when Apple II Emulation Mode is enabled. It has special mainboard logic to support this, which changes the board's normal RESET behavior. And this feature is probably a little more complicated than you may think it is...
Here's the relevant schematic:
(And remember, all this logic is implemented with basic SN74xx LS TTL ICs on the Apple III...)
- "/RESET" is the normal "CTRL-RESET", which triggers a full system reset. This, however, also ends the Apple II Emulation Mode and boots the Apple III back in native Apple III Mode.
- "/XRESET" triggers when the "RESET" button is pressed individually. It triggers the NMI interrupt on the Apple III. However, if Apple II Emulation Mode is enabled (/AIISW=low), then it also triggers an IORESET.
- There is also a feature to lock and prevent a RESET (/RESET LK), but we ignore this here.
So, when the Apple III is configured for Apple II Emulation, it is splitting the mainboard's RESET signal into two separated domains. The RESET button triggers an I/O reset - which only affects the I/O slots and some related logic. But it does not trigger a CPU RESET. Instead, it also triggers an NMI interrupt.
In order for the Apple II Emulation to behave like a real Apple II, the Apple III used a slightly modified copy of the Apple II ROM for emulation. Apple patched the NMI vector ($FFFA/$FFFB) to point to the same address like the 6502's RESET vector.
So, when the user presses the RESET button in "Apple II Emulation Mode" then:
- All I/O slots receive a hardware RESET.
- The 6502 does not receive a RESET, however, it triggers the NMI interrupt, which triggers the same routine like the Apple II CPU RESET.
So, all is good, right? The Apple III is fully able to mimic the Apple II behavior. Software couldn't tell the difference?
Well, no. It's a complex & clever approach. However, it is flawed...
What's wrong with Apple III's "warm start" when emulating the Apple II?
While the idea of using the NMI interrupt to mimic the Apple II warm start behavior on the Apple III was clever, it has a significant flaw. It's a matter of timing:
- NMI is an "edge triggered interrupt". And it triggers on the falling edge of the input signal. And as shown by the Apple III schematics, it triggers at the very moment the RESET button is pressed (when the "/XRESET" signal goes LOW).
- The RESET and IORESET signals, however, are "level-triggered" signals. As long as IORESET is low, all I/O is reset.
What could possibly go wrong?
The problem on the Apple III is that:
- Pressing RESET immediately triggers the NMI. This causes the 6502 to execute the warm start routines with the next clock cycle. Within a microseconds...
- However, no matter how quick you are in releasing the RESET button, IORESET is asserted much longer. At least several milliseconds - due to the debouncing logic. But a normal user would probably keep the RESET button pressed for a few hundred milliseconds or maybe an entire second anyway. Meanwhile the 6502 CPU is already executing code...
This behavior is clearly different on an Apple II. On the Apple II the CPU and I/O are both blocked while RESET is pressed. And both, CPU+I/O, will resume normal operation with perfect synchronicity once it is released.
Reproducing the Issue
Here's a simple example reproducing the issue on the Apple III:
- Load the Apple II Emulation disk.
- Enter Apple II Emulation Mode (press RETURN).
- Go to the BASIC prompt (briefly press the RESET button individually).
- Press the RESET button again, but this time keep it pressed.
- With the other hand, type
- Now release the RESET button.
The disk drive does not start spinning. The machine is stuck (frozen). The routine accessing the disk drive isn't prepared for the drive and controller card to be unresponsive (since RESET was still active when you typed "PR#6").
The same would have affected any Apple II software, which used the warm start routine and tried to immediately access any I/O following a warm start. This was never an issue on Apple II, since this machine never starts executing code while RESET was still asserted. But such software would have issues in Apple III's "Apple II Emulation Mode".
Workarounds are possible. I added a little Apple III-specific routine to my firmware update utility. It checks and waits until IORESET is released, detecting when the user has finally let go of the RESET button. It does so by accessing the I/O device on the DAN][ Controller card, and checking if the device is already able to respond. Read/write I/O operations are ignored until IORESET was released.
Moral of the story?
Well, it just demonstrates another imperfection in Apple III's "Apple II Emulation Mode". When simple things (like a CPU hardware reset) are implemented in a rather complicated manner, subtle issues are easily introduced...
Did it affect any actual Apple II software back in the day? Hard to tell. There is a good chance that it didn't. Most of the serious, more complex Apple II business software wouldn't run on the Apple III anyway. Other, more fundamental limitations were already preventing the software from starting in the first place, like the hardware limitation of only allowing 48KB of RAM in "Apple II Emulation Mode"...