6

The early microcomputers were well served by 8-bit CPUs with 16-bit address bus width, but later generations of these machines tended to run out of address space, and had to resort to some form of bank switching. For example, the Commodore 64 had an irregular scheme that switched several windows of the address space between RAM and ROM or memory-mapped I/O. The Tandy CoCo 3 went so far as to provide a memory management unit that could map any 8K page of the address space to any 8K out of up to half a megabyte of RAM.

As far as I have been able to gather from e.g. Apple IIe auxiliary RAM bank select register address -- C073 or C07X? the Apple IIe had a very simple scheme with a single variable to select which 64K of RAM was currently active.

How did this work from a software perspective? Say your program is running in bank 0 and wants to swap in bank 1 to stash some data. So you execute an instruction to switch banks... and the next instruction fails to execute, because now bank 1 is active, so that's where the CPU is getting code from, but it's initially empty, so your program promptly crashes before it has any opportunity to copy code across.

Presumably the machine must have provided some way to get around this problem. How was it done?

3 Answers 3

4

Summary

You dealt with the problem of switching a bank under running code by making sure that the next instruction address in the other bank had the appropriate code to continue executing your program. This was set up by setting the system to read from one bank but write to the other so that your executing code could run from one bank but set up the other bank.

The following three sections discuss the original Apple II Language Card banking; the new main/alternate Extended 80 Column Card added to the IIe and IIc, and give a more detailed description of how to run your own code in the alternate bank.

Apple II ROM/RAM Banking

...Apple IIe auxiliary RAM bank select register address -- C073 or C07X? the Apple IIe had a very simple scheme with a single variable to select which 64K of RAM was currently active.

The scheme was not so simple. The main/auxiliary bank select allowed access to the RAM supplied by the Extended 80-column Text Card, but that was new to the IIe (as an official Apple API; it was actually first implemented in 3rd party cards), and was in addition to the much older Apple II/II+ Language Card banking scheme for the top 12K of the address space.

