20

On the Apple IIgs, the 256K of built-in main memory is divided into two sections: The "fast" RAM, banks 00 and 01, and the "slow" RAM, banks E0 and E1. CPU access to slow RAM required the CPU to slow to the 1MHz speed of the earlier Apple II models. (Later models with 1MB on board are similar, just with more fast RAM).

It's possible to set a soft switch ($C035) to control write shadowing, in which writes to bank 00 and 01 are copied automagically into banks E0 and E1. This allows the CPU to run at full speed while accessing this memory. The primary purpose of this was to allow the CPU to write data into the video buffer, which was in slow RAM, without slowing down.

But my question is how did this work? Obviously, something is copying this data, but how? The FPI cannot write the data to slow RAM itself, as it has no direct connection. Only the Mega II can write to slow RAM.

Based on looking at the schematic, the Mega II chip has access to the slow RAM - but it doesn't have access to the PH2 2.8MHz clock used on the CPU buses when in high speed mode. The FPI, on the other hand, generates the PH2 clock and also can see the CPU buses, but it doesn't connect to the slow RAM, and the only way it seems to be able to pass data to the Mega II is via the main buses which are shared with the CPU.

The FPI and Mega II share only one clock: The 14Mhz clock which was the master clock in older models. At 14MHz, the FPI could shift the address and data to the Mega II one bit at a time and still keep up with the CPU, but there doesn't seem to be any signal line suited for this.

Having the FPI sneak data to the Mega II when the CPU isn't looking turns out to have the same problems as having the Mega II copy the writes in real time.

The other thing I can think of is that the FPI disconnects the CPU from the bus long enough to send this data over to the Mega II. Normally you'd slow to 1MHz to send data to the Mega II this way - which would be unfortunate because it would pretty much defeat the whole point of the write shadowing. This seems unlikely because it seems like it would perform worse than not doing it at all, but maybe they have a way to do it without totally killing performance.

So I am out of ideas. Where's the magic?

1
  • 1
    Interesting and especially well prepared question. Thank you. AFAIR from my Apple II times, it's like your second asumption. the CPU gets slowed down for one clock. This isn't as bad as it seams, since 'useful' RAM access (i.e. screen writing) is in average less than 10% of all clocks even in the tightest of all loops. Worst case is a 2.5 MHz Apple :)
    – Raffzahn
    Jan 22, 2018 at 11:22

1 Answer 1

18

That's an interesting and especially well prepared question. Thank you.

AFAIR your second assumption is right. When shadowing is enabled for a region (see below) the CPU gets synchronized and slowed down to 1 MHz during the writing cycle for a clock period.

This isn't as bad as it seems, since 'useful' RAM access (i.e. screen writing) is on average less than 10% of all clocks even in the tightest of all loops (*1). And the whole idea of shadowing is to restrict this slow down to just a single write cycle (on the 1 MHz side). Reading the same location (or any other 'on-screen' location) in 00/01 again isn't slowed down.

In fact, as long as it's only about writing to a screen region, direct access to E0/E1 for the same purpose isn't any slower at all. The CPU also gets slowed down to 1 MHz only for the access cycle (*2). But in this case, reading would also be slowed down. And with placing a program in E0/E1 the machine will effectively slow down to (a tiny bit more than) 1 MHz.

With shadowing, only writes do slow down, while reads are satisfied from fast memory (00/01). It's about squeezing out the very last bit of speed when slow memory is involved. For all practical purpose the effective speed of a program using slow memory for screen data lingers between 2.0 and 2.8 MHz (*3) depending on the code structure and timing(*2). Shadow memory operation pushes it way toward the upper boundary, making the use of slow memory not a real burden (*4).

Shadowing is really only meant to speed up screen access. For everything else, needed for Apple II compatibility, direct access to E0/E1 is the only way. Shadowing is only available to 6 regions. They are partly overlapping and controlled via bits at E0/C035:

0 - 0400...07FF - Text1
1 - 2000...3FFF - HGR1
2 - 4000...5FFF - HGR2
3 - 2000...9FFF - Super High-res
4 - 2000...3FFF - Double High-res ($01/2000...)
5 - Unused
6 - C000...DFFF - Switches/Slot Memory
7 - Speed indicator

Shadowing will only be done for the region enabled. Thus only data written after the corresponding switch is on will reach E0/E1.

Conclusion: Just switch it on and pump your data to the screen using 00/01.


Having said that, there might still be need to improve even upon shadowing. For example more sophisticated games do not just copy data to the screen, but issue more complex operations needing to manipulate data more than once before it is displayed (aka bit-blitting) . Also double buffering might be a good idea to use all the time for picture generation. Sheppy (*5) has written a quite awesome answer about how to use shadowing and CPU tricks to implement double buffering and fastest possible screen copy by using the effects of shadow memory.


*1 - Just grab a sheet of paper and count execution cycles according to what the access is and in which region.

*2 - It's a bit more complex, as both memory systems are not simply synchronized in a way that the fast clock is a fraction less multiple of the slow clock. Thus there might be an additional waiting period of up to 4/5 of a 1 MHz cycle to synchronize. In worst case this means almost doubling the penalty. Sheppy mentions this in another related questions answer.

*3 - Ofc, ignoring the optional stupidity to put code there.

*4 - Don't get fooled by horror stories told by "experts". Do the math (*1) yourself with the logic explained in mind.

*5 - One of the demi-gods of Apple II programming and still around.

6
  • No love for the second lores page at $0800-$0BFF?
    – supercat
    May 24, 2019 at 21:20
  • @supercat AFAIK not. Second text page has always been an unloved child. Mostly due the fact that its location is used as default area for BASIC, thus not really usable without additional measures when loading a program. So when doing the IIgs extensions Apple didn't add shadowing support.
    – Raffzahn
    May 25, 2019 at 8:22
  • The original (ROM 01) IIgs has an "Alternate Display Mode" CDA that enables a manual copy. My understanding is that this was an oversight rather than a deliberate omission. The ROM 03 IIgs added native support for shadowing text/GR page 2. en.wikipedia.org/wiki/…
    – fadden
    Jul 1, 2020 at 18:00
  • @fadden Interesting, Didn't know. Thanks. Do you know how it's switched on in ROM3?
    – Raffzahn
    Jul 1, 2020 at 18:54
  • 1
    One of the reserved bits (5) in $c035 is used. See Apple IIgs Hardware Reference, 2nd edition, page 20. Also, you list bit 7 as being a speed indicator, but it's marked as "reserved" in the hardware ref. Bit 7 in $C036 is the 1MHz / 2.8MHz switch. And I just noticed that shadowing across other banks is possible with bit 4 in $c036, but "for proper operation of the Apple IIgs operating system, this bit must always be set to 0."
    – fadden
    Jul 1, 2020 at 20:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .