For my own benefit as much as anyone’s, here’s how Apple /// extended addressing works. (This doesn’t need to be linked at MW; there’s no end-user value here unless you are an end user who plans to write new software for the Apple ///).
The hardware outside of the CPU knows *nothing* about what instruction the CPU is executing. Therefore, for emulation, you do not need to modify a standard 6502 core to emulate the /// successfully. You *do* need a core that outputs the SYNC pin or otherwise signals opcode fetches, however, and emulation of the false reads and prefetch quirks helps.
On each and every CPU read:
– If it’s not an opcode fetch (6502 SYNC pin is low)
– And it’s to the zero page (original 6502 address is 0x00xx)
– And the current zero page (VIA 0 port B) has bits 3 and 4 set ((zp & 0x18) == 0x18)
– Fetch the corresponding byte from “page X” (current zero page XOR 0x0c00) (this is called the “X byte”)
– If bit 7 of the X byte is set, enable extended addressing for every read and write until the next opcode fetch (rising edge of SYNC). Because some opcodes do a false read, it’s important that this continue until the opcode fetch.
– If bit 7 of the X byte is clear, do nothing, the memory address occurs as normal
When extended addressing is enabled:
– If the low nibble of the X byte is 0-0xe, the address space has the bank specified by that nibble from 0000-7fff and the next bank up from that at 8000-ffff. (Apple /// banks are 32k)
– If the low nibble of the X byte is 0xf, bank 0 is mapped from 2000-9fff and RAM is mapped in from 0000-1fff and a000-ffff. In particular, the RAM hidden under the two VIAs is accessible in this manner; SOS uses those bytes for the time and date.
– Bits 4, 5, and 6 of the Xbyte are ignored. Old versions of MESS tried to do something special for Xbyte = 0xff, but that’s incorrect, the hardware treats that as 0x8f.
– It should go without saying, but the check for extended addressing is not done while you are already in extended addressing mode. So an extended read to a zero page location will follow the rules immediately above here; they won’t follow the initial flowchart to determine if extended addressing should be enabled).
Finally, this isn’t related to the extended addressing, but it’s easy to get wrong. When ROM is banked in from f000-ffff, writes to that region will go through to the underlying RAM unless the write protect bit (bit 3) in the environment register (VIA 0 port A) is set. The diagnostics disk won’t boot with this wrong.