That pre-IIe system offered ROM or RAM for $E000-$FFFF (mapping 8K of 16K) and ROM or one of two RAM banks for $D000-$DFFF (mapping 4K of 12K). (The $C800-$CFFF range could also be mapped on the fly to ROM in any of the expansion slots, but that's probably not so relevant to this discussion.) The upper 8K bank and one of the lower 4K banks were often used for a different version of the ROM (e.g., to use the Integer BASIC ROM code on an Apple II+ with Applesoft ROMs) but of course if you were using the standard on-board ROM code (or not using ROM code at all) all 16K of RAM in those three banks was available for any purpose you liked.

A very useful additional feature was that the bank selection could be set to let you read ROM but write RAM. So if you needed to write new code and data to RAM in the $D000-$FFFF range for later use you could do this while still using the $D000-$FFFF ROM bank and switch only after the RAM was fully set up. (You could not, however, read one RAM bank and write the other RAM bank in the $D000-$DFFF range.)

Apple IIe Additions

The additional bank switching added by the Apple IIe with the extended 80 column RAM card was the alternate bank, which was essentially a full duplication of all the RAM banks above. That is, as well as two RAM banks for $0000-$BFFF (the lower 48K) you now had ROM and two 8K RAM banks at $E000-$FFFF and ROM and four 4K RAM banks at $D000-$DFFF. The IIc also supported a second 12K alternate ROM bank, though this was used only from the second version (version 0—the first version was version 255 or -1) of the ROMs onward. I don't know offhand if the IIe supported the same.

(The IIc provided the card slot ROMs at $C800-$CFFF for all slots from onboard ROM as well, and this also was expanded with alternate mapping for these with the ROM expansion. This worked exactly as everything else did above; the ROM for a particular slot was chosen with the usual Apple II scheme to do that and whether the alternate bank was selected determined which of the two banks for that slot was selected.)

Additionally, and unlike the $D000-$DFFF RAM banks, for the $0000-$BFFF range it was possible to set the read and write banks separately, so that you could run code and read data from the main bank but write data to the auxiliary bank or vice versa.

The Apple IIc Technical Reference Manual describes all this in detail in Chapter 2: Memory Organization and Control section "Overview of the Address Space" (p.20). (This is described similarly in other IIe and IIc manuals; this particular one is just what I happened to have at hand.) Here is the overview diagram:

Apple IIc memory map

Using Code in the Alternate Bank

Say your program is running in bank 0 and wants to swap in bank 1 to stash some data. So you execute an instruction to switch banks... and the next instruction fails to execute, because now bank 1 is active, so that's where the CPU is getting code from, but it's initially empty, so your program promptly crashes before it has any opportunity to copy code across.

Presumably the machine must have provided some way to get around this problem.

The way to get around this was to make sure that, if you were switching an area of memory where you were currently executing code, to make sure that you had first set up that area to have the correct to continue program execution in the other bank.

Generally, you'd run setup code from the main bank in the lower 48K, switch the write (but not read) bank to the alternate bank, and write all your additional code to the alternate bank before ever trying to execute from it. You were responsible for making sure that at any instruction where you switched read from main to alternate bank the code in alternate bank at the next location was the correct code to continue executing (and vice versa when switching from the alternate to the main bank).

The later IIc ROMs did this themselves, too; the code makes extensive use of switching between main and alternate ROM banks. The ROM also provided routines for copying data between RAM banks (as mentioned in Peterl's answer) so your own code didn't have to handle the switching.

3
  • 2
    There are also extension memory cards that are Saturn compatible. Which will add supplemental 16 K language cards in addition to the original one. A 128K Saturn compatible card will add 16 4K blocks to the D000-DFFF range and 8 8K blocks to the E000-FFFF range. Depending on the configuration it will only add 6K blocks and keep the F800-FFFF from ROM. Nov 8, 2021 at 16:49
  • 1
    The simplest way of handling such issues is to often have a region of address space which contains the same code in both banks. Code running from that region of address space may then switch which banks are used for accessing data without having it affect the execution of the code.
    – supercat
    Nov 8, 2021 at 20:12
  • 1
    @cjs: The ROM routines are AUXMOVE and XFER, referred to in the answer from PeterI. He links to the docs. Nov 9, 2021 at 10:39
9

The Apple IIe actually had an incredibly painful memory map; the answer you’ve linked to is about auxiliary RAM cards that add more than an additional 64kb of RAM to the system, i.e. the complete total is the base 64kb plus the first 64kb of auxiliary plus some more 64kb quantities of auxiliary. What the register mentioned in that question does is select which of the auxiliary banks is visible anywhere in the CPU’s address space that auxiliary memory is currently visible. It doesn’t affect the address space beyond that.

The CPU’s address space is actually broken up into ten regions, all of different sizes and not all of them contiguous. The rules for what goes in each region are unique to that region and sometimes even involves alternate options, e.g for the region 2000–3FFF:

Reading: contains auxiliary RAM if either (i) 80STORE, PAGE2 and HIRES are set; or (ii) 80STORE is reset and RAMRD is set. Contains base RAM otherwise.

That being the case, you both use the ability to page for reading and writing separately, or you can shuffle bytes around by changing regions of the memory map independently.

6

You can set which bank you're reading and writing to separately

So if you don't want to use the built in routines (AUXMOVE / XFER) your code would typically copy it's self into the aux memory by setting the read from main memory ($C002) and write to aux memory ($C004) flags.

Once that has been done the code exists in both spaces and you can happily swap the read and write soft switches as appropriate.

The zero page and stack don't usually swap (There is another pair of soft switches for this)

See https://archive.org/details/Apple_IIe_Technical_Reference_Manual/page/n119/mode/2up

The value at $C073 is only changing which bank of 64K is in use for the aux memory, so you'd need to copy the code into multiple banks (or use the ROM AUXMOVE routine)

3
  • 1
    With perhaps a bit of work, this could and should be the accepted answer. It's the only one that mentions the firmware routines - XFER in particular for jumping to code in either bank - as well as the main switches and links to the docs. Nov 9, 2021 at 10:25
  • 2
    @NickWestgate Do you really think AUXMOVE and XFER are the important things here? They seem to to answer the question with, basically, "Use this magic." (Though perhaps my bias towards thorough understanding of what tools are doing is making me view the question in a different light than the poster intended.)
    – cjs
    Nov 9, 2021 at 10:50
  • 1
    @cjs: It's always worth knowing what's going on under the hood (all abstractions are leaky) but I remember knowing and using these ROM routines back in the day, so I think it's worth pointing out they're there - that there was firmware support - and corollaries like the protocol for switching ZP and the Stack Pointer storage locations. Nov 11, 2021 at 10:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